refactor(xai): move code_execution into plugin

This commit is contained in:
huntharo
2026-03-28 17:11:55 -04:00
committed by Peter Steinberger
parent 1617e0218f
commit b7ab0ddb55
25 changed files with 271 additions and 291 deletions

View File

@@ -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",

View File

@@ -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}

View File

@@ -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).

View File

@@ -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,
},
},
},
},
},
}

View File

@@ -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 | |

View File

@@ -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<string, unknown>) {
@@ -16,11 +16,13 @@ function installCodeExecutionFetch(payload?: Record<string, unknown>) {
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;

View File

@@ -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<OpenClawConfig["tools"]> extends infer Tools
? Tools extends { code_execution?: infer CodeExecution }
? CodeExecution
: undefined
: undefined;
type XaiPluginConfig = NonNullable<
NonNullable<OpenClawConfig["plugins"]>["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<string, unknown> | 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<string, unknown>).xai;
if (!xaiEntry || typeof xaiEntry !== "object") {
return undefined;
}
const config = (xaiEntry as Record<string, unknown>).config;
if (!config || typeof config !== "object") {
return undefined;
}
const codeExecution = (config as Record<string, unknown>).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<string, unknown> | 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<string, unknown>) => {
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",
});
}

View File

@@ -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({

View File

@@ -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"
}
}
}
}
}

View File

@@ -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(

View File

@@ -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] : []),

View File

@@ -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",

View File

@@ -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,

View File

@@ -1,3 +1,2 @@
export { createCodeExecutionTool } from "./code-execution.js";
export { createWebFetchTool, extractReadableContent, fetchFirecrawlContent } from "./web-fetch.js";
export { createWebSearchTool } from "./web-search.js";

View File

@@ -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);
});

View File

@@ -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",

View File

@@ -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).",

View File

@@ -724,15 +724,6 @@ export const FIELD_HELP: Record<string, string> = {
"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":

View File

@@ -254,11 +254,6 @@ export const FIELD_LABELS: Record<string, string> = {
"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",

View File

@@ -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<string, ToolPolicyConfig>;
/** Remote xAI sandboxed code execution. */
code_execution?: CodeExecutionToolConfig;
web?: {
search?: {
/** Enable web search tool (default: true when API key is present). */

View File

@@ -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

View File

@@ -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"],
},
},
},

View File

@@ -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<string, unknown> | 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);
}

View File

@@ -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);
}

View File

@@ -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",