diff --git a/codex-rs/app-server-protocol/schema/json/EventMsg.json b/codex-rs/app-server-protocol/schema/json/EventMsg.json index c81f69d1098..50ac156ffb0 100644 --- a/codex-rs/app-server-protocol/schema/json/EventMsg.json +++ b/codex-rs/app-server-protocol/schema/json/EventMsg.json @@ -517,6 +517,50 @@ ], "type": "object" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, "EventMsg": { "description": "Response event from the agent NOTE: Make sure none of these values have optional types, as it will mess up the extension code-gen.", "oneOf": [ @@ -1793,6 +1837,70 @@ "title": "DynamicToolCallRequestEventMsg", "type": "object" }, + { + "properties": { + "arguments": { + "description": "Dynamic tool call arguments." + }, + "call_id": { + "description": "Identifier for the corresponding DynamicToolCallRequest.", + "type": "string" + }, + "content_items": { + "description": "Dynamic tool response content items.", + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": "array" + }, + "duration": { + "allOf": [ + { + "$ref": "#/definitions/Duration" + } + ], + "description": "The duration of the dynamic tool call." + }, + "error": { + "description": "Optional error text when the tool call failed before producing a response.", + "type": [ + "string", + "null" + ] + }, + "success": { + "description": "Whether the tool call succeeded.", + "type": "boolean" + }, + "tool": { + "description": "Dynamic tool name.", + "type": "string" + }, + "turn_id": { + "description": "Turn ID that this dynamic tool call belongs to.", + "type": "string" + }, + "type": { + "enum": [ + "dynamic_tool_call_response" + ], + "title": "DynamicToolCallResponseEventMsgType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "content_items", + "duration", + "success", + "tool", + "turn_id", + "type" + ], + "title": "DynamicToolCallResponseEventMsg", + "type": "object" + }, { "properties": { "item_id": { @@ -7105,6 +7213,70 @@ "title": "DynamicToolCallRequestEventMsg", "type": "object" }, + { + "properties": { + "arguments": { + "description": "Dynamic tool call arguments." + }, + "call_id": { + "description": "Identifier for the corresponding DynamicToolCallRequest.", + "type": "string" + }, + "content_items": { + "description": "Dynamic tool response content items.", + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": "array" + }, + "duration": { + "allOf": [ + { + "$ref": "#/definitions/Duration" + } + ], + "description": "The duration of the dynamic tool call." + }, + "error": { + "description": "Optional error text when the tool call failed before producing a response.", + "type": [ + "string", + "null" + ] + }, + "success": { + "description": "Whether the tool call succeeded.", + "type": "boolean" + }, + "tool": { + "description": "Dynamic tool name.", + "type": "string" + }, + "turn_id": { + "description": "Turn ID that this dynamic tool call belongs to.", + "type": "string" + }, + "type": { + "enum": [ + "dynamic_tool_call_response" + ], + "title": "DynamicToolCallResponseEventMsgType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "content_items", + "duration", + "success", + "tool", + "turn_id", + "type" + ], + "title": "DynamicToolCallResponseEventMsg", + "type": "object" + }, { "properties": { "item_id": { diff --git a/codex-rs/app-server-protocol/schema/json/ServerNotification.json b/codex-rs/app-server-protocol/schema/json/ServerNotification.json index b2dc4c3c3e8..4329b0d45b6 100644 --- a/codex-rs/app-server-protocol/schema/json/ServerNotification.json +++ b/codex-rs/app-server-protocol/schema/json/ServerNotification.json @@ -778,6 +778,58 @@ ], "type": "object" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "ErrorNotification": { "properties": { "error": { @@ -1965,6 +2017,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 859970ef660..60db70272e2 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 @@ -1486,50 +1486,6 @@ ], "type": "object" }, - "DynamicToolCallOutputContentItem": { - "oneOf": [ - { - "properties": { - "text": { - "type": "string" - }, - "type": { - "enum": [ - "inputText" - ], - "title": "InputTextDynamicToolCallOutputContentItemType", - "type": "string" - } - }, - "required": [ - "text", - "type" - ], - "title": "InputTextDynamicToolCallOutputContentItem", - "type": "object" - }, - { - "properties": { - "imageUrl": { - "type": "string" - }, - "type": { - "enum": [ - "inputImage" - ], - "title": "InputImageDynamicToolCallOutputContentItemType", - "type": "string" - } - }, - "required": [ - "imageUrl", - "type" - ], - "title": "InputImageDynamicToolCallOutputContentItem", - "type": "object" - } - ] - }, "DynamicToolCallParams": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { @@ -1562,7 +1518,7 @@ "properties": { "contentItems": { "items": { - "$ref": "#/definitions/DynamicToolCallOutputContentItem" + "$ref": "#/definitions/v2/DynamicToolCallOutputContentItem" }, "type": "array" }, @@ -2854,6 +2810,70 @@ "title": "DynamicToolCallRequestEventMsg", "type": "object" }, + { + "properties": { + "arguments": { + "description": "Dynamic tool call arguments." + }, + "call_id": { + "description": "Identifier for the corresponding DynamicToolCallRequest.", + "type": "string" + }, + "content_items": { + "description": "Dynamic tool response content items.", + "items": { + "$ref": "#/definitions/v2/DynamicToolCallOutputContentItem" + }, + "type": "array" + }, + "duration": { + "allOf": [ + { + "$ref": "#/definitions/Duration" + } + ], + "description": "The duration of the dynamic tool call." + }, + "error": { + "description": "Optional error text when the tool call failed before producing a response.", + "type": [ + "string", + "null" + ] + }, + "success": { + "description": "Whether the tool call succeeded.", + "type": "boolean" + }, + "tool": { + "description": "Dynamic tool name.", + "type": "string" + }, + "turn_id": { + "description": "Turn ID that this dynamic tool call belongs to.", + "type": "string" + }, + "type": { + "enum": [ + "dynamic_tool_call_response" + ], + "title": "DynamicToolCallResponseEventMsgType", + "type": "string" + } + }, + "required": [ + "arguments", + "call_id", + "content_items", + "duration", + "success", + "tool", + "turn_id", + "type" + ], + "title": "DynamicToolCallResponseEventMsg", + "type": "object" + }, { "properties": { "item_id": { @@ -8726,6 +8746,58 @@ "title": "DeprecationNoticeNotification", "type": "object" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "DynamicToolSpec": { "properties": { "description": { @@ -12438,6 +12510,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/v2/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/v2/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 98d8a631e94..c8824f560e1 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json @@ -185,6 +185,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -633,6 +685,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 ee10e470e04..04dbc073892 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json @@ -185,6 +185,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -633,6 +685,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 760477095f7..61449aa7850 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json @@ -299,6 +299,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -747,6 +799,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 71f9da2f3b2..c1dee7a5896 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json @@ -345,6 +345,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -1207,6 +1259,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 5907d13cea0..e9bce99fbdb 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json @@ -299,6 +299,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -980,6 +1032,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 9944457c3ed..e487ad0d8dc 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json @@ -299,6 +299,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -980,6 +1032,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 7778773a166..b606e34a28f 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json @@ -345,6 +345,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -1207,6 +1259,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 c4bcdf70923..faea619708b 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json @@ -299,6 +299,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -980,6 +1032,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 6b3d2ebc58a..a1de9f9efa3 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json @@ -345,6 +345,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -1207,6 +1259,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 2fbd9538f34..f8faff0101c 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json @@ -299,6 +299,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -980,6 +1032,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 df3e7beee5a..b1be7b2de64 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json @@ -299,6 +299,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -980,6 +1032,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 2c8eec7f908..84bb60c8e88 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json @@ -299,6 +299,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -747,6 +799,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 5585cd455ad..863814e1b47 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json @@ -299,6 +299,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -747,6 +799,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { 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 4462c314d27..aba5d973ab5 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json @@ -299,6 +299,58 @@ ], "type": "string" }, + "DynamicToolCallOutputContentItem": { + "oneOf": [ + { + "properties": { + "text": { + "type": "string" + }, + "type": { + "enum": [ + "inputText" + ], + "title": "InputTextDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "title": "InputTextDynamicToolCallOutputContentItem", + "type": "object" + }, + { + "properties": { + "imageUrl": { + "type": "string" + }, + "type": { + "enum": [ + "inputImage" + ], + "title": "InputImageDynamicToolCallOutputContentItemType", + "type": "string" + } + }, + "required": [ + "imageUrl", + "type" + ], + "title": "InputImageDynamicToolCallOutputContentItem", + "type": "object" + } + ] + }, + "DynamicToolCallStatus": { + "enum": [ + "inProgress", + "completed", + "failed" + ], + "type": "string" + }, "FileUpdateChange": { "properties": { "diff": { @@ -747,6 +799,59 @@ "title": "McpToolCallThreadItem", "type": "object" }, + { + "properties": { + "arguments": true, + "contentItems": { + "items": { + "$ref": "#/definitions/DynamicToolCallOutputContentItem" + }, + "type": [ + "array", + "null" + ] + }, + "durationMs": { + "description": "The duration of the dynamic tool call in milliseconds.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, + "id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/DynamicToolCallStatus" + }, + "success": { + "type": [ + "boolean", + "null" + ] + }, + "tool": { + "type": "string" + }, + "type": { + "enum": [ + "dynamicToolCall" + ], + "title": "DynamicToolCallThreadItemType", + "type": "string" + } + }, + "required": [ + "arguments", + "id", + "status", + "tool", + "type" + ], + "title": "DynamicToolCallThreadItem", + "type": "object" + }, { "properties": { "agentsStates": { diff --git a/codex-rs/app-server-protocol/schema/typescript/DynamicToolCallOutputContentItem.ts b/codex-rs/app-server-protocol/schema/typescript/DynamicToolCallOutputContentItem.ts new file mode 100644 index 00000000000..8f432109d1b --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/DynamicToolCallOutputContentItem.ts @@ -0,0 +1,5 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type DynamicToolCallOutputContentItem = { "type": "inputText", text: string, } | { "type": "inputImage", imageUrl: string, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/DynamicToolCallResponseEvent.ts b/codex-rs/app-server-protocol/schema/typescript/DynamicToolCallResponseEvent.ts new file mode 100644 index 00000000000..442c0ce6f31 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/DynamicToolCallResponseEvent.ts @@ -0,0 +1,39 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { DynamicToolCallOutputContentItem } from "./DynamicToolCallOutputContentItem"; +import type { JsonValue } from "./serde_json/JsonValue"; + +export type DynamicToolCallResponseEvent = { +/** + * Identifier for the corresponding DynamicToolCallRequest. + */ +call_id: string, +/** + * Turn ID that this dynamic tool call belongs to. + */ +turn_id: string, +/** + * Dynamic tool name. + */ +tool: string, +/** + * Dynamic tool call arguments. + */ +arguments: JsonValue, +/** + * Dynamic tool response content items. + */ +content_items: Array, +/** + * Whether the tool call succeeded. + */ +success: boolean, +/** + * Optional error text when the tool call failed before producing a response. + */ +error: string | null, +/** + * The duration of the dynamic tool call. + */ +duration: string, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/EventMsg.ts b/codex-rs/app-server-protocol/schema/typescript/EventMsg.ts index cc1009bfd58..f1e528d7db8 100644 --- a/codex-rs/app-server-protocol/schema/typescript/EventMsg.ts +++ b/codex-rs/app-server-protocol/schema/typescript/EventMsg.ts @@ -24,6 +24,7 @@ import type { CollabWaitingEndEvent } from "./CollabWaitingEndEvent"; import type { ContextCompactedEvent } from "./ContextCompactedEvent"; import type { DeprecationNoticeEvent } from "./DeprecationNoticeEvent"; import type { DynamicToolCallRequest } from "./DynamicToolCallRequest"; +import type { DynamicToolCallResponseEvent } from "./DynamicToolCallResponseEvent"; import type { ElicitationRequestEvent } from "./ElicitationRequestEvent"; import type { ErrorEvent } from "./ErrorEvent"; import type { ExecApprovalRequestEvent } from "./ExecApprovalRequestEvent"; @@ -79,4 +80,4 @@ import type { WebSearchEndEvent } from "./WebSearchEndEvent"; * Response event from the agent * NOTE: Make sure none of these values have optional types, as it will mess up the extension code-gen. */ -export type EventMsg = { "type": "error" } & ErrorEvent | { "type": "warning" } & WarningEvent | { "type": "realtime_conversation_started" } & RealtimeConversationStartedEvent | { "type": "realtime_conversation_realtime" } & RealtimeConversationRealtimeEvent | { "type": "realtime_conversation_closed" } & RealtimeConversationClosedEvent | { "type": "model_reroute" } & ModelRerouteEvent | { "type": "context_compacted" } & ContextCompactedEvent | { "type": "thread_rolled_back" } & ThreadRolledBackEvent | { "type": "task_started" } & TurnStartedEvent | { "type": "task_complete" } & TurnCompleteEvent | { "type": "token_count" } & TokenCountEvent | { "type": "agent_message" } & AgentMessageEvent | { "type": "user_message" } & UserMessageEvent | { "type": "agent_message_delta" } & AgentMessageDeltaEvent | { "type": "agent_reasoning" } & AgentReasoningEvent | { "type": "agent_reasoning_delta" } & AgentReasoningDeltaEvent | { "type": "agent_reasoning_raw_content" } & AgentReasoningRawContentEvent | { "type": "agent_reasoning_raw_content_delta" } & AgentReasoningRawContentDeltaEvent | { "type": "agent_reasoning_section_break" } & AgentReasoningSectionBreakEvent | { "type": "session_configured" } & SessionConfiguredEvent | { "type": "thread_name_updated" } & ThreadNameUpdatedEvent | { "type": "mcp_startup_update" } & McpStartupUpdateEvent | { "type": "mcp_startup_complete" } & McpStartupCompleteEvent | { "type": "mcp_tool_call_begin" } & McpToolCallBeginEvent | { "type": "mcp_tool_call_end" } & McpToolCallEndEvent | { "type": "web_search_begin" } & WebSearchBeginEvent | { "type": "web_search_end" } & WebSearchEndEvent | { "type": "exec_command_begin" } & ExecCommandBeginEvent | { "type": "exec_command_output_delta" } & ExecCommandOutputDeltaEvent | { "type": "terminal_interaction" } & TerminalInteractionEvent | { "type": "exec_command_end" } & ExecCommandEndEvent | { "type": "view_image_tool_call" } & ViewImageToolCallEvent | { "type": "exec_approval_request" } & ExecApprovalRequestEvent | { "type": "request_user_input" } & RequestUserInputEvent | { "type": "dynamic_tool_call_request" } & DynamicToolCallRequest | { "type": "skill_request_approval" } & SkillRequestApprovalEvent | { "type": "elicitation_request" } & ElicitationRequestEvent | { "type": "apply_patch_approval_request" } & ApplyPatchApprovalRequestEvent | { "type": "deprecation_notice" } & DeprecationNoticeEvent | { "type": "background_event" } & BackgroundEventEvent | { "type": "undo_started" } & UndoStartedEvent | { "type": "undo_completed" } & UndoCompletedEvent | { "type": "stream_error" } & StreamErrorEvent | { "type": "patch_apply_begin" } & PatchApplyBeginEvent | { "type": "patch_apply_end" } & PatchApplyEndEvent | { "type": "turn_diff" } & TurnDiffEvent | { "type": "get_history_entry_response" } & GetHistoryEntryResponseEvent | { "type": "mcp_list_tools_response" } & McpListToolsResponseEvent | { "type": "list_custom_prompts_response" } & ListCustomPromptsResponseEvent | { "type": "list_skills_response" } & ListSkillsResponseEvent | { "type": "list_remote_skills_response" } & ListRemoteSkillsResponseEvent | { "type": "remote_skill_downloaded" } & RemoteSkillDownloadedEvent | { "type": "skills_update_available" } | { "type": "plan_update" } & UpdatePlanArgs | { "type": "turn_aborted" } & TurnAbortedEvent | { "type": "shutdown_complete" } | { "type": "entered_review_mode" } & ReviewRequest | { "type": "exited_review_mode" } & ExitedReviewModeEvent | { "type": "raw_response_item" } & RawResponseItemEvent | { "type": "item_started" } & ItemStartedEvent | { "type": "item_completed" } & ItemCompletedEvent | { "type": "agent_message_content_delta" } & AgentMessageContentDeltaEvent | { "type": "plan_delta" } & PlanDeltaEvent | { "type": "reasoning_content_delta" } & ReasoningContentDeltaEvent | { "type": "reasoning_raw_content_delta" } & ReasoningRawContentDeltaEvent | { "type": "collab_agent_spawn_begin" } & CollabAgentSpawnBeginEvent | { "type": "collab_agent_spawn_end" } & CollabAgentSpawnEndEvent | { "type": "collab_agent_interaction_begin" } & CollabAgentInteractionBeginEvent | { "type": "collab_agent_interaction_end" } & CollabAgentInteractionEndEvent | { "type": "collab_waiting_begin" } & CollabWaitingBeginEvent | { "type": "collab_waiting_end" } & CollabWaitingEndEvent | { "type": "collab_close_begin" } & CollabCloseBeginEvent | { "type": "collab_close_end" } & CollabCloseEndEvent | { "type": "collab_resume_begin" } & CollabResumeBeginEvent | { "type": "collab_resume_end" } & CollabResumeEndEvent; +export type EventMsg = { "type": "error" } & ErrorEvent | { "type": "warning" } & WarningEvent | { "type": "realtime_conversation_started" } & RealtimeConversationStartedEvent | { "type": "realtime_conversation_realtime" } & RealtimeConversationRealtimeEvent | { "type": "realtime_conversation_closed" } & RealtimeConversationClosedEvent | { "type": "model_reroute" } & ModelRerouteEvent | { "type": "context_compacted" } & ContextCompactedEvent | { "type": "thread_rolled_back" } & ThreadRolledBackEvent | { "type": "task_started" } & TurnStartedEvent | { "type": "task_complete" } & TurnCompleteEvent | { "type": "token_count" } & TokenCountEvent | { "type": "agent_message" } & AgentMessageEvent | { "type": "user_message" } & UserMessageEvent | { "type": "agent_message_delta" } & AgentMessageDeltaEvent | { "type": "agent_reasoning" } & AgentReasoningEvent | { "type": "agent_reasoning_delta" } & AgentReasoningDeltaEvent | { "type": "agent_reasoning_raw_content" } & AgentReasoningRawContentEvent | { "type": "agent_reasoning_raw_content_delta" } & AgentReasoningRawContentDeltaEvent | { "type": "agent_reasoning_section_break" } & AgentReasoningSectionBreakEvent | { "type": "session_configured" } & SessionConfiguredEvent | { "type": "thread_name_updated" } & ThreadNameUpdatedEvent | { "type": "mcp_startup_update" } & McpStartupUpdateEvent | { "type": "mcp_startup_complete" } & McpStartupCompleteEvent | { "type": "mcp_tool_call_begin" } & McpToolCallBeginEvent | { "type": "mcp_tool_call_end" } & McpToolCallEndEvent | { "type": "web_search_begin" } & WebSearchBeginEvent | { "type": "web_search_end" } & WebSearchEndEvent | { "type": "exec_command_begin" } & ExecCommandBeginEvent | { "type": "exec_command_output_delta" } & ExecCommandOutputDeltaEvent | { "type": "terminal_interaction" } & TerminalInteractionEvent | { "type": "exec_command_end" } & ExecCommandEndEvent | { "type": "view_image_tool_call" } & ViewImageToolCallEvent | { "type": "exec_approval_request" } & ExecApprovalRequestEvent | { "type": "request_user_input" } & RequestUserInputEvent | { "type": "dynamic_tool_call_request" } & DynamicToolCallRequest | { "type": "dynamic_tool_call_response" } & DynamicToolCallResponseEvent | { "type": "skill_request_approval" } & SkillRequestApprovalEvent | { "type": "elicitation_request" } & ElicitationRequestEvent | { "type": "apply_patch_approval_request" } & ApplyPatchApprovalRequestEvent | { "type": "deprecation_notice" } & DeprecationNoticeEvent | { "type": "background_event" } & BackgroundEventEvent | { "type": "undo_started" } & UndoStartedEvent | { "type": "undo_completed" } & UndoCompletedEvent | { "type": "stream_error" } & StreamErrorEvent | { "type": "patch_apply_begin" } & PatchApplyBeginEvent | { "type": "patch_apply_end" } & PatchApplyEndEvent | { "type": "turn_diff" } & TurnDiffEvent | { "type": "get_history_entry_response" } & GetHistoryEntryResponseEvent | { "type": "mcp_list_tools_response" } & McpListToolsResponseEvent | { "type": "list_custom_prompts_response" } & ListCustomPromptsResponseEvent | { "type": "list_skills_response" } & ListSkillsResponseEvent | { "type": "list_remote_skills_response" } & ListRemoteSkillsResponseEvent | { "type": "remote_skill_downloaded" } & RemoteSkillDownloadedEvent | { "type": "skills_update_available" } | { "type": "plan_update" } & UpdatePlanArgs | { "type": "turn_aborted" } & TurnAbortedEvent | { "type": "shutdown_complete" } | { "type": "entered_review_mode" } & ReviewRequest | { "type": "exited_review_mode" } & ExitedReviewModeEvent | { "type": "raw_response_item" } & RawResponseItemEvent | { "type": "item_started" } & ItemStartedEvent | { "type": "item_completed" } & ItemCompletedEvent | { "type": "agent_message_content_delta" } & AgentMessageContentDeltaEvent | { "type": "plan_delta" } & PlanDeltaEvent | { "type": "reasoning_content_delta" } & ReasoningContentDeltaEvent | { "type": "reasoning_raw_content_delta" } & ReasoningRawContentDeltaEvent | { "type": "collab_agent_spawn_begin" } & CollabAgentSpawnBeginEvent | { "type": "collab_agent_spawn_end" } & CollabAgentSpawnEndEvent | { "type": "collab_agent_interaction_begin" } & CollabAgentInteractionBeginEvent | { "type": "collab_agent_interaction_end" } & CollabAgentInteractionEndEvent | { "type": "collab_waiting_begin" } & CollabWaitingBeginEvent | { "type": "collab_waiting_end" } & CollabWaitingEndEvent | { "type": "collab_close_begin" } & CollabCloseBeginEvent | { "type": "collab_close_end" } & CollabCloseEndEvent | { "type": "collab_resume_begin" } & CollabResumeBeginEvent | { "type": "collab_resume_end" } & CollabResumeEndEvent; diff --git a/codex-rs/app-server-protocol/schema/typescript/index.ts b/codex-rs/app-server-protocol/schema/typescript/index.ts index 3a1281cf2aa..fa3a1ee615e 100644 --- a/codex-rs/app-server-protocol/schema/typescript/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/index.ts @@ -54,7 +54,9 @@ export type { ConversationSummary } from "./ConversationSummary"; export type { CreditsSnapshot } from "./CreditsSnapshot"; export type { CustomPrompt } from "./CustomPrompt"; export type { DeprecationNoticeEvent } from "./DeprecationNoticeEvent"; +export type { DynamicToolCallOutputContentItem } from "./DynamicToolCallOutputContentItem"; export type { DynamicToolCallRequest } from "./DynamicToolCallRequest"; +export type { DynamicToolCallResponseEvent } from "./DynamicToolCallResponseEvent"; export type { ElicitationRequestEvent } from "./ElicitationRequestEvent"; export type { ErrorEvent } from "./ErrorEvent"; export type { EventMsg } from "./EventMsg"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/DynamicToolCallStatus.ts b/codex-rs/app-server-protocol/schema/typescript/v2/DynamicToolCallStatus.ts new file mode 100644 index 00000000000..04f44ec0a8b --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/DynamicToolCallStatus.ts @@ -0,0 +1,5 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type DynamicToolCallStatus = "inProgress" | "completed" | "failed"; 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 dee39cd5db7..d937d53b444 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts @@ -8,6 +8,8 @@ import type { CollabAgentTool } from "./CollabAgentTool"; import type { CollabAgentToolCallStatus } from "./CollabAgentToolCallStatus"; import type { CommandAction } from "./CommandAction"; import type { CommandExecutionStatus } from "./CommandExecutionStatus"; +import type { DynamicToolCallOutputContentItem } from "./DynamicToolCallOutputContentItem"; +import type { DynamicToolCallStatus } from "./DynamicToolCallStatus"; import type { FileUpdateChange } from "./FileUpdateChange"; import type { McpToolCallError } from "./McpToolCallError"; import type { McpToolCallResult } from "./McpToolCallResult"; @@ -50,6 +52,10 @@ durationMs: number | null, } | { "type": "fileChange", id: string, changes: Arra /** * The duration of the MCP tool call in milliseconds. */ +durationMs: number | null, } | { "type": "dynamicToolCall", id: string, tool: string, arguments: JsonValue, status: DynamicToolCallStatus, contentItems: Array | null, success: boolean | null, +/** + * The duration of the dynamic tool call in milliseconds. + */ durationMs: number | null, } | { "type": "collabAgentToolCall", /** * Unique identifier for this collab tool call. diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts index 12e6e9adb1d..f92358cfdf9 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts @@ -58,6 +58,7 @@ export type { DeprecationNoticeNotification } from "./DeprecationNoticeNotificat export type { DynamicToolCallOutputContentItem } from "./DynamicToolCallOutputContentItem"; export type { DynamicToolCallParams } from "./DynamicToolCallParams"; export type { DynamicToolCallResponse } from "./DynamicToolCallResponse"; +export type { DynamicToolCallStatus } from "./DynamicToolCallStatus"; export type { DynamicToolSpec } from "./DynamicToolSpec"; export type { ErrorNotification } from "./ErrorNotification"; export type { ExecPolicyAmendment } from "./ExecPolicyAmendment"; 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 c6d0cc00fe9..97ad8d521ff 100644 --- a/codex-rs/app-server-protocol/src/protocol/thread_history.rs +++ b/codex-rs/app-server-protocol/src/protocol/thread_history.rs @@ -3,6 +3,8 @@ use crate::protocol::v2::CollabAgentTool; use crate::protocol::v2::CollabAgentToolCallStatus; use crate::protocol::v2::CommandAction; use crate::protocol::v2::CommandExecutionStatus; +use crate::protocol::v2::DynamicToolCallOutputContentItem; +use crate::protocol::v2::DynamicToolCallStatus; use crate::protocol::v2::FileUpdateChange; use crate::protocol::v2::McpToolCallError; use crate::protocol::v2::McpToolCallResult; @@ -22,6 +24,7 @@ use codex_protocol::protocol::AgentReasoningRawContentEvent; use codex_protocol::protocol::AgentStatus; use codex_protocol::protocol::CompactedItem; use codex_protocol::protocol::ContextCompactedEvent; +use codex_protocol::protocol::DynamicToolCallResponseEvent; use codex_protocol::protocol::ErrorEvent; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::ExecCommandBeginEvent; @@ -125,6 +128,12 @@ impl ThreadHistoryBuilder { EventMsg::ExecCommandEnd(payload) => self.handle_exec_command_end(payload), EventMsg::PatchApplyBegin(payload) => self.handle_patch_apply_begin(payload), EventMsg::PatchApplyEnd(payload) => self.handle_patch_apply_end(payload), + EventMsg::DynamicToolCallRequest(payload) => { + self.handle_dynamic_tool_call_request(payload) + } + EventMsg::DynamicToolCallResponse(payload) => { + self.handle_dynamic_tool_call_response(payload) + } EventMsg::McpToolCallBegin(payload) => self.handle_mcp_tool_call_begin(payload), EventMsg::McpToolCallEnd(payload) => self.handle_mcp_tool_call_end(payload), EventMsg::ViewImageToolCall(payload) => self.handle_view_image_tool_call(payload), @@ -382,6 +391,49 @@ impl ThreadHistoryBuilder { } } + fn handle_dynamic_tool_call_request( + &mut self, + payload: &codex_protocol::dynamic_tools::DynamicToolCallRequest, + ) { + let item = ThreadItem::DynamicToolCall { + id: payload.call_id.clone(), + tool: payload.tool.clone(), + arguments: payload.arguments.clone(), + status: DynamicToolCallStatus::InProgress, + content_items: None, + success: None, + duration_ms: None, + }; + if payload.turn_id.is_empty() { + self.upsert_item_in_current_turn(item); + } else { + self.upsert_item_in_turn_id(&payload.turn_id, item); + } + } + + fn handle_dynamic_tool_call_response(&mut self, payload: &DynamicToolCallResponseEvent) { + let status = if payload.success { + DynamicToolCallStatus::Completed + } else { + DynamicToolCallStatus::Failed + }; + let duration_ms = i64::try_from(payload.duration.as_millis()).ok(); + let item = ThreadItem::DynamicToolCall { + id: payload.call_id.clone(), + tool: payload.tool.clone(), + arguments: payload.arguments.clone(), + status, + content_items: Some(convert_dynamic_tool_content_items(&payload.content_items)), + success: Some(payload.success), + duration_ms, + }; + if payload.turn_id.is_empty() { + self.upsert_item_in_current_turn(item); + } else { + self.upsert_item_in_turn_id(&payload.turn_id, item); + } + } + fn handle_mcp_tool_call_begin(&mut self, payload: &McpToolCallBeginEvent) { let item = ThreadItem::McpToolCall { id: payload.call_id.clone(), @@ -913,6 +965,23 @@ pub fn convert_patch_changes( converted } +fn convert_dynamic_tool_content_items( + items: &[codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem], +) -> Vec { + items + .iter() + .cloned() + .map(|item| match item { + codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem::InputText { text } => { + DynamicToolCallOutputContentItem::InputText { text } + } + codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem::InputImage { + image_url, + } => DynamicToolCallOutputContentItem::InputImage { image_url }, + }) + .collect() +} + fn map_patch_change_kind(change: &codex_protocol::protocol::FileChange) -> PatchChangeKind { match change { codex_protocol::protocol::FileChange::Add { .. } => PatchChangeKind::Add, @@ -1002,6 +1071,7 @@ impl From<&PendingTurn> for Turn { mod tests { use super::*; use codex_protocol::ThreadId; + use codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem as CoreDynamicToolCallOutputContentItem; use codex_protocol::items::TurnItem as CoreTurnItem; use codex_protocol::items::UserMessageItem as CoreUserMessageItem; use codex_protocol::models::MessagePhase as CoreMessagePhase; @@ -1012,6 +1082,7 @@ mod tests { use codex_protocol::protocol::AgentReasoningRawContentEvent; use codex_protocol::protocol::CodexErrorInfo; use codex_protocol::protocol::CompactedItem; + use codex_protocol::protocol::DynamicToolCallResponseEvent; use codex_protocol::protocol::ExecCommandEndEvent; use codex_protocol::protocol::ExecCommandSource; use codex_protocol::protocol::ItemStartedEvent; @@ -1606,6 +1677,65 @@ mod tests { ); } + #[test] + fn reconstructs_dynamic_tool_items_from_request_and_response_events() { + let events = vec![ + EventMsg::TurnStarted(TurnStartedEvent { + turn_id: "turn-1".into(), + model_context_window: None, + collaboration_mode_kind: Default::default(), + }), + EventMsg::UserMessage(UserMessageEvent { + message: "run dynamic tool".into(), + images: None, + text_elements: Vec::new(), + local_images: Vec::new(), + }), + EventMsg::DynamicToolCallRequest( + codex_protocol::dynamic_tools::DynamicToolCallRequest { + call_id: "dyn-1".into(), + turn_id: "turn-1".into(), + tool: "lookup_ticket".into(), + arguments: serde_json::json!({"id":"ABC-123"}), + }, + ), + EventMsg::DynamicToolCallResponse(DynamicToolCallResponseEvent { + call_id: "dyn-1".into(), + turn_id: "turn-1".into(), + tool: "lookup_ticket".into(), + arguments: serde_json::json!({"id":"ABC-123"}), + content_items: vec![CoreDynamicToolCallOutputContentItem::InputText { + text: "Ticket is open".into(), + }], + success: true, + error: None, + duration: Duration::from_millis(42), + }), + ]; + + let items = events + .into_iter() + .map(RolloutItem::EventMsg) + .collect::>(); + let turns = build_turns_from_rollout_items(&items); + assert_eq!(turns.len(), 1); + assert_eq!(turns[0].items.len(), 2); + assert_eq!( + turns[0].items[1], + ThreadItem::DynamicToolCall { + id: "dyn-1".into(), + tool: "lookup_ticket".into(), + arguments: serde_json::json!({"id":"ABC-123"}), + status: DynamicToolCallStatus::Completed, + content_items: Some(vec![DynamicToolCallOutputContentItem::InputText { + text: "Ticket is open".into(), + }]), + success: Some(true), + duration_ms: Some(42), + } + ); + } + #[test] fn reconstructs_declined_exec_and_patch_items() { let events = vec![ diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index b1f6ceb5c1f..b66af095423 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -2742,6 +2742,19 @@ pub enum ThreadItem { }, #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] + DynamicToolCall { + id: String, + tool: String, + arguments: JsonValue, + status: DynamicToolCallStatus, + content_items: Option>, + success: Option, + /// The duration of the dynamic tool call in milliseconds. + #[ts(type = "number | null")] + duration_ms: Option, + }, + #[serde(rename_all = "camelCase")] + #[ts(rename_all = "camelCase")] CollabAgentToolCall { /// Unique identifier for this collab tool call. id: String, @@ -2790,6 +2803,7 @@ impl ThreadItem { | ThreadItem::CommandExecution { id, .. } | ThreadItem::FileChange { id, .. } | ThreadItem::McpToolCall { id, .. } + | ThreadItem::DynamicToolCall { id, .. } | ThreadItem::CollabAgentToolCall { id, .. } | ThreadItem::WebSearch { id, .. } | ThreadItem::ImageView { id, .. } @@ -2970,6 +2984,15 @@ pub enum McpToolCallStatus { Failed, } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub enum DynamicToolCallStatus { + InProgress, + Completed, + Failed, +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index 8ee15688c6d..0df0fcc67a5 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -702,6 +702,13 @@ When a dynamic tool is invoked during a turn, the server sends an `item/tool/cal } ``` +The server also emits item lifecycle notifications around the request: + +1. `item/started` with `item.type = "dynamicToolCall"`, `status = "inProgress"`, plus `tool` and `arguments`. +2. `item/tool/call` request. +3. Client response. +4. `item/completed` with `item.type = "dynamicToolCall"`, final `status`, and the returned `contentItems`/`success`. + The client must respond with content items. Use `inputText` for text and `inputImage` for image URLs/data URLs: ```json diff --git a/codex-rs/app-server/src/bespoke_event_handling.rs b/codex-rs/app-server/src/bespoke_event_handling.rs index 2a5557b5bad..2b348dbf828 100644 --- a/codex-rs/app-server/src/bespoke_event_handling.rs +++ b/codex-rs/app-server/src/bespoke_event_handling.rs @@ -26,7 +26,9 @@ use codex_app_server_protocol::CommandExecutionRequestApprovalResponse; use codex_app_server_protocol::CommandExecutionStatus; use codex_app_server_protocol::ContextCompactedNotification; use codex_app_server_protocol::DeprecationNoticeNotification; +use codex_app_server_protocol::DynamicToolCallOutputContentItem; use codex_app_server_protocol::DynamicToolCallParams; +use codex_app_server_protocol::DynamicToolCallStatus; use codex_app_server_protocol::ErrorNotification; use codex_app_server_protocol::ExecCommandApprovalParams; use codex_app_server_protocol::ExecCommandApprovalResponse; @@ -461,12 +463,32 @@ pub(crate) async fn apply_bespoke_event_handling( EventMsg::DynamicToolCallRequest(request) => { if matches!(api_version, ApiVersion::V2) { let call_id = request.call_id; + let turn_id = request.turn_id; + let tool = request.tool; + let arguments = request.arguments; + let item = ThreadItem::DynamicToolCall { + id: call_id.clone(), + tool: tool.clone(), + arguments: arguments.clone(), + status: DynamicToolCallStatus::InProgress, + content_items: None, + success: None, + duration_ms: None, + }; + let notification = ItemStartedNotification { + thread_id: conversation_id.to_string(), + turn_id: turn_id.clone(), + item, + }; + outgoing + .send_server_notification(ServerNotification::ItemStarted(notification)) + .await; let params = DynamicToolCallParams { thread_id: conversation_id.to_string(), - turn_id: request.turn_id, + turn_id: turn_id.clone(), call_id: call_id.clone(), - tool: request.tool, - arguments: request.arguments, + tool: tool.clone(), + arguments: arguments.clone(), }; let rx = outgoing .send_request(ServerRequestPayload::DynamicToolCall(params)) @@ -493,6 +515,46 @@ pub(crate) async fn apply_bespoke_event_handling( .await; } } + EventMsg::DynamicToolCallResponse(response) => { + if matches!(api_version, ApiVersion::V2) { + let status = if response.success { + DynamicToolCallStatus::Completed + } else { + DynamicToolCallStatus::Failed + }; + let duration_ms = i64::try_from(response.duration.as_millis()).ok(); + let item = ThreadItem::DynamicToolCall { + id: response.call_id, + tool: response.tool, + arguments: response.arguments, + status, + content_items: Some( + response + .content_items + .into_iter() + .map(|item| match item { + CoreDynamicToolCallOutputContentItem::InputText { text } => { + DynamicToolCallOutputContentItem::InputText { text } + } + CoreDynamicToolCallOutputContentItem::InputImage { image_url } => { + DynamicToolCallOutputContentItem::InputImage { image_url } + } + }) + .collect(), + ), + success: Some(response.success), + duration_ms, + }; + let notification = ItemCompletedNotification { + thread_id: conversation_id.to_string(), + turn_id: response.turn_id, + item, + }; + outgoing + .send_server_notification(ServerNotification::ItemCompleted(notification)) + .await; + } + } // TODO(celia): properly construct McpToolCall TurnItem in core. EventMsg::McpToolCallBegin(begin_event) => { let notification = construct_mcp_tool_call_notification( diff --git a/codex-rs/app-server/src/dynamic_tools.rs b/codex-rs/app-server/src/dynamic_tools.rs index 31374d80b6c..522bcfdcac4 100644 --- a/codex-rs/app-server/src/dynamic_tools.rs +++ b/codex-rs/app-server/src/dynamic_tools.rs @@ -1,3 +1,4 @@ +use codex_app_server_protocol::DynamicToolCallOutputContentItem; use codex_app_server_protocol::DynamicToolCallResponse; use codex_core::CodexThread; use codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem as CoreDynamicToolCallOutputContentItem; @@ -15,65 +16,23 @@ pub(crate) async fn on_call_response( conversation: Arc, ) { let response = receiver.await; - let value = match response { - Ok(Ok(value)) => value, + let (response, _error) = match response { + Ok(Ok(value)) => decode_response(value), Ok(Err(err)) => { error!("request failed with client error: {err:?}"); - let fallback = CoreDynamicToolResponse { - content_items: vec![CoreDynamicToolCallOutputContentItem::InputText { - text: "dynamic tool request failed".to_string(), - }], - success: false, - }; - if let Err(err) = conversation - .submit(Op::DynamicToolResponse { - id: call_id.clone(), - response: fallback, - }) - .await - { - error!("failed to submit DynamicToolResponse: {err}"); - } - return; + fallback_response("dynamic tool request failed") } Err(err) => { error!("request failed: {err:?}"); - let fallback = CoreDynamicToolResponse { - content_items: vec![CoreDynamicToolCallOutputContentItem::InputText { - text: "dynamic tool request failed".to_string(), - }], - success: false, - }; - if let Err(err) = conversation - .submit(Op::DynamicToolResponse { - id: call_id.clone(), - response: fallback, - }) - .await - { - error!("failed to submit DynamicToolResponse: {err}"); - } - return; + fallback_response("dynamic tool request failed") } }; - let response = serde_json::from_value::(value).unwrap_or_else(|err| { - error!("failed to deserialize DynamicToolCallResponse: {err}"); - DynamicToolCallResponse { - content_items: vec![ - codex_app_server_protocol::DynamicToolCallOutputContentItem::InputText { - text: "dynamic tool response was invalid".to_string(), - }, - ], - success: false, - } - }); - let DynamicToolCallResponse { content_items, success, - } = response; - let response = CoreDynamicToolResponse { + } = response.clone(); + let core_response = CoreDynamicToolResponse { content_items: content_items .into_iter() .map(CoreDynamicToolCallOutputContentItem::from) @@ -82,11 +41,33 @@ pub(crate) async fn on_call_response( }; if let Err(err) = conversation .submit(Op::DynamicToolResponse { - id: call_id, - response, + id: call_id.clone(), + response: core_response, }) .await { error!("failed to submit DynamicToolResponse: {err}"); } } + +fn decode_response(value: serde_json::Value) -> (DynamicToolCallResponse, Option) { + match serde_json::from_value::(value) { + Ok(response) => (response, None), + Err(err) => { + error!("failed to deserialize DynamicToolCallResponse: {err}"); + fallback_response("dynamic tool response was invalid") + } + } +} + +fn fallback_response(message: &str) -> (DynamicToolCallResponse, Option) { + ( + DynamicToolCallResponse { + content_items: vec![DynamicToolCallOutputContentItem::InputText { + text: message.to_string(), + }], + success: false, + }, + Some(message.to_string()), + ) +} diff --git a/codex-rs/app-server/tests/suite/v2/dynamic_tools.rs b/codex-rs/app-server/tests/suite/v2/dynamic_tools.rs index f4cd85a61d1..52a597f66b8 100644 --- a/codex-rs/app-server/tests/suite/v2/dynamic_tools.rs +++ b/codex-rs/app-server/tests/suite/v2/dynamic_tools.rs @@ -7,10 +7,15 @@ use app_test_support::to_response; use codex_app_server_protocol::DynamicToolCallOutputContentItem; use codex_app_server_protocol::DynamicToolCallParams; use codex_app_server_protocol::DynamicToolCallResponse; +use codex_app_server_protocol::DynamicToolCallStatus; use codex_app_server_protocol::DynamicToolSpec; +use codex_app_server_protocol::ItemCompletedNotification; +use codex_app_server_protocol::ItemStartedNotification; +use codex_app_server_protocol::JSONRPCNotification; use codex_app_server_protocol::JSONRPCResponse; use codex_app_server_protocol::RequestId; use codex_app_server_protocol::ServerRequest; +use codex_app_server_protocol::ThreadItem; use codex_app_server_protocol::ThreadStartParams; use codex_app_server_protocol::ThreadStartResponse; use codex_app_server_protocol::TurnStartParams; @@ -163,11 +168,12 @@ async fn dynamic_tool_call_round_trip_sends_text_content_items_to_model() -> Res ) .await??; let ThreadStartResponse { thread, .. } = to_response::(thread_resp)?; + let thread_id = thread.id.clone(); // Start a turn so the tool call is emitted. let turn_req = mcp .send_turn_start_request(TurnStartParams { - thread_id: thread.id.clone(), + thread_id: thread_id.clone(), input: vec![V2UserInput::Text { text: "Run the tool".to_string(), text_elements: Vec::new(), @@ -181,6 +187,30 @@ async fn dynamic_tool_call_round_trip_sends_text_content_items_to_model() -> Res ) .await??; let TurnStartResponse { turn } = to_response::(turn_resp)?; + let turn_id = turn.id.clone(); + + let started = wait_for_dynamic_tool_started(&mut mcp, call_id).await?; + assert_eq!(started.thread_id, thread_id); + assert_eq!(started.turn_id, turn_id.clone()); + let ThreadItem::DynamicToolCall { + id, + tool, + arguments, + status, + content_items, + success, + duration_ms, + } = started.item + else { + panic!("expected dynamic tool call item"); + }; + assert_eq!(id, call_id); + assert_eq!(tool, tool_name); + assert_eq!(arguments, tool_args); + assert_eq!(status, DynamicToolCallStatus::InProgress); + assert_eq!(content_items, None); + assert_eq!(success, None); + assert_eq!(duration_ms, None); // Read the tool call request from the app server. let request = timeout( @@ -194,8 +224,8 @@ async fn dynamic_tool_call_round_trip_sends_text_content_items_to_model() -> Res }; let expected = DynamicToolCallParams { - thread_id: thread.id, - turn_id: turn.id, + thread_id: thread_id.clone(), + turn_id: turn_id.clone(), call_id: call_id.to_string(), tool: tool_name.to_string(), arguments: tool_args.clone(), @@ -212,6 +242,34 @@ async fn dynamic_tool_call_round_trip_sends_text_content_items_to_model() -> Res mcp.send_response(request_id, serde_json::to_value(response)?) .await?; + let completed = wait_for_dynamic_tool_completed(&mut mcp, call_id).await?; + assert_eq!(completed.thread_id, thread_id); + assert_eq!(completed.turn_id, turn_id); + let ThreadItem::DynamicToolCall { + id, + tool, + arguments, + status, + content_items, + success, + duration_ms, + } = completed.item + else { + panic!("expected dynamic tool call item"); + }; + assert_eq!(id, call_id); + assert_eq!(tool, tool_name); + assert_eq!(arguments, tool_args); + assert_eq!(status, DynamicToolCallStatus::Completed); + assert_eq!( + content_items, + Some(vec![DynamicToolCallOutputContentItem::InputText { + text: "dynamic-ok".to_string(), + }]) + ); + assert_eq!(success, Some(true)); + assert!(duration_ms.is_some()); + timeout( DEFAULT_READ_TIMEOUT, mcp.read_stream_until_notification_message("turn/completed"), @@ -282,10 +340,11 @@ async fn dynamic_tool_call_round_trip_sends_content_items_to_model() -> Result<( ) .await??; let ThreadStartResponse { thread, .. } = to_response::(thread_resp)?; + let thread_id = thread.id.clone(); let turn_req = mcp .send_turn_start_request(TurnStartParams { - thread_id: thread.id.clone(), + thread_id: thread_id.clone(), input: vec![V2UserInput::Text { text: "Run the tool".to_string(), text_elements: Vec::new(), @@ -299,6 +358,11 @@ async fn dynamic_tool_call_round_trip_sends_content_items_to_model() -> Result<( ) .await??; let TurnStartResponse { turn } = to_response::(turn_resp)?; + let turn_id = turn.id.clone(); + + let started = wait_for_dynamic_tool_started(&mut mcp, call_id).await?; + assert_eq!(started.thread_id, thread_id.clone()); + assert_eq!(started.turn_id, turn_id.clone()); let request = timeout( DEFAULT_READ_TIMEOUT, @@ -311,8 +375,8 @@ async fn dynamic_tool_call_round_trip_sends_content_items_to_model() -> Result<( }; let expected = DynamicToolCallParams { - thread_id: thread.id, - turn_id: turn.id, + thread_id, + turn_id: turn_id.clone(), call_id: call_id.to_string(), tool: tool_name.to_string(), arguments: tool_args, @@ -346,6 +410,32 @@ async fn dynamic_tool_call_round_trip_sends_content_items_to_model() -> Result<( mcp.send_response(request_id, serde_json::to_value(response)?) .await?; + let completed = wait_for_dynamic_tool_completed(&mut mcp, call_id).await?; + assert_eq!(completed.thread_id, expected.thread_id.clone()); + assert_eq!(completed.turn_id, turn_id); + let ThreadItem::DynamicToolCall { + status, + content_items: completed_content_items, + success, + .. + } = completed.item + else { + panic!("expected dynamic tool call item"); + }; + assert_eq!(status, DynamicToolCallStatus::Completed); + assert_eq!( + completed_content_items, + Some(vec![ + DynamicToolCallOutputContentItem::InputText { + text: "dynamic-ok".to_string(), + }, + DynamicToolCallOutputContentItem::InputImage { + image_url: "data:image/png;base64,AAA".to_string(), + }, + ]) + ); + assert_eq!(success, Some(true)); + timeout( DEFAULT_READ_TIMEOUT, mcp.read_stream_until_notification_message("turn/completed"), @@ -432,6 +522,46 @@ fn function_call_output_raw_output(body: &Value, call_id: &str) -> Option .cloned() } +async fn wait_for_dynamic_tool_started( + mcp: &mut McpProcess, + call_id: &str, +) -> Result { + loop { + let notification: JSONRPCNotification = timeout( + DEFAULT_READ_TIMEOUT, + mcp.read_stream_until_notification_message("item/started"), + ) + .await??; + let Some(params) = notification.params else { + continue; + }; + let started: ItemStartedNotification = serde_json::from_value(params)?; + if matches!(&started.item, ThreadItem::DynamicToolCall { id, .. } if id == call_id) { + return Ok(started); + } + } +} + +async fn wait_for_dynamic_tool_completed( + mcp: &mut McpProcess, + call_id: &str, +) -> Result { + loop { + let notification: JSONRPCNotification = timeout( + DEFAULT_READ_TIMEOUT, + mcp.read_stream_until_notification_message("item/completed"), + ) + .await??; + let Some(params) = notification.params else { + continue; + }; + let completed: ItemCompletedNotification = serde_json::from_value(params)?; + if matches!(&completed.item, ThreadItem::DynamicToolCall { id, .. } if id == call_id) { + return Ok(completed); + } + } +} + fn create_config_toml(codex_home: &Path, server_uri: &str) -> std::io::Result<()> { let config_toml = codex_home.join("config.toml"); std::fs::write( diff --git a/codex-rs/core/src/rollout/policy.rs b/codex-rs/core/src/rollout/policy.rs index 8232330232a..a1e77ba4fca 100644 --- a/codex-rs/core/src/rollout/policy.rs +++ b/codex-rs/core/src/rollout/policy.rs @@ -120,7 +120,9 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option { | EventMsg::CollabAgentInteractionEnd(_) | EventMsg::CollabWaitingEnd(_) | EventMsg::CollabCloseEnd(_) - | EventMsg::CollabResumeEnd(_) => Some(EventPersistenceMode::Extended), + | EventMsg::CollabResumeEnd(_) + | EventMsg::DynamicToolCallRequest(_) + | EventMsg::DynamicToolCallResponse(_) => Some(EventPersistenceMode::Extended), EventMsg::Warning(_) | EventMsg::RealtimeConversationStarted(_) | EventMsg::RealtimeConversationRealtime(_) @@ -141,7 +143,6 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option { | EventMsg::ExecApprovalRequest(_) | EventMsg::SkillRequestApproval(_) | EventMsg::RequestUserInput(_) - | EventMsg::DynamicToolCallRequest(_) | EventMsg::ElicitationRequest(_) | EventMsg::ApplyPatchApprovalRequest(_) | EventMsg::BackgroundEvent(_) diff --git a/codex-rs/core/src/tools/handlers/dynamic.rs b/codex-rs/core/src/tools/handlers/dynamic.rs index 51dc8db56f9..23c8474b9ff 100644 --- a/codex-rs/core/src/tools/handlers/dynamic.rs +++ b/codex-rs/core/src/tools/handlers/dynamic.rs @@ -12,8 +12,10 @@ use codex_protocol::dynamic_tools::DynamicToolCallRequest; use codex_protocol::dynamic_tools::DynamicToolResponse; use codex_protocol::models::FunctionCallOutputBody; use codex_protocol::models::FunctionCallOutputContentItem; +use codex_protocol::protocol::DynamicToolCallResponseEvent; use codex_protocol::protocol::EventMsg; use serde_json::Value; +use std::time::Instant; use tokio::sync::oneshot; use tracing::warn; @@ -81,7 +83,7 @@ async fn request_dynamic_tool( tool: String, arguments: Value, ) -> Option { - let _sub_id = turn_context.sub_id.clone(); + let turn_id = turn_context.sub_id.clone(); let (tx_response, rx_response) = oneshot::channel(); let event_id = call_id.clone(); let prev_entry = { @@ -98,12 +100,39 @@ async fn request_dynamic_tool( warn!("Overwriting existing pending dynamic tool call for call_id: {event_id}"); } + let started_at = Instant::now(); let event = EventMsg::DynamicToolCallRequest(DynamicToolCallRequest { - call_id, - turn_id: turn_context.sub_id.clone(), - tool, - arguments, + call_id: call_id.clone(), + turn_id: turn_id.clone(), + tool: tool.clone(), + arguments: arguments.clone(), }); session.send_event(turn_context, event).await; - rx_response.await.ok() + let response = rx_response.await.ok(); + + let response_event = match &response { + Some(response) => EventMsg::DynamicToolCallResponse(DynamicToolCallResponseEvent { + call_id, + turn_id, + tool, + arguments, + content_items: response.content_items.clone(), + success: response.success, + error: None, + duration: started_at.elapsed(), + }), + None => EventMsg::DynamicToolCallResponse(DynamicToolCallResponseEvent { + call_id, + turn_id, + tool, + arguments, + content_items: Vec::new(), + success: false, + error: Some("dynamic tool call was cancelled before receiving a response".to_string()), + duration: started_at.elapsed(), + }), + }; + session.send_event(turn_context, response_event).await; + + response } diff --git a/codex-rs/exec/src/event_processor_with_human_output.rs b/codex-rs/exec/src/event_processor_with_human_output.rs index 6e679052e03..eac514a8f1e 100644 --- a/codex-rs/exec/src/event_processor_with_human_output.rs +++ b/codex-rs/exec/src/event_processor_with_human_output.rs @@ -854,6 +854,7 @@ impl EventProcessor for EventProcessorWithHumanOutput { | EventMsg::RealtimeConversationRealtime(_) | EventMsg::RealtimeConversationClosed(_) | EventMsg::DynamicToolCallRequest(_) + | EventMsg::DynamicToolCallResponse(_) | EventMsg::SkillRequestApproval(_) => {} } CodexStatus::Running @@ -925,6 +926,7 @@ impl EventProcessorWithHumanOutput { | EventMsg::ThreadRolledBack(_) | EventMsg::RequestUserInput(_) | EventMsg::DynamicToolCallRequest(_) + | EventMsg::DynamicToolCallResponse(_) ) } diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index 382081dd3de..75cc1393925 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -694,6 +694,7 @@ fn should_suppress_agent_job_event(msg: &EventMsg) -> bool { | EventMsg::ApplyPatchApprovalRequest(_) | EventMsg::RequestUserInput(_) | EventMsg::DynamicToolCallRequest(_) + | EventMsg::DynamicToolCallResponse(_) | EventMsg::ElicitationRequest(_) | EventMsg::Error(_) | EventMsg::Warning(_) diff --git a/codex-rs/mcp-server/src/codex_tool_runner.rs b/codex-rs/mcp-server/src/codex_tool_runner.rs index eff8d8e13eb..805ac0e6ea3 100644 --- a/codex-rs/mcp-server/src/codex_tool_runner.rs +++ b/codex-rs/mcp-server/src/codex_tool_runner.rs @@ -363,6 +363,7 @@ async fn run_codex_tool_session_inner( | EventMsg::ExitedReviewMode(_) | EventMsg::RequestUserInput(_) | EventMsg::DynamicToolCallRequest(_) + | EventMsg::DynamicToolCallResponse(_) | EventMsg::SkillRequestApproval(_) | EventMsg::ContextCompacted(_) | EventMsg::ModelReroute(_) diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index a8770cc90a0..0e2e86f8ca8 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -20,6 +20,7 @@ use crate::config_types::Personality; use crate::config_types::ReasoningSummary as ReasoningSummaryConfig; use crate::config_types::WindowsSandboxLevel; use crate::custom_prompts::CustomPrompt; +use crate::dynamic_tools::DynamicToolCallOutputContentItem; use crate::dynamic_tools::DynamicToolCallRequest; use crate::dynamic_tools::DynamicToolResponse; use crate::dynamic_tools::DynamicToolSpec; @@ -1053,6 +1054,8 @@ pub enum EventMsg { DynamicToolCallRequest(DynamicToolCallRequest), + DynamicToolCallResponse(DynamicToolCallResponseEvent), + SkillRequestApproval(SkillRequestApprovalEvent), ElicitationRequest(ElicitationRequestEvent), @@ -1781,6 +1784,27 @@ pub struct McpToolCallEndEvent { pub result: Result, } +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS, PartialEq)] +pub struct DynamicToolCallResponseEvent { + /// Identifier for the corresponding DynamicToolCallRequest. + pub call_id: String, + /// Turn ID that this dynamic tool call belongs to. + pub turn_id: String, + /// Dynamic tool name. + pub tool: String, + /// Dynamic tool call arguments. + pub arguments: serde_json::Value, + /// Dynamic tool response content items. + pub content_items: Vec, + /// Whether the tool call succeeded. + pub success: bool, + /// Optional error text when the tool call failed before producing a response. + pub error: Option, + /// The duration of the dynamic tool call. + #[ts(type = "string")] + pub duration: Duration, +} + impl McpToolCallEndEvent { pub fn is_success(&self) -> bool { match &self.result { diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index ac8da4d55d7..3639fe50289 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -4461,6 +4461,7 @@ impl ChatWidget { | EventMsg::ReasoningContentDelta(_) | EventMsg::ReasoningRawContentDelta(_) | EventMsg::DynamicToolCallRequest(_) + | EventMsg::DynamicToolCallResponse(_) | EventMsg::SkillRequestApproval(_) => {} EventMsg::RealtimeConversationStarted(ev) => { if !from_replay {