mirror of
https://github.com/openai/codex.git
synced 2026-05-22 03:54:18 +00:00
Compare commits
16 Commits
rust-v0.12
...
dev/ashwin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27d20b3e54 | ||
|
|
1945812d7c | ||
|
|
c6b0cf680b | ||
|
|
df316191fa | ||
|
|
ae038b9b88 | ||
|
|
4b9f85e15b | ||
|
|
37679d2a6c | ||
|
|
42d3e1b45f | ||
|
|
c857d458ad | ||
|
|
861ac203d8 | ||
|
|
eb50e97cf1 | ||
|
|
b3b0ce3645 | ||
|
|
6cfd0fd5e9 | ||
|
|
400d1a5f57 | ||
|
|
7b0f953a6c | ||
|
|
33fa66ae1e |
@@ -13784,9 +13784,117 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ToolFeatureConfig": {
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ToolsV2": {
|
||||
"properties": {
|
||||
"agent_jobs": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"agents": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"disable_defaults": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"document_generation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"filesystem": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"image_generation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"javascript": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"planning": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"shell": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"user_input": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"view_image": {
|
||||
"description": "Legacy enablement for the `view_image` capability.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
@@ -13795,7 +13903,7 @@
|
||||
"web_search": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/WebSearchToolConfig"
|
||||
"$ref": "#/definitions/v2/WebSearchFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
@@ -14417,6 +14525,46 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WebSearchFeatureConfig": {
|
||||
"properties": {
|
||||
"allowed_domains": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"context_size": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/WebSearchContextSize"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"enabled": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/WebSearchLocation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"WebSearchLocation": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -14455,41 +14603,6 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WebSearchToolConfig": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"allowed_domains": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"context_size": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/WebSearchContextSize"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/WebSearchLocation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"WindowsSandboxSetupCompletedNotification": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
|
||||
@@ -11544,9 +11544,117 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ToolFeatureConfig": {
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ToolsV2": {
|
||||
"properties": {
|
||||
"agent_jobs": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"agents": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"disable_defaults": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"document_generation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"filesystem": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"image_generation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"javascript": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"planning": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"shell": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"user_input": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"view_image": {
|
||||
"description": "Legacy enablement for the `view_image` capability.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
@@ -11555,7 +11663,7 @@
|
||||
"web_search": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchToolConfig"
|
||||
"$ref": "#/definitions/WebSearchFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
@@ -12177,6 +12285,46 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WebSearchFeatureConfig": {
|
||||
"properties": {
|
||||
"allowed_domains": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"context_size": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchContextSize"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"enabled": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchLocation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"WebSearchLocation": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -12215,41 +12363,6 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WebSearchToolConfig": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"allowed_domains": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"context_size": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchContextSize"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchLocation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"WindowsSandboxSetupCompletedNotification": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
|
||||
@@ -760,9 +760,117 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ToolFeatureConfig": {
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ToolsV2": {
|
||||
"properties": {
|
||||
"agent_jobs": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"agents": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"disable_defaults": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"document_generation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"filesystem": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"image_generation": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"javascript": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"planning": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"shell": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"user_input": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ToolFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"view_image": {
|
||||
"description": "Legacy enablement for the `view_image` capability.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
@@ -771,7 +879,7 @@
|
||||
"web_search": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchToolConfig"
|
||||
"$ref": "#/definitions/WebSearchFeatureConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
@@ -798,6 +906,46 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WebSearchFeatureConfig": {
|
||||
"properties": {
|
||||
"allowed_domains": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"context_size": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchContextSize"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"enabled": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchLocation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"WebSearchLocation": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -835,41 +983,6 @@
|
||||
"live"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WebSearchToolConfig": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"allowed_domains": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"context_size": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchContextSize"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchLocation"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// 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 { WebSearchContextSize } from "./WebSearchContextSize";
|
||||
import type { WebSearchLocation } from "./WebSearchLocation";
|
||||
|
||||
export type WebSearchToolConfig = { context_size: WebSearchContextSize | null, allowed_domains: Array<string> | null, location: WebSearchLocation | null, };
|
||||
@@ -74,5 +74,4 @@ export type { WebSearchAction } from "./WebSearchAction";
|
||||
export type { WebSearchContextSize } from "./WebSearchContextSize";
|
||||
export type { WebSearchLocation } from "./WebSearchLocation";
|
||||
export type { WebSearchMode } from "./WebSearchMode";
|
||||
export type { WebSearchToolConfig } from "./WebSearchToolConfig";
|
||||
export * as v2 from "./v2";
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ToolFeatureConfig = { enabled: boolean | null, };
|
||||
@@ -1,6 +1,11 @@
|
||||
// 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 { WebSearchToolConfig } from "../WebSearchToolConfig";
|
||||
import type { ToolFeatureConfig } from "./ToolFeatureConfig";
|
||||
import type { WebSearchFeatureConfig } from "./WebSearchFeatureConfig";
|
||||
|
||||
export type ToolsV2 = { web_search: WebSearchToolConfig | null, view_image: boolean | null, };
|
||||
export type ToolsV2 = { disable_defaults: boolean | null, shell: ToolFeatureConfig | null, filesystem: ToolFeatureConfig | null, javascript: ToolFeatureConfig | null, agents: ToolFeatureConfig | null, agent_jobs: ToolFeatureConfig | null, planning: ToolFeatureConfig | null, user_input: ToolFeatureConfig | null, web_search: WebSearchFeatureConfig | null, image_generation: ToolFeatureConfig | null, document_generation: ToolFeatureConfig | null,
|
||||
/**
|
||||
* Legacy enablement for the `view_image` capability.
|
||||
*/
|
||||
view_image: boolean | null, };
|
||||
|
||||
@@ -0,0 +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 { WebSearchContextSize } from "../WebSearchContextSize";
|
||||
import type { WebSearchLocation } from "../WebSearchLocation";
|
||||
|
||||
export type WebSearchFeatureConfig = { enabled: boolean | null, context_size: WebSearchContextSize | null, allowed_domains: Array<string> | null, location: WebSearchLocation | null, };
|
||||
@@ -305,6 +305,7 @@ export type { ThreadUnsubscribeParams } from "./ThreadUnsubscribeParams";
|
||||
export type { ThreadUnsubscribeResponse } from "./ThreadUnsubscribeResponse";
|
||||
export type { ThreadUnsubscribeStatus } from "./ThreadUnsubscribeStatus";
|
||||
export type { TokenUsageBreakdown } from "./TokenUsageBreakdown";
|
||||
export type { ToolFeatureConfig } from "./ToolFeatureConfig";
|
||||
export type { ToolRequestUserInputAnswer } from "./ToolRequestUserInputAnswer";
|
||||
export type { ToolRequestUserInputOption } from "./ToolRequestUserInputOption";
|
||||
export type { ToolRequestUserInputParams } from "./ToolRequestUserInputParams";
|
||||
@@ -328,6 +329,7 @@ export type { TurnSteerParams } from "./TurnSteerParams";
|
||||
export type { TurnSteerResponse } from "./TurnSteerResponse";
|
||||
export type { UserInput } from "./UserInput";
|
||||
export type { WebSearchAction } from "./WebSearchAction";
|
||||
export type { WebSearchFeatureConfig } from "./WebSearchFeatureConfig";
|
||||
export type { WindowsSandboxSetupCompletedNotification } from "./WindowsSandboxSetupCompletedNotification";
|
||||
export type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode";
|
||||
export type { WindowsSandboxSetupStartParams } from "./WindowsSandboxSetupStartParams";
|
||||
|
||||
@@ -533,11 +533,38 @@ pub struct SandboxWorkspaceWrite {
|
||||
pub exclude_slash_tmp: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ToolFeatureConfig {
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct WebSearchFeatureConfig {
|
||||
pub enabled: Option<bool>,
|
||||
#[serde(flatten)]
|
||||
pub config: WebSearchToolConfig,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct ToolsV2 {
|
||||
pub web_search: Option<WebSearchToolConfig>,
|
||||
pub disable_defaults: Option<bool>,
|
||||
pub shell: Option<ToolFeatureConfig>,
|
||||
pub filesystem: Option<ToolFeatureConfig>,
|
||||
pub javascript: Option<ToolFeatureConfig>,
|
||||
pub agents: Option<ToolFeatureConfig>,
|
||||
pub agent_jobs: Option<ToolFeatureConfig>,
|
||||
pub planning: Option<ToolFeatureConfig>,
|
||||
pub user_input: Option<ToolFeatureConfig>,
|
||||
pub web_search: Option<WebSearchFeatureConfig>,
|
||||
pub image_generation: Option<ToolFeatureConfig>,
|
||||
pub document_generation: Option<ToolFeatureConfig>,
|
||||
/// Legacy enablement for the `view_image` capability.
|
||||
pub view_image: Option<bool>,
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ use codex_app_server_protocol::JSONRPCResponse;
|
||||
use codex_app_server_protocol::MergeStrategy;
|
||||
use codex_app_server_protocol::RequestId;
|
||||
use codex_app_server_protocol::SandboxMode;
|
||||
use codex_app_server_protocol::ToolFeatureConfig;
|
||||
use codex_app_server_protocol::ToolsV2;
|
||||
use codex_app_server_protocol::WebSearchFeatureConfig;
|
||||
use codex_app_server_protocol::WriteStatus;
|
||||
use codex_core::config::set_project_trust_level;
|
||||
use codex_protocol::config_types::TrustLevel;
|
||||
@@ -97,11 +99,17 @@ async fn config_read_includes_tools() -> Result<()> {
|
||||
model = "gpt-user"
|
||||
|
||||
[tools.web_search]
|
||||
enabled = true
|
||||
context_size = "low"
|
||||
allowed_domains = ["example.com"]
|
||||
|
||||
[tools]
|
||||
disable_defaults = true
|
||||
view_image = false
|
||||
|
||||
[tools.shell]
|
||||
|
||||
[tools.filesystem]
|
||||
"#,
|
||||
)?;
|
||||
let codex_home_path = codex_home.path().canonicalize()?;
|
||||
@@ -131,11 +139,24 @@ view_image = false
|
||||
assert_eq!(
|
||||
tools,
|
||||
ToolsV2 {
|
||||
web_search: Some(WebSearchToolConfig {
|
||||
context_size: Some(WebSearchContextSize::Low),
|
||||
allowed_domains: Some(vec!["example.com".to_string()]),
|
||||
location: None,
|
||||
disable_defaults: Some(true),
|
||||
shell: Some(ToolFeatureConfig { enabled: None }),
|
||||
filesystem: Some(ToolFeatureConfig { enabled: None }),
|
||||
javascript: None,
|
||||
agents: None,
|
||||
agent_jobs: None,
|
||||
planning: None,
|
||||
user_input: None,
|
||||
web_search: Some(WebSearchFeatureConfig {
|
||||
enabled: Some(true),
|
||||
config: WebSearchToolConfig {
|
||||
context_size: Some(WebSearchContextSize::Low),
|
||||
allowed_domains: Some(vec!["example.com".to_string()]),
|
||||
location: None,
|
||||
},
|
||||
}),
|
||||
image_generation: None,
|
||||
document_generation: None,
|
||||
view_image: Some(false),
|
||||
}
|
||||
);
|
||||
@@ -163,7 +184,12 @@ view_image = false
|
||||
file: user_file.clone(),
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
origins.get("tools.disable_defaults").expect("origin").name,
|
||||
ConfigLayerSource::User {
|
||||
file: user_file.clone(),
|
||||
}
|
||||
);
|
||||
let layers = layers.expect("layers present");
|
||||
assert_layers_user_then_optional_system(&layers, user_file)?;
|
||||
|
||||
@@ -203,15 +229,18 @@ location = { country = "US", city = "New York", timezone = "America/New_York" }
|
||||
|
||||
assert_eq!(
|
||||
config.tools.expect("tools present").web_search,
|
||||
Some(WebSearchToolConfig {
|
||||
context_size: Some(WebSearchContextSize::High),
|
||||
allowed_domains: Some(vec!["example.com".to_string()]),
|
||||
location: Some(WebSearchLocation {
|
||||
country: Some("US".to_string()),
|
||||
region: None,
|
||||
city: Some("New York".to_string()),
|
||||
timezone: Some("America/New_York".to_string()),
|
||||
}),
|
||||
Some(WebSearchFeatureConfig {
|
||||
enabled: None,
|
||||
config: WebSearchToolConfig {
|
||||
context_size: Some(WebSearchContextSize::High),
|
||||
allowed_domains: Some(vec!["example.com".to_string()]),
|
||||
location: Some(WebSearchLocation {
|
||||
country: Some("US".to_string()),
|
||||
region: None,
|
||||
city: Some("New York".to_string()),
|
||||
timezone: Some("America/New_York".to_string()),
|
||||
}),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ use codex_protocol::openai_models::ReasoningEffort;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::Value;
|
||||
use serde_json::json;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
@@ -153,6 +154,46 @@ async fn thread_start_creates_thread_and_emits_started() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_start_accepts_grouped_tool_overrides() -> Result<()> {
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
create_config_toml(codex_home.path(), &server.uri())?;
|
||||
|
||||
let mut mcp = McpProcess::new(codex_home.path()).await?;
|
||||
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
|
||||
|
||||
let req_id = mcp
|
||||
.send_thread_start_request(ThreadStartParams {
|
||||
config: Some(HashMap::from([(
|
||||
"tools".to_string(),
|
||||
json!({
|
||||
"disable_defaults": true,
|
||||
"shell": {},
|
||||
"filesystem": {},
|
||||
"web_search": {
|
||||
"enabled": true,
|
||||
"context_size": "low",
|
||||
"allowed_domains": ["example.com"]
|
||||
}
|
||||
}),
|
||||
)])),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
let resp: JSONRPCResponse = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_response_message(RequestId::Integer(req_id)),
|
||||
)
|
||||
.await??;
|
||||
let ThreadStartResponse { thread, .. } = to_response::<ThreadStartResponse>(resp)?;
|
||||
assert!(!thread.id.is_empty(), "thread id should not be empty");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_start_respects_project_config_from_cwd() -> Result<()> {
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
|
||||
@@ -1552,6 +1552,15 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ToolFeatureToml": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"ToolSuggestConfig": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -1591,15 +1600,48 @@
|
||||
"ToolsToml": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"agent_jobs": {
|
||||
"$ref": "#/definitions/ToolFeatureToml"
|
||||
},
|
||||
"agents": {
|
||||
"$ref": "#/definitions/ToolFeatureToml"
|
||||
},
|
||||
"disable_defaults": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"document_generation": {
|
||||
"$ref": "#/definitions/ToolFeatureToml"
|
||||
},
|
||||
"filesystem": {
|
||||
"$ref": "#/definitions/ToolFeatureToml"
|
||||
},
|
||||
"image_generation": {
|
||||
"$ref": "#/definitions/ToolFeatureToml"
|
||||
},
|
||||
"javascript": {
|
||||
"$ref": "#/definitions/ToolFeatureToml"
|
||||
},
|
||||
"planning": {
|
||||
"$ref": "#/definitions/ToolFeatureToml"
|
||||
},
|
||||
"shell": {
|
||||
"$ref": "#/definitions/ToolFeatureToml"
|
||||
},
|
||||
"user_input": {
|
||||
"$ref": "#/definitions/ToolFeatureToml"
|
||||
},
|
||||
"view_image": {
|
||||
"default": null,
|
||||
"description": "Enable the `view_image` tool that lets the agent attach local images.",
|
||||
"description": "Legacy enablement for the `view_image` capability.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"web_search": {
|
||||
"allOf": [
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchToolConfig"
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/WebSearchFeatureToml"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
@@ -1726,6 +1768,27 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WebSearchFeatureToml": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"allowed_domains": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"context_size": {
|
||||
"$ref": "#/definitions/WebSearchContextSize"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/definitions/WebSearchLocation"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"WebSearchLocation": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -1752,24 +1815,6 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WebSearchToolConfig": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"allowed_domains": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"context_size": {
|
||||
"$ref": "#/definitions/WebSearchContextSize"
|
||||
},
|
||||
"location": {
|
||||
"$ref": "#/definitions/WebSearchLocation"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"WindowsSandboxModeToml": {
|
||||
"enum": [
|
||||
"elevated",
|
||||
|
||||
@@ -889,6 +889,8 @@ impl TurnContext {
|
||||
sandbox_policy: self.sandbox_policy.get(),
|
||||
windows_sandbox_level: self.windows_sandbox_level,
|
||||
})
|
||||
.with_tool_feature_overrides(config.tool_feature_overrides.clone())
|
||||
.with_legacy_view_image_override(config.legacy_view_image_override)
|
||||
.with_unified_exec_shell_mode(self.tools_config.unified_exec_shell_mode.clone())
|
||||
.with_web_search_config(self.tools_config.web_search_config.clone())
|
||||
.with_allow_login_shell(self.tools_config.allow_login_shell)
|
||||
@@ -1327,6 +1329,8 @@ impl Session {
|
||||
sandbox_policy: session_configuration.sandbox_policy.get(),
|
||||
windows_sandbox_level: session_configuration.windows_sandbox_level,
|
||||
})
|
||||
.with_tool_feature_overrides(per_turn_config.tool_feature_overrides.clone())
|
||||
.with_legacy_view_image_override(per_turn_config.legacy_view_image_override)
|
||||
.with_unified_exec_shell_mode_for_session(
|
||||
user_shell,
|
||||
shell_zsh_path,
|
||||
@@ -5192,6 +5196,8 @@ async fn spawn_review_thread(
|
||||
sandbox_policy: parent_turn_context.sandbox_policy.get(),
|
||||
windows_sandbox_level: parent_turn_context.windows_sandbox_level,
|
||||
})
|
||||
.with_tool_feature_overrides(config.tool_feature_overrides.clone())
|
||||
.with_legacy_view_image_override(config.legacy_view_image_override)
|
||||
.with_unified_exec_shell_mode_for_session(
|
||||
sess.services.user_shell.as_ref(),
|
||||
sess.services.shell_zsh_path.as_ref(),
|
||||
|
||||
@@ -17,6 +17,7 @@ use assert_matches::assert_matches;
|
||||
use codex_config::CONFIG_TOML_FILE;
|
||||
use codex_features::Feature;
|
||||
use codex_features::FeaturesToml;
|
||||
use codex_protocol::config_types::WebSearchContextSize;
|
||||
use codex_protocol::permissions::FileSystemAccessMode;
|
||||
use codex_protocol::permissions::FileSystemPath;
|
||||
use codex_protocol::permissions::FileSystemSandboxEntry;
|
||||
@@ -196,6 +197,7 @@ web_search = true
|
||||
Some(ToolsToml {
|
||||
web_search: None,
|
||||
view_image: None,
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -215,6 +217,35 @@ web_search = false
|
||||
Some(ToolsToml {
|
||||
web_search: None,
|
||||
view_image: None,
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tools_feature_tables_deserialize() {
|
||||
let cfg: ConfigToml = toml::from_str(
|
||||
r#"
|
||||
[tools]
|
||||
disable_defaults = true
|
||||
|
||||
[tools.shell]
|
||||
|
||||
[tools.filesystem]
|
||||
enabled = false
|
||||
"#,
|
||||
)
|
||||
.expect("TOML deserialization should succeed");
|
||||
|
||||
assert_eq!(
|
||||
cfg.tools,
|
||||
Some(ToolsToml {
|
||||
disable_defaults: Some(true),
|
||||
shell: Some(ToolFeatureToml { enabled: None }),
|
||||
filesystem: Some(ToolFeatureToml {
|
||||
enabled: Some(false),
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -1455,7 +1486,10 @@ fn web_search_mode_defaults_to_none_if_unset() {
|
||||
let profile = ConfigProfile::default();
|
||||
let features = Features::with_defaults();
|
||||
|
||||
assert_eq!(resolve_web_search_mode(&cfg, &profile, &features), None);
|
||||
assert_eq!(
|
||||
resolve_web_search_mode(&cfg, &profile, &features, &ToolFeatureOverrides::default()),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1469,7 +1503,7 @@ fn web_search_mode_prefers_profile_over_legacy_flags() {
|
||||
features.enable(Feature::WebSearchCached);
|
||||
|
||||
assert_eq!(
|
||||
resolve_web_search_mode(&cfg, &profile, &features),
|
||||
resolve_web_search_mode(&cfg, &profile, &features, &ToolFeatureOverrides::default()),
|
||||
Some(WebSearchMode::Live)
|
||||
);
|
||||
}
|
||||
@@ -1485,11 +1519,154 @@ fn web_search_mode_disabled_overrides_legacy_request() {
|
||||
features.enable(Feature::WebSearchRequest);
|
||||
|
||||
assert_eq!(
|
||||
resolve_web_search_mode(&cfg, &profile, &features),
|
||||
resolve_web_search_mode(&cfg, &profile, &features, &ToolFeatureOverrides::default()),
|
||||
Some(WebSearchMode::Disabled)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_search_mode_disable_defaults_disables_tool() {
|
||||
let cfg = ConfigToml::default();
|
||||
let profile = ConfigProfile::default();
|
||||
let mut features = Features::with_defaults();
|
||||
features.enable(Feature::WebSearchCached);
|
||||
let overrides = ToolFeatureOverrides {
|
||||
disable_defaults: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
resolve_web_search_mode(&cfg, &profile, &features, &overrides),
|
||||
Some(WebSearchMode::Disabled)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_search_mode_disable_defaults_ignores_explicit_mode_without_grouped_enable() {
|
||||
let cfg = ConfigToml {
|
||||
web_search: Some(WebSearchMode::Cached),
|
||||
..Default::default()
|
||||
};
|
||||
let profile = ConfigProfile::default();
|
||||
let features = Features::with_defaults();
|
||||
let overrides = ToolFeatureOverrides {
|
||||
disable_defaults: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
resolve_web_search_mode(&cfg, &profile, &features, &overrides),
|
||||
Some(WebSearchMode::Disabled)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_search_mode_explicit_disabled_wins_when_feature_enabled() {
|
||||
let cfg = ConfigToml {
|
||||
web_search: Some(WebSearchMode::Disabled),
|
||||
..Default::default()
|
||||
};
|
||||
let profile = ConfigProfile::default();
|
||||
let mut features = Features::with_defaults();
|
||||
features.enable(Feature::WebSearchCached);
|
||||
let overrides = ToolFeatureOverrides {
|
||||
web_search: Some(true),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
resolve_web_search_mode(&cfg, &profile, &features, &overrides),
|
||||
Some(WebSearchMode::Disabled)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_tool_feature_overrides_returns_defaults_when_omitted() {
|
||||
let cfg: ConfigToml = toml::from_str(
|
||||
r#"
|
||||
[tools]
|
||||
view_image = false
|
||||
"#,
|
||||
)
|
||||
.expect("TOML deserialization should succeed");
|
||||
|
||||
assert_eq!(
|
||||
resolve_tool_feature_overrides(&cfg, &ConfigProfile::default()),
|
||||
ToolFeatureOverrides::default()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_tool_feature_overrides_profile_web_search_config_only_inherits_disabled_state() {
|
||||
let cfg = ConfigToml {
|
||||
tools: Some(ToolsToml {
|
||||
web_search: Some(WebSearchFeatureToml {
|
||||
enabled: Some(false),
|
||||
config: WebSearchToolConfig::default(),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
let profile = ConfigProfile {
|
||||
tools: Some(ToolsToml {
|
||||
web_search: Some(WebSearchFeatureToml {
|
||||
enabled: None,
|
||||
config: WebSearchToolConfig {
|
||||
context_size: Some(WebSearchContextSize::Low),
|
||||
..Default::default()
|
||||
},
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
resolve_tool_feature_overrides(&cfg, &profile),
|
||||
ToolFeatureOverrides {
|
||||
web_search: Some(false),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_tool_feature_overrides_web_search_config_only_defaults_to_enabled_when_both_layers_present()
|
||||
{
|
||||
let cfg = ConfigToml {
|
||||
tools: Some(ToolsToml {
|
||||
web_search: Some(WebSearchFeatureToml {
|
||||
enabled: None,
|
||||
config: WebSearchToolConfig::default(),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
let profile = ConfigProfile {
|
||||
tools: Some(ToolsToml {
|
||||
web_search: Some(WebSearchFeatureToml {
|
||||
enabled: None,
|
||||
config: WebSearchToolConfig {
|
||||
context_size: Some(WebSearchContextSize::Low),
|
||||
..Default::default()
|
||||
},
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
resolve_tool_feature_overrides(&cfg, &profile),
|
||||
ToolFeatureOverrides {
|
||||
web_search: Some(true),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_search_mode_for_turn_uses_preference_for_read_only() {
|
||||
let web_search_mode = Constrained::allow_any(WebSearchMode::Cached);
|
||||
@@ -4331,6 +4508,8 @@ fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> {
|
||||
include_apply_patch_tool: false,
|
||||
web_search_mode: Constrained::allow_any(WebSearchMode::Cached),
|
||||
web_search_config: None,
|
||||
tool_feature_overrides: ToolFeatureOverrides::default(),
|
||||
legacy_view_image_override: None,
|
||||
use_experimental_unified_exec_tool: !cfg!(windows),
|
||||
background_terminal_max_timeout: DEFAULT_MAX_BACKGROUND_TERMINAL_TIMEOUT_MS,
|
||||
ghost_snapshot: GhostSnapshotConfig::default(),
|
||||
@@ -4474,6 +4653,8 @@ fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
|
||||
include_apply_patch_tool: false,
|
||||
web_search_mode: Constrained::allow_any(WebSearchMode::Cached),
|
||||
web_search_config: None,
|
||||
tool_feature_overrides: ToolFeatureOverrides::default(),
|
||||
legacy_view_image_override: None,
|
||||
use_experimental_unified_exec_tool: !cfg!(windows),
|
||||
background_terminal_max_timeout: DEFAULT_MAX_BACKGROUND_TERMINAL_TIMEOUT_MS,
|
||||
ghost_snapshot: GhostSnapshotConfig::default(),
|
||||
@@ -4615,6 +4796,8 @@ fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> {
|
||||
include_apply_patch_tool: false,
|
||||
web_search_mode: Constrained::allow_any(WebSearchMode::Cached),
|
||||
web_search_config: None,
|
||||
tool_feature_overrides: ToolFeatureOverrides::default(),
|
||||
legacy_view_image_override: None,
|
||||
use_experimental_unified_exec_tool: !cfg!(windows),
|
||||
background_terminal_max_timeout: DEFAULT_MAX_BACKGROUND_TERMINAL_TIMEOUT_MS,
|
||||
ghost_snapshot: GhostSnapshotConfig::default(),
|
||||
@@ -4742,6 +4925,8 @@ fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> {
|
||||
include_apply_patch_tool: false,
|
||||
web_search_mode: Constrained::allow_any(WebSearchMode::Cached),
|
||||
web_search_config: None,
|
||||
tool_feature_overrides: ToolFeatureOverrides::default(),
|
||||
legacy_view_image_override: None,
|
||||
use_experimental_unified_exec_tool: !cfg!(windows),
|
||||
background_terminal_max_timeout: DEFAULT_MAX_BACKGROUND_TERMINAL_TIMEOUT_MS,
|
||||
ghost_snapshot: GhostSnapshotConfig::default(),
|
||||
|
||||
@@ -54,6 +54,7 @@ use crate::project_doc::LOCAL_PROJECT_DOC_FILENAME;
|
||||
use crate::protocol::AskForApproval;
|
||||
use crate::protocol::ReadOnlyAccess;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::tools::registry::ToolFeatureKey;
|
||||
use crate::unified_exec::DEFAULT_MAX_BACKGROUND_TERMINAL_TIMEOUT_MS;
|
||||
use crate::unified_exec::MIN_EMPTY_YIELD_TIME_MS;
|
||||
use crate::windows_sandbox::WindowsSandboxLevelExt;
|
||||
@@ -546,6 +547,12 @@ pub struct Config {
|
||||
/// Additional parameters for the web search tool when it is enabled.
|
||||
pub web_search_config: Option<WebSearchConfig>,
|
||||
|
||||
/// Explicit grouped tool feature overrides requested by config.
|
||||
pub tool_feature_overrides: ToolFeatureOverrides,
|
||||
|
||||
/// Legacy `tools.view_image` fallback used when no explicit capability override is present.
|
||||
pub legacy_view_image_override: Option<bool>,
|
||||
|
||||
/// If set to `true`, used only the experimental unified exec tool.
|
||||
pub use_experimental_unified_exec_tool: bool,
|
||||
|
||||
@@ -600,6 +607,38 @@ pub struct Config {
|
||||
pub otel: crate::config::types::OtelConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||
pub struct ToolFeatureOverrides {
|
||||
pub disable_defaults: bool,
|
||||
pub shell: Option<bool>,
|
||||
pub filesystem: Option<bool>,
|
||||
pub javascript: Option<bool>,
|
||||
pub agents: Option<bool>,
|
||||
pub agent_jobs: Option<bool>,
|
||||
pub planning: Option<bool>,
|
||||
pub user_input: Option<bool>,
|
||||
pub web_search: Option<bool>,
|
||||
pub image_generation: Option<bool>,
|
||||
pub document_generation: Option<bool>,
|
||||
}
|
||||
|
||||
impl ToolFeatureOverrides {
|
||||
pub(crate) fn for_feature(&self, feature: ToolFeatureKey) -> Option<bool> {
|
||||
match feature {
|
||||
ToolFeatureKey::Shell => self.shell,
|
||||
ToolFeatureKey::Filesystem => self.filesystem,
|
||||
ToolFeatureKey::Javascript => self.javascript,
|
||||
ToolFeatureKey::Agents => self.agents,
|
||||
ToolFeatureKey::AgentJobs => self.agent_jobs,
|
||||
ToolFeatureKey::Planning => self.planning,
|
||||
ToolFeatureKey::UserInput => self.user_input,
|
||||
ToolFeatureKey::WebSearch => self.web_search,
|
||||
ToolFeatureKey::ImageGeneration => self.image_generation,
|
||||
ToolFeatureKey::DocumentGeneration => self.document_generation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ConfigBuilder {
|
||||
codex_home: Option<PathBuf>,
|
||||
@@ -1604,42 +1643,82 @@ pub struct RealtimeAudioToml {
|
||||
pub speaker: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||
#[schemars(deny_unknown_fields)]
|
||||
pub struct ToolFeatureToml {
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
impl ToolFeatureToml {
|
||||
fn is_enabled(&self) -> bool {
|
||||
self.enabled.unwrap_or(true)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||
#[schemars(deny_unknown_fields)]
|
||||
pub struct WebSearchFeatureToml {
|
||||
pub enabled: Option<bool>,
|
||||
#[serde(flatten)]
|
||||
pub config: WebSearchToolConfig,
|
||||
}
|
||||
|
||||
impl WebSearchFeatureToml {
|
||||
fn is_enabled(&self) -> bool {
|
||||
self.enabled.unwrap_or(true)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||
#[schemars(deny_unknown_fields)]
|
||||
pub struct ToolsToml {
|
||||
pub disable_defaults: Option<bool>,
|
||||
pub shell: Option<ToolFeatureToml>,
|
||||
pub filesystem: Option<ToolFeatureToml>,
|
||||
pub javascript: Option<ToolFeatureToml>,
|
||||
pub agents: Option<ToolFeatureToml>,
|
||||
pub agent_jobs: Option<ToolFeatureToml>,
|
||||
pub planning: Option<ToolFeatureToml>,
|
||||
pub user_input: Option<ToolFeatureToml>,
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "deserialize_optional_web_search_tool_config"
|
||||
deserialize_with = "deserialize_optional_web_search_feature_config"
|
||||
)]
|
||||
pub web_search: Option<WebSearchToolConfig>,
|
||||
#[schemars(schema_with = "crate::config::schema::web_search_feature_schema")]
|
||||
pub web_search: Option<WebSearchFeatureToml>,
|
||||
pub image_generation: Option<ToolFeatureToml>,
|
||||
pub document_generation: Option<ToolFeatureToml>,
|
||||
|
||||
/// Enable the `view_image` tool that lets the agent attach local images.
|
||||
/// Legacy enablement for the `view_image` capability.
|
||||
#[serde(default)]
|
||||
pub view_image: Option<bool>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum WebSearchToolConfigInput {
|
||||
enum WebSearchFeatureConfigInput {
|
||||
Enabled(bool),
|
||||
Config(WebSearchToolConfig),
|
||||
Feature(WebSearchFeatureToml),
|
||||
}
|
||||
|
||||
fn deserialize_optional_web_search_tool_config<'de, D>(
|
||||
fn deserialize_optional_web_search_feature_config<'de, D>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<WebSearchToolConfig>, D::Error>
|
||||
) -> Result<Option<WebSearchFeatureToml>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value = Option::<WebSearchToolConfigInput>::deserialize(deserializer)?;
|
||||
let value = Option::<WebSearchFeatureConfigInput>::deserialize(deserializer)?;
|
||||
|
||||
Ok(match value {
|
||||
None => None,
|
||||
Some(WebSearchToolConfigInput::Enabled(enabled)) => {
|
||||
// Preserve legacy behavior: accept boolean `tools.web_search = true|false`
|
||||
// without treating it as a grouped feature override.
|
||||
Some(WebSearchFeatureConfigInput::Enabled(enabled)) => {
|
||||
let _ = enabled;
|
||||
None
|
||||
}
|
||||
Some(WebSearchToolConfigInput::Config(config)) => Some(config),
|
||||
Some(WebSearchFeatureConfigInput::Feature(feature)) => Some(feature),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1722,7 +1801,10 @@ pub struct AgentRoleToml {
|
||||
impl From<ToolsToml> for Tools {
|
||||
fn from(tools_toml: ToolsToml) -> Self {
|
||||
Self {
|
||||
web_search: tools_toml.web_search.is_some().then_some(true),
|
||||
web_search: tools_toml
|
||||
.web_search
|
||||
.as_ref()
|
||||
.map(WebSearchFeatureToml::is_enabled),
|
||||
view_image: tools_toml.view_image,
|
||||
}
|
||||
}
|
||||
@@ -2034,31 +2116,42 @@ fn resolve_web_search_mode(
|
||||
config_toml: &ConfigToml,
|
||||
config_profile: &ConfigProfile,
|
||||
features: &Features,
|
||||
tool_feature_overrides: &ToolFeatureOverrides,
|
||||
) -> Option<WebSearchMode> {
|
||||
if let Some(mode) = config_profile.web_search.or(config_toml.web_search) {
|
||||
return Some(mode);
|
||||
match tool_feature_overrides.web_search {
|
||||
Some(false) => Some(WebSearchMode::Disabled),
|
||||
None if tool_feature_overrides.disable_defaults => Some(WebSearchMode::Disabled),
|
||||
None | Some(true) => config_profile
|
||||
.web_search
|
||||
.or(config_toml.web_search)
|
||||
.or_else(|| {
|
||||
if features.enabled(Feature::WebSearchCached) {
|
||||
Some(WebSearchMode::Cached)
|
||||
} else if features.enabled(Feature::WebSearchRequest) {
|
||||
Some(WebSearchMode::Live)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
}
|
||||
if features.enabled(Feature::WebSearchCached) {
|
||||
return Some(WebSearchMode::Cached);
|
||||
}
|
||||
if features.enabled(Feature::WebSearchRequest) {
|
||||
return Some(WebSearchMode::Live);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn resolve_web_search_config(
|
||||
config_toml: &ConfigToml,
|
||||
config_profile: &ConfigProfile,
|
||||
) -> Option<WebSearchConfig> {
|
||||
let base = config_toml
|
||||
.tools
|
||||
.as_ref()
|
||||
.and_then(|tools| tools.web_search.as_ref());
|
||||
let profile = config_profile
|
||||
.tools
|
||||
.as_ref()
|
||||
.and_then(|tools| tools.web_search.as_ref());
|
||||
let base = config_toml.tools.as_ref().and_then(|tools| {
|
||||
tools
|
||||
.web_search
|
||||
.as_ref()
|
||||
.map(|web_search| &web_search.config)
|
||||
});
|
||||
let profile = config_profile.tools.as_ref().and_then(|tools| {
|
||||
tools
|
||||
.web_search
|
||||
.as_ref()
|
||||
.map(|web_search| &web_search.config)
|
||||
});
|
||||
|
||||
match (base, profile) {
|
||||
(None, None) => None,
|
||||
@@ -2068,6 +2161,93 @@ fn resolve_web_search_config(
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_legacy_view_image_override(
|
||||
config_toml: &ConfigToml,
|
||||
config_profile: &ConfigProfile,
|
||||
) -> Option<bool> {
|
||||
config_profile
|
||||
.tools
|
||||
.as_ref()
|
||||
.and_then(|tools| tools.view_image)
|
||||
.or(config_profile.tools_view_image)
|
||||
.or_else(|| {
|
||||
config_toml
|
||||
.tools
|
||||
.as_ref()
|
||||
.and_then(|tools| tools.view_image)
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_tool_feature_overrides(
|
||||
config_toml: &ConfigToml,
|
||||
config_profile: &ConfigProfile,
|
||||
) -> ToolFeatureOverrides {
|
||||
let base = config_toml.tools.as_ref();
|
||||
let profile = config_profile.tools.as_ref();
|
||||
|
||||
let resolve_feature = |profile_feature: Option<&ToolFeatureToml>,
|
||||
base_feature: Option<&ToolFeatureToml>| {
|
||||
profile_feature
|
||||
.map(ToolFeatureToml::is_enabled)
|
||||
.or_else(|| base_feature.map(ToolFeatureToml::is_enabled))
|
||||
};
|
||||
|
||||
ToolFeatureOverrides {
|
||||
disable_defaults: profile
|
||||
.and_then(|tools| tools.disable_defaults)
|
||||
.or_else(|| base.and_then(|tools| tools.disable_defaults))
|
||||
.unwrap_or(false),
|
||||
shell: resolve_feature(
|
||||
profile.and_then(|tools| tools.shell.as_ref()),
|
||||
base.and_then(|tools| tools.shell.as_ref()),
|
||||
),
|
||||
filesystem: resolve_feature(
|
||||
profile.and_then(|tools| tools.filesystem.as_ref()),
|
||||
base.and_then(|tools| tools.filesystem.as_ref()),
|
||||
),
|
||||
javascript: resolve_feature(
|
||||
profile.and_then(|tools| tools.javascript.as_ref()),
|
||||
base.and_then(|tools| tools.javascript.as_ref()),
|
||||
),
|
||||
agents: resolve_feature(
|
||||
profile.and_then(|tools| tools.agents.as_ref()),
|
||||
base.and_then(|tools| tools.agents.as_ref()),
|
||||
),
|
||||
agent_jobs: resolve_feature(
|
||||
profile.and_then(|tools| tools.agent_jobs.as_ref()),
|
||||
base.and_then(|tools| tools.agent_jobs.as_ref()),
|
||||
),
|
||||
planning: resolve_feature(
|
||||
profile.and_then(|tools| tools.planning.as_ref()),
|
||||
base.and_then(|tools| tools.planning.as_ref()),
|
||||
),
|
||||
user_input: resolve_feature(
|
||||
profile.and_then(|tools| tools.user_input.as_ref()),
|
||||
base.and_then(|tools| tools.user_input.as_ref()),
|
||||
),
|
||||
web_search: match (
|
||||
profile.and_then(|tools| tools.web_search.as_ref()),
|
||||
base.and_then(|tools| tools.web_search.as_ref()),
|
||||
) {
|
||||
(Some(profile_web_search), Some(base_web_search)) => profile_web_search
|
||||
.enabled
|
||||
.or(base_web_search.enabled)
|
||||
.or(Some(true)),
|
||||
(Some(profile_web_search), None) => Some(profile_web_search.is_enabled()),
|
||||
(None, Some(base_web_search)) => Some(base_web_search.is_enabled()),
|
||||
(None, None) => None,
|
||||
},
|
||||
image_generation: resolve_feature(
|
||||
profile.and_then(|tools| tools.image_generation.as_ref()),
|
||||
base.and_then(|tools| tools.image_generation.as_ref()),
|
||||
),
|
||||
document_generation: resolve_feature(
|
||||
profile.and_then(|tools| tools.document_generation.as_ref()),
|
||||
base.and_then(|tools| tools.document_generation.as_ref()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_web_search_mode_for_turn(
|
||||
web_search_mode: &Constrained<WebSearchMode>,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
@@ -2372,13 +2552,16 @@ impl Config {
|
||||
);
|
||||
approval_policy = constrained_approval_policy.value();
|
||||
}
|
||||
let tool_feature_overrides = resolve_tool_feature_overrides(&cfg, &config_profile);
|
||||
let approvals_reviewer = approvals_reviewer_override
|
||||
.or(config_profile.approvals_reviewer)
|
||||
.or(cfg.approvals_reviewer)
|
||||
.unwrap_or(ApprovalsReviewer::User);
|
||||
let web_search_mode = resolve_web_search_mode(&cfg, &config_profile, &features)
|
||||
.unwrap_or(WebSearchMode::Cached);
|
||||
let web_search_mode =
|
||||
resolve_web_search_mode(&cfg, &config_profile, &features, &tool_feature_overrides)
|
||||
.unwrap_or(WebSearchMode::Cached);
|
||||
let web_search_config = resolve_web_search_config(&cfg, &config_profile);
|
||||
let legacy_view_image_override = resolve_legacy_view_image_override(&cfg, &config_profile);
|
||||
|
||||
let agent_roles =
|
||||
agent_roles::load_agent_roles(&cfg, &config_layer_stack, &mut startup_warnings)?;
|
||||
@@ -2798,6 +2981,8 @@ impl Config {
|
||||
include_apply_patch_tool: include_apply_patch_tool_flag,
|
||||
web_search_mode: constrained_web_search_mode.value,
|
||||
web_search_config,
|
||||
tool_feature_overrides,
|
||||
legacy_view_image_override,
|
||||
use_experimental_unified_exec_tool,
|
||||
background_terminal_max_timeout,
|
||||
ghost_snapshot,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::config::ConfigToml;
|
||||
use crate::config::WebSearchFeatureToml;
|
||||
use crate::config::types::RawMcpServerConfig;
|
||||
use codex_features::FEATURES;
|
||||
use codex_features::legacy_feature_keys;
|
||||
@@ -53,6 +54,21 @@ pub(crate) fn mcp_servers_schema(schema_gen: &mut SchemaGenerator) -> Schema {
|
||||
Schema::Object(object)
|
||||
}
|
||||
|
||||
/// Schema for `tools.web_search`, which still accepts a legacy boolean
|
||||
/// shorthand in addition to the grouped object form.
|
||||
pub(crate) fn web_search_feature_schema(schema_gen: &mut SchemaGenerator) -> Schema {
|
||||
Schema::Object(SchemaObject {
|
||||
subschemas: Some(Box::new(schemars::schema::SubschemaValidation {
|
||||
any_of: Some(vec![
|
||||
schema_gen.subschema_for::<bool>(),
|
||||
schema_gen.subschema_for::<WebSearchFeatureToml>(),
|
||||
]),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
/// Build the config schema for `config.toml`.
|
||||
pub fn config_schema() -> RootSchema {
|
||||
SchemaSettings::draft07()
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::function_tool::FunctionCallError;
|
||||
use crate::memories::usage::emit_metric_for_tool_read;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::sandbox_tags::sandbox_tag;
|
||||
use crate::tools::code_mode::PUBLIC_TOOL_NAME;
|
||||
use crate::tools::context::ToolInvocation;
|
||||
use crate::tools::context::ToolOutput;
|
||||
use crate::tools::context::ToolPayload;
|
||||
@@ -20,9 +21,212 @@ use codex_hooks::HookToolInput;
|
||||
use codex_hooks::HookToolInputLocalShell;
|
||||
use codex_hooks::HookToolKind;
|
||||
use codex_protocol::models::ResponseInputItem;
|
||||
use codex_protocol::models::VIEW_IMAGE_TOOL_NAME;
|
||||
use codex_utils_readiness::Readiness;
|
||||
use tracing::warn;
|
||||
|
||||
pub(crate) const CONTAINER_EXEC_TOOL_NAME: &str = "container.exec";
|
||||
pub(crate) const EXEC_COMMAND_TOOL_NAME: &str = "exec_command";
|
||||
pub(crate) const LOCAL_SHELL_TOOL_NAME: &str = "local_shell";
|
||||
pub(crate) const SHELL_COMMAND_TOOL_NAME: &str = "shell_command";
|
||||
pub(crate) const SHELL_TOOL_NAME: &str = "shell";
|
||||
pub(crate) const WRITE_STDIN_TOOL_NAME: &str = "write_stdin";
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
/// Individual built-in tools known to Codex, independent of how they are
|
||||
/// grouped for config-driven enablement.
|
||||
pub(crate) enum BuiltinToolKey {
|
||||
ApplyPatch,
|
||||
Artifacts,
|
||||
CloseAgent,
|
||||
CodeMode,
|
||||
ContainerExec,
|
||||
ExecCommand,
|
||||
GrepFiles,
|
||||
ImageGeneration,
|
||||
JsRepl,
|
||||
JsReplReset,
|
||||
ListDir,
|
||||
ListMcpResources,
|
||||
ListMcpResourceTemplates,
|
||||
LocalShell,
|
||||
ReadFile,
|
||||
ReadMcpResource,
|
||||
RequestPermissions,
|
||||
RequestUserInput,
|
||||
ReportAgentJobResult,
|
||||
ResumeAgent,
|
||||
SearchToolBm25,
|
||||
SendInput,
|
||||
Shell,
|
||||
ShellCommand,
|
||||
SpawnAgent,
|
||||
SpawnAgentsOnCsv,
|
||||
TestSyncTool,
|
||||
UpdatePlan,
|
||||
ViewImage,
|
||||
Wait,
|
||||
WebSearch,
|
||||
WriteStdin,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
/// Coarse-grained built-in tool capability groups exposed in `config.tools`.
|
||||
pub(crate) enum ToolFeatureKey {
|
||||
Shell,
|
||||
Filesystem,
|
||||
Javascript,
|
||||
Agents,
|
||||
AgentJobs,
|
||||
Planning,
|
||||
UserInput,
|
||||
WebSearch,
|
||||
ImageGeneration,
|
||||
DocumentGeneration,
|
||||
}
|
||||
|
||||
impl BuiltinToolKey {
|
||||
pub(crate) const ALL: [Self; 32] = [
|
||||
Self::ApplyPatch,
|
||||
Self::Artifacts,
|
||||
Self::CloseAgent,
|
||||
Self::CodeMode,
|
||||
Self::ContainerExec,
|
||||
Self::ExecCommand,
|
||||
Self::GrepFiles,
|
||||
Self::ImageGeneration,
|
||||
Self::JsRepl,
|
||||
Self::JsReplReset,
|
||||
Self::ListDir,
|
||||
Self::ListMcpResources,
|
||||
Self::ListMcpResourceTemplates,
|
||||
Self::LocalShell,
|
||||
Self::ReadFile,
|
||||
Self::ReadMcpResource,
|
||||
Self::RequestPermissions,
|
||||
Self::RequestUserInput,
|
||||
Self::ReportAgentJobResult,
|
||||
Self::ResumeAgent,
|
||||
Self::SearchToolBm25,
|
||||
Self::SendInput,
|
||||
Self::Shell,
|
||||
Self::ShellCommand,
|
||||
Self::SpawnAgent,
|
||||
Self::SpawnAgentsOnCsv,
|
||||
Self::TestSyncTool,
|
||||
Self::UpdatePlan,
|
||||
Self::ViewImage,
|
||||
Self::Wait,
|
||||
Self::WebSearch,
|
||||
Self::WriteStdin,
|
||||
];
|
||||
|
||||
pub(crate) fn iter() -> impl Iterator<Item = Self> {
|
||||
Self::ALL.into_iter()
|
||||
}
|
||||
|
||||
pub(crate) const fn invocation_names(self) -> &'static [&'static str] {
|
||||
match self {
|
||||
Self::CodeMode => &[PUBLIC_TOOL_NAME],
|
||||
Self::ContainerExec => &[CONTAINER_EXEC_TOOL_NAME],
|
||||
Self::ExecCommand => &[EXEC_COMMAND_TOOL_NAME],
|
||||
Self::LocalShell => &[LOCAL_SHELL_TOOL_NAME],
|
||||
Self::Shell => &[SHELL_TOOL_NAME],
|
||||
Self::ShellCommand => &[SHELL_COMMAND_TOOL_NAME],
|
||||
Self::WriteStdin => &[WRITE_STDIN_TOOL_NAME],
|
||||
Self::ListMcpResources => &["list_mcp_resources"],
|
||||
Self::ListMcpResourceTemplates => &["list_mcp_resource_templates"],
|
||||
Self::ReadMcpResource => &["read_mcp_resource"],
|
||||
Self::UpdatePlan => &["update_plan"],
|
||||
Self::JsRepl => &["js_repl"],
|
||||
Self::JsReplReset => &["js_repl_reset"],
|
||||
Self::RequestUserInput => &["request_user_input"],
|
||||
Self::RequestPermissions => &["request_permissions"],
|
||||
Self::SearchToolBm25 => &["tool_search"],
|
||||
Self::ApplyPatch => &["apply_patch"],
|
||||
Self::GrepFiles => &["grep_files"],
|
||||
Self::ReadFile => &["read_file"],
|
||||
Self::ListDir => &["list_dir"],
|
||||
Self::TestSyncTool => &["test_sync_tool"],
|
||||
Self::WebSearch => &["web_search"],
|
||||
Self::ImageGeneration => &["image_generation"],
|
||||
Self::ViewImage => &[VIEW_IMAGE_TOOL_NAME],
|
||||
Self::Artifacts => &["artifacts"],
|
||||
Self::SpawnAgent => &["spawn_agent"],
|
||||
Self::SendInput => &["send_input"],
|
||||
Self::ResumeAgent => &["resume_agent"],
|
||||
Self::Wait => &["wait_agent"],
|
||||
Self::CloseAgent => &["close_agent"],
|
||||
Self::SpawnAgentsOnCsv => &["spawn_agents_on_csv"],
|
||||
Self::ReportAgentJobResult => &["report_agent_job_result"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolFeatureKey {
|
||||
const ALL: [Self; 10] = [
|
||||
Self::Shell,
|
||||
Self::Filesystem,
|
||||
Self::Javascript,
|
||||
Self::Agents,
|
||||
Self::AgentJobs,
|
||||
Self::Planning,
|
||||
Self::UserInput,
|
||||
Self::WebSearch,
|
||||
Self::ImageGeneration,
|
||||
Self::DocumentGeneration,
|
||||
];
|
||||
|
||||
pub(crate) fn iter() -> impl Iterator<Item = Self> {
|
||||
Self::ALL.into_iter()
|
||||
}
|
||||
|
||||
pub(crate) const fn builtin_tool_keys(self) -> &'static [BuiltinToolKey] {
|
||||
match self {
|
||||
Self::Shell => &[
|
||||
BuiltinToolKey::ContainerExec,
|
||||
BuiltinToolKey::ExecCommand,
|
||||
BuiltinToolKey::LocalShell,
|
||||
BuiltinToolKey::Shell,
|
||||
BuiltinToolKey::ShellCommand,
|
||||
BuiltinToolKey::WriteStdin,
|
||||
],
|
||||
Self::Filesystem => &[
|
||||
BuiltinToolKey::ApplyPatch,
|
||||
BuiltinToolKey::GrepFiles,
|
||||
BuiltinToolKey::ReadFile,
|
||||
BuiltinToolKey::ListDir,
|
||||
BuiltinToolKey::ViewImage,
|
||||
],
|
||||
Self::Javascript => &[BuiltinToolKey::JsRepl, BuiltinToolKey::JsReplReset],
|
||||
Self::Agents => &[
|
||||
BuiltinToolKey::SpawnAgent,
|
||||
BuiltinToolKey::SendInput,
|
||||
BuiltinToolKey::ResumeAgent,
|
||||
BuiltinToolKey::Wait,
|
||||
BuiltinToolKey::CloseAgent,
|
||||
],
|
||||
Self::AgentJobs => &[
|
||||
BuiltinToolKey::SpawnAgentsOnCsv,
|
||||
BuiltinToolKey::ReportAgentJobResult,
|
||||
],
|
||||
Self::Planning => &[BuiltinToolKey::UpdatePlan],
|
||||
Self::UserInput => &[BuiltinToolKey::RequestUserInput],
|
||||
Self::WebSearch => &[BuiltinToolKey::WebSearch],
|
||||
Self::ImageGeneration => &[BuiltinToolKey::ImageGeneration],
|
||||
Self::DocumentGeneration => &[BuiltinToolKey::Artifacts],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn for_builtin_tool(tool: BuiltinToolKey) -> Option<Self> {
|
||||
Self::iter().find(|feature| feature.builtin_tool_keys().contains(&tool))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn builtin_tool_key(name: &str) -> Option<BuiltinToolKey> {
|
||||
BuiltinToolKey::iter().find(|key| key.invocation_names().contains(&name))
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ToolKind {
|
||||
Function,
|
||||
|
||||
@@ -3,6 +3,7 @@ use crate::client_common::tools::FreeformToolFormat;
|
||||
use crate::client_common::tools::ResponsesApiTool;
|
||||
use crate::client_common::tools::ToolSpec;
|
||||
use crate::config::AgentRoleConfig;
|
||||
use crate::config::ToolFeatureOverrides;
|
||||
use crate::mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
use crate::mcp_connection_manager::ToolInfo;
|
||||
use crate::models_manager::collaboration_mode_presets::CollaborationModesConfig;
|
||||
@@ -31,7 +32,16 @@ use crate::tools::handlers::multi_agents::MAX_WAIT_TIMEOUT_MS;
|
||||
use crate::tools::handlers::multi_agents::MIN_WAIT_TIMEOUT_MS;
|
||||
use crate::tools::handlers::request_permissions_tool_description;
|
||||
use crate::tools::handlers::request_user_input_tool_description;
|
||||
use crate::tools::registry::BuiltinToolKey;
|
||||
use crate::tools::registry::CONTAINER_EXEC_TOOL_NAME;
|
||||
use crate::tools::registry::EXEC_COMMAND_TOOL_NAME;
|
||||
use crate::tools::registry::LOCAL_SHELL_TOOL_NAME;
|
||||
use crate::tools::registry::SHELL_COMMAND_TOOL_NAME;
|
||||
use crate::tools::registry::SHELL_TOOL_NAME;
|
||||
use crate::tools::registry::ToolFeatureKey;
|
||||
use crate::tools::registry::ToolRegistryBuilder;
|
||||
use crate::tools::registry::WRITE_STDIN_TOOL_NAME;
|
||||
use crate::tools::registry::builtin_tool_key;
|
||||
use crate::tools::registry::tool_handler_key;
|
||||
use codex_features::Feature;
|
||||
use codex_features::Features;
|
||||
@@ -269,6 +279,8 @@ pub(crate) struct ToolsConfig {
|
||||
shell_command_backend: ShellCommandBackendConfig,
|
||||
pub unified_exec_shell_mode: UnifiedExecShellMode,
|
||||
pub allow_login_shell: bool,
|
||||
pub tool_feature_overrides: ToolFeatureOverrides,
|
||||
pub legacy_view_image_override: Option<bool>,
|
||||
pub apply_patch_tool_type: Option<ApplyPatchToolType>,
|
||||
pub web_search_mode: Option<WebSearchMode>,
|
||||
pub web_search_config: Option<WebSearchConfig>,
|
||||
@@ -403,6 +415,8 @@ impl ToolsConfig {
|
||||
shell_command_backend,
|
||||
unified_exec_shell_mode: UnifiedExecShellMode::Direct,
|
||||
allow_login_shell: true,
|
||||
tool_feature_overrides: ToolFeatureOverrides::default(),
|
||||
legacy_view_image_override: None,
|
||||
apply_patch_tool_type,
|
||||
web_search_mode: *web_search_mode,
|
||||
web_search_config: None,
|
||||
@@ -439,6 +453,22 @@ impl ToolsConfig {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_tool_feature_overrides(
|
||||
mut self,
|
||||
tool_feature_overrides: ToolFeatureOverrides,
|
||||
) -> Self {
|
||||
self.tool_feature_overrides = tool_feature_overrides;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_legacy_view_image_override(
|
||||
mut self,
|
||||
legacy_view_image_override: Option<bool>,
|
||||
) -> Self {
|
||||
self.legacy_view_image_override = legacy_view_image_override;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_unified_exec_shell_mode(
|
||||
mut self,
|
||||
unified_exec_shell_mode: UnifiedExecShellMode,
|
||||
@@ -473,6 +503,71 @@ impl ToolsConfig {
|
||||
nested.code_mode_only_enabled = false;
|
||||
nested
|
||||
}
|
||||
|
||||
pub fn is_builtin_tool_invocation_enabled(&self, tool_name: &str) -> bool {
|
||||
let Some(tool) = builtin_tool_key(tool_name) else {
|
||||
return false;
|
||||
};
|
||||
let Some(feature) = ToolFeatureKey::for_builtin_tool(tool) else {
|
||||
return true;
|
||||
};
|
||||
if self.is_feature_explicitly_controlled(feature) {
|
||||
// In explicit grouped mode (`tools.disable_defaults = true`), the
|
||||
// `[tools.<feature>]` table is the source of truth for exposure.
|
||||
// That intentionally bypasses legacy fallback logic such as
|
||||
// top-level `web_search` mode-based enablement.
|
||||
return self.is_tool_feature_enabled(feature);
|
||||
}
|
||||
|
||||
match tool {
|
||||
BuiltinToolKey::ApplyPatch => self.apply_patch_tool_type.is_some(),
|
||||
BuiltinToolKey::ViewImage => self.legacy_view_image_override.unwrap_or(true),
|
||||
BuiltinToolKey::WebSearch => self.is_web_search_enabled(),
|
||||
_ => self.is_tool_feature_enabled(feature),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_feature_explicitly_controlled(&self, feature: ToolFeatureKey) -> bool {
|
||||
self.tool_feature_overrides.disable_defaults
|
||||
|| self.tool_feature_overrides.for_feature(feature).is_some()
|
||||
}
|
||||
|
||||
fn is_web_search_enabled(&self) -> bool {
|
||||
// The resolved web_search_mode already reflects config, feature defaults,
|
||||
// and any requirement-driven overrides.
|
||||
self.web_search_mode
|
||||
.is_some_and(|mode| mode != WebSearchMode::Disabled)
|
||||
}
|
||||
|
||||
fn is_tool_feature_enabled(&self, feature: ToolFeatureKey) -> bool {
|
||||
if let Some(enabled) = self.tool_feature_overrides.for_feature(feature) {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
if self.tool_feature_overrides.disable_defaults {
|
||||
false
|
||||
} else {
|
||||
self.is_tool_feature_enabled_by_default(feature)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_tool_feature_enabled_by_default(&self, feature: ToolFeatureKey) -> bool {
|
||||
match feature {
|
||||
ToolFeatureKey::Shell => self.shell_type != ConfigShellToolType::Disabled,
|
||||
ToolFeatureKey::Filesystem => self
|
||||
.experimental_supported_tools
|
||||
.iter()
|
||||
.any(|tool| matches!(tool.as_str(), "grep_files" | "read_file" | "list_dir")),
|
||||
ToolFeatureKey::Javascript => self.js_repl_enabled,
|
||||
ToolFeatureKey::Agents => self.collab_tools,
|
||||
ToolFeatureKey::AgentJobs => self.agent_jobs_tools,
|
||||
ToolFeatureKey::Planning => true,
|
||||
ToolFeatureKey::UserInput => self.request_user_input,
|
||||
ToolFeatureKey::WebSearch => self.is_web_search_enabled(),
|
||||
ToolFeatureKey::ImageGeneration => self.image_gen_tool,
|
||||
ToolFeatureKey::DocumentGeneration => self.artifact_tools,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn supports_image_generation(model_info: &ModelInfo) -> bool {
|
||||
@@ -2331,6 +2426,44 @@ fn push_tool_spec(
|
||||
}
|
||||
}
|
||||
|
||||
fn push_builtin_tool_spec_if_enabled(
|
||||
builder: &mut ToolRegistryBuilder,
|
||||
config: &ToolsConfig,
|
||||
invocation_name: &str,
|
||||
spec: ToolSpec,
|
||||
supports_parallel_tool_calls: bool,
|
||||
) {
|
||||
if config.is_builtin_tool_invocation_enabled(invocation_name) {
|
||||
push_tool_spec(
|
||||
builder,
|
||||
spec,
|
||||
supports_parallel_tool_calls,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_builtin_tool_with_handler_if_enabled<H>(
|
||||
builder: &mut ToolRegistryBuilder,
|
||||
config: &ToolsConfig,
|
||||
invocation_name: &str,
|
||||
spec: ToolSpec,
|
||||
supports_parallel_tool_calls: bool,
|
||||
handler: std::sync::Arc<H>,
|
||||
) where
|
||||
H: crate::tools::registry::ToolHandler + 'static,
|
||||
{
|
||||
if config.is_builtin_tool_invocation_enabled(invocation_name) {
|
||||
push_tool_spec(
|
||||
builder,
|
||||
spec,
|
||||
supports_parallel_tool_calls,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler(invocation_name, handler);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn mcp_tool_to_openai_tool(
|
||||
fully_qualified_name: String,
|
||||
tool: rmcp::model::Tool,
|
||||
@@ -2670,62 +2803,69 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
|
||||
match &config.shell_type {
|
||||
ConfigShellToolType::Default => {
|
||||
push_tool_spec(
|
||||
push_builtin_tool_spec_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
SHELL_TOOL_NAME,
|
||||
create_shell_tool(exec_permission_approvals_enabled),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
ConfigShellToolType::Local => {
|
||||
push_tool_spec(
|
||||
push_builtin_tool_spec_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
LOCAL_SHELL_TOOL_NAME,
|
||||
ToolSpec::LocalShell {},
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
ConfigShellToolType::UnifiedExec => {
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
EXEC_COMMAND_TOOL_NAME,
|
||||
create_exec_command_tool(
|
||||
config.allow_login_shell,
|
||||
exec_permission_approvals_enabled,
|
||||
),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
unified_exec_handler.clone(),
|
||||
);
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
WRITE_STDIN_TOOL_NAME,
|
||||
create_write_stdin_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
unified_exec_handler,
|
||||
);
|
||||
builder.register_handler("exec_command", unified_exec_handler.clone());
|
||||
builder.register_handler("write_stdin", unified_exec_handler);
|
||||
}
|
||||
ConfigShellToolType::Disabled => {
|
||||
// Do nothing.
|
||||
}
|
||||
ConfigShellToolType::ShellCommand => {
|
||||
push_tool_spec(
|
||||
push_builtin_tool_spec_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
SHELL_COMMAND_TOOL_NAME,
|
||||
create_shell_command_tool(
|
||||
config.allow_login_shell,
|
||||
exec_permission_approvals_enabled,
|
||||
),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if config.shell_type != ConfigShellToolType::Disabled {
|
||||
if config.shell_type != ConfigShellToolType::Disabled
|
||||
&& config.is_builtin_tool_invocation_enabled(SHELL_TOOL_NAME)
|
||||
{
|
||||
// Always register shell aliases so older prompts remain compatible.
|
||||
builder.register_handler("shell", shell_handler.clone());
|
||||
builder.register_handler("container.exec", shell_handler.clone());
|
||||
builder.register_handler("local_shell", shell_handler);
|
||||
builder.register_handler("shell_command", shell_command_handler);
|
||||
builder.register_handler(SHELL_TOOL_NAME, shell_handler.clone());
|
||||
builder.register_handler(CONTAINER_EXEC_TOOL_NAME, shell_handler.clone());
|
||||
builder.register_handler(LOCAL_SHELL_TOOL_NAME, shell_handler);
|
||||
builder.register_handler(SHELL_COMMAND_TOOL_NAME, shell_command_handler);
|
||||
}
|
||||
|
||||
if mcp_tools.is_some() {
|
||||
@@ -2752,41 +2892,46 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
builder.register_handler("read_mcp_resource", mcp_resource_handler);
|
||||
}
|
||||
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"update_plan",
|
||||
PLAN_TOOL.clone(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
plan_handler,
|
||||
);
|
||||
builder.register_handler("update_plan", plan_handler);
|
||||
|
||||
if config.js_repl_enabled {
|
||||
push_tool_spec(
|
||||
if config.js_repl_enabled && config.is_builtin_tool_invocation_enabled("js_repl") {
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"js_repl",
|
||||
create_js_repl_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
js_repl_handler,
|
||||
);
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"js_repl_reset",
|
||||
create_js_repl_reset_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
js_repl_reset_handler,
|
||||
);
|
||||
builder.register_handler("js_repl", js_repl_handler);
|
||||
builder.register_handler("js_repl_reset", js_repl_reset_handler);
|
||||
}
|
||||
|
||||
if config.request_user_input {
|
||||
push_tool_spec(
|
||||
if config.request_user_input && config.is_builtin_tool_invocation_enabled("request_user_input")
|
||||
{
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"request_user_input",
|
||||
create_request_user_input_tool(CollaborationModesConfig {
|
||||
default_mode_request_user_input: config.default_mode_request_user_input,
|
||||
}),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
request_user_input_handler,
|
||||
);
|
||||
builder.register_handler("request_user_input", request_user_input_handler);
|
||||
}
|
||||
|
||||
if config.request_permissions_tool_enabled {
|
||||
@@ -2831,22 +2976,26 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
builder.register_handler(TOOL_SUGGEST_TOOL_NAME, tool_suggest_handler);
|
||||
}
|
||||
|
||||
if let Some(apply_patch_tool_type) = &config.apply_patch_tool_type {
|
||||
if let Some(apply_patch_tool_type) = &config.apply_patch_tool_type
|
||||
&& config.is_builtin_tool_invocation_enabled("apply_patch")
|
||||
{
|
||||
match apply_patch_tool_type {
|
||||
ApplyPatchToolType::Freeform => {
|
||||
push_tool_spec(
|
||||
push_builtin_tool_spec_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"apply_patch",
|
||||
create_apply_patch_freeform_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
ApplyPatchToolType::Function => {
|
||||
push_tool_spec(
|
||||
push_builtin_tool_spec_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"apply_patch",
|
||||
create_apply_patch_json_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2856,44 +3005,50 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
if config
|
||||
.experimental_supported_tools
|
||||
.contains(&"grep_files".to_string())
|
||||
&& config.is_builtin_tool_invocation_enabled("grep_files")
|
||||
{
|
||||
let grep_files_handler = Arc::new(GrepFilesHandler);
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"grep_files",
|
||||
create_grep_files_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
grep_files_handler,
|
||||
);
|
||||
builder.register_handler("grep_files", grep_files_handler);
|
||||
}
|
||||
|
||||
if config
|
||||
.experimental_supported_tools
|
||||
.contains(&"read_file".to_string())
|
||||
&& config.is_builtin_tool_invocation_enabled("read_file")
|
||||
{
|
||||
let read_file_handler = Arc::new(ReadFileHandler);
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"read_file",
|
||||
create_read_file_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
read_file_handler,
|
||||
);
|
||||
builder.register_handler("read_file", read_file_handler);
|
||||
}
|
||||
|
||||
if config
|
||||
.experimental_supported_tools
|
||||
.iter()
|
||||
.any(|tool| tool == "list_dir")
|
||||
&& config.is_builtin_tool_invocation_enabled("list_dir")
|
||||
{
|
||||
let list_dir_handler = Arc::new(ListDirHandler);
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"list_dir",
|
||||
create_list_dir_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
list_dir_handler,
|
||||
);
|
||||
builder.register_handler("list_dir", list_dir_handler);
|
||||
}
|
||||
|
||||
if config
|
||||
@@ -2916,7 +3071,9 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
Some(WebSearchMode::Disabled) | None => None,
|
||||
};
|
||||
|
||||
if let Some(external_web_access) = external_web_access {
|
||||
if let Some(external_web_access) = external_web_access
|
||||
&& config.is_builtin_tool_invocation_enabled("web_search")
|
||||
{
|
||||
let search_content_types = match config.web_search_tool_type {
|
||||
WebSearchToolType::Text => None,
|
||||
WebSearchToolType::TextAndImage => Some(
|
||||
@@ -2927,8 +3084,10 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
),
|
||||
};
|
||||
|
||||
push_tool_spec(
|
||||
push_builtin_tool_spec_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"web_search",
|
||||
ToolSpec::WebSearch {
|
||||
external_web_access: Some(external_web_access),
|
||||
filters: config
|
||||
@@ -2946,96 +3105,107 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
search_content_types,
|
||||
},
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
|
||||
if config.image_gen_tool {
|
||||
push_tool_spec(
|
||||
push_builtin_tool_spec_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"image_generation",
|
||||
ToolSpec::ImageGeneration {
|
||||
output_format: "png".to_string(),
|
||||
},
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"view_image",
|
||||
create_view_image_tool(config.can_request_original_image_detail),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
view_image_handler,
|
||||
);
|
||||
builder.register_handler("view_image", view_image_handler);
|
||||
|
||||
if config.artifact_tools {
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"artifacts",
|
||||
create_artifacts_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
artifacts_handler,
|
||||
);
|
||||
builder.register_handler("artifacts", artifacts_handler);
|
||||
}
|
||||
|
||||
if config.collab_tools {
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"spawn_agent",
|
||||
create_spawn_agent_tool(config),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
Arc::new(SpawnAgentHandler),
|
||||
);
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"send_input",
|
||||
create_send_input_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
Arc::new(SendInputHandler),
|
||||
);
|
||||
if !config.multi_agent_v2 {
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"resume_agent",
|
||||
create_resume_agent_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
Arc::new(ResumeAgentHandler),
|
||||
);
|
||||
builder.register_handler("resume_agent", Arc::new(ResumeAgentHandler));
|
||||
}
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"wait_agent",
|
||||
create_wait_agent_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
Arc::new(WaitAgentHandler),
|
||||
);
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"close_agent",
|
||||
create_close_agent_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
Arc::new(CloseAgentHandler),
|
||||
);
|
||||
builder.register_handler("spawn_agent", Arc::new(SpawnAgentHandler));
|
||||
builder.register_handler("send_input", Arc::new(SendInputHandler));
|
||||
builder.register_handler("wait_agent", Arc::new(WaitAgentHandler));
|
||||
builder.register_handler("close_agent", Arc::new(CloseAgentHandler));
|
||||
}
|
||||
|
||||
if config.agent_jobs_tools {
|
||||
let agent_jobs_handler = Arc::new(BatchJobHandler);
|
||||
push_tool_spec(
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"spawn_agents_on_csv",
|
||||
create_spawn_agents_on_csv_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
agent_jobs_handler.clone(),
|
||||
);
|
||||
builder.register_handler("spawn_agents_on_csv", agent_jobs_handler.clone());
|
||||
if config.agent_jobs_worker_tools {
|
||||
push_tool_spec(
|
||||
if config.agent_jobs_worker_tools
|
||||
&& config.is_builtin_tool_invocation_enabled("report_agent_job_result")
|
||||
{
|
||||
push_builtin_tool_with_handler_if_enabled(
|
||||
&mut builder,
|
||||
config,
|
||||
"report_agent_job_result",
|
||||
create_report_agent_job_result_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
agent_jobs_handler,
|
||||
);
|
||||
builder.register_handler("report_agent_job_result", agent_jobs_handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::client_common::tools::FreeformTool;
|
||||
use crate::config::ToolFeatureOverrides;
|
||||
use crate::config::test_config;
|
||||
use crate::models_manager::manager::ModelsManager;
|
||||
use crate::models_manager::model_info::with_config_overrides;
|
||||
@@ -515,12 +516,52 @@ fn test_build_specs_collab_tools_enabled() {
|
||||
sandbox_policy: &SandboxPolicy::DangerFullAccess,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
});
|
||||
let (tools, _) = build_specs(&tools_config, None, None, &[]).build();
|
||||
let (tools, registry) = build_specs(&tools_config, None, None, &[]).build();
|
||||
assert_contains_tool_names(
|
||||
&tools,
|
||||
&["spawn_agent", "send_input", "wait_agent", "close_agent"],
|
||||
);
|
||||
assert_lacks_tool_name(&tools, "spawn_agents_on_csv");
|
||||
assert!(registry.has_handler("spawn_agent", None));
|
||||
assert!(registry.has_handler("send_input", None));
|
||||
assert!(registry.has_handler("resume_agent", None));
|
||||
assert!(registry.has_handler("wait_agent", None));
|
||||
assert!(registry.has_handler("close_agent", None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_specs_multi_agent_handlers_omitted_when_capability_disabled() {
|
||||
let config = test_config();
|
||||
let model_info = ModelsManager::construct_model_info_offline_for_tests("gpt-5-codex", &config);
|
||||
let mut features = Features::with_defaults();
|
||||
features.enable(Feature::Collab);
|
||||
let available_models = Vec::new();
|
||||
let tools_config = ToolsConfig::new(&ToolsConfigParams {
|
||||
model_info: &model_info,
|
||||
available_models: &available_models,
|
||||
features: &features,
|
||||
web_search_mode: Some(WebSearchMode::Cached),
|
||||
session_source: SessionSource::Cli,
|
||||
sandbox_policy: &SandboxPolicy::DangerFullAccess,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
})
|
||||
.with_tool_feature_overrides(ToolFeatureOverrides {
|
||||
disable_defaults: true,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let (tools, registry) = build_specs(&tools_config, None, None, &[]).build();
|
||||
|
||||
for tool_name in [
|
||||
"spawn_agent",
|
||||
"send_input",
|
||||
"resume_agent",
|
||||
"wait_agent",
|
||||
"close_agent",
|
||||
] {
|
||||
assert_lacks_tool_name(&tools, tool_name);
|
||||
assert!(!registry.has_handler(tool_name, None));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1136,6 +1177,79 @@ fn web_search_mode_live_sets_external_web_access_true() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_search_mode_respects_disable_defaults() {
|
||||
let features = Features::with_defaults();
|
||||
let available_models = Vec::new();
|
||||
let tools_config = ToolsConfig::new(&ToolsConfigParams {
|
||||
model_info: &search_capable_model_info(),
|
||||
available_models: &available_models,
|
||||
features: &features,
|
||||
web_search_mode: Some(WebSearchMode::Live),
|
||||
session_source: SessionSource::Cli,
|
||||
sandbox_policy: &SandboxPolicy::DangerFullAccess,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
})
|
||||
.with_tool_feature_overrides(ToolFeatureOverrides {
|
||||
disable_defaults: true,
|
||||
shell: Some(true),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let (tools, _) = build_specs(&tools_config, None, None, &[]).build();
|
||||
|
||||
assert_lacks_tool_name(&tools, "web_search");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disable_defaults_ignores_legacy_view_image_override_without_filesystem_override() {
|
||||
let features = Features::with_defaults();
|
||||
let available_models = Vec::new();
|
||||
let tools_config = ToolsConfig::new(&ToolsConfigParams {
|
||||
model_info: &search_capable_model_info(),
|
||||
available_models: &available_models,
|
||||
features: &features,
|
||||
web_search_mode: Some(WebSearchMode::Disabled),
|
||||
session_source: SessionSource::Cli,
|
||||
sandbox_policy: &SandboxPolicy::DangerFullAccess,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
})
|
||||
.with_tool_feature_overrides(ToolFeatureOverrides {
|
||||
disable_defaults: true,
|
||||
..Default::default()
|
||||
})
|
||||
.with_legacy_view_image_override(Some(true));
|
||||
|
||||
let (tools, _) = build_specs(&tools_config, None, None, &[]).build();
|
||||
|
||||
assert_lacks_tool_name(&tools, "view_image");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_filesystem_override_enables_view_image_with_disable_defaults() {
|
||||
let features = Features::with_defaults();
|
||||
let available_models = Vec::new();
|
||||
let tools_config = ToolsConfig::new(&ToolsConfigParams {
|
||||
model_info: &search_capable_model_info(),
|
||||
available_models: &available_models,
|
||||
features: &features,
|
||||
web_search_mode: Some(WebSearchMode::Disabled),
|
||||
session_source: SessionSource::Cli,
|
||||
sandbox_policy: &SandboxPolicy::DangerFullAccess,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
})
|
||||
.with_tool_feature_overrides(ToolFeatureOverrides {
|
||||
disable_defaults: true,
|
||||
filesystem: Some(true),
|
||||
..Default::default()
|
||||
})
|
||||
.with_legacy_view_image_override(Some(true));
|
||||
|
||||
let (tools, _) = build_specs(&tools_config, None, None, &[]).build();
|
||||
|
||||
assert_contains_tool_names(&tools, &["view_image"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn web_search_config_is_forwarded_to_tool_spec() {
|
||||
let config = test_config();
|
||||
|
||||
Reference in New Issue
Block a user