diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index f856b43d66..af6b790a38 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -15483,6 +15483,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/v2/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index c17efe7a45..987fa2c8b1 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -13369,6 +13369,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json index 0831483a32..19e277c9ef 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json @@ -199,6 +199,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -270,6 +334,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -285,6 +449,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -464,6 +701,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "TextElement": { "properties": { "byteRange": { @@ -589,6 +1468,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json index 16bfeece14..81960a5db5 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json @@ -199,6 +199,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -270,6 +334,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -285,6 +449,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -464,6 +701,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "TextElement": { "properties": { "byteRange": { @@ -589,6 +1468,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json index 16abcd7806..aca3f4a73a 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json @@ -336,6 +336,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -407,6 +471,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -422,6 +586,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -608,6 +845,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "TextElement": { "properties": { "byteRange": { @@ -733,6 +1612,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json index 653c5f2387..bd30e36af3 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json @@ -451,6 +451,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -718,6 +782,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "GitInfo": { "properties": { "branch": { @@ -756,6 +920,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -1078,6 +1315,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "SandboxPolicy": { "oneOf": [ { @@ -1559,6 +2438,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json index 2f5cbb9500..d465e60532 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json @@ -339,6 +339,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -410,6 +474,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "GitInfo": { "properties": { "branch": { @@ -448,6 +612,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -634,6 +871,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "SessionSource": { "oneOf": [ { @@ -1009,6 +1888,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json index b9ae59708a..706e82c7f0 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json @@ -339,6 +339,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -410,6 +474,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "GitInfo": { "properties": { "branch": { @@ -448,6 +612,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -634,6 +871,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "SessionSource": { "oneOf": [ { @@ -1009,6 +1888,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json index cda474c294..22dc28da1b 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json @@ -339,6 +339,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -410,6 +474,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "GitInfo": { "properties": { "branch": { @@ -448,6 +612,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -634,6 +871,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "SessionSource": { "oneOf": [ { @@ -1009,6 +1888,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json index 27cf47f2fc..937b94f484 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json @@ -451,6 +451,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -718,6 +782,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "GitInfo": { "properties": { "branch": { @@ -756,6 +920,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -1078,6 +1315,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "SandboxPolicy": { "oneOf": [ { @@ -1559,6 +2438,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json index e5339f4e99..99113987f5 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json @@ -339,6 +339,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -410,6 +474,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "GitInfo": { "properties": { "branch": { @@ -448,6 +612,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -634,6 +871,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "SessionSource": { "oneOf": [ { @@ -1009,6 +1888,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json index 7d93606aa4..ade1a17f09 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json @@ -451,6 +451,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -718,6 +782,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "GitInfo": { "properties": { "branch": { @@ -756,6 +920,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -1078,6 +1315,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "SandboxPolicy": { "oneOf": [ { @@ -1559,6 +2438,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json index 774686e46a..078c0d1670 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json @@ -339,6 +339,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -410,6 +474,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "GitInfo": { "properties": { "branch": { @@ -448,6 +612,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -634,6 +871,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "SessionSource": { "oneOf": [ { @@ -1009,6 +1888,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json index 64179af7e1..d9ed931ead 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json @@ -339,6 +339,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -410,6 +474,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "GitInfo": { "properties": { "branch": { @@ -448,6 +612,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -634,6 +871,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "SessionSource": { "oneOf": [ { @@ -1009,6 +1888,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json index 0739fa31bc..32426750c6 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json @@ -336,6 +336,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -407,6 +471,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -422,6 +586,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -608,6 +845,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "TextElement": { "properties": { "byteRange": { @@ -733,6 +1612,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json index bc5917ef15..c89fa7372b 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json @@ -336,6 +336,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -407,6 +471,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -422,6 +586,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -608,6 +845,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "TextElement": { "properties": { "byteRange": { @@ -733,6 +1612,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json index 22ad85d906..e71f05a6f9 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json @@ -336,6 +336,70 @@ ], "type": "string" }, + "ContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextContentItem", + "type": "object" + }, + { + "properties": { + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageContentItem", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "output_text" + ], + "title": "OutputTextContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "OutputTextContentItem", + "type": "object" + } + ] + }, "DynamicToolCallOutputContentItem": { "oneOf": [ { @@ -407,6 +471,106 @@ ], "type": "object" }, + "FunctionCallOutputBody": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "$ref": "#/definitions/FunctionCallOutputContentItem" + }, + "type": "array" + } + ] + }, + "FunctionCallOutputContentItem": { + "description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.", + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "input_text" + ], + "title": "InputTextFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextFunctionCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "detail": { + "anyOf": [ + { + "$ref": "#/definitions/ImageDetail" + }, + { + "type": "null" + } + ] + }, + "image_url": { + "type": "string" + }, + "type": { + "enum": [ + "input_image" + ], + "title": "InputImageFunctionCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "image_url", + "type" + ], + "title": "InputImageFunctionCallOutputContentItem", + "type": "object" + } + ] + }, + "GhostCommit": { + "description": "Details of a ghost commit created from a repository state.", + "properties": { + "id": { + "type": "string" + }, + "parent": { + "type": [ + "string", + "null" + ] + }, + "preexisting_untracked_dirs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preexisting_untracked_files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "id", + "preexisting_untracked_dirs", + "preexisting_untracked_files" + ], + "type": "object" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -422,6 +586,79 @@ ], "type": "object" }, + "ImageDetail": { + "enum": [ + "auto", + "low", + "high", + "original" + ], + "type": "string" + }, + "LocalShellAction": { + "oneOf": [ + { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + }, + "env": { + "additionalProperties": { + "type": "string" + }, + "type": [ + "object", + "null" + ] + }, + "timeout_ms": { + "format": "uint64", + "minimum": 0.0, + "type": [ + "integer", + "null" + ] + }, + "type": { + "enum": [ + "exec" + ], + "title": "ExecLocalShellActionType", + "type": "string" + }, + "user": { + "type": [ + "string", + "null" + ] + }, + "working_directory": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "command", + "type" + ], + "title": "ExecLocalShellAction", + "type": "object" + } + ] + }, + "LocalShellStatus": { + "enum": [ + "completed", + "in_progress", + "incomplete" + ], + "type": "string" + }, "McpToolCallError": { "properties": { "message": { @@ -608,6 +845,648 @@ ], "type": "string" }, + "ReasoningItemContent": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "reasoning_text" + ], + "title": "ReasoningTextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "ReasoningTextReasoningItemContent", + "type": "object" + }, + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "text" + ], + "title": "TextReasoningItemContentType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "TextReasoningItemContent", + "type": "object" + } + ] + }, + "ReasoningItemReasoningSummary": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "summary_text" + ], + "title": "SummaryTextReasoningItemReasoningSummaryType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "SummaryTextReasoningItemReasoningSummary", + "type": "object" + } + ] + }, + "ResponseItem": { + "oneOf": [ + { + "properties": { + "content": { + "items": { + "$ref": "#/definitions/ContentItem" + }, + "type": "array" + }, + "end_turn": { + "type": [ + "boolean", + "null" + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "phase": { + "anyOf": [ + { + "$ref": "#/definitions/MessagePhase" + }, + { + "type": "null" + } + ] + }, + "role": { + "type": "string" + }, + "type": { + "enum": [ + "message" + ], + "title": "MessageResponseItemType", + "type": "string" + } + }, + "required": [ + "content", + "role", + "type" + ], + "title": "MessageResponseItem", + "type": "object" + }, + { + "properties": { + "content": { + "default": null, + "items": { + "$ref": "#/definitions/ReasoningItemContent" + }, + "type": [ + "array", + "null" + ] + }, + "encrypted_content": { + "type": [ + "string", + "null" + ] + }, + "summary": { + "items": { + "$ref": "#/definitions/ReasoningItemReasoningSummary" + }, + "type": "array" + }, + "type": { + "enum": [ + "reasoning" + ], + "title": "ReasoningResponseItemType", + "type": "string" + } + }, + "required": [ + "summary", + "type" + ], + "title": "ReasoningResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "$ref": "#/definitions/LocalShellAction" + }, + "call_id": { + "description": "Set when using the Responses API.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Legacy id field retained for compatibility with older payloads.", + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "$ref": "#/definitions/LocalShellStatus" + }, + "type": { + "enum": [ + "local_shell_call" + ], + "title": "LocalShellCallResponseItemType", + "type": "string" + } + }, + "required": [ + "action", + "status", + "type" + ], + "title": "LocalShellCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": { + "type": "string" + }, + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "name": { + "type": "string" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "function_call" + ], + "title": "FunctionCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "name", + "type" + ], + "title": "FunctionCallResponseItem", + "type": "object" + }, + { + "properties": { + "arguments": true, + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "tool_search_call" + ], + "title": "ToolSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "execution", + "type" + ], + "title": "ToolSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "function_call_output" + ], + "title": "FunctionCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "FunctionCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "input": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "custom_tool_call" + ], + "title": "CustomToolCallResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "input", + "name", + "type" + ], + "title": "CustomToolCallResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "output": { + "$ref": "#/definitions/FunctionCallOutputBody" + }, + "type": { + "enum": [ + "custom_tool_call_output" + ], + "title": "CustomToolCallOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "call_id", + "output", + "type" + ], + "title": "CustomToolCallOutputResponseItem", + "type": "object" + }, + { + "properties": { + "call_id": { + "type": [ + "string", + "null" + ] + }, + "execution": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tools": { + "items": true, + "type": "array" + }, + "type": { + "enum": [ + "tool_search_output" + ], + "title": "ToolSearchOutputResponseItemType", + "type": "string" + } + }, + "required": [ + "execution", + "status", + "tools", + "type" + ], + "title": "ToolSearchOutputResponseItem", + "type": "object" + }, + { + "properties": { + "action": { + "anyOf": [ + { + "$ref": "#/definitions/ResponsesApiWebSearchAction" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": [ + "string", + "null" + ], + "writeOnly": true + }, + "status": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "web_search_call" + ], + "title": "WebSearchCallResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "WebSearchCallResponseItem", + "type": "object" + }, + { + "properties": { + "id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "revised_prompt": { + "type": [ + "string", + "null" + ] + }, + "status": { + "type": "string" + }, + "type": { + "enum": [ + "image_generation_call" + ], + "title": "ImageGenerationCallResponseItemType", + "type": "string" + } + }, + "required": [ + "id", + "result", + "status", + "type" + ], + "title": "ImageGenerationCallResponseItem", + "type": "object" + }, + { + "properties": { + "ghost_commit": { + "$ref": "#/definitions/GhostCommit" + }, + "type": { + "enum": [ + "ghost_snapshot" + ], + "title": "GhostSnapshotResponseItemType", + "type": "string" + } + }, + "required": [ + "ghost_commit", + "type" + ], + "title": "GhostSnapshotResponseItem", + "type": "object" + }, + { + "properties": { + "encrypted_content": { + "type": "string" + }, + "type": { + "enum": [ + "compaction" + ], + "title": "CompactionResponseItemType", + "type": "string" + } + }, + "required": [ + "encrypted_content", + "type" + ], + "title": "CompactionResponseItem", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponseItemType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponseItem", + "type": "object" + } + ] + }, + "ResponsesApiWebSearchAction": { + "oneOf": [ + { + "properties": { + "queries": { + "items": { + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "query": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "search" + ], + "title": "SearchResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "SearchResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "open_page" + ], + "title": "OpenPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "OpenPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "pattern": { + "type": [ + "string", + "null" + ] + }, + "type": { + "enum": [ + "find_in_page" + ], + "title": "FindInPageResponsesApiWebSearchActionType", + "type": "string" + }, + "url": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "type" + ], + "title": "FindInPageResponsesApiWebSearchAction", + "type": "object" + }, + { + "properties": { + "type": { + "enum": [ + "other" + ], + "title": "OtherResponsesApiWebSearchActionType", + "type": "string" + } + }, + "required": [ + "type" + ], + "title": "OtherResponsesApiWebSearchAction", + "type": "object" + } + ] + }, "TextElement": { "properties": { "byteRange": { @@ -733,6 +1612,30 @@ "title": "AgentMessageThreadItem", "type": "object" }, + { + "properties": { + "id": { + "type": "string" + }, + "item": { + "$ref": "#/definitions/ResponseItem" + }, + "type": { + "enum": [ + "rawResponseItem" + ], + "title": "RawResponseItemThreadItemType", + "type": "string" + } + }, + "required": [ + "id", + "item", + "type" + ], + "title": "RawResponseItemThreadItem", + "type": "object" + }, { "description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.", "properties": { diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts index f7880c9d32..cbd50b71f2 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts @@ -4,6 +4,7 @@ import type { AbsolutePathBuf } from "../AbsolutePathBuf"; import type { MessagePhase } from "../MessagePhase"; import type { ReasoningEffort } from "../ReasoningEffort"; +import type { ResponseItem } from "../ResponseItem"; import type { JsonValue } from "../serde_json/JsonValue"; import type { CollabAgentState } from "./CollabAgentState"; import type { CollabAgentTool } from "./CollabAgentTool"; @@ -23,7 +24,7 @@ import type { PatchApplyStatus } from "./PatchApplyStatus"; import type { UserInput } from "./UserInput"; import type { WebSearchAction } from "./WebSearchAction"; -export type ThreadItem = { "type": "userMessage", id: string, content: Array, } | { "type": "hookPrompt", id: string, fragments: Array, } | { "type": "agentMessage", id: string, text: string, phase: MessagePhase | null, memoryCitation: MemoryCitation | null, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array, content: Array, } | { "type": "commandExecution", id: string, +export type ThreadItem = { "type": "userMessage", id: string, content: Array, } | { "type": "hookPrompt", id: string, fragments: Array, } | { "type": "agentMessage", id: string, text: string, phase: MessagePhase | null, memoryCitation: MemoryCitation | null, } | { "type": "rawResponseItem", id: string, item: ResponseItem, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array, content: Array, } | { "type": "commandExecution", id: string, /** * The command to be executed. */ diff --git a/codex-rs/app-server-protocol/src/protocol/thread_history.rs b/codex-rs/app-server-protocol/src/protocol/thread_history.rs index 64307c24bf..bc486df237 100644 --- a/codex-rs/app-server-protocol/src/protocol/thread_history.rs +++ b/codex-rs/app-server-protocol/src/protocol/thread_history.rs @@ -37,6 +37,7 @@ use codex_protocol::protocol::GuardianAssessmentEvent; use codex_protocol::protocol::GuardianAssessmentStatus; use codex_protocol::protocol::ImageGenerationBeginEvent; use codex_protocol::protocol::ImageGenerationEndEvent; +use codex_protocol::protocol::InterAgentCommunication; use codex_protocol::protocol::ItemCompletedEvent; use codex_protocol::protocol::ItemStartedEvent; use codex_protocol::protocol::McpToolCallBeginEvent; @@ -244,6 +245,13 @@ impl ThreadHistoryBuilder { }; if role != "user" { + if InterAgentCommunication::is_message_content(content) { + let id = id.clone().unwrap_or_else(|| self.next_item_id()); + self.ensure_turn().items.push(ThreadItem::RawResponseItem { + id, + item: item.clone(), + }); + } return; } @@ -1191,6 +1199,7 @@ impl From<&PendingTurn> for Turn { mod tests { use super::*; use crate::protocol::v2::CommandExecutionSource; + use codex_protocol::AgentPath; use codex_protocol::ThreadId; use codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem as CoreDynamicToolCallOutputContentItem; use codex_protocol::items::HookPromptFragment as CoreHookPromptFragment; @@ -1210,6 +1219,7 @@ mod tests { use codex_protocol::protocol::DynamicToolCallResponseEvent; use codex_protocol::protocol::ExecCommandEndEvent; use codex_protocol::protocol::ExecCommandSource; + use codex_protocol::protocol::InterAgentCommunication; use codex_protocol::protocol::ItemStartedEvent; use codex_protocol::protocol::McpInvocation; use codex_protocol::protocol::McpToolCallEndEvent; @@ -2828,6 +2838,99 @@ mod tests { ); } + #[test] + fn reconstructs_inter_agent_raw_response_item_between_watchdog_spawn_and_close() { + let sender_thread_id = ThreadId::try_from("00000000-0000-0000-0000-000000000001") + .expect("valid sender thread id"); + let watchdog_thread_id = ThreadId::try_from("00000000-0000-0000-0000-000000000002") + .expect("valid watchdog thread id"); + let communication = InterAgentCommunication::new( + AgentPath::try_from("/root/watchdog").expect("valid agent path"), + AgentPath::root(), + Vec::new(), + "goodbye".to_string(), + /*trigger_turn*/ true, + ); + let response_item: codex_protocol::models::ResponseItem = + communication.to_response_input_item().into(); + let items = vec![ + RolloutItem::EventMsg(EventMsg::CollabAgentSpawnEnd( + codex_protocol::protocol::CollabAgentSpawnEndEvent { + call_id: "spawn-watchdog".into(), + sender_thread_id, + new_thread_id: Some(watchdog_thread_id), + new_agent_nickname: Some("Boyle".into()), + new_agent_role: Some("watchdog".into()), + prompt: "Every time you start, respond with goodbye.".into(), + model: "arcanine 1m".into(), + reasoning_effort: codex_protocol::openai_models::ReasoningEffort::Low, + status: AgentStatus::PendingInit, + }, + )), + RolloutItem::ResponseItem(response_item.clone()), + RolloutItem::EventMsg(EventMsg::CollabCloseEnd( + codex_protocol::protocol::CollabCloseEndEvent { + call_id: "watchdog-close".into(), + sender_thread_id, + receiver_thread_id: watchdog_thread_id, + receiver_agent_nickname: Some("Boyle".into()), + receiver_agent_role: Some("watchdog".into()), + status: AgentStatus::Completed(Some("goodbye".into())), + }, + )), + ]; + + let turns = build_turns_from_rollout_items(&items); + assert_eq!(turns.len(), 1); + assert_eq!( + turns[0].items, + vec![ + ThreadItem::CollabAgentToolCall { + id: "spawn-watchdog".into(), + tool: CollabAgentTool::SpawnAgent, + status: CollabAgentToolCallStatus::Completed, + sender_thread_id: sender_thread_id.to_string(), + receiver_thread_ids: vec![watchdog_thread_id.to_string()], + prompt: Some("Every time you start, respond with goodbye.".into()), + model: Some("arcanine 1m".into()), + reasoning_effort: Some(codex_protocol::openai_models::ReasoningEffort::Low), + agents_states: [( + watchdog_thread_id.to_string(), + CollabAgentState { + status: crate::protocol::v2::CollabAgentStatus::PendingInit, + message: None, + }, + )] + .into_iter() + .collect(), + }, + ThreadItem::RawResponseItem { + id: "item-1".into(), + item: response_item, + }, + ThreadItem::CollabAgentToolCall { + id: "watchdog-close".into(), + tool: CollabAgentTool::CloseAgent, + status: CollabAgentToolCallStatus::Completed, + sender_thread_id: sender_thread_id.to_string(), + receiver_thread_ids: vec![watchdog_thread_id.to_string()], + prompt: None, + model: None, + reasoning_effort: None, + agents_states: [( + watchdog_thread_id.to_string(), + CollabAgentState { + status: crate::protocol::v2::CollabAgentStatus::Completed, + message: Some("goodbye".into()), + }, + )] + .into_iter() + .collect(), + }, + ], + ); + } + #[test] fn reconstructs_interrupted_send_input_as_completed_collab_call() { // `send_input(interrupt=true)` first stops the child's active turn, then redirects it with diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 963ac69000..91411b46aa 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -5880,6 +5880,9 @@ pub enum ThreadItem { }, #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] + RawResponseItem { id: String, item: ResponseItem }, + #[serde(rename_all = "camelCase")] + #[ts(rename_all = "camelCase")] /// EXPERIMENTAL - proposed plan item content. The completed plan item is /// authoritative and may not match the concatenation of `PlanDelta` text. Plan { id: String, text: String }, @@ -6024,6 +6027,7 @@ impl ThreadItem { ThreadItem::UserMessage { id, .. } | ThreadItem::HookPrompt { id, .. } | ThreadItem::AgentMessage { id, .. } + | ThreadItem::RawResponseItem { id, .. } | ThreadItem::Plan { id, .. } | ThreadItem::Reasoning { id, .. } | ThreadItem::CommandExecution { id, .. } diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index dab47ec3a2..210de0733f 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -1138,6 +1138,7 @@ Today both notifications carry an empty `items` array even when item events were - `userMessage` — `{id, content}` where `content` is a list of user inputs (`text`, `image`, or `localImage`). - `agentMessage` — `{id, text}` containing the accumulated agent reply. +- `rawResponseItem` — `{id, item}` for selected persisted Responses API items that clients need to replay exactly, such as inter-agent messages restored by `thread/read`, `thread/resume`, and `thread/fork`. Live streams deliver the same item shape through `rawResponseItem/completed`. - `plan` — `{id, text}` emitted for plan-mode turns; plan text can stream via `item/plan/delta` (experimental). - `reasoning` — `{id, summary, content}` where `summary` holds streamed reasoning summaries (applicable for most OpenAI models) and `content` holds raw reasoning blocks (applicable for e.g. open source models). - `commandExecution` — `{id, command, cwd, status, commandActions, aggregatedOutput?, exitCode?, durationMs?}` for sandboxed commands; `status` is `inProgress`, `completed`, `failed`, or `declined`. diff --git a/codex-rs/app-server/src/bespoke_event_handling.rs b/codex-rs/app-server/src/bespoke_event_handling.rs index e702152356..646b7d77d3 100644 --- a/codex-rs/app-server/src/bespoke_event_handling.rs +++ b/codex-rs/app-server/src/bespoke_event_handling.rs @@ -2092,6 +2092,7 @@ mod tests { use codex_app_server_protocol::TurnPlanStepStatus; use codex_login::AuthManager; use codex_login::CodexAuth; + use codex_protocol::AgentPath; use codex_protocol::items::HookPromptFragment; use codex_protocol::items::build_hook_prompt_message; use codex_protocol::models::FileSystemPermissions as CoreFileSystemPermissions; @@ -2105,6 +2106,7 @@ mod tests { use codex_protocol::protocol::CreditsSnapshot; use codex_protocol::protocol::GuardianAssessmentEvent; use codex_protocol::protocol::GuardianAssessmentStatus; + use codex_protocol::protocol::InterAgentCommunication; use codex_protocol::protocol::RateLimitSnapshot; use codex_protocol::protocol::RateLimitWindow; use codex_protocol::protocol::TokenUsage; @@ -3675,4 +3677,45 @@ mod tests { assert!(rx.try_recv().is_err(), "no extra messages expected"); Ok(()) } + + #[tokio::test] + async fn test_inter_agent_raw_response_emits_raw_response_item_completed() -> Result<()> { + let (tx, mut rx) = mpsc::channel(CHANNEL_CAPACITY); + let outgoing = Arc::new(OutgoingMessageSender::new( + tx, + codex_analytics::AnalyticsEventsClient::disabled(), + )); + let conversation_id = ThreadId::new(); + let outgoing = ThreadScopedOutgoingMessageSender::new( + outgoing, + vec![ConnectionId(1)], + conversation_id, + ); + let communication = InterAgentCommunication::new( + AgentPath::try_from("/root/watchdog").expect("valid agent path"), + AgentPath::root(), + Vec::new(), + "ping 21 (21)".to_string(), + /*trigger_turn*/ true, + ); + let item: codex_protocol::models::ResponseItem = + communication.to_response_input_item().into(); + + maybe_emit_raw_response_item_completed(conversation_id, "turn-1", item.clone(), &outgoing) + .await; + + let msg = recv_broadcast_message(&mut rx).await?; + match msg { + OutgoingMessage::AppServerNotification( + ServerNotification::RawResponseItemCompleted(notification), + ) => { + assert_eq!(notification.thread_id, conversation_id.to_string()); + assert_eq!(notification.turn_id, "turn-1"); + assert_eq!(notification.item, item); + } + other => bail!("unexpected message: {other:?}"), + } + assert!(rx.try_recv().is_err(), "no extra messages expected"); + Ok(()) + } } diff --git a/codex-rs/app-server/tests/suite/v2/thread_resume.rs b/codex-rs/app-server/tests/suite/v2/thread_resume.rs index 48673387b8..057e45783e 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_resume.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_resume.rs @@ -15,6 +15,10 @@ use app_test_support::to_response; use app_test_support::write_chatgpt_auth; use chrono::Utc; use codex_app_server_protocol::AskForApproval; +use codex_app_server_protocol::CollabAgentState; +use codex_app_server_protocol::CollabAgentStatus; +use codex_app_server_protocol::CollabAgentTool; +use codex_app_server_protocol::CollabAgentToolCallStatus; use codex_app_server_protocol::CommandExecutionApprovalDecision; use codex_app_server_protocol::CommandExecutionRequestApprovalResponse; use codex_app_server_protocol::FileChangeApprovalDecision; @@ -47,12 +51,20 @@ use codex_app_server_protocol::TurnStatus; use codex_app_server_protocol::UserInput; use codex_config::types::AuthCredentialsStoreMode; use codex_login::REFRESH_TOKEN_URL_OVERRIDE_ENV_VAR; +use codex_protocol::AgentPath; use codex_protocol::ThreadId; use codex_protocol::config_types::Personality; use codex_protocol::models::ContentItem; use codex_protocol::models::ResponseItem; +use codex_protocol::openai_models::ReasoningEffort; use codex_protocol::protocol::AgentMessageEvent; +use codex_protocol::protocol::AgentStatus; +use codex_protocol::protocol::CollabAgentSpawnEndEvent; +use codex_protocol::protocol::CollabCloseEndEvent; use codex_protocol::protocol::EventMsg; +use codex_protocol::protocol::InterAgentCommunication; +use codex_protocol::protocol::RolloutItem; +use codex_protocol::protocol::RolloutLine; use codex_protocol::protocol::SessionMeta; use codex_protocol::protocol::SessionMetaLine; use codex_protocol::protocol::SessionSource as RolloutSessionSource; @@ -2669,6 +2681,145 @@ async fn thread_resume_supports_history_and_overrides() -> Result<()> { Ok(()) } +#[tokio::test] +async fn thread_resume_reconstructs_inter_agent_raw_item_and_closed_watchdog() -> Result<()> { + let server = create_mock_responses_server_repeating_assistant("Done").await; + let codex_home = TempDir::new()?; + create_config_toml(codex_home.path(), &server.uri())?; + + let filename_ts = "2025-01-05T12-00-00"; + let meta_rfc3339 = "2025-01-05T12:00:00Z"; + let conversation_id = create_fake_rollout_with_text_elements( + codex_home.path(), + filename_ts, + meta_rfc3339, + "Saved user message", + Vec::new(), + Some("mock_provider"), + /*git_info*/ None, + )?; + let rollout_file_path = rollout_path(codex_home.path(), filename_ts, &conversation_id); + let persisted_rollout = std::fs::read_to_string(&rollout_file_path)?; + let sender_thread_id = ThreadId::from_string("019cff70-2599-75e2-af72-b90000001002") + .expect("valid sender thread id"); + let watchdog_thread_id = ThreadId::from_string("019cff70-2599-75e2-af72-b90000001003") + .expect("valid watchdog thread id"); + let communication = InterAgentCommunication::new( + AgentPath::try_from("/root/watchdog").expect("valid agent path"), + AgentPath::root(), + Vec::new(), + "goodbye".to_string(), + /*trigger_turn*/ true, + ); + let raw_response_item: ResponseItem = communication.to_response_input_item().into(); + let appended_rollout = [ + RolloutLine { + timestamp: meta_rfc3339.to_string(), + item: RolloutItem::EventMsg(EventMsg::CollabAgentSpawnEnd(CollabAgentSpawnEndEvent { + call_id: "spawn-watchdog".to_string(), + sender_thread_id, + new_thread_id: Some(watchdog_thread_id), + new_agent_nickname: Some("Boyle".to_string()), + new_agent_role: Some("watchdog".to_string()), + prompt: "Every time you start, respond with goodbye.".to_string(), + model: "arcanine 1m".to_string(), + reasoning_effort: ReasoningEffort::Low, + status: AgentStatus::PendingInit, + })), + }, + RolloutLine { + timestamp: meta_rfc3339.to_string(), + item: RolloutItem::ResponseItem(raw_response_item.clone()), + }, + RolloutLine { + timestamp: meta_rfc3339.to_string(), + item: RolloutItem::EventMsg(EventMsg::CollabCloseEnd(CollabCloseEndEvent { + call_id: "watchdog-close".to_string(), + sender_thread_id, + receiver_thread_id: watchdog_thread_id, + receiver_agent_nickname: Some("Boyle".to_string()), + receiver_agent_role: Some("watchdog".to_string()), + status: AgentStatus::Completed(Some("goodbye".to_string())), + })), + }, + ] + .into_iter() + .map(|line| serde_json::to_string(&line)) + .collect::, _>>()? + .join("\n"); + std::fs::write( + &rollout_file_path, + format!("{persisted_rollout}{appended_rollout}\n"), + )?; + + let mut mcp = McpProcess::new(codex_home.path()).await?; + timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; + + let resume_id = mcp + .send_thread_resume_request(ThreadResumeParams { + thread_id: conversation_id, + ..Default::default() + }) + .await?; + let resume_resp: JSONRPCResponse = timeout( + DEFAULT_READ_TIMEOUT, + mcp.read_stream_until_response_message(RequestId::Integer(resume_id)), + ) + .await??; + let ThreadResumeResponse { thread, .. } = to_response::(resume_resp)?; + + let reconstructed_turn = thread.turns.last().expect("reconstructed watchdog turn"); + assert_eq!( + reconstructed_turn.items[1..], + vec![ + ThreadItem::CollabAgentToolCall { + id: "spawn-watchdog".to_string(), + tool: CollabAgentTool::SpawnAgent, + status: CollabAgentToolCallStatus::Completed, + sender_thread_id: sender_thread_id.to_string(), + receiver_thread_ids: vec![watchdog_thread_id.to_string()], + prompt: Some("Every time you start, respond with goodbye.".to_string()), + model: Some("arcanine 1m".to_string()), + reasoning_effort: Some(ReasoningEffort::Low), + agents_states: [( + watchdog_thread_id.to_string(), + CollabAgentState { + status: CollabAgentStatus::PendingInit, + message: None, + }, + )] + .into_iter() + .collect(), + }, + ThreadItem::RawResponseItem { + id: "item-2".to_string(), + item: raw_response_item, + }, + ThreadItem::CollabAgentToolCall { + id: "watchdog-close".to_string(), + tool: CollabAgentTool::CloseAgent, + status: CollabAgentToolCallStatus::Completed, + sender_thread_id: sender_thread_id.to_string(), + receiver_thread_ids: vec![watchdog_thread_id.to_string()], + prompt: None, + model: None, + reasoning_effort: None, + agents_states: [( + watchdog_thread_id.to_string(), + CollabAgentState { + status: CollabAgentStatus::Completed, + message: Some("goodbye".to_string()), + }, + )] + .into_iter() + .collect(), + }, + ] + ); + + Ok(()) +} + struct RestartedThreadFixture { mcp: McpProcess, thread_id: String, diff --git a/codex-rs/core/src/tools/handlers/multi_agents/send_input.rs b/codex-rs/core/src/tools/handlers/multi_agents/send_input.rs index 4ae3240cb3..218383a3ac 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents/send_input.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents/send_input.rs @@ -1,5 +1,8 @@ use super::*; use crate::agent::control::render_input_preview; +use codex_protocol::AgentPath; +use codex_protocol::protocol::InterAgentCommunication; +use codex_protocol::protocol::SessionSource; pub(crate) struct Handler; @@ -25,6 +28,8 @@ impl ToolHandler for Handler { let arguments = function_arguments(payload)?; let args: SendInputArgs = parse_arguments(&arguments)?; let receiver_thread_id = parse_agent_id_target(&args.target)?; + let message = args.message.clone(); + let items = args.items.clone(); let input_items = parse_collab_input(args.message, args.items)?; let prompt = render_input_preview(&input_items); let receiver_agent = session @@ -53,10 +58,42 @@ impl ToolHandler for Handler { ) .await; let agent_control = session.services.agent_control.clone(); - let result = agent_control - .send_input(receiver_thread_id, input_items) - .await - .map_err(|err| collab_agent_error(receiver_thread_id, err)); + let sender_is_subagent = matches!(&turn.session_source, SessionSource::SubAgent(_)); + let result = match (sender_is_subagent, message, items) { + (true, Some(message), None) => { + let sender_path = turn + .session_source + .get_agent_path() + .or_else(|| { + agent_control + .get_agent_metadata(session.conversation_id) + .and_then(|metadata| metadata.agent_path) + }) + .unwrap_or_else(|| fallback_agent_path(session.conversation_id)); + let receiver_path = receiver_agent + .agent_path + .clone() + .unwrap_or_else(|| fallback_agent_path(receiver_thread_id)); + agent_control + .send_inter_agent_communication( + receiver_thread_id, + InterAgentCommunication::new( + sender_path, + receiver_path, + Vec::new(), + message, + /*trigger_turn*/ true, + ), + ) + .await + } + _ => { + agent_control + .send_input(receiver_thread_id, input_items) + .await + } + } + .map_err(|err| collab_agent_error(receiver_thread_id, err)); let status = session .services .agent_control @@ -83,6 +120,13 @@ impl ToolHandler for Handler { } } +fn fallback_agent_path(thread_id: ThreadId) -> AgentPath { + let name = format!("thread_{}", thread_id.to_string().replace('-', "_")); + AgentPath::root() + .join(&name) + .unwrap_or_else(|_| AgentPath::root()) +} + #[derive(Debug, Deserialize)] struct SendInputArgs { target: String, diff --git a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs index 4e05d9fc7d..bdd1ed90da 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs @@ -2864,6 +2864,63 @@ async fn send_input_accepts_structured_items() { .expect("shutdown should submit"); } +#[tokio::test] +async fn send_input_from_subagent_message_uses_inter_agent_communication() { + let (mut session, mut turn) = make_session_and_context().await; + let manager = thread_manager(); + session.services.agent_control = manager.agent_control(); + let config = turn.config.as_ref().clone(); + let parent = manager.start_thread(config).await.expect("start parent"); + let parent_thread_id = parent.thread_id; + session + .services + .agent_control + .register_session_root(parent_thread_id, &SessionSource::Cli); + let sender_path = AgentPath::try_from("/root/worker").expect("valid sender path"); + turn.session_source = SessionSource::SubAgent(SubAgentSource::ThreadSpawn { + parent_thread_id, + depth: 1, + agent_path: Some(sender_path.clone()), + agent_nickname: Some("Worker".to_string()), + agent_role: None, + }); + + let invocation = invocation( + Arc::new(session), + Arc::new(turn), + "send_input", + function_payload(json!({ + "target": parent_thread_id.to_string(), + "message": "ready for review" + })), + ); + SendInputHandler + .handle(invocation) + .await + .expect("send_input should succeed"); + + let expected = Op::InterAgentCommunication { + communication: InterAgentCommunication::new( + sender_path, + AgentPath::root(), + Vec::new(), + "ready for review".to_string(), + /*trigger_turn*/ true, + ), + }; + let captured = manager + .captured_ops() + .into_iter() + .find(|(id, op)| *id == parent_thread_id && *op == expected); + assert_eq!(captured, Some((parent_thread_id, expected))); + + let _ = parent + .thread + .submit(Op::Shutdown {}) + .await + .expect("shutdown should submit"); +} + #[tokio::test] async fn resume_agent_rejects_invalid_id() { let (session, turn) = make_session_and_context().await; diff --git a/codex-rs/tui/src/app/agent_navigation.rs b/codex-rs/tui/src/app/agent_navigation.rs index db9e47c5bc..b8643d1d3d 100644 --- a/codex-rs/tui/src/app/agent_navigation.rs +++ b/codex-rs/tui/src/app/agent_navigation.rs @@ -63,10 +63,7 @@ impl AgentNavigationState { self.threads.get(thread_id) } - /// Returns whether the picker cache currently knows about any threads. - /// - /// This is the cheapest way for `App` to decide whether opening the picker should show "No - /// agents available yet." rather than constructing picker rows from an empty state. + #[cfg(test)] pub(crate) fn is_empty(&self) -> bool { self.threads.is_empty() } @@ -132,17 +129,6 @@ impl AgentNavigationState { self.order.retain(|candidate| *candidate != thread_id); } - /// Returns whether there is at least one tracked thread other than the primary one. - /// - /// `App` uses this to decide whether the picker should be available even when the collaboration - /// feature flag is currently disabled, because already-existing sub-agent threads should remain - /// inspectable. - pub(crate) fn has_non_primary_thread(&self, primary_thread_id: Option) -> bool { - self.threads - .keys() - .any(|thread_id| Some(*thread_id) != primary_thread_id) - } - /// Returns live picker rows in the same order users cycle through them. /// /// The `order` vector is intentionally historical and may briefly contain thread ids that no diff --git a/codex-rs/tui/src/app/session_lifecycle.rs b/codex-rs/tui/src/app/session_lifecycle.rs index 4eded21f53..1bdb38648b 100644 --- a/codex-rs/tui/src/app/session_lifecycle.rs +++ b/codex-rs/tui/src/app/session_lifecycle.rs @@ -26,24 +26,36 @@ impl App { } } - let has_non_primary_agent_thread = self + let collab_enabled = self.config.features.enabled(Feature::Collab); + let selectable_threads = self .agent_navigation - .has_non_primary_thread(self.primary_thread_id); - if !self.config.features.enabled(Feature::Collab) && !has_non_primary_agent_thread { + .ordered_threads() + .into_iter() + .filter(|(thread_id, entry)| { + let is_primary = Some(*thread_id) == self.primary_thread_id; + let is_watchdog = entry.agent_role.as_deref() == Some("watchdog"); + let is_open_agent = !entry.is_closed && !is_watchdog; + let is_existing_replay_thread = self.thread_event_channels.contains_key(thread_id) + && entry.agent_role.is_none(); + is_primary || is_open_agent || (is_existing_replay_thread && !is_watchdog) + }) + .collect::>(); + let has_non_primary_agent_thread = selectable_threads + .iter() + .any(|(thread_id, _)| Some(*thread_id) != self.primary_thread_id); + if !collab_enabled && !has_non_primary_agent_thread { self.chat_widget.open_multi_agent_enable_prompt(); return; } - if self.agent_navigation.is_empty() { + if selectable_threads.is_empty() { self.chat_widget .add_info_message("No agents available yet.".to_string(), /*hint*/ None); return; } let mut initial_selected_idx = None; - let items: Vec = self - .agent_navigation - .ordered_threads() + let items: Vec = selectable_threads .iter() .enumerate() .map(|(idx, (thread_id, entry))| { diff --git a/codex-rs/tui/src/app_server_session.rs b/codex-rs/tui/src/app_server_session.rs index 449da8e212..fed714dd3f 100644 --- a/codex-rs/tui/src/app_server_session.rs +++ b/codex-rs/tui/src/app_server_session.rs @@ -1187,7 +1187,8 @@ fn thread_start_params_from_config( config: config_request_overrides_from_config(config), ephemeral: Some(config.ephemeral), session_start_source, - persist_extended_history: false, + experimental_raw_events: true, + persist_extended_history: true, ..ThreadStartParams::default() } } @@ -1550,6 +1551,7 @@ mod tests { .map(permissions_selection_from_active_profile) ); assert_eq!(params.model_provider, Some(config.model_provider_id)); + assert!(params.experimental_raw_events); } #[tokio::test] diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index e315f0d60f..19e6900709 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -77,6 +77,7 @@ use crate::status::StatusHistoryHandle; use crate::status::format_directory_display; use crate::status::format_tokens_compact; use crate::status::rate_limit_snapshot_display_for_limit; +use crate::subagent_panel::SubagentPanelRegistry; use crate::terminal_title::SetTerminalTitleResult; use crate::terminal_title::clear_terminal_title; use crate::terminal_title::set_terminal_title; @@ -89,6 +90,8 @@ use codex_app_server_protocol::AddCreditsNudgeEmailStatus; use codex_app_server_protocol::AppInfo; use codex_app_server_protocol::AppSummary; use codex_app_server_protocol::CodexErrorInfo as AppServerCodexErrorInfo; +use codex_app_server_protocol::CollabAgentState; +use codex_app_server_protocol::CollabAgentStatus; use codex_app_server_protocol::CollabAgentTool; use codex_app_server_protocol::CollabAgentToolCallStatus; use codex_app_server_protocol::CommandExecutionRequestApprovalParams; @@ -157,10 +160,14 @@ use codex_protocol::config_types::WindowsSandboxLevel; use codex_protocol::items::AgentMessageContent; use codex_protocol::items::AgentMessageItem; use codex_protocol::models::MessagePhase; +use codex_protocol::models::ResponseItem; use codex_protocol::models::local_image_label_text; use codex_protocol::parse_command::ParsedCommand; use codex_protocol::plan_tool::PlanItemArg as UpdatePlanItemArg; use codex_protocol::plan_tool::StepStatus as UpdatePlanItemStatus; +use codex_protocol::protocol::AgentStatus; +use codex_protocol::protocol::InterAgentCommunication; + use codex_protocol::request_permissions::RequestPermissionsEvent; use codex_protocol::user_input::ByteRange; use codex_protocol::user_input::TextElement; @@ -205,6 +212,23 @@ const PLAN_MODE_REASONING_SCOPE_ALL_MODES: &str = "Apply to global default and P const CONNECTORS_SELECTION_VIEW_ID: &str = "connectors-selection"; const TUI_STUB_MESSAGE: &str = "Not available in TUI yet."; +fn app_server_collab_state_to_core(state: &CollabAgentState) -> AgentStatus { + match state.status { + CollabAgentStatus::PendingInit => AgentStatus::PendingInit, + CollabAgentStatus::Running => AgentStatus::Running, + CollabAgentStatus::Interrupted => AgentStatus::Interrupted, + CollabAgentStatus::Completed => AgentStatus::Completed(state.message.clone()), + CollabAgentStatus::Errored => AgentStatus::Errored( + state + .message + .clone() + .unwrap_or_else(|| "Agent failed".to_string()), + ), + CollabAgentStatus::Shutdown => AgentStatus::Shutdown, + CollabAgentStatus::NotFound => AgentStatus::NotFound, + } +} + /// Choose the keybinding used to edit the most-recently queued message. /// /// Apple Terminal, Warp, and VSCode integrated terminals intercept or silently @@ -430,6 +454,14 @@ fn is_unified_exec_source(source: ExecCommandSource) -> bool { ) } +fn inter_agent_message_from_item(item: &ResponseItem) -> Option<(String, String)> { + let ResponseItem::Message { content, .. } = item else { + return None; + }; + let communication = InterAgentCommunication::from_message_content(content)?; + Some((communication.author.to_string(), communication.content)) +} + fn is_standard_tool_call(parsed_cmd: &[ParsedCommand]) -> bool { !parsed_cmd.is_empty() && parsed_cmd @@ -737,6 +769,7 @@ pub(crate) struct ChatWidget { codex_op_target: CodexOpTarget, bottom_pane: BottomPane, active_cell: Option>, + subagent_panel: Option, /// Monotonic-ish counter used to invalidate transcript overlay caching. /// /// The transcript overlay appends a cached "live tail" for the current active cell. Most @@ -806,6 +839,7 @@ pub(crate) struct ChatWidget { running_commands: HashMap, collab_agent_metadata: HashMap, pending_collab_spawn_requests: HashMap, + subagent_panel_registry: SubagentPanelRegistry, suppressed_exec_calls: HashSet, skills_all: Vec, skills_initial_state: Option>, @@ -1011,6 +1045,7 @@ pub(crate) struct ChatWidget { external_editor_state: ExternalEditorState, realtime_conversation: RealtimeConversationUiState, last_rendered_user_message_display: Option, + last_replayed_inter_agent_message: Option<(String, String)>, last_non_retry_error: Option<(String, String)>, } @@ -1571,6 +1606,10 @@ impl ThreadItemRenderSource { Self::Replay(replay_kind) => Some(replay_kind), } } + + fn should_update_subagent_panel(self) -> bool { + !matches!(self, Self::Replay(ReplayKind::ResumeInitialMessages)) + } } fn exec_approval_request_from_params( @@ -3952,7 +3991,38 @@ impl ChatWidget { self.request_redraw(); } - fn on_collab_agent_tool_call(&mut self, item: ThreadItem) { + fn refresh_subagent_panel(&mut self) { + self.subagent_panel = self.subagent_panel_registry.rebuild_panel(); + self.request_redraw(); + } + + fn on_raw_response_item(&mut self, item: ResponseItem, from_replay: bool) { + let Some((sender, message)) = inter_agent_message_from_item(&item) else { + if from_replay { + self.last_replayed_inter_agent_message = None; + } + return; + }; + + let replay_key = (sender.clone(), message.clone()); + if from_replay { + if self.last_replayed_inter_agent_message.as_ref() == Some(&replay_key) { + return; + } + self.last_replayed_inter_agent_message = Some(replay_key); + } else { + self.last_replayed_inter_agent_message = None; + } + + let hint = (!sender.is_empty()).then(|| format!("from {sender}")); + self.add_to_history(history_cell::new_info_event( + format!("Agent message: {message}"), + hint, + )); + self.request_redraw(); + } + + fn on_collab_agent_tool_call(&mut self, item: ThreadItem, update_subagent_panel: bool) { let ThreadItem::CollabAgentToolCall { id, tool, status, .. } = &item @@ -3981,6 +4051,75 @@ impl ChatWidget { ) { self.on_collab_event(cell); } + + if matches!(status, CollabAgentToolCallStatus::InProgress) { + return; + } + + let ThreadItem::CollabAgentToolCall { + receiver_thread_ids, + prompt, + agents_states, + .. + } = &item + else { + return; + }; + let first_receiver = receiver_thread_ids + .first() + .and_then(|thread_id| ThreadId::from_string(thread_id).ok()); + + match tool { + CollabAgentTool::SpawnAgent => { + if update_subagent_panel && let Some(receiver_thread_id) = first_receiver { + let metadata = self.collab_agent_metadata(receiver_thread_id); + let status = agents_states + .get(&receiver_thread_id.to_string()) + .map(app_server_collab_state_to_core) + .unwrap_or(AgentStatus::PendingInit); + self.subagent_panel_registry.on_spawn( + receiver_thread_id, + metadata.agent_nickname, + metadata.agent_role, + prompt.as_deref().unwrap_or_default(), + status, + ); + self.refresh_subagent_panel(); + } + } + CollabAgentTool::SendInput | CollabAgentTool::ResumeAgent => { + if update_subagent_panel && let Some(receiver_thread_id) = first_receiver { + let status = agents_states + .get(&receiver_thread_id.to_string()) + .map(app_server_collab_state_to_core) + .unwrap_or_else(|| AgentStatus::Errored("Agent interaction failed".into())); + self.subagent_panel_registry + .update_status(receiver_thread_id, status); + self.refresh_subagent_panel(); + } + } + CollabAgentTool::Wait => { + if update_subagent_panel { + for receiver_thread_id in receiver_thread_ids { + if let Ok(thread_id) = ThreadId::from_string(receiver_thread_id) + && let Some(status) = agents_states + .get(receiver_thread_id) + .map(app_server_collab_state_to_core) + { + self.subagent_panel_registry + .update_status(thread_id, status); + } + } + self.refresh_subagent_panel(); + } + } + CollabAgentTool::CloseAgent => { + if update_subagent_panel && let Some(receiver_thread_id) = first_receiver { + self.subagent_panel_registry.close(receiver_thread_id); + self.refresh_subagent_panel(); + } + } + } } pub(crate) fn handle_history_entry_response(&mut self, event: HistoryLookupResponse) { @@ -4832,6 +4971,7 @@ impl ChatWidget { &chat_keymap.edit_queued_message, current_terminal_info, ); + let animations_enabled = config.animations; let mut widget = Self { app_event_tx: app_event_tx.clone(), frame_requester: frame_requester.clone(), @@ -4847,6 +4987,7 @@ impl ChatWidget { skills: None, }), active_cell, + subagent_panel: None, active_cell_revision: 0, config, effective_service_tier, @@ -4878,6 +5019,7 @@ impl ChatWidget { running_commands: HashMap::new(), collab_agent_metadata: HashMap::new(), pending_collab_spawn_requests: HashMap::new(), + subagent_panel_registry: SubagentPanelRegistry::new(animations_enabled), suppressed_exec_calls: HashSet::new(), last_unified_wait: None, unified_exec_wait_streak: None, @@ -4979,6 +5121,7 @@ impl ChatWidget { external_editor_state: ExternalEditorState::Closed, realtime_conversation: RealtimeConversationUiState::default(), last_rendered_user_message_display: None, + last_replayed_inter_agent_message: None, last_non_retry_error: None, }; @@ -5999,6 +6142,9 @@ impl ChatWidget { }), }); } + ThreadItem::RawResponseItem { item, .. } => { + self.on_raw_response_item(item, from_replay); + } ThreadItem::Plan { text, .. } => self.on_plan_item_completed(text), ThreadItem::Reasoning { summary, content, .. @@ -6067,17 +6213,20 @@ impl ChatWidget { model, reasoning_effort, agents_states, - } => self.on_collab_agent_tool_call(ThreadItem::CollabAgentToolCall { - id, - tool, - status, - sender_thread_id, - receiver_thread_ids, - prompt, - model, - reasoning_effort, - agents_states, - }), + } => self.on_collab_agent_tool_call( + ThreadItem::CollabAgentToolCall { + id, + tool, + status, + sender_thread_id, + receiver_thread_ids, + prompt, + model, + reasoning_effort, + agents_states, + }, + render_source.should_update_subagent_panel(), + ), ThreadItem::DynamicToolCall { .. } => {} } @@ -6192,6 +6341,9 @@ impl ChatWidget { ServerNotification::ItemCompleted(notification) => { self.handle_item_completed_notification(notification, replay_kind); } + ServerNotification::RawResponseItemCompleted(notification) => { + self.on_raw_response_item(notification.item, from_replay); + } ServerNotification::AgentMessageDelta(notification) => { self.on_agent_message_delta(notification.delta); } @@ -6342,7 +6494,6 @@ impl ChatWidget { | ServerNotification::ThreadStatusChanged(_) | ServerNotification::ThreadArchived(_) | ServerNotification::ThreadUnarchived(_) - | ServerNotification::RawResponseItemCompleted(_) | ServerNotification::CommandExecOutputDelta(_) | ServerNotification::FileChangePatchUpdated(_) | ServerNotification::McpToolCallProgress(_) @@ -6439,17 +6590,20 @@ impl ChatWidget { model, reasoning_effort, agents_states, - } => self.on_collab_agent_tool_call(ThreadItem::CollabAgentToolCall { - id, - tool, - status, - sender_thread_id, - receiver_thread_ids, - prompt, - model, - reasoning_effort, - agents_states, - }), + } => self.on_collab_agent_tool_call( + ThreadItem::CollabAgentToolCall { + id, + tool, + status, + sender_thread_id, + receiver_thread_ids, + prompt, + model, + reasoning_effort, + agents_states, + }, + !from_replay, + ), ThreadItem::EnteredReviewMode { review, .. } => { if !from_replay { self.enter_review_mode_with_hint(review, /*from_replay*/ false); @@ -10790,9 +10944,16 @@ impl ChatWidget { } _ => RenderableItem::Owned(Box::new(())), }; + let subagent_panel_renderable = match &self.subagent_panel { + Some(panel) => RenderableItem::Borrowed(panel).inset(Insets::tlbr( + /*top*/ 1, /*left*/ 0, /*bottom*/ 0, /*right*/ 0, + )), + None => RenderableItem::Owned(Box::new(())), + }; let mut flex = FlexRenderable::new(); flex.push(/*flex*/ 1, active_cell_renderable); flex.push(/*flex*/ 0, active_hook_cell_renderable); + flex.push(/*flex*/ 0, subagent_panel_renderable); flex.push( /*flex*/ 0, RenderableItem::Borrowed(&self.bottom_pane).inset(Insets::tlbr( diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__live_app_server_raw_inter_agent_message_renders_agent_message_cell.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__live_app_server_raw_inter_agent_message_renders_agent_message_cell.snap new file mode 100644 index 0000000000..3bd41463f7 --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__live_app_server_raw_inter_agent_message_renders_agent_message_cell.snap @@ -0,0 +1,5 @@ +--- +source: tui/src/chatwidget/tests/app_server.rs +expression: rendered +--- +• Agent message: ping 21 (21) from /root/watchdog diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_closed_watchdog_history_cells.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_closed_watchdog_history_cells.snap new file mode 100644 index 0000000000..0e88d1dc15 --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_closed_watchdog_history_cells.snap @@ -0,0 +1,12 @@ +--- +source: tui/src/chatwidget/tests/app_server.rs +expression: replayed_history +--- +• Spawned Boyle [watchdog] (arcanine 1m low) + └ Every time you start, respond with goodbye. + + +• Agent message: goodbye from /root/watchdog + + +• Closed Boyle [watchdog] diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_does_not_resurrect_closed_watchdog_panel_row.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_does_not_resurrect_closed_watchdog_panel_row.snap new file mode 100644 index 0000000000..fb4df815af --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_does_not_resurrect_closed_watchdog_panel_row.snap @@ -0,0 +1,9 @@ +--- +source: tui/src/chatwidget/tests/app_server.rs +expression: screen +--- + + +› Ask Codex to do anything + + gpt-5.3-codex default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_does_not_resurrect_open_subagent_panel_row.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_does_not_resurrect_open_subagent_panel_row.snap new file mode 100644 index 0000000000..fb4df815af --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_does_not_resurrect_open_subagent_panel_row.snap @@ -0,0 +1,9 @@ +--- +source: tui/src/chatwidget/tests/app_server.rs +expression: screen +--- + + +› Ask Codex to do anything + + gpt-5.3-codex default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_open_subagent_history_cells.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_open_subagent_history_cells.snap new file mode 100644 index 0000000000..d0b3ce07af --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__resume_replay_open_subagent_history_cells.snap @@ -0,0 +1,6 @@ +--- +source: tui/src/chatwidget/tests/app_server.rs +expression: replayed_history +--- +• Spawned Avicenna [fast-worker] (arcanine 1m medium) + └ Compute the exact value. diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__subagent_panel_mounts_watchdog_spawn.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__subagent_panel_mounts_watchdog_spawn.snap new file mode 100644 index 0000000000..9d3ed6bb1b --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__subagent_panel_mounts_watchdog_spawn.snap @@ -0,0 +1,13 @@ +--- +source: tui/src/chatwidget/tests/app_server.rs +expression: screen +--- + +• Subagents (0s • no subagents running • esc to interrupt) +• [#1] [watchdog] watch-buildpando-rpc-context-tracing-spike idle — Watch /build/pando-rpc-context-tracing-spike work on Pando RPC +accounting tracing spike. Goal: end-to-end no-expl... + + +› Ask Codex to do anything + + gpt-5.3-codex default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__subagent_panel_renders_subagent_and_watchdog_rows.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__subagent_panel_renders_subagent_and_watchdog_rows.snap new file mode 100644 index 0000000000..23f47f8121 --- /dev/null +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__subagent_panel_renders_subagent_and_watchdog_rows.snap @@ -0,0 +1,13 @@ +--- +source: tui/src/chatwidget/tests/app_server.rs +expression: screen +--- + +• Subagents (0s • 2 subagents, 1 running • esc to interrupt) +• [#1] Explorer running — Audit the TUI app-server event flow and report visible regressions. +• [#2] [watchdog] Watcher idle — Watch the worker for stalled progress. + + +› Ask Codex to do anything + + gpt-5.3-codex default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/tests/app_server.rs b/codex-rs/tui/src/chatwidget/tests/app_server.rs index 13b86e2afb..c55e4ff2a6 100644 --- a/codex-rs/tui/src/chatwidget/tests/app_server.rs +++ b/codex-rs/tui/src/chatwidget/tests/app_server.rs @@ -1,4 +1,12 @@ use super::*; +use codex_app_server_protocol::RawResponseItemCompletedNotification; +use codex_app_server_protocol::build_turns_from_rollout_items; +use codex_protocol::AgentPath; +use codex_protocol::protocol::CollabAgentSpawnEndEvent; +use codex_protocol::protocol::CollabCloseEndEvent; +use codex_protocol::protocol::EventMsg; +use codex_protocol::protocol::InterAgentCommunication; +use codex_protocol::protocol::RolloutItem; use pretty_assertions::assert_eq; #[tokio::test] @@ -68,6 +76,38 @@ async fn collab_spawn_end_shows_requested_model_and_effort() { ); } +#[tokio::test] +async fn live_app_server_raw_inter_agent_message_renders_agent_message_cell() { + let (mut chat, mut rx, _ops) = make_chatwidget_manual(/*model_override*/ None).await; + let communication = InterAgentCommunication::new( + AgentPath::try_from("/root/watchdog").expect("valid agent path"), + AgentPath::root(), + Vec::new(), + "ping 21 (21)".to_string(), + /*trigger_turn*/ true, + ); + + chat.handle_server_notification( + ServerNotification::RawResponseItemCompleted(RawResponseItemCompletedNotification { + thread_id: "thread-1".to_string(), + turn_id: "turn-1".to_string(), + item: communication.to_response_input_item().into(), + }), + /*replay_kind*/ None, + ); + + let rendered = drain_insert_history(&mut rx) + .into_iter() + .map(|lines| lines_to_single_string(&lines)) + .collect::>() + .join("\n"); + + assert_chatwidget_snapshot!( + "live_app_server_raw_inter_agent_message_renders_agent_message_cell", + rendered + ); +} + #[tokio::test] async fn live_app_server_user_message_item_completed_does_not_duplicate_rendered_prompt() { let (mut chat, mut rx, mut op_rx) = make_chatwidget_manual(/*model_override*/ None).await; @@ -522,6 +562,369 @@ async fn live_app_server_collab_spawn_completed_renders_requested_model_and_effo ); } +#[tokio::test] +async fn subagent_panel_mounts_watchdog_spawn() { + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; + let sender_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001002").expect("valid thread id"); + let watchdog_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001003").expect("valid thread id"); + + chat.set_collab_agent_metadata( + watchdog_thread_id, + Some("watch-buildpando-rpc-context-tracing-spike".to_string()), + Some("watchdog".to_string()), + ); + chat.handle_server_notification( + ServerNotification::ItemCompleted(ItemCompletedNotification { + thread_id: "thread-1".to_string(), + turn_id: "turn-1".to_string(), + item: AppServerThreadItem::CollabAgentToolCall { + id: "spawn-watchdog".to_string(), + tool: AppServerCollabAgentTool::SpawnAgent, + status: AppServerCollabAgentToolCallStatus::Completed, + sender_thread_id: sender_thread_id.to_string(), + receiver_thread_ids: vec![watchdog_thread_id.to_string()], + prompt: Some( + "Watch /build/pando-rpc-context-tracing-spike work on Pando RPC accounting tracing spike. Goal: end-to-end no-explicit...".to_string(), + ), + model: Some("gpt-5.4".to_string()), + reasoning_effort: Some(ReasoningEffortConfig::High), + agents_states: HashMap::from([( + watchdog_thread_id.to_string(), + AppServerCollabAgentState { + status: AppServerCollabAgentStatus::PendingInit, + message: None, + }, + )]), + }, + }), + /*replay_kind*/ None, + ); + + let width = 140; + let height = chat.desired_height(width); + let mut terminal = + ratatui::Terminal::new(VT100Backend::new(width, height)).expect("create terminal"); + terminal.set_viewport_area(ratatui::prelude::Rect::new(0, 0, width, height)); + terminal + .draw(|f| chat.render(f.area(), f.buffer_mut())) + .expect("render chat widget"); + let screen = normalized_backend_snapshot(terminal.backend()); + + assert_chatwidget_snapshot!("subagent_panel_mounts_watchdog_spawn", screen); +} + +#[tokio::test] +async fn subagent_panel_renders_subagent_and_watchdog_rows() { + let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; + let sender_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001002").expect("valid thread id"); + let worker_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001003").expect("valid thread id"); + let watchdog_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001004").expect("valid thread id"); + + chat.set_collab_agent_metadata( + worker_thread_id, + Some("Explorer".to_string()), + Some("worker".to_string()), + ); + chat.handle_server_notification( + ServerNotification::ItemCompleted(ItemCompletedNotification { + thread_id: "thread-1".to_string(), + turn_id: "turn-1".to_string(), + item: AppServerThreadItem::CollabAgentToolCall { + id: "spawn-worker".to_string(), + tool: AppServerCollabAgentTool::SpawnAgent, + status: AppServerCollabAgentToolCallStatus::Completed, + sender_thread_id: sender_thread_id.to_string(), + receiver_thread_ids: vec![worker_thread_id.to_string()], + prompt: Some( + "Audit the TUI app-server event flow and report visible regressions." + .to_string(), + ), + model: Some("gpt-5.4".to_string()), + reasoning_effort: Some(ReasoningEffortConfig::High), + agents_states: HashMap::from([( + worker_thread_id.to_string(), + AppServerCollabAgentState { + status: AppServerCollabAgentStatus::Running, + message: None, + }, + )]), + }, + }), + /*replay_kind*/ None, + ); + + chat.set_collab_agent_metadata( + watchdog_thread_id, + Some("Watcher".to_string()), + Some("watchdog".to_string()), + ); + chat.handle_server_notification( + ServerNotification::ItemCompleted(ItemCompletedNotification { + thread_id: "thread-1".to_string(), + turn_id: "turn-1".to_string(), + item: AppServerThreadItem::CollabAgentToolCall { + id: "spawn-watchdog".to_string(), + tool: AppServerCollabAgentTool::SpawnAgent, + status: AppServerCollabAgentToolCallStatus::Completed, + sender_thread_id: sender_thread_id.to_string(), + receiver_thread_ids: vec![watchdog_thread_id.to_string()], + prompt: Some("Watch the worker for stalled progress.".to_string()), + model: Some("gpt-5.4".to_string()), + reasoning_effort: Some(ReasoningEffortConfig::Low), + agents_states: HashMap::from([( + watchdog_thread_id.to_string(), + AppServerCollabAgentState { + status: AppServerCollabAgentStatus::PendingInit, + message: None, + }, + )]), + }, + }), + /*replay_kind*/ None, + ); + + let width = 140; + let height = chat.desired_height(width); + let mut terminal = + ratatui::Terminal::new(VT100Backend::new(width, height)).expect("create terminal"); + terminal.set_viewport_area(ratatui::prelude::Rect::new(0, 0, width, height)); + terminal + .draw(|f| chat.render(f.area(), f.buffer_mut())) + .expect("render chat widget"); + let screen = normalized_backend_snapshot(terminal.backend()); + + assert_chatwidget_snapshot!("subagent_panel_renders_subagent_and_watchdog_rows", screen); +} + +#[tokio::test] +async fn watchdog_goodbye_message_closes_subagent_panel_row() { + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; + let sender_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001002").expect("valid thread id"); + let watchdog_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001003").expect("valid thread id"); + + chat.set_collab_agent_metadata( + watchdog_thread_id, + Some("Boyle".to_string()), + Some("watchdog".to_string()), + ); + chat.handle_server_notification( + ServerNotification::ItemCompleted(ItemCompletedNotification { + thread_id: "thread-1".to_string(), + turn_id: "turn-1".to_string(), + item: AppServerThreadItem::CollabAgentToolCall { + id: "spawn-watchdog".to_string(), + tool: AppServerCollabAgentTool::SpawnAgent, + status: AppServerCollabAgentToolCallStatus::Completed, + sender_thread_id: sender_thread_id.to_string(), + receiver_thread_ids: vec![watchdog_thread_id.to_string()], + prompt: Some( + "Every time you start, respond with exactly `ping $RANDOM ($SUM)`.".to_string(), + ), + model: Some("arcanine 1m".to_string()), + reasoning_effort: Some(ReasoningEffortConfig::Low), + agents_states: HashMap::from([( + watchdog_thread_id.to_string(), + AppServerCollabAgentState { + status: AppServerCollabAgentStatus::PendingInit, + message: None, + }, + )]), + }, + }), + /*replay_kind*/ None, + ); + + let communication = InterAgentCommunication::new( + AgentPath::try_from("/root/watchdog").expect("valid agent path"), + AgentPath::root(), + Vec::new(), + "goodbye".to_string(), + /*trigger_turn*/ true, + ); + chat.handle_server_notification( + ServerNotification::RawResponseItemCompleted(RawResponseItemCompletedNotification { + thread_id: "thread-1".to_string(), + turn_id: "turn-1".to_string(), + item: communication.to_response_input_item().into(), + }), + /*replay_kind*/ None, + ); + chat.handle_server_notification( + ServerNotification::ItemCompleted(ItemCompletedNotification { + thread_id: "thread-1".to_string(), + turn_id: "turn-1".to_string(), + item: AppServerThreadItem::CollabAgentToolCall { + id: "watchdog-close".to_string(), + tool: AppServerCollabAgentTool::CloseAgent, + status: AppServerCollabAgentToolCallStatus::Completed, + sender_thread_id: sender_thread_id.to_string(), + receiver_thread_ids: vec![watchdog_thread_id.to_string()], + prompt: None, + model: None, + reasoning_effort: None, + agents_states: HashMap::from([( + watchdog_thread_id.to_string(), + AppServerCollabAgentState { + status: AppServerCollabAgentStatus::Completed, + message: Some("goodbye".to_string()), + }, + )]), + }, + }), + /*replay_kind*/ None, + ); + + let inserted = drain_insert_history(&mut rx) + .into_iter() + .map(|lines| lines_to_single_string(&lines)) + .collect::>() + .join("\n"); + assert_chatwidget_snapshot!("watchdog_goodbye_message_inserts_close_history", inserted); + + let width = 140; + let height = chat.desired_height(width); + let mut terminal = + ratatui::Terminal::new(VT100Backend::new(width, height)).expect("create terminal"); + terminal.set_viewport_area(ratatui::prelude::Rect::new(0, 0, width, height)); + terminal + .draw(|f| chat.render(f.area(), f.buffer_mut())) + .expect("render chat widget"); + let screen = normalized_backend_snapshot(terminal.backend()); + + assert_chatwidget_snapshot!("watchdog_goodbye_message_closes_subagent_panel_row", screen); +} + +#[tokio::test] +async fn resume_replay_does_not_resurrect_closed_watchdog_panel_row() { + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; + let sender_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001002").expect("valid thread id"); + let watchdog_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001003").expect("valid thread id"); + + chat.set_collab_agent_metadata( + watchdog_thread_id, + Some("Boyle".to_string()), + Some("watchdog".to_string()), + ); + let communication = InterAgentCommunication::new( + AgentPath::try_from("/root/watchdog").expect("valid agent path"), + AgentPath::root(), + Vec::new(), + "goodbye".to_string(), + /*trigger_turn*/ true, + ); + let turns = build_turns_from_rollout_items(&[ + RolloutItem::EventMsg(EventMsg::CollabAgentSpawnEnd(CollabAgentSpawnEndEvent { + call_id: "spawn-watchdog".to_string(), + sender_thread_id, + new_thread_id: Some(watchdog_thread_id), + new_agent_nickname: Some("Boyle".to_string()), + new_agent_role: Some("watchdog".to_string()), + prompt: "Every time you start, respond with goodbye.".to_string(), + model: "arcanine 1m".to_string(), + reasoning_effort: ReasoningEffortConfig::Low, + status: AgentStatus::PendingInit, + })), + RolloutItem::ResponseItem(communication.to_response_input_item().into()), + RolloutItem::EventMsg(EventMsg::CollabCloseEnd(CollabCloseEndEvent { + call_id: "watchdog-close".to_string(), + sender_thread_id, + receiver_thread_id: watchdog_thread_id, + receiver_agent_nickname: Some("Boyle".to_string()), + receiver_agent_role: Some("watchdog".to_string()), + status: AgentStatus::Completed(Some("goodbye".to_string())), + })), + ]); + chat.replay_thread_turns(turns, ReplayKind::ResumeInitialMessages); + + let replayed_history = drain_insert_history(&mut rx) + .into_iter() + .map(|lines| lines_to_single_string(&lines)) + .collect::>() + .join("\n"); + assert_chatwidget_snapshot!( + "resume_replay_closed_watchdog_history_cells", + replayed_history + ); + + let width = 140; + let height = chat.desired_height(width); + let mut terminal = + ratatui::Terminal::new(VT100Backend::new(width, height)).expect("create terminal"); + terminal.set_viewport_area(ratatui::prelude::Rect::new(0, 0, width, height)); + terminal + .draw(|f| chat.render(f.area(), f.buffer_mut())) + .expect("render chat widget"); + let screen = normalized_backend_snapshot(terminal.backend()); + + assert_chatwidget_snapshot!( + "resume_replay_does_not_resurrect_closed_watchdog_panel_row", + screen + ); +} + +#[tokio::test] +async fn resume_replay_does_not_resurrect_open_subagent_panel_row() { + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; + let sender_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001012").expect("valid thread id"); + let subagent_thread_id = + ThreadId::from_string("019cff70-2599-75e2-af72-b90000001013").expect("valid thread id"); + + chat.set_collab_agent_metadata( + subagent_thread_id, + Some("Avicenna".to_string()), + Some("fast-worker".to_string()), + ); + let turns = build_turns_from_rollout_items(&[RolloutItem::EventMsg( + EventMsg::CollabAgentSpawnEnd(CollabAgentSpawnEndEvent { + call_id: "spawn-subagent".to_string(), + sender_thread_id, + new_thread_id: Some(subagent_thread_id), + new_agent_nickname: Some("Avicenna".to_string()), + new_agent_role: Some("fast-worker".to_string()), + prompt: "Compute the exact value.".to_string(), + model: "arcanine 1m".to_string(), + reasoning_effort: ReasoningEffortConfig::Medium, + status: AgentStatus::Running, + }), + )]); + chat.replay_thread_turns(turns, ReplayKind::ResumeInitialMessages); + + let replayed_history = drain_insert_history(&mut rx) + .into_iter() + .map(|lines| lines_to_single_string(&lines)) + .collect::>() + .join("\n"); + assert_chatwidget_snapshot!( + "resume_replay_open_subagent_history_cells", + replayed_history + ); + + let width = 140; + let height = chat.desired_height(width); + let mut terminal = + ratatui::Terminal::new(VT100Backend::new(width, height)).expect("create terminal"); + terminal.set_viewport_area(ratatui::prelude::Rect::new(0, 0, width, height)); + terminal + .draw(|f| chat.render(f.area(), f.buffer_mut())) + .expect("render chat widget"); + let screen = normalized_backend_snapshot(terminal.backend()); + + assert_chatwidget_snapshot!( + "resume_replay_does_not_resurrect_open_subagent_panel_row", + screen + ); +} + #[tokio::test] async fn live_app_server_failed_turn_does_not_duplicate_error_history() { let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await; diff --git a/codex-rs/tui/src/chatwidget/tests/helpers.rs b/codex-rs/tui/src/chatwidget/tests/helpers.rs index 04f7e3d907..03c842fbf9 100644 --- a/codex-rs/tui/src/chatwidget/tests/helpers.rs +++ b/codex-rs/tui/src/chatwidget/tests/helpers.rs @@ -183,11 +183,13 @@ pub(super) async fn make_chatwidget_manual( let current_collaboration_mode = base_mode; let active_collaboration_mask = collaboration_modes::default_mask(model_catalog.as_ref()); let effective_service_tier = cfg.service_tier; + let animations_enabled = cfg.animations; let mut widget = ChatWidget { app_event_tx, codex_op_target: super::CodexOpTarget::Direct(op_tx), bottom_pane: bottom, active_cell: None, + subagent_panel: None, active_cell_revision: 0, config: cfg, effective_service_tier, @@ -226,6 +228,9 @@ pub(super) async fn make_chatwidget_manual( running_commands: HashMap::new(), collab_agent_metadata: HashMap::new(), pending_collab_spawn_requests: HashMap::new(), + subagent_panel_registry: crate::subagent_panel::SubagentPanelRegistry::new( + animations_enabled, + ), suppressed_exec_calls: HashSet::new(), skills_all: Vec::new(), skills_initial_state: None, @@ -321,6 +326,7 @@ pub(super) async fn make_chatwidget_manual( external_editor_state: ExternalEditorState::Closed, realtime_conversation: RealtimeConversationUiState::default(), last_rendered_user_message_display: None, + last_replayed_inter_agent_message: None, last_non_retry_error: None, }; widget.set_model(&resolved_model); diff --git a/codex-rs/tui/src/history_cell.rs b/codex-rs/tui/src/history_cell.rs index 5ed2cee9ed..5d3502e8f9 100644 --- a/codex-rs/tui/src/history_cell.rs +++ b/codex-rs/tui/src/history_cell.rs @@ -25,11 +25,13 @@ use crate::markdown::append_markdown; use crate::motion::MotionMode; use crate::motion::ReducedMotionIndicator; use crate::motion::activity_indicator; +use crate::motion::shimmer_text; use crate::render::line_utils::line_to_static; use crate::render::line_utils::prefix_lines; use crate::render::line_utils::push_owned_lines; use crate::render::renderable::Renderable; use crate::session_state::ThreadSessionState; +use crate::status_indicator_widget::fmt_elapsed_compact; use crate::style::proposed_plan_style; use crate::style::user_message_style; #[cfg(test)] @@ -73,6 +75,7 @@ use codex_protocol::openai_models::ReasoningEffort as ReasoningEffortConfig; use codex_protocol::plan_tool::PlanItemArg; use codex_protocol::plan_tool::StepStatus; use codex_protocol::plan_tool::UpdatePlanArgs; +use codex_protocol::protocol::AgentStatus; use codex_protocol::user_input::TextElement; use codex_utils_absolute_path::AbsolutePathBuf; use codex_utils_cli::format_env_display; @@ -92,6 +95,8 @@ use std::collections::HashMap; use std::io::Cursor; use std::path::Path; use std::path::PathBuf; +use std::sync::Arc; +use std::sync::Mutex; use std::time::Duration; use std::time::Instant; use tracing::error; @@ -560,6 +565,188 @@ impl HistoryCell for PlainHistoryCell { } } +#[derive(Clone, Debug)] +pub(crate) struct SubagentPanelAgent { + pub(crate) ordinal: i32, + pub(crate) name: String, + pub(crate) status: AgentStatus, + pub(crate) is_watchdog: bool, + pub(crate) preview: String, + pub(crate) latest_update_at: Instant, +} + +#[derive(Clone, Debug)] +pub(crate) struct SubagentPanelState { + pub(crate) started_at: Instant, + pub(crate) total_agents: i32, + pub(crate) running_count: i32, + pub(crate) running_agents: Vec, +} + +impl SubagentPanelState { + pub(crate) fn has_animating_agents(&self, now: Instant) -> bool { + self.running_agents + .iter() + .any(|agent| should_subagent_panel_shimmer(agent, now)) + } +} + +#[derive(Clone, Debug)] +pub(crate) struct SubagentStatusCell { + state: Arc>, + animations_enabled: bool, +} + +impl SubagentStatusCell { + pub(crate) fn new( + state: Arc>, + animations_enabled: bool, + ) -> SubagentStatusCell { + SubagentStatusCell { + state, + animations_enabled, + } + } +} + +impl HistoryCell for SubagentStatusCell { + fn display_lines(&self, width: u16) -> Vec> { + let state = { + let guard = self + .state + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + guard.clone() + }; + if state.running_agents.is_empty() { + return Vec::new(); + } + + let elapsed = fmt_elapsed_compact(state.started_at.elapsed().as_secs()); + let total_agents = state.total_agents.max(state.running_count); + let count_label = subagent_count_label(total_agents, state.running_count); + let header_suffix = format!("({elapsed} • {count_label} • esc to interrupt)"); + + let mut lines = Vec::new(); + lines.push(Line::from(vec![ + "• ".dim(), + "Subagents".bold(), + " ".into(), + header_suffix.dim(), + ])); + + let mut running_agents = state.running_agents; + running_agents.sort_by_key(|agent| agent.ordinal); + let preview_budget = running_preview_budget(width); + let now = Instant::now(); + lines.extend(running_agents.into_iter().map(|agent| { + let preview = truncate_text(agent.preview.trim(), preview_budget); + let mut spans: Vec> = + vec!["• ".dim(), format!("[#{}] ", agent.ordinal).dim()]; + if agent.is_watchdog { + spans.push("[watchdog] ".magenta().dim()); + } + spans.push(Span::from(agent.name.clone())); + spans.push(" ".into()); + spans.push(status_span_for_subagent_panel(&agent)); + spans.push(" — ".dim()); + if self.animations_enabled && should_subagent_panel_shimmer(&agent, now) { + spans.extend(shimmer_text(&preview, MotionMode::Animated)); + } else { + spans.push(Span::from(preview)); + } + Line::from(spans) + })); + + lines + } + + fn transcript_animation_tick(&self) -> Option { + if !self.animations_enabled { + return None; + } + let guard = self + .state + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + let now = Instant::now(); + if !guard.has_animating_agents(now) { + return None; + } + Some((now.duration_since(guard.started_at).as_millis() / 100) as u64) + } +} + +impl Renderable for SubagentStatusCell { + fn render(&self, area: Rect, buf: &mut Buffer) { + let lines = self.display_lines(area.width); + let paragraph = Paragraph::new(Text::from(lines)).wrap(Wrap { trim: false }); + let y = if area.height == 0 { + 0 + } else { + let overflow = paragraph + .line_count(area.width) + .saturating_sub(usize::from(area.height)); + u16::try_from(overflow).unwrap_or(u16::MAX) + }; + paragraph.scroll((y, 0)).render(area, buf); + } + + fn desired_height(&self, width: u16) -> u16 { + HistoryCell::desired_height(self, width) + } +} + +fn running_preview_budget(width: u16) -> usize { + let width = width as usize; + width.saturating_sub(24).clamp(60, 160) +} + +fn is_running_agent_status(status: &AgentStatus) -> bool { + matches!(status, AgentStatus::PendingInit | AgentStatus::Running) +} + +fn status_span_for_subagent_panel(agent: &SubagentPanelAgent) -> Span<'static> { + match &agent.status { + AgentStatus::PendingInit if agent.is_watchdog => "idle".dim(), + AgentStatus::PendingInit | AgentStatus::Running => "running".cyan().bold(), + AgentStatus::Interrupted => "interrupted".magenta(), + AgentStatus::Completed(_) => "completed".green(), + AgentStatus::Errored(_) => "errored".red(), + AgentStatus::Shutdown => "shutdown".dim(), + AgentStatus::NotFound => "not found".red(), + } +} + +const SUBAGENT_SHIMMER_WINDOW: Duration = Duration::from_secs(1); + +fn should_subagent_panel_shimmer(agent: &SubagentPanelAgent, now: Instant) -> bool { + if agent.is_watchdog && matches!(agent.status, AgentStatus::PendingInit) { + return false; + } + is_running_agent_status(&agent.status) + && now.saturating_duration_since(agent.latest_update_at) <= SUBAGENT_SHIMMER_WINDOW +} + +fn subagent_count_label(total: i32, running: i32) -> String { + if total <= 0 || running <= 0 { + return "no subagents running".to_string(); + } + let total_label = subagent_pluralize(total, "subagent"); + if running >= total { + return format!("{total_label} running"); + } + format!("{total_label}, {running} running") +} + +fn subagent_pluralize(count: i32, singular: &str) -> String { + if count == 1 { + format!("1 {singular}") + } else { + format!("{count} {singular}s") + } +} + #[cfg_attr(debug_assertions, allow(dead_code))] #[derive(Debug)] pub(crate) struct UpdateAvailableHistoryCell { @@ -3225,6 +3412,48 @@ mod tests { render_lines(&cell.transcript_lines(u16::MAX)) } + #[test] + fn subagent_panel_renders_watchdog_handle_as_idle() { + let state = Arc::new(Mutex::new(SubagentPanelState { + started_at: Instant::now(), + total_agents: 1, + running_count: 0, + running_agents: vec![SubagentPanelAgent { + ordinal: 1, + name: "watchdog-agent".to_string(), + status: AgentStatus::PendingInit, + is_watchdog: true, + preview: "monitor parent progress".to_string(), + latest_update_at: Instant::now(), + }], + })); + let cell = SubagentStatusCell::new(state, /*animations_enabled*/ true); + let lines = render_lines(&cell.display_lines(/*width*/ 120)); + + assert!(lines[0].contains("no subagents running")); + assert!(lines[1].contains("[watchdog] watchdog-agent idle")); + } + + #[test] + fn subagent_panel_animation_tick_ignores_idle_watchdogs() { + let state = Arc::new(Mutex::new(SubagentPanelState { + started_at: Instant::now(), + total_agents: 1, + running_count: 0, + running_agents: vec![SubagentPanelAgent { + ordinal: 1, + name: "watchdog-agent".to_string(), + status: AgentStatus::PendingInit, + is_watchdog: true, + preview: "monitor parent progress".to_string(), + latest_update_at: Instant::now(), + }], + })); + let cell = SubagentStatusCell::new(state, /*animations_enabled*/ true); + + assert_eq!(cell.transcript_animation_tick(), None); + } + fn image_block(data: &str) -> serde_json::Value { serde_json::to_value(Content::image(data.to_string(), "image/png")) .expect("image content should serialize") diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs index 466b7b9e6e..717a1d26d9 100644 --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -165,6 +165,7 @@ mod status; mod status_indicator_widget; mod streaming; mod style; +mod subagent_panel; mod terminal_palette; mod terminal_probe; mod terminal_title; diff --git a/codex-rs/tui/src/subagent_panel.rs b/codex-rs/tui/src/subagent_panel.rs new file mode 100644 index 0000000000..c6879ca377 --- /dev/null +++ b/codex-rs/tui/src/subagent_panel.rs @@ -0,0 +1,235 @@ +use crate::history_cell::SubagentPanelAgent; +use crate::history_cell::SubagentPanelState; +use crate::history_cell::SubagentStatusCell; +use crate::text_formatting::truncate_text; +use codex_protocol::ThreadId; +use codex_protocol::protocol::AgentStatus; +use std::collections::HashMap; +use std::sync::Arc; +use std::sync::Mutex; +use std::time::Instant; + +const SUBAGENT_PROMPT_PREVIEW_BUDGET: usize = 120; +const SUBAGENT_UPDATE_PREVIEW_BUDGET: usize = 160; + +#[derive(Debug, Clone)] +struct SubagentInfo { + ordinal: i32, + name: String, + role: Option, + prompt_preview: String, + status: AgentStatus, + spawned_at: Instant, + latest_preview: String, + latest_update_at: Instant, +} + +impl SubagentInfo { + fn new(ordinal: i32, name: String, role: Option, prompt: &str) -> Self { + let now = Instant::now(); + let prompt_preview = prompt_preview(prompt); + Self { + ordinal, + name, + role, + prompt_preview: prompt_preview.clone(), + status: AgentStatus::PendingInit, + spawned_at: now, + latest_preview: prompt_preview, + latest_update_at: now, + } + } + + fn is_watchdog(&self) -> bool { + self.role.as_deref() == Some("watchdog") + } + + fn is_visible_in_panel(&self) -> bool { + if self.is_watchdog() { + return matches!(self.status, AgentStatus::PendingInit | AgentStatus::Running); + } + matches!(self.status, AgentStatus::PendingInit | AgentStatus::Running) + } + + fn is_running_for_panel(&self) -> bool { + if self.is_watchdog() { + return matches!(self.status, AgentStatus::Running); + } + matches!(self.status, AgentStatus::PendingInit | AgentStatus::Running) + } + + fn update_status(&mut self, status: AgentStatus) { + self.latest_preview = + status_preview(&status).unwrap_or_else(|| self.prompt_preview.clone()); + self.status = status; + self.latest_update_at = Instant::now(); + } +} + +#[derive(Debug, Default)] +pub(crate) struct SubagentPanelRegistry { + agents: HashMap, + order: Vec, + panel_state: Option>>, + animations_enabled: bool, +} + +impl SubagentPanelRegistry { + pub(crate) fn new(animations_enabled: bool) -> Self { + Self { + animations_enabled, + ..Self::default() + } + } + + pub(crate) fn on_spawn( + &mut self, + thread_id: ThreadId, + nickname: Option, + role: Option, + prompt: &str, + status: AgentStatus, + ) { + if role.as_deref() == Some("watchdog") { + self.prune_superseded_watchdogs(thread_id); + } + + let ordinal = self.ordinal_for(thread_id); + let name = nickname + .filter(|nickname| !nickname.trim().is_empty()) + .unwrap_or_else(|| derive_subagent_name(prompt, ordinal)); + + let info = self.agents.entry(thread_id).or_insert_with(|| { + self.order.push(thread_id); + SubagentInfo::new(ordinal, name.clone(), role.clone(), prompt) + }); + info.name = name; + info.role = role; + info.update_status(status); + } + + pub(crate) fn update_status(&mut self, thread_id: ThreadId, status: AgentStatus) { + if let Some(info) = self.agents.get_mut(&thread_id) { + info.update_status(status); + } + } + + pub(crate) fn close(&mut self, thread_id: ThreadId) { + self.agents.remove(&thread_id); + self.order.retain(|candidate| *candidate != thread_id); + } + + pub(crate) fn rebuild_panel(&mut self) -> Option { + let mut visible = self + .order + .iter() + .filter_map(|thread_id| self.agents.get(thread_id)) + .filter(|info| info.is_visible_in_panel()) + .collect::>(); + visible.sort_by_key(|info| info.ordinal); + + if visible.is_empty() { + self.panel_state = None; + return None; + } + + let started_at = visible + .iter() + .map(|info| info.spawned_at) + .min() + .unwrap_or_else(Instant::now); + let running_count = i32::try_from( + visible + .iter() + .filter(|info| info.is_running_for_panel()) + .count(), + ) + .unwrap_or(i32::MAX); + let total_agents = i32::try_from(visible.len()).unwrap_or(i32::MAX); + let running_agents = visible + .into_iter() + .map(|info| SubagentPanelAgent { + ordinal: info.ordinal, + name: info.name.clone(), + status: info.status.clone(), + is_watchdog: info.is_watchdog(), + preview: info.latest_preview.clone(), + latest_update_at: info.latest_update_at, + }) + .collect(); + let state = SubagentPanelState { + started_at, + total_agents, + running_count, + running_agents, + }; + + match &self.panel_state { + Some(existing) => { + let mut guard = existing + .lock() + .unwrap_or_else(std::sync::PoisonError::into_inner); + *guard = state; + } + None => { + self.panel_state = Some(Arc::new(Mutex::new(state))); + } + } + + self.panel_state + .as_ref() + .map(|state| SubagentStatusCell::new(Arc::clone(state), self.animations_enabled)) + } + + fn ordinal_for(&self, thread_id: ThreadId) -> i32 { + if let Some(existing) = self.agents.get(&thread_id) { + return existing.ordinal; + } + i32::try_from(self.order.len()) + .unwrap_or(i32::MAX - 1) + .saturating_add(1) + } + + fn prune_superseded_watchdogs(&mut self, keep_thread_id: ThreadId) { + let superseded = self + .agents + .iter() + .filter_map(|(thread_id, info)| { + (info.is_watchdog() && *thread_id != keep_thread_id).then_some(*thread_id) + }) + .collect::>(); + for thread_id in superseded { + self.close(thread_id); + } + } +} + +fn prompt_preview(prompt: &str) -> String { + let first_line = prompt + .lines() + .find(|line| !line.trim().is_empty()) + .unwrap_or(prompt) + .trim(); + truncate_text(first_line, SUBAGENT_PROMPT_PREVIEW_BUDGET) +} + +fn derive_subagent_name(prompt: &str, ordinal: i32) -> String { + let preview = prompt_preview(prompt); + if preview.is_empty() { + return format!("agent-{ordinal}"); + } + preview +} + +fn status_preview(status: &AgentStatus) -> Option { + match status { + AgentStatus::Completed(Some(message)) | AgentStatus::Errored(message) => Some( + truncate_text(message.trim(), SUBAGENT_UPDATE_PREVIEW_BUDGET), + ), + AgentStatus::Completed(None) => Some("completed".to_string()), + AgentStatus::Interrupted => Some("interrupted".to_string()), + AgentStatus::Shutdown => Some("shutdown".to_string()), + AgentStatus::NotFound => Some("not found".to_string()), + AgentStatus::PendingInit | AgentStatus::Running => None, + } +}