Support standalone tool outputs in turn/start (#41002)

## What changed

- Add an optional `toolOutput` to `turn/start` for starting or steering a turn with a named function-call output instead of user input.
- Emit standalone outputs as `functionCallOutput` thread items, persist them in durable history, and include them in resumed threads.
- Validate that tool outputs have a name, are not combined with nonempty `input`, satisfy the text-size limit, and use supported image URLs.

## Testing

- Cover standalone tool-output notifications, model input, and resumed history in both legacy and paginated history modes.
- Cover the text-size limit for structured tool output.

GitOrigin-RevId: a1eeec7b9b7de67b1a1c5e829a54552b85ec118b
This commit is contained in:
rka-oai
2026-08-26 23:58:10 +00:00
committed by copyberry
parent 2926014075
commit e56e4922eb
52 changed files with 3327 additions and 42 deletions
+2
View File
@@ -495,6 +495,7 @@ impl TurnToolCounts {
ThreadItem::UserMessage { .. }
| ThreadItem::HookPrompt { .. }
| ThreadItem::AgentMessage { .. }
| ThreadItem::FunctionCallOutput { .. }
| ThreadItem::Plan { .. }
| ThreadItem::Reasoning { .. }
| ThreadItem::ImageView { .. }
@@ -2438,6 +2439,7 @@ fn tracked_tool_item_id(item: &ThreadItem) -> Option<&str> {
ThreadItem::UserMessage { .. }
| ThreadItem::HookPrompt { .. }
| ThreadItem::AgentMessage { .. }
| ThreadItem::FunctionCallOutput { .. }
| ThreadItem::Plan { .. }
| ThreadItem::Reasoning { .. }
| ThreadItem::SubAgentActivity { .. }
@@ -5395,6 +5395,16 @@
"threadId": {
"type": "string"
},
"toolOutput": {
"anyOf": [
{
"$ref": "#/definitions/TurnToolOutput"
},
{
"type": "null"
}
]
},
"turnTrigger": {
"description": "Optional source classification for the caller that starts this turn. Ignored when this request steers an already-active turn.",
"type": [
@@ -5438,6 +5448,27 @@
],
"type": "object"
},
"TurnToolOutput": {
"properties": {
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
}
},
"required": [
"name",
"output"
],
"type": "object"
},
"UserInput": {
"oneOf": [
{
@@ -1678,6 +1678,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"FuzzyFileSearchMatchType": {
"enum": [
"file",
@@ -4383,6 +4491,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -20697,6 +20697,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/v2/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -24337,6 +24371,16 @@
"threadId": {
"type": "string"
},
"toolOutput": {
"anyOf": [
{
"$ref": "#/definitions/v2/TurnToolOutput"
},
{
"type": "null"
}
]
},
"turnTrigger": {
"description": "Optional source classification for the caller that starts this turn. Ignored when this request steers an already-active turn.",
"type": [
@@ -24435,6 +24479,27 @@
"title": "TurnSteerResponse",
"type": "object"
},
"TurnToolOutput": {
"properties": {
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/v2/FunctionCallOutputBody"
}
},
"required": [
"name",
"output"
],
"type": "object"
},
"TurnsPage": {
"properties": {
"backwardsCursor": {
@@ -18432,6 +18432,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -22072,6 +22106,16 @@
"threadId": {
"type": "string"
},
"toolOutput": {
"anyOf": [
{
"$ref": "#/definitions/TurnToolOutput"
},
{
"type": "null"
}
]
},
"turnTrigger": {
"description": "Optional source classification for the caller that starts this turn. Ignored when this request steers an already-active turn.",
"type": [
@@ -22170,6 +22214,27 @@
"title": "TurnSteerResponse",
"type": "object"
},
"TurnToolOutput": {
"properties": {
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
}
},
"required": [
"name",
"output"
],
"type": "object"
},
"TurnsPage": {
"properties": {
"backwardsCursor": {
@@ -301,6 +301,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -717,6 +825,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -301,6 +301,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -717,6 +825,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -441,6 +441,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -905,6 +1013,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -522,6 +522,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"GitInfo": {
"properties": {
"branch": {
@@ -1471,6 +1579,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -301,6 +301,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -717,6 +825,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -444,6 +444,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"GitInfo": {
"properties": {
"branch": {
@@ -1262,6 +1370,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -444,6 +444,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"GitInfo": {
"properties": {
"branch": {
@@ -1262,6 +1370,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -444,6 +444,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"GitInfo": {
"properties": {
"branch": {
@@ -1262,6 +1370,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -522,6 +522,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"GitInfo": {
"properties": {
"branch": {
@@ -1471,6 +1579,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -444,6 +444,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"GitInfo": {
"properties": {
"branch": {
@@ -1262,6 +1370,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -444,6 +444,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"GitInfo": {
"properties": {
"branch": {
@@ -1262,6 +1370,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -522,6 +522,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"GitInfo": {
"properties": {
"branch": {
@@ -1471,6 +1579,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -444,6 +444,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"GitInfo": {
"properties": {
"branch": {
@@ -1262,6 +1370,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -441,6 +441,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -905,6 +1013,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -444,6 +444,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"GitInfo": {
"properties": {
"branch": {
@@ -1262,6 +1370,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -441,6 +441,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -905,6 +1013,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -129,6 +129,114 @@
],
"type": "string"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"ImageDetail": {
"enum": [
"auto",
@@ -389,6 +497,27 @@
],
"type": "object"
},
"TurnToolOutput": {
"properties": {
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
}
},
"required": [
"name",
"output"
],
"type": "object"
},
"UserInput": {
"oneOf": [
{
@@ -685,6 +814,16 @@
"threadId": {
"type": "string"
},
"toolOutput": {
"anyOf": [
{
"$ref": "#/definitions/TurnToolOutput"
},
{
"type": "null"
}
]
},
"turnTrigger": {
"description": "Optional source classification for the caller that starts this turn. Ignored when this request steers an already-active turn.",
"type": [
@@ -441,6 +441,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -905,6 +1013,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -441,6 +441,114 @@
],
"type": "object"
},
"FunctionCallOutputBody": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"$ref": "#/definitions/FunctionCallOutputContentItem"
},
"type": "array"
}
]
},
"FunctionCallOutputContentItem": {
"description": "Responses API compatible content items that can be returned by a tool call. This is a subset of ContentItem with the types we support as function call outputs.",
"oneOf": [
{
"properties": {
"text": {
"type": "string"
},
"type": {
"enum": [
"input_text"
],
"title": "InputTextFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"text",
"type"
],
"title": "InputTextFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"detail": {
"anyOf": [
{
"$ref": "#/definitions/ImageDetail"
},
{
"type": "null"
}
]
},
"image_url": {
"type": "string"
},
"type": {
"enum": [
"input_image"
],
"title": "InputImageFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"image_url",
"type"
],
"title": "InputImageFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"audio_url": {
"type": "string"
},
"type": {
"enum": [
"input_audio"
],
"title": "InputAudioFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"audio_url",
"type"
],
"title": "InputAudioFunctionCallOutputContentItem",
"type": "object"
},
{
"properties": {
"encrypted_content": {
"type": "string"
},
"type": {
"enum": [
"encrypted_content"
],
"title": "EncryptedContentFunctionCallOutputContentItemType",
"type": "string"
}
},
"required": [
"encrypted_content",
"type"
],
"title": "EncryptedContentFunctionCallOutputContentItem",
"type": "object"
}
]
},
"HookPromptFragment": {
"properties": {
"hookRunId": {
@@ -905,6 +1013,40 @@
"title": "AgentMessageThreadItem",
"type": "object"
},
{
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": [
"string",
"null"
]
},
"output": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
"functionCallOutput"
],
"title": "FunctionCallOutputThreadItemType",
"type": "string"
}
},
"required": [
"id",
"name",
"output",
"type"
],
"title": "FunctionCallOutputThreadItem",
"type": "object"
},
{
"description": "EXPERIMENTAL - proposed plan item content. The completed plan item is authoritative and may not match the concatenation of `PlanDelta` text.",
"properties": {
@@ -1,6 +1,7 @@
// 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 { FunctionCallOutputBody } from "../FunctionCallOutputBody";
import type { ImageGenerationItem } from "../ImageGenerationItem";
import type { LegacyAppPathString } from "../LegacyAppPathString";
import type { MessagePhase } from "../MessagePhase";
@@ -28,7 +29,7 @@ import type { PatchApplyStatus } from "./PatchApplyStatus";
import type { SubAgentActivityKind } from "./SubAgentActivityKind";
import type { UserInput } from "./UserInput";
export type ThreadItem = { "type": "userMessage", id: string, clientId: string | null, content: Array<UserInput>, } | { "type": "hookPrompt", id: string, fragments: Array<HookPromptFragment>, } | { "type": "agentMessage", id: string, text: string, phase: MessagePhase | null, memoryCitation: MemoryCitation | null, delivery: AgentMessageDelivery | null, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array<string>, content: Array<string>, } | { "type": "commandExecution", id: string,
export type ThreadItem = { "type": "userMessage", id: string, clientId: string | null, content: Array<UserInput>, } | { "type": "hookPrompt", id: string, fragments: Array<HookPromptFragment>, } | { "type": "agentMessage", id: string, text: string, phase: MessagePhase | null, memoryCitation: MemoryCitation | null, delivery: AgentMessageDelivery | null, } | { "type": "functionCallOutput", id: string, name: string, namespace: string | null, output: FunctionCallOutputBody, } | { "type": "plan", id: string, text: string, } | { "type": "reasoning", id: string, summary: Array<string>, content: Array<string>, } | { "type": "commandExecution", id: string,
/**
* Trusted first-party plugin id when this command resolves to one plugin script.
*/
@@ -8,13 +8,14 @@ import type { JsonValue } from "../serde_json/JsonValue";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { SandboxPolicy } from "./SandboxPolicy";
import type { TurnToolOutput } from "./TurnToolOutput";
import type { UserInput } from "./UserInput";
export type TurnStartParams = {threadId: string, clientUserMessageId?: string | null, input: Array<UserInput>, /**
* Optional source classification for the caller that starts this turn.
* Ignored when this request steers an already-active turn.
*/
turnTrigger?: string | null, /**
turnTrigger?: string | null, toolOutput?: TurnToolOutput | null, /**
* Override the working directory for this turn and subsequent turns.
*/
cwd?: string | null, /**
@@ -0,0 +1,6 @@
// 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 { FunctionCallOutputBody } from "../FunctionCallOutputBody";
export type TurnToolOutput = { name: string, namespace: string | null, output: FunctionCallOutputBody, };
@@ -589,6 +589,7 @@ export type { TurnStartedNotification } from "./TurnStartedNotification";
export type { TurnStatus } from "./TurnStatus";
export type { TurnSteerParams } from "./TurnSteerParams";
export type { TurnSteerResponse } from "./TurnSteerResponse";
export type { TurnToolOutput } from "./TurnToolOutput";
export type { TurnsPage } from "./TurnsPage";
export type { UserInput } from "./UserInput";
export type { WarningNotification } from "./WarningNotification";
@@ -604,6 +604,7 @@ impl ThreadHistoryBuilder {
let should_upsert = match item {
codex_protocol::items::TurnItem::Plan(plan) => !plan.text.is_empty(),
codex_protocol::items::TurnItem::HookPrompt(_)
| codex_protocol::items::TurnItem::FunctionCallOutput(_)
| codex_protocol::items::TurnItem::CommandExecution(_)
| codex_protocol::items::TurnItem::DynamicToolCall(_)
| codex_protocol::items::TurnItem::CollabAgentToolCall(_)
@@ -34,6 +34,7 @@ use codex_protocol::items::McpToolCallStatus as CoreMcpToolCallStatus;
use codex_protocol::items::TurnItem as CoreTurnItem;
use codex_protocol::memory_citation::MemoryCitation as CoreMemoryCitation;
use codex_protocol::memory_citation::MemoryCitationEntry as CoreMemoryCitationEntry;
use codex_protocol::models::FunctionCallOutputBody;
use codex_protocol::models::MessagePhase;
use codex_protocol::models::ResponseItem;
use codex_protocol::openai_models::ReasoningEffort;
@@ -257,6 +258,14 @@ pub enum ThreadItem {
},
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]
FunctionCallOutput {
id: String,
name: String,
namespace: Option<String>,
output: FunctionCallOutputBody,
},
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]
/// EXPERIMENTAL - proposed plan item content. The completed plan item is
/// authoritative and may not match the concatenation of `PlanDelta` text.
Plan {
@@ -429,6 +438,7 @@ impl ThreadItem {
ThreadItem::UserMessage { id, .. }
| ThreadItem::HookPrompt { id, .. }
| ThreadItem::AgentMessage { id, .. }
| ThreadItem::FunctionCallOutput { id, .. }
| ThreadItem::Plan { id, .. }
| ThreadItem::Reasoning { id, .. }
| ThreadItem::CommandExecution { id, .. }
@@ -873,6 +883,12 @@ impl From<CoreTurnItem> for ThreadItem {
delivery: agent.delivery,
}
}
CoreTurnItem::FunctionCallOutput(output) => ThreadItem::FunctionCallOutput {
id: output.id,
name: output.name,
namespace: output.namespace,
output: output.output,
},
CoreTurnItem::Plan(plan) => ThreadItem::Plan {
id: plan.id,
text: plan.text,
@@ -4724,6 +4724,7 @@ fn turn_start_params_preserve_explicit_null_service_tier() {
client_user_message_id: None,
input: vec![],
turn_trigger: None,
tool_output: None,
responsesapi_client_metadata: None,
additional_context: None,
environments: None,
@@ -9,6 +9,7 @@ use codex_protocol::config_types::CollaborationMode;
use codex_protocol::config_types::MultiAgentMode;
use codex_protocol::config_types::Personality;
use codex_protocol::config_types::ReasoningSummary;
use codex_protocol::models::FunctionCallOutputBody;
use codex_protocol::models::ImageDetail;
use codex_protocol::openai_models::ReasoningEffort;
use codex_protocol::plan_tool::PlanItemArg as CorePlanItemArg;
@@ -134,6 +135,15 @@ impl From<CyberAccessProgram> for CoreCyberAccessProgram {
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct TurnToolOutput {
pub name: String,
pub namespace: Option<String>,
pub output: FunctionCallOutputBody,
}
#[derive(
Serialize, Deserialize, Debug, Default, Clone, PartialEq, JsonSchema, TS, ExperimentalApi,
)]
@@ -148,6 +158,8 @@ pub struct TurnStartParams {
/// Ignored when this request steers an already-active turn.
#[ts(optional = nullable)]
pub turn_trigger: Option<String>,
#[ts(optional = nullable)]
pub tool_output: Option<Box<TurnToolOutput>>,
/// Optional metadata to enrich Codex's ResponsesAPI turn metadata.
///
/// Entries are flattened into the JSON string sent as
+24 -6
View File
@@ -209,8 +209,8 @@ Example with notification opt-out:
- `thread/backgroundTerminals/terminate` — terminate one running background terminal by app-server `processId` (experimental; requires `capabilities.experimentalApi`); returns whether a process was terminated.
- `thread/rollback` — deprecated and will be removed soon. Drop the last N turns from the agent’s in-memory context and persist a rollback marker in the rollout so future resumes see the pruned history; returns the updated `thread` (with `turns` populated) on success. Paginated threads do not support rollback. Parent-owned Multi-Agent V2 subagents reject direct rollback requests.
- `thread/revert` — replace a loaded paginated thread's durable history with the prefix strictly before `beforeTurnId` while preserving its thread id. The operation interrupts an active turn if needed, leaves older rollout files immutable, reloads the thread, returns updated thread metadata with empty `turns` plus pagination cursors, and emits `thread/reverted`. It does not revert local file changes. Parent-owned Multi-Agent V2 subagents reject direct revert requests.
- `turn/start` — add user input to a thread and begin Codex generation; responds with the initial `turn` object and streams `turn/started`, `item/*`, and `turn/completed` notifications. Optional `turnTrigger` classifies who or what started a new turn and is sent as `turn_trigger` in Responses request metadata; it is ignored if the request steers an active turn. `clientUserMessageId` is optional; when supplied, the corresponding `userMessage` item echoes it as `clientId`. Experimental `runtimeWorkspaceRoots` supplies the default roots for newly resolved environment selections. Explicit `environments[].runtimeWorkspaceRoots` override that fallback with environment-native absolute paths. Prefer experimental `permissions` profile selection by id for permission overrides; the legacy `sandboxPolicy` field is still accepted but cannot be combined with `permissions`. For `collaborationMode`, `settings.developer_instructions: null` means "use built-in instructions for the selected mode". Deprecated experimental `multiAgentMode` is ignored; Ultra reasoning effort selects proactive behavior. Parent-owned Multi-Agent V2 subagents reject direct turns.
- `thread/inject_items` — append raw Responses API items to a loaded thread’s model-visible history without starting a user turn; returns `{}` on success. Parent-owned Multi-Agent V2 subagents reject direct item injection.
- `turn/start` — add user input or a named standalone function-call output to a thread and begin Codex generation; responds with the initial `turn` object and streams `turn/started`, `item/*`, and `turn/completed` notifications. For standalone outputs, provide `toolOutput` with an empty `input` array. Optional `turnTrigger` classifies who or what started a new turn and is sent as `turn_trigger` in Responses request metadata; it is ignored if the request steers an active turn. `clientUserMessageId` is optional; when supplied, the corresponding `userMessage` item echoes it as `clientId`. Experimental `runtimeWorkspaceRoots` supplies the default roots for newly resolved environment selections. Explicit `environments[].runtimeWorkspaceRoots` override that fallback with environment-native absolute paths. Prefer experimental `permissions` profile selection by id for permission overrides; the legacy `sandboxPolicy` field is still accepted but cannot be combined with `permissions`. For `collaborationMode`, `settings.developer_instructions: null` means "use built-in instructions for the selected mode". Deprecated experimental `multiAgentMode` is ignored; Ultra reasoning effort selects proactive behavior. Parent-owned Multi-Agent V2 subagents reject direct turns.
- `thread/inject_items` — append raw Responses API items to a loaded thread’s model-visible history without starting a turn; returns `{}` on success. Parent-owned Multi-Agent V2 subagents reject direct item injection.
- `turn/settings/update` — experimental; publish a narrow model-settings patch to the exact live task identified by `threadId` and `turnId`, regardless of task kind. Requires `step_model_switching`; returns `status: "applied"` or `status: "targetUnavailable"`, or a request error if rejected. Future-thread settings and already captured steps are unchanged. Parent-owned Multi-Agent V2 subagents reject direct settings updates.
- `turn/steer` — add user input to an already in-flight regular turn without starting a new turn; returns the active `turnId` that accepted the input. `clientUserMessageId` is optional; when supplied, the corresponding `userMessage` item echoes it as `clientId`. Review and manual compaction turns reject `turn/steer`. Parent-owned Multi-Agent V2 subagents reject direct steering.
- `turn/interrupt` — request cancellation of an in-flight turn by `(thread_id, turn_id)`; success is an empty `{}` response and the turn finishes with `status: "interrupted"`. Also available for parent-owned Multi-Agent V2 subagents.
@@ -1045,12 +1045,29 @@ Invoke a plugin by including a UI mention token such as `@sample` in the text in
} } }
```
### Example: Inject raw history items
### Example: Start a turn (standalone tool output)
Use `thread/inject_items` to append prebuilt Responses API items to a loaded thread’s prompt history without starting a user turn. These items are persisted to the rollout and included in subsequent model requests. A standalone `function_call_output` can omit `call_id` when it has a nonempty `name`; `namespace` is optional, and the output retains tool-tier authority. Any `input_image` items must use inline data URLs; remote HTTP(S) image URLs are rejected.
Provide a named `toolOutput` with an empty `input` array to start a real turn or join an active regular turn. `namespace` is nullable, and `output` can be text or structured content items. The output retains tool-tier authority and appears as a `functionCallOutput` item in durable history and standard item notifications; clients decide whether to display it.
```json
{ "method": "thread/inject_items", "id": 36, "params": {
{ "method": "turn/start", "id": 36, "params": {
"threadId": "thr_123",
"input": [],
"toolOutput": {
"name": "send_message_to_thread",
"namespace": "codex_app",
"output": "Another agent delegated this task."
}
} }
{ "id": 36, "result": { "turn": { "id": "turn_460", "status": "inProgress", "items": [], "error": null } } }
```
### Example: Inject raw history items
Use `thread/inject_items` to append prebuilt Responses API items to a loaded thread’s prompt history without starting a turn. These items are persisted to the rollout and included in subsequent model requests. A standalone `function_call_output` can omit `call_id` when it has a nonempty `name`; `namespace` is optional, and the output retains tool-tier authority. Any `input_image` items must use inline data URLs; remote HTTP(S) image URLs are rejected. History-only outputs are not exposed as thread items.
```json
{ "method": "thread/inject_items", "id": 37, "params": {
"threadId": "thr_123",
"items": [
{
@@ -1066,7 +1083,7 @@ Use `thread/inject_items` to append prebuilt Responses API items to a loaded thr
}
]
} }
{ "id": 36, "result": {} }
{ "id": 37, "result": {} }
```
### Example: Start realtime with WebRTC
@@ -1706,6 +1723,7 @@ The app-server streams JSON-RPC notifications while a turn is running. Each turn
`ThreadItem` is the tagged union carried in turn responses and `item/*` notifications. Currently we support events for the following items:
- `userMessage` — `{id, clientId, content}` where `clientId` is the optional `clientUserMessageId` supplied to `turn/start` or `turn/steer`, and `content` is a list of user inputs (`text`, `image`, `localImage`, `audio`, or `localAudio`).
- `functionCallOutput` — `{id, name, namespace, output}` for a standalone function-call output without a `call_id`. `namespace` is nullable, and `output` is either a string or structured content items. Clients decide whether to render these tool-authority items; ordinary paired function-call outputs are not emitted separately.
- `agentMessage` — `{id, text, phase, memoryCitation, delivery}` containing the accumulated agent reply. `delivery: "async"` identifies a user-visible message sent without ending the current turn; ordinary agent messages have `delivery: null`.
- `plan` — `{id, text}` emitted for plan-mode turns; plan text can stream via `item/plan/delta` (experimental).
- `reasoning` — `{id, summary, content}` where `summary` holds streamed reasoning summaries (applicable for most OpenAI models) and `content` holds raw reasoning blocks (applicable for e.g. open source models).
@@ -664,6 +664,7 @@ async fn turn_start_jsonrpc_span_parents_core_turn_spans() -> Result<()> {
text_elements: Vec::new(),
}],
turn_trigger: None,
tool_output: None,
responsesapi_client_metadata: None,
additional_context: None,
cwd: None,
@@ -5,7 +5,9 @@ use codex_agent_extension::AgentRun;
use codex_agent_extension::AgentRunner;
use codex_protocol::error::CodexErrorDetails;
use codex_protocol::models::ContentItem;
use codex_protocol::models::FunctionCallOutputBody;
use codex_protocol::models::FunctionCallOutputContentItem;
use codex_protocol::models::FunctionCallOutputPayload;
use codex_protocol::protocol::AdditionalContextEntry as CoreAdditionalContextEntry;
use codex_protocol::protocol::AdditionalContextKind as CoreAdditionalContextKind;
use codex_protocol::protocol::TurnSettingsUpdate;
@@ -509,7 +511,38 @@ impl TurnRequestProcessor {
})?;
self.ensure_direct_input_allowed(&request_id, thread.as_ref())
.await?;
if let Err(error) = Self::validate_v2_input_limit(&params.input) {
if let Some(tool_output) = &params.tool_output {
if !params.input.is_empty() {
return Err(invalid_request(
"`toolOutput` cannot be combined with nonempty `input`",
));
}
if tool_output.name.is_empty() {
return Err(invalid_request("`toolOutput.name` must not be empty"));
}
}
let actual_chars = params
.input
.iter()
.map(V2UserInput::text_char_count)
.sum::<usize>()
+ params
.tool_output
.as_ref()
.map_or(0, |output| match &output.output {
FunctionCallOutputBody::Text(text) => text.chars().count(),
FunctionCallOutputBody::ContentItems(items) => items
.iter()
.map(|item| match item {
FunctionCallOutputContentItem::InputText { text } => {
text.chars().count()
}
_ => 0,
})
.sum(),
});
if actual_chars > MAX_USER_INPUT_TEXT_CHARS {
let error = Self::input_too_large_error(actual_chars);
self.track_error_response(
&request_id,
&error,
@@ -532,15 +565,32 @@ impl TurnRequestProcessor {
let environment_selections =
resolve_turn_environment_selections(self.thread_manager.as_ref(), params.environments)?;
// Map v2 input items to core input items.
let mapped_items: Vec<CoreInputItem> = params
.input
.into_iter()
.map(V2UserInput::into_core)
.collect();
let client_user_message_id = params.client_user_message_id;
let additional_context = map_additional_context(params.additional_context);
let turn_has_input = !mapped_items.is_empty();
let turn_has_input = !params.input.is_empty();
let input = if let Some(tool_output) = params.tool_output {
let item = ResponseItem::FunctionCallOutput {
id: None,
call_id: None,
name: Some(tool_output.name),
namespace: tool_output.namespace,
output: FunctionCallOutputPayload {
body: tool_output.output,
success: None,
},
internal_chat_message_metadata_passthrough: None,
};
validate_response_item_image_urls(std::slice::from_ref(&item))?;
TurnInput::ResponseItem(item)
} else {
TurnInput::UserInput {
content: params
.input
.into_iter()
.map(V2UserInput::into_core)
.collect(),
client_id: params.client_user_message_id,
}
};
let cwd = resolve_request_cwd(params.cwd)?;
let environments = self
.build_environment_override(
@@ -569,26 +619,25 @@ impl TurnRequestProcessor {
},
)
.await?;
self.seal_realtime_transcript_before_user_input(thread_id, &mapped_items)
.await?;
if let TurnInput::UserInput { content, .. } = &input {
self.seal_realtime_transcript_before_user_input(thread_id, content)
.await?;
}
let submission = thread
.start_or_steer_turn(
TurnInputRequest::new(TurnInput::UserInput {
content: mapped_items,
client_id: client_user_message_id,
})
.with_thread_settings(thread_settings)
.on_start(TurnStartOptions {
turn_trigger: params.turn_trigger,
final_output_json_schema: params.output_schema,
service_tier: params.service_tier_for_turn,
cyber_access_program: params.cyber_access_program.map(Into::into),
..Default::default()
})
.with_additional_context(additional_context)
.with_responses_metadata(params.responsesapi_client_metadata)
.with_trace(self.request_trace_context(&request_id).await),
TurnInputRequest::new(input)
.with_thread_settings(thread_settings)
.on_start(TurnStartOptions {
turn_trigger: params.turn_trigger,
final_output_json_schema: params.output_schema,
service_tier: params.service_tier_for_turn,
cyber_access_program: params.cyber_access_program.map(Into::into),
..Default::default()
})
.with_additional_context(additional_context)
.with_responses_metadata(params.responsesapi_client_metadata)
.with_trace(self.request_trace_context(&request_id).await),
)
.await
.map_err(|err| {
@@ -4,17 +4,27 @@ use app_test_support::MockResponsesConfig;
use app_test_support::TestAppServer;
use codex_app_server_protocol::AdditionalContextEntry;
use codex_app_server_protocol::AdditionalContextKind;
use codex_app_server_protocol::ItemCompletedNotification;
use codex_app_server_protocol::ItemStartedNotification;
use codex_app_server_protocol::ThreadHistoryMode;
use codex_app_server_protocol::ThreadInjectItemsParams;
use codex_app_server_protocol::ThreadInjectItemsResponse;
use codex_app_server_protocol::ThreadItem;
use codex_app_server_protocol::ThreadResumeParams;
use codex_app_server_protocol::ThreadResumeResponse;
use codex_app_server_protocol::ThreadStartParams;
use codex_app_server_protocol::ThreadStartResponse;
use codex_app_server_protocol::TurnStartParams;
use codex_app_server_protocol::TurnStartResponse;
use codex_app_server_protocol::TurnStartedNotification;
use codex_app_server_protocol::TurnStatus;
use codex_app_server_protocol::TurnToolOutput;
use codex_app_server_protocol::UserInput as V2UserInput;
use codex_core::RolloutRecorder;
use codex_features::Feature;
use codex_protocol::ThreadId;
use codex_protocol::models::ContentItem;
use codex_protocol::models::FunctionCallOutputBody;
use codex_protocol::models::ResponseItem;
use codex_rollout::InitialHistory;
use codex_rollout::RolloutItem;
@@ -27,12 +37,17 @@ use serde_json::Value;
use serde_json::json;
use std::collections::HashMap;
use tempfile::TempDir;
use test_case::test_case;
use tokio::time::timeout;
const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
#[test_case(ThreadHistoryMode::Legacy; "legacy")]
#[test_case(ThreadHistoryMode::Paginated; "paginated")]
#[tokio::test]
async fn thread_inject_items_adds_raw_response_items_to_thread_history() -> Result<()> {
async fn thread_inject_items_adds_raw_response_items_to_thread_history(
history_mode: ThreadHistoryMode,
) -> Result<()> {
let server = responses::start_mock_server().await;
let body = responses::sse(vec![
responses::ev_response_created("resp-1"),
@@ -61,6 +76,7 @@ async fn thread_inject_items_adds_raw_response_items_to_thread_history() -> Resu
let thread_req = mcp
.send_thread_start_request_with_auto_env(ThreadStartParams {
model: Some("mock-model".to_string()),
history_mode: Some(history_mode),
..Default::default()
})
.await?;
@@ -110,6 +126,8 @@ async fn thread_inject_items_adds_raw_response_items_to_thread_history() -> Resu
.await?;
let _response: ThreadInjectItemsResponse =
timeout(DEFAULT_READ_TIMEOUT, mcp.read_response(inject_req)).await??;
assert!(response_mock.requests().is_empty());
assert_eq!(
state_db
.get_thread_memory_mode(ThreadId::from_string(&thread.id)?)
@@ -266,6 +284,79 @@ async fn thread_inject_items_adds_raw_response_items_to_thread_history() -> Resu
"named unpaired tool output should be sent in the next model request"
);
let delegated_mock = responses::mount_sse_once(
&server,
responses::sse(vec![responses::ev_completed("resp-delegated")]),
)
.await;
mcp.clear_message_buffer();
let delegated_req = mcp
.send_turn_start_request(TurnStartParams {
thread_id: thread.id.clone(),
input: Vec::new(),
tool_output: Some(Box::new(TurnToolOutput {
name: "send_message_to_thread".to_string(),
namespace: Some("codex_app".to_string()),
output: FunctionCallOutputBody::Text("Start a delegated turn.".to_string()),
})),
..Default::default()
})
.await?;
let TurnStartResponse { turn } =
timeout(DEFAULT_READ_TIMEOUT, mcp.read_response(delegated_req)).await??;
let turn_started: TurnStartedNotification =
timeout(DEFAULT_READ_TIMEOUT, mcp.read_notification("turn/started")).await??;
let item_started: ItemStartedNotification =
timeout(DEFAULT_READ_TIMEOUT, mcp.read_notification("item/started")).await??;
let item_completed: ItemCompletedNotification = timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_notification("item/completed"),
)
.await??;
timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_notification_message("turn/completed"),
)
.await??;
assert_eq!(turn.id, turn_started.turn.id);
assert_eq!(turn_started.turn.status, TurnStatus::InProgress);
assert_eq!(item_completed.turn_id, turn_started.turn.id);
assert_eq!(item_started.item, item_completed.item);
assert!(matches!(
&item_completed.item,
ThreadItem::FunctionCallOutput {
name,
namespace,
output: FunctionCallOutputBody::Text(output),
..
} if name == "send_message_to_thread"
&& namespace.as_deref() == Some("codex_app")
&& output == "Start a delegated turn."
));
assert!(
delegated_mock
.single_request()
.input()
.into_iter()
.any(|item| item["type"] == "function_call_output"
&& item["output"] == "Start a delegated turn."),
"the delegated turn must preserve the original model-visible tool output"
);
let resume_req = mcp
.send_thread_resume_request(ThreadResumeParams {
thread_id: thread.id,
..Default::default()
})
.await?;
let ThreadResumeResponse { thread, .. } =
timeout(DEFAULT_READ_TIMEOUT, mcp.read_response(resume_req)).await??;
assert_eq!(thread.turns.len(), 2);
assert!(thread.turns.iter().any(|turn| {
turn.id == turn_started.turn.id
&& turn.status == TurnStatus::Completed
&& turn.items.contains(&item_completed.item)
}));
Ok(())
}
@@ -1473,15 +1473,15 @@ async fn turn_start_rejects_combined_oversized_text_input() -> Result<()> {
let turn_req = mcp
.send_turn_start_request(TurnStartParams {
thread_id: thread.id,
thread_id: thread.id.clone(),
client_user_message_id: None,
input: vec![
V2UserInput::Text {
text: first,
text: first.clone(),
text_elements: Vec::new(),
},
V2UserInput::Text {
text: second,
text: second.clone(),
text_elements: Vec::new(),
},
],
@@ -1504,6 +1504,30 @@ async fn turn_start_rejects_combined_oversized_text_input() -> Result<()> {
assert_eq!(data["max_chars"], MAX_USER_INPUT_TEXT_CHARS);
assert_eq!(data["actual_chars"], actual_chars);
let tool_req = mcp
.send_raw_request(
"turn/start",
Some(json!({
"threadId": thread.id,
"input": [],
"toolOutput": {
"name": "send_message_to_thread",
"output": [
{ "type": "input_text", "text": first },
{ "type": "input_text", "text": second },
],
},
})),
)
.await?;
let err: JSONRPCError = timeout(
DEFAULT_READ_TIMEOUT,
mcp.read_stream_until_error_message(RequestId::Integer(tool_req)),
)
.await??;
assert_eq!(err.error.code, INVALID_PARAMS_ERROR_CODE);
assert_eq!(err.error.data, Some(data));
let turn_started = tokio::time::timeout(
std::time::Duration::from_millis(250),
mcp.read_stream_until_notification_message("turn/started"),
@@ -3003,6 +3027,7 @@ async fn turn_start_explicit_local_environment_updates_legacy_cwd_between_turns(
text_elements: Vec::new(),
}],
turn_trigger: None,
tool_output: None,
responsesapi_client_metadata: None,
additional_context: None,
cwd: Some(first_cwd.clone()),
@@ -3054,6 +3079,7 @@ async fn turn_start_explicit_local_environment_updates_legacy_cwd_between_turns(
text_elements: Vec::new(),
}],
turn_trigger: None,
tool_output: None,
responsesapi_client_metadata: None,
additional_context: None,
cwd: None,
+19
View File
@@ -25,6 +25,7 @@ use codex_hooks::hook_execution_mode_label;
use codex_hooks::hook_handler_type_label;
use codex_otel::HOOK_RUN_DURATION_METRIC;
use codex_otel::HOOK_RUN_METRIC;
use codex_protocol::items::FunctionCallOutputItem;
use codex_protocol::items::TurnItem;
use codex_protocol::items::UserMessageItem;
use codex_protocol::models::ResponseItem;
@@ -659,6 +660,24 @@ pub(crate) async fn record_pending_input(
TurnInput::FunctionCallOutput(item) => {
sess.record_conversation_items(turn_context, std::slice::from_ref(&item))
.await;
if let ResponseItem::FunctionCallOutput {
id: Some(id),
name: Some(name),
namespace,
output,
..
} = item
{
let item = TurnItem::FunctionCallOutput(FunctionCallOutputItem {
id: id.to_string(),
name,
namespace,
output: output.body,
});
sess.emit_turn_item_started(turn_context, &item).await;
sess.emit_turn_item_completed(turn_context, item).await;
}
sess.ensure_rollout_materialized(persist_context).await;
}
TurnInput::InterAgentCommunication(communication) => {
sess.record_inter_agent_communication(turn_context, communication)
+1
View File
@@ -976,6 +976,7 @@ async fn run_exec_session(args: ExecRunArgs) -> anyhow::Result<()> {
turn_trigger: None,
client_user_message_id: None,
input: items.into_iter().map(Into::into).collect(),
tool_output: None,
responsesapi_client_metadata: None,
additional_context: None,
environments: None,
+13
View File
@@ -5,6 +5,7 @@ use crate::dynamic_tools::DynamicToolCallOutputContentItem;
use crate::mcp::CallToolResult;
use crate::memory_citation::MemoryCitation;
use crate::models::ContentItem;
use crate::models::FunctionCallOutputBody;
use crate::models::ImageDetail;
use crate::models::MessagePhase;
use crate::models::ResponseItem;
@@ -43,6 +44,7 @@ use ts_rs::TS;
#[ts(tag = "type")]
pub enum TurnItem {
UserMessage(UserMessageItem),
FunctionCallOutput(FunctionCallOutputItem),
HookPrompt(HookPromptItem),
AgentMessage(AgentMessageItem),
Plan(PlanItem),
@@ -83,6 +85,16 @@ pub struct UserMessageItem {
pub content: Vec<UserInput>,
}
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
pub struct FunctionCallOutputItem {
pub id: String,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional)]
pub namespace: Option<String>,
pub output: FunctionCallOutputBody,
}
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema, PartialEq, Eq)]
pub struct HookPromptItem {
pub id: String,
@@ -677,6 +689,7 @@ impl TurnItem {
pub fn id(&self) -> String {
match self {
TurnItem::UserMessage(item) => item.id.clone(),
TurnItem::FunctionCallOutput(item) => item.id.clone(),
TurnItem::HookPrompt(item) => item.id.clone(),
TurnItem::AgentMessage(item) => item.id.clone(),
TurnItem::Plan(item) => item.id.clone(),
+1 -1
View File
@@ -520,7 +520,7 @@ impl TurnItem {
pub fn as_legacy_events(&self, show_raw_agent_reasoning: bool) -> Vec<EventMsg> {
match self {
TurnItem::UserMessage(item) => vec![item.as_legacy_event()],
TurnItem::HookPrompt(_) => Vec::new(),
TurnItem::FunctionCallOutput(_) | TurnItem::HookPrompt(_) => Vec::new(),
TurnItem::AgentMessage(item) => item.as_legacy_events(),
TurnItem::Plan(_) => Vec::new(),
TurnItem::CommandExecution(_)
@@ -261,6 +261,7 @@ fn rollout_item_type(item: &RolloutItem) -> String {
fn turn_item_type(item: &TurnItem) -> &'static str {
match item {
TurnItem::UserMessage(_) => "user_message",
TurnItem::FunctionCallOutput(_) => "function_call_output",
TurnItem::HookPrompt(_) => "hook_prompt",
TurnItem::AgentMessage(_) => "agent_message",
TurnItem::Plan(_) => "plan",
+3 -1
View File
@@ -96,7 +96,9 @@ pub fn should_persist_event_msg(ev: &EventMsg, history_mode: ThreadHistoryMode)
matches!(history_mode, ThreadHistoryMode::Paginated)
|| matches!(
event.item,
TurnItem::Plan(_) | TurnItem::Extension(ExtensionItem::Sleep(_))
TurnItem::FunctionCallOutput(_)
| TurnItem::Plan(_)
| TurnItem::Extension(ExtensionItem::Sleep(_))
)
|| matches!(
&event.item,
@@ -518,6 +518,7 @@ WHERE thread_id = ?
..
}
| ThreadItem::HookPrompt { .. }
| ThreadItem::FunctionCallOutput { .. }
| ThreadItem::Plan { .. }
| ThreadItem::Reasoning { .. }
| ThreadItem::CommandExecution { .. }
@@ -332,6 +332,7 @@ fn searchable_text(item: &ThreadItem) -> Option<Cow<'_, str>> {
(!text.is_empty()).then_some(Cow::Owned(text))
}
ThreadItem::HookPrompt { .. }
| ThreadItem::FunctionCallOutput { .. }
| ThreadItem::Plan { .. }
| ThreadItem::Reasoning { .. }
| ThreadItem::CommandExecution { .. }
+4 -1
View File
@@ -192,7 +192,10 @@ fn activity_summary(item: &ThreadItem) -> Option<String> {
ThreadItem::EnteredReviewMode { .. } => return Some("Entered review mode".to_string()),
ThreadItem::ExitedReviewMode { .. } => return Some("Exited review mode".to_string()),
ThreadItem::ContextCompaction { .. } => return Some("Compacted context".to_string()),
ThreadItem::UserMessage { .. } | ThreadItem::HookPrompt { .. } | ThreadItem::Sleep(_) => {
ThreadItem::UserMessage { .. }
| ThreadItem::HookPrompt { .. }
| ThreadItem::FunctionCallOutput { .. }
| ThreadItem::Sleep(_) => {
return None;
}
};
+1
View File
@@ -1208,6 +1208,7 @@ impl AppServerSession {
turn_trigger: None,
client_user_message_id: None,
input: items,
tool_output: None,
responsesapi_client_metadata: None,
additional_context: None,
environments: None,
+1 -1
View File
@@ -218,7 +218,7 @@ impl ChatWidget {
ThreadItem::ContextCompaction { .. } => {
self.add_info_message("Context compacted".to_string(), /*hint*/ None);
}
ThreadItem::HookPrompt { .. } => {}
ThreadItem::HookPrompt { .. } | ThreadItem::FunctionCallOutput { .. } => {}
ThreadItem::CollabAgentToolCall {
id,
tool,
+18
View File
@@ -1061,6 +1061,7 @@ async fn execute_inner(
"name": "webSearch", "status": null
})),
ThreadItem::UserMessage { .. }
| ThreadItem::FunctionCallOutput { .. }
| ThreadItem::HookPrompt { .. }
| ThreadItem::AgentMessage { .. }
| ThreadItem::Plan { .. }
@@ -1316,6 +1317,23 @@ fn turn_summary(turn: &Turn, include_outputs: bool, output_chars: usize) -> Valu
ThreadItem::HookPrompt { id, fragments } => json!({
"type": "hookPrompt", "id": id, "fragmentCount": fragments.len()
}),
ThreadItem::FunctionCallOutput {
id,
name,
namespace,
output,
} => {
let mut item = json!({
"type": "functionCallOutput", "id": id, "name": name, "namespace": namespace
});
if include_outputs {
item["output"] = output_summary(
output.to_text().as_deref().unwrap_or("[non-text output]"),
output_chars,
);
}
item
}
ThreadItem::AgentMessage { id, text, phase, .. } => json!({
"type": "agentMessage", "id": id, "text": truncate(text, DEFAULT_OUTPUT_CHARS), "phase": phase
}),
+1
View File
@@ -281,6 +281,7 @@ fn fallback_transcript_cell(item: &ThreadItem) -> Option<PlainHistoryCell> {
}
ThreadItem::UserMessage { .. }
| ThreadItem::AgentMessage { .. }
| ThreadItem::FunctionCallOutput { .. }
| ThreadItem::Plan { .. }
| ThreadItem::Reasoning { .. }
| ThreadItem::Sleep(_) => return None,