diff --git a/.openclaw-sync/source.json b/.openclaw-sync/source.json index c55ce5a68..15b4290c9 100644 --- a/.openclaw-sync/source.json +++ b/.openclaw-sync/source.json @@ -1,5 +1,5 @@ { "repository": "openclaw/openclaw", - "sha": "7e0e2f81e557471f7477ca886c26931c046f32ef", - "syncedAt": "2026-04-06T12:31:05.453Z" + "sha": "a2b065b09011d060f2119a52d87fe2aafcb10a68", + "syncedAt": "2026-04-06T12:41:32.816Z" } diff --git a/docs/cli/gateway.md b/docs/cli/gateway.md index 355e994bb..d0566ce67 100644 --- a/docs/cli/gateway.md +++ b/docs/cli/gateway.md @@ -57,6 +57,7 @@ Notes: - `--reset`: reset dev config + credentials + sessions + workspace (requires `--dev`). - `--force`: kill any existing listener on the selected port before starting. - `--verbose`: verbose logs. +- `--cli-backend-logs`: only show CLI backend logs in the console (and enable stdout/stderr). - `--ws-log `: websocket log style (default `auto`). - `--compact`: alias for `--ws-log compact`. - `--raw-stream`: log raw model stream events to jsonl. diff --git a/docs/cli/index.md b/docs/cli/index.md index 60cab7bd2..3b8c0feda 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -501,7 +501,7 @@ Options: `openrouter-api-key`, `kilocode-api-key`, `litellm-api-key`, `ai-gateway-api-key`, `cloudflare-ai-gateway-api-key`, `moonshot-api-key`, `moonshot-api-key-cn`, `kimi-code-api-key`, `synthetic-api-key`, `venice-api-key`, `together-api-key`, - `huggingface-api-key`, `apiKey`, `gemini-api-key`, `zai-api-key`, + `huggingface-api-key`, `apiKey`, `gemini-api-key`, `google-gemini-cli`, `zai-api-key`, `zai-coding-global`, `zai-coding-cn`, `zai-global`, `zai-cn`, `xiaomi-api-key`, `minimax-global-oauth`, `minimax-global-api`, `minimax-cn-oauth`, `minimax-cn-api`, `opencode-zen`, `opencode-go`, `github-copilot`, `copilot-proxy`, `xai-api-key`, @@ -1353,6 +1353,7 @@ Options: - `--reset` (reset dev config + credentials + sessions + workspace) - `--force` (kill existing listener on port) - `--verbose` +- `--cli-backend-logs` - `--ws-log ` - `--compact` (alias for `--ws-log compact`) - `--raw-stream` diff --git a/docs/concepts/context.md b/docs/concepts/context.md index 5c48bed11..5d9bd60af 100644 --- a/docs/concepts/context.md +++ b/docs/concepts/context.md @@ -167,7 +167,7 @@ pluggable interface, lifecycle hooks, and configuration. `/context` prefers the latest **run-built** system prompt report when available: - `System prompt (run)` = captured from the last embedded (tool-capable) run and persisted in the session store. -- `System prompt (estimate)` = computed on the fly when no run report exists yet. +- `System prompt (estimate)` = computed on the fly when no run report exists (or when running via a CLI backend that doesn’t generate the report). Either way, it reports sizes and top contributors; it does **not** dump the full system prompt or tool schemas. diff --git a/docs/concepts/model-providers.md b/docs/concepts/model-providers.md index df9e951c8..98dabdafc 100644 --- a/docs/concepts/model-providers.md +++ b/docs/concepts/model-providers.md @@ -165,11 +165,13 @@ Current bundled examples: wrappers, provider-family metadata, bundled image-generation provider registration for `gpt-image-1`, and bundled video-generation provider registration for `sora-2` -- `google`: Gemini 3.1 forward-compat fallback, native Gemini replay - validation, bootstrap replay sanitation, tagged reasoning-output mode, - modern-model matching, bundled image-generation provider registration for - Gemini image-preview models, and bundled video-generation provider - registration for Veo models +- `google` and `google-gemini-cli`: Gemini 3.1 forward-compat fallback, + native Gemini replay validation, bootstrap replay sanitation, tagged + reasoning-output mode, modern-model matching, bundled image-generation + provider registration for Gemini image-preview models, and bundled + video-generation provider registration for Veo models; Gemini CLI OAuth also + owns auth-profile token formatting, usage-token parsing, and quota endpoint + fetching for usage surfaces - `moonshot`: shared transport, plugin-owned thinking payload normalization - `kilocode`: shared transport, plugin-owned request headers, reasoning payload normalization, proxy-Gemini thought-signature sanitation, and cache-TTL @@ -347,10 +349,21 @@ OpenClaw ships with the pi‑ai catalog. These providers require **no** (or legacy `cached_content`) to forward a provider-native `cachedContents/...` handle; Gemini cache hits surface as OpenClaw `cacheRead` -### Google Vertex +### Google Vertex and Gemini CLI -- Provider: `google-vertex` -- Auth: gcloud ADC +- Providers: `google-vertex`, `google-gemini-cli` +- Auth: Vertex uses gcloud ADC; Gemini CLI uses its OAuth flow +- Caution: Gemini CLI OAuth in OpenClaw is an unofficial integration. Some users have reported Google account restrictions after using third-party clients. Review Google terms and use a non-critical account if you choose to proceed. +- Gemini CLI OAuth is shipped as part of the bundled `google` plugin. + - Install Gemini CLI first: + - `brew install gemini-cli` + - or `npm install -g @google/gemini-cli` + - Enable: `openclaw plugins enable google` + - Login: `openclaw models auth login --provider google-gemini-cli --set-default` + - Default model: `google-gemini-cli/gemini-3.1-pro-preview` + - Note: you do **not** paste a client id or secret into `openclaw.json`. The CLI login flow stores + tokens in auth profiles on the gateway host. + - If requests fail after login, set `GOOGLE_CLOUD_PROJECT` or `GOOGLE_CLOUD_PROJECT_ID` on the gateway host. - Gemini CLI JSON replies are parsed from `response`; usage falls back to `stats`, with `stats.cached` normalized into OpenClaw `cacheRead`. diff --git a/docs/docs.json b/docs/docs.json index 1cd9ac213..b9207fae0 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1377,6 +1377,7 @@ "gateway/openai-http-api", "gateway/openresponses-http-api", "gateway/tools-invoke-http-api", + "gateway/cli-backends", "gateway/local-models" ] }, @@ -2741,6 +2742,7 @@ "ja-JP/gateway/openai-http-api", "ja-JP/gateway/openresponses-http-api", "ja-JP/gateway/tools-invoke-http-api", + "ja-JP/gateway/cli-backends", "ja-JP/gateway/local-models" ] }, @@ -3490,6 +3492,7 @@ "es/gateway/openai-http-api", "es/gateway/openresponses-http-api", "es/gateway/tools-invoke-http-api", + "es/gateway/cli-backends", "es/gateway/local-models" ] }, @@ -4239,6 +4242,7 @@ "pt-BR/gateway/openai-http-api", "pt-BR/gateway/openresponses-http-api", "pt-BR/gateway/tools-invoke-http-api", + "pt-BR/gateway/cli-backends", "pt-BR/gateway/local-models" ] }, @@ -4988,6 +4992,7 @@ "ko/gateway/openai-http-api", "ko/gateway/openresponses-http-api", "ko/gateway/tools-invoke-http-api", + "ko/gateway/cli-backends", "ko/gateway/local-models" ] }, @@ -5737,6 +5742,7 @@ "de/gateway/openai-http-api", "de/gateway/openresponses-http-api", "de/gateway/tools-invoke-http-api", + "de/gateway/cli-backends", "de/gateway/local-models" ] }, @@ -6486,6 +6492,7 @@ "fr/gateway/openai-http-api", "fr/gateway/openresponses-http-api", "fr/gateway/tools-invoke-http-api", + "fr/gateway/cli-backends", "fr/gateway/local-models" ] }, @@ -7235,6 +7242,7 @@ "ar/gateway/openai-http-api", "ar/gateway/openresponses-http-api", "ar/gateway/tools-invoke-http-api", + "ar/gateway/cli-backends", "ar/gateway/local-models" ] }, @@ -7984,6 +7992,7 @@ "it/gateway/openai-http-api", "it/gateway/openresponses-http-api", "it/gateway/tools-invoke-http-api", + "it/gateway/cli-backends", "it/gateway/local-models" ] }, @@ -8733,6 +8742,7 @@ "tr/gateway/openai-http-api", "tr/gateway/openresponses-http-api", "tr/gateway/tools-invoke-http-api", + "tr/gateway/cli-backends", "tr/gateway/local-models" ] }, @@ -9482,6 +9492,7 @@ "uk/gateway/openai-http-api", "uk/gateway/openresponses-http-api", "uk/gateway/tools-invoke-http-api", + "uk/gateway/cli-backends", "uk/gateway/local-models" ] }, @@ -10231,6 +10242,7 @@ "id/gateway/openai-http-api", "id/gateway/openresponses-http-api", "id/gateway/tools-invoke-http-api", + "id/gateway/cli-backends", "id/gateway/local-models" ] }, @@ -10980,6 +10992,7 @@ "pl/gateway/openai-http-api", "pl/gateway/openresponses-http-api", "pl/gateway/tools-invoke-http-api", + "pl/gateway/cli-backends", "pl/gateway/local-models" ] }, diff --git a/docs/gateway/cli-backends.md b/docs/gateway/cli-backends.md new file mode 100644 index 000000000..ecaa54687 --- /dev/null +++ b/docs/gateway/cli-backends.md @@ -0,0 +1,287 @@ +--- +summary: "CLI backends: local AI CLI fallback with optional MCP tool bridge" +read_when: + - You want a reliable fallback when API providers fail + - You are running Codex CLI or other local AI CLIs and want to reuse them + - You want to understand the MCP loopback bridge for CLI backend tool access +title: "CLI Backends" +--- + +# CLI backends (fallback runtime) + +OpenClaw can run **local AI CLIs** as a **text-only fallback** when API providers are down, +rate-limited, or temporarily misbehaving. This is intentionally conservative: + +- **OpenClaw tools are not injected directly**, but backends with `bundleMcp: true` + can receive gateway tools via a loopback MCP bridge. +- **JSONL streaming** for CLIs that support it. +- **Sessions are supported** (so follow-up turns stay coherent). +- **Images can be passed through** if the CLI accepts image paths. + +This is designed as a **safety net** rather than a primary path. Use it when you +want “always works” text responses without relying on external APIs. + +If you want a full harness runtime with ACP session controls, background tasks, +thread/conversation binding, and persistent external coding sessions, use +[ACP Agents](/tools/acp-agents) instead. CLI backends are not ACP. + +## Beginner-friendly quick start + +You can use Codex CLI **without any config** (the bundled OpenAI plugin +registers a default backend): + +```bash +openclaw agent --message "hi" --model codex-cli/gpt-5.4 +``` + +If your gateway runs under launchd/systemd and PATH is minimal, add just the +command path: + +```json5 +{ + agents: { + defaults: { + cliBackends: { + "codex-cli": { + command: "/opt/homebrew/bin/codex", + }, + }, + }, + }, +} +``` + +That’s it. No keys, no extra auth config needed beyond the CLI itself. + +If you use a bundled CLI backend as the **primary message provider** on a +gateway host, OpenClaw now auto-loads the owning bundled plugin when your config +explicitly references that backend in a model ref or under +`agents.defaults.cliBackends`. + +## Using it as a fallback + +Add a CLI backend to your fallback list so it only runs when primary models fail: + +```json5 +{ + agents: { + defaults: { + model: { + primary: "anthropic/claude-opus-4-6", + fallbacks: ["codex-cli/gpt-5.4"], + }, + models: { + "anthropic/claude-opus-4-6": { alias: "Opus" }, + "codex-cli/gpt-5.4": {}, + }, + }, + }, +} +``` + +Notes: + +- If you use `agents.defaults.models` (allowlist), you must include your CLI backend models there too. +- If the primary provider fails (auth, rate limits, timeouts), OpenClaw will + try the CLI backend next. + +## Configuration overview + +All CLI backends live under: + +``` +agents.defaults.cliBackends +``` + +Each entry is keyed by a **provider id** (e.g. `codex-cli`, `my-cli`). +The provider id becomes the left side of your model ref: + +``` +/ +``` + +### Example configuration + +```json5 +{ + agents: { + defaults: { + cliBackends: { + "codex-cli": { + command: "/opt/homebrew/bin/codex", + }, + "my-cli": { + command: "my-cli", + args: ["--json"], + output: "json", + input: "arg", + modelArg: "--model", + modelAliases: { + "claude-opus-4-6": "opus", + "claude-sonnet-4-6": "sonnet", + }, + sessionArg: "--session", + sessionMode: "existing", + sessionIdFields: ["session_id", "conversation_id"], + systemPromptArg: "--system", + systemPromptWhen: "first", + imageArg: "--image", + imageMode: "repeat", + serialize: true, + }, + }, + }, + }, +} +``` + +## How it works + +1. **Selects a backend** based on the provider prefix (`codex-cli/...`). +2. **Builds a system prompt** using the same OpenClaw prompt + workspace context. +3. **Executes the CLI** with a session id (if supported) so history stays consistent. +4. **Parses output** (JSON or plain text) and returns the final text. +5. **Persists session ids** per backend, so follow-ups reuse the same CLI session. + + +The bundled Anthropic `claude-cli` backend was removed after Anthropic's +OpenClaw billing boundary changed. OpenClaw still supports generic CLI +backends, but Anthropic API traffic should use the Anthropic provider directly +instead of the removed local Claude CLI path. + + +## Sessions + +- If the CLI supports sessions, set `sessionArg` (e.g. `--session-id`) or + `sessionArgs` (placeholder `{sessionId}`) when the ID needs to be inserted + into multiple flags. +- If the CLI uses a **resume subcommand** with different flags, set + `resumeArgs` (replaces `args` when resuming) and optionally `resumeOutput` + (for non-JSON resumes). +- `sessionMode`: + - `always`: always send a session id (new UUID if none stored). + - `existing`: only send a session id if one was stored before. + - `none`: never send a session id. + +Serialization notes: + +- `serialize: true` keeps same-lane runs ordered. +- Most CLIs serialize on one provider lane. +- OpenClaw drops stored CLI session reuse when the backend auth state changes, including relogin, token rotation, or a changed auth profile credential. + +## Images (pass-through) + +If your CLI accepts image paths, set `imageArg`: + +```json5 +imageArg: "--image", +imageMode: "repeat" +``` + +OpenClaw will write base64 images to temp files. If `imageArg` is set, those +paths are passed as CLI args. If `imageArg` is missing, OpenClaw appends the +file paths to the prompt (path injection), which is enough for CLIs that auto- +load local files from plain paths. + +## Inputs / outputs + +- `output: "json"` (default) tries to parse JSON and extract text + session id. +- For Gemini CLI JSON output, OpenClaw reads reply text from `response` and + usage from `stats` when `usage` is missing or empty. +- `output: "jsonl"` parses JSONL streams (for example Codex CLI `--json`) and extracts the final agent message plus session + identifiers when present. +- `output: "text"` treats stdout as the final response. + +Input modes: + +- `input: "arg"` (default) passes the prompt as the last CLI arg. +- `input: "stdin"` sends the prompt via stdin. +- If the prompt is very long and `maxPromptArgChars` is set, stdin is used. + +## Defaults (plugin-owned) + +The bundled OpenAI plugin also registers a default for `codex-cli`: + +- `command: "codex"` +- `args: ["exec","--json","--color","never","--sandbox","workspace-write","--skip-git-repo-check"]` +- `resumeArgs: ["exec","resume","{sessionId}","--color","never","--sandbox","workspace-write","--skip-git-repo-check"]` +- `output: "jsonl"` +- `resumeOutput: "text"` +- `modelArg: "--model"` +- `imageArg: "--image"` +- `sessionMode: "existing"` + +The bundled Google plugin also registers a default for `google-gemini-cli`: + +- `command: "gemini"` +- `args: ["--prompt", "--output-format", "json"]` +- `resumeArgs: ["--resume", "{sessionId}", "--prompt", "--output-format", "json"]` +- `modelArg: "--model"` +- `sessionMode: "existing"` +- `sessionIdFields: ["session_id", "sessionId"]` + +Prerequisite: the local Gemini CLI must be installed and available as +`gemini` on `PATH` (`brew install gemini-cli` or +`npm install -g @google/gemini-cli`). + +Gemini CLI JSON notes: + +- Reply text is read from the JSON `response` field. +- Usage falls back to `stats` when `usage` is absent or empty. +- `stats.cached` is normalized into OpenClaw `cacheRead`. +- If `stats.input` is missing, OpenClaw derives input tokens from + `stats.input_tokens - stats.cached`. + +Override only if needed (common: absolute `command` path). + +## Plugin-owned defaults + +CLI backend defaults are now part of the plugin surface: + +- Plugins register them with `api.registerCliBackend(...)`. +- The backend `id` becomes the provider prefix in model refs. +- User config in `agents.defaults.cliBackends.` still overrides the plugin default. +- Backend-specific config cleanup stays plugin-owned through the optional + `normalizeConfig` hook. + +## Bundle MCP overlays + +CLI backends do **not** receive OpenClaw tool calls directly, but a backend can +opt into a generated MCP config overlay with `bundleMcp: true`. + +Current bundled behavior: + +- `codex-cli`: no bundle MCP overlay +- `google-gemini-cli`: no bundle MCP overlay + +When bundle MCP is enabled, OpenClaw: + +- spawns a loopback HTTP MCP server that exposes gateway tools to the CLI process +- authenticates the bridge with a per-session token (`OPENCLAW_MCP_TOKEN`) +- scopes tool access to the current session, account, and channel context +- loads enabled bundle-MCP servers for the current workspace +- merges them with any existing backend `--mcp-config` +- rewrites the CLI args to pass `--strict-mcp-config --mcp-config ` + +If no MCP servers are enabled, OpenClaw still injects a strict config when a +backend opts into bundle MCP so background runs stay isolated. + +## Limitations + +- **No direct OpenClaw tool calls.** OpenClaw does not inject tool calls into + the CLI backend protocol. Backends only see gateway tools when they opt into + `bundleMcp: true`. +- **Streaming is backend-specific.** Some backends stream JSONL; others buffer + until exit. +- **Structured outputs** depend on the CLI’s JSON format. +- **Codex CLI sessions** resume via text output (no JSONL), which is less + structured than the initial `--json` run. OpenClaw sessions still work + normally. + +## Troubleshooting + +- **CLI not found**: set `command` to a full path. +- **Wrong model name**: use `modelAliases` to map `provider/model` → CLI model. +- **No session continuity**: ensure `sessionArg` is set and `sessionMode` is not + `none` (Codex CLI currently cannot resume with JSON output). +- **Images ignored**: set `imageArg` (and verify CLI supports file paths). diff --git a/docs/gateway/configuration-reference.md b/docs/gateway/configuration-reference.md index ad80794ea..b11f34ba1 100644 --- a/docs/gateway/configuration-reference.md +++ b/docs/gateway/configuration-reference.md @@ -1082,6 +1082,37 @@ Z.AI GLM-4.x models automatically enable thinking mode unless you set `--thinkin Z.AI models enable `tool_stream` by default for tool call streaming. Set `agents.defaults.models["zai/"].params.tool_stream` to `false` to disable it. Anthropic Claude 4.6 models default to `adaptive` thinking when no explicit thinking level is set. +### `agents.defaults.cliBackends` + +Optional CLI backends for text-only fallback runs (no tool calls). Useful as a backup when API providers fail. + +```json5 +{ + agents: { + defaults: { + cliBackends: { + "codex-cli": { + command: "/opt/homebrew/bin/codex", + }, + "my-cli": { + command: "my-cli", + args: ["--json"], + output: "json", + modelArg: "--model", + sessionArg: "--session", + sessionMode: "existing", + systemPromptArg: "--system", + systemPromptWhen: "first", + imageArg: "--image", + imageMode: "repeat", + }, + }, + }, + }, +} +``` + +- CLI backends are text-first; tools are always disabled. - Sessions supported when `sessionArg` is set. - Image pass-through supported when `imageArg` accepts file paths. diff --git a/docs/gateway/doctor.md b/docs/gateway/doctor.md index c08ce6008..de793c4f7 100644 --- a/docs/gateway/doctor.md +++ b/docs/gateway/doctor.md @@ -315,7 +315,7 @@ skips refresh attempts. Doctor also detects stale removed Anthropic Claude CLI state. If old `anthropic:claude-cli` credential bytes still exist in `auth-profiles.json`, doctor converts them back into Anthropic token/OAuth profiles and rewrites -stale `claude-cli/...` model refs. +stale `claude-cli/...` model refs plus `agents.defaults.cliBackends.claude-cli`. If the bytes are gone, doctor removes the stale config and prints recovery commands instead. diff --git a/docs/help/faq.md b/docs/help/faq.md index c2a2fb21c..e5ef075c2 100644 --- a/docs/help/faq.md +++ b/docs/help/faq.md @@ -675,11 +675,17 @@ for usage/billing and raise limits as needed. Gemini CLI uses a **plugin auth flow**, not a client id or secret in `openclaw.json`. - Use the Gemini API provider instead: + Steps: - 1. Enable the plugin: `openclaw plugins enable google` - 2. Run `openclaw onboard --auth-choice gemini-api-key` - 3. Set a Google model such as `google/gemini-3.1-pro-preview` + 1. Install Gemini CLI locally so `gemini` is on `PATH` + - Homebrew: `brew install gemini-cli` + - npm: `npm install -g @google/gemini-cli` + 2. Enable the plugin: `openclaw plugins enable google` + 3. Login: `openclaw models auth login --provider google-gemini-cli --set-default` + 4. Default model after login: `google-gemini-cli/gemini-3.1-pro-preview` + 5. If requests fail, set `GOOGLE_CLOUD_PROJECT` or `GOOGLE_CLOUD_PROJECT_ID` on the gateway host + + This stores OAuth tokens in auth profiles on the gateway host. Details: [Model providers](/concepts/model-providers). diff --git a/docs/help/testing.md b/docs/help/testing.md index 25d5b108b..4c30e0a95 100644 --- a/docs/help/testing.md +++ b/docs/help/testing.md @@ -196,7 +196,7 @@ Live tests are split into two layers so we can isolate failures: - `OPENCLAW_LIVE_MODELS=all` is an alias for the modern allowlist - or `OPENCLAW_LIVE_MODELS="openai/gpt-5.4,anthropic/claude-opus-4-6,..."` (comma allowlist) - How to select providers: - - `OPENCLAW_LIVE_PROVIDERS="google,google-antigravity"` (comma allowlist) + - `OPENCLAW_LIVE_PROVIDERS="google,google-antigravity,google-gemini-cli"` (comma allowlist) - Where keys come from: - By default: profile store and env fallbacks - Set `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` to enforce **profile store** only @@ -227,7 +227,7 @@ Live tests are split into two layers so we can isolate failures: - `OPENCLAW_LIVE_GATEWAY_MODELS=all` is an alias for the modern allowlist - Or set `OPENCLAW_LIVE_GATEWAY_MODELS="provider/model"` (or comma list) to narrow - How to select providers (avoid “OpenRouter everything”): - - `OPENCLAW_LIVE_GATEWAY_PROVIDERS="google,google-antigravity,openai,anthropic,zai,minimax"` (comma allowlist) + - `OPENCLAW_LIVE_GATEWAY_PROVIDERS="google,google-antigravity,google-gemini-cli,openai,anthropic,zai,minimax"` (comma allowlist) - Tool + image probes are always on in this live test: - `read` probe + `exec+read` probe (tool stress) - image probe runs when the model advertises image input support @@ -245,6 +245,46 @@ openclaw models list openclaw models list --json ``` +## Live: CLI backend smoke (Codex CLI or other local CLIs) + +- Test: `src/gateway/gateway-cli-backend.live.test.ts` +- Goal: validate the Gateway + agent pipeline using a local CLI backend, without touching your default config. +- Enable: + - `pnpm test:live` (or `OPENCLAW_LIVE_TEST=1` if invoking Vitest directly) + - `OPENCLAW_LIVE_CLI_BACKEND=1` +- Defaults: + - Model: `codex-cli/gpt-5.4` + - Command: `codex` + - Args: `["exec","--json","--color","never","--sandbox","read-only","--skip-git-repo-check"]` +- Overrides (optional): + - `OPENCLAW_LIVE_CLI_BACKEND_MODEL="codex-cli/gpt-5.4"` + - `OPENCLAW_LIVE_CLI_BACKEND_COMMAND="/full/path/to/codex"` + - `OPENCLAW_LIVE_CLI_BACKEND_ARGS='["exec","--json","--color","never","--sandbox","read-only","--skip-git-repo-check"]'` + - `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_PROBE=1` to send a real image attachment (paths are injected into the prompt). + - `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_ARG="--image"` to pass image file paths as CLI args instead of prompt injection. + - `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE="repeat"` (or `"list"`) to control how image args are passed when `IMAGE_ARG` is set. + - `OPENCLAW_LIVE_CLI_BACKEND_RESUME_PROBE=1` to send a second turn and validate resume flow. + +Example: + +```bash +OPENCLAW_LIVE_CLI_BACKEND=1 \ + OPENCLAW_LIVE_CLI_BACKEND_MODEL="codex-cli/gpt-5.4" \ + pnpm test:live src/gateway/gateway-cli-backend.live.test.ts +``` + +Docker recipe: + +```bash +pnpm test:docker:live-cli-backend +``` + +Notes: + +- The Docker runner lives at `scripts/test-live-cli-backend-docker.sh`. +- It runs the live CLI-backend smoke inside the repo Docker image as the non-root `node` user. +- For `codex-cli`, it installs the Linux `@openai/codex` package into a cached writable prefix at `OPENCLAW_DOCKER_CLI_TOOLS_DIR` (default: `~/.cache/openclaw/docker-cli-tools`). + ## Live: ACP bind smoke (`/acp spawn ... --bind here`) - Test: `src/gateway/gateway-acp-bind.live.test.ts` @@ -309,6 +349,10 @@ Notes: - `google/...` uses the Gemini API (API key). - `google-antigravity/...` uses the Antigravity OAuth bridge (Cloud Code Assist-style agent endpoint). +- `google-gemini-cli/...` uses the local Gemini CLI on your machine (separate auth + tooling quirks). +- Gemini API vs Gemini CLI: + - API: OpenClaw calls Google’s hosted Gemini API over HTTP (API key / profile auth); this is what most users mean by “Gemini”. + - CLI: OpenClaw shells out to a local `gemini` binary; it has its own auth and can behave differently (streaming/tool support/version skew). ## Live: model matrix (what we cover) @@ -359,7 +403,7 @@ If you have keys enabled, we also support testing via: More providers you can include in the live matrix (if you have creds/config): -- Built-in: `openai`, `openai-codex`, `anthropic`, `google`, `google-vertex`, `google-antigravity`, `zai`, `openrouter`, `opencode`, `opencode-go`, `xai`, `groq`, `cerebras`, `mistral`, `github-copilot` +- Built-in: `openai`, `openai-codex`, `anthropic`, `google`, `google-vertex`, `google-antigravity`, `google-gemini-cli`, `zai`, `openrouter`, `opencode`, `opencode-go`, `xai`, `groq`, `cerebras`, `mistral`, `github-copilot` - Via `models.providers` (custom endpoints): `minimax` (cloud/API), plus any OpenAI/Anthropic-compatible proxy (LM Studio, vLLM, LiteLLM, etc.) Tip: don’t try to hardcode “all models” in docs. The authoritative list is whatever `discoverModels(...)` returns on your machine + whatever keys are available. @@ -454,6 +498,7 @@ The live-model Docker runners also bind-mount only the needed CLI auth homes (or - Direct models: `pnpm test:docker:live-models` (script: `scripts/test-live-models-docker.sh`) - ACP bind smoke: `pnpm test:docker:live-acp-bind` (script: `scripts/test-live-acp-bind-docker.sh`) +- CLI backend smoke: `pnpm test:docker:live-cli-backend` (script: `scripts/test-live-cli-backend-docker.sh`) - Gateway + dev agent: `pnpm test:docker:live-gateway` (script: `scripts/test-live-gateway-models-docker.sh`) - Open WebUI live smoke: `pnpm test:docker:openwebui` (script: `scripts/e2e/openwebui-docker.sh`) - Onboarding wizard (TTY, full scaffolding): `pnpm test:docker:onboard` (script: `scripts/e2e/onboard-docker.sh`) diff --git a/docs/plugins/architecture.md b/docs/plugins/architecture.md index 583b43ad5..673da4a5f 100644 --- a/docs/plugins/architecture.md +++ b/docs/plugins/architecture.md @@ -30,6 +30,7 @@ native OpenClaw plugin registers against one or more capability types: | Capability | Registration method | Example plugins | | ---------------------- | ------------------------------------------------ | ------------------------------------ | | Text inference | `api.registerProvider(...)` | `openai`, `anthropic` | +| CLI inference backend | `api.registerCliBackend(...)` | `openai`, `anthropic` | | Speech | `api.registerSpeechProvider(...)` | `elevenlabs`, `microsoft` | | Realtime transcription | `api.registerRealtimeTranscriptionProvider(...)` | `openai` | | Realtime voice | `api.registerRealtimeVoiceProvider(...)` | `openai` | diff --git a/docs/plugins/building-plugins.md b/docs/plugins/building-plugins.md index 1b71b8076..0ebfde9ca 100644 --- a/docs/plugins/building-plugins.md +++ b/docs/plugins/building-plugins.md @@ -151,6 +151,7 @@ A single plugin can register any number of capabilities via the `api` object: | Capability | Registration method | Detailed guide | | ---------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------- | | Text inference (LLM) | `api.registerProvider(...)` | [Provider Plugins](/plugins/sdk-provider-plugins) | +| CLI inference backend | `api.registerCliBackend(...)` | [CLI Backends](/gateway/cli-backends) | | Channel / messaging | `api.registerChannel(...)` | [Channel Plugins](/plugins/sdk-channel-plugins) | | Speech (TTS/STT) | `api.registerSpeechProvider(...)` | [Provider Plugins](/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) | | Realtime transcription | `api.registerRealtimeTranscriptionProvider(...)` | [Provider Plugins](/plugins/sdk-provider-plugins#step-5-add-extra-capabilities) | diff --git a/docs/plugins/manifest.md b/docs/plugins/manifest.md index 256117d22..986325277 100644 --- a/docs/plugins/manifest.md +++ b/docs/plugins/manifest.md @@ -89,6 +89,7 @@ Those belong in your plugin code and `package.json`. "modelSupport": { "modelPrefixes": ["router-"] }, + "cliBackends": ["openrouter-cli"], "providerAuthEnvVars": { "openrouter": ["OPENROUTER_API_KEY"] }, @@ -139,6 +140,7 @@ Those belong in your plugin code and `package.json`. | `channels` | No | `string[]` | Channel ids owned by this plugin. Used for discovery and config validation. | | `providers` | No | `string[]` | Provider ids owned by this plugin. | | `modelSupport` | No | `object` | Manifest-owned shorthand model-family metadata used to auto-load the plugin before runtime. | +| `cliBackends` | No | `string[]` | CLI inference backend ids owned by this plugin. Used for startup auto-activation from explicit config refs. | | `providerAuthEnvVars` | No | `Record` | Cheap provider-auth env metadata that OpenClaw can inspect without loading plugin code. | | `providerAuthChoices` | No | `object[]` | Cheap auth-choice metadata for onboarding pickers, preferred-provider resolution, and simple CLI flag wiring. | | `contracts` | No | `object` | Static bundled capability snapshot for speech, realtime transcription, realtime voice, media-understanding, image-generation, music-generation, video-generation, web-fetch, web search, and tool ownership. | @@ -443,7 +445,7 @@ See [Configuration reference](/gateway/configuration) for the full `plugins.*` s - `kind: "memory"` is selected by `plugins.slots.memory`. - `kind: "context-engine"` is selected by `plugins.slots.contextEngine` (default: built-in `legacy`). -- `channels`, `providers`, and `skills` can be omitted when a +- `channels`, `providers`, `cliBackends`, and `skills` can be omitted when a plugin does not need them. - If your plugin depends on native modules, document the build steps and any package-manager allowlist requirements (for example, pnpm `allow-build-scripts` diff --git a/docs/plugins/sdk-overview.md b/docs/plugins/sdk-overview.md index dfdcdd094..d91f00e8f 100644 --- a/docs/plugins/sdk-overview.md +++ b/docs/plugins/sdk-overview.md @@ -122,6 +122,7 @@ explicitly promotes one as public. | `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` | | `plugin-sdk/provider-setup` | Curated local/self-hosted provider setup helpers | | `plugin-sdk/self-hosted-provider-setup` | Focused OpenAI-compatible self-hosted provider setup helpers | + | `plugin-sdk/cli-backend` | CLI backend defaults + watchdog constants | | `plugin-sdk/provider-auth-runtime` | Runtime API-key resolution helpers for provider plugins | | `plugin-sdk/provider-auth-api-key` | API-key onboarding/profile-write helpers such as `upsertApiKeyProfile` | | `plugin-sdk/provider-auth-result` | Standard OAuth auth-result builder | @@ -292,6 +293,7 @@ methods: | Method | What it registers | | ------------------------------------------------ | -------------------------------- | | `api.registerProvider(...)` | Text inference (LLM) | +| `api.registerCliBackend(...)` | Local CLI inference backend | | `api.registerChannel(...)` | Messaging channel | | `api.registerSpeechProvider(...)` | Text-to-speech / STT synthesis | | `api.registerRealtimeTranscriptionProvider(...)` | Streaming realtime transcription | @@ -362,6 +364,18 @@ Use `commands` by itself only when you do not need lazy root CLI registration. That eager compatibility path remains supported, but it does not install descriptor-backed placeholders for parse-time lazy loading. +### CLI backend registration + +`api.registerCliBackend(...)` lets a plugin own the default config for a local +AI CLI backend such as `codex-cli`. + +- The backend `id` becomes the provider prefix in model refs like `codex-cli/gpt-5`. +- The backend `config` uses the same shape as `agents.defaults.cliBackends.`. +- User config still wins. OpenClaw merges `agents.defaults.cliBackends.` over the + plugin default before running the CLI. +- Use `normalizeConfig` when a backend needs compatibility rewrites after merge + (for example normalizing old flag shapes). + ### Exclusive slots | Method | What it registers | diff --git a/docs/plugins/sdk-provider-plugins.md b/docs/plugins/sdk-provider-plugins.md index dfeaed8a6..bf9e38bd7 100644 --- a/docs/plugins/sdk-provider-plugins.md +++ b/docs/plugins/sdk-provider-plugins.md @@ -283,7 +283,7 @@ API key auth, and dynamic model resolution. Real bundled examples: - - `google`: `google-gemini` + - `google` and `google-gemini-cli`: `google-gemini` - `openrouter`, `kilocode`, `opencode`, and `opencode-go`: `passthrough-gemini` - `amazon-bedrock` and `anthropic-vertex`: `anthropic-by-model` - `minimax`: `hybrid-anthropic-openai` @@ -303,7 +303,7 @@ API key auth, and dynamic model resolution. Real bundled examples: - - `google`: `google-thinking` + - `google` and `google-gemini-cli`: `google-thinking` - `kilocode`: `kilocode-thinking` - `moonshot`: `moonshot-thinking` - `minimax` and `minimax-portal`: `minimax-fast-mode` diff --git a/docs/providers/anthropic.md b/docs/providers/anthropic.md index 678649960..a6c4011a6 100644 --- a/docs/providers/anthropic.md +++ b/docs/providers/anthropic.md @@ -225,6 +225,8 @@ The bundled Anthropic `claude-cli` backend was removed. - The same OpenClaw-like system prompt does not hit that guard on the Anthropic SDK + `ANTHROPIC_API_KEY` path. - Use Anthropic API keys for Anthropic traffic in OpenClaw. +- If you need a local CLI fallback runtime, use another supported CLI backend + such as Codex CLI. See [/gateway/cli-backends](/gateway/cli-backends). ## Notes diff --git a/docs/providers/google.md b/docs/providers/google.md index e8a983349..4d3c60455 100644 --- a/docs/providers/google.md +++ b/docs/providers/google.md @@ -1,9 +1,9 @@ --- title: "Google (Gemini)" -summary: "Google Gemini setup (API key, image generation, media understanding, web search)" +summary: "Google Gemini setup (API key + OAuth, image generation, media understanding, web search)" read_when: - You want to use Google Gemini models with OpenClaw - - You need the API key auth flow + - You need the API key or OAuth auth flow --- # Google (Gemini) @@ -15,6 +15,7 @@ Gemini Grounding. - Provider: `google` - Auth: `GEMINI_API_KEY` or `GOOGLE_API_KEY` - API: Google Gemini API +- Alternative provider: `google-gemini-cli` (OAuth) ## Quick start @@ -45,6 +46,46 @@ openclaw onboard --non-interactive \ --gemini-api-key "$GEMINI_API_KEY" ``` +## OAuth (Gemini CLI) + +An alternative provider `google-gemini-cli` uses PKCE OAuth instead of an API +key. This is an unofficial integration; some users report account +restrictions. Use at your own risk. + +- Default model: `google-gemini-cli/gemini-3.1-pro-preview` +- Alias: `gemini-cli` +- Install prerequisite: local Gemini CLI available as `gemini` + - Homebrew: `brew install gemini-cli` + - npm: `npm install -g @google/gemini-cli` +- Login: + +```bash +openclaw models auth login --provider google-gemini-cli --set-default +``` + +Environment variables: + +- `OPENCLAW_GEMINI_OAUTH_CLIENT_ID` +- `OPENCLAW_GEMINI_OAUTH_CLIENT_SECRET` + +(Or the `GEMINI_CLI_*` variants.) + +If Gemini CLI OAuth requests fail after login, set +`GOOGLE_CLOUD_PROJECT` or `GOOGLE_CLOUD_PROJECT_ID` on the gateway host and +retry. + +If login fails before the browser flow starts, make sure the local `gemini` +command is installed and on `PATH`. OpenClaw supports both Homebrew installs +and global npm installs, including common Windows/npm layouts. + +Gemini CLI JSON usage notes: + +- Reply text comes from the CLI JSON `response` field. +- Usage falls back to `stats` when the CLI leaves `usage` empty. +- `stats.cached` is normalized into OpenClaw `cacheRead`. +- If `stats.input` is missing, OpenClaw derives input tokens from + `stats.input_tokens - stats.cached`. + ## Capabilities | Capability | Supported | @@ -98,8 +139,9 @@ The bundled `google` image-generation provider defaults to - Edit mode: enabled, up to 5 input images - Geometry controls: `size`, `aspectRatio`, and `resolution` -Image generation, media understanding, and Gemini Grounding all stay on the -`google` provider id. +The OAuth-only `google-gemini-cli` provider is a separate text-inference +surface. Image generation, media understanding, and Gemini Grounding stay on +the `google` provider id. To use Google as the default image provider: diff --git a/docs/providers/models.md b/docs/providers/models.md index c18b1e481..cffa65003 100644 --- a/docs/providers/models.md +++ b/docs/providers/models.md @@ -54,6 +54,7 @@ model as `provider/model`. - `anthropic-vertex` - implicit Anthropic on Google Vertex support when Vertex credentials are available; no separate onboarding auth choice - `copilot-proxy` - local VS Code Copilot Proxy bridge; use `openclaw onboard --auth-choice copilot-proxy` +- `google-gemini-cli` - unofficial Gemini CLI OAuth flow; requires a local `gemini` install (`brew install gemini-cli` or `npm install -g @google/gemini-cli`); default model `google-gemini-cli/gemini-3.1-pro-preview`; use `openclaw onboard --auth-choice google-gemini-cli` or `openclaw models auth login --provider google-gemini-cli --set-default` For the full provider catalog (xAI, Groq, Mistral, etc.) and advanced configuration, see [Model providers](/concepts/model-providers). diff --git a/docs/reference/session-management-compaction.md b/docs/reference/session-management-compaction.md index 01219de43..1b22a8cc6 100644 --- a/docs/reference/session-management-compaction.md +++ b/docs/reference/session-management-compaction.md @@ -332,7 +332,7 @@ Notes: - The default prompt/system prompt include a `NO_REPLY` hint to suppress delivery. - The flush runs once per compaction cycle (tracked in `sessions.json`). -- The flush runs only for embedded Pi sessions. +- The flush runs only for embedded Pi sessions (CLI backends skip it). - The flush is skipped when the session workspace is read-only (`workspaceAccess: "ro"` or `"none"`). - See [Memory](/concepts/memory) for the workspace file layout and write patterns. diff --git a/docs/tools/acp-agents.md b/docs/tools/acp-agents.md index 683a3bbe2..d8f7df806 100644 --- a/docs/tools/acp-agents.md +++ b/docs/tools/acp-agents.md @@ -23,10 +23,11 @@ instead of ACP. There are three nearby surfaces that are easy to confuse: -| You want to... | Use this | Notes | -| ---------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------- | -| Run Codex, Claude Code, Gemini CLI, or another external harness _through_ OpenClaw | This page: ACP agents | Chat-bound sessions, `/acp spawn`, `sessions_spawn({ runtime: "acp" })`, background tasks, runtime controls | -| Expose an OpenClaw Gateway session _as_ an ACP server for an editor or client | [`openclaw acp`](/cli/acp) | Bridge mode. IDE/client talks ACP to OpenClaw over stdio/WebSocket | +| You want to... | Use this | Notes | +| ---------------------------------------------------------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| Run Codex, Claude Code, Gemini CLI, or another external harness _through_ OpenClaw | This page: ACP agents | Chat-bound sessions, `/acp spawn`, `sessions_spawn({ runtime: "acp" })`, background tasks, runtime controls | +| Expose an OpenClaw Gateway session _as_ an ACP server for an editor or client | [`openclaw acp`](/cli/acp) | Bridge mode. IDE/client talks ACP to OpenClaw over stdio/WebSocket | +| Reuse a local AI CLI as a text-only fallback model | [CLI Backends](/gateway/cli-backends) | Not ACP. No OpenClaw tools, no ACP controls, no harness runtime | ## Does this work out of the box? @@ -111,9 +112,12 @@ For Claude Code through ACP, the stack is: Important distinction: - ACP Claude is a harness session with ACP controls, session resume, background-task tracking, and optional conversation/thread binding. - For operators, the practical rule is: +- CLI backends are separate text-only local fallback runtimes. See [CLI Backends](/gateway/cli-backends). + +For operators, the practical rule is: - want `/acp spawn`, bindable sessions, runtime controls, or persistent harness work: use ACP +- want simple local text fallback through the raw CLI: use CLI backends ## Bound sessions