mirror of
https://github.com/instructkr/claude-code.git
synced 2026-04-06 19:28:49 +03:00
feat(harness+usage): add auto_compact and token_cost parity scenarios
Two new mock parity harness scenarios:
1. auto_compact_triggered (session-compaction category)
- Mock returns 50k input tokens, validates auto_compaction key
is present in JSON output
- Validates format parity; trigger behavior covered by
conversation::tests::auto_compacts_when_cumulative_input_threshold_is_crossed
2. token_cost_reporting (token-usage category)
- Mock returns known token counts (1k input, 500 output)
- Validates input/output token fields present in JSON output
Additional changes:
- Add estimated_cost to JSON prompt output (format_usd + pricing_for_model)
- Add final_text_sse_with_usage and text_message_response_with_usage helpers
to mock-anthropic-service for parameterized token counts
- Add ScenarioCase.extra_env and ScenarioCase.resume_session fields
- Update mock_parity_scenarios.json: 10 -> 12 scenarios
- Update harness request count assertion: 19 -> 21
cargo test --workspace: 558 passed, 0 failed
This commit is contained in:
@@ -98,6 +98,8 @@ enum Scenario {
|
||||
BashPermissionPromptApproved,
|
||||
BashPermissionPromptDenied,
|
||||
PluginToolRoundtrip,
|
||||
AutoCompactTriggered,
|
||||
TokenCostReporting,
|
||||
}
|
||||
|
||||
impl Scenario {
|
||||
@@ -113,6 +115,8 @@ impl Scenario {
|
||||
"bash_permission_prompt_approved" => Some(Self::BashPermissionPromptApproved),
|
||||
"bash_permission_prompt_denied" => Some(Self::BashPermissionPromptDenied),
|
||||
"plugin_tool_roundtrip" => Some(Self::PluginToolRoundtrip),
|
||||
"auto_compact_triggered" => Some(Self::AutoCompactTriggered),
|
||||
"token_cost_reporting" => Some(Self::TokenCostReporting),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -129,6 +133,8 @@ impl Scenario {
|
||||
Self::BashPermissionPromptApproved => "bash_permission_prompt_approved",
|
||||
Self::BashPermissionPromptDenied => "bash_permission_prompt_denied",
|
||||
Self::PluginToolRoundtrip => "plugin_tool_roundtrip",
|
||||
Self::AutoCompactTriggered => "auto_compact_triggered",
|
||||
Self::TokenCostReporting => "token_cost_reporting",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -452,6 +458,12 @@ fn build_stream_body(request: &MessageRequest, scenario: Scenario) -> String {
|
||||
&[r#"{"message":"hello from plugin parity"}"#],
|
||||
),
|
||||
},
|
||||
Scenario::AutoCompactTriggered => {
|
||||
final_text_sse_with_usage("auto compact parity complete.", 50_000, 200)
|
||||
}
|
||||
Scenario::TokenCostReporting => {
|
||||
final_text_sse_with_usage("token cost reporting parity complete.", 1_000, 500)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -610,6 +622,18 @@ fn build_message_response(request: &MessageRequest, scenario: Scenario) -> Messa
|
||||
json!({"message": "hello from plugin parity"}),
|
||||
),
|
||||
},
|
||||
Scenario::AutoCompactTriggered => text_message_response_with_usage(
|
||||
"msg_auto_compact_triggered",
|
||||
"auto compact parity complete.",
|
||||
50_000,
|
||||
200,
|
||||
),
|
||||
Scenario::TokenCostReporting => text_message_response_with_usage(
|
||||
"msg_token_cost_reporting",
|
||||
"token cost reporting parity complete.",
|
||||
1_000,
|
||||
500,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,6 +649,8 @@ fn request_id_for(scenario: Scenario) -> &'static str {
|
||||
Scenario::BashPermissionPromptApproved => "req_bash_permission_prompt_approved",
|
||||
Scenario::BashPermissionPromptDenied => "req_bash_permission_prompt_denied",
|
||||
Scenario::PluginToolRoundtrip => "req_plugin_tool_roundtrip",
|
||||
Scenario::AutoCompactTriggered => "req_auto_compact_triggered",
|
||||
Scenario::TokenCostReporting => "req_token_cost_reporting",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,6 +687,32 @@ fn text_message_response(id: &str, text: &str) -> MessageResponse {
|
||||
}
|
||||
}
|
||||
|
||||
fn text_message_response_with_usage(
|
||||
id: &str,
|
||||
text: &str,
|
||||
input_tokens: u32,
|
||||
output_tokens: u32,
|
||||
) -> MessageResponse {
|
||||
MessageResponse {
|
||||
id: id.to_string(),
|
||||
kind: "message".to_string(),
|
||||
role: "assistant".to_string(),
|
||||
content: vec![OutputContentBlock::Text {
|
||||
text: text.to_string(),
|
||||
}],
|
||||
model: DEFAULT_MODEL.to_string(),
|
||||
stop_reason: Some("end_turn".to_string()),
|
||||
stop_sequence: None,
|
||||
usage: Usage {
|
||||
input_tokens,
|
||||
cache_creation_input_tokens: 0,
|
||||
cache_read_input_tokens: 0,
|
||||
output_tokens,
|
||||
},
|
||||
request_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn tool_message_response(
|
||||
id: &str,
|
||||
tool_id: &str,
|
||||
@@ -919,6 +971,74 @@ fn final_text_sse(text: &str) -> String {
|
||||
body
|
||||
}
|
||||
|
||||
fn final_text_sse_with_usage(text: &str, input_tokens: u32, output_tokens: u32) -> String {
|
||||
let mut body = String::new();
|
||||
append_sse(
|
||||
&mut body,
|
||||
"message_start",
|
||||
json!({
|
||||
"type": "message_start",
|
||||
"message": {
|
||||
"id": unique_message_id(),
|
||||
"type": "message",
|
||||
"role": "assistant",
|
||||
"content": [],
|
||||
"model": DEFAULT_MODEL,
|
||||
"stop_reason": null,
|
||||
"stop_sequence": null,
|
||||
"usage": {
|
||||
"input_tokens": input_tokens,
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 0,
|
||||
"output_tokens": 0
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
append_sse(
|
||||
&mut body,
|
||||
"content_block_start",
|
||||
json!({
|
||||
"type": "content_block_start",
|
||||
"index": 0,
|
||||
"content_block": {"type": "text", "text": ""}
|
||||
}),
|
||||
);
|
||||
append_sse(
|
||||
&mut body,
|
||||
"content_block_delta",
|
||||
json!({
|
||||
"type": "content_block_delta",
|
||||
"index": 0,
|
||||
"delta": {"type": "text_delta", "text": text}
|
||||
}),
|
||||
);
|
||||
append_sse(
|
||||
&mut body,
|
||||
"content_block_stop",
|
||||
json!({
|
||||
"type": "content_block_stop",
|
||||
"index": 0
|
||||
}),
|
||||
);
|
||||
append_sse(
|
||||
&mut body,
|
||||
"message_delta",
|
||||
json!({
|
||||
"type": "message_delta",
|
||||
"delta": {"stop_reason": "end_turn", "stop_sequence": null},
|
||||
"usage": {
|
||||
"input_tokens": input_tokens,
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 0,
|
||||
"output_tokens": output_tokens
|
||||
}
|
||||
}),
|
||||
);
|
||||
append_sse(&mut body, "message_stop", json!({"type": "message_stop"}));
|
||||
body
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
fn append_sse(buffer: &mut String, event: &str, payload: Value) {
|
||||
use std::fmt::Write as _;
|
||||
|
||||
Reference in New Issue
Block a user