Record reasoning replay removal metrics (#61017)

## What changed

Parse reasoning removals from response `input_transformations` and carry the counts through completion events to sampling telemetry.

- Add `codex.responses.reasoning_replay` to distinguish unavailable reports, no reported removals, prefix mismatches, and other removals.
- Add `codex.responses.reasoning_items_removed` histograms by bounded removal reason, grouping unknown or missing reasons under `other`.
- Include zero counts for usable reports; exclude missing, null, or malformed reports from histograms without failing the response.
- Use the sampling step's session telemetry when recording response events.

## Testing

Add SSE and WebSocket integration coverage for report availability, removal counts, unknown reasons, zero observations, and `product_sku` tags in exported metrics.

GitOrigin-RevId: 83c70ca6067fa4b34bf5c463958b4632a7a0a188
This commit is contained in:
Alex Kira
2026-11-12 04:31:25 +00:00
committed by copyberry
parent b75ec48a2c
commit 64b8d019c8
12 changed files with 304 additions and 1 deletions
+2
View File
@@ -2842,6 +2842,7 @@ where
response_id,
token_usage,
usage_metadata,
reasoning_removals,
end_turn,
}) => {
feedback_tags!(last_model_response_id = &response_id);
@@ -2866,6 +2867,7 @@ where
response_id,
token_usage,
usage_metadata,
reasoning_removals,
end_turn,
}))
.await
+2
View File
@@ -1820,6 +1820,7 @@ async fn response_stream_records_last_model_feedback_ids() {
response_id: "resp-123".to_string(),
token_usage: None,
usage_metadata: None,
reasoning_removals: None,
end_turn: Some(true),
}),
]);
@@ -2864,6 +2865,7 @@ async fn intercepted_output_reaches_trace_and_websocket_bookkeeping() -> anyhow:
response_id: "response".into(),
token_usage: None,
usage_metadata: None,
reasoning_removals: None,
end_turn: None,
}))
.await?;
+2
View File
@@ -1433,6 +1433,7 @@ mod tests {
response_id: "resp-compact".into(),
token_usage: Some(usage.clone()),
usage_metadata: None,
reasoning_removals: None,
end_turn: Some(true),
})]);
let result = collect_compaction_output(
@@ -1485,6 +1486,7 @@ mod tests {
amount: Some("0.125".to_string()),
metadata: Some(serde_json::json!({ "extra": { "label": "example" } })),
}),
reasoning_removals: None,
end_turn: Some(true),
}),
]);
+2 -1
View File
@@ -3178,7 +3178,7 @@ async fn try_run_sampling_request(
let Some(event) = resampling.filter(event, &step_context.tool_router) else {
continue;
};
sess.services
step_context
.session_telemetry
.record_responses(&handle_responses, &event);
@@ -3532,6 +3532,7 @@ async fn try_run_sampling_request(
response_id,
token_usage,
usage_metadata,
reasoning_removals: _,
end_turn,
} => {
if let Some(accepted) = pending_audio.take() {