Improve goal completion usage reporting (#22907)

## Why

Goal completion follow-up turns currently receive a preformatted English
usage sentence such as `time used: 2586 seconds`. That nudges the model
to echo an awkward raw seconds count in the final reply, even though the
tool result already exposes structured usage fields like
`goal.timeUsedSeconds`, `goal.tokensUsed`, and `goal.tokenBudget`.

## What changed

- Replace the preformatted completion usage sentence with guidance to
read the structured goal fields from the tool result.
- Preserve token-budget reporting while allowing the model to phrase
elapsed time in a concise, human-friendly way that fits the response
language.
- Update core coverage for both the generated completion guidance and
the session flow that forwards it back to the model.

## Verification

Previously, it would have output a final message indicating that it
"worked for 303 seconds". Now it shows the following:

<img width="286" height="35" alt="image"
src="https://github.com/user-attachments/assets/d7011880-9449-46a7-856f-4e50ae00eb45"
/>
This commit is contained in:
Eric Traut
2026-05-16 11:49:40 -07:00
committed by GitHub
parent a280248021
commit 941e7f825e
2 changed files with 7 additions and 14 deletions

View File

@@ -8893,7 +8893,7 @@ async fn completed_goal_accounts_current_turn_tokens_before_tool_response() -> a
assert_eq!(complete_output["remainingTokens"], 0);
assert_eq!(
complete_output["completionBudgetReport"],
"Goal achieved. Report final budget usage to the user: tokens used: 580 of 500."
"Goal achieved. Report final usage from this tool result's structured goal fields. If `goal.tokenBudget` is present, include token usage from `goal.tokensUsed` and `goal.tokenBudget`. If `goal.timeUsedSeconds` is greater than 0, summarize elapsed time in a concise, human-friendly form appropriate to the response language."
);
let requests = responses.requests();
let completion_followup_request = requests

View File

@@ -87,20 +87,13 @@ fn goal_response(
}
fn completion_budget_report(goal: &ThreadGoal) -> Option<String> {
let mut parts = Vec::new();
if let Some(budget) = goal.token_budget {
parts.push(format!("tokens used: {} of {budget}", goal.tokens_used));
}
if goal.time_used_seconds > 0 {
parts.push(format!("time used: {} seconds", goal.time_used_seconds));
}
if parts.is_empty() {
if goal.token_budget.is_none() && goal.time_used_seconds <= 0 {
None
} else {
Some(format!(
"Goal achieved. Report final budget usage to the user: {}.",
parts.join("; ")
))
Some(
"Goal achieved. Report final usage from this tool result's structured goal fields. If `goal.tokenBudget` is present, include token usage from `goal.tokensUsed` and `goal.tokenBudget`. If `goal.timeUsedSeconds` is greater than 0, summarize elapsed time in a concise, human-friendly form appropriate to the response language."
.to_string(),
)
}
}
@@ -131,7 +124,7 @@ mod tests {
goal: Some(goal),
remaining_tokens: Some(6_750),
completion_budget_report: Some(
"Goal achieved. Report final budget usage to the user: tokens used: 3250 of 10000; time used: 75 seconds."
"Goal achieved. Report final usage from this tool result's structured goal fields. If `goal.tokenBudget` is present, include token usage from `goal.tokensUsed` and `goal.tokenBudget`. If `goal.timeUsedSeconds` is greater than 0, summarize elapsed time in a concise, human-friendly form appropriate to the response language."
.to_string()
),
}