mirror of
https://github.com/openai/codex.git
synced 2026-10-21 17:48:44 +00:00
Attribute command and plugin analytics to the invoking model (#45445)
## Why Command execution and plugin measurement events lack model and reasoning-effort labels. Attribution needs to reflect the step that invoked the command, even when model settings change before a background process finishes. ## What changed - Add `model_slug` and `reasoning_effort` to command execution and plugin measurement analytics. - Capture model context from resolved step settings and carry it through execution, approval, Guardian review, and plugin metrics collection. - Preserve the first command-start model context when subsequent start notifications arrive. - Keep the carried context out of serialized protocol items and generated schemas. ## Testing Extend analytics tests to cover model switches before invocation and during background execution, default reasoning effort, Guardian-denied commands, and repeated start notifications retaining the original model context. GitOrigin-RevId: af90e1c0d39bab625f2e89786085b61a9b96c0ce
This commit is contained in:
@@ -97,6 +97,7 @@ pub fn build_command_execution_begin_item(payload: &ExecCommandBeginEvent) -> Th
|
||||
let presentation =
|
||||
CommandExecutionPresentation::from_raw(&payload.command, &payload.parsed_cmd, &payload.cwd);
|
||||
ThreadItem::CommandExecution {
|
||||
model_context: None,
|
||||
id: payload.call_id.clone(),
|
||||
plugin_id: payload.plugin_id.clone(),
|
||||
script_path: payload.script_path.clone(),
|
||||
@@ -123,6 +124,7 @@ pub fn build_command_execution_end_item(payload: &ExecCommandEndEvent) -> Thread
|
||||
CommandExecutionPresentation::from_raw(&payload.command, &payload.parsed_cmd, &payload.cwd);
|
||||
|
||||
ThreadItem::CommandExecution {
|
||||
model_context: None,
|
||||
id: payload.call_id.clone(),
|
||||
plugin_id: payload.plugin_id.clone(),
|
||||
script_path: payload.script_path.clone(),
|
||||
@@ -199,6 +201,7 @@ pub fn build_item_from_guardian_event(
|
||||
}];
|
||||
Some(ThreadItem::CommandExecution {
|
||||
id: id.clone(),
|
||||
model_context: assessment.model_context.clone(),
|
||||
plugin_id: assessment.plugin_id.clone(),
|
||||
script_path: assessment.script_path.clone(),
|
||||
command,
|
||||
@@ -237,6 +240,7 @@ pub fn build_item_from_guardian_event(
|
||||
};
|
||||
Some(ThreadItem::CommandExecution {
|
||||
id: id.clone(),
|
||||
model_context: assessment.model_context.clone(),
|
||||
plugin_id: assessment.plugin_id.clone(),
|
||||
script_path: assessment.script_path.clone(),
|
||||
command,
|
||||
|
||||
@@ -131,6 +131,7 @@ fn guardian_stdin_reviews_preserve_parent_command_history() {
|
||||
|
||||
let assessment = GuardianAssessmentEvent {
|
||||
review_reason: None,
|
||||
model_context: None,
|
||||
id: "review-stdin".into(),
|
||||
target_item_id: Some("terminal-command".into()),
|
||||
plugin_id: None,
|
||||
|
||||
@@ -2255,6 +2255,7 @@ mod tests {
|
||||
.to_string(),
|
||||
}];
|
||||
let command_item = CoreTurnItem::CommandExecution(CoreCommandExecutionItem {
|
||||
model_context: None,
|
||||
id: "exec-1".to_string(),
|
||||
plugin_id: Some("sample@openai-curated".to_string()),
|
||||
script_path: Some("scripts/run.py".to_string()),
|
||||
@@ -2340,6 +2341,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
build_turns_from_rollout_items(&items[..2])[0].items,
|
||||
vec![ThreadItem::CommandExecution {
|
||||
model_context: None,
|
||||
id: "exec-1".to_string(),
|
||||
plugin_id: Some("sample@openai-curated".to_string()),
|
||||
script_path: Some("scripts/run.py".to_string()),
|
||||
@@ -2365,6 +2367,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
turns[0].items,
|
||||
vec![ThreadItem::CommandExecution {
|
||||
model_context: None,
|
||||
id: "exec-1".to_string(),
|
||||
plugin_id: Some("sample@openai-curated".to_string()),
|
||||
script_path: Some("scripts/run.py".to_string()),
|
||||
@@ -3051,6 +3054,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
turns[0].items[2],
|
||||
ThreadItem::CommandExecution {
|
||||
model_context: None,
|
||||
id: "exec-1".into(),
|
||||
plugin_id: None,
|
||||
script_path: None,
|
||||
@@ -3321,6 +3325,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
turns[0].items[1],
|
||||
ThreadItem::CommandExecution {
|
||||
model_context: None,
|
||||
id: "exec-declined".into(),
|
||||
plugin_id: None,
|
||||
script_path: None,
|
||||
@@ -3372,6 +3377,7 @@ mod tests {
|
||||
}),
|
||||
EventMsg::GuardianAssessment(GuardianAssessmentEvent {
|
||||
review_reason: None,
|
||||
model_context: None,
|
||||
id: "review-guardian-exec".into(),
|
||||
target_item_id: Some("guardian-exec".into()),
|
||||
plugin_id: Some("sample@openai-curated".into()),
|
||||
@@ -3394,6 +3400,7 @@ mod tests {
|
||||
}),
|
||||
EventMsg::GuardianAssessment(GuardianAssessmentEvent {
|
||||
review_reason: None,
|
||||
model_context: None,
|
||||
id: "review-guardian-exec".into(),
|
||||
target_item_id: Some("guardian-exec".into()),
|
||||
plugin_id: Some("sample@openai-curated".into()),
|
||||
@@ -3428,6 +3435,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
turns[0].items[1],
|
||||
ThreadItem::CommandExecution {
|
||||
model_context: None,
|
||||
id: "guardian-exec".into(),
|
||||
plugin_id: Some("sample@openai-curated".into()),
|
||||
script_path: Some("scripts/run.py".into()),
|
||||
@@ -3467,6 +3475,7 @@ mod tests {
|
||||
}),
|
||||
EventMsg::GuardianAssessment(GuardianAssessmentEvent {
|
||||
review_reason: None,
|
||||
model_context: None,
|
||||
id: "review-guardian-execve".into(),
|
||||
target_item_id: Some("guardian-execve".into()),
|
||||
plugin_id: Some("sample@openai-curated".into()),
|
||||
@@ -3500,6 +3509,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
turns[0].items[1],
|
||||
ThreadItem::CommandExecution {
|
||||
model_context: None,
|
||||
id: "guardian-execve".into(),
|
||||
plugin_id: Some("sample@openai-curated".into()),
|
||||
script_path: Some("scripts/run.py".into()),
|
||||
@@ -3701,6 +3711,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
turns[0].items[1],
|
||||
ThreadItem::CommandExecution {
|
||||
model_context: None,
|
||||
id: "exec-late".into(),
|
||||
plugin_id: None,
|
||||
script_path: None,
|
||||
|
||||
@@ -287,6 +287,10 @@ pub enum ThreadItem {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase")]
|
||||
CommandExecution {
|
||||
#[serde(skip)]
|
||||
#[schemars(skip)]
|
||||
#[ts(skip)]
|
||||
model_context: Option<codex_protocol::items::ModelInvocationContext>,
|
||||
id: String,
|
||||
/// Trusted first-party plugin id when this command resolves to one plugin script.
|
||||
#[serde(default)]
|
||||
@@ -910,6 +914,7 @@ impl From<CoreTurnItem> for ThreadItem {
|
||||
);
|
||||
ThreadItem::CommandExecution {
|
||||
id: command.id,
|
||||
model_context: command.model_context,
|
||||
plugin_id: command.plugin_id,
|
||||
script_path: command.script_path,
|
||||
command: presentation.command,
|
||||
|
||||
@@ -3210,6 +3210,7 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
|
||||
);
|
||||
|
||||
let command_item = TurnItem::CommandExecution(CommandExecutionItem {
|
||||
model_context: None,
|
||||
id: "exec-1".to_string(),
|
||||
plugin_id: Some("sample@openai-curated".to_string()),
|
||||
script_path: Some("scripts/run.py".to_string()),
|
||||
@@ -3242,6 +3243,7 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
|
||||
assert_eq!(
|
||||
ThreadItem::from(command_item),
|
||||
ThreadItem::CommandExecution {
|
||||
model_context: None,
|
||||
id: "exec-1".to_string(),
|
||||
plugin_id: Some("sample@openai-curated".to_string()),
|
||||
script_path: Some("scripts/run.py".to_string()),
|
||||
|
||||
Reference in New Issue
Block a user