Skip to content

Commit c869852

Browse files
nikomatsakisNiko Matsakislqd
authored
Raw comments (#298)
* synchronize titles on issues * don't use LLM, just link to comments * include goal comment text * updated "why this goal" text from blog post * improve output of comments * pluralize * Update crates/rust-project-goals-cli-llm/src/updates.rs Co-authored-by: Rémy Rakic <remy.rakic+github@gmail.com> --------- Co-authored-by: Niko Matsakis <nikomat@amazon.com> Co-authored-by: Rémy Rakic <remy.rakic+github@gmail.com>
1 parent 0766ae8 commit c869852

File tree

9 files changed

+111
-203
lines changed

9 files changed

+111
-203
lines changed

crates/rust-project-goals-cli-llm/src/main.rs

-6
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,18 @@ async fn main() -> anyhow::Result<()> {
2424
} = Opt::parse();
2525
let UpdateArgs {
2626
milestone,
27-
quick,
2827
vscode,
2928
output_file,
3029
start_date,
3130
end_date,
32-
model_id,
33-
region,
3431
} = &serde_json::from_str(&updates_json)?;
3532
updates::updates(
3633
&repository,
3734
milestone,
3835
output_file.as_deref(),
3936
start_date,
4037
end_date,
41-
*quick,
4238
*vscode,
43-
model_id.as_deref(),
44-
region.as_deref(),
4539
)
4640
.await?;
4741
Ok(())

crates/rust-project-goals-cli-llm/src/templates.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::path::{Path, PathBuf};
22

33
use handlebars::{DirectorySourceOptions, Handlebars};
4+
use rust_project_goals::gh::issues::ExistingGithubComment;
45
use serde::Serialize;
56

67
use rust_project_goals_json::Progress;
@@ -44,8 +45,7 @@ handlebars::handlebars_helper!(is_complete: |p: Progress| match p {
4445
pub struct Updates {
4546
pub milestone: String,
4647
pub flagship_goals: Vec<UpdatesGoal>,
47-
pub other_goals_with_updates: Vec<UpdatesGoal>,
48-
pub other_goals_without_updates: Vec<UpdatesGoal>,
48+
pub other_goals: Vec<UpdatesGoal>,
4949
}
5050

5151
impl Updates {
@@ -74,7 +74,10 @@ pub struct UpdatesGoal {
7474
pub is_closed: bool,
7575

7676
/// Markdown with update text (bullet list)
77-
pub updates_markdown: String,
77+
pub comments: Vec<ExistingGithubComment>,
78+
79+
/// Comments.len but accessible to the template
80+
pub num_comments: usize,
7881

7982
/// Progress towards the goal
8083
pub progress: Progress,

crates/rust-project-goals-cli-llm/src/updates.rs

+13-151
Original file line numberDiff line numberDiff line change
@@ -6,50 +6,25 @@ use std::io::Write;
66
use std::path::Path;
77
use std::process::{Command, Stdio};
88

9-
use crate::llm::LargeLanguageModel;
109
use crate::templates::{self, Updates, UpdatesGoal};
1110
use rust_project_goals::gh::issues::ExistingGithubIssue;
1211
use rust_project_goals::gh::{
1312
issue_id::{IssueId, Repository},
1413
issues::{checkboxes, list_issues_in_milestone, ExistingGithubComment},
1514
};
1615

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-
3616
pub async fn updates(
3717
repository: &Repository,
3818
milestone: &str,
3919
output_file: Option<&Path>,
4020
start_date: &Option<NaiveDate>,
4121
end_date: &Option<NaiveDate>,
42-
quick: bool,
4322
vscode: bool,
44-
model_id: Option<&str>,
45-
region: Option<&str>,
4623
) -> anyhow::Result<()> {
4724
if output_file.is_none() && !vscode {
4825
anyhow::bail!("either `--output-file` or `--vscode` must be specified");
4926
}
5027

51-
let llm = LargeLanguageModel::new(model_id, region).await?;
52-
5328
let issues = list_issues_in_milestone(repository, milestone)?;
5429

5530
let filter = Filter {
@@ -69,14 +44,10 @@ pub async fn updates(
6944

7045
let mut updates = templates::Updates {
7146
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?,
7549
};
7650

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-
8051
progress_bar::finalize_progress_bar();
8152

8253
// Render the output using handlebars and write it to the file.
@@ -108,17 +79,16 @@ pub async fn updates(
10879
Ok(())
10980
}
11081

111-
async fn prepare_flagship_goals(
82+
async fn prepare_goals(
11283
repository: &Repository,
11384
issues: &[ExistingGithubIssue],
11485
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.
12090
for issue in issues {
121-
if !issue.has_flagship_label() {
91+
if flagship != issue.has_flagship_label() {
12292
continue;
12393
}
12494

@@ -135,34 +105,9 @@ async fn prepare_flagship_goals(
135105

136106
let mut comments = issue.comments.clone();
137107
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));
139109

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 {
166111
title: title.clone(),
167112
issue_number: issue.number,
168113
issue_assignees: comma(&issue.assignees),
@@ -173,96 +118,13 @@ async fn prepare_flagship_goals(
173118
.url(),
174119
progress,
175120
is_closed: issue.state == GithubIssueState::Closed,
176-
updates_markdown: summary,
121+
num_comments: comments.len(),
122+
comments,
177123
});
178124

179125
progress_bar::inc_progress_bar();
180126
}
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)
266128
}
267129

268130
struct Filter<'f> {

crates/rust-project-goals-cli/src/rfc.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rust_project_goals::{
1313
gh::{
1414
issue_id::{IssueId, Repository},
1515
issues::{
16-
change_milestone, create_comment, create_issue, fetch_issue, list_issues_in_milestone, lock_issue, sync_assignees, update_issue_body, FLAGSHIP_LABEL, LOCK_TEXT
16+
change_milestone, change_title, create_comment, create_issue, fetch_issue, list_issues_in_milestone, lock_issue, sync_assignees, update_issue_body, CONTINUING_GOAL_PREFIX, FLAGSHIP_LABEL, LOCK_TEXT
1717
},
1818
labels::GhLabel,
1919
},
@@ -199,6 +199,11 @@ enum GithubAction<'doc> {
199199
issue: GithubIssue<'doc>,
200200
},
201201

202+
ChangeTitle {
203+
number: u64,
204+
title: String,
205+
},
206+
202207
ChangeMilestone {
203208
number: u64,
204209
milestone: String,
@@ -333,6 +338,10 @@ fn initialize_issues<'doc>(
333338
.collect(),
334339
});
335340
}
341+
342+
if existing_issue.title != desired_issue.title {
343+
actions.insert(GithubAction::ChangeTitle { number: existing_issue.number, title: desired_issue.title });
344+
}
336345

337346
if existing_issue.milestone.as_ref().map(|m| m.title.as_str()) != Some(timeframe) {
338347
actions.insert(GithubAction::ChangeMilestone {
@@ -342,9 +351,7 @@ fn initialize_issues<'doc>(
342351
actions.insert(GithubAction::Comment {
343352
number: existing_issue.number,
344353
body: format!(
345-
"This is a continuing project goal, and the updates below \
346-
this comment will be for the new period {}",
347-
timeframe
354+
"{CONTINUING_GOAL_PREFIX} {timeframe}",
348355
),
349356
});
350357
}
@@ -525,6 +532,9 @@ impl Display for GithubAction<'_> {
525532
GithubAction::ChangeMilestone { number, milestone } => {
526533
write!(f, "update issue #{} milestone to \"{}\"", number, milestone)
527534
}
535+
GithubAction::ChangeTitle { number, title } => {
536+
write!(f, "update issue #{} title to \"{}\"", number, title)
537+
}
528538
GithubAction::Comment { number, body } => {
529539
write!(f, "post comment on issue #{}: \"{}\"", number, body)
530540
}
@@ -596,6 +606,11 @@ impl GithubAction<'_> {
596606
Ok(())
597607
}
598608

609+
GithubAction::ChangeTitle { number, title } => {
610+
change_title(repository, number, &title)?;
611+
Ok(())
612+
}
613+
599614
GithubAction::Comment { number, body } => {
600615
create_comment(repository, number, &body)?;
601616
Ok(())

crates/rust-project-goals-llm/src/lib.rs

-12
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ pub struct UpdateArgs {
1111
/// Milestone for which we generate tracking issue data (e.g., `2024h2`).
1212
pub milestone: String,
1313

14-
/// Quick mode does not use an LLM to generate a summary.
15-
#[arg(long)]
16-
pub quick: bool,
17-
1814
/// Quick mode does not use an LLM to generate a summary.
1915
#[arg(long)]
2016
pub vscode: bool,
@@ -30,12 +26,4 @@ pub struct UpdateArgs {
3026
/// End date for comments.
3127
/// If not given, no end date.
3228
pub end_date: Option<chrono::NaiveDate>,
33-
34-
/// Set a custom model id for the LLM.
35-
#[arg(long)]
36-
pub model_id: Option<String>,
37-
38-
/// Set a custom region.
39-
#[arg(long)]
40-
pub region: Option<String>,
4129
}

0 commit comments

Comments
 (0)