Skip to content
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions crates/goose-cli/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,16 @@ struct JsonOutput {

#[derive(Serialize, Deserialize, Debug)]
struct JsonMetadata {
/// Cumulative tokens across the whole session (sum of every LLM round-trip).
/// Mirrors `Session::accumulated_total_tokens`, **not** `Session::total_tokens`
/// (which is the last-turn context size and gets overwritten / reset on
/// compaction — see `update_session_metrics` in
/// `goose/src/agents/reply_parts.rs`).
total_tokens: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
input_tokens: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
output_tokens: Option<i32>,
status: String,
}

Expand All @@ -82,8 +91,15 @@ enum StreamEvent {
Error {
error: String,
},
/// Emitted once at end of a `goose run` in `--output-format stream-json`.
/// `total_tokens` is the **cumulative** session usage
/// (`Session::accumulated_total_tokens`), not the last-turn context size.
Complete {
total_tokens: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
input_tokens: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
output_tokens: Option<i32>,
},
}

Expand Down Expand Up @@ -1265,11 +1281,15 @@ impl CliSession {
.await
{
Ok(session) => JsonMetadata {
total_tokens: session.total_tokens,
total_tokens: session.accumulated_total_tokens.or(session.total_tokens),
input_tokens: session.accumulated_input_tokens.or(session.input_tokens),
output_tokens: session.accumulated_output_tokens.or(session.output_tokens),
status: "completed".to_string(),
},
Err(_) => JsonMetadata {
total_tokens: None,
input_tokens: None,
output_tokens: None,
status: "completed".to_string(),
},
};
Expand All @@ -1279,15 +1299,26 @@ impl CliSession {
};
println!("{}", serde_json::to_string_pretty(&json_output)?);
} else if is_stream_json_mode {
let total_tokens = self
let session = self
.agent
.config
.session_manager
.get_session(&self.session_id, false)
.await
.ok()
.and_then(|s| s.total_tokens);
emit_stream_event(&StreamEvent::Complete { total_tokens });
.ok();
let (total_tokens, input_tokens, output_tokens) = match session {
Some(s) => (
s.accumulated_total_tokens.or(s.total_tokens),
s.accumulated_input_tokens.or(s.input_tokens),
s.accumulated_output_tokens.or(s.output_tokens),
),
None => (None, None, None),
};
emit_stream_event(&StreamEvent::Complete {
total_tokens,
input_tokens,
output_tokens,
});
} else {
println!();
}
Expand Down
Loading