Skip to content

Commit 0124f68

Browse files
Duncanwpfleger96
andcommitted
fix(agent): extend checked/unknown treatment to input/output token accumulation
input and output token accumulators used saturating_add throughout, while the PR's own total and cache counters already used checked_add with Unknown/Poisoned poison semantics (flagged by Wes's agent review). Introduce TurnIOState (Unseen | Exact(n) | Poisoned) in types.rs: - fold_round(n): overflow -> Poisoned, absence handled by caller - merge_session(turn): Poisoned poisons permanently; Exact checked-add - exact_value(): Some(n) only for Exact Wire changes: - accumulatedInputTokens / accumulatedOutputTokens: emitted only when Exact; omitted (never null, never u64::MAX) when Poisoned - used: saturating fallback to 0 for display-only proxy (ACP dead code) ACP changes: - UsageUpdatePayload.accumulated_{input,output}_tokens: Option<u64> with #[serde(default)] for backward compat; None = publisher-poisoned - absent field -> delta_reliable: false, null turn fields, null cumulative - SessionState.last_{input,output}: Option<u64> to match provenance - TurnUsage.cumulative_{input,output}_tokens: Option<u64> - pool.rs: pass through directly (TokenCounts fields already Option<u64>) - Box<UsageUpdatePayload> in GooseSessionUpdateVariant to satisfy clippy::large_enum_variant after struct grew with new doc+Option fields Tests added (426+686 pass): - TurnIOState unit tests: fold overflow, merge_session overflow, exact_value - wire: omit input/output when poisoned; emit when exact - ACP: absent input/output -> unreliable; goose payload unchanged; round-trip: poison mid-session -> subsequent turns stay unknown Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
1 parent ec9115d commit 0124f68

8 files changed

Lines changed: 836 additions & 147 deletions

File tree

crates/buzz-acp/src/acp.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,8 +1860,8 @@ impl AcpClient {
18601860
tracing::debug!(
18611861
target: "acp::usage",
18621862
session_id = %notif.session_id,
1863-
input = payload.accumulated_input_tokens,
1864-
output = payload.accumulated_output_tokens,
1863+
input = ?payload.accumulated_input_tokens,
1864+
output = ?payload.accumulated_output_tokens,
18651865
// A subset of `input`, logged so downstream accounting can
18661866
// price it at the provider's cached rate. Always emitted,
18671867
// including as 0, so a parser can tell "no cache hits"
@@ -4353,8 +4353,8 @@ mod tests {
43534353
assert_eq!(usage.session_id, "s1");
43544354
assert_eq!(usage.turn_seq, 1);
43554355
assert!(!usage.delta_reliable, "first turn must be unreliable");
4356-
assert_eq!(usage.cumulative_input_tokens, 1000);
4357-
assert_eq!(usage.cumulative_output_tokens, 200);
4356+
assert_eq!(usage.cumulative_input_tokens, Some(1000));
4357+
assert_eq!(usage.cumulative_output_tokens, Some(200));
43584358
assert_eq!(usage.cumulative_cost_usd, Some(0.01));
43594359

43604360
// Second take must be None.

crates/buzz-acp/src/pool.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3698,8 +3698,8 @@ pub(crate) fn build_turn_metric_counts(
36983698
None
36993699
};
37003700
let cumulative_counts = Some(TokenCounts {
3701-
input_tokens: Some(usage.cumulative_input_tokens),
3702-
output_tokens: Some(usage.cumulative_output_tokens),
3701+
input_tokens: usage.cumulative_input_tokens,
3702+
output_tokens: usage.cumulative_output_tokens,
37033703
// Present when every turn in the session reported a genuine provider
37043704
// total. None when the session has never emitted one or any turn lacked
37053705
// one. Never derived from input+output (NIP-AM MUST NOT).
@@ -6168,8 +6168,8 @@ mod tests {
61686168
turn_cost_usd: None,
61696169
turn_cache_read_tokens: None,
61706170
turn_cache_write_tokens: None,
6171-
cumulative_input_tokens: 100,
6172-
cumulative_output_tokens: 50,
6171+
cumulative_input_tokens: Some(100),
6172+
cumulative_output_tokens: Some(50),
61736173
cumulative_total_tokens: None,
61746174
cumulative_cost_usd: None,
61756175
cumulative_cache_read_tokens: None,
@@ -6207,8 +6207,8 @@ mod tests {
62076207
turn_cost_usd: Some(0.001),
62086208
turn_cache_read_tokens: None,
62096209
turn_cache_write_tokens: None,
6210-
cumulative_input_tokens: 200,
6211-
cumulative_output_tokens: 80,
6210+
cumulative_input_tokens: Some(200),
6211+
cumulative_output_tokens: Some(80),
62126212
cumulative_total_tokens: None,
62136213
cumulative_cost_usd: Some(0.001),
62146214
cumulative_cache_read_tokens: None,
@@ -6247,8 +6247,8 @@ mod tests {
62476247
turn_cost_usd: None,
62486248
turn_cache_read_tokens: None,
62496249
turn_cache_write_tokens: None,
6250-
cumulative_input_tokens: 150,
6251-
cumulative_output_tokens: 70,
6250+
cumulative_input_tokens: Some(150),
6251+
cumulative_output_tokens: Some(70),
62526252
cumulative_total_tokens: None,
62536253
cumulative_cost_usd: None,
62546254
cumulative_cache_read_tokens: None,
@@ -6287,8 +6287,8 @@ mod tests {
62876287
turn_cost_usd: None,
62886288
turn_cache_read_tokens: None,
62896289
turn_cache_write_tokens: None,
6290-
cumulative_input_tokens: 400,
6291-
cumulative_output_tokens: 100,
6290+
cumulative_input_tokens: Some(400),
6291+
cumulative_output_tokens: Some(100),
62926292
cumulative_total_tokens: None,
62936293
cumulative_cost_usd: None,
62946294
cumulative_cache_read_tokens: None,
@@ -6324,8 +6324,8 @@ mod tests {
63246324
turn_cost_usd: None,
63256325
turn_cache_read_tokens: None,
63266326
turn_cache_write_tokens: None,
6327-
cumulative_input_tokens: 500,
6328-
cumulative_output_tokens: 120,
6327+
cumulative_input_tokens: Some(500),
6328+
cumulative_output_tokens: Some(120),
63296329
cumulative_total_tokens: Some(620), // genuine cumulative total
63306330
cumulative_cost_usd: None,
63316331
cumulative_cache_read_tokens: None,
@@ -6376,8 +6376,8 @@ mod tests {
63766376
turn_cost_usd: None,
63776377
turn_cache_read_tokens: None,
63786378
turn_cache_write_tokens: None,
6379-
cumulative_input_tokens: 200,
6380-
cumulative_output_tokens: 60,
6379+
cumulative_input_tokens: Some(200),
6380+
cumulative_output_tokens: Some(60),
63816381
cumulative_total_tokens: None, // session has no total
63826382
cumulative_cost_usd: None,
63836383
cumulative_cache_read_tokens: None,

0 commit comments

Comments
 (0)