Skip to content

Commit b7ab0dd

Browse files
huntharosteipete
authored andcommitted
refactor(xai): move code_execution into plugin
1 parent 1617e02 commit b7ab0dd

25 files changed

Lines changed: 271 additions & 291 deletions

docs/.generated/config-baseline.json

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21600,7 +21600,10 @@
2160021600
{
2160121601
"path": "channels.matrix.accessToken",
2160221602
"kind": "channel",
21603-
"type": "string",
21603+
"type": [
21604+
"object",
21605+
"string"
21606+
],
2160421607
"required": false,
2160521608
"deprecated": false,
2160621609
"sensitive": true,
@@ -21611,6 +21614,36 @@
2161121614
"network",
2161221615
"security"
2161321616
],
21617+
"hasChildren": true
21618+
},
21619+
{
21620+
"path": "channels.matrix.accessToken.id",
21621+
"kind": "channel",
21622+
"type": "string",
21623+
"required": true,
21624+
"deprecated": false,
21625+
"sensitive": false,
21626+
"tags": [],
21627+
"hasChildren": false
21628+
},
21629+
{
21630+
"path": "channels.matrix.accessToken.provider",
21631+
"kind": "channel",
21632+
"type": "string",
21633+
"required": true,
21634+
"deprecated": false,
21635+
"sensitive": false,
21636+
"tags": [],
21637+
"hasChildren": false
21638+
},
21639+
{
21640+
"path": "channels.matrix.accessToken.source",
21641+
"kind": "channel",
21642+
"type": "string",
21643+
"required": true,
21644+
"deprecated": false,
21645+
"sensitive": false,
21646+
"tags": [],
2161421647
"hasChildren": false
2161521648
},
2161621649
{
@@ -23867,6 +23900,16 @@
2386723900
"tags": [],
2386823901
"hasChildren": false
2386923902
},
23903+
{
23904+
"path": "channels.msteams.blockStreaming",
23905+
"kind": "channel",
23906+
"type": "boolean",
23907+
"required": false,
23908+
"deprecated": false,
23909+
"sensitive": false,
23910+
"tags": [],
23911+
"hasChildren": false
23912+
},
2387023913
{
2387123914
"path": "channels.msteams.blockStreamingCoalesce",
2387223915
"kind": "channel",
@@ -44771,6 +44814,26 @@
4477144814
"tags": [],
4477244815
"hasChildren": false
4477344816
},
44817+
{
44818+
"path": "models.providers.*.models.*.compat.unsupportedToolSchemaKeywords",
44819+
"kind": "core",
44820+
"type": "array",
44821+
"required": false,
44822+
"deprecated": false,
44823+
"sensitive": false,
44824+
"tags": [],
44825+
"hasChildren": true
44826+
},
44827+
{
44828+
"path": "models.providers.*.models.*.compat.unsupportedToolSchemaKeywords.*",
44829+
"kind": "core",
44830+
"type": "string",
44831+
"required": false,
44832+
"deprecated": false,
44833+
"sensitive": false,
44834+
"tags": [],
44835+
"hasChildren": false
44836+
},
4477444837
{
4477544838
"path": "models.providers.*.models.*.contextWindow",
4477644839
"kind": "core",

docs/.generated/config-baseline.jsonl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5574}
1+
{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5580}
22
{"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}
33
{"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}
44
{"recordType":"path","path":"acp.allowedAgents.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -1921,7 +1921,10 @@
19211921
{"recordType":"path","path":"channels.line.tokenFile","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
19221922
{"recordType":"path","path":"channels.line.webhookPath","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
19231923
{"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}
1924-
{"recordType":"path","path":"channels.matrix.accessToken","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":true,"tags":["access","auth","channels","network","security"],"hasChildren":false}
1924+
{"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}
1925+
{"recordType":"path","path":"channels.matrix.accessToken.id","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
1926+
{"recordType":"path","path":"channels.matrix.accessToken.provider","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
1927+
{"recordType":"path","path":"channels.matrix.accessToken.source","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
19251928
{"recordType":"path","path":"channels.matrix.accounts","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
19261929
{"recordType":"path","path":"channels.matrix.accounts.*","kind":"channel","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
19271930
{"recordType":"path","path":"channels.matrix.ackReaction","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -2127,6 +2130,7 @@
21272130
{"recordType":"path","path":"channels.msteams.appPassword.id","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
21282131
{"recordType":"path","path":"channels.msteams.appPassword.provider","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
21292132
{"recordType":"path","path":"channels.msteams.appPassword.source","kind":"channel","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
2133+
{"recordType":"path","path":"channels.msteams.blockStreaming","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
21302134
{"recordType":"path","path":"channels.msteams.blockStreamingCoalesce","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
21312135
{"recordType":"path","path":"channels.msteams.blockStreamingCoalesce.idleMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
21322136
{"recordType":"path","path":"channels.msteams.blockStreamingCoalesce.maxChars","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -3950,6 +3954,8 @@
39503954
{"recordType":"path","path":"models.providers.*.models.*.compat.thinkingFormat","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
39513955
{"recordType":"path","path":"models.providers.*.models.*.compat.toolCallArgumentsEncoding","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
39523956
{"recordType":"path","path":"models.providers.*.models.*.compat.toolSchemaProfile","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
3957+
{"recordType":"path","path":"models.providers.*.models.*.compat.unsupportedToolSchemaKeywords","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
3958+
{"recordType":"path","path":"models.providers.*.models.*.compat.unsupportedToolSchemaKeywords.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
39533959
{"recordType":"path","path":"models.providers.*.models.*.contextWindow","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
39543960
{"recordType":"path","path":"models.providers.*.models.*.cost","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
39553961
{"recordType":"path","path":"models.providers.*.models.*.cost.cacheRead","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}

docs/providers/xai.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ OpenClaw now uses the xAI Responses API as the bundled xAI transport. The same
3232
and remote `code_execution`.
3333
If you store an xAI key under `plugins.entries.xai.config.webSearch.apiKey`,
3434
the bundled xAI model provider now reuses that key as a fallback too.
35+
`code_execution` tuning lives under `plugins.entries.xai.config.codeExecution`.
3536

3637
## Current bundled model catalog
3738

@@ -63,5 +64,6 @@ openclaw config set tools.web.search.provider grok
6364

6465
- OpenClaw applies xAI-specific tool-schema and tool-call compatibility fixes automatically on the shared runner path.
6566
- `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.
67+
- `x_search` and `code_execution` are owned by the bundled xAI plugin rather than hardcoded into the core model runtime.
6668
- `code_execution` is remote xAI sandbox execution, not local [`exec`](/tools/exec).
6769
- For the broader provider overview, see [Model providers](/providers/index).

docs/tools/code-execution.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,28 @@ devices. Use [`exec`](/tools/exec) for that.
3030

3131
You need an xAI API key. Any of these work:
3232

33-
- `tools.code_execution.apiKey`
3433
- `XAI_API_KEY`
3534
- `plugins.entries.xai.config.webSearch.apiKey`
3635

3736
Example:
3837

3938
```json5
4039
{
41-
tools: {
42-
code_execution: {
43-
enabled: true,
44-
apiKey: "xai-...",
45-
model: "grok-4-1-fast",
46-
maxTurns: 2,
47-
timeoutSeconds: 30,
40+
plugins: {
41+
entries: {
42+
xai: {
43+
config: {
44+
webSearch: {
45+
apiKey: "xai-...",
46+
},
47+
codeExecution: {
48+
enabled: true,
49+
model: "grok-4-1-fast",
50+
maxTurns: 2,
51+
timeoutSeconds: 30,
52+
},
53+
},
54+
},
4855
},
4956
},
5057
}

docs/tools/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ These tools ship with OpenClaw and are available without installing any plugins:
5555
| Tool | What it does | Page |
5656
| --------------------------------------- | -------------------------------------------------------- | --------------------------------------- |
5757
| `exec` / `process` | Run shell commands, manage background processes | [Exec](/tools/exec) |
58-
| `code_execution` | Run sandboxed remote Python analysis with xAI | [Code Execution](/tools/code-execution) |
58+
| `code_execution` | Run sandboxed remote Python analysis | [Code Execution](/tools/code-execution) |
5959
| `browser` | Control a Chromium browser (navigate, click, screenshot) | [Browser](/tools/browser) |
6060
| `web_search` / `x_search` / `web_fetch` | Search the web, search X posts, fetch page content | [Web](/tools/web) |
6161
| `read` / `write` / `edit` | File I/O in the workspace | |
Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { afterEach, describe, expect, it, vi } from "vitest";
2-
import { withFetchPreconnect } from "../../test-utils/fetch-mock.js";
2+
import { withFetchPreconnect } from "../../test/helpers/extensions/fetch-mock.js";
33
import { createCodeExecutionTool } from "./code-execution.js";
44

55
function installCodeExecutionFetch(payload?: Record<string, unknown>) {
@@ -16,11 +16,13 @@ function installCodeExecutionFetch(payload?: Record<string, unknown>) {
1616
content: [
1717
{
1818
type: "output_text",
19-
text: "The moving average is 42.",
19+
text: "Mean: 42",
20+
annotations: [{ type: "url_citation", url: "https://example.com/data.csv" }],
2021
},
2122
],
2223
},
2324
],
25+
citations: ["https://example.com/data.csv"],
2426
},
2527
),
2628
} as Response),
@@ -42,7 +44,7 @@ afterEach(() => {
4244
vi.restoreAllMocks();
4345
});
4446

45-
describe("code_execution tool", () => {
47+
describe("xai code_execution tool", () => {
4648
it("enables code_execution when the xAI plugin web search key is configured", () => {
4749
const tool = createCodeExecutionTool({
4850
config: {
@@ -67,18 +69,27 @@ describe("code_execution tool", () => {
6769
const mockFetch = installCodeExecutionFetch();
6870
const tool = createCodeExecutionTool({
6971
config: {
70-
tools: {
71-
code_execution: {
72-
apiKey: "xai-config-test", // pragma: allowlist secret
73-
model: "grok-4-1-fast",
74-
maxTurns: 2,
72+
plugins: {
73+
entries: {
74+
xai: {
75+
config: {
76+
webSearch: {
77+
apiKey: "xai-config-test", // pragma: allowlist secret
78+
},
79+
codeExecution: {
80+
model: "grok-4-1-fast",
81+
maxTurns: 2,
82+
timeoutSeconds: 45,
83+
},
84+
},
85+
},
7586
},
7687
},
7788
},
7889
});
7990

80-
const result = await tool?.execute?.("code-exec:1", {
81-
task: "Calculate the average of 40, 42, and 44.",
91+
const result = await tool?.execute?.("code-execution:1", {
92+
task: "Calculate the mean of [40, 42, 44]",
8293
});
8394

8495
expect(mockFetch).toHaveBeenCalled();
@@ -110,8 +121,8 @@ describe("code_execution tool", () => {
110121
},
111122
});
112123

113-
await tool?.execute?.("code-exec:plugin-key", {
114-
task: "Sum 1 + 2 + 3.",
124+
await tool?.execute?.("code-execution:plugin-key", {
125+
task: "Compute the standard deviation of [1, 2, 3]",
115126
});
116127

117128
const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;
@@ -136,8 +147,8 @@ describe("code_execution tool", () => {
136147
},
137148
});
138149

139-
await tool?.execute?.("code-exec:legacy-key", {
140-
task: "Multiply 6 * 7.",
150+
await tool?.execute?.("code-execution:legacy-key", {
151+
task: "Count rows in a two-column table",
141152
});
142153

143154
const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;

0 commit comments

Comments
 (0)