diff --git a/codex-rs/app-server-protocol/schema/json/EventMsg.json b/codex-rs/app-server-protocol/schema/json/EventMsg.json index cbf6f7476..ad420594b 100644 --- a/codex-rs/app-server-protocol/schema/json/EventMsg.json +++ b/codex-rs/app-server-protocol/schema/json/EventMsg.json @@ -3059,6 +3059,10 @@ "description": "Identifier for the collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent.", + "type": "string" + }, "new_agent_nickname": { "description": "Optional nickname assigned to the new agent.", "type": [ @@ -3088,6 +3092,14 @@ "description": "Initial prompt sent to the agent. Can be empty to prevent CoT leaking at the beginning.", "type": "string" }, + "reasoning_effort": { + "allOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + } + ], + "description": "Reasoning effort requested for the spawned agent." + }, "sender_thread_id": { "allOf": [ { @@ -3114,7 +3126,9 @@ }, "required": [ "call_id", + "model", "prompt", + "reasoning_effort", "sender_thread_id", "status", "type" @@ -9278,6 +9292,10 @@ "description": "Identifier for the collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent.", + "type": "string" + }, "new_agent_nickname": { "description": "Optional nickname assigned to the new agent.", "type": [ @@ -9307,6 +9325,14 @@ "description": "Initial prompt sent to the agent. Can be empty to prevent CoT leaking at the beginning.", "type": "string" }, + "reasoning_effort": { + "allOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + } + ], + "description": "Reasoning effort requested for the spawned agent." + }, "sender_thread_id": { "allOf": [ { @@ -9333,7 +9359,9 @@ }, "required": [ "call_id", + "model", "prompt", + "reasoning_effort", "sender_thread_id", "status", "type" diff --git a/codex-rs/app-server-protocol/schema/json/ServerNotification.json b/codex-rs/app-server-protocol/schema/json/ServerNotification.json index a3836b48f..2dec976b2 100644 --- a/codex-rs/app-server-protocol/schema/json/ServerNotification.json +++ b/codex-rs/app-server-protocol/schema/json/ServerNotification.json @@ -1588,6 +1588,18 @@ ], "type": "object" }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "ReasoningSummaryPartAddedNotification": { "properties": { "itemId": { @@ -2375,6 +2387,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -2382,6 +2401,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 39d50f12c..3e88ff54d 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 @@ -4422,6 +4422,10 @@ "description": "Identifier for the collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent.", + "type": "string" + }, "new_agent_nickname": { "description": "Optional nickname assigned to the new agent.", "type": [ @@ -4451,6 +4455,14 @@ "description": "Initial prompt sent to the agent. Can be empty to prevent CoT leaking at the beginning.", "type": "string" }, + "reasoning_effort": { + "allOf": [ + { + "$ref": "#/definitions/v2/ReasoningEffort" + } + ], + "description": "Reasoning effort requested for the spawned agent." + }, "sender_thread_id": { "allOf": [ { @@ -4477,7 +4489,9 @@ }, "required": [ "call_id", + "model", "prompt", + "reasoning_effort", "sender_thread_id", "status", "type" @@ -15802,6 +15816,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -15809,6 +15830,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/v2/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 85eb8eee1..704e6d12f 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 @@ -6224,6 +6224,10 @@ "description": "Identifier for the collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent.", + "type": "string" + }, "new_agent_nickname": { "description": "Optional nickname assigned to the new agent.", "type": [ @@ -6253,6 +6257,14 @@ "description": "Initial prompt sent to the agent. Can be empty to prevent CoT leaking at the beginning.", "type": "string" }, + "reasoning_effort": { + "allOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + } + ], + "description": "Reasoning effort requested for the spawned agent." + }, "sender_thread_id": { "allOf": [ { @@ -6279,7 +6291,9 @@ }, "required": [ "call_id", + "model", "prompt", + "reasoning_effort", "sender_thread_id", "status", "type" @@ -13569,6 +13583,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -13576,6 +13597,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 8f5fcc367..4a8358944 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json @@ -374,6 +374,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "TextElement": { "properties": { "byteRange": { @@ -751,6 +763,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -758,6 +777,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 0108ff5d7..4940cb19a 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json @@ -374,6 +374,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "TextElement": { "properties": { "byteRange": { @@ -751,6 +763,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -758,6 +777,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 3c5d11cad..15b66e990 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json @@ -488,6 +488,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "TextElement": { "properties": { "byteRange": { @@ -865,6 +877,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -872,6 +891,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 aa8017080..82532ca0c 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json @@ -1349,6 +1349,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -1356,6 +1363,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 3965739d1..341069d24 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json @@ -511,6 +511,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "SessionSource": { "oneOf": [ { @@ -1103,6 +1115,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -1110,6 +1129,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 a74ee5d63..f502f7620 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json @@ -511,6 +511,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "SessionSource": { "oneOf": [ { @@ -1103,6 +1115,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -1110,6 +1129,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 f00275398..a902b747e 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json @@ -511,6 +511,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "SessionSource": { "oneOf": [ { @@ -1103,6 +1115,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -1110,6 +1129,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 3db3e5e96..6a1ec1ccc 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json @@ -1349,6 +1349,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -1356,6 +1363,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 e95b2d850..2207ea5d0 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadRollbackResponse.json @@ -511,6 +511,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "SessionSource": { "oneOf": [ { @@ -1103,6 +1115,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -1110,6 +1129,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 eca31f444..3382e76b1 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json @@ -1349,6 +1349,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -1356,6 +1363,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 698793bbd..aa821520d 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json @@ -511,6 +511,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "SessionSource": { "oneOf": [ { @@ -1103,6 +1115,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -1110,6 +1129,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 30d1e2841..de94a4ced 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json @@ -511,6 +511,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "SessionSource": { "oneOf": [ { @@ -1103,6 +1115,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -1110,6 +1129,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 89a9e580d..7f49860e8 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json @@ -488,6 +488,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "TextElement": { "properties": { "byteRange": { @@ -865,6 +877,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -872,6 +891,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 dbe082c3b..5a5117502 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json @@ -488,6 +488,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "TextElement": { "properties": { "byteRange": { @@ -865,6 +877,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -872,6 +891,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { 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 07323f202..3800ee102 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json @@ -488,6 +488,18 @@ } ] }, + "ReasoningEffort": { + "description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning", + "enum": [ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh" + ], + "type": "string" + }, "TextElement": { "properties": { "byteRange": { @@ -865,6 +877,13 @@ "description": "Unique identifier for this collab tool call.", "type": "string" }, + "model": { + "description": "Model requested for the spawned agent, when applicable.", + "type": [ + "string", + "null" + ] + }, "prompt": { "description": "Prompt text sent as part of the collab tool call, when available.", "type": [ @@ -872,6 +891,17 @@ "null" ] }, + "reasoningEffort": { + "anyOf": [ + { + "$ref": "#/definitions/ReasoningEffort" + }, + { + "type": "null" + } + ], + "description": "Reasoning effort requested for the spawned agent, when applicable." + }, "receiverThreadIds": { "description": "Thread ID of the receiving agent, when applicable. In case of spawn operation, this corresponds to the newly spawned agent.", "items": { diff --git a/codex-rs/app-server-protocol/schema/typescript/CollabAgentSpawnEndEvent.ts b/codex-rs/app-server-protocol/schema/typescript/CollabAgentSpawnEndEvent.ts index 34753c8e0..1ec1835a6 100644 --- a/codex-rs/app-server-protocol/schema/typescript/CollabAgentSpawnEndEvent.ts +++ b/codex-rs/app-server-protocol/schema/typescript/CollabAgentSpawnEndEvent.ts @@ -2,6 +2,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { AgentStatus } from "./AgentStatus"; +import type { ReasoningEffort } from "./ReasoningEffort"; import type { ThreadId } from "./ThreadId"; export type CollabAgentSpawnEndEvent = { @@ -30,6 +31,14 @@ new_agent_role?: string | null, * beginning. */ prompt: string, +/** + * Model requested for the spawned agent. + */ +model: string, +/** + * Reasoning effort requested for the spawned agent. + */ +reasoning_effort: ReasoningEffort, /** * Last known status of the new agent reported to the sender agent. */ 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 488c07e54..bcc81c025 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadItem.ts @@ -2,6 +2,7 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { MessagePhase } from "../MessagePhase"; +import type { ReasoningEffort } from "../ReasoningEffort"; import type { JsonValue } from "../serde_json/JsonValue"; import type { CollabAgentState } from "./CollabAgentState"; import type { CollabAgentTool } from "./CollabAgentTool"; @@ -82,6 +83,14 @@ receiverThreadIds: Array, * Prompt text sent as part of the collab tool call, when available. */ prompt: string | null, +/** + * Model requested for the spawned agent, when applicable. + */ +model: string | null, +/** + * Reasoning effort requested for the spawned agent, when applicable. + */ +reasoningEffort: ReasoningEffort | null, /** * Last known status of the target agents, when available. */ 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 38a8c6496..65f2d99ff 100644 --- a/codex-rs/app-server-protocol/src/protocol/thread_history.rs +++ b/codex-rs/app-server-protocol/src/protocol/thread_history.rs @@ -554,6 +554,8 @@ impl ThreadHistoryBuilder { sender_thread_id: payload.sender_thread_id.to_string(), receiver_thread_ids: Vec::new(), prompt: Some(payload.prompt.clone()), + model: Some(payload.model.clone()), + reasoning_effort: Some(payload.reasoning_effort), agents_states: HashMap::new(), }; self.upsert_item_in_current_turn(item); @@ -587,6 +589,8 @@ impl ThreadHistoryBuilder { sender_thread_id: payload.sender_thread_id.to_string(), receiver_thread_ids, prompt: Some(payload.prompt.clone()), + model: Some(payload.model.clone()), + reasoning_effort: Some(payload.reasoning_effort), agents_states, }); } @@ -602,6 +606,8 @@ impl ThreadHistoryBuilder { sender_thread_id: payload.sender_thread_id.to_string(), receiver_thread_ids: vec![payload.receiver_thread_id.to_string()], prompt: Some(payload.prompt.clone()), + model: None, + reasoning_effort: None, agents_states: HashMap::new(), }; self.upsert_item_in_current_turn(item); @@ -624,6 +630,8 @@ impl ThreadHistoryBuilder { sender_thread_id: payload.sender_thread_id.to_string(), receiver_thread_ids: vec![receiver_id.clone()], prompt: Some(payload.prompt.clone()), + model: None, + reasoning_effort: None, agents_states: [(receiver_id, received_status)].into_iter().collect(), }); } @@ -643,6 +651,8 @@ impl ThreadHistoryBuilder { .map(ToString::to_string) .collect(), prompt: None, + model: None, + reasoning_effort: None, agents_states: HashMap::new(), }; self.upsert_item_in_current_turn(item); @@ -676,6 +686,8 @@ impl ThreadHistoryBuilder { sender_thread_id: payload.sender_thread_id.to_string(), receiver_thread_ids, prompt: None, + model: None, + reasoning_effort: None, agents_states, }); } @@ -691,6 +703,8 @@ impl ThreadHistoryBuilder { sender_thread_id: payload.sender_thread_id.to_string(), receiver_thread_ids: vec![payload.receiver_thread_id.to_string()], prompt: None, + model: None, + reasoning_effort: None, agents_states: HashMap::new(), }; self.upsert_item_in_current_turn(item); @@ -715,6 +729,8 @@ impl ThreadHistoryBuilder { sender_thread_id: payload.sender_thread_id.to_string(), receiver_thread_ids: vec![receiver_id], prompt: None, + model: None, + reasoning_effort: None, agents_states, }); } @@ -730,6 +746,8 @@ impl ThreadHistoryBuilder { sender_thread_id: payload.sender_thread_id.to_string(), receiver_thread_ids: vec![payload.receiver_thread_id.to_string()], prompt: None, + model: None, + reasoning_effort: None, agents_states: HashMap::new(), }; self.upsert_item_in_current_turn(item); @@ -757,6 +775,8 @@ impl ThreadHistoryBuilder { sender_thread_id: payload.sender_thread_id.to_string(), receiver_thread_ids: vec![receiver_id], prompt: None, + model: None, + reasoning_effort: None, agents_states, }); } @@ -2325,6 +2345,8 @@ mod tests { sender_thread_id: "00000000-0000-0000-0000-000000000001".into(), receiver_thread_ids: vec!["00000000-0000-0000-0000-000000000002".into()], prompt: None, + model: None, + reasoning_effort: None, agents_states: [( "00000000-0000-0000-0000-000000000002".into(), CollabAgentState { @@ -2338,6 +2360,63 @@ mod tests { ); } + #[test] + fn reconstructs_collab_spawn_end_item_with_model_metadata() { + let sender_thread_id = ThreadId::try_from("00000000-0000-0000-0000-000000000001") + .expect("valid sender thread id"); + let spawned_thread_id = ThreadId::try_from("00000000-0000-0000-0000-000000000002") + .expect("valid receiver thread id"); + let events = vec![ + EventMsg::UserMessage(UserMessageEvent { + message: "spawn agent".into(), + images: None, + text_elements: Vec::new(), + local_images: Vec::new(), + }), + EventMsg::CollabAgentSpawnEnd(codex_protocol::protocol::CollabAgentSpawnEndEvent { + call_id: "spawn-1".into(), + sender_thread_id, + new_thread_id: Some(spawned_thread_id), + new_agent_nickname: Some("Scout".into()), + new_agent_role: Some("explorer".into()), + prompt: "inspect the repo".into(), + model: "gpt-5.4-mini".into(), + reasoning_effort: codex_protocol::openai_models::ReasoningEffort::Medium, + status: AgentStatus::Running, + }), + ]; + + 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::CollabAgentToolCall { + id: "spawn-1".into(), + tool: CollabAgentTool::SpawnAgent, + status: CollabAgentToolCallStatus::Completed, + sender_thread_id: "00000000-0000-0000-0000-000000000001".into(), + receiver_thread_ids: vec!["00000000-0000-0000-0000-000000000002".into()], + prompt: Some("inspect the repo".into()), + model: Some("gpt-5.4-mini".into()), + reasoning_effort: Some(codex_protocol::openai_models::ReasoningEffort::Medium), + agents_states: [( + "00000000-0000-0000-0000-000000000002".into(), + CollabAgentState { + status: crate::protocol::v2::CollabAgentStatus::Running, + message: None, + }, + )] + .into_iter() + .collect(), + } + ); + } + #[test] fn rollback_failed_error_does_not_mark_turn_failed() { 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 aaf0484a5..e2603de9a 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -3946,6 +3946,10 @@ pub enum ThreadItem { receiver_thread_ids: Vec, /// Prompt text sent as part of the collab tool call, when available. prompt: Option, + /// Model requested for the spawned agent, when applicable. + model: Option, + /// Reasoning effort requested for the spawned agent, when applicable. + reasoning_effort: Option, /// Last known status of the target agents, when available. agents_states: HashMap, }, diff --git a/codex-rs/app-server/src/bespoke_event_handling.rs b/codex-rs/app-server/src/bespoke_event_handling.rs index 620f397af..c8255e4dd 100644 --- a/codex-rs/app-server/src/bespoke_event_handling.rs +++ b/codex-rs/app-server/src/bespoke_event_handling.rs @@ -862,6 +862,8 @@ pub(crate) async fn apply_bespoke_event_handling( sender_thread_id: begin_event.sender_thread_id.to_string(), receiver_thread_ids: Vec::new(), prompt: Some(begin_event.prompt), + model: Some(begin_event.model), + reasoning_effort: Some(begin_event.reasoning_effort), agents_states: HashMap::new(), }; let notification = ItemStartedNotification { @@ -899,6 +901,8 @@ pub(crate) async fn apply_bespoke_event_handling( sender_thread_id: end_event.sender_thread_id.to_string(), receiver_thread_ids, prompt: Some(end_event.prompt), + model: Some(end_event.model), + reasoning_effort: Some(end_event.reasoning_effort), agents_states, }; let notification = ItemCompletedNotification { @@ -919,6 +923,8 @@ pub(crate) async fn apply_bespoke_event_handling( sender_thread_id: begin_event.sender_thread_id.to_string(), receiver_thread_ids, prompt: Some(begin_event.prompt), + model: None, + reasoning_effort: None, agents_states: HashMap::new(), }; let notification = ItemStartedNotification { @@ -945,6 +951,8 @@ pub(crate) async fn apply_bespoke_event_handling( sender_thread_id: end_event.sender_thread_id.to_string(), receiver_thread_ids: vec![receiver_id.clone()], prompt: Some(end_event.prompt), + model: None, + reasoning_effort: None, agents_states: [(receiver_id, received_status)].into_iter().collect(), }; let notification = ItemCompletedNotification { @@ -969,6 +977,8 @@ pub(crate) async fn apply_bespoke_event_handling( sender_thread_id: begin_event.sender_thread_id.to_string(), receiver_thread_ids, prompt: None, + model: None, + reasoning_effort: None, agents_states: HashMap::new(), }; let notification = ItemStartedNotification { @@ -1005,6 +1015,8 @@ pub(crate) async fn apply_bespoke_event_handling( sender_thread_id: end_event.sender_thread_id.to_string(), receiver_thread_ids, prompt: None, + model: None, + reasoning_effort: None, agents_states, }; let notification = ItemCompletedNotification { @@ -1024,6 +1036,8 @@ pub(crate) async fn apply_bespoke_event_handling( sender_thread_id: begin_event.sender_thread_id.to_string(), receiver_thread_ids: vec![begin_event.receiver_thread_id.to_string()], prompt: None, + model: None, + reasoning_effort: None, agents_states: HashMap::new(), }; let notification = ItemStartedNotification { @@ -1064,6 +1078,8 @@ pub(crate) async fn apply_bespoke_event_handling( sender_thread_id: end_event.sender_thread_id.to_string(), receiver_thread_ids: vec![receiver_id], prompt: None, + model: None, + reasoning_effort: None, agents_states, }; let notification = ItemCompletedNotification { @@ -2515,6 +2531,8 @@ fn collab_resume_begin_item( sender_thread_id: begin_event.sender_thread_id.to_string(), receiver_thread_ids: vec![begin_event.receiver_thread_id.to_string()], prompt: None, + model: None, + reasoning_effort: None, agents_states: HashMap::new(), } } @@ -2539,6 +2557,8 @@ fn collab_resume_end_item(end_event: codex_protocol::protocol::CollabResumeEndEv sender_thread_id: end_event.sender_thread_id.to_string(), receiver_thread_ids: vec![receiver_id], prompt: None, + model: None, + reasoning_effort: None, agents_states, } } @@ -2911,6 +2931,8 @@ mod tests { sender_thread_id: event.sender_thread_id.to_string(), receiver_thread_ids: vec![event.receiver_thread_id.to_string()], prompt: None, + model: None, + reasoning_effort: None, agents_states: HashMap::new(), }; assert_eq!(item, expected); @@ -2936,6 +2958,8 @@ mod tests { sender_thread_id: event.sender_thread_id.to_string(), receiver_thread_ids: vec![receiver_id.clone()], prompt: None, + model: None, + reasoning_effort: None, agents_states: [( receiver_id, V2CollabAgentStatus::from(codex_protocol::protocol::AgentStatus::NotFound), diff --git a/codex-rs/app-server/tests/suite/v2/turn_start.rs b/codex-rs/app-server/tests/suite/v2/turn_start.rs index 8f0847527..1b2493b99 100644 --- a/codex-rs/app-server/tests/suite/v2/turn_start.rs +++ b/codex-rs/app-server/tests/suite/v2/turn_start.rs @@ -13,6 +13,10 @@ use codex_app_server::INPUT_TOO_LARGE_ERROR_CODE; use codex_app_server::INVALID_PARAMS_ERROR_CODE; use codex_app_server_protocol::ByteRange; use codex_app_server_protocol::ClientInfo; +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::CommandExecutionStatus; @@ -68,6 +72,12 @@ const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs const TEST_ORIGINATOR: &str = "codex_vscode"; const LOCAL_PRAGMATIC_TEMPLATE: &str = "You are a deeply pragmatic, effective software engineer."; +fn body_contains(req: &wiremock::Request, text: &str) -> bool { + String::from_utf8(req.body.clone()) + .ok() + .is_some_and(|body| body.contains(text)) +} + #[tokio::test] async fn turn_start_sends_originator_header() -> Result<()> { let responses = vec![create_final_assistant_message_sse_response("Done")?]; @@ -1653,6 +1663,198 @@ async fn turn_start_file_change_approval_v2() -> Result<()> { Ok(()) } +#[tokio::test] +async fn turn_start_emits_spawn_agent_item_with_model_metadata_v2() -> Result<()> { + skip_if_no_network!(Ok(())); + + const CHILD_PROMPT: &str = "child: do work"; + const PARENT_PROMPT: &str = "spawn a child and continue"; + const SPAWN_CALL_ID: &str = "spawn-call-1"; + const REQUESTED_MODEL: &str = "gpt-5.1"; + const REQUESTED_REASONING_EFFORT: ReasoningEffort = ReasoningEffort::Low; + + let server = responses::start_mock_server().await; + let spawn_args = serde_json::to_string(&json!({ + "message": CHILD_PROMPT, + "model": REQUESTED_MODEL, + "reasoning_effort": REQUESTED_REASONING_EFFORT, + }))?; + let _parent_turn = responses::mount_sse_once_match( + &server, + |req: &wiremock::Request| body_contains(req, PARENT_PROMPT), + responses::sse(vec![ + responses::ev_response_created("resp-turn1-1"), + responses::ev_function_call(SPAWN_CALL_ID, "spawn_agent", &spawn_args), + responses::ev_completed("resp-turn1-1"), + ]), + ) + .await; + let _child_turn = responses::mount_sse_once_match( + &server, + |req: &wiremock::Request| { + body_contains(req, CHILD_PROMPT) && !body_contains(req, SPAWN_CALL_ID) + }, + responses::sse(vec![ + responses::ev_response_created("resp-child-1"), + responses::ev_assistant_message("msg-child-1", "child done"), + responses::ev_completed("resp-child-1"), + ]), + ) + .await; + let _parent_follow_up = responses::mount_sse_once_match( + &server, + |req: &wiremock::Request| body_contains(req, SPAWN_CALL_ID), + responses::sse(vec![ + responses::ev_response_created("resp-turn1-2"), + responses::ev_assistant_message("msg-turn1-2", "parent done"), + responses::ev_completed("resp-turn1-2"), + ]), + ) + .await; + + let codex_home = TempDir::new()?; + create_config_toml( + codex_home.path(), + &server.uri(), + "never", + &BTreeMap::from([(Feature::Collab, true)]), + )?; + + let mut mcp = McpProcess::new(codex_home.path()).await?; + timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; + + let thread_req = mcp + .send_thread_start_request(ThreadStartParams { + model: Some("gpt-5.2-codex".to_string()), + ..Default::default() + }) + .await?; + let thread_resp: JSONRPCResponse = timeout( + DEFAULT_READ_TIMEOUT, + mcp.read_stream_until_response_message(RequestId::Integer(thread_req)), + ) + .await??; + let ThreadStartResponse { thread, .. } = to_response::(thread_resp)?; + + let turn_req = mcp + .send_turn_start_request(TurnStartParams { + thread_id: thread.id.clone(), + input: vec![V2UserInput::Text { + text: PARENT_PROMPT.to_string(), + text_elements: Vec::new(), + }], + ..Default::default() + }) + .await?; + let turn_resp: JSONRPCResponse = timeout( + DEFAULT_READ_TIMEOUT, + mcp.read_stream_until_response_message(RequestId::Integer(turn_req)), + ) + .await??; + let turn: TurnStartResponse = to_response::(turn_resp)?; + + let spawn_started = timeout(DEFAULT_READ_TIMEOUT, async { + loop { + let started_notif = mcp + .read_stream_until_notification_message("item/started") + .await?; + let started: ItemStartedNotification = + serde_json::from_value(started_notif.params.expect("item/started params"))?; + if let ThreadItem::CollabAgentToolCall { id, .. } = &started.item + && id == SPAWN_CALL_ID + { + return Ok::(started.item); + } + } + }) + .await??; + assert_eq!( + spawn_started, + ThreadItem::CollabAgentToolCall { + id: SPAWN_CALL_ID.to_string(), + tool: CollabAgentTool::SpawnAgent, + status: CollabAgentToolCallStatus::InProgress, + sender_thread_id: thread.id.clone(), + receiver_thread_ids: Vec::new(), + prompt: Some(CHILD_PROMPT.to_string()), + model: Some(REQUESTED_MODEL.to_string()), + reasoning_effort: Some(REQUESTED_REASONING_EFFORT), + agents_states: HashMap::new(), + } + ); + + let spawn_completed = timeout(DEFAULT_READ_TIMEOUT, async { + loop { + let completed_notif = mcp + .read_stream_until_notification_message("item/completed") + .await?; + let completed: ItemCompletedNotification = + serde_json::from_value(completed_notif.params.expect("item/completed params"))?; + if let ThreadItem::CollabAgentToolCall { id, .. } = &completed.item + && id == SPAWN_CALL_ID + { + return Ok::(completed.item); + } + } + }) + .await??; + let ThreadItem::CollabAgentToolCall { + id, + tool, + status, + sender_thread_id, + receiver_thread_ids, + prompt, + model, + reasoning_effort, + agents_states, + } = spawn_completed + else { + unreachable!("loop ensures we break on collab agent tool call items"); + }; + let receiver_thread_id = receiver_thread_ids + .first() + .cloned() + .expect("spawn completion should include child thread id"); + assert_eq!(id, SPAWN_CALL_ID); + assert_eq!(tool, CollabAgentTool::SpawnAgent); + assert_eq!(status, CollabAgentToolCallStatus::Completed); + assert_eq!(sender_thread_id, thread.id); + assert_eq!(receiver_thread_ids, vec![receiver_thread_id.clone()]); + assert_eq!(prompt, Some(CHILD_PROMPT.to_string())); + assert_eq!(model, Some(REQUESTED_MODEL.to_string())); + assert_eq!(reasoning_effort, Some(REQUESTED_REASONING_EFFORT)); + assert_eq!( + agents_states, + HashMap::from([( + receiver_thread_id, + CollabAgentState { + status: CollabAgentStatus::PendingInit, + message: None, + }, + )]) + ); + + let turn_completed = timeout(DEFAULT_READ_TIMEOUT, async { + loop { + let turn_completed_notif = mcp + .read_stream_until_notification_message("turn/completed") + .await?; + let turn_completed: TurnCompletedNotification = serde_json::from_value( + turn_completed_notif.params.expect("turn/completed params"), + )?; + if turn_completed.thread_id == thread.id && turn_completed.turn.id == turn.turn.id { + return Ok::(turn_completed); + } + } + }) + .await??; + assert_eq!(turn_completed.thread_id, thread.id); + assert_eq!(turn_completed.turn.id, turn.turn.id); + + Ok(()) +} + #[tokio::test] async fn turn_start_file_change_approval_accept_for_session_persists_v2() -> Result<()> { skip_if_no_network!(Ok(())); diff --git a/codex-rs/core/src/tools/handlers/multi_agents.rs b/codex-rs/core/src/tools/handlers/multi_agents.rs index 61ccb06fb..9c9393a18 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents.rs @@ -223,6 +223,8 @@ mod spawn { new_agent_nickname, new_agent_role, prompt, + model: args.model.clone().unwrap_or_default(), + reasoning_effort: args.reasoning_effort.unwrap_or_default(), status, } .into(), diff --git a/codex-rs/exec/tests/event_processor_with_json_output.rs b/codex-rs/exec/tests/event_processor_with_json_output.rs index e31da9dc6..082a99905 100644 --- a/codex-rs/exec/tests/event_processor_with_json_output.rs +++ b/codex-rs/exec/tests/event_processor_with_json_output.rs @@ -579,6 +579,8 @@ fn collab_spawn_begin_and_end_emit_item_events() { new_agent_nickname: None, new_agent_role: None, prompt: prompt.clone(), + model: "gpt-5".to_string(), + reasoning_effort: ReasoningEffortConfig::default(), status: AgentStatus::Running, }), ); diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 2d7c63a75..e1efba859 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -3179,6 +3179,10 @@ pub struct CollabAgentSpawnEndEvent { /// Initial prompt sent to the agent. Can be empty to prevent CoT leaking at the /// beginning. pub prompt: String, + /// Model requested for the spawned agent. + pub model: String, + /// Reasoning effort requested for the spawned agent. + pub reasoning_effort: ReasoningEffortConfig, /// Last known status of the new agent reported to the sender agent. pub status: AgentStatus, } diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index c18d1070b..e7a0ac144 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -2040,6 +2040,8 @@ async fn collab_spawn_end_shows_requested_model_and_effort() { new_agent_nickname: Some("Robie".to_string()), new_agent_role: Some("explorer".to_string()), prompt: "Explore the repo".to_string(), + model: "gpt-5".to_string(), + reasoning_effort: ReasoningEffortConfig::High, status: AgentStatus::PendingInit, }), }); diff --git a/codex-rs/tui/src/multi_agents.rs b/codex-rs/tui/src/multi_agents.rs index db66acf71..00a1c0429 100644 --- a/codex-rs/tui/src/multi_agents.rs +++ b/codex-rs/tui/src/multi_agents.rs @@ -183,6 +183,7 @@ pub(crate) fn spawn_end( new_agent_role, prompt, status: _, + .. } = ev; let title = match new_thread_id { @@ -601,6 +602,8 @@ mod tests { new_agent_nickname: Some("Robie".to_string()), new_agent_role: Some("explorer".to_string()), prompt: "Compute 11! and reply with just the integer result.".to_string(), + model: "gpt-5".to_string(), + reasoning_effort: ReasoningEffortConfig::High, status: AgentStatus::PendingInit, }, Some(&SpawnRequestSummary { @@ -737,6 +740,8 @@ mod tests { new_agent_nickname: Some("Robie".to_string()), new_agent_role: Some("explorer".to_string()), prompt: String::new(), + model: "gpt-5".to_string(), + reasoning_effort: ReasoningEffortConfig::High, status: AgentStatus::PendingInit, }, Some(&SpawnRequestSummary {