diff --git a/docs/.generated/config-baseline.json b/docs/.generated/config-baseline.json index d9697ae2874..cd1b0ebd86d 100644 --- a/docs/.generated/config-baseline.json +++ b/docs/.generated/config-baseline.json @@ -21600,7 +21600,10 @@ { "path": "channels.matrix.accessToken", "kind": "channel", - "type": "string", + "type": [ + "object", + "string" + ], "required": false, "deprecated": false, "sensitive": true, @@ -21611,6 +21614,36 @@ "network", "security" ], + "hasChildren": true + }, + { + "path": "channels.matrix.accessToken.id", + "kind": "channel", + "type": "string", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "channels.matrix.accessToken.provider", + "kind": "channel", + "type": "string", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, + { + "path": "channels.matrix.accessToken.source", + "kind": "channel", + "type": "string", + "required": true, + "deprecated": false, + "sensitive": false, + "tags": [], "hasChildren": false }, { @@ -23867,6 +23900,16 @@ "tags": [], "hasChildren": false }, + { + "path": "channels.msteams.blockStreaming", + "kind": "channel", + "type": "boolean", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, { "path": "channels.msteams.blockStreamingCoalesce", "kind": "channel", @@ -44771,6 +44814,26 @@ "tags": [], "hasChildren": false }, + { + "path": "models.providers.*.models.*.compat.unsupportedToolSchemaKeywords", + "kind": "core", + "type": "array", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": true + }, + { + "path": "models.providers.*.models.*.compat.unsupportedToolSchemaKeywords.*", + "kind": "core", + "type": "string", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [], + "hasChildren": false + }, { "path": "models.providers.*.models.*.contextWindow", "kind": "core", diff --git a/docs/.generated/config-baseline.jsonl b/docs/.generated/config-baseline.jsonl index 2f67fa407a2..df8cf9d8627 100644 --- a/docs/.generated/config-baseline.jsonl +++ b/docs/.generated/config-baseline.jsonl @@ -1,4 +1,4 @@ -{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5574} +{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5580} {"recordType":"path","path":"acp","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"ACP","help":"ACP runtime controls for enabling dispatch, selecting backends, constraining allowed agent targets, and tuning streamed turn projection behavior.","hasChildren":true} {"recordType":"path","path":"acp.allowedAgents","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"ACP Allowed Agents","help":"Allowlist of ACP target agent ids permitted for ACP runtime sessions. Empty means no additional allowlist restriction.","hasChildren":true} {"recordType":"path","path":"acp.allowedAgents.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} @@ -1921,7 +1921,10 @@ {"recordType":"path","path":"channels.line.tokenFile","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"channels.line.webhookPath","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"channels.matrix","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Matrix","help":"open protocol; install the plugin to enable.","hasChildren":true} -{"recordType":"path","path":"channels.matrix.accessToken","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":true,"tags":["access","auth","channels","network","security"],"hasChildren":false} +{"recordType":"path","path":"channels.matrix.accessToken","kind":"channel","type":["object","string"],"required":false,"deprecated":false,"sensitive":true,"tags":["access","auth","channels","network","security"],"hasChildren":true} +{"recordType":"path","path":"channels.matrix.accessToken.id","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} +{"recordType":"path","path":"channels.matrix.accessToken.provider","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} +{"recordType":"path","path":"channels.matrix.accessToken.source","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"channels.matrix.accounts","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true} {"recordType":"path","path":"channels.matrix.accounts.*","kind":"channel","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"channels.matrix.ackReaction","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} @@ -2127,6 +2130,7 @@ {"recordType":"path","path":"channels.msteams.appPassword.id","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"channels.msteams.appPassword.provider","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"channels.msteams.appPassword.source","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} +{"recordType":"path","path":"channels.msteams.blockStreaming","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"channels.msteams.blockStreamingCoalesce","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true} {"recordType":"path","path":"channels.msteams.blockStreamingCoalesce.idleMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"channels.msteams.blockStreamingCoalesce.maxChars","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} @@ -3950,6 +3954,8 @@ {"recordType":"path","path":"models.providers.*.models.*.compat.thinkingFormat","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"models.providers.*.models.*.compat.toolCallArgumentsEncoding","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"models.providers.*.models.*.compat.toolSchemaProfile","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} +{"recordType":"path","path":"models.providers.*.models.*.compat.unsupportedToolSchemaKeywords","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true} +{"recordType":"path","path":"models.providers.*.models.*.compat.unsupportedToolSchemaKeywords.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"models.providers.*.models.*.contextWindow","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} {"recordType":"path","path":"models.providers.*.models.*.cost","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true} {"recordType":"path","path":"models.providers.*.models.*.cost.cacheRead","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} diff --git a/docs/providers/xai.md b/docs/providers/xai.md index 6e98a24bd92..4765ce87611 100644 --- a/docs/providers/xai.md +++ b/docs/providers/xai.md @@ -32,6 +32,7 @@ OpenClaw now uses the xAI Responses API as the bundled xAI transport. The same and remote `code_execution`. If you store an xAI key under `plugins.entries.xai.config.webSearch.apiKey`, the bundled xAI model provider now reuses that key as a fallback too. +`code_execution` tuning lives under `plugins.entries.xai.config.codeExecution`. ## Current bundled model catalog @@ -63,5 +64,6 @@ openclaw config set tools.web.search.provider grok - OpenClaw applies xAI-specific tool-schema and tool-call compatibility fixes automatically on the shared runner path. - `web_search`, `x_search`, and `code_execution` are exposed as OpenClaw tools. OpenClaw enables the specific xAI built-in it needs inside each tool request instead of attaching all native tools to every chat turn. +- `x_search` and `code_execution` are owned by the bundled xAI plugin rather than hardcoded into the core model runtime. - `code_execution` is remote xAI sandbox execution, not local [`exec`](/tools/exec). - For the broader provider overview, see [Model providers](/providers/index). diff --git a/docs/tools/code-execution.md b/docs/tools/code-execution.md index c47eee153b7..1e64319dee0 100644 --- a/docs/tools/code-execution.md +++ b/docs/tools/code-execution.md @@ -30,7 +30,6 @@ devices. Use [`exec`](/tools/exec) for that. You need an xAI API key. Any of these work: -- `tools.code_execution.apiKey` - `XAI_API_KEY` - `plugins.entries.xai.config.webSearch.apiKey` @@ -38,13 +37,21 @@ Example: ```json5 { - tools: { - code_execution: { - enabled: true, - apiKey: "xai-...", - model: "grok-4-1-fast", - maxTurns: 2, - timeoutSeconds: 30, + plugins: { + entries: { + xai: { + config: { + webSearch: { + apiKey: "xai-...", + }, + codeExecution: { + enabled: true, + model: "grok-4-1-fast", + maxTurns: 2, + timeoutSeconds: 30, + }, + }, + }, }, }, } diff --git a/docs/tools/index.md b/docs/tools/index.md index bb3dc325b9e..36608591fe6 100644 --- a/docs/tools/index.md +++ b/docs/tools/index.md @@ -55,7 +55,7 @@ These tools ship with OpenClaw and are available without installing any plugins: | Tool | What it does | Page | | --------------------------------------- | -------------------------------------------------------- | --------------------------------------- | | `exec` / `process` | Run shell commands, manage background processes | [Exec](/tools/exec) | -| `code_execution` | Run sandboxed remote Python analysis with xAI | [Code Execution](/tools/code-execution) | +| `code_execution` | Run sandboxed remote Python analysis | [Code Execution](/tools/code-execution) | | `browser` | Control a Chromium browser (navigate, click, screenshot) | [Browser](/tools/browser) | | `web_search` / `x_search` / `web_fetch` | Search the web, search X posts, fetch page content | [Web](/tools/web) | | `read` / `write` / `edit` | File I/O in the workspace | | diff --git a/src/agents/tools/code-execution.test.ts b/extensions/xai/code-execution.test.ts similarity index 77% rename from src/agents/tools/code-execution.test.ts rename to extensions/xai/code-execution.test.ts index f54c72794ce..d26f7542ad7 100644 --- a/src/agents/tools/code-execution.test.ts +++ b/extensions/xai/code-execution.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { withFetchPreconnect } from "../../test-utils/fetch-mock.js"; +import { withFetchPreconnect } from "../../test/helpers/extensions/fetch-mock.js"; import { createCodeExecutionTool } from "./code-execution.js"; function installCodeExecutionFetch(payload?: Record) { @@ -16,11 +16,13 @@ function installCodeExecutionFetch(payload?: Record) { content: [ { type: "output_text", - text: "The moving average is 42.", + text: "Mean: 42", + annotations: [{ type: "url_citation", url: "https://example.com/data.csv" }], }, ], }, ], + citations: ["https://example.com/data.csv"], }, ), } as Response), @@ -42,7 +44,7 @@ afterEach(() => { vi.restoreAllMocks(); }); -describe("code_execution tool", () => { +describe("xai code_execution tool", () => { it("enables code_execution when the xAI plugin web search key is configured", () => { const tool = createCodeExecutionTool({ config: { @@ -67,18 +69,27 @@ describe("code_execution tool", () => { const mockFetch = installCodeExecutionFetch(); const tool = createCodeExecutionTool({ config: { - tools: { - code_execution: { - apiKey: "xai-config-test", // pragma: allowlist secret - model: "grok-4-1-fast", - maxTurns: 2, + plugins: { + entries: { + xai: { + config: { + webSearch: { + apiKey: "xai-config-test", // pragma: allowlist secret + }, + codeExecution: { + model: "grok-4-1-fast", + maxTurns: 2, + timeoutSeconds: 45, + }, + }, + }, }, }, }, }); - const result = await tool?.execute?.("code-exec:1", { - task: "Calculate the average of 40, 42, and 44.", + const result = await tool?.execute?.("code-execution:1", { + task: "Calculate the mean of [40, 42, 44]", }); expect(mockFetch).toHaveBeenCalled(); @@ -110,8 +121,8 @@ describe("code_execution tool", () => { }, }); - await tool?.execute?.("code-exec:plugin-key", { - task: "Sum 1 + 2 + 3.", + await tool?.execute?.("code-execution:plugin-key", { + task: "Compute the standard deviation of [1, 2, 3]", }); const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined; @@ -136,8 +147,8 @@ describe("code_execution tool", () => { }, }); - await tool?.execute?.("code-exec:legacy-key", { - task: "Multiply 6 * 7.", + await tool?.execute?.("code-execution:legacy-key", { + task: "Count rows in a two-column table", }); const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined; diff --git a/src/agents/tools/code-execution.ts b/extensions/xai/code-execution.ts similarity index 51% rename from src/agents/tools/code-execution.ts rename to extensions/xai/code-execution.ts index a41c4886cce..e5d51972f4e 100644 --- a/src/agents/tools/code-execution.ts +++ b/extensions/xai/code-execution.ts @@ -1,21 +1,33 @@ import { Type } from "@sinclair/typebox"; +import { getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/config-runtime"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/plugin-entry"; +import { + jsonResult, + readConfiguredSecretString, + readProviderEnvValue, + readStringParam, + resolveProviderWebSearchPluginConfig, +} from "openclaw/plugin-sdk/provider-web-search"; import { buildXaiCodeExecutionPayload, requestXaiCodeExecution, resolveXaiCodeExecutionMaxTurns, resolveXaiCodeExecutionModel, -} from "../../../extensions/xai/src/code-execution-shared.js"; -import type { OpenClawConfig } from "../../config/config.js"; -import { resolveProviderWebSearchPluginConfig } from "../../plugin-sdk/provider-web-search.js"; -import { jsonResult, readStringParam } from "./common.js"; -import { readConfiguredSecretString, readProviderEnvValue } from "./web-search-provider-common.js"; +} from "./src/code-execution-shared.js"; -type CodeExecutionConfig = - NonNullable extends infer Tools - ? Tools extends { code_execution?: infer CodeExecution } - ? CodeExecution - : undefined - : undefined; +type XaiPluginConfig = NonNullable< + NonNullable["entries"] +>["xai"] extends { + config?: infer Config; +} + ? Config + : undefined; + +type CodeExecutionConfig = XaiPluginConfig extends infer Config + ? Config extends { codeExecution?: infer CodeExecution } + ? CodeExecution + : undefined + : undefined; function readLegacyGrokApiKey(cfg?: OpenClawConfig): string | undefined { const search = cfg?.tools?.web?.search; @@ -29,57 +41,66 @@ function readLegacyGrokApiKey(cfg?: OpenClawConfig): string | undefined { ); } -function readPluginXaiWebSearchApiKey(cfg?: OpenClawConfig): string | undefined { - return readConfiguredSecretString( - resolveProviderWebSearchPluginConfig(cfg as Record | undefined, "xai")?.apiKey, - "plugins.entries.xai.config.webSearch.apiKey", - ); -} - -function resolveFallbackXaiApiKey(cfg?: OpenClawConfig): string | undefined { - return readPluginXaiWebSearchApiKey(cfg) ?? readLegacyGrokApiKey(cfg); -} - -function resolveCodeExecutionConfig(cfg?: OpenClawConfig): CodeExecutionConfig | undefined { - const codeExecution = cfg?.tools?.code_execution; +function readPluginCodeExecutionConfig(cfg?: OpenClawConfig): CodeExecutionConfig | undefined { + const entries = cfg?.plugins?.entries; + if (!entries || typeof entries !== "object") { + return undefined; + } + const xaiEntry = (entries as Record).xai; + if (!xaiEntry || typeof xaiEntry !== "object") { + return undefined; + } + const config = (xaiEntry as Record).config; + if (!config || typeof config !== "object") { + return undefined; + } + const codeExecution = (config as Record).codeExecution; if (!codeExecution || typeof codeExecution !== "object") { return undefined; } - return codeExecution; + return codeExecution as CodeExecutionConfig; +} + +function resolveFallbackXaiApiKey(cfg?: OpenClawConfig): string | undefined { + return ( + readConfiguredSecretString( + resolveProviderWebSearchPluginConfig(cfg as Record | undefined, "xai") + ?.apiKey, + "plugins.entries.xai.config.webSearch.apiKey", + ) ?? readLegacyGrokApiKey(cfg) + ); } function resolveCodeExecutionEnabled(params: { - cfg?: OpenClawConfig; + sourceConfig?: OpenClawConfig; + runtimeConfig?: OpenClawConfig; config?: CodeExecutionConfig; }): boolean { if (params.config?.enabled === false) { return false; } - const configuredApiKey = readConfiguredSecretString( - params.config?.apiKey, - "tools.code_execution.apiKey", - ); return Boolean( - configuredApiKey || - resolveFallbackXaiApiKey(params.cfg) || + resolveFallbackXaiApiKey(params.runtimeConfig) ?? + resolveFallbackXaiApiKey(params.sourceConfig) ?? readProviderEnvValue(["XAI_API_KEY"]), ); } -function resolveCodeExecutionApiKey( - config?: CodeExecutionConfig, - cfg?: OpenClawConfig, -): string | undefined { - return ( - readConfiguredSecretString(config?.apiKey, "tools.code_execution.apiKey") ?? - resolveFallbackXaiApiKey(cfg) ?? - readProviderEnvValue(["XAI_API_KEY"]) - ); -} - -export function createCodeExecutionTool(options?: { config?: OpenClawConfig }) { - const codeExecutionConfig = resolveCodeExecutionConfig(options?.config); - if (!resolveCodeExecutionEnabled({ cfg: options?.config, config: codeExecutionConfig })) { +export function createCodeExecutionTool(options?: { + config?: OpenClawConfig; + runtimeConfig?: OpenClawConfig | null; +}) { + const runtimeConfig = options?.runtimeConfig ?? getRuntimeConfigSnapshot(); + const codeExecutionConfig = + readPluginCodeExecutionConfig(runtimeConfig ?? undefined) ?? + readPluginCodeExecutionConfig(options?.config); + if ( + !resolveCodeExecutionEnabled({ + sourceConfig: options?.config, + runtimeConfig: runtimeConfig ?? undefined, + config: codeExecutionConfig, + }) + ) { return null; } @@ -95,12 +116,15 @@ export function createCodeExecutionTool(options?: { config?: OpenClawConfig }) { }), }), execute: async (_toolCallId: string, args: Record) => { - const apiKey = resolveCodeExecutionApiKey(codeExecutionConfig, options?.config); + const apiKey = + resolveFallbackXaiApiKey(runtimeConfig ?? undefined) ?? + resolveFallbackXaiApiKey(options?.config) ?? + readProviderEnvValue(["XAI_API_KEY"]); if (!apiKey) { return jsonResult({ error: "missing_xai_api_key", message: - "code_execution needs an xAI API key. Set XAI_API_KEY in the Gateway environment, or configure tools.code_execution.apiKey or plugins.entries.xai.config.webSearch.apiKey.", + "code_execution needs an xAI API key. Set XAI_API_KEY in the Gateway environment, or configure plugins.entries.xai.config.webSearch.apiKey.", docs: "https://docs.openclaw.ai/tools/code-execution", }); } diff --git a/extensions/xai/index.ts b/extensions/xai/index.ts index 1b61e19430f..5253a57b5fd 100644 --- a/extensions/xai/index.ts +++ b/extensions/xai/index.ts @@ -7,6 +7,7 @@ import { createToolStreamWrapper } from "openclaw/plugin-sdk/provider-stream"; import { resolveProviderWebSearchPluginConfig } from "openclaw/plugin-sdk/provider-web-search"; import { normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input"; import { applyXaiModelCompat, normalizeXaiModelId } from "./api.js"; +import { createCodeExecutionTool } from "./code-execution.js"; import { applyXaiConfig, XAI_DEFAULT_MODEL_REF } from "./onboard.js"; import { buildXaiProvider } from "./provider-catalog.js"; import { isModernXaiModel, resolveXaiForwardCompatModel } from "./provider-models.js"; @@ -137,6 +138,14 @@ export default defineSingleProviderPluginEntry({ }, register(api) { api.registerWebSearchProvider(createXaiWebSearchProvider()); + api.registerTool( + (ctx) => + createCodeExecutionTool({ + config: ctx.config, + runtimeConfig: ctx.runtimeConfig, + }), + { name: "code_execution" }, + ); api.registerTool( (ctx) => createXSearchTool({ diff --git a/extensions/xai/openclaw.plugin.json b/extensions/xai/openclaw.plugin.json index efc7c1ed029..d933a06228c 100644 --- a/extensions/xai/openclaw.plugin.json +++ b/extensions/xai/openclaw.plugin.json @@ -33,11 +33,27 @@ "webSearch.inlineCitations": { "label": "Inline Citations", "help": "Include inline markdown citations in Grok responses." + }, + "codeExecution.enabled": { + "label": "Enable Code Execution", + "help": "Enable the code_execution tool for remote xAI sandbox analysis." + }, + "codeExecution.model": { + "label": "Code Execution Model", + "help": "xAI model override for code_execution." + }, + "codeExecution.maxTurns": { + "label": "Code Execution Max Turns", + "help": "Optional max internal tool turns xAI may use for code_execution." + }, + "codeExecution.timeoutSeconds": { + "label": "Code Execution Timeout", + "help": "Timeout in seconds for code_execution requests." } }, "contracts": { "webSearchProviders": ["grok"], - "tools": ["x_search"] + "tools": ["code_execution", "x_search"] }, "configSchema": { "type": "object", @@ -57,6 +73,24 @@ "type": "boolean" } } + }, + "codeExecution": { + "type": "object", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + }, + "model": { + "type": "string" + }, + "maxTurns": { + "type": "number" + }, + "timeoutSeconds": { + "type": "number" + } + } } } } diff --git a/extensions/xai/x-search.ts b/extensions/xai/x-search.ts index 6dc54b1cdb4..db0c902da5f 100644 --- a/extensions/xai/x-search.ts +++ b/extensions/xai/x-search.ts @@ -199,7 +199,7 @@ export function createXSearchTool(options?: { label: "X Search", name: "x_search", description: - "Search X (formerly Twitter) using xAI. Returns AI-synthesized answers with citations from real-time X post search.", + "Search X (formerly Twitter) using xAI, including targeted post or thread lookups. For per-post stats like reposts, replies, bookmarks, or views, prefer the exact post URL or status ID.", parameters: Type.Object({ query: Type.String({ description: "X search query string." }), allowed_x_handles: Type.Optional( diff --git a/src/agents/openclaw-tools.ts b/src/agents/openclaw-tools.ts index dc591ec1927..c2570a1c7cb 100644 --- a/src/agents/openclaw-tools.ts +++ b/src/agents/openclaw-tools.ts @@ -30,11 +30,7 @@ import { createSessionsSpawnTool } from "./tools/sessions-spawn-tool.js"; import { createSessionsYieldTool } from "./tools/sessions-yield-tool.js"; import { createSubagentsTool } from "./tools/subagents-tool.js"; import { createTtsTool } from "./tools/tts-tool.js"; -import { - createCodeExecutionTool, - createWebFetchTool, - createWebSearchTool, -} from "./tools/web-tools.js"; +import { createWebFetchTool, createWebSearchTool } from "./tools/web-tools.js"; import { resolveWorkspaceRoot } from "./workspace-dir.js"; type OpenClawToolsDeps = { @@ -163,9 +159,6 @@ export function createOpenClawTools( sandboxed: options?.sandboxed, runtimeWebSearch: runtimeWebTools?.search, }); - const codeExecutionTool = createCodeExecutionTool({ - config: options?.config, - }); const webFetchTool = createWebFetchTool({ config: options?.config, sandboxed: options?.sandboxed, @@ -262,7 +255,6 @@ export function createOpenClawTools( sandboxed: options?.sandboxed, }), ...(webSearchTool ? [webSearchTool] : []), - ...(codeExecutionTool ? [codeExecutionTool] : []), ...(webFetchTool ? [webFetchTool] : []), ...(imageTool ? [imageTool] : []), ...(pdfTool ? [pdfTool] : []), diff --git a/src/agents/system-prompt.ts b/src/agents/system-prompt.ts index b6f87c4fdda..d5f2893ee25 100644 --- a/src/agents/system-prompt.ts +++ b/src/agents/system-prompt.ts @@ -233,11 +233,7 @@ export function buildAgentSystemPrompt(params: { ls: "List directory contents", exec: "Run shell commands (pty available for TTY-required CLIs)", process: "Manage background exec sessions", - code_execution: - "Run sandboxed remote Python analysis with xAI (no local shell or filesystem access)", web_search: "Search the web", - x_search: - "Search X (formerly Twitter) posts with xAI, including targeted post or thread lookups; for per-post stats use the exact post URL or status ID when possible", web_fetch: "Fetch and extract readable content from a URL", // Channel docking: add login tools here when a channel needs interactive linking. browser: "Control web browser", diff --git a/src/agents/tool-catalog.ts b/src/agents/tool-catalog.ts index 6587cf8e25b..42ebb18da99 100644 --- a/src/agents/tool-catalog.ts +++ b/src/agents/tool-catalog.ts @@ -84,7 +84,7 @@ const CORE_TOOL_DEFINITIONS: CoreToolDefinition[] = [ { id: "code_execution", label: "code_execution", - description: "Run sandboxed remote analysis with xAI", + description: "Run sandboxed remote analysis", sectionId: "runtime", profiles: ["coding"], includeInOpenClawGroup: true, diff --git a/src/agents/tools/web-tools.ts b/src/agents/tools/web-tools.ts index 742313132fe..3acaa4c763f 100644 --- a/src/agents/tools/web-tools.ts +++ b/src/agents/tools/web-tools.ts @@ -1,3 +1,2 @@ -export { createCodeExecutionTool } from "./code-execution.js"; export { createWebFetchTool, extractReadableContent, fetchFirecrawlContent } from "./web-fetch.js"; export { createWebSearchTool } from "./web-search.js"; diff --git a/src/cli/command-secret-targets.test.ts b/src/cli/command-secret-targets.test.ts index 1d6a0c79189..0baa8c10870 100644 --- a/src/cli/command-secret-targets.test.ts +++ b/src/cli/command-secret-targets.test.ts @@ -10,7 +10,6 @@ describe("command secret target ids", () => { const ids = getAgentRuntimeCommandSecretTargetIds(); expect(ids.has("agents.defaults.memorySearch.remote.apiKey")).toBe(true); expect(ids.has("agents.list[].memorySearch.remote.apiKey")).toBe(true); - expect(ids.has("tools.code_execution.apiKey")).toBe(true); expect(ids.has("tools.web.fetch.firecrawl.apiKey")).toBe(true); expect(ids.has("tools.web.x_search.apiKey")).toBe(true); }); diff --git a/src/cli/command-secret-targets.ts b/src/cli/command-secret-targets.ts index 34fd11d1cce..0f1ca32ec06 100644 --- a/src/cli/command-secret-targets.ts +++ b/src/cli/command-secret-targets.ts @@ -23,7 +23,6 @@ const COMMAND_SECRET_TARGETS = { "agents.list[].memorySearch.remote.", "skills.entries.", "messages.tts.", - "tools.code_execution", "tools.web.search", "tools.web.fetch.firecrawl.", "tools.web.x_search", diff --git a/src/config/schema.base.generated.ts b/src/config/schema.base.generated.ts index 606c3dd0c6e..8e454431031 100644 --- a/src/config/schema.base.generated.ts +++ b/src/config/schema.base.generated.ts @@ -7164,94 +7164,6 @@ export const GENERATED_BASE_CONFIG_SCHEMA = { }, additionalProperties: false, }, - code_execution: { - type: "object", - properties: { - enabled: { - type: "boolean", - }, - apiKey: { - anyOf: [ - { - type: "string", - }, - { - oneOf: [ - { - type: "object", - properties: { - source: { - type: "string", - const: "env", - }, - provider: { - type: "string", - pattern: "^[a-z][a-z0-9_-]{0,63}$", - }, - id: { - type: "string", - pattern: "^[A-Z][A-Z0-9_]{0,127}$", - }, - }, - required: ["source", "provider", "id"], - additionalProperties: false, - }, - { - type: "object", - properties: { - source: { - type: "string", - const: "file", - }, - provider: { - type: "string", - pattern: "^[a-z][a-z0-9_-]{0,63}$", - }, - id: { - type: "string", - }, - }, - required: ["source", "provider", "id"], - additionalProperties: false, - }, - { - type: "object", - properties: { - source: { - type: "string", - const: "exec", - }, - provider: { - type: "string", - pattern: "^[a-z][a-z0-9_-]{0,63}$", - }, - id: { - type: "string", - }, - }, - required: ["source", "provider", "id"], - additionalProperties: false, - }, - ], - }, - ], - }, - model: { - type: "string", - }, - maxTurns: { - type: "integer", - minimum: -9007199254740991, - maximum: 9007199254740991, - }, - timeoutSeconds: { - type: "integer", - exclusiveMinimum: 0, - maximum: 9007199254740991, - }, - }, - additionalProperties: false, - }, exec: { type: "object", properties: { @@ -13063,32 +12975,6 @@ export const GENERATED_BASE_CONFIG_SCHEMA = { help: "Cache TTL in minutes for x_search results.", tags: ["performance", "storage", "tools"], }, - "tools.code_execution.enabled": { - label: "Enable Code Execution Tool", - help: "Enable the code_execution tool (requires XAI_API_KEY or tools.code_execution.apiKey).", - tags: ["tools"], - }, - "tools.code_execution.apiKey": { - label: "xAI API Key", - help: "xAI API key for remote code execution (fallback: XAI_API_KEY env var).", - tags: ["security", "auth", "tools"], - sensitive: true, - }, - "tools.code_execution.model": { - label: "Code Execution Model", - help: 'Model to use for remote code execution (default: "grok-4-1-fast").', - tags: ["models", "tools"], - }, - "tools.code_execution.maxTurns": { - label: "Code Execution Max Turns", - help: "Optional max internal tool turns xAI may use per code_execution request. Omit to let xAI choose.", - tags: ["performance", "tools"], - }, - "tools.code_execution.timeoutSeconds": { - label: "Code Execution Timeout (sec)", - help: "Timeout in seconds for code_execution requests.", - tags: ["performance", "tools"], - }, "gateway.controlUi.basePath": { label: "Control UI Base Path", help: "Optional URL prefix where the Control UI is served (e.g. /openclaw).", diff --git a/src/config/schema.help.ts b/src/config/schema.help.ts index 72ebdc065ca..1363900c595 100644 --- a/src/config/schema.help.ts +++ b/src/config/schema.help.ts @@ -724,15 +724,6 @@ export const FIELD_HELP: Record = { "Optional max internal search/tool turns xAI may use per x_search request. Omit to let xAI choose.", "tools.web.x_search.timeoutSeconds": "Timeout in seconds for x_search requests.", "tools.web.x_search.cacheTtlMinutes": "Cache TTL in minutes for x_search results.", - "tools.code_execution.enabled": - "Enable the code_execution tool (requires XAI_API_KEY or tools.code_execution.apiKey).", - "tools.code_execution.apiKey": - "xAI API key for remote code execution (fallback: XAI_API_KEY env var).", - "tools.code_execution.model": - 'Model to use for remote code execution (default: "grok-4-1-fast").', - "tools.code_execution.maxTurns": - "Optional max internal tool turns xAI may use per code_execution request. Omit to let xAI choose.", - "tools.code_execution.timeoutSeconds": "Timeout in seconds for code_execution requests.", models: "Model catalog root for provider definitions, merge/replace behavior, and optional Bedrock discovery integration. Keep provider definitions explicit and validated before relying on production failover paths.", "models.mode": diff --git a/src/config/schema.labels.ts b/src/config/schema.labels.ts index 74840e7e948..6fd71eb8df7 100644 --- a/src/config/schema.labels.ts +++ b/src/config/schema.labels.ts @@ -254,11 +254,6 @@ export const FIELD_LABELS: Record = { "tools.web.x_search.maxTurns": "X Search Max Turns", "tools.web.x_search.timeoutSeconds": "X Search Timeout (sec)", "tools.web.x_search.cacheTtlMinutes": "X Search Cache TTL (min)", - "tools.code_execution.enabled": "Enable Code Execution Tool", - "tools.code_execution.apiKey": "xAI API Key", // pragma: allowlist secret - "tools.code_execution.model": "Code Execution Model", - "tools.code_execution.maxTurns": "Code Execution Max Turns", - "tools.code_execution.timeoutSeconds": "Code Execution Timeout (sec)", "gateway.controlUi.basePath": "Control UI Base Path", "gateway.controlUi.root": "Control UI Assets Root", "gateway.controlUi.allowedOrigins": "Control UI Allowed Origins", diff --git a/src/config/types.tools.ts b/src/config/types.tools.ts index a12ba791d54..3325ebd59af 100644 --- a/src/config/types.tools.ts +++ b/src/config/types.tools.ts @@ -476,19 +476,6 @@ type XSearchToolConfig = { cacheTtlMinutes?: number; }; -type CodeExecutionToolConfig = { - /** Enable remote xAI code execution (default: true when an xAI API key is available). */ - enabled?: boolean; - /** API key for xAI (defaults to XAI_API_KEY env var). Supports SecretRef. */ - apiKey?: SecretInput; - /** Model id to use for remote code execution. */ - model?: string; - /** Optional max internal tool turns for xAI to use. */ - maxTurns?: number; - /** Timeout in seconds for code execution requests. */ - timeoutSeconds?: number; -}; - export type ToolsConfig = { /** Base tool profile applied before allow/deny lists. */ profile?: ToolProfileId; @@ -498,8 +485,6 @@ export type ToolsConfig = { deny?: string[]; /** Optional tool policy overrides keyed by provider id or "provider/model". */ byProvider?: Record; - /** Remote xAI sandboxed code execution. */ - code_execution?: CodeExecutionToolConfig; web?: { search?: { /** Enable web search tool (default: true when API key is present). */ diff --git a/src/config/zod-schema.agent-runtime.ts b/src/config/zod-schema.agent-runtime.ts index 088d443e49c..fa231127705 100644 --- a/src/config/zod-schema.agent-runtime.ts +++ b/src/config/zod-schema.agent-runtime.ts @@ -361,17 +361,6 @@ export const ToolsWebXSearchSchema = z .strict() .optional(); -export const ToolCodeExecutionSchema = z - .object({ - enabled: z.boolean().optional(), - apiKey: SecretInputSchema.optional().register(sensitive), - model: z.string().optional(), - maxTurns: z.number().int().optional(), - timeoutSeconds: z.number().int().positive().optional(), - }) - .strict() - .optional(); - export const ToolsWebSchema = z .object({ search: ToolsWebSearchSchema, @@ -865,7 +854,6 @@ export const ToolsSchema = z }) .strict() .optional(), - code_execution: ToolCodeExecutionSchema, exec: ToolExecSchema, fs: ToolFsSchema, subagents: z diff --git a/src/plugins/bundled-plugin-metadata.generated.ts b/src/plugins/bundled-plugin-metadata.generated.ts index b0cfea4896b..20431ff43a4 100644 --- a/src/plugins/bundled-plugin-metadata.generated.ts +++ b/src/plugins/bundled-plugin-metadata.generated.ts @@ -18525,6 +18525,7 @@ export const GENERATED_BUNDLED_PLUGIN_METADATA = [ }, publicSurfaceArtifacts: [ "api.js", + "code-execution.js", "model-definitions.js", "model-id.js", "onboard.js", @@ -18532,6 +18533,7 @@ export const GENERATED_BUNDLED_PLUGIN_METADATA = [ "provider-models.js", "stream.js", "web-search.js", + "x-search.js", ], packageName: "@openclaw/xai-plugin", packageVersion: "2026.3.27", @@ -18560,6 +18562,24 @@ export const GENERATED_BUNDLED_PLUGIN_METADATA = [ }, }, }, + codeExecution: { + type: "object", + additionalProperties: false, + properties: { + enabled: { + type: "boolean", + }, + model: { + type: "string", + }, + maxTurns: { + type: "number", + }, + timeoutSeconds: { + type: "number", + }, + }, + }, }, }, enabledByDefault: true, @@ -18596,10 +18616,26 @@ export const GENERATED_BUNDLED_PLUGIN_METADATA = [ label: "Inline Citations", help: "Include inline markdown citations in Grok responses.", }, + "codeExecution.enabled": { + label: "Enable Code Execution", + help: "Enable the code_execution tool for remote xAI sandbox analysis.", + }, + "codeExecution.model": { + label: "Code Execution Model", + help: "xAI model override for code_execution.", + }, + "codeExecution.maxTurns": { + label: "Code Execution Max Turns", + help: "Optional max internal tool turns xAI may use for code_execution.", + }, + "codeExecution.timeoutSeconds": { + label: "Code Execution Timeout", + help: "Timeout in seconds for code_execution requests.", + }, }, contracts: { webSearchProviders: ["grok"], - tools: ["x_search"], + tools: ["code_execution", "x_search"], }, }, }, diff --git a/src/secrets/runtime-config-collectors-core.ts b/src/secrets/runtime-config-collectors-core.ts index 9df7138130f..ef571b3f54f 100644 --- a/src/secrets/runtime-config-collectors-core.ts +++ b/src/secrets/runtime-config-collectors-core.ts @@ -292,33 +292,6 @@ function collectMessagesTtsAssignments(params: { }); } -function collectCodeExecutionAssignments(params: { - config: OpenClawConfig; - defaults: SecretDefaults | undefined; - context: ResolverContext; -}): void { - const tools = params.config.tools as Record | undefined; - if (!isRecord(tools)) { - return; - } - const codeExecution = isRecord(tools.code_execution) ? tools.code_execution : undefined; - if (!codeExecution) { - return; - } - collectSecretInputAssignment({ - value: codeExecution.apiKey, - path: "tools.code_execution.apiKey", - expected: "string", - defaults: params.defaults, - context: params.context, - active: codeExecution.enabled !== false, - inactiveReason: "tools.code_execution is disabled.", - apply: (value) => { - codeExecution.apiKey = value; - }, - }); -} - function collectCronAssignments(params: { config: OpenClawConfig; defaults: SecretDefaults | undefined; @@ -452,6 +425,5 @@ export function collectCoreConfigAssignments(params: { collectGatewayAssignments(params); collectSandboxSshAssignments(params); collectMessagesTtsAssignments(params); - collectCodeExecutionAssignments(params); collectCronAssignments(params); } diff --git a/src/secrets/runtime.coverage.test.ts b/src/secrets/runtime.coverage.test.ts index 4f4e9f2b83f..3cbca0410c0 100644 --- a/src/secrets/runtime.coverage.test.ts +++ b/src/secrets/runtime.coverage.test.ts @@ -208,9 +208,6 @@ function buildConfigForOpenClawTarget(entry: SecretRegistryEntry, envId: string) if (entry.id === "plugins.entries.tavily.config.webSearch.apiKey") { setPathCreateStrict(config, ["tools", "web", "search", "provider"], "tavily"); } - if (entry.id === "tools.code_execution.apiKey") { - setPathCreateStrict(config, ["tools", "code_execution", "enabled"], true); - } if (entry.id === "tools.web.x_search.apiKey") { setPathCreateStrict(config, ["tools", "web", "x_search", "enabled"], true); } diff --git a/src/secrets/target-registry-data.ts b/src/secrets/target-registry-data.ts index 711ab4dc67d..1a931c10ef5 100644 --- a/src/secrets/target-registry-data.ts +++ b/src/secrets/target-registry-data.ts @@ -703,17 +703,6 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [ includeInConfigure: true, includeInAudit: true, }, - { - id: "tools.code_execution.apiKey", - targetType: "tools.code_execution.apiKey", - configFile: "openclaw.json", - pathPattern: "tools.code_execution.apiKey", - secretShape: SECRET_INPUT_SHAPE, - expectedResolvedValue: "string", - includeInPlan: true, - includeInConfigure: true, - includeInAudit: true, - }, { id: "tools.web.fetch.firecrawl.apiKey", targetType: "tools.web.fetch.firecrawl.apiKey",