@@ -6,50 +6,25 @@ use std::io::Write;
6
6
use std:: path:: Path ;
7
7
use std:: process:: { Command , Stdio } ;
8
8
9
- use crate :: llm:: LargeLanguageModel ;
10
9
use crate :: templates:: { self , Updates , UpdatesGoal } ;
11
10
use rust_project_goals:: gh:: issues:: ExistingGithubIssue ;
12
11
use rust_project_goals:: gh:: {
13
12
issue_id:: { IssueId , Repository } ,
14
13
issues:: { checkboxes, list_issues_in_milestone, ExistingGithubComment } ,
15
14
} ;
16
15
17
- const QUICK_UPDATES : & [ & str ] = & [
18
- "Jack and Jill went up the hill" ,
19
- "To fetch a pail of water" ,
20
- "Jack fell down and broke his crown" ,
21
- "And Jill came tumbling after." ,
22
- "Up Jack got and home did trot," ,
23
- "As fast as he could caper;" ,
24
- "Went to bed to mend his head" ,
25
- "With vinegar and brown paper." ,
26
- "Jill came in and she did grin" ,
27
- "To see his paper plaster;" ,
28
- "Mother, vex’d, did whip her next" ,
29
- "For causing Jack's disaster." ,
30
- ] ;
31
-
32
- fn comments_forever ( ) -> impl Iterator < Item = & ' static str > {
33
- QUICK_UPDATES . iter ( ) . copied ( ) . cycle ( )
34
- }
35
-
36
16
pub async fn updates (
37
17
repository : & Repository ,
38
18
milestone : & str ,
39
19
output_file : Option < & Path > ,
40
20
start_date : & Option < NaiveDate > ,
41
21
end_date : & Option < NaiveDate > ,
42
- quick : bool ,
43
22
vscode : bool ,
44
- model_id : Option < & str > ,
45
- region : Option < & str > ,
46
23
) -> anyhow:: Result < ( ) > {
47
24
if output_file. is_none ( ) && !vscode {
48
25
anyhow:: bail!( "either `--output-file` or `--vscode` must be specified" ) ;
49
26
}
50
27
51
- let llm = LargeLanguageModel :: new ( model_id, region) . await ?;
52
-
53
28
let issues = list_issues_in_milestone ( repository, milestone) ?;
54
29
55
30
let filter = Filter {
@@ -69,14 +44,10 @@ pub async fn updates(
69
44
70
45
let mut updates = templates:: Updates {
71
46
milestone : milestone. to_string ( ) ,
72
- flagship_goals : vec ! [ ] ,
73
- other_goals_with_updates : vec ! [ ] ,
74
- other_goals_without_updates : vec ! [ ] ,
47
+ flagship_goals : prepare_goals ( repository, & issues, & filter, true ) . await ?,
48
+ other_goals : prepare_goals ( repository, & issues, & filter, false ) . await ?,
75
49
} ;
76
50
77
- prepare_flagship_goals ( repository, & issues, & filter, & llm, quick, & mut updates) . await ?;
78
- prepare_other_goals ( repository, & issues, & filter, & llm, quick, & mut updates) . await ?;
79
-
80
51
progress_bar:: finalize_progress_bar ( ) ;
81
52
82
53
// Render the output using handlebars and write it to the file.
@@ -108,17 +79,16 @@ pub async fn updates(
108
79
Ok ( ( ) )
109
80
}
110
81
111
- async fn prepare_flagship_goals (
82
+ async fn prepare_goals (
112
83
repository : & Repository ,
113
84
issues : & [ ExistingGithubIssue ] ,
114
85
filter : & Filter < ' _ > ,
115
- llm : & LargeLanguageModel ,
116
- quick : bool ,
117
- updates : & mut Updates ,
118
- ) -> anyhow:: Result < ( ) > {
119
- // First process the flagship goals, for which we capture the full text of comments.
86
+ flagship : bool ,
87
+ ) -> anyhow:: Result < Vec < UpdatesGoal > > {
88
+ let mut result = vec ! [ ] ;
89
+ // We process flagship and regular goals in two passes, and capture comments differently for flagship goals.
120
90
for issue in issues {
121
- if ! issue. has_flagship_label ( ) {
91
+ if flagship != issue. has_flagship_label ( ) {
122
92
continue ;
123
93
}
124
94
@@ -135,34 +105,9 @@ async fn prepare_flagship_goals(
135
105
136
106
let mut comments = issue. comments . clone ( ) ;
137
107
comments. sort_by_key ( |c| c. created_at . clone ( ) ) ;
138
- comments. retain ( |c| filter. matches ( c) ) ;
108
+ comments. retain ( |c| !c . is_automated_comment ( ) && filter. matches ( c) ) ;
139
109
140
- let summary: String = if comments. len ( ) == 0 {
141
- format ! ( "No updates in this period." )
142
- } else if quick {
143
- QUICK_UPDATES . iter ( ) . copied ( ) . collect ( )
144
- } else {
145
- let prompt = format ! (
146
- "The following comments are updates to a project goal entitled '{title}'. \
147
- The goal is assigned to {people} ({assignees}). \
148
- Summarize the major developments, writing for general Rust users. \
149
- Write the update in the third person and do not use pronouns when referring to people. \
150
- Do not respond with anything but the summary paragraphs. \
151
- ",
152
- people = if issue. assignees. len( ) == 1 {
153
- "1 person" . to_string( )
154
- } else {
155
- format!( "{} people" , issue. assignees. len( ) )
156
- } ,
157
- assignees = comma( & issue. assignees) ,
158
- ) ;
159
- let updates: String = comments. iter ( ) . map ( |c| format ! ( "\n {}\n " , c. body) ) . collect ( ) ;
160
- llm. query ( & prompt, & updates)
161
- . await
162
- . with_context ( || format ! ( "making request to LLM failed" ) ) ?
163
- } ;
164
-
165
- updates. flagship_goals . push ( UpdatesGoal {
110
+ result. push ( UpdatesGoal {
166
111
title : title. clone ( ) ,
167
112
issue_number : issue. number ,
168
113
issue_assignees : comma ( & issue. assignees ) ,
@@ -173,96 +118,13 @@ async fn prepare_flagship_goals(
173
118
. url ( ) ,
174
119
progress,
175
120
is_closed : issue. state == GithubIssueState :: Closed ,
176
- updates_markdown : summary,
121
+ num_comments : comments. len ( ) ,
122
+ comments,
177
123
} ) ;
178
124
179
125
progress_bar:: inc_progress_bar ( ) ;
180
126
}
181
- Ok ( ( ) )
182
- }
183
-
184
- async fn prepare_other_goals (
185
- repository : & Repository ,
186
- issues : & [ ExistingGithubIssue ] ,
187
- filter : & Filter < ' _ > ,
188
- llm : & LargeLanguageModel ,
189
- quick : bool ,
190
- updates : & mut Updates ,
191
- ) -> anyhow:: Result < ( ) > {
192
- // Next process the remaining goals, for which we generate a summary using an LLVM.
193
- let mut quick_comments = comments_forever ( ) ;
194
- for issue in issues {
195
- if issue. has_flagship_label ( ) {
196
- continue ;
197
- }
198
-
199
- let title = & issue. title ;
200
-
201
- progress_bar:: print_progress_bar_info (
202
- & format ! ( "Issue #{number}" , number = issue. number) ,
203
- title,
204
- progress_bar:: Color :: Green ,
205
- progress_bar:: Style :: Bold ,
206
- ) ;
207
-
208
- // Find the relevant updates that have occurred.
209
- let mut comments = issue. comments . clone ( ) ;
210
- comments. sort_by_key ( |c| c. created_at . clone ( ) ) ;
211
- comments. retain ( |c| filter. matches ( c) ) ;
212
-
213
- // Use an LLM to summarize the updates.
214
- let summary = if comments. len ( ) == 0 {
215
- format ! ( "* No updates in this period." )
216
- } else if quick {
217
- let num_comments = std:: cmp:: min ( comments. len ( ) , 3 ) ;
218
- quick_comments
219
- . by_ref ( )
220
- . take ( num_comments)
221
- . map ( |c| format ! ( "* {c}\n " ) )
222
- . collect ( )
223
- } else {
224
- let prompt = format ! (
225
- "The following comments are updates to a project goal entitled '{title}'. \
226
- The goal is assigned to {people} ({assignees}). \
227
- Summarize the updates with a list of one or two bullet points, each one sentence. \
228
- Write the update in the third person and do not use pronouns when referring to people. \
229
- Format the bullet points as markdown with each bullet point beginning with `* `. \
230
- Do not respond with anything but the bullet points. \
231
- ",
232
- people = if issue. assignees. len( ) == 1 {
233
- "1 person" . to_string( )
234
- } else {
235
- format!( "{} people" , issue. assignees. len( ) )
236
- } ,
237
- assignees = comma( & issue. assignees) ,
238
- ) ;
239
- let updates: String = comments. iter ( ) . map ( |c| format ! ( "\n {}\n " , c. body) ) . collect ( ) ;
240
- llm. query ( & prompt, & updates) . await ?
241
- } ;
242
-
243
- let goal = UpdatesGoal {
244
- title : title. clone ( ) ,
245
- issue_number : issue. number ,
246
- issue_assignees : comma ( & issue. assignees ) ,
247
- issue_url : IssueId {
248
- repository : repository. clone ( ) ,
249
- number : issue. number ,
250
- }
251
- . url ( ) ,
252
- is_closed : issue. state == GithubIssueState :: Closed ,
253
- updates_markdown : summary,
254
- progress : checkboxes ( & issue) ,
255
- } ;
256
-
257
- if comments. len ( ) > 0 {
258
- updates. other_goals_with_updates . push ( goal) ;
259
- } else {
260
- updates. other_goals_without_updates . push ( goal) ;
261
- }
262
-
263
- progress_bar:: inc_progress_bar ( ) ;
264
- }
265
- Ok ( ( ) )
127
+ Ok ( result)
266
128
}
267
129
268
130
struct Filter < ' f > {
0 commit comments