mirror of
https://github.com/openai/codex.git
synced 2026-11-09 20:50:33 +00:00
Allow deferring plain-text MCP output in thread item listings (#60390)
## What changed Add experimental `deferOutput.mcpToolCall` support to `thread/items/list` requests scoped to a `turnId`. Successful, completed MCP calls with nonempty, unannotated plain-text results can return empty `result.content` with `outputDeferred: true`. Clients can retrieve the saved output through `thread/items/read`; connector identity remains on the listed item. Keep rich results, JSON or fenced text, app UI results, and built-in `codex_app` results inline. Preserve plain-text output when creating bounded previews of oversized MCP results so those previews remain eligible for deferral. Reads return the saved preview when output exceeds the 64 KiB history limit. ## Testing Extend thread history integration coverage for independent and combined command/MCP deferral, experimental capability gating, excluded result types, connector identity, oversized previews, and retrieval of deferred items. GitOrigin-RevId: 5c160b30a4eac2a9b70e3fa65b6dbd83e935338b
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use codex_protocol::mcp::CallToolResult;
|
||||
use codex_protocol::mcp::plain_output_text;
|
||||
use codex_protocol::models::FunctionCallOutputBody;
|
||||
use codex_protocol::models::FunctionCallOutputContentItem;
|
||||
use codex_protocol::models::FunctionCallOutputPayload;
|
||||
@@ -72,7 +73,7 @@ pub fn truncate_mcp_tool_result(
|
||||
result: &CallToolResult,
|
||||
max_bytes: usize,
|
||||
) -> Cow<'_, CallToolResult> {
|
||||
let Ok(serialized) = serde_json::to_string(result) else {
|
||||
let Ok(mut serialized) = serde_json::to_string(result) else {
|
||||
return Cow::Borrowed(result);
|
||||
};
|
||||
if serialized.len() <= max_bytes {
|
||||
@@ -81,6 +82,26 @@ pub fn truncate_mcp_tool_result(
|
||||
|
||||
let meta = None;
|
||||
|
||||
// Keep plain output recognizable after truncation. Rich results retain their
|
||||
// serialized preview so history can distinguish them from plain output.
|
||||
if result.is_error != Some(true)
|
||||
&& result.structured_content.is_none()
|
||||
&& result.meta.is_none()
|
||||
&& let Some(blocks) = result
|
||||
.content
|
||||
.iter()
|
||||
.map(plain_output_text)
|
||||
.collect::<Option<Vec<_>>>()
|
||||
&& blocks.iter().any(|text| !text.is_empty())
|
||||
{
|
||||
serialized.clear();
|
||||
serialized.push_str("Truncated tool output:");
|
||||
for text in blocks {
|
||||
serialized.push('\n');
|
||||
serialized.push_str(text);
|
||||
}
|
||||
}
|
||||
|
||||
let mut preview_budget = max_bytes;
|
||||
loop {
|
||||
let preview = if preview_budget == 0 {
|
||||
|
||||
Reference in New Issue
Block a user