mirror of
https://github.com/openai/codex.git
synced 2026-05-21 19:45:26 +00:00
Compare commits
3 Commits
sapling-pr
...
codex/setu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e963813824 | ||
|
|
90006cb729 | ||
|
|
df3e2c3265 |
@@ -1664,6 +1664,71 @@
|
||||
"ThreadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"ToolOptionPickerOption": {
|
||||
"description": "EXPERIMENTAL. Defines a single selectable option for request_option_picker.",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"label"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ToolOptionPickerParams": {
|
||||
"description": "EXPERIMENTAL. Params sent with a request_option_picker event.",
|
||||
"properties": {
|
||||
"allowMultiple": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"itemId": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ToolOptionPickerOption"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"question": {
|
||||
"type": "string"
|
||||
},
|
||||
"skipLabel": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"submitLabel": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"turnId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"allowMultiple",
|
||||
"itemId",
|
||||
"options",
|
||||
"question",
|
||||
"threadId",
|
||||
"turnId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ToolRequestUserInputOption": {
|
||||
"description": "EXPERIMENTAL. Defines a single selectable option for request_user_input.",
|
||||
"properties": {
|
||||
@@ -1743,6 +1808,26 @@
|
||||
"question"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ToolSetupCodexContextPickerParams": {
|
||||
"description": "EXPERIMENTAL. Params sent with a setup_codex_context_picker event.",
|
||||
"properties": {
|
||||
"itemId": {
|
||||
"type": "string"
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"turnId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"itemId",
|
||||
"threadId",
|
||||
"turnId"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"description": "Request initiated from the server and sent to the client.",
|
||||
@@ -1822,6 +1907,56 @@
|
||||
"title": "Item/tool/requestUserInputRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "EXPERIMENTAL - Request compact option selection from the user for a tool call.",
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"item/tool/requestOptionPicker"
|
||||
],
|
||||
"title": "Item/tool/requestOptionPickerRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ToolOptionPickerParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Item/tool/requestOptionPickerRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "EXPERIMENTAL - Request the onboarding context source picker.",
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"item/tool/requestSetupCodexContextPicker"
|
||||
],
|
||||
"title": "Item/tool/requestSetupCodexContextPickerRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ToolSetupCodexContextPickerParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Item/tool/requestSetupCodexContextPickerRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "Request input for an MCP server elicitation.",
|
||||
"properties": {
|
||||
|
||||
69
codex-rs/app-server-protocol/schema/json/ToolOptionPickerParams.json
generated
Normal file
69
codex-rs/app-server-protocol/schema/json/ToolOptionPickerParams.json
generated
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"ToolOptionPickerOption": {
|
||||
"description": "EXPERIMENTAL. Defines a single selectable option for request_option_picker.",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"label"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"description": "EXPERIMENTAL. Params sent with a request_option_picker event.",
|
||||
"properties": {
|
||||
"allowMultiple": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"itemId": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ToolOptionPickerOption"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"question": {
|
||||
"type": "string"
|
||||
},
|
||||
"skipLabel": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"submitLabel": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"turnId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"allowMultiple",
|
||||
"itemId",
|
||||
"options",
|
||||
"question",
|
||||
"threadId",
|
||||
"turnId"
|
||||
],
|
||||
"title": "ToolOptionPickerParams",
|
||||
"type": "object"
|
||||
}
|
||||
38
codex-rs/app-server-protocol/schema/json/ToolOptionPickerResponse.json
generated
Normal file
38
codex-rs/app-server-protocol/schema/json/ToolOptionPickerResponse.json
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"ToolOptionPickerAction": {
|
||||
"description": "EXPERIMENTAL. Action selected for request_option_picker.",
|
||||
"enum": [
|
||||
"submit",
|
||||
"skip",
|
||||
"dismiss"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"description": "EXPERIMENTAL. Captures a user's response to request_option_picker.",
|
||||
"properties": {
|
||||
"action": {
|
||||
"$ref": "#/definitions/ToolOptionPickerAction"
|
||||
},
|
||||
"freeformAnswer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"selectedOptions": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"action",
|
||||
"selectedOptions"
|
||||
],
|
||||
"title": "ToolOptionPickerResponse",
|
||||
"type": "object"
|
||||
}
|
||||
22
codex-rs/app-server-protocol/schema/json/ToolSetupCodexContextPickerParams.json
generated
Normal file
22
codex-rs/app-server-protocol/schema/json/ToolSetupCodexContextPickerParams.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "EXPERIMENTAL. Params sent with a setup_codex_context_picker event.",
|
||||
"properties": {
|
||||
"itemId": {
|
||||
"type": "string"
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"turnId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"itemId",
|
||||
"threadId",
|
||||
"turnId"
|
||||
],
|
||||
"title": "ToolSetupCodexContextPickerParams",
|
||||
"type": "object"
|
||||
}
|
||||
32
codex-rs/app-server-protocol/schema/json/ToolSetupCodexContextPickerResponse.json
generated
Normal file
32
codex-rs/app-server-protocol/schema/json/ToolSetupCodexContextPickerResponse.json
generated
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"ToolSetupCodexContextPickerAction": {
|
||||
"description": "EXPERIMENTAL. Action selected for setup_codex_context_picker.",
|
||||
"enum": [
|
||||
"continue",
|
||||
"skip",
|
||||
"dismiss"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"description": "EXPERIMENTAL. Captures a user's response to setup_codex_context_picker.",
|
||||
"properties": {
|
||||
"action": {
|
||||
"$ref": "#/definitions/ToolSetupCodexContextPickerAction"
|
||||
},
|
||||
"selectedSources": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"action",
|
||||
"selectedSources"
|
||||
],
|
||||
"title": "ToolSetupCodexContextPickerResponse",
|
||||
"type": "object"
|
||||
}
|
||||
@@ -5296,6 +5296,56 @@
|
||||
"title": "Item/tool/requestUserInputRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "EXPERIMENTAL - Request compact option selection from the user for a tool call.",
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/v2/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"item/tool/requestOptionPicker"
|
||||
],
|
||||
"title": "Item/tool/requestOptionPickerRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ToolOptionPickerParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Item/tool/requestOptionPickerRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "EXPERIMENTAL - Request the onboarding context source picker.",
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/v2/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"item/tool/requestSetupCodexContextPicker"
|
||||
],
|
||||
"title": "Item/tool/requestSetupCodexContextPickerRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/ToolSetupCodexContextPickerParams"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Item/tool/requestSetupCodexContextPickerRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"description": "Request input for an MCP server elicitation.",
|
||||
"properties": {
|
||||
@@ -5473,6 +5523,109 @@
|
||||
],
|
||||
"title": "ServerRequest"
|
||||
},
|
||||
"ToolOptionPickerAction": {
|
||||
"description": "EXPERIMENTAL. Action selected for request_option_picker.",
|
||||
"enum": [
|
||||
"submit",
|
||||
"skip",
|
||||
"dismiss"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ToolOptionPickerOption": {
|
||||
"description": "EXPERIMENTAL. Defines a single selectable option for request_option_picker.",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"label"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ToolOptionPickerParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "EXPERIMENTAL. Params sent with a request_option_picker event.",
|
||||
"properties": {
|
||||
"allowMultiple": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"itemId": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/ToolOptionPickerOption"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"question": {
|
||||
"type": "string"
|
||||
},
|
||||
"skipLabel": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"submitLabel": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"turnId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"allowMultiple",
|
||||
"itemId",
|
||||
"options",
|
||||
"question",
|
||||
"threadId",
|
||||
"turnId"
|
||||
],
|
||||
"title": "ToolOptionPickerParams",
|
||||
"type": "object"
|
||||
},
|
||||
"ToolOptionPickerResponse": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "EXPERIMENTAL. Captures a user's response to request_option_picker.",
|
||||
"properties": {
|
||||
"action": {
|
||||
"$ref": "#/definitions/ToolOptionPickerAction"
|
||||
},
|
||||
"freeformAnswer": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"selectedOptions": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"action",
|
||||
"selectedOptions"
|
||||
],
|
||||
"title": "ToolOptionPickerResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"ToolRequestUserInputAnswer": {
|
||||
"description": "EXPERIMENTAL. Captures a user's answer to a request_user_input question.",
|
||||
"properties": {
|
||||
@@ -5587,6 +5740,58 @@
|
||||
"title": "ToolRequestUserInputResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"ToolSetupCodexContextPickerAction": {
|
||||
"description": "EXPERIMENTAL. Action selected for setup_codex_context_picker.",
|
||||
"enum": [
|
||||
"continue",
|
||||
"skip",
|
||||
"dismiss"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ToolSetupCodexContextPickerParams": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "EXPERIMENTAL. Params sent with a setup_codex_context_picker event.",
|
||||
"properties": {
|
||||
"itemId": {
|
||||
"type": "string"
|
||||
},
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"turnId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"itemId",
|
||||
"threadId",
|
||||
"turnId"
|
||||
],
|
||||
"title": "ToolSetupCodexContextPickerParams",
|
||||
"type": "object"
|
||||
},
|
||||
"ToolSetupCodexContextPickerResponse": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "EXPERIMENTAL. Captures a user's response to setup_codex_context_picker.",
|
||||
"properties": {
|
||||
"action": {
|
||||
"$ref": "#/definitions/ToolSetupCodexContextPickerAction"
|
||||
},
|
||||
"selectedSources": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"action",
|
||||
"selectedSources"
|
||||
],
|
||||
"title": "ToolSetupCodexContextPickerResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"W3cTraceContext": {
|
||||
"properties": {
|
||||
"traceparent": {
|
||||
|
||||
@@ -11,9 +11,11 @@ import type { DynamicToolCallParams } from "./v2/DynamicToolCallParams";
|
||||
import type { FileChangeRequestApprovalParams } from "./v2/FileChangeRequestApprovalParams";
|
||||
import type { McpServerElicitationRequestParams } from "./v2/McpServerElicitationRequestParams";
|
||||
import type { PermissionsRequestApprovalParams } from "./v2/PermissionsRequestApprovalParams";
|
||||
import type { ToolOptionPickerParams } from "./v2/ToolOptionPickerParams";
|
||||
import type { ToolRequestUserInputParams } from "./v2/ToolRequestUserInputParams";
|
||||
import type { ToolSetupCodexContextPickerParams } from "./v2/ToolSetupCodexContextPickerParams";
|
||||
|
||||
/**
|
||||
* Request initiated from the server and sent to the client.
|
||||
*/
|
||||
export type ServerRequest = { "method": "item/commandExecution/requestApproval", id: RequestId, params: CommandExecutionRequestApprovalParams, } | { "method": "item/fileChange/requestApproval", id: RequestId, params: FileChangeRequestApprovalParams, } | { "method": "item/tool/requestUserInput", id: RequestId, params: ToolRequestUserInputParams, } | { "method": "mcpServer/elicitation/request", id: RequestId, params: McpServerElicitationRequestParams, } | { "method": "item/permissions/requestApproval", id: RequestId, params: PermissionsRequestApprovalParams, } | { "method": "item/tool/call", id: RequestId, params: DynamicToolCallParams, } | { "method": "account/chatgptAuthTokens/refresh", id: RequestId, params: ChatgptAuthTokensRefreshParams, } | { "method": "attestation/generate", id: RequestId, params: AttestationGenerateParams, } | { "method": "applyPatchApproval", id: RequestId, params: ApplyPatchApprovalParams, } | { "method": "execCommandApproval", id: RequestId, params: ExecCommandApprovalParams, };
|
||||
export type ServerRequest = { "method": "item/commandExecution/requestApproval", id: RequestId, params: CommandExecutionRequestApprovalParams, } | { "method": "item/fileChange/requestApproval", id: RequestId, params: FileChangeRequestApprovalParams, } | { "method": "item/tool/requestUserInput", id: RequestId, params: ToolRequestUserInputParams, } | { "method": "item/tool/requestOptionPicker", id: RequestId, params: ToolOptionPickerParams, } | { "method": "item/tool/requestSetupCodexContextPicker", id: RequestId, params: ToolSetupCodexContextPickerParams, } | { "method": "mcpServer/elicitation/request", id: RequestId, params: McpServerElicitationRequestParams, } | { "method": "item/permissions/requestApproval", id: RequestId, params: PermissionsRequestApprovalParams, } | { "method": "item/tool/call", id: RequestId, params: DynamicToolCallParams, } | { "method": "account/chatgptAuthTokens/refresh", id: RequestId, params: ChatgptAuthTokensRefreshParams, } | { "method": "attestation/generate", id: RequestId, params: AttestationGenerateParams, } | { "method": "applyPatchApproval", id: RequestId, params: ApplyPatchApprovalParams, } | { "method": "execCommandApproval", id: RequestId, params: ExecCommandApprovalParams, };
|
||||
|
||||
8
codex-rs/app-server-protocol/schema/typescript/v2/ToolOptionPickerAction.ts
generated
Normal file
8
codex-rs/app-server-protocol/schema/typescript/v2/ToolOptionPickerAction.ts
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
// 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.
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. Action selected for request_option_picker.
|
||||
*/
|
||||
export type ToolOptionPickerAction = "submit" | "skip" | "dismiss";
|
||||
8
codex-rs/app-server-protocol/schema/typescript/v2/ToolOptionPickerOption.ts
generated
Normal file
8
codex-rs/app-server-protocol/schema/typescript/v2/ToolOptionPickerOption.ts
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
// 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.
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. Defines a single selectable option for request_option_picker.
|
||||
*/
|
||||
export type ToolOptionPickerOption = { label: string, description: string | null, };
|
||||
9
codex-rs/app-server-protocol/schema/typescript/v2/ToolOptionPickerParams.ts
generated
Normal file
9
codex-rs/app-server-protocol/schema/typescript/v2/ToolOptionPickerParams.ts
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
// 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 { ToolOptionPickerOption } from "./ToolOptionPickerOption";
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. Params sent with a request_option_picker event.
|
||||
*/
|
||||
export type ToolOptionPickerParams = { threadId: string, turnId: string, itemId: string, question: string, options: Array<ToolOptionPickerOption>, allowMultiple: boolean, submitLabel: string | null, skipLabel: string | null, };
|
||||
9
codex-rs/app-server-protocol/schema/typescript/v2/ToolOptionPickerResponse.ts
generated
Normal file
9
codex-rs/app-server-protocol/schema/typescript/v2/ToolOptionPickerResponse.ts
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
// 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 { ToolOptionPickerAction } from "./ToolOptionPickerAction";
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. Captures a user's response to request_option_picker.
|
||||
*/
|
||||
export type ToolOptionPickerResponse = { action: ToolOptionPickerAction, selectedOptions: Array<string>, freeformAnswer: string | null, };
|
||||
8
codex-rs/app-server-protocol/schema/typescript/v2/ToolSetupCodexContextPickerAction.ts
generated
Normal file
8
codex-rs/app-server-protocol/schema/typescript/v2/ToolSetupCodexContextPickerAction.ts
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
// 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.
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. Action selected for setup_codex_context_picker.
|
||||
*/
|
||||
export type ToolSetupCodexContextPickerAction = "continue" | "skip" | "dismiss";
|
||||
8
codex-rs/app-server-protocol/schema/typescript/v2/ToolSetupCodexContextPickerParams.ts
generated
Normal file
8
codex-rs/app-server-protocol/schema/typescript/v2/ToolSetupCodexContextPickerParams.ts
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
// 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.
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. Params sent with a setup_codex_context_picker event.
|
||||
*/
|
||||
export type ToolSetupCodexContextPickerParams = { threadId: string, turnId: string, itemId: string, };
|
||||
9
codex-rs/app-server-protocol/schema/typescript/v2/ToolSetupCodexContextPickerResponse.ts
generated
Normal file
9
codex-rs/app-server-protocol/schema/typescript/v2/ToolSetupCodexContextPickerResponse.ts
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
// 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 { ToolSetupCodexContextPickerAction } from "./ToolSetupCodexContextPickerAction";
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. Captures a user's response to setup_codex_context_picker.
|
||||
*/
|
||||
export type ToolSetupCodexContextPickerResponse = { action: ToolSetupCodexContextPickerAction, selectedSources: Array<string>, };
|
||||
@@ -425,11 +425,18 @@ export type { ThreadUnsubscribeParams } from "./ThreadUnsubscribeParams";
|
||||
export type { ThreadUnsubscribeResponse } from "./ThreadUnsubscribeResponse";
|
||||
export type { ThreadUnsubscribeStatus } from "./ThreadUnsubscribeStatus";
|
||||
export type { TokenUsageBreakdown } from "./TokenUsageBreakdown";
|
||||
export type { ToolOptionPickerAction } from "./ToolOptionPickerAction";
|
||||
export type { ToolOptionPickerOption } from "./ToolOptionPickerOption";
|
||||
export type { ToolOptionPickerParams } from "./ToolOptionPickerParams";
|
||||
export type { ToolOptionPickerResponse } from "./ToolOptionPickerResponse";
|
||||
export type { ToolRequestUserInputAnswer } from "./ToolRequestUserInputAnswer";
|
||||
export type { ToolRequestUserInputOption } from "./ToolRequestUserInputOption";
|
||||
export type { ToolRequestUserInputParams } from "./ToolRequestUserInputParams";
|
||||
export type { ToolRequestUserInputQuestion } from "./ToolRequestUserInputQuestion";
|
||||
export type { ToolRequestUserInputResponse } from "./ToolRequestUserInputResponse";
|
||||
export type { ToolSetupCodexContextPickerAction } from "./ToolSetupCodexContextPickerAction";
|
||||
export type { ToolSetupCodexContextPickerParams } from "./ToolSetupCodexContextPickerParams";
|
||||
export type { ToolSetupCodexContextPickerResponse } from "./ToolSetupCodexContextPickerResponse";
|
||||
export type { ToolsV2 } from "./ToolsV2";
|
||||
export type { Turn } from "./Turn";
|
||||
export type { TurnCompletedNotification } from "./TurnCompletedNotification";
|
||||
|
||||
@@ -1334,6 +1334,18 @@ server_request_definitions! {
|
||||
response: v2::ToolRequestUserInputResponse,
|
||||
},
|
||||
|
||||
/// EXPERIMENTAL - Request compact option selection from the user for a tool call.
|
||||
ToolOptionPicker => "item/tool/requestOptionPicker" {
|
||||
params: v2::ToolOptionPickerParams,
|
||||
response: v2::ToolOptionPickerResponse,
|
||||
},
|
||||
|
||||
/// EXPERIMENTAL - Request the onboarding context source picker.
|
||||
ToolSetupCodexContextPicker => "item/tool/requestSetupCodexContextPicker" {
|
||||
params: v2::ToolSetupCodexContextPickerParams,
|
||||
response: v2::ToolSetupCodexContextPickerResponse,
|
||||
},
|
||||
|
||||
/// Request input for an MCP server elicitation.
|
||||
McpServerElicitationRequest => "mcpServer/elicitation/request" {
|
||||
params: v2::McpServerElicitationRequestParams,
|
||||
|
||||
@@ -1447,3 +1447,76 @@ pub struct ToolRequestUserInputAnswer {
|
||||
pub struct ToolRequestUserInputResponse {
|
||||
pub answers: HashMap<String, ToolRequestUserInputAnswer>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL. Defines a single selectable option for request_option_picker.
|
||||
pub struct ToolOptionPickerOption {
|
||||
pub label: String,
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL. Params sent with a request_option_picker event.
|
||||
pub struct ToolOptionPickerParams {
|
||||
pub thread_id: String,
|
||||
pub turn_id: String,
|
||||
pub item_id: String,
|
||||
pub question: String,
|
||||
pub options: Vec<ToolOptionPickerOption>,
|
||||
pub allow_multiple: bool,
|
||||
pub submit_label: Option<String>,
|
||||
pub skip_label: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL. Action selected for request_option_picker.
|
||||
pub enum ToolOptionPickerAction {
|
||||
Submit,
|
||||
Skip,
|
||||
Dismiss,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL. Captures a user's response to request_option_picker.
|
||||
pub struct ToolOptionPickerResponse {
|
||||
pub action: ToolOptionPickerAction,
|
||||
pub selected_options: Vec<String>,
|
||||
pub freeform_answer: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL. Params sent with a setup_codex_context_picker event.
|
||||
pub struct ToolSetupCodexContextPickerParams {
|
||||
pub thread_id: String,
|
||||
pub turn_id: String,
|
||||
pub item_id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL. Action selected for setup_codex_context_picker.
|
||||
pub enum ToolSetupCodexContextPickerAction {
|
||||
Continue,
|
||||
Skip,
|
||||
Dismiss,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL. Captures a user's response to setup_codex_context_picker.
|
||||
pub struct ToolSetupCodexContextPickerResponse {
|
||||
pub action: ToolSetupCodexContextPickerAction,
|
||||
pub selected_sources: Vec<String>,
|
||||
}
|
||||
|
||||
@@ -65,10 +65,17 @@ use codex_app_server_protocol::ThreadSettingsUpdatedNotification;
|
||||
use codex_app_server_protocol::ThreadStatus;
|
||||
use codex_app_server_protocol::ThreadTokenUsage;
|
||||
use codex_app_server_protocol::ThreadTokenUsageUpdatedNotification;
|
||||
use codex_app_server_protocol::ToolOptionPickerAction;
|
||||
use codex_app_server_protocol::ToolOptionPickerOption;
|
||||
use codex_app_server_protocol::ToolOptionPickerParams;
|
||||
use codex_app_server_protocol::ToolOptionPickerResponse;
|
||||
use codex_app_server_protocol::ToolRequestUserInputOption;
|
||||
use codex_app_server_protocol::ToolRequestUserInputParams;
|
||||
use codex_app_server_protocol::ToolRequestUserInputQuestion;
|
||||
use codex_app_server_protocol::ToolRequestUserInputResponse;
|
||||
use codex_app_server_protocol::ToolSetupCodexContextPickerAction;
|
||||
use codex_app_server_protocol::ToolSetupCodexContextPickerParams;
|
||||
use codex_app_server_protocol::ToolSetupCodexContextPickerResponse;
|
||||
use codex_app_server_protocol::Turn;
|
||||
use codex_app_server_protocol::TurnCompletedNotification;
|
||||
use codex_app_server_protocol::TurnDiffUpdatedNotification;
|
||||
@@ -90,6 +97,8 @@ use codex_core::review_prompts;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::items::parse_hook_prompt_message;
|
||||
use codex_protocol::models::AdditionalPermissionProfile as CoreAdditionalPermissionProfile;
|
||||
use codex_protocol::option_picker::OptionPickerAction as CoreOptionPickerAction;
|
||||
use codex_protocol::option_picker::OptionPickerResponse as CoreOptionPickerResponse;
|
||||
use codex_protocol::plan_tool::UpdatePlanArgs;
|
||||
use codex_protocol::protocol::CodexErrorInfo as CoreCodexErrorInfo;
|
||||
use codex_protocol::protocol::Event;
|
||||
@@ -108,6 +117,8 @@ use codex_protocol::request_permissions::RequestPermissionProfile as CoreRequest
|
||||
use codex_protocol::request_permissions::RequestPermissionsResponse as CoreRequestPermissionsResponse;
|
||||
use codex_protocol::request_user_input::RequestUserInputAnswer as CoreRequestUserInputAnswer;
|
||||
use codex_protocol::request_user_input::RequestUserInputResponse as CoreRequestUserInputResponse;
|
||||
use codex_protocol::setup_codex_context_picker::SetupCodexContextPickerAction as CoreSetupCodexContextPickerAction;
|
||||
use codex_protocol::setup_codex_context_picker::SetupCodexContextPickerResponse as CoreSetupCodexContextPickerResponse;
|
||||
use codex_sandboxing::policy_transforms::intersect_permission_profiles;
|
||||
use codex_shell_command::parse_command::shlex_join;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
@@ -690,6 +701,67 @@ pub(crate) async fn apply_bespoke_event_handling(
|
||||
.await;
|
||||
});
|
||||
}
|
||||
EventMsg::OptionPicker(request) => {
|
||||
let user_input_guard = thread_watch_manager
|
||||
.note_user_input_requested(&conversation_id.to_string())
|
||||
.await;
|
||||
let options = request
|
||||
.options
|
||||
.into_iter()
|
||||
.map(|option| ToolOptionPickerOption {
|
||||
label: option.label,
|
||||
description: option.description,
|
||||
})
|
||||
.collect();
|
||||
let params = ToolOptionPickerParams {
|
||||
thread_id: conversation_id.to_string(),
|
||||
turn_id: request.turn_id,
|
||||
item_id: request.call_id,
|
||||
question: request.question,
|
||||
options,
|
||||
allow_multiple: request.allow_multiple,
|
||||
submit_label: request.submit_label,
|
||||
skip_label: request.skip_label,
|
||||
};
|
||||
let (pending_request_id, rx) = outgoing
|
||||
.send_request(ServerRequestPayload::ToolOptionPicker(params))
|
||||
.await;
|
||||
tokio::spawn(async move {
|
||||
on_option_picker_response(
|
||||
event_turn_id,
|
||||
pending_request_id,
|
||||
rx,
|
||||
conversation,
|
||||
thread_state,
|
||||
user_input_guard,
|
||||
)
|
||||
.await;
|
||||
});
|
||||
}
|
||||
EventMsg::SetupCodexContextPicker(request) => {
|
||||
let user_input_guard = thread_watch_manager
|
||||
.note_user_input_requested(&conversation_id.to_string())
|
||||
.await;
|
||||
let params = ToolSetupCodexContextPickerParams {
|
||||
thread_id: conversation_id.to_string(),
|
||||
turn_id: request.turn_id,
|
||||
item_id: request.call_id,
|
||||
};
|
||||
let (pending_request_id, rx) = outgoing
|
||||
.send_request(ServerRequestPayload::ToolSetupCodexContextPicker(params))
|
||||
.await;
|
||||
tokio::spawn(async move {
|
||||
on_setup_codex_context_picker_response(
|
||||
event_turn_id,
|
||||
pending_request_id,
|
||||
rx,
|
||||
conversation,
|
||||
thread_state,
|
||||
user_input_guard,
|
||||
)
|
||||
.await;
|
||||
});
|
||||
}
|
||||
EventMsg::ElicitationRequest(request) => {
|
||||
let permission_guard = thread_watch_manager
|
||||
.note_permission_requested(&conversation_id.to_string())
|
||||
@@ -1599,6 +1671,159 @@ async fn handle_token_count_event(
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_option_picker_response(
|
||||
event_turn_id: String,
|
||||
pending_request_id: RequestId,
|
||||
receiver: oneshot::Receiver<ClientRequestResult>,
|
||||
conversation: Arc<CodexThread>,
|
||||
thread_state: Arc<Mutex<ThreadState>>,
|
||||
user_input_guard: ThreadWatchActiveGuard,
|
||||
) {
|
||||
let response = receiver.await;
|
||||
resolve_server_request_on_thread_listener(&thread_state, pending_request_id).await;
|
||||
drop(user_input_guard);
|
||||
let value = match response {
|
||||
Ok(Ok(value)) => value,
|
||||
Ok(Err(err)) if is_turn_transition_server_request_error(&err) => return,
|
||||
Ok(Err(err)) => {
|
||||
error!("option picker request failed with client error: {err:?}");
|
||||
submit_empty_option_picker_response(event_turn_id, conversation).await;
|
||||
return;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("option picker request failed: {err:?}");
|
||||
submit_empty_option_picker_response(event_turn_id, conversation).await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let response =
|
||||
serde_json::from_value::<ToolOptionPickerResponse>(value).unwrap_or_else(|err| {
|
||||
error!("failed to deserialize ToolOptionPickerResponse: {err}");
|
||||
ToolOptionPickerResponse {
|
||||
action: ToolOptionPickerAction::Dismiss,
|
||||
selected_options: Vec::new(),
|
||||
freeform_answer: None,
|
||||
}
|
||||
});
|
||||
let response = CoreOptionPickerResponse {
|
||||
action: match response.action {
|
||||
ToolOptionPickerAction::Submit => CoreOptionPickerAction::Submit,
|
||||
ToolOptionPickerAction::Skip => CoreOptionPickerAction::Skip,
|
||||
ToolOptionPickerAction::Dismiss => CoreOptionPickerAction::Dismiss,
|
||||
},
|
||||
selected_options: response.selected_options,
|
||||
freeform_answer: response.freeform_answer,
|
||||
};
|
||||
|
||||
if let Err(err) = conversation
|
||||
.submit(Op::OptionPickerResponse {
|
||||
id: event_turn_id,
|
||||
response,
|
||||
})
|
||||
.await
|
||||
{
|
||||
error!("failed to submit OptionPickerResponse: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
async fn submit_empty_option_picker_response(
|
||||
event_turn_id: String,
|
||||
conversation: Arc<CodexThread>,
|
||||
) {
|
||||
let response = CoreOptionPickerResponse {
|
||||
action: CoreOptionPickerAction::Dismiss,
|
||||
selected_options: Vec::new(),
|
||||
freeform_answer: None,
|
||||
};
|
||||
if let Err(err) = conversation
|
||||
.submit(Op::OptionPickerResponse {
|
||||
id: event_turn_id,
|
||||
response,
|
||||
})
|
||||
.await
|
||||
{
|
||||
error!("failed to submit OptionPickerResponse: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_setup_codex_context_picker_response(
|
||||
event_turn_id: String,
|
||||
pending_request_id: RequestId,
|
||||
receiver: oneshot::Receiver<ClientRequestResult>,
|
||||
conversation: Arc<CodexThread>,
|
||||
thread_state: Arc<Mutex<ThreadState>>,
|
||||
user_input_guard: ThreadWatchActiveGuard,
|
||||
) {
|
||||
let response = receiver.await;
|
||||
resolve_server_request_on_thread_listener(&thread_state, pending_request_id).await;
|
||||
drop(user_input_guard);
|
||||
let value = match response {
|
||||
Ok(Ok(value)) => value,
|
||||
Ok(Err(err)) if is_turn_transition_server_request_error(&err) => return,
|
||||
Ok(Err(err)) => {
|
||||
error!("setup codex context picker request failed with client error: {err:?}");
|
||||
submit_empty_setup_codex_context_picker_response(event_turn_id, conversation).await;
|
||||
return;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("setup codex context picker request failed: {err:?}");
|
||||
submit_empty_setup_codex_context_picker_response(event_turn_id, conversation).await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let response = serde_json::from_value::<ToolSetupCodexContextPickerResponse>(value)
|
||||
.unwrap_or_else(|err| {
|
||||
error!("failed to deserialize ToolSetupCodexContextPickerResponse: {err}");
|
||||
ToolSetupCodexContextPickerResponse {
|
||||
action: ToolSetupCodexContextPickerAction::Dismiss,
|
||||
selected_sources: Vec::new(),
|
||||
}
|
||||
});
|
||||
let response = CoreSetupCodexContextPickerResponse {
|
||||
action: match response.action {
|
||||
ToolSetupCodexContextPickerAction::Continue => {
|
||||
CoreSetupCodexContextPickerAction::Continue
|
||||
}
|
||||
ToolSetupCodexContextPickerAction::Skip => CoreSetupCodexContextPickerAction::Skip,
|
||||
ToolSetupCodexContextPickerAction::Dismiss => {
|
||||
CoreSetupCodexContextPickerAction::Dismiss
|
||||
}
|
||||
},
|
||||
selected_source_ids: response.selected_sources,
|
||||
};
|
||||
|
||||
if let Err(err) = conversation
|
||||
.submit(Op::SetupCodexContextPickerResponse {
|
||||
id: event_turn_id,
|
||||
response,
|
||||
})
|
||||
.await
|
||||
{
|
||||
error!("failed to submit SetupCodexContextPickerResponse: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
async fn submit_empty_setup_codex_context_picker_response(
|
||||
event_turn_id: String,
|
||||
conversation: Arc<CodexThread>,
|
||||
) {
|
||||
let response = CoreSetupCodexContextPickerResponse {
|
||||
action: CoreSetupCodexContextPickerAction::Dismiss,
|
||||
selected_source_ids: Vec::new(),
|
||||
};
|
||||
if let Err(err) = conversation
|
||||
.submit(Op::SetupCodexContextPickerResponse {
|
||||
id: event_turn_id,
|
||||
response,
|
||||
})
|
||||
.await
|
||||
{
|
||||
error!("failed to submit SetupCodexContextPickerResponse: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_error(
|
||||
_conversation_id: ThreadId,
|
||||
error: TurnError,
|
||||
|
||||
@@ -500,6 +500,9 @@
|
||||
"network_proxy": {
|
||||
"$ref": "#/definitions/FeatureToml_for_NetworkProxyConfigToml"
|
||||
},
|
||||
"onboarding_interactive_tools": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"personality": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -4431,6 +4434,9 @@
|
||||
"network_proxy": {
|
||||
"$ref": "#/definitions/FeatureToml_for_NetworkProxyConfigToml"
|
||||
},
|
||||
"onboarding_interactive_tools": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"personality": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -26,6 +26,7 @@ use crate::tasks::UserShellCommandTask;
|
||||
use crate::tasks::execute_user_shell_command;
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ResponseInputItem;
|
||||
use codex_protocol::option_picker::OptionPickerResponse;
|
||||
use codex_protocol::protocol::CodexErrorInfo;
|
||||
use codex_protocol::protocol::ErrorEvent;
|
||||
use codex_protocol::protocol::Event;
|
||||
@@ -49,6 +50,7 @@ use codex_protocol::protocol::TurnAbortReason;
|
||||
use codex_protocol::protocol::WarningEvent;
|
||||
use codex_protocol::request_permissions::RequestPermissionsResponse;
|
||||
use codex_protocol::request_user_input::RequestUserInputResponse;
|
||||
use codex_protocol::setup_codex_context_picker::SetupCodexContextPickerResponse;
|
||||
|
||||
use crate::context_manager::is_user_turn_boundary;
|
||||
use codex_protocol::dynamic_tools::DynamicToolResponse;
|
||||
@@ -435,6 +437,23 @@ pub async fn request_user_input_response(
|
||||
sess.notify_user_input_response(&id, response).await;
|
||||
}
|
||||
|
||||
pub async fn option_picker_response(
|
||||
sess: &Arc<Session>,
|
||||
id: String,
|
||||
response: OptionPickerResponse,
|
||||
) {
|
||||
sess.notify_option_picker_response(&id, response).await;
|
||||
}
|
||||
|
||||
pub async fn setup_codex_context_picker_response(
|
||||
sess: &Arc<Session>,
|
||||
id: String,
|
||||
response: SetupCodexContextPickerResponse,
|
||||
) {
|
||||
sess.notify_setup_codex_context_picker_response(&id, response)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn request_permissions_response(
|
||||
sess: &Arc<Session>,
|
||||
id: String,
|
||||
@@ -792,6 +811,14 @@ pub(super) async fn submission_loop(
|
||||
request_user_input_response(&sess, id, response).await;
|
||||
false
|
||||
}
|
||||
Op::OptionPickerResponse { id, response } => {
|
||||
option_picker_response(&sess, id, response).await;
|
||||
false
|
||||
}
|
||||
Op::SetupCodexContextPickerResponse { id, response } => {
|
||||
setup_codex_context_picker_response(&sess, id, response).await;
|
||||
false
|
||||
}
|
||||
Op::RequestPermissionsResponse { id, response } => {
|
||||
request_permissions_response(&sess, id, response).await;
|
||||
false
|
||||
|
||||
@@ -120,6 +120,7 @@ use codex_protocol::request_permissions::RequestPermissionsEvent;
|
||||
use codex_protocol::request_permissions::RequestPermissionsResponse;
|
||||
use codex_protocol::request_user_input::RequestUserInputArgs;
|
||||
use codex_protocol::request_user_input::RequestUserInputResponse;
|
||||
use codex_protocol::setup_codex_context_picker::SetupCodexContextPickerResponse;
|
||||
use codex_rmcp_client::ElicitationResponse;
|
||||
use codex_rollout::state_db;
|
||||
use codex_rollout_trace::AgentResultTracePayload;
|
||||
@@ -325,6 +326,8 @@ use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ResponseInputItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::openai_models::ReasoningEffort as ReasoningEffortConfig;
|
||||
use codex_protocol::option_picker::OptionPickerArgs;
|
||||
use codex_protocol::option_picker::OptionPickerResponse;
|
||||
use codex_protocol::protocol::ApplyPatchApprovalRequestEvent;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::CodexErrorInfo;
|
||||
@@ -343,12 +346,14 @@ use codex_protocol::protocol::ModelVerificationEvent;
|
||||
use codex_protocol::protocol::NetworkApprovalContext;
|
||||
use codex_protocol::protocol::NonSteerableTurnKind;
|
||||
use codex_protocol::protocol::Op;
|
||||
use codex_protocol::protocol::OptionPickerEvent;
|
||||
use codex_protocol::protocol::RateLimitSnapshot;
|
||||
use codex_protocol::protocol::RequestUserInputEvent;
|
||||
use codex_protocol::protocol::ReviewDecision;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::protocol::SessionConfiguredEvent;
|
||||
use codex_protocol::protocol::SessionNetworkProxyRuntime;
|
||||
use codex_protocol::protocol::SetupCodexContextPickerEvent;
|
||||
use codex_protocol::protocol::StreamErrorEvent;
|
||||
use codex_protocol::protocol::Submission;
|
||||
use codex_protocol::protocol::ThreadMemoryMode;
|
||||
@@ -2319,6 +2324,144 @@ impl Session {
|
||||
rx_response.await.ok()
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::await_holding_invalid_type,
|
||||
reason = "active turn checks and turn state updates must remain atomic"
|
||||
)]
|
||||
pub async fn request_option_picker(
|
||||
&self,
|
||||
turn_context: &TurnContext,
|
||||
call_id: String,
|
||||
args: OptionPickerArgs,
|
||||
) -> Option<OptionPickerResponse> {
|
||||
let sub_id = turn_context.sub_id.clone();
|
||||
let (tx_response, rx_response) = oneshot::channel();
|
||||
let event_id = sub_id.clone();
|
||||
let prev_entry = {
|
||||
let mut active = self.active_turn.lock().await;
|
||||
match active.as_mut() {
|
||||
Some(at) => {
|
||||
let mut ts = at.turn_state.lock().await;
|
||||
ts.insert_pending_option_picker(sub_id, tx_response)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
if prev_entry.is_some() {
|
||||
warn!("Overwriting existing pending option picker for sub_id: {event_id}");
|
||||
}
|
||||
|
||||
let event = EventMsg::OptionPicker(OptionPickerEvent {
|
||||
call_id,
|
||||
turn_id: turn_context.sub_id.clone(),
|
||||
question: args.question,
|
||||
options: args.options,
|
||||
allow_multiple: args.allow_multiple,
|
||||
submit_label: args.submit_label,
|
||||
skip_label: args.skip_label,
|
||||
});
|
||||
turn_context
|
||||
.turn_metadata_state
|
||||
.mark_user_input_requested_during_turn();
|
||||
self.send_event(turn_context, event).await;
|
||||
rx_response.await.ok()
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::await_holding_invalid_type,
|
||||
reason = "active turn checks and turn state updates must remain atomic"
|
||||
)]
|
||||
pub async fn notify_option_picker_response(
|
||||
&self,
|
||||
sub_id: &str,
|
||||
response: OptionPickerResponse,
|
||||
) {
|
||||
let entry = {
|
||||
let mut active = self.active_turn.lock().await;
|
||||
match active.as_mut() {
|
||||
Some(at) => {
|
||||
let mut ts = at.turn_state.lock().await;
|
||||
ts.remove_pending_option_picker(sub_id)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
match entry {
|
||||
Some(tx_response) => {
|
||||
tx_response.send(response).ok();
|
||||
}
|
||||
None => {
|
||||
warn!("No pending option picker found for sub_id: {sub_id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::await_holding_invalid_type,
|
||||
reason = "active turn checks and turn state updates must remain atomic"
|
||||
)]
|
||||
pub async fn request_setup_codex_context_picker(
|
||||
&self,
|
||||
turn_context: &TurnContext,
|
||||
call_id: String,
|
||||
) -> Option<SetupCodexContextPickerResponse> {
|
||||
let sub_id = turn_context.sub_id.clone();
|
||||
let (tx_response, rx_response) = oneshot::channel();
|
||||
let event_id = sub_id.clone();
|
||||
let prev_entry = {
|
||||
let mut active = self.active_turn.lock().await;
|
||||
match active.as_mut() {
|
||||
Some(at) => {
|
||||
let mut ts = at.turn_state.lock().await;
|
||||
ts.insert_pending_setup_codex_context_picker(sub_id, tx_response)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
if prev_entry.is_some() {
|
||||
warn!("Overwriting existing pending setup codex context picker for sub_id: {event_id}");
|
||||
}
|
||||
|
||||
let event = EventMsg::SetupCodexContextPicker(SetupCodexContextPickerEvent {
|
||||
call_id,
|
||||
turn_id: turn_context.sub_id.clone(),
|
||||
});
|
||||
turn_context
|
||||
.turn_metadata_state
|
||||
.mark_user_input_requested_during_turn();
|
||||
self.send_event(turn_context, event).await;
|
||||
rx_response.await.ok()
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::await_holding_invalid_type,
|
||||
reason = "active turn checks and turn state updates must remain atomic"
|
||||
)]
|
||||
pub async fn notify_setup_codex_context_picker_response(
|
||||
&self,
|
||||
sub_id: &str,
|
||||
response: SetupCodexContextPickerResponse,
|
||||
) {
|
||||
let entry = {
|
||||
let mut active = self.active_turn.lock().await;
|
||||
match active.as_mut() {
|
||||
Some(at) => {
|
||||
let mut ts = at.turn_state.lock().await;
|
||||
ts.remove_pending_setup_codex_context_picker(sub_id)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
match entry {
|
||||
Some(tx_response) => {
|
||||
tx_response.send(response).ok();
|
||||
}
|
||||
None => {
|
||||
warn!("No pending setup codex context picker found for sub_id: {sub_id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::await_holding_invalid_type,
|
||||
reason = "active turn checks and turn state updates must remain atomic"
|
||||
|
||||
@@ -1362,6 +1362,8 @@ pub(super) fn realtime_text_for_event(msg: &EventMsg) -> Option<String> {
|
||||
| EventMsg::ExecApprovalRequest(_)
|
||||
| EventMsg::RequestPermissions(_)
|
||||
| EventMsg::RequestUserInput(_)
|
||||
| EventMsg::OptionPicker(_)
|
||||
| EventMsg::SetupCodexContextPicker(_)
|
||||
| EventMsg::DynamicToolCallRequest(_)
|
||||
| EventMsg::DynamicToolCallResponse(_)
|
||||
| EventMsg::GuardianAssessment(_)
|
||||
|
||||
@@ -14,6 +14,7 @@ use codex_protocol::dynamic_tools::DynamicToolResponse;
|
||||
use codex_protocol::request_permissions::RequestPermissionProfile;
|
||||
use codex_protocol::request_permissions::RequestPermissionsResponse;
|
||||
use codex_protocol::request_user_input::RequestUserInputResponse;
|
||||
use codex_protocol::setup_codex_context_picker::SetupCodexContextPickerResponse;
|
||||
use codex_rmcp_client::ElicitationResponse;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use rmcp::model::RequestId;
|
||||
@@ -23,6 +24,7 @@ use crate::session::TurnInputQueue;
|
||||
use crate::session::turn_context::TurnContext;
|
||||
use crate::tasks::AnySessionTask;
|
||||
use codex_protocol::models::AdditionalPermissionProfile;
|
||||
use codex_protocol::option_picker::OptionPickerResponse;
|
||||
use codex_protocol::protocol::ReviewDecision;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
|
||||
@@ -113,6 +115,9 @@ pub(crate) struct TurnState {
|
||||
pending_approvals: HashMap<String, oneshot::Sender<ReviewDecision>>,
|
||||
pending_request_permissions: HashMap<String, PendingRequestPermissions>,
|
||||
pending_user_input: HashMap<String, oneshot::Sender<RequestUserInputResponse>>,
|
||||
pending_option_picker: HashMap<String, oneshot::Sender<OptionPickerResponse>>,
|
||||
pending_setup_codex_context_picker:
|
||||
HashMap<String, oneshot::Sender<SetupCodexContextPickerResponse>>,
|
||||
pending_elicitations: HashMap<(String, RequestId), oneshot::Sender<ElicitationResponse>>,
|
||||
pending_dynamic_tools: HashMap<String, oneshot::Sender<DynamicToolResponse>>,
|
||||
pub(crate) pending_input: TurnInputQueue,
|
||||
@@ -150,6 +155,8 @@ impl TurnState {
|
||||
self.pending_approvals.clear();
|
||||
self.pending_request_permissions.clear();
|
||||
self.pending_user_input.clear();
|
||||
self.pending_option_picker.clear();
|
||||
self.pending_setup_codex_context_picker.clear();
|
||||
self.pending_elicitations.clear();
|
||||
self.pending_dynamic_tools.clear();
|
||||
}
|
||||
@@ -185,6 +192,36 @@ impl TurnState {
|
||||
self.pending_user_input.remove(key)
|
||||
}
|
||||
|
||||
pub(crate) fn insert_pending_option_picker(
|
||||
&mut self,
|
||||
key: String,
|
||||
tx: oneshot::Sender<OptionPickerResponse>,
|
||||
) -> Option<oneshot::Sender<OptionPickerResponse>> {
|
||||
self.pending_option_picker.insert(key, tx)
|
||||
}
|
||||
|
||||
pub(crate) fn remove_pending_option_picker(
|
||||
&mut self,
|
||||
key: &str,
|
||||
) -> Option<oneshot::Sender<OptionPickerResponse>> {
|
||||
self.pending_option_picker.remove(key)
|
||||
}
|
||||
|
||||
pub(crate) fn insert_pending_setup_codex_context_picker(
|
||||
&mut self,
|
||||
key: String,
|
||||
tx: oneshot::Sender<SetupCodexContextPickerResponse>,
|
||||
) -> Option<oneshot::Sender<SetupCodexContextPickerResponse>> {
|
||||
self.pending_setup_codex_context_picker.insert(key, tx)
|
||||
}
|
||||
|
||||
pub(crate) fn remove_pending_setup_codex_context_picker(
|
||||
&mut self,
|
||||
key: &str,
|
||||
) -> Option<oneshot::Sender<SetupCodexContextPickerResponse>> {
|
||||
self.pending_setup_codex_context_picker.remove(key)
|
||||
}
|
||||
|
||||
pub(crate) fn insert_pending_elicitation(
|
||||
&mut self,
|
||||
server_name: String,
|
||||
|
||||
@@ -15,6 +15,7 @@ pub(crate) mod multi_agents;
|
||||
pub(crate) mod multi_agents_common;
|
||||
pub(crate) mod multi_agents_spec;
|
||||
pub(crate) mod multi_agents_v2;
|
||||
mod option_picker;
|
||||
mod plan;
|
||||
pub(crate) mod plan_spec;
|
||||
mod request_permissions;
|
||||
@@ -22,6 +23,7 @@ mod request_plugin_install;
|
||||
pub(crate) mod request_plugin_install_spec;
|
||||
mod request_user_input;
|
||||
pub(crate) mod request_user_input_spec;
|
||||
mod setup_codex_context_picker;
|
||||
mod shell;
|
||||
pub(crate) mod shell_spec;
|
||||
mod test_sync;
|
||||
@@ -61,10 +63,12 @@ pub use mcp::McpHandler;
|
||||
pub use mcp_resource::ListMcpResourceTemplatesHandler;
|
||||
pub use mcp_resource::ListMcpResourcesHandler;
|
||||
pub use mcp_resource::ReadMcpResourceHandler;
|
||||
pub use option_picker::OptionPickerHandler;
|
||||
pub use plan::PlanHandler;
|
||||
pub use request_permissions::RequestPermissionsHandler;
|
||||
pub use request_plugin_install::RequestPluginInstallHandler;
|
||||
pub use request_user_input::RequestUserInputHandler;
|
||||
pub use setup_codex_context_picker::SetupCodexContextPickerHandler;
|
||||
pub use shell::ShellCommandHandler;
|
||||
pub(crate) use shell::ShellCommandHandlerOptions;
|
||||
pub use test_sync::TestSyncHandler;
|
||||
|
||||
77
codex-rs/core/src/tools/handlers/option_picker.rs
Normal file
77
codex-rs/core/src/tools/handlers/option_picker.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use crate::function_tool::FunctionCallError;
|
||||
use crate::tools::context::FunctionToolOutput;
|
||||
use crate::tools::context::ToolInvocation;
|
||||
use crate::tools::context::ToolPayload;
|
||||
use crate::tools::context::boxed_tool_output;
|
||||
use crate::tools::handlers::parse_arguments;
|
||||
use crate::tools::registry::CoreToolRuntime;
|
||||
use crate::tools::registry::ToolExecutor;
|
||||
use codex_protocol::option_picker::OptionPickerArgs;
|
||||
use codex_tools::REQUEST_OPTION_PICKER_TOOL_NAME;
|
||||
use codex_tools::ToolName;
|
||||
use codex_tools::ToolSpec;
|
||||
use codex_tools::create_request_option_picker_tool;
|
||||
|
||||
pub struct OptionPickerHandler;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ToolExecutor<ToolInvocation> for OptionPickerHandler {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::plain(REQUEST_OPTION_PICKER_TOOL_NAME)
|
||||
}
|
||||
|
||||
fn spec(&self) -> ToolSpec {
|
||||
create_request_option_picker_tool()
|
||||
}
|
||||
|
||||
async fn handle(
|
||||
&self,
|
||||
invocation: ToolInvocation,
|
||||
) -> Result<Box<dyn crate::tools::context::ToolOutput>, FunctionCallError> {
|
||||
let ToolInvocation {
|
||||
session,
|
||||
turn,
|
||||
call_id,
|
||||
payload,
|
||||
..
|
||||
} = invocation;
|
||||
|
||||
let arguments = match payload {
|
||||
ToolPayload::Function { arguments } => arguments,
|
||||
_ => {
|
||||
return Err(FunctionCallError::RespondToModel(format!(
|
||||
"{REQUEST_OPTION_PICKER_TOOL_NAME} handler received unsupported payload"
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
if turn.session_source.is_non_root_agent() {
|
||||
return Err(FunctionCallError::RespondToModel(
|
||||
"request_option_picker can only be used by the root thread".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let args: OptionPickerArgs = parse_arguments(&arguments)?;
|
||||
let response = session
|
||||
.request_option_picker(turn.as_ref(), call_id, args)
|
||||
.await
|
||||
.ok_or_else(|| {
|
||||
FunctionCallError::RespondToModel(format!(
|
||||
"{REQUEST_OPTION_PICKER_TOOL_NAME} was cancelled before receiving a response"
|
||||
))
|
||||
})?;
|
||||
|
||||
let content = serde_json::to_string(&response).map_err(|err| {
|
||||
FunctionCallError::Fatal(format!(
|
||||
"failed to serialize {REQUEST_OPTION_PICKER_TOOL_NAME} response: {err}"
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(boxed_tool_output(FunctionToolOutput::from_text(
|
||||
content,
|
||||
Some(true),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl CoreToolRuntime for OptionPickerHandler {}
|
||||
@@ -0,0 +1,77 @@
|
||||
use crate::function_tool::FunctionCallError;
|
||||
use crate::tools::context::FunctionToolOutput;
|
||||
use crate::tools::context::ToolInvocation;
|
||||
use crate::tools::context::ToolPayload;
|
||||
use crate::tools::context::boxed_tool_output;
|
||||
use crate::tools::handlers::parse_arguments;
|
||||
use crate::tools::registry::CoreToolRuntime;
|
||||
use crate::tools::registry::ToolExecutor;
|
||||
use codex_protocol::setup_codex_context_picker::SetupCodexContextPickerArgs;
|
||||
use codex_tools::SETUP_CODEX_CONTEXT_PICKER_TOOL_NAME;
|
||||
use codex_tools::ToolName;
|
||||
use codex_tools::ToolSpec;
|
||||
use codex_tools::create_setup_codex_context_picker_tool;
|
||||
|
||||
pub struct SetupCodexContextPickerHandler;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ToolExecutor<ToolInvocation> for SetupCodexContextPickerHandler {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::plain(SETUP_CODEX_CONTEXT_PICKER_TOOL_NAME)
|
||||
}
|
||||
|
||||
fn spec(&self) -> ToolSpec {
|
||||
create_setup_codex_context_picker_tool()
|
||||
}
|
||||
|
||||
async fn handle(
|
||||
&self,
|
||||
invocation: ToolInvocation,
|
||||
) -> Result<Box<dyn crate::tools::context::ToolOutput>, FunctionCallError> {
|
||||
let ToolInvocation {
|
||||
session,
|
||||
turn,
|
||||
call_id,
|
||||
payload,
|
||||
..
|
||||
} = invocation;
|
||||
|
||||
let arguments = match payload {
|
||||
ToolPayload::Function { arguments } => arguments,
|
||||
_ => {
|
||||
return Err(FunctionCallError::RespondToModel(format!(
|
||||
"{SETUP_CODEX_CONTEXT_PICKER_TOOL_NAME} handler received unsupported payload"
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
if turn.session_source.is_non_root_agent() {
|
||||
return Err(FunctionCallError::RespondToModel(
|
||||
"setup_codex_context_picker can only be used by the root thread".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let _: SetupCodexContextPickerArgs = parse_arguments(&arguments)?;
|
||||
let response = session
|
||||
.request_setup_codex_context_picker(turn.as_ref(), call_id)
|
||||
.await
|
||||
.ok_or_else(|| {
|
||||
FunctionCallError::RespondToModel(format!(
|
||||
"{SETUP_CODEX_CONTEXT_PICKER_TOOL_NAME} was cancelled before receiving a response"
|
||||
))
|
||||
})?;
|
||||
|
||||
let content = serde_json::to_string(&response).map_err(|err| {
|
||||
FunctionCallError::Fatal(format!(
|
||||
"failed to serialize {SETUP_CODEX_CONTEXT_PICKER_TOOL_NAME} response: {err}"
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(boxed_tool_output(FunctionToolOutput::from_text(
|
||||
content,
|
||||
Some(true),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl CoreToolRuntime for SetupCodexContextPickerHandler {}
|
||||
@@ -13,11 +13,13 @@ use crate::tools::handlers::ListAvailablePluginsToInstallHandler;
|
||||
use crate::tools::handlers::ListMcpResourceTemplatesHandler;
|
||||
use crate::tools::handlers::ListMcpResourcesHandler;
|
||||
use crate::tools::handlers::McpHandler;
|
||||
use crate::tools::handlers::OptionPickerHandler;
|
||||
use crate::tools::handlers::PlanHandler;
|
||||
use crate::tools::handlers::ReadMcpResourceHandler;
|
||||
use crate::tools::handlers::RequestPermissionsHandler;
|
||||
use crate::tools::handlers::RequestPluginInstallHandler;
|
||||
use crate::tools::handlers::RequestUserInputHandler;
|
||||
use crate::tools::handlers::SetupCodexContextPickerHandler;
|
||||
use crate::tools::handlers::ShellCommandHandler;
|
||||
use crate::tools::handlers::ShellCommandHandlerOptions;
|
||||
use crate::tools::handlers::TestSyncHandler;
|
||||
@@ -571,6 +573,10 @@ fn add_core_utility_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut
|
||||
planned_tools.add(RequestUserInputHandler {
|
||||
available_modes: request_user_input_available_modes(features),
|
||||
});
|
||||
if features.enabled(Feature::OnboardingInteractiveTools) {
|
||||
planned_tools.add(OptionPickerHandler);
|
||||
planned_tools.add(SetupCodexContextPickerHandler);
|
||||
}
|
||||
|
||||
if features.enabled(Feature::RequestPermissionsTool) {
|
||||
planned_tools.add(RequestPermissionsHandler);
|
||||
|
||||
@@ -1596,6 +1596,30 @@ async fn handle_server_request(
|
||||
)
|
||||
.await
|
||||
}
|
||||
ServerRequest::ToolOptionPicker { request_id, params } => {
|
||||
reject_server_request(
|
||||
client,
|
||||
request_id,
|
||||
&method,
|
||||
format!(
|
||||
"request_option_picker is not supported in exec mode for thread `{}`",
|
||||
params.thread_id
|
||||
),
|
||||
)
|
||||
.await
|
||||
}
|
||||
ServerRequest::ToolSetupCodexContextPicker { request_id, params } => {
|
||||
reject_server_request(
|
||||
client,
|
||||
request_id,
|
||||
&method,
|
||||
format!(
|
||||
"setup_codex_context_picker is not supported in exec mode for thread `{}`",
|
||||
params.thread_id
|
||||
),
|
||||
)
|
||||
.await
|
||||
}
|
||||
ServerRequest::DynamicToolCall { request_id, params } => {
|
||||
reject_server_request(
|
||||
client,
|
||||
|
||||
@@ -174,6 +174,8 @@ pub enum Feature {
|
||||
MentionsV2,
|
||||
/// Allow request_user_input in Default collaboration mode.
|
||||
DefaultModeRequestUserInput,
|
||||
/// Allow onboarding-only interactive tools.
|
||||
OnboardingInteractiveTools,
|
||||
/// Enable automatic review for approval prompts.
|
||||
GuardianApproval,
|
||||
/// Enable persisted thread goals and automatic goal continuation.
|
||||
@@ -1068,6 +1070,12 @@ pub const FEATURES: &[FeatureSpec] = &[
|
||||
stage: Stage::UnderDevelopment,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::OnboardingInteractiveTools,
|
||||
key: "onboarding_interactive_tools",
|
||||
stage: Stage::UnderDevelopment,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::GuardianApproval,
|
||||
key: "guardian_approval",
|
||||
|
||||
@@ -369,6 +369,8 @@ async fn run_codex_tool_session_inner(
|
||||
| EventMsg::ReasoningRawContentDelta(_)
|
||||
| EventMsg::ExitedReviewMode(_)
|
||||
| EventMsg::RequestUserInput(_)
|
||||
| EventMsg::OptionPicker(_)
|
||||
| EventMsg::SetupCodexContextPicker(_)
|
||||
| EventMsg::RequestPermissions(_)
|
||||
| EventMsg::DynamicToolCallRequest(_)
|
||||
| EventMsg::DynamicToolCallResponse(_)
|
||||
|
||||
@@ -21,11 +21,13 @@ pub mod models;
|
||||
pub mod network_policy;
|
||||
pub mod num_format;
|
||||
pub mod openai_models;
|
||||
pub mod option_picker;
|
||||
pub mod parse_command;
|
||||
pub mod permissions;
|
||||
pub mod plan_tool;
|
||||
pub mod protocol;
|
||||
pub mod request_permissions;
|
||||
pub mod request_user_input;
|
||||
pub mod setup_codex_context_picker;
|
||||
pub mod shell_environment;
|
||||
pub mod user_input;
|
||||
|
||||
58
codex-rs/protocol/src/option_picker.rs
Normal file
58
codex-rs/protocol/src/option_picker.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OptionPickerOption {
|
||||
pub label: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OptionPickerArgs {
|
||||
pub question: String,
|
||||
pub options: Vec<OptionPickerOption>,
|
||||
#[serde(default)]
|
||||
pub allow_multiple: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub submit_label: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub skip_label: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum OptionPickerAction {
|
||||
Submit,
|
||||
Skip,
|
||||
Dismiss,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OptionPickerResponse {
|
||||
pub action: OptionPickerAction,
|
||||
pub selected_options: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub freeform_answer: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OptionPickerEvent {
|
||||
/// Responses API call id for the associated tool call, if available.
|
||||
pub call_id: String,
|
||||
/// Turn ID that this request belongs to.
|
||||
pub turn_id: String,
|
||||
pub question: String,
|
||||
pub options: Vec<OptionPickerOption>,
|
||||
pub allow_multiple: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub submit_label: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub skip_label: Option<String>,
|
||||
}
|
||||
@@ -43,11 +43,13 @@ use crate::models::SandboxEnforcement;
|
||||
use crate::models::WebSearchAction;
|
||||
use crate::num_format::format_with_separators;
|
||||
use crate::openai_models::ReasoningEffort as ReasoningEffortConfig;
|
||||
use crate::option_picker::OptionPickerResponse;
|
||||
use crate::parse_command::ParsedCommand;
|
||||
use crate::plan_tool::UpdatePlanArgs;
|
||||
use crate::request_permissions::RequestPermissionsEvent;
|
||||
use crate::request_permissions::RequestPermissionsResponse;
|
||||
use crate::request_user_input::RequestUserInputResponse;
|
||||
use crate::setup_codex_context_picker::SetupCodexContextPickerResponse;
|
||||
use crate::user_input::UserInput;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use schemars::JsonSchema;
|
||||
@@ -75,6 +77,7 @@ pub use crate::approvals::NetworkApprovalContext;
|
||||
pub use crate::approvals::NetworkApprovalProtocol;
|
||||
pub use crate::approvals::NetworkPolicyAmendment;
|
||||
pub use crate::approvals::NetworkPolicyRuleAction;
|
||||
pub use crate::option_picker::OptionPickerEvent;
|
||||
pub use crate::permissions::FileSystemAccessMode;
|
||||
pub use crate::permissions::FileSystemPath;
|
||||
pub use crate::permissions::FileSystemSandboxEntry;
|
||||
@@ -85,6 +88,7 @@ pub use crate::permissions::NetworkSandboxPolicy;
|
||||
use crate::permissions::default_read_only_subpaths_for_writable_root;
|
||||
pub use crate::request_permissions::RequestPermissionsArgs;
|
||||
pub use crate::request_user_input::RequestUserInputEvent;
|
||||
pub use crate::setup_codex_context_picker::SetupCodexContextPickerEvent;
|
||||
|
||||
/// Open/close tags for special user-input blocks. Used across crates to avoid
|
||||
/// duplicated hardcoded strings.
|
||||
@@ -579,6 +583,22 @@ pub enum Op {
|
||||
response: RequestUserInputResponse,
|
||||
},
|
||||
|
||||
/// Resolve a request_option_picker tool call.
|
||||
OptionPickerResponse {
|
||||
/// Turn id for the in-flight request.
|
||||
id: String,
|
||||
/// User-provided selection.
|
||||
response: OptionPickerResponse,
|
||||
},
|
||||
|
||||
/// Resolve a setup_codex_context_picker tool call.
|
||||
SetupCodexContextPickerResponse {
|
||||
/// Turn id for the in-flight request.
|
||||
id: String,
|
||||
/// User-selected onboarding context sources.
|
||||
response: SetupCodexContextPickerResponse,
|
||||
},
|
||||
|
||||
/// Resolve a request_permissions tool call.
|
||||
RequestPermissionsResponse {
|
||||
/// Call id for the in-flight request.
|
||||
@@ -728,6 +748,8 @@ impl Op {
|
||||
Self::PatchApproval { .. } => "patch_approval",
|
||||
Self::ResolveElicitation { .. } => "resolve_elicitation",
|
||||
Self::UserInputAnswer { .. } => "user_input_answer",
|
||||
Self::OptionPickerResponse { .. } => "option_picker_response",
|
||||
Self::SetupCodexContextPickerResponse { .. } => "setup_codex_context_picker_response",
|
||||
Self::RequestPermissionsResponse { .. } => "request_permissions_response",
|
||||
Self::DynamicToolResponse { .. } => "dynamic_tool_response",
|
||||
Self::RefreshMcpServers { .. } => "refresh_mcp_servers",
|
||||
@@ -1246,6 +1268,10 @@ pub enum EventMsg {
|
||||
|
||||
RequestUserInput(RequestUserInputEvent),
|
||||
|
||||
OptionPicker(OptionPickerEvent),
|
||||
|
||||
SetupCodexContextPicker(SetupCodexContextPickerEvent),
|
||||
|
||||
DynamicToolCallRequest(DynamicToolCallRequest),
|
||||
|
||||
DynamicToolCallResponse(DynamicToolCallResponseEvent),
|
||||
|
||||
32
codex-rs/protocol/src/setup_codex_context_picker.rs
Normal file
32
codex-rs/protocol/src/setup_codex_context_picker.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SetupCodexContextPickerArgs {}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum SetupCodexContextPickerAction {
|
||||
Continue,
|
||||
Skip,
|
||||
Dismiss,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SetupCodexContextPickerResponse {
|
||||
pub action: SetupCodexContextPickerAction,
|
||||
pub selected_source_ids: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SetupCodexContextPickerEvent {
|
||||
/// Responses API call id for the associated tool call, if available.
|
||||
pub call_id: String,
|
||||
/// Turn ID that this request belongs to.
|
||||
pub turn_id: String,
|
||||
}
|
||||
@@ -251,6 +251,8 @@ pub(crate) fn tool_runtime_trace_event(event: &EventMsg) -> Option<ToolRuntimeTr
|
||||
| EventMsg::ExecApprovalRequest(_)
|
||||
| EventMsg::RequestPermissions(_)
|
||||
| EventMsg::RequestUserInput(_)
|
||||
| EventMsg::OptionPicker(_)
|
||||
| EventMsg::SetupCodexContextPicker(_)
|
||||
| EventMsg::DynamicToolCallRequest(_)
|
||||
| EventMsg::DynamicToolCallResponse(_)
|
||||
| EventMsg::ElicitationRequest(_)
|
||||
@@ -322,6 +324,8 @@ pub(crate) fn wrapped_protocol_event_type(event: &EventMsg) -> Option<&'static s
|
||||
| EventMsg::ExecApprovalRequest(_)
|
||||
| EventMsg::RequestPermissions(_)
|
||||
| EventMsg::RequestUserInput(_)
|
||||
| EventMsg::OptionPicker(_)
|
||||
| EventMsg::SetupCodexContextPicker(_)
|
||||
| EventMsg::DynamicToolCallRequest(_)
|
||||
| EventMsg::DynamicToolCallResponse(_)
|
||||
| EventMsg::ElicitationRequest(_)
|
||||
|
||||
@@ -191,6 +191,8 @@ fn event_msg_persistence_mode(ev: &EventMsg) -> Option<EventPersistenceMode> {
|
||||
| EventMsg::ExecApprovalRequest(_)
|
||||
| EventMsg::RequestPermissions(_)
|
||||
| EventMsg::RequestUserInput(_)
|
||||
| EventMsg::OptionPicker(_)
|
||||
| EventMsg::SetupCodexContextPicker(_)
|
||||
| EventMsg::ElicitationRequest(_)
|
||||
| EventMsg::ApplyPatchApprovalRequest(_)
|
||||
| EventMsg::StreamError(_)
|
||||
|
||||
@@ -7,8 +7,10 @@ mod function_call_error;
|
||||
mod image_detail;
|
||||
mod json_schema;
|
||||
mod mcp_tool;
|
||||
mod option_picker_tool;
|
||||
mod request_plugin_install;
|
||||
mod responses_api;
|
||||
mod setup_codex_context_picker_tool;
|
||||
mod tool_call;
|
||||
mod tool_config;
|
||||
mod tool_definition;
|
||||
@@ -36,6 +38,8 @@ pub use json_schema::JsonSchemaType;
|
||||
pub use json_schema::parse_tool_input_schema;
|
||||
pub use mcp_tool::mcp_call_tool_result_output_schema;
|
||||
pub use mcp_tool::parse_mcp_tool;
|
||||
pub use option_picker_tool::REQUEST_OPTION_PICKER_TOOL_NAME;
|
||||
pub use option_picker_tool::create_request_option_picker_tool;
|
||||
pub use request_plugin_install::REQUEST_PLUGIN_INSTALL_APPROVAL_KIND_VALUE;
|
||||
pub use request_plugin_install::REQUEST_PLUGIN_INSTALL_PERSIST_ALWAYS_VALUE;
|
||||
pub use request_plugin_install::REQUEST_PLUGIN_INSTALL_PERSIST_KEY;
|
||||
@@ -57,6 +61,8 @@ pub use responses_api::dynamic_tool_to_responses_api_tool;
|
||||
pub use responses_api::mcp_tool_to_deferred_responses_api_tool;
|
||||
pub use responses_api::mcp_tool_to_responses_api_tool;
|
||||
pub use responses_api::tool_definition_to_responses_api_tool;
|
||||
pub use setup_codex_context_picker_tool::SETUP_CODEX_CONTEXT_PICKER_TOOL_NAME;
|
||||
pub use setup_codex_context_picker_tool::create_setup_codex_context_picker_tool;
|
||||
pub use tool_call::ToolCall;
|
||||
pub use tool_config::ShellCommandBackendConfig;
|
||||
pub use tool_config::ToolEnvironmentMode;
|
||||
|
||||
65
codex-rs/tools/src/option_picker_tool.rs
Normal file
65
codex-rs/tools/src/option_picker_tool.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use crate::JsonSchema;
|
||||
use crate::ResponsesApiTool;
|
||||
use crate::ToolSpec;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub const REQUEST_OPTION_PICKER_TOOL_NAME: &str = "request_option_picker";
|
||||
|
||||
pub fn create_request_option_picker_tool() -> ToolSpec {
|
||||
let option_props = BTreeMap::from([
|
||||
(
|
||||
"label".to_string(),
|
||||
JsonSchema::string(Some("User-facing option label.".to_string())),
|
||||
),
|
||||
(
|
||||
"description".to_string(),
|
||||
JsonSchema::string(Some(
|
||||
"Optional short description for the option.".to_string(),
|
||||
)),
|
||||
),
|
||||
]);
|
||||
let properties = BTreeMap::from([
|
||||
(
|
||||
"question".to_string(),
|
||||
JsonSchema::string(Some("Question to show the user.".to_string())),
|
||||
),
|
||||
(
|
||||
"options".to_string(),
|
||||
JsonSchema::array(
|
||||
JsonSchema::object(
|
||||
option_props,
|
||||
Some(vec!["label".to_string()]),
|
||||
Some(false.into()),
|
||||
),
|
||||
Some("Selectable options to show in the picker.".to_string()),
|
||||
),
|
||||
),
|
||||
(
|
||||
"allowMultiple".to_string(),
|
||||
JsonSchema::boolean(Some(
|
||||
"Set true when the user may choose more than one option.".to_string(),
|
||||
)),
|
||||
),
|
||||
(
|
||||
"submitLabel".to_string(),
|
||||
JsonSchema::string(Some("Optional label for the submit button.".to_string())),
|
||||
),
|
||||
(
|
||||
"skipLabel".to_string(),
|
||||
JsonSchema::string(Some("Optional label for the skip button.".to_string())),
|
||||
),
|
||||
]);
|
||||
|
||||
ToolSpec::Function(ResponsesApiTool {
|
||||
name: REQUEST_OPTION_PICKER_TOOL_NAME.to_string(),
|
||||
description: "Ask the user to choose from a compact list of onboarding options. Use only when setting up Codex from the onboarding tutorial.".to_string(),
|
||||
strict: false,
|
||||
defer_loading: None,
|
||||
parameters: JsonSchema::object(
|
||||
properties,
|
||||
Some(vec!["question".to_string(), "options".to_string()]),
|
||||
Some(false.into()),
|
||||
),
|
||||
output_schema: None,
|
||||
})
|
||||
}
|
||||
17
codex-rs/tools/src/setup_codex_context_picker_tool.rs
Normal file
17
codex-rs/tools/src/setup_codex_context_picker_tool.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use crate::JsonSchema;
|
||||
use crate::ResponsesApiTool;
|
||||
use crate::ToolSpec;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub const SETUP_CODEX_CONTEXT_PICKER_TOOL_NAME: &str = "setup_codex_context_picker";
|
||||
|
||||
pub fn create_setup_codex_context_picker_tool() -> ToolSpec {
|
||||
ToolSpec::Function(ResponsesApiTool {
|
||||
name: SETUP_CODEX_CONTEXT_PICKER_TOOL_NAME.to_string(),
|
||||
description: "Open Codex's onboarding context source picker so the user can connect work apps or add a folder before the assistant continues setup.".to_string(),
|
||||
strict: false,
|
||||
defer_loading: None,
|
||||
parameters: JsonSchema::object(BTreeMap::new(), Some(Vec::new()), Some(false.into())),
|
||||
output_schema: None,
|
||||
})
|
||||
}
|
||||
@@ -27,8 +27,9 @@ pub fn request_user_input_available_modes(features: &Features) -> Vec<ModeKind>
|
||||
.into_iter()
|
||||
.filter(|mode| {
|
||||
mode.allows_request_user_input()
|
||||
|| (features.enabled(Feature::DefaultModeRequestUserInput)
|
||||
&& *mode == ModeKind::Default)
|
||||
|| (*mode == ModeKind::Default
|
||||
&& (features.enabled(Feature::DefaultModeRequestUserInput)
|
||||
|| features.enabled(Feature::OnboardingInteractiveTools)))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,12 @@ pub(super) fn server_request_thread_id(request: &ServerRequest) -> Option<Thread
|
||||
ServerRequest::ToolRequestUserInput { params, .. } => {
|
||||
ThreadId::from_string(¶ms.thread_id).ok()
|
||||
}
|
||||
ServerRequest::ToolOptionPicker { params, .. } => {
|
||||
ThreadId::from_string(¶ms.thread_id).ok()
|
||||
}
|
||||
ServerRequest::ToolSetupCodexContextPicker { params, .. } => {
|
||||
ThreadId::from_string(¶ms.thread_id).ok()
|
||||
}
|
||||
ServerRequest::McpServerElicitationRequest { params, .. } => {
|
||||
ThreadId::from_string(¶ms.thread_id).ok()
|
||||
}
|
||||
|
||||
@@ -127,6 +127,19 @@ impl PendingAppServerRequests {
|
||||
);
|
||||
None
|
||||
}
|
||||
ServerRequest::ToolOptionPicker { request_id, .. } => {
|
||||
Some(UnsupportedAppServerRequest {
|
||||
request_id: request_id.clone(),
|
||||
message: "Option picker requests are not available in TUI yet.".to_string(),
|
||||
})
|
||||
}
|
||||
ServerRequest::ToolSetupCodexContextPicker { request_id, .. } => {
|
||||
Some(UnsupportedAppServerRequest {
|
||||
request_id: request_id.clone(),
|
||||
message: "Setup Codex context picker requests are not available in TUI yet."
|
||||
.to_string(),
|
||||
})
|
||||
}
|
||||
ServerRequest::DynamicToolCall { request_id, .. } => {
|
||||
Some(UnsupportedAppServerRequest {
|
||||
request_id: request_id.clone(),
|
||||
@@ -336,7 +349,9 @@ impl PendingAppServerRequests {
|
||||
.mcp_requests
|
||||
.values()
|
||||
.any(|pending_request_id| pending_request_id == request_id),
|
||||
ServerRequest::DynamicToolCall { .. }
|
||||
ServerRequest::ToolOptionPicker { .. }
|
||||
| ServerRequest::ToolSetupCodexContextPicker { .. }
|
||||
| ServerRequest::DynamicToolCall { .. }
|
||||
| ServerRequest::ChatgptAuthTokensRefresh { .. }
|
||||
| ServerRequest::AttestationGenerate { .. }
|
||||
| ServerRequest::ApplyPatchApproval { .. }
|
||||
|
||||
@@ -85,6 +85,8 @@ impl SideParentStatus {
|
||||
pub(super) fn for_request(request: &ServerRequest) -> Option<Self> {
|
||||
match request {
|
||||
ServerRequest::ToolRequestUserInput { .. } => Some(SideParentStatus::NeedsInput),
|
||||
ServerRequest::ToolOptionPicker { .. } => Some(SideParentStatus::NeedsInput),
|
||||
ServerRequest::ToolSetupCodexContextPicker { .. } => Some(SideParentStatus::NeedsInput),
|
||||
ServerRequest::CommandExecutionRequestApproval { .. }
|
||||
| ServerRequest::FileChangeRequestApproval { .. }
|
||||
| ServerRequest::McpServerElicitationRequest { .. }
|
||||
|
||||
@@ -35,7 +35,9 @@ impl ChatWidget {
|
||||
ServerRequest::ToolRequestUserInput { params, .. } => {
|
||||
self.on_request_user_input(params);
|
||||
}
|
||||
ServerRequest::DynamicToolCall { .. }
|
||||
ServerRequest::ToolOptionPicker { .. }
|
||||
| ServerRequest::ToolSetupCodexContextPicker { .. }
|
||||
| ServerRequest::DynamicToolCall { .. }
|
||||
| ServerRequest::AttestationGenerate { .. }
|
||||
| ServerRequest::ChatgptAuthTokensRefresh { .. }
|
||||
| ServerRequest::ApplyPatchApproval { .. }
|
||||
|
||||
Reference in New Issue
Block a user