mirror of https://github.com/openclaw/openclaw.git
Tools: add xAI-backed code_execution
This commit is contained in:
parent
1c9684608a
commit
396bf20cc6
|
|
@ -60229,6 +60229,124 @@
|
|||
"tags": [],
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.code_execution",
|
||||
"kind": "core",
|
||||
"type": "object",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [],
|
||||
"hasChildren": true
|
||||
},
|
||||
{
|
||||
"path": "tools.code_execution.apiKey",
|
||||
"kind": "core",
|
||||
"type": [
|
||||
"object",
|
||||
"string"
|
||||
],
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": true,
|
||||
"tags": [
|
||||
"auth",
|
||||
"security",
|
||||
"tools"
|
||||
],
|
||||
"label": "xAI API Key",
|
||||
"help": "xAI API key for remote code execution (fallback: XAI_API_KEY env var).",
|
||||
"hasChildren": true
|
||||
},
|
||||
{
|
||||
"path": "tools.code_execution.apiKey.id",
|
||||
"kind": "core",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [],
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.code_execution.apiKey.provider",
|
||||
"kind": "core",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [],
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.code_execution.apiKey.source",
|
||||
"kind": "core",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [],
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.code_execution.enabled",
|
||||
"kind": "core",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [
|
||||
"tools"
|
||||
],
|
||||
"label": "Enable Code Execution Tool",
|
||||
"help": "Enable the code_execution tool (requires XAI_API_KEY or tools.code_execution.apiKey).",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.code_execution.maxTurns",
|
||||
"kind": "core",
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [
|
||||
"performance",
|
||||
"tools"
|
||||
],
|
||||
"label": "Code Execution Max Turns",
|
||||
"help": "Optional max internal tool turns xAI may use per code_execution request. Omit to let xAI choose.",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.code_execution.model",
|
||||
"kind": "core",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [
|
||||
"models",
|
||||
"tools"
|
||||
],
|
||||
"label": "Code Execution Model",
|
||||
"help": "Model to use for remote code execution (default: \"grok-4-1-fast\").",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.code_execution.timeoutSeconds",
|
||||
"kind": "core",
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [
|
||||
"performance",
|
||||
"tools"
|
||||
],
|
||||
"label": "Code Execution Timeout (sec)",
|
||||
"help": "Timeout in seconds for code_execution requests.",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.deny",
|
||||
"kind": "core",
|
||||
|
|
@ -64706,6 +64824,154 @@
|
|||
"help": "Timeout in seconds for web_search requests.",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search",
|
||||
"kind": "core",
|
||||
"type": "object",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [],
|
||||
"hasChildren": true
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search.apiKey",
|
||||
"kind": "core",
|
||||
"type": [
|
||||
"object",
|
||||
"string"
|
||||
],
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": true,
|
||||
"tags": [
|
||||
"auth",
|
||||
"security",
|
||||
"tools"
|
||||
],
|
||||
"label": "xAI API Key",
|
||||
"help": "xAI API key for X search (fallback: XAI_API_KEY env var).",
|
||||
"hasChildren": true
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search.apiKey.id",
|
||||
"kind": "core",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [],
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search.apiKey.provider",
|
||||
"kind": "core",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [],
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search.apiKey.source",
|
||||
"kind": "core",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [],
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search.cacheTtlMinutes",
|
||||
"kind": "core",
|
||||
"type": "number",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [
|
||||
"performance",
|
||||
"storage",
|
||||
"tools"
|
||||
],
|
||||
"label": "X Search Cache TTL (min)",
|
||||
"help": "Cache TTL in minutes for x_search results.",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search.enabled",
|
||||
"kind": "core",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [
|
||||
"tools"
|
||||
],
|
||||
"label": "Enable X Search Tool",
|
||||
"help": "Enable the x_search tool (requires XAI_API_KEY or tools.web.x_search.apiKey).",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search.inlineCitations",
|
||||
"kind": "core",
|
||||
"type": "boolean",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [
|
||||
"tools"
|
||||
],
|
||||
"label": "X Search Inline Citations",
|
||||
"help": "Keep inline citations from xAI in x_search responses when available (default: false).",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search.maxTurns",
|
||||
"kind": "core",
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [
|
||||
"performance",
|
||||
"tools"
|
||||
],
|
||||
"label": "X Search Max Turns",
|
||||
"help": "Optional max internal search/tool turns xAI may use per x_search request. Omit to let xAI choose.",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search.model",
|
||||
"kind": "core",
|
||||
"type": "string",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [
|
||||
"models",
|
||||
"tools"
|
||||
],
|
||||
"label": "X Search Model",
|
||||
"help": "Model to use for X search (default: \"grok-4-1-fast-non-reasoning\").",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "tools.web.x_search.timeoutSeconds",
|
||||
"kind": "core",
|
||||
"type": "integer",
|
||||
"required": false,
|
||||
"deprecated": false,
|
||||
"sensitive": false,
|
||||
"tags": [
|
||||
"performance",
|
||||
"tools"
|
||||
],
|
||||
"label": "X Search Timeout (sec)",
|
||||
"help": "Timeout in seconds for x_search requests.",
|
||||
"hasChildren": false
|
||||
},
|
||||
{
|
||||
"path": "ui",
|
||||
"kind": "core",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5554}
|
||||
{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5574}
|
||||
{"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}
|
||||
|
|
@ -5134,6 +5134,15 @@
|
|||
{"recordType":"path","path":"tools.byProvider.*.deny","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"tools.byProvider.*.deny.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"tools.byProvider.*.profile","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"tools.code_execution","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"tools.code_execution.apiKey","kind":"core","type":["object","string"],"required":false,"deprecated":false,"sensitive":true,"tags":["auth","security","tools"],"label":"xAI API Key","help":"xAI API key for remote code execution (fallback: XAI_API_KEY env var).","hasChildren":true}
|
||||
{"recordType":"path","path":"tools.code_execution.apiKey.id","kind":"core","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"tools.code_execution.apiKey.provider","kind":"core","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"tools.code_execution.apiKey.source","kind":"core","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"tools.code_execution.enabled","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Enable Code Execution Tool","help":"Enable the code_execution tool (requires XAI_API_KEY or tools.code_execution.apiKey).","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.code_execution.maxTurns","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Code Execution Max Turns","help":"Optional max internal tool turns xAI may use per code_execution request. Omit to let xAI choose.","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.code_execution.model","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["models","tools"],"label":"Code Execution Model","help":"Model to use for remote code execution (default: \"grok-4-1-fast\").","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.code_execution.timeoutSeconds","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Code Execution Timeout (sec)","help":"Timeout in seconds for code_execution requests.","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.deny","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access","tools"],"label":"Tool Denylist","help":"Global tool denylist that blocks listed tools even when profile or provider rules would allow them. Use deny rules for emergency lockouts and long-term defense-in-depth.","hasChildren":true}
|
||||
{"recordType":"path","path":"tools.deny.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"tools.elevated","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Elevated Tool Access","help":"Elevated tool access controls for privileged command surfaces that should only be reachable from trusted senders. Keep disabled unless operator workflows explicitly require elevated actions.","hasChildren":true}
|
||||
|
|
@ -5525,6 +5534,17 @@
|
|||
{"recordType":"path","path":"tools.web.search.perplexity.model","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.search.provider","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Web Search Provider","help":"Search provider id. Auto-detected from available API keys if omitted.","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.search.timeoutSeconds","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Web Search Timeout (sec)","help":"Timeout in seconds for web_search requests.","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.x_search","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"tools.web.x_search.apiKey","kind":"core","type":["object","string"],"required":false,"deprecated":false,"sensitive":true,"tags":["auth","security","tools"],"label":"xAI API Key","help":"xAI API key for X search (fallback: XAI_API_KEY env var).","hasChildren":true}
|
||||
{"recordType":"path","path":"tools.web.x_search.apiKey.id","kind":"core","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.x_search.apiKey.provider","kind":"core","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.x_search.apiKey.source","kind":"core","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.x_search.cacheTtlMinutes","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":["performance","storage","tools"],"label":"X Search Cache TTL (min)","help":"Cache TTL in minutes for x_search results.","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.x_search.enabled","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Enable X Search Tool","help":"Enable the x_search tool (requires XAI_API_KEY or tools.web.x_search.apiKey).","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.x_search.inlineCitations","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"X Search Inline Citations","help":"Keep inline citations from xAI in x_search responses when available (default: false).","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.x_search.maxTurns","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"X Search Max Turns","help":"Optional max internal search/tool turns xAI may use per x_search request. Omit to let xAI choose.","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.x_search.model","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["models","tools"],"label":"X Search Model","help":"Model to use for X search (default: \"grok-4-1-fast-non-reasoning\").","hasChildren":false}
|
||||
{"recordType":"path","path":"tools.web.x_search.timeoutSeconds","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"X Search Timeout (sec)","help":"Timeout in seconds for x_search requests.","hasChildren":false}
|
||||
{"recordType":"path","path":"ui","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"UI","help":"UI presentation settings for accenting and assistant identity shown in control surfaces. Use this for branding and readability customization without changing runtime behavior.","hasChildren":true}
|
||||
{"recordType":"path","path":"ui.assistant","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Assistant Appearance","help":"Assistant display identity settings for name and avatar shown in UI surfaces. Keep these values aligned with your operator-facing persona and support expectations.","hasChildren":true}
|
||||
{"recordType":"path","path":"ui.assistant.avatar","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Assistant Avatar","help":"Assistant avatar image source used in UI surfaces (URL, path, or data URI depending on runtime support). Use trusted assets and consistent branding dimensions for clean rendering.","hasChildren":false}
|
||||
|
|
|
|||
|
|
@ -1146,6 +1146,7 @@
|
|||
]
|
||||
},
|
||||
"tools/btw",
|
||||
"tools/code-execution",
|
||||
"tools/diffs",
|
||||
"tools/elevated",
|
||||
"tools/exec",
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ openclaw onboard --auth-choice xai-api-key
|
|||
```
|
||||
|
||||
OpenClaw now uses the xAI Responses API as the bundled xAI transport. The same
|
||||
`XAI_API_KEY` can also power Grok-backed `web_search` and first-class `x_search`.
|
||||
`XAI_API_KEY` can also power Grok-backed `web_search`, first-class `x_search`,
|
||||
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.
|
||||
|
||||
|
|
@ -61,5 +62,6 @@ openclaw config set tools.web.search.provider grok
|
|||
## Notes
|
||||
|
||||
- OpenClaw applies xAI-specific tool-schema and tool-call compatibility fixes automatically on the shared runner path.
|
||||
- `web_search` and `x_search` are exposed as OpenClaw tools. OpenClaw enables the specific xAI built-in it needs inside each tool request instead of attaching both search tools to every chat turn.
|
||||
- `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.
|
||||
- `code_execution` is remote xAI sandbox execution, not local [`exec`](/tools/exec).
|
||||
- For the broader provider overview, see [Model providers](/providers/index).
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
summary: "code_execution -- run sandboxed remote Python analysis with xAI"
|
||||
read_when:
|
||||
- You want to enable or configure code_execution
|
||||
- You want remote analysis without local shell access
|
||||
- You want to combine x_search or web_search with remote Python analysis
|
||||
title: "Code Execution"
|
||||
---
|
||||
|
||||
# Code Execution
|
||||
|
||||
`code_execution` runs sandboxed remote Python analysis on xAI's Responses API.
|
||||
This is different from local [`exec`](/tools/exec):
|
||||
|
||||
- `exec` runs shell commands on your machine or node
|
||||
- `code_execution` runs Python in xAI's remote sandbox
|
||||
|
||||
Use `code_execution` for:
|
||||
|
||||
- calculations
|
||||
- tabulation
|
||||
- quick statistics
|
||||
- chart-style analysis
|
||||
- analyzing data returned by `x_search` or `web_search`
|
||||
|
||||
Do **not** use it when you need local files, your shell, your repo, or paired
|
||||
devices. Use [`exec`](/tools/exec) for that.
|
||||
|
||||
## Setup
|
||||
|
||||
You need an xAI API key. Any of these work:
|
||||
|
||||
- `tools.code_execution.apiKey`
|
||||
- `XAI_API_KEY`
|
||||
- `plugins.entries.xai.config.webSearch.apiKey`
|
||||
|
||||
Example:
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
code_execution: {
|
||||
enabled: true,
|
||||
apiKey: "xai-...",
|
||||
model: "grok-4-1-fast",
|
||||
maxTurns: 2,
|
||||
timeoutSeconds: 30,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## How To Use It
|
||||
|
||||
Ask naturally and make the analysis intent explicit:
|
||||
|
||||
```text
|
||||
Use code_execution to calculate the 7-day moving average for these numbers: ...
|
||||
```
|
||||
|
||||
```text
|
||||
Use x_search to find posts mentioning OpenClaw this week, then use code_execution to count them by day.
|
||||
```
|
||||
|
||||
```text
|
||||
Use web_search to gather the latest AI benchmark numbers, then use code_execution to compare percent changes.
|
||||
```
|
||||
|
||||
The tool takes a single `task` parameter internally, so the agent should send
|
||||
the full analysis request and any inline data in one prompt.
|
||||
|
||||
## Limits
|
||||
|
||||
- This is remote xAI execution, not local process execution.
|
||||
- It should be treated as ephemeral analysis, not a persistent notebook.
|
||||
- Do not assume access to local files or your workspace.
|
||||
- For fresh X data, use [`x_search`](/tools/web#x_search) first.
|
||||
|
||||
## See Also
|
||||
|
||||
- [Web tools](/tools/web)
|
||||
- [Exec](/tools/exec)
|
||||
- [xAI](/providers/xai)
|
||||
|
|
@ -52,19 +52,20 @@ OpenClaw has three layers that work together:
|
|||
|
||||
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) |
|
||||
| `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 | |
|
||||
| `apply_patch` | Multi-hunk file patches | [Apply Patch](/tools/apply-patch) |
|
||||
| `message` | Send messages across all channels | [Agent Send](/tools/agent-send) |
|
||||
| `canvas` | Drive node Canvas (present, eval, snapshot) | |
|
||||
| `nodes` | Discover and target paired devices | |
|
||||
| `cron` / `gateway` | Manage scheduled jobs, restart gateway | |
|
||||
| `image` / `image_generate` | Analyze or generate images | |
|
||||
| `sessions_*` / `agents_list` | Session management, sub-agents | [Sub-agents](/tools/subagents) |
|
||||
| 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) |
|
||||
| `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 | |
|
||||
| `apply_patch` | Multi-hunk file patches | [Apply Patch](/tools/apply-patch) |
|
||||
| `message` | Send messages across all channels | [Agent Send](/tools/agent-send) |
|
||||
| `canvas` | Drive node Canvas (present, eval, snapshot) | |
|
||||
| `nodes` | Discover and target paired devices | |
|
||||
| `cron` / `gateway` | Manage scheduled jobs, restart gateway | |
|
||||
| `image` / `image_generate` | Analyze or generate images | |
|
||||
| `sessions_*` / `agents_list` | Session management, sub-agents | [Sub-agents](/tools/subagents) |
|
||||
|
||||
For image work, use `image` for analysis and `image_generate` for generation or editing. If you target `openai/*`, `google/*`, `fal/*`, or another non-default image provider, configure that provider's auth/API key first.
|
||||
|
||||
|
|
@ -111,7 +112,7 @@ Use `group:*` shorthands in allow/deny lists:
|
|||
|
||||
| Group | Tools |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------- |
|
||||
| `group:runtime` | exec, bash, process |
|
||||
| `group:runtime` | exec, bash, process, code_execution |
|
||||
| `group:fs` | read, write, edit, apply_patch |
|
||||
| `group:sessions` | sessions_list, sessions_history, sessions_send, sessions_spawn, sessions_yield, subagents, session_status |
|
||||
| `group:memory` | memory_search, memory_get |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
import { normalizeXaiModelId } from "openclaw/plugin-sdk/provider-models";
|
||||
import { postTrustedWebToolsJson } from "openclaw/plugin-sdk/provider-web-search";
|
||||
import { extractXaiWebSearchContent, type XaiWebSearchResponse } from "./web-search-shared.js";
|
||||
|
||||
export const XAI_CODE_EXECUTION_ENDPOINT = "https://api.x.ai/v1/responses";
|
||||
export const XAI_DEFAULT_CODE_EXECUTION_MODEL = "grok-4-1-fast";
|
||||
|
||||
export type XaiCodeExecutionConfig = {
|
||||
apiKey?: unknown;
|
||||
model?: unknown;
|
||||
maxTurns?: unknown;
|
||||
};
|
||||
|
||||
export type XaiCodeExecutionResponse = XaiWebSearchResponse & {
|
||||
output?: Array<{
|
||||
type?: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type XaiCodeExecutionResult = {
|
||||
content: string;
|
||||
citations: string[];
|
||||
usedCodeExecution: boolean;
|
||||
outputTypes: string[];
|
||||
};
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
export function resolveXaiCodeExecutionConfig(
|
||||
config?: Record<string, unknown>,
|
||||
): XaiCodeExecutionConfig {
|
||||
return isRecord(config) ? (config as XaiCodeExecutionConfig) : {};
|
||||
}
|
||||
|
||||
export function resolveXaiCodeExecutionModel(config?: Record<string, unknown>): string {
|
||||
const resolved = resolveXaiCodeExecutionConfig(config);
|
||||
return typeof resolved.model === "string" && resolved.model.trim()
|
||||
? normalizeXaiModelId(resolved.model.trim())
|
||||
: XAI_DEFAULT_CODE_EXECUTION_MODEL;
|
||||
}
|
||||
|
||||
export function resolveXaiCodeExecutionMaxTurns(
|
||||
config?: Record<string, unknown>,
|
||||
): number | undefined {
|
||||
const raw = resolveXaiCodeExecutionConfig(config).maxTurns;
|
||||
if (typeof raw !== "number" || !Number.isFinite(raw)) {
|
||||
return undefined;
|
||||
}
|
||||
const normalized = Math.trunc(raw);
|
||||
return normalized > 0 ? normalized : undefined;
|
||||
}
|
||||
|
||||
export function buildXaiCodeExecutionPayload(params: {
|
||||
task: string;
|
||||
model: string;
|
||||
tookMs: number;
|
||||
content: string;
|
||||
citations: string[];
|
||||
usedCodeExecution: boolean;
|
||||
outputTypes: string[];
|
||||
}): Record<string, unknown> {
|
||||
return {
|
||||
task: params.task,
|
||||
provider: "xai",
|
||||
model: params.model,
|
||||
tookMs: params.tookMs,
|
||||
content: params.content,
|
||||
citations: params.citations,
|
||||
usedCodeExecution: params.usedCodeExecution,
|
||||
outputTypes: params.outputTypes,
|
||||
};
|
||||
}
|
||||
|
||||
export async function requestXaiCodeExecution(params: {
|
||||
apiKey: string;
|
||||
model: string;
|
||||
timeoutSeconds: number;
|
||||
maxTurns?: number;
|
||||
task: string;
|
||||
}): Promise<XaiCodeExecutionResult> {
|
||||
return await postTrustedWebToolsJson(
|
||||
{
|
||||
url: XAI_CODE_EXECUTION_ENDPOINT,
|
||||
timeoutSeconds: params.timeoutSeconds,
|
||||
apiKey: params.apiKey,
|
||||
body: {
|
||||
model: params.model,
|
||||
input: [{ role: "user", content: params.task }],
|
||||
tools: [{ type: "code_interpreter" }],
|
||||
...(params.maxTurns ? { max_turns: params.maxTurns } : {}),
|
||||
},
|
||||
errorLabel: "xAI",
|
||||
},
|
||||
async (response) => {
|
||||
const data = (await response.json()) as XaiCodeExecutionResponse;
|
||||
const { text, annotationCitations } = extractXaiWebSearchContent(data);
|
||||
const outputTypes = Array.isArray(data.output)
|
||||
? [
|
||||
...new Set(
|
||||
data.output
|
||||
.map((entry) => entry?.type)
|
||||
.filter((value): value is string => Boolean(value)),
|
||||
),
|
||||
]
|
||||
: [];
|
||||
const citations =
|
||||
Array.isArray(data.citations) && data.citations.length > 0
|
||||
? data.citations
|
||||
: annotationCitations;
|
||||
return {
|
||||
content: text ?? "No response",
|
||||
citations,
|
||||
usedCodeExecution: outputTypes.includes("code_interpreter_call"),
|
||||
outputTypes,
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
buildXaiCodeExecutionPayload,
|
||||
requestXaiCodeExecution,
|
||||
resolveXaiCodeExecutionConfig,
|
||||
resolveXaiCodeExecutionMaxTurns,
|
||||
resolveXaiCodeExecutionModel,
|
||||
XAI_DEFAULT_CODE_EXECUTION_MODEL,
|
||||
} as const;
|
||||
|
|
@ -27,7 +27,12 @@ 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 { createWebFetchTool, createWebSearchTool, createXSearchTool } from "./tools/web-tools.js";
|
||||
import {
|
||||
createCodeExecutionTool,
|
||||
createWebFetchTool,
|
||||
createWebSearchTool,
|
||||
createXSearchTool,
|
||||
} from "./tools/web-tools.js";
|
||||
import { resolveWorkspaceRoot } from "./workspace-dir.js";
|
||||
|
||||
type OpenClawToolsDeps = {
|
||||
|
|
@ -159,6 +164,9 @@ export function createOpenClawTools(
|
|||
config: options?.config,
|
||||
runtimeXSearch: runtimeWebTools?.xSearch,
|
||||
});
|
||||
const codeExecutionTool = createCodeExecutionTool({
|
||||
config: options?.config,
|
||||
});
|
||||
const webFetchTool = createWebFetchTool({
|
||||
config: options?.config,
|
||||
sandboxed: options?.sandboxed,
|
||||
|
|
@ -256,6 +264,7 @@ export function createOpenClawTools(
|
|||
}),
|
||||
...(webSearchTool ? [webSearchTool] : []),
|
||||
...(xSearchTool ? [xSearchTool] : []),
|
||||
...(codeExecutionTool ? [codeExecutionTool] : []),
|
||||
...(webFetchTool ? [webFetchTool] : []),
|
||||
...(imageTool ? [imageTool] : []),
|
||||
...(pdfTool ? [pdfTool] : []),
|
||||
|
|
|
|||
|
|
@ -282,4 +282,50 @@ describe("openclaw tools runtime web metadata wiring", () => {
|
|||
"https://x.com/openclaw/status/1",
|
||||
]);
|
||||
});
|
||||
|
||||
it("resolves code_execution SecretRef from the active runtime snapshot", async () => {
|
||||
const snapshot = await prepareAndActivate({
|
||||
config: asConfig({
|
||||
tools: {
|
||||
code_execution: {
|
||||
apiKey: { source: "env", provider: "default", id: "CODE_EXECUTION_RUNTIME_REF" },
|
||||
},
|
||||
},
|
||||
}),
|
||||
env: {
|
||||
CODE_EXECUTION_RUNTIME_REF: "code-execution-runtime-key",
|
||||
},
|
||||
});
|
||||
|
||||
const mockFetch = vi.fn((_input?: unknown, _init?: unknown) =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () =>
|
||||
Promise.resolve({
|
||||
output: [
|
||||
{ type: "code_interpreter_call" },
|
||||
{
|
||||
type: "message",
|
||||
content: [{ type: "output_text", text: "runtime code execution ok" }],
|
||||
},
|
||||
],
|
||||
}),
|
||||
} as Response),
|
||||
);
|
||||
global.fetch = withFetchPreconnect(mockFetch);
|
||||
|
||||
const codeExecution = findTool("code_execution", snapshot.config);
|
||||
const result = await codeExecution.execute("call-runtime-code-execution", {
|
||||
task: "Add 20 + 22",
|
||||
});
|
||||
|
||||
expect(mockFetch).toHaveBeenCalled();
|
||||
expect(String(mockFetch.mock.calls[0]?.[0])).toContain("api.x.ai/v1/responses");
|
||||
const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;
|
||||
const body = JSON.parse(typeof request?.body === "string" ? request.body : "{}") as {
|
||||
tools?: Array<Record<string, unknown>>;
|
||||
};
|
||||
expect(body.tools).toEqual([{ type: "code_interpreter" }]);
|
||||
expect((result.details as { usedCodeExecution?: boolean }).usedCodeExecution).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -233,6 +233,8 @@ 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",
|
||||
|
|
@ -270,6 +272,7 @@ export function buildAgentSystemPrompt(params: {
|
|||
"ls",
|
||||
"exec",
|
||||
"process",
|
||||
"code_execution",
|
||||
"web_search",
|
||||
"web_fetch",
|
||||
"browser",
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ import { describe, expect, it } from "vitest";
|
|||
import { resolveCoreToolProfilePolicy } from "./tool-catalog.js";
|
||||
|
||||
describe("tool-catalog", () => {
|
||||
it("includes web_search, x_search, and web_fetch in the coding profile policy", () => {
|
||||
it("includes code_execution, web_search, x_search, and web_fetch in the coding profile policy", () => {
|
||||
const policy = resolveCoreToolProfilePolicy("coding");
|
||||
expect(policy).toBeDefined();
|
||||
expect(policy!.allow).toContain("code_execution");
|
||||
expect(policy!.allow).toContain("web_search");
|
||||
expect(policy!.allow).toContain("x_search");
|
||||
expect(policy!.allow).toContain("web_fetch");
|
||||
|
|
|
|||
|
|
@ -81,6 +81,14 @@ const CORE_TOOL_DEFINITIONS: CoreToolDefinition[] = [
|
|||
sectionId: "runtime",
|
||||
profiles: ["coding"],
|
||||
},
|
||||
{
|
||||
id: "code_execution",
|
||||
label: "code_execution",
|
||||
description: "Run sandboxed remote analysis with xAI",
|
||||
sectionId: "runtime",
|
||||
profiles: ["coding"],
|
||||
includeInOpenClawGroup: true,
|
||||
},
|
||||
{
|
||||
id: "web_search",
|
||||
label: "web_search",
|
||||
|
|
|
|||
|
|
@ -92,6 +92,11 @@
|
|||
"title": "Web Fetch",
|
||||
"detailKeys": ["url", "extractMode", "maxChars"]
|
||||
},
|
||||
"code_execution": {
|
||||
"emoji": "🧮",
|
||||
"title": "Code Execution",
|
||||
"detailKeys": ["task"]
|
||||
},
|
||||
"message": {
|
||||
"emoji": "✉️",
|
||||
"title": "Message",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,148 @@
|
|||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { withFetchPreconnect } from "../../test-utils/fetch-mock.js";
|
||||
import { createCodeExecutionTool } from "./code-execution.js";
|
||||
|
||||
function installCodeExecutionFetch(payload?: Record<string, unknown>) {
|
||||
const mockFetch = vi.fn((_input?: unknown, _init?: unknown) =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () =>
|
||||
Promise.resolve(
|
||||
payload ?? {
|
||||
output: [
|
||||
{ type: "code_interpreter_call" },
|
||||
{
|
||||
type: "message",
|
||||
content: [
|
||||
{
|
||||
type: "output_text",
|
||||
text: "The moving average is 42.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
),
|
||||
} as Response),
|
||||
);
|
||||
global.fetch = withFetchPreconnect(mockFetch);
|
||||
return mockFetch;
|
||||
}
|
||||
|
||||
function parseFirstRequestBody(mockFetch: ReturnType<typeof installCodeExecutionFetch>) {
|
||||
const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;
|
||||
const requestBody = request?.body;
|
||||
return JSON.parse(typeof requestBody === "string" ? requestBody : "{}") as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("code_execution tool", () => {
|
||||
it("enables code_execution when the xAI plugin web search key is configured", () => {
|
||||
const tool = createCodeExecutionTool({
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
xai: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "xai-plugin-key", // pragma: allowlist secret
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(tool?.name).toBe("code_execution");
|
||||
});
|
||||
|
||||
it("uses the xAI Responses code_interpreter tool", async () => {
|
||||
const mockFetch = installCodeExecutionFetch();
|
||||
const tool = createCodeExecutionTool({
|
||||
config: {
|
||||
tools: {
|
||||
code_execution: {
|
||||
apiKey: "xai-config-test", // pragma: allowlist secret
|
||||
model: "grok-4-1-fast",
|
||||
maxTurns: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const result = await tool?.execute?.("code-exec:1", {
|
||||
task: "Calculate the average of 40, 42, and 44.",
|
||||
});
|
||||
|
||||
expect(mockFetch).toHaveBeenCalled();
|
||||
expect(String(mockFetch.mock.calls[0]?.[0])).toContain("api.x.ai/v1/responses");
|
||||
const body = parseFirstRequestBody(mockFetch);
|
||||
expect(body.model).toBe("grok-4-1-fast");
|
||||
expect(body.max_turns).toBe(2);
|
||||
expect(body.tools).toEqual([{ type: "code_interpreter" }]);
|
||||
expect(
|
||||
(result?.details as { usedCodeExecution?: boolean } | undefined)?.usedCodeExecution,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("reuses the xAI plugin web search key for code_execution requests", async () => {
|
||||
const mockFetch = installCodeExecutionFetch();
|
||||
const tool = createCodeExecutionTool({
|
||||
config: {
|
||||
plugins: {
|
||||
entries: {
|
||||
xai: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "xai-plugin-key", // pragma: allowlist secret
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await tool?.execute?.("code-exec:plugin-key", {
|
||||
task: "Sum 1 + 2 + 3.",
|
||||
});
|
||||
|
||||
const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;
|
||||
expect((request?.headers as Record<string, string> | undefined)?.Authorization).toBe(
|
||||
"Bearer xai-plugin-key",
|
||||
);
|
||||
});
|
||||
|
||||
it("reuses the legacy grok web search key for code_execution requests", async () => {
|
||||
const mockFetch = installCodeExecutionFetch();
|
||||
const tool = createCodeExecutionTool({
|
||||
config: {
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
grok: {
|
||||
apiKey: "xai-legacy-key", // pragma: allowlist secret
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await tool?.execute?.("code-exec:legacy-key", {
|
||||
task: "Multiply 6 * 7.",
|
||||
});
|
||||
|
||||
const request = mockFetch.mock.calls[0]?.[1] as RequestInit | undefined;
|
||||
expect((request?.headers as Record<string, string> | undefined)?.Authorization).toBe(
|
||||
"Bearer xai-legacy-key",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
import { Type } from "@sinclair/typebox";
|
||||
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";
|
||||
|
||||
type CodeExecutionConfig =
|
||||
NonNullable<OpenClawConfig["tools"]> extends infer Tools
|
||||
? Tools extends { code_execution?: infer CodeExecution }
|
||||
? CodeExecution
|
||||
: undefined
|
||||
: undefined;
|
||||
|
||||
function readLegacyGrokApiKey(cfg?: OpenClawConfig): string | undefined {
|
||||
const search = cfg?.tools?.web?.search;
|
||||
if (!search || typeof search !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
const grok = (search as Record<string, unknown>).grok;
|
||||
return readConfiguredSecretString(
|
||||
grok && typeof grok === "object" ? (grok as Record<string, unknown>).apiKey : undefined,
|
||||
"tools.web.search.grok.apiKey",
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
if (!codeExecution || typeof codeExecution !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
return codeExecution;
|
||||
}
|
||||
|
||||
function resolveCodeExecutionEnabled(params: {
|
||||
cfg?: 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) ||
|
||||
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 })) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
label: "Code Execution",
|
||||
name: "code_execution",
|
||||
description:
|
||||
"Run sandboxed Python analysis with xAI. Use for calculations, tabulation, summaries, and chart-style analysis without local machine access.",
|
||||
parameters: Type.Object({
|
||||
task: Type.String({
|
||||
description:
|
||||
"The full analysis task for xAI's remote Python sandbox. Include any data to analyze directly in the task.",
|
||||
}),
|
||||
}),
|
||||
execute: async (_toolCallId: string, args: Record<string, unknown>) => {
|
||||
const apiKey = resolveCodeExecutionApiKey(codeExecutionConfig, options?.config);
|
||||
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.",
|
||||
docs: "https://docs.openclaw.ai/tools/code-execution",
|
||||
});
|
||||
}
|
||||
|
||||
const task = readStringParam(args, "task", { required: true });
|
||||
const codeExecutionConfigRecord = codeExecutionConfig as Record<string, unknown> | undefined;
|
||||
const model = resolveXaiCodeExecutionModel(codeExecutionConfigRecord);
|
||||
const maxTurns = resolveXaiCodeExecutionMaxTurns(codeExecutionConfigRecord);
|
||||
const startedAt = Date.now();
|
||||
const result = await requestXaiCodeExecution({
|
||||
apiKey,
|
||||
model,
|
||||
timeoutSeconds: codeExecutionConfig?.timeoutSeconds ?? 30,
|
||||
maxTurns,
|
||||
task,
|
||||
});
|
||||
return jsonResult(
|
||||
buildXaiCodeExecutionPayload({
|
||||
task,
|
||||
model,
|
||||
tookMs: Date.now() - startedAt,
|
||||
content: result.content,
|
||||
citations: result.citations,
|
||||
usedCodeExecution: result.usedCodeExecution,
|
||||
outputTypes: result.outputTypes,
|
||||
}),
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export { createWebFetchTool, extractReadableContent, fetchFirecrawlContent } from "./web-fetch.js";
|
||||
export { createWebSearchTool } from "./web-search.js";
|
||||
export { createXSearchTool } from "./x-search.js";
|
||||
export { createCodeExecutionTool } from "./code-execution.js";
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ 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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ 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",
|
||||
|
|
|
|||
|
|
@ -7164,6 +7164,94 @@ 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: {
|
||||
|
|
@ -12975,6 +13063,32 @@ 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).",
|
||||
|
|
|
|||
|
|
@ -724,6 +724,15 @@ 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":
|
||||
|
|
|
|||
|
|
@ -254,6 +254,11 @@ 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",
|
||||
|
|
|
|||
|
|
@ -476,6 +476,19 @@ 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;
|
||||
|
|
@ -485,6 +498,8 @@ 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). */
|
||||
|
|
|
|||
|
|
@ -361,6 +361,17 @@ 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,
|
||||
|
|
@ -854,6 +865,7 @@ export const ToolsSchema = z
|
|||
})
|
||||
.strict()
|
||||
.optional(),
|
||||
code_execution: ToolCodeExecutionSchema,
|
||||
exec: ToolExecSchema,
|
||||
fs: ToolFsSchema,
|
||||
subagents: z
|
||||
|
|
|
|||
|
|
@ -292,6 +292,33 @@ 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;
|
||||
|
|
@ -425,5 +452,6 @@ export function collectCoreConfigAssignments(params: {
|
|||
collectGatewayAssignments(params);
|
||||
collectSandboxSshAssignments(params);
|
||||
collectMessagesTtsAssignments(params);
|
||||
collectCodeExecutionAssignments(params);
|
||||
collectCronAssignments(params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,6 +208,9 @@ 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -703,6 +703,17 @@ 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",
|
||||
|
|
|
|||
Loading…
Reference in New Issue