mirror of
https://github.com/openai/codex.git
synced 2026-05-26 14:04:48 +00:00
## Why The goal extension needs more context when a turn starts than `turn_store` alone provides. In particular, goal accounting needs the stable turn id, the effective collaboration mode, and the cumulative token-usage baseline captured at turn start so it can: - suppress goal accounting for plan-mode turns - compute exact per-turn deltas from cumulative `total_token_usage` snapshots instead of relying on the most recent usage event alone - keep the extension-owned accounting path aligned with the host turn lifecycle ## What - extend `codex_extension_api::TurnStartInput` to expose `turn_id`, `collaboration_mode`, and `token_usage_at_turn_start` - pass the full `TurnContext` plus the captured token-usage baseline through the turn-start lifecycle emission path - initialize goal turn accounting from the turn-start baseline and collaboration mode - switch goal token accounting to compute deltas from cumulative `total_token_usage` snapshots - add coverage for the new turn-start lifecycle fields and for goal-accounting baseline behavior ## Testing - added `turn_start_lifecycle_exposes_turn_metadata_and_token_baseline` in `codex-rs/core/src/session/tests.rs` - added `ext/goal/tests/accounting.rs` coverage for baseline-aware goal accounting and plan-mode suppression
69 lines
1.8 KiB
Rust
69 lines
1.8 KiB
Rust
#![allow(dead_code)]
|
|
|
|
#[path = "../src/accounting.rs"]
|
|
mod accounting;
|
|
|
|
use accounting::GoalAccountingState;
|
|
use codex_protocol::config_types::ModeKind;
|
|
use codex_protocol::protocol::TokenUsage;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
#[test]
|
|
fn goal_accounting_uses_turn_start_baseline_for_exact_deltas() {
|
|
let state = GoalAccountingState::default();
|
|
state.start_turn(
|
|
"turn-1",
|
|
ModeKind::Default,
|
|
&token_usage(
|
|
/*input_tokens*/ 100, /*cached_input_tokens*/ 10, /*output_tokens*/ 30,
|
|
/*reasoning_output_tokens*/ 5, /*total_tokens*/ 135,
|
|
),
|
|
);
|
|
|
|
let recorded = state
|
|
.record_token_usage(
|
|
"turn-1",
|
|
&token_usage(
|
|
/*input_tokens*/ 120, /*cached_input_tokens*/ 14,
|
|
/*output_tokens*/ 42, /*reasoning_output_tokens*/ 8,
|
|
/*total_tokens*/ 162,
|
|
),
|
|
)
|
|
.expect("token delta should be recorded");
|
|
|
|
assert_eq!(28, recorded.turn_delta);
|
|
assert_eq!(28, recorded.thread_unflushed_delta);
|
|
}
|
|
|
|
#[test]
|
|
fn goal_accounting_ignores_plan_mode_turns() {
|
|
let state = GoalAccountingState::default();
|
|
state.start_turn("turn-1", ModeKind::Plan, &TokenUsage::default());
|
|
|
|
let recorded = state.record_token_usage(
|
|
"turn-1",
|
|
&token_usage(
|
|
/*input_tokens*/ 20, /*cached_input_tokens*/ 5, /*output_tokens*/ 8,
|
|
/*reasoning_output_tokens*/ 2, /*total_tokens*/ 30,
|
|
),
|
|
);
|
|
|
|
assert_eq!(None, recorded);
|
|
}
|
|
|
|
fn token_usage(
|
|
input_tokens: i64,
|
|
cached_input_tokens: i64,
|
|
output_tokens: i64,
|
|
reasoning_output_tokens: i64,
|
|
total_tokens: i64,
|
|
) -> TokenUsage {
|
|
TokenUsage {
|
|
input_tokens,
|
|
cached_input_tokens,
|
|
output_tokens,
|
|
reasoning_output_tokens,
|
|
total_tokens,
|
|
}
|
|
}
|