Skip to content

Commit 2c53e50

Browse files
committed
Works
1 parent abccd3e commit 2c53e50

File tree

19 files changed

+295
-74
lines changed

19 files changed

+295
-74
lines changed

codex-rs/core/src/codex.rs

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1941,6 +1941,7 @@ async fn try_run_turn(
19411941
call_id: String::new(),
19421942
output: FunctionCallOutputPayload {
19431943
content: msg.to_string(),
1944+
content_items: None,
19441945
success: None,
19451946
},
19461947
};
@@ -1955,6 +1956,7 @@ async fn try_run_turn(
19551956
call_id: String::new(),
19561957
output: FunctionCallOutputPayload {
19571958
content: message,
1959+
content_items: None,
19581960
success: None,
19591961
},
19601962
};
@@ -2093,41 +2095,6 @@ pub(super) fn get_last_assistant_message_from_turn(responses: &[ResponseItem]) -
20932095
}
20942096
})
20952097
}
2096-
pub(crate) fn convert_call_tool_result_to_function_call_output_payload(
2097-
call_tool_result: &CallToolResult,
2098-
) -> FunctionCallOutputPayload {
2099-
let CallToolResult {
2100-
content,
2101-
is_error,
2102-
structured_content,
2103-
} = call_tool_result;
2104-
2105-
// In terms of what to send back to the model, we prefer structured_content,
2106-
// if available, and fallback to content, otherwise.
2107-
let mut is_success = is_error != &Some(true);
2108-
let content = if let Some(structured_content) = structured_content
2109-
&& structured_content != &serde_json::Value::Null
2110-
&& let Ok(serialized_structured_content) = serde_json::to_string(&structured_content)
2111-
{
2112-
serialized_structured_content
2113-
} else {
2114-
match serde_json::to_string(&content) {
2115-
Ok(serialized_content) => serialized_content,
2116-
Err(err) => {
2117-
// If we could not serialize either content or structured_content to
2118-
// JSON, flag this as an error.
2119-
is_success = false;
2120-
err.to_string()
2121-
}
2122-
}
2123-
};
2124-
2125-
FunctionCallOutputPayload {
2126-
content,
2127-
success: Some(is_success),
2128-
}
2129-
}
2130-
21312098
/// Emits an ExitedReviewMode Event with optional ReviewOutput,
21322099
/// and records a developer message with the review output.
21332100
pub(crate) async fn exit_review_mode(
@@ -2312,13 +2279,14 @@ mod tests {
23122279
})),
23132280
};
23142281

2315-
let got = convert_call_tool_result_to_function_call_output_payload(&ctr);
2282+
let got = FunctionCallOutputPayload::from_call_tool_result(&ctr);
23162283
let expected = FunctionCallOutputPayload {
23172284
content: serde_json::to_string(&json!({
23182285
"ok": true,
23192286
"value": 42
23202287
}))
23212288
.unwrap(),
2289+
content_items: None,
23222290
success: Some(true),
23232291
};
23242292

@@ -2441,10 +2409,11 @@ mod tests {
24412409
structured_content: Some(serde_json::Value::Null),
24422410
};
24432411

2444-
let got = convert_call_tool_result_to_function_call_output_payload(&ctr);
2412+
let got = FunctionCallOutputPayload::from_call_tool_result(&ctr);
24452413
let expected = FunctionCallOutputPayload {
24462414
content: serde_json::to_string(&vec![text_block("hello"), text_block("world")])
24472415
.unwrap(),
2416+
content_items: None,
24482417
success: Some(true),
24492418
};
24502419

@@ -2459,9 +2428,10 @@ mod tests {
24592428
structured_content: Some(json!({ "message": "bad" })),
24602429
};
24612430

2462-
let got = convert_call_tool_result_to_function_call_output_payload(&ctr);
2431+
let got = FunctionCallOutputPayload::from_call_tool_result(&ctr);
24632432
let expected = FunctionCallOutputPayload {
24642433
content: serde_json::to_string(&json!({ "message": "bad" })).unwrap(),
2434+
content_items: None,
24652435
success: Some(false),
24662436
};
24672437

@@ -2476,9 +2446,10 @@ mod tests {
24762446
structured_content: None,
24772447
};
24782448

2479-
let got = convert_call_tool_result_to_function_call_output_payload(&ctr);
2449+
let got = FunctionCallOutputPayload::from_call_tool_result(&ctr);
24802450
let expected = FunctionCallOutputPayload {
24812451
content: serde_json::to_string(&vec![text_block("alpha")]).unwrap(),
2452+
content_items: None,
24822453
success: Some(true),
24832454
};
24842455

codex-rs/core/src/conversation_history.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ impl ConversationHistory {
107107
call_id: call_id.clone(),
108108
output: FunctionCallOutputPayload {
109109
content: "aborted".to_string(),
110+
content_items: None,
110111
success: None,
111112
},
112113
},
@@ -154,6 +155,7 @@ impl ConversationHistory {
154155
call_id: call_id.clone(),
155156
output: FunctionCallOutputPayload {
156157
content: "aborted".to_string(),
158+
content_items: None,
157159
success: None,
158160
},
159161
},
@@ -448,6 +450,7 @@ mod tests {
448450
call_id: "call-1".to_string(),
449451
output: FunctionCallOutputPayload {
450452
content: "ok".to_string(),
453+
content_items: None,
451454
success: None,
452455
},
453456
},
@@ -464,6 +467,7 @@ mod tests {
464467
call_id: "call-2".to_string(),
465468
output: FunctionCallOutputPayload {
466469
content: "ok".to_string(),
470+
content_items: None,
467471
success: None,
468472
},
469473
},
@@ -498,6 +502,7 @@ mod tests {
498502
call_id: "call-3".to_string(),
499503
output: FunctionCallOutputPayload {
500504
content: "ok".to_string(),
505+
content_items: None,
501506
success: None,
502507
},
503508
},
@@ -554,6 +559,7 @@ mod tests {
554559
call_id: "call-x".to_string(),
555560
output: FunctionCallOutputPayload {
556561
content: "aborted".to_string(),
562+
content_items: None,
557563
success: None,
558564
},
559565
},
@@ -631,6 +637,7 @@ mod tests {
631637
call_id: "shell-1".to_string(),
632638
output: FunctionCallOutputPayload {
633639
content: "aborted".to_string(),
640+
content_items: None,
634641
success: None,
635642
},
636643
},
@@ -645,6 +652,7 @@ mod tests {
645652
call_id: "orphan-1".to_string(),
646653
output: FunctionCallOutputPayload {
647654
content: "ok".to_string(),
655+
content_items: None,
648656
success: None,
649657
},
650658
}];
@@ -685,6 +693,7 @@ mod tests {
685693
call_id: "c2".to_string(),
686694
output: FunctionCallOutputPayload {
687695
content: "ok".to_string(),
696+
content_items: None,
688697
success: None,
689698
},
690699
},
@@ -727,6 +736,7 @@ mod tests {
727736
call_id: "c1".to_string(),
728737
output: FunctionCallOutputPayload {
729738
content: "aborted".to_string(),
739+
content_items: None,
730740
success: None,
731741
},
732742
},
@@ -757,6 +767,7 @@ mod tests {
757767
call_id: "s1".to_string(),
758768
output: FunctionCallOutputPayload {
759769
content: "aborted".to_string(),
770+
content_items: None,
760771
success: None,
761772
},
762773
},
@@ -822,6 +833,7 @@ mod tests {
822833
call_id: "orphan-1".to_string(),
823834
output: FunctionCallOutputPayload {
824835
content: "ok".to_string(),
836+
content_items: None,
825837
success: None,
826838
},
827839
}];
@@ -856,6 +868,7 @@ mod tests {
856868
call_id: "c2".to_string(),
857869
output: FunctionCallOutputPayload {
858870
content: "ok".to_string(),
871+
content_items: None,
859872
success: None,
860873
},
861874
},

codex-rs/core/src/mcp_tool_call.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub(crate) async fn handle_mcp_tool_call(
3434
call_id: call_id.clone(),
3535
output: FunctionCallOutputPayload {
3636
content: format!("err: {e}"),
37+
content_items: None,
3738
success: Some(false),
3839
},
3940
};

codex-rs/core/src/response_processing.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,11 @@ pub(crate) async fn process_items(
6060
items_to_record_in_conversation_history.push(item);
6161
let output = match result {
6262
Ok(call_tool_result) => {
63-
crate::codex::convert_call_tool_result_to_function_call_output_payload(
64-
call_tool_result,
65-
)
63+
FunctionCallOutputPayload::from_call_tool_result(call_tool_result)
6664
}
6765
Err(err) => FunctionCallOutputPayload {
6866
content: err.clone(),
67+
content_items: None,
6968
success: Some(false),
7069
},
7170
};

codex-rs/core/src/tools/context.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::tools::TELEMETRY_PREVIEW_MAX_LINES;
55
use crate::tools::TELEMETRY_PREVIEW_TRUNCATION_NOTICE;
66
use crate::turn_diff_tracker::TurnDiffTracker;
77
use codex_otel::otel_event_manager::OtelEventManager;
8+
use codex_protocol::models::FunctionCallOutputContentItem;
89
use codex_protocol::models::FunctionCallOutputPayload;
910
use codex_protocol::models::ResponseInputItem;
1011
use codex_protocol::models::ShellToolCallParams;
@@ -66,6 +67,7 @@ impl ToolPayload {
6667
pub enum ToolOutput {
6768
Function {
6869
content: String,
70+
content_items: Option<Vec<FunctionCallOutputContentItem>>,
6971
success: Option<bool>,
7072
},
7173
Mcp {
@@ -90,7 +92,11 @@ impl ToolOutput {
9092

9193
pub fn into_response(self, call_id: &str, payload: &ToolPayload) -> ResponseInputItem {
9294
match self {
93-
ToolOutput::Function { content, success } => {
95+
ToolOutput::Function {
96+
content,
97+
content_items,
98+
success,
99+
} => {
94100
if matches!(payload, ToolPayload::Custom { .. }) {
95101
ResponseInputItem::CustomToolCallOutput {
96102
call_id: call_id.to_string(),
@@ -99,7 +105,11 @@ impl ToolOutput {
99105
} else {
100106
ResponseInputItem::FunctionCallOutput {
101107
call_id: call_id.to_string(),
102-
output: FunctionCallOutputPayload { content, success },
108+
output: FunctionCallOutputPayload {
109+
content,
110+
content_items,
111+
success,
112+
},
103113
}
104114
}
105115
}
@@ -163,6 +173,7 @@ mod tests {
163173
};
164174
let response = ToolOutput::Function {
165175
content: "patched".to_string(),
176+
content_items: None,
166177
success: Some(true),
167178
}
168179
.into_response("call-42", &payload);
@@ -183,6 +194,7 @@ mod tests {
183194
};
184195
let response = ToolOutput::Function {
185196
content: "ok".to_string(),
197+
content_items: None,
186198
success: Some(true),
187199
}
188200
.into_response("fn-1", &payload);
@@ -191,6 +203,7 @@ mod tests {
191203
ResponseInputItem::FunctionCallOutput { call_id, output } => {
192204
assert_eq!(call_id, "fn-1");
193205
assert_eq!(output.content, "ok");
206+
assert!(output.content_items.is_none());
194207
assert_eq!(output.success, Some(true));
195208
}
196209
other => panic!("expected FunctionCallOutput, got {other:?}"),

codex-rs/core/src/tools/handlers/apply_patch.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ impl ToolHandler for ApplyPatchHandler {
8282
let content = item?;
8383
Ok(ToolOutput::Function {
8484
content,
85+
content_items: None,
8586
success: Some(true),
8687
})
8788
}
@@ -126,6 +127,7 @@ impl ToolHandler for ApplyPatchHandler {
126127
let content = emitter.finish(event_ctx, out).await?;
127128
Ok(ToolOutput::Function {
128129
content,
130+
content_items: None,
129131
success: Some(true),
130132
})
131133
}

codex-rs/core/src/tools/handlers/grep_files.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,13 @@ impl ToolHandler for GrepFilesHandler {
9090
if search_results.is_empty() {
9191
Ok(ToolOutput::Function {
9292
content: "No matches found.".to_string(),
93+
content_items: None,
9394
success: Some(false),
9495
})
9596
} else {
9697
Ok(ToolOutput::Function {
9798
content: search_results.join("\n"),
99+
content_items: None,
98100
success: Some(true),
99101
})
100102
}

codex-rs/core/src/tools/handlers/list_dir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ impl ToolHandler for ListDirHandler {
106106
output.extend(entries);
107107
Ok(ToolOutput::Function {
108108
content: output.join("\n"),
109+
content_items: None,
109110
success: Some(true),
110111
})
111112
}

codex-rs/core/src/tools/handlers/mcp.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,16 @@ impl ToolHandler for McpHandler {
5656
Ok(ToolOutput::Mcp { result })
5757
}
5858
codex_protocol::models::ResponseInputItem::FunctionCallOutput { output, .. } => {
59-
let codex_protocol::models::FunctionCallOutputPayload { content, success } = output;
60-
Ok(ToolOutput::Function { content, success })
59+
let codex_protocol::models::FunctionCallOutputPayload {
60+
content,
61+
content_items,
62+
success,
63+
} = output;
64+
Ok(ToolOutput::Function {
65+
content,
66+
content_items,
67+
success,
68+
})
6169
}
6270
_ => Err(FunctionCallError::RespondToModel(
6371
"mcp handler received unexpected response variant".to_string(),

0 commit comments

Comments
 (0)