Merge remote-tracking branch 'origin/main' into cs/codex-native-web-search-spec

# Conflicts:
#	src/agents/pi-embedded-runner/extra-params.ts
#	src/agents/pi-embedded-runner/openai-stream-wrappers.ts
This commit is contained in:
Christof Salis 2026-03-17 06:25:55 +01:00
commit e1e51171b0
926 changed files with 21587 additions and 13022 deletions

View File

@ -42,10 +42,13 @@ pnpm test:parallels:macos \
## Notes
- Snapshot target: closest to `macOS 26.3.1 fresh`.
- Snapshot resolver now prefers matching `*-poweroff*` clones when the base hint also matches. That lets the harness reuse disk-only recovery snapshots without passing a longer hint.
- If Windows/Linux snapshot restore logs show `PET_QUESTION_SNAPSHOT_STATE_INCOMPATIBLE_CPU`, drop the suspended state once, create a `*-poweroff*` replacement snapshot, and rerun. The smoke scripts now auto-start restored power-off snapshots.
- Harness configures Discord inside the guest; no checked-in token/config.
- Use the `openclaw` wrapper for guest `message send/read`; `node openclaw.mjs message ...` does not expose the lazy message subcommands the same way.
- Write `channels.discord.guilds` in one JSON object (`--strict-json`), not dotted `config set channels.discord.guilds.<snowflake>...` paths; numeric snowflakes get treated like array indexes.
- Avoid `prlctl enter` / expect for long Discord setup scripts; it line-wraps/corrupts long commands. Use `prlctl exec --current-user /bin/sh -lc ...` for the Discord config phase.
- Full 3-OS sweeps: the shared build lock is safe in parallel, but snapshot restore is still a Parallels bottleneck. Prefer serialized Windows/Linux restore-heavy reruns if the host is already under load.
- Harness cleanup deletes the temporary Discord smoke messages at exit.
- Per-phase logs: `/tmp/openclaw-parallels-smoke.*`
- Machine summary: pass `--json`

View File

@ -206,6 +206,9 @@ jobs:
- runtime: node
task: channels
command: pnpm test:channels
- runtime: node
task: contracts
command: pnpm test:contracts
- runtime: node
task: protocol
command: pnpm protocol:check

View File

@ -30,6 +30,8 @@ Docs: https://docs.openclaw.ai
- secrets: harden read-only SecretRef command paths and diagnostics. (#47794) Thanks @joshavant.
- Browser/existing-session: support `browser.profiles.<name>.userDataDir` so Chrome DevTools MCP can attach to Brave, Edge, and other Chromium-based browsers through their own user data directories. (#48170) Thanks @velvet-shark.
- Skills/prompt budget: preserve all registered skills via a compact catalog fallback before dropping entries when the full prompt format exceeds `maxSkillsPromptChars`. (#47553) Thanks @snese.
- Plugins/bundles: make enabled bundle MCP servers expose runnable tools in embedded Pi, and default relative bundle MCP launches to the bundle root so marketplace bundles like Context7 work through Pi instead of stopping at config import.
- Scope message SecretRef resolution and harden doctor/status paths. (#48728) Thanks @joshavant.
### Breaking
@ -78,6 +80,7 @@ Docs: https://docs.openclaw.ai
- Z.AI/onboarding: add `glm-5-turbo` to the default Z.AI provider catalog so onboarding-generated configs expose the new model alongside the existing GLM defaults. (#46670) Thanks @tomsun28.
- Zalo Personal/group gating: stop reapplying `dmPolicy.allowFrom` as a sender gate for already-allowlisted groups when `groupAllowFrom` is unset, so any member of an allowed group can trigger replies while DMs stay restricted. (#46663) Fixes #40146. Thanks @Takhoffman.
- Zalo/plugin runtime: export `resolveClientIp` from `openclaw/plugin-sdk/zalo` so installed builds no longer crash on startup when the webhook monitor loads from the packaged extension instead of the monorepo source tree. (#46549) Thanks @No898.
- Docker/live tests: mount external CLI auth homes into writable container copies, derive Codex OAuth expiry from JWT `exp`, refresh synced CLI creds instead of trusting stale cached expiry, and make gateway live probes wait on transcript output so `pnpm test:docker:all` stays green in Linux.
- Plugins/install precedence: keep bundled plugins ahead of auto-discovered globals by default, but let an explicitly installed plugin record win its own duplicate-id tie so installed channel plugins load from `~/.openclaw/extensions` after `openclaw plugins install`. (#46722) Thanks @Takhoffman.
- Control UI/logging: make browser-safe logger imports avoid eager temp-dir resolution so the bundled Control UI no longer crashes to a blank screen when logging reaches `tmp-openclaw-dir`. (#48469) Fixes #48062. Thanks @7inspire.
- Plugins/scoped ids: preserve scoped plugin ids during install and config keying, and keep bundled plugins ahead of discovered duplicate ids by default so `@scope/name` plugins no longer collide with unscoped installs. (#47413) Thanks @vincentkoc.
@ -105,6 +108,8 @@ Docs: https://docs.openclaw.ai
- Agents/usage tracking: stop forcing `supportsUsageInStreaming: false` on non-native OpenAI-completions providers so compatible backends report token usage and cost again instead of showing all zeros. (#46500) Fixes #46142. Thanks @ademczuk.
- Plugins/subagents: preserve gateway-owned plugin subagent access across runtime, tool, and embedded-runner load paths so gateway plugin tools and context engines can still spawn and manage subagents after the loader cache split. (#46648) Thanks @jalehman.
- Control UI/overview: keep the language dropdown aligned with the persisted locale during dashboard startup so refreshing the page does not fall back to English before locale hydration completes. (#48019) Thanks @git-jxj.
- Agents/compaction: rerun transcript repair after `session.compact()` so orphaned `tool_result` blocks cannot survive compaction and break later Anthropic requests. (#16095) thanks @claw-sylphx.
- Agents/compaction: trigger overflow recovery from the tool-result guard once post-compaction context still exceeds the safe threshold, so long tool loops compact before the next model call hard-fails. (#29371) thanks @keshav55.
## 2026.3.13
@ -183,7 +188,6 @@ Docs: https://docs.openclaw.ai
- Auth/login lockout recovery: clear stale `auth_permanent` and `billing` disabled state for all profiles matching the target provider when `openclaw models auth login` is invoked, so users locked out by expired or revoked OAuth tokens can recover by re-authenticating instead of waiting for the cooldown timer to expire. (#43057)
- Auto-reply/context-engine compaction: persist the exact embedded-run metadata compaction count for main and followup runner session accounting, so metadata-only auto-compactions no longer undercount multi-compaction runs. (#42629) thanks @uf-hy.
- Auth/Codex CLI reuse: sync reused Codex CLI credentials into the supported `openai-codex:default` OAuth profile instead of reviving the deprecated `openai-codex:codex-cli` slot, so doctor cleanup no longer loops. (#45353) thanks @Gugu-sugar.
- WhatsApp/group replies: recognize implicit reply-to-bot mentions when WhatsApp sends the quoted sender in `@lid` format, including device-suffixed self identities. (#23029) Thanks @sparkyrider.
## 2026.3.12
@ -276,6 +280,9 @@ Docs: https://docs.openclaw.ai
- Docs/Brave pricing: escape literal dollar signs in Brave Search cost text so the docs render the free credit and per-request pricing correctly. (#44989) Thanks @keelanfh.
- Feishu/file uploads: preserve literal UTF-8 filenames in `im.file.create` so Chinese and other non-ASCII filenames no longer appear percent-encoded in chat. (#34262) Thanks @fabiaodemianyang and @KangShuaiFu.
- Agents/compaction safeguard: trim large kept `toolResult` payloads consistently for budgeting, pruning, and identifier seeding, then restore preserved payloads after prune so oversized safeguard summaries stay stable. (#44133) thanks @SayrWolfridge.
- Agents/compaction: compare post-compaction token sanity checks against full-session pre-compaction totals and skip the check when token estimation fails, so sessions with large bootstrap context keep real token counts instead of falling back to unknown. (#28347) thanks @efe-arv.
- Discord/gateway startup: treat plain-text and transient `/gateway/bot` metadata fetch failures as transient startup errors so Discord gateway boot no longer crashes on unhandled rejections. (#44397) Thanks @jalehman.
- Agents/Ollama overflow: rewrite Ollama `prompt too long` API payloads through the normal context-overflow sanitizer so embedded sessions keep the friendly overflow copy and auto-compaction trigger. (#34019) thanks @lishuaigit.
## 2026.3.11

View File

@ -91,7 +91,9 @@ Welcome to the lobster tank! 🦞
- Run tests: `pnpm build && pnpm check && pnpm test`
- For extension/plugin changes, run the fast local lane first:
- `pnpm test:extension <extension-name>`
- If you changed shared plugin or channel surfaces, still run the broader relevant lanes (`pnpm test:extensions`, `pnpm test:channels`, or `pnpm test`) before asking for review
- `pnpm test:extension --list` to see valid extension ids
- If you changed shared plugin or channel surfaces, run `pnpm test:contracts`
- If you changed broader runtime behavior, still run the relevant wider lanes (`pnpm test:extensions`, `pnpm test:channels`, or `pnpm test`) before asking for review
- If you have access to Codex, run `codex review --base origin/main` locally before opening or updating your PR. Treat this as the current highest standard of AI review, even if GitHub Codex review also runs.
- Ensure CI checks pass
- Keep PRs focused (one thing per PR; do not mix unrelated concerns)

View File

@ -23,10 +23,10 @@ It answers you on the channels you already use (WhatsApp, Telegram, Slack, Disco
If you want a personal, single-user assistant that feels local, fast, and always-on, this is it.
[Website](https://openclaw.ai) · [Docs](https://docs.openclaw.ai) · [Vision](VISION.md) · [DeepWiki](https://deepwiki.com/openclaw/openclaw) · [Getting Started](https://docs.openclaw.ai/start/getting-started) · [Updating](https://docs.openclaw.ai/install/updating) · [Showcase](https://docs.openclaw.ai/start/showcase) · [FAQ](https://docs.openclaw.ai/help/faq) · [Wizard](https://docs.openclaw.ai/start/wizard) · [Nix](https://github.com/openclaw/nix-openclaw) · [Docker](https://docs.openclaw.ai/install/docker) · [Discord](https://discord.gg/clawd)
[Website](https://openclaw.ai) · [Docs](https://docs.openclaw.ai) · [Vision](VISION.md) · [DeepWiki](https://deepwiki.com/openclaw/openclaw) · [Getting Started](https://docs.openclaw.ai/start/getting-started) · [Updating](https://docs.openclaw.ai/install/updating) · [Showcase](https://docs.openclaw.ai/start/showcase) · [FAQ](https://docs.openclaw.ai/help/faq) · [Onboarding](https://docs.openclaw.ai/start/wizard) · [Nix](https://github.com/openclaw/nix-openclaw) · [Docker](https://docs.openclaw.ai/install/docker) · [Discord](https://discord.gg/clawd)
Preferred setup: run the onboarding wizard (`openclaw onboard`) in your terminal.
The wizard guides you step by step through setting up the gateway, workspace, channels, and skills. The CLI wizard is the recommended path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**.
Preferred setup: run `openclaw onboard` in your terminal.
OpenClaw Onboard guides you step by step through setting up the gateway, workspace, channels, and skills. It is the recommended CLI setup path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**.
Works with npm, pnpm, or bun.
New install? Start here: [Getting started](https://docs.openclaw.ai/start/getting-started)
@ -58,7 +58,7 @@ npm install -g openclaw@latest
openclaw onboard --install-daemon
```
The wizard installs the Gateway daemon (launchd/systemd user service) so it stays running.
OpenClaw Onboard installs the Gateway daemon (launchd/systemd user service) so it stays running.
## Quick start (TL;DR)
@ -132,7 +132,7 @@ Run `openclaw doctor` to surface risky/misconfigured DM policies.
- **[Live Canvas](https://docs.openclaw.ai/platforms/mac/canvas)** — agent-driven visual workspace with [A2UI](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui).
- **[First-class tools](https://docs.openclaw.ai/tools)** — browser, canvas, nodes, cron, sessions, and Discord/Slack actions.
- **[Companion apps](https://docs.openclaw.ai/platforms/macos)** — macOS menu bar app + iOS/Android [nodes](https://docs.openclaw.ai/nodes).
- **[Onboarding](https://docs.openclaw.ai/start/wizard) + [skills](https://docs.openclaw.ai/tools/skills)** — wizard-driven setup with bundled/managed/workspace skills.
- **[Onboarding](https://docs.openclaw.ai/start/wizard) + [skills](https://docs.openclaw.ai/tools/skills)** — onboarding-driven setup with bundled/managed/workspace skills.
## Star History
@ -143,7 +143,7 @@ Run `openclaw doctor` to surface risky/misconfigured DM policies.
### Core platform
- [Gateway WS control plane](https://docs.openclaw.ai/gateway) with sessions, presence, config, cron, webhooks, [Control UI](https://docs.openclaw.ai/web), and [Canvas host](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui).
- [CLI surface](https://docs.openclaw.ai/tools/agent-send): gateway, agent, send, [wizard](https://docs.openclaw.ai/start/wizard), and [doctor](https://docs.openclaw.ai/gateway/doctor).
- [CLI surface](https://docs.openclaw.ai/tools/agent-send): gateway, agent, send, [onboarding](https://docs.openclaw.ai/start/wizard), and [doctor](https://docs.openclaw.ai/gateway/doctor).
- [Pi agent runtime](https://docs.openclaw.ai/concepts/agent) in RPC mode with tool streaming and block streaming.
- [Session model](https://docs.openclaw.ai/concepts/session): `main` for direct chats, group isolation, activation modes, queue modes, reply-back. Group rules: [Groups](https://docs.openclaw.ai/channels/groups).
- [Media pipeline](https://docs.openclaw.ai/nodes/images): images/audio/video, transcription hooks, size caps, temp file lifecycle. Audio details: [Audio](https://docs.openclaw.ai/nodes/audio).
@ -422,7 +422,7 @@ Use these when youre past the onboarding flow and want the deeper reference.
- [Run the Gateway by the book with the operational runbook.](https://docs.openclaw.ai/gateway)
- [Learn how the Control UI/Web surfaces work and how to expose them safely.](https://docs.openclaw.ai/web)
- [Understand remote access over SSH tunnels or tailnets.](https://docs.openclaw.ai/gateway/remote)
- [Follow the onboarding wizard flow for a guided setup.](https://docs.openclaw.ai/start/wizard)
- [Follow OpenClaw Onboard for a guided setup.](https://docs.openclaw.ai/start/wizard)
- [Wire external triggers via the webhook surface.](https://docs.openclaw.ai/automation/webhook)
- [Set up Gmail Pub/Sub triggers.](https://docs.openclaw.ai/automation/gmail-pubsub)
- [Learn the macOS menu bar companion details.](https://docs.openclaw.ai/platforms/mac/menu-bar)

View File

@ -126,7 +126,7 @@ launchctl load ~/Library/LaunchAgents/com.user.poke-messages.plist
## Onboarding
BlueBubbles is available in the interactive setup wizard:
BlueBubbles is available in interactive onboarding:
```
openclaw onboard

View File

@ -168,7 +168,7 @@ openclaw pairing approve discord <CODE>
<Note>
Token resolution is account-aware. Config token values win over env fallback. `DISCORD_BOT_TOKEN` is only used for the default account.
For advanced outbound calls (message tool/channel actions), an explicit per-call `token` is used for that call. Account policy/retry settings still come from the selected account in the active runtime snapshot.
For advanced outbound calls (message tool/channel actions), an explicit per-call `token` is used for that call. This applies to send and read/probe-style actions (for example read/search/fetch/thread/pins/permissions). Account policy/retry settings still come from the selected account in the active runtime snapshot.
</Note>
## Recommended: Set up a guild workspace

View File

@ -30,9 +30,9 @@ openclaw plugins install @openclaw/feishu
There are two ways to add the Feishu channel:
### Method 1: setup wizard (recommended)
### Method 1: onboarding (recommended)
If you just installed OpenClaw, run the setup wizard:
If you just installed OpenClaw, run onboarding:
```bash
openclaw onboard

View File

@ -16,7 +16,7 @@ Nostr is a decentralized protocol for social networking. This channel enables Op
### Onboarding (recommended)
- The setup wizard (`openclaw onboard`) and `openclaw channels add` list optional channel plugins.
- Onboarding (`openclaw onboard`) and `openclaw channels add` list optional channel plugins.
- Selecting Nostr prompts you to install the plugin on demand.
Install defaults:

View File

@ -115,7 +115,7 @@ Token resolution order is account-aware. In practice, config values win over env
`channels.telegram.allowFrom` accepts numeric Telegram user IDs. `telegram:` / `tg:` prefixes are accepted and normalized.
`dmPolicy: "allowlist"` with empty `allowFrom` blocks all DMs and is rejected by config validation.
The setup wizard accepts `@username` input and resolves it to numeric IDs.
Onboarding accepts `@username` input and resolves it to numeric IDs.
If you upgraded and your config contains `@username` allowlist entries, run `openclaw doctor --fix` to resolve them (best-effort; requires a Telegram bot token).
If you previously relied on pairing-store allowlist files, `openclaw doctor --fix` can recover entries into `channels.telegram.allowFrom` in allowlist flows (for example when `dmPolicy: "allowlist"` has no explicit IDs yet).

View File

@ -32,6 +32,8 @@ Notes:
- Doctor includes a memory-search readiness check and can recommend `openclaw configure --section model` when embedding credentials are missing.
- If sandbox mode is enabled but Docker is unavailable, doctor reports a high-signal warning with remediation (`install Docker` or `openclaw config set agents.defaults.sandbox.mode off`).
- If `gateway.auth.token`/`gateway.auth.password` are SecretRef-managed and unavailable in the current command path, doctor reports a read-only warning and does not write plaintext fallback credentials.
- If channel SecretRef inspection fails in a fix path, doctor continues and reports a warning instead of exiting early.
- Telegram `allowFrom` username auto-resolution (`doctor --fix`) requires a resolvable Telegram token in the current command path. If token inspection is unavailable, doctor reports a warning and skips auto-resolution for that pass.
## macOS: `launchctl` env overrides

View File

@ -318,22 +318,22 @@ Initialize config + workspace.
Options:
- `--workspace <dir>`: agent workspace path (default `~/.openclaw/workspace`).
- `--wizard`: run the setup wizard.
- `--non-interactive`: run wizard without prompts.
- `--mode <local|remote>`: wizard mode.
- `--wizard`: run onboarding.
- `--non-interactive`: run onboarding without prompts.
- `--mode <local|remote>`: onboard mode.
- `--remote-url <url>`: remote Gateway URL.
- `--remote-token <token>`: remote Gateway token.
Wizard auto-runs when any wizard flags are present (`--non-interactive`, `--mode`, `--remote-url`, `--remote-token`).
Onboarding auto-runs when any onboarding flags are present (`--non-interactive`, `--mode`, `--remote-url`, `--remote-token`).
### `onboard`
Interactive wizard to set up gateway, workspace, and skills.
Interactive onboarding for gateway, workspace, and skills.
Options:
- `--workspace <dir>`
- `--reset` (reset config + credentials + sessions before wizard)
- `--reset` (reset config + credentials + sessions before onboarding)
- `--reset-scope <config|config+creds+sessions|full>` (default `config+creds+sessions`; use `full` to also remove workspace)
- `--non-interactive`
- `--mode <local|remote>`

View File

@ -50,6 +50,16 @@ Name lookup:
- `--dry-run`
- `--verbose`
## SecretRef behavior
- `openclaw message` resolves supported channel SecretRefs before running the selected action.
- Resolution is scoped to the active action target when possible:
- channel-scoped when `--channel` is set (or inferred from prefixed targets like `discord:...`)
- account-scoped when `--account` is set (channel globals + selected account surfaces)
- when `--account` is omitted, OpenClaw does not force a `default` account SecretRef scope
- Unresolved SecretRefs on unrelated channels do not block a targeted message action.
- If the selected channel/account SecretRef is unresolved, the command fails closed for that action.
## Actions
### Core

View File

@ -1,5 +1,5 @@
---
summary: "CLI reference for `openclaw onboard` (interactive setup wizard)"
summary: "CLI reference for `openclaw onboard` (interactive onboarding)"
read_when:
- You want guided setup for gateway, workspace, auth, channels, and skills
title: "onboard"
@ -7,11 +7,11 @@ title: "onboard"
# `openclaw onboard`
Interactive setup wizard (local or remote Gateway setup).
Interactive onboarding for local or remote Gateway setup.
## Related guides
- CLI onboarding hub: [Setup Wizard (CLI)](/start/wizard)
- CLI onboarding hub: [Onboarding (CLI)](/start/wizard)
- Onboarding overview: [Onboarding Overview](/start/onboarding-overview)
- CLI onboarding reference: [CLI Setup Reference](/start/wizard-cli-reference)
- CLI automation: [CLI Automation](/start/wizard-cli-automation)

View File

@ -1,7 +1,7 @@
---
summary: "CLI reference for `openclaw setup` (initialize config + workspace)"
read_when:
- Youre doing first-run setup without the full setup wizard
- Youre doing first-run setup without full CLI onboarding
- You want to set the default workspace path
title: "setup"
---
@ -13,7 +13,7 @@ Initialize `~/.openclaw/openclaw.json` and the agent workspace.
Related:
- Getting started: [Getting started](/start/getting-started)
- Wizard: [Onboarding](/start/onboarding)
- CLI onboarding: [Onboarding (CLI)](/start/wizard)
## Examples
@ -22,7 +22,7 @@ openclaw setup
openclaw setup --workspace ~/.openclaw/workspace
```
To run the wizard via setup:
To run onboarding via setup:
```bash
openclaw setup --wizard

View File

@ -27,3 +27,4 @@ Notes:
- Read-only status surfaces (`status`, `status --json`, `status --all`) resolve supported SecretRefs for their targeted config paths when possible.
- If a supported channel SecretRef is configured but unavailable in the current command path, status stays read-only and reports degraded output instead of crashing. Human output shows warnings such as “configured token unavailable in this command path”, and JSON output includes `secretDiagnostics`.
- When command-local SecretRef resolution succeeds, status prefers the resolved snapshot and clears transient “secret unavailable” channel markers from the final output.
- `status --all` includes a Secrets overview row and a diagnosis section that summarizes secret diagnostics (truncated for readability) without stopping report generation.

View File

@ -34,9 +34,9 @@ Related:
- Use fallbacks for cost/latency-sensitive tasks and lower-stakes chat.
- For tool-enabled agents or untrusted inputs, avoid older/weaker model tiers.
## Setup wizard (recommended)
## Onboarding (recommended)
If you dont want to hand-edit config, run the setup wizard:
If you dont want to hand-edit config, run onboarding:
```bash
openclaw onboard

View File

@ -49,7 +49,7 @@ openclaw models status
openclaw doctor
```
If youd rather not manage env vars yourself, the setup wizard can store
If youd rather not manage env vars yourself, onboarding can store
API keys for daemon use: `openclaw onboard`.
See [Help](/help) for details on env inheritance (`env.shellEnv`,

View File

@ -2950,7 +2950,7 @@ Notes:
## Wizard
Metadata written by CLI wizards (`onboard`, `configure`, `doctor`):
Metadata written by CLI guided setup flows (`onboard`, `configure`, `doctor`):
```json5
{

View File

@ -38,7 +38,7 @@ See the [full reference](/gateway/configuration-reference) for every available f
<Tabs>
<Tab title="Interactive wizard">
```bash
openclaw onboard # full setup wizard
openclaw onboard # full onboarding flow
openclaw configure # config wizard
```
</Tab>

View File

@ -738,7 +738,7 @@ In minimal mode, the Gateway still broadcasts enough for device discovery (`role
Gateway auth is **required by default**. If no token/password is configured,
the Gateway refuses WebSocket connections (failclosed).
The setup wizard generates a token by default (even for loopback) so
Onboarding generates a token by default (even for loopback) so
local clients must authenticate.
Set a token so **all** WS clients must authenticate:

View File

@ -36,7 +36,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
- [How do I install OpenClaw on a VPS?](#how-do-i-install-openclaw-on-a-vps)
- [Where are the cloud/VPS install guides?](#where-are-the-cloudvps-install-guides)
- [Can I ask OpenClaw to update itself?](#can-i-ask-openclaw-to-update-itself)
- [What does the setup wizard actually do?](#what-does-the-setup-wizard-actually-do)
- [What does onboarding actually do?](#what-does-onboarding-actually-do)
- [Do I need a Claude or OpenAI subscription to run this?](#do-i-need-a-claude-or-openai-subscription-to-run-this)
- [Can I use Claude Max subscription without an API key](#can-i-use-claude-max-subscription-without-an-api-key)
- [How does Anthropic "setup-token" auth work?](#how-does-anthropic-setuptoken-auth-work)
@ -317,7 +317,7 @@ Install docs: [Install](/install), [Installer flags](/install/installer), [Updat
### What's the recommended way to install and set up OpenClaw
The repo recommends running from source and using the setup wizard:
The repo recommends running from source and using onboarding:
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
@ -627,7 +627,7 @@ More detail: [Install](/install) and [Installer flags](/install/installer).
### How do I install OpenClaw on Linux
Short answer: follow the Linux guide, then run the setup wizard.
Short answer: follow the Linux guide, then run onboarding.
- Linux quick path + service install: [Linux](/platforms/linux).
- Full walkthrough: [Getting Started](/start/getting-started).
@ -685,7 +685,7 @@ openclaw gateway restart
Docs: [Update](/cli/update), [Updating](/install/updating).
### What does the setup wizard actually do
### What does onboarding actually do
`openclaw onboard` is the recommended setup path. In **local mode** it walks you through:
@ -723,7 +723,7 @@ If you want the clearest and safest supported path for production, use an Anthro
### How does Anthropic setuptoken auth work
`claude setup-token` generates a **token string** via the Claude Code CLI (it is not available in the web console). You can run it on **any machine**. Choose **Anthropic token (paste setup-token)** in the wizard or paste it with `openclaw models auth paste-token --provider anthropic`. The token is stored as an auth profile for the **anthropic** provider and used like an API key (no auto-refresh). More detail: [OAuth](/concepts/oauth).
`claude setup-token` generates a **token string** via the Claude Code CLI (it is not available in the web console). You can run it on **any machine**. Choose **Anthropic token (paste setup-token)** in onboarding or paste it with `openclaw models auth paste-token --provider anthropic`. The token is stored as an auth profile for the **anthropic** provider and used like an API key (no auto-refresh). More detail: [OAuth](/concepts/oauth).
### Where do I find an Anthropic setuptoken
@ -733,7 +733,7 @@ It is **not** in the Anthropic Console. The setup-token is generated by the **Cl
claude setup-token
```
Copy the token it prints, then choose **Anthropic token (paste setup-token)** in the wizard. If you want to run it on the gateway host, use `openclaw models auth setup-token --provider anthropic`. If you ran `claude setup-token` elsewhere, paste it on the gateway host with `openclaw models auth paste-token --provider anthropic`. See [Anthropic](/providers/anthropic).
Copy the token it prints, then choose **Anthropic token (paste setup-token)** in onboarding. If you want to run it on the gateway host, use `openclaw models auth setup-token --provider anthropic`. If you ran `claude setup-token` elsewhere, paste it on the gateway host with `openclaw models auth paste-token --provider anthropic`. See [Anthropic](/providers/anthropic).
### Do you support Claude subscription auth (Claude Pro or Max)
@ -767,15 +767,15 @@ Yes - via pi-ai's **Amazon Bedrock (Converse)** provider with **manual config**.
### How does Codex auth work
OpenClaw supports **OpenAI Code (Codex)** via OAuth (ChatGPT sign-in). The wizard can run the OAuth flow and will set the default model to `openai-codex/gpt-5.4` when appropriate. See [Model providers](/concepts/model-providers) and [Wizard](/start/wizard).
OpenClaw supports **OpenAI Code (Codex)** via OAuth (ChatGPT sign-in). Onboarding can run the OAuth flow and will set the default model to `openai-codex/gpt-5.4` when appropriate. See [Model providers](/concepts/model-providers) and [Onboarding (CLI)](/start/wizard).
### Do you support OpenAI subscription auth Codex OAuth
Yes. OpenClaw fully supports **OpenAI Code (Codex) subscription OAuth**.
OpenAI explicitly allows subscription OAuth usage in external tools/workflows
like OpenClaw. The setup wizard can run the OAuth flow for you.
like OpenClaw. Onboarding can run the OAuth flow for you.
See [OAuth](/concepts/oauth), [Model providers](/concepts/model-providers), and [Wizard](/start/wizard).
See [OAuth](/concepts/oauth), [Model providers](/concepts/model-providers), and [Onboarding (CLI)](/start/wizard).
### How do I set up Gemini CLI OAuth
@ -844,7 +844,7 @@ without WhatsApp/Telegram.
`channels.telegram.allowFrom` is **the human sender's Telegram user ID** (numeric). It is not the bot username.
The setup wizard accepts `@username` input and resolves it to a numeric ID, but OpenClaw authorization uses numeric IDs only.
Onboarding accepts `@username` input and resolves it to a numeric ID, but OpenClaw authorization uses numeric IDs only.
Safer (no third-party bot):
@ -1909,7 +1909,7 @@ openclaw onboard --install-daemon
Notes:
- The setup wizard also offers **Reset** if it sees an existing config. See [Wizard](/start/wizard).
- Onboarding also offers **Reset** if it sees an existing config. See [Onboarding (CLI)](/start/wizard).
- If you used profiles (`--profile` / `OPENCLAW_PROFILE`), reset each state dir (defaults are `~/.openclaw-<profile>`).
- Dev reset: `openclaw gateway --dev --reset` (dev-only; wipes dev config + credentials + sessions + workspace).

View File

@ -362,7 +362,7 @@ If you want to rely on env keys (e.g. exported in your `~/.profile`), run local
## Docker runners (optional “works in Linux” checks)
These run `pnpm test:live` inside the repo Docker image, mounting your local config dir and workspace (and sourcing `~/.profile` if mounted). They also bind-mount CLI auth homes like `~/.codex`, `~/.claude`, `~/.qwen`, and `~/.minimax` when present so external-CLI OAuth stays available in-container:
These run `pnpm test:live` inside the repo Docker image, mounting your local config dir and workspace (and sourcing `~/.profile` if mounted). They also bind-mount CLI auth homes like `~/.codex`, `~/.claude`, `~/.qwen`, and `~/.minimax` when present, then copy them into the container home before the run so external-CLI OAuth can refresh tokens without mutating the host auth store:
- Direct models: `pnpm test:docker:live-models` (script: `scripts/test-live-models-docker.sh`)
- Gateway + dev agent: `pnpm test:docker:live-gateway` (script: `scripts/test-live-gateway-models-docker.sh`)
@ -373,6 +373,9 @@ These run `pnpm test:live` inside the repo Docker image, mounting your local con
The live-model Docker runners also bind-mount the current checkout read-only and
stage it into a temporary workdir inside the container. This keeps the runtime
image slim while still running Vitest against your exact local source/config.
`test:docker:live-models` still runs `pnpm test:live`, so pass through
`OPENCLAW_LIVE_GATEWAY_*` as well when you need to narrow or exclude gateway
live coverage from that Docker lane.
Manual ACP plain-language thread smoke (not CI):
@ -384,8 +387,9 @@ Useful env vars:
- `OPENCLAW_CONFIG_DIR=...` (default: `~/.openclaw`) mounted to `/home/node/.openclaw`
- `OPENCLAW_WORKSPACE_DIR=...` (default: `~/.openclaw/workspace`) mounted to `/home/node/.openclaw/workspace`
- `OPENCLAW_PROFILE_FILE=...` (default: `~/.profile`) mounted to `/home/node/.profile` and sourced before running tests
- External CLI auth dirs under `$HOME` (`.codex`, `.claude`, `.qwen`, `.minimax`) are mounted read-only to the matching `/home/node/...` paths when present
- External CLI auth dirs under `$HOME` (`.codex`, `.claude`, `.qwen`, `.minimax`) are mounted read-only under `/host-auth/...`, then copied into `/home/node/...` before tests start
- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` to narrow the run
- `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...` to filter providers in-container
- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` to ensure creds come from the profile store (not env)
## Docs sanity

View File

@ -33,7 +33,7 @@ title: "OpenClaw"
<Card title="Get Started" href="/start/getting-started" icon="rocket">
Install OpenClaw and bring up the Gateway in minutes.
</Card>
<Card title="Run the Wizard" href="/start/wizard" icon="sparkles">
<Card title="Run Onboarding" href="/start/wizard" icon="sparkles">
Guided setup with `openclaw onboard` and pairing flows.
</Card>
<Card title="Open the Control UI" href="/web/control-ui" icon="layout-dashboard">

View File

@ -51,7 +51,7 @@ From repo root:
This script:
- builds the gateway image locally (or pulls a remote image if `OPENCLAW_IMAGE` is set)
- runs the setup wizard
- runs onboarding
- prints optional provider setup hints
- starts the gateway via Docker Compose
- generates a gateway token and writes it to `.env`

View File

@ -33,7 +33,7 @@ For VPS/cloud hosts, avoid third-party "1-click" marketplace images when possibl
<AccordionGroup>
<Accordion title="Installer script" icon="rocket" defaultOpen>
Downloads the CLI, installs it globally via npm, and launches the setup wizard.
Downloads the CLI, installs it globally via npm, and launches onboarding.
<Tabs>
<Tab title="macOS / Linux / WSL2">

View File

@ -21,7 +21,7 @@ and you configure everything via the `/setup` web wizard.
## What you get
- Hosted OpenClaw Gateway + Control UI
- Web setup wizard at `/setup` (no terminal commands)
- Web setup at `/setup` (no terminal commands)
- Persistent storage via Northflank Volume (`/data`) so config/credentials/workspace survive redeploys
## Setup flow
@ -32,7 +32,7 @@ and you configure everything via the `/setup` web wizard.
4. Click **Run setup**.
5. Open the Control UI at `https://<your-northflank-domain>/openclaw`
If Telegram DMs are set to pairing, the setup wizard can approve the pairing code.
If Telegram DMs are set to pairing, web setup can approve the pairing code.
## Getting chat tokens

View File

@ -29,13 +29,13 @@ Railway will either:
Then open:
- `https://<your-railway-domain>/setup` — setup wizard (password protected)
- `https://<your-railway-domain>/setup` — web setup (password protected)
- `https://<your-railway-domain>/openclaw` — Control UI
## What you get
- Hosted OpenClaw Gateway + Control UI
- Web setup wizard at `/setup` (no terminal commands)
- Web setup at `/setup` (no terminal commands)
- Persistent storage via Railway Volume (`/data`) so config/credentials/workspace survive redeploys
- Backup export at `/setup/export` to migrate off Railway later
@ -70,7 +70,7 @@ Set these variables on the service:
3. (Optional) Add Telegram/Discord/Slack tokens.
4. Click **Run setup**.
If Telegram DMs are set to pairing, the setup wizard can approve the pairing code.
If Telegram DMs are set to pairing, web setup can approve the pairing code.
## Getting chat tokens

View File

@ -73,7 +73,7 @@ The Blueprint defaults to `starter`. To use free tier, change `plan: free` in yo
## After deployment
### Complete the setup wizard
### Complete web setup
1. Navigate to `https://<your-service>.onrender.com/setup`
2. Enter your `SETUP_PASSWORD`

View File

@ -22,7 +22,7 @@ curl -fsSL https://openclaw.ai/install.sh | bash
Notes:
- Add `--no-onboard` if you dont want the setup wizard to run again.
- Add `--no-onboard` if you dont want onboarding to run again.
- For **source installs**, use:
```bash

View File

@ -10,6 +10,10 @@ title: "Media Understanding"
OpenClaw can **summarize inbound media** (image/audio/video) before the reply pipeline runs. It autodetects when local tools or provider keys are available, and can be disabled or customized. If understanding is off, models still receive the original files/URLs as usual.
Vendor-specific media behavior is registered by vendor plugins, while OpenClaw
core owns the shared `tools.media` config, fallback order, and reply-pipeline
integration.
## Goals
- Optional: predigest inbound media into short text for faster routing + better command parsing.
@ -184,7 +188,10 @@ If you set `capabilities`, the entry only runs for those media types. For shared
lists, OpenClaw can infer defaults:
- `openai`, `anthropic`, `minimax`: **image**
- `moonshot`: **image + video**
- `google` (Gemini API): **image + audio + video**
- `mistral`: **audio**
- `zai`: **image**
- `groq`: **audio**
- `deepgram`: **audio**
@ -193,11 +200,11 @@ If you omit `capabilities`, the entry is eligible for the list it appears in.
## Provider support matrix (OpenClaw integrations)
| Capability | Provider integration | Notes |
| ---------- | ------------------------------------------------ | --------------------------------------------------------- |
| Image | OpenAI / Anthropic / Google / others via `pi-ai` | Any image-capable model in the registry works. |
| Audio | OpenAI, Groq, Deepgram, Google, Mistral | Provider transcription (Whisper/Deepgram/Gemini/Voxtral). |
| Video | Google (Gemini API) | Provider video understanding. |
| Capability | Provider integration | Notes |
| ---------- | -------------------------------------------------- | ----------------------------------------------------------------------- |
| Image | OpenAI, Anthropic, Google, MiniMax, Moonshot, Z.AI | Vendor plugins register image support against core media understanding. |
| Audio | OpenAI, Groq, Deepgram, Google, Mistral | Provider transcription (Whisper/Deepgram/Gemini/Voxtral). |
| Video | Google, Moonshot | Provider video understanding via vendor plugins. |
## Model selection guidance

View File

@ -321,7 +321,7 @@ Since the Pi is just the Gateway (models run in the cloud), use API-based models
## Auto-Start on Boot
The setup wizard sets this up, but to verify:
Onboarding sets this up, but to verify:
```bash
# Check service is enabled

View File

@ -104,11 +104,15 @@ loader. Cursor command markdown works through the same path.
- `HOOK.md`
- `handler.ts` or `handler.js`
#### MCP for CLI backends
#### MCP for Pi
- enabled bundles can contribute MCP server config
- current runtime wiring is used by the `claude-cli` backend
- OpenClaw merges bundle MCP config into the backend `--mcp-config` file
- OpenClaw merges bundle MCP config into the effective embedded Pi settings as
`mcpServers`
- OpenClaw also exposes supported bundle MCP tools during embedded Pi agent
turns by launching supported stdio MCP servers as subprocesses
- project-local Pi settings still apply after bundle defaults, so workspace
settings can override bundle MCP entries when needed
#### Embedded Pi settings
@ -133,7 +137,6 @@ diagnostics/info output, but OpenClaw does not run them yet:
- Cursor `.cursor/agents`
- Cursor `.cursor/hooks.json`
- Cursor `.cursor/rules`
- Cursor `mcpServers` outside the current mapped runtime paths
- Codex inline/app metadata beyond capability reporting
## Capability reporting
@ -153,7 +156,8 @@ Current exceptions:
- Claude `commands` is considered supported because it maps to skills
- Claude `settings` is considered supported because it maps to embedded Pi settings
- Cursor `commands` is considered supported because it maps to skills
- bundle MCP is considered supported where OpenClaw actually imports it
- bundle MCP is considered supported because it maps into embedded Pi settings
and exposes supported stdio tools to embedded Pi
- Codex `hooks` is considered supported only for OpenClaw hook-pack layouts
## Format differences
@ -195,6 +199,8 @@ Claude-specific notes:
- `commands/` is treated like skill content
- `settings.json` is imported into embedded Pi settings
- `.mcp.json` and manifest `mcpServers` can expose supported stdio tools to
embedded Pi
- `hooks/hooks.json` is detected, but not executed as Claude automation
### Cursor
@ -246,7 +252,9 @@ Current behavior:
- bundle discovery reads files inside the plugin root with boundary checks
- skills and hook-pack paths must stay inside the plugin root
- bundle settings files are read with the same boundary checks
- OpenClaw does not execute arbitrary bundle runtime code in-process
- supported stdio bundle MCP servers may be launched as subprocesses for
embedded Pi tool calls
- OpenClaw does not load arbitrary bundle runtime modules in-process
This makes bundle support safer by default than native plugin modules, but you
should still treat third-party bundles as trusted content for the features they

View File

@ -204,7 +204,7 @@ Example with a stable public host:
## TTS for calls
Voice Call uses the core `messages.tts` configuration (OpenAI or ElevenLabs) for
Voice Call uses the core `messages.tts` configuration for
streaming speech on calls. You can override it under the plugin config with the
**same shape** — it deepmerges with `messages.tts`.
@ -222,7 +222,7 @@ streaming speech on calls. You can override it under the plugin config with the
Notes:
- **Edge TTS is ignored for voice calls** (telephony audio needs PCM; Edge output is unreliable).
- **Microsoft speech is ignored for voice calls** (telephony audio needs PCM; the current Microsoft transport does not expose telephony PCM output).
- Core TTS is used when Twilio media streaming is enabled; otherwise calls fall back to provider native voices.
### More examples

View File

@ -16,15 +16,15 @@ Ollama is a local LLM runtime that makes it easy to run open-source models on yo
## Quick start
### Onboarding wizard (recommended)
### Onboarding (recommended)
The fastest way to set up Ollama is through the setup wizard:
The fastest way to set up Ollama is through onboarding:
```bash
openclaw onboard
```
Select **Ollama** from the provider list. The wizard will:
Select **Ollama** from the provider list. Onboarding will:
1. Ask for the Ollama base URL where your instance can be reached (default `http://127.0.0.1:11434`).
2. Let you choose **Cloud + Local** (cloud models and local models) or **Local** (local models only).

View File

@ -1,24 +1,24 @@
---
summary: "Full reference for the CLI setup wizard: every step, flag, and config field"
summary: "Full reference for CLI onboarding: every step, flag, and config field"
read_when:
- Looking up a specific wizard step or flag
- Looking up a specific onboarding step or flag
- Automating onboarding with non-interactive mode
- Debugging wizard behavior
title: "Setup Wizard Reference"
sidebarTitle: "Wizard Reference"
- Debugging onboarding behavior
title: "Onboarding Reference"
sidebarTitle: "Onboarding Reference"
---
# Setup Wizard Reference
# Onboarding Reference
This is the full reference for the `openclaw onboard` CLI wizard.
For a high-level overview, see [Setup Wizard](/start/wizard).
This is the full reference for `openclaw onboard`.
For a high-level overview, see [Onboarding (CLI)](/start/wizard).
## Flow details (local mode)
<Steps>
<Step title="Existing config detection">
- If `~/.openclaw/openclaw.json` exists, choose **Keep / Modify / Reset**.
- Re-running the wizard does **not** wipe anything unless you explicitly choose **Reset**
- Re-running onboarding does **not** wipe anything unless you explicitly choose **Reset**
(or pass `--reset`).
- CLI `--reset` defaults to `config+creds+sessions`; use `--reset-scope full`
to also remove workspace.
@ -31,9 +31,9 @@ For a high-level overview, see [Setup Wizard](/start/wizard).
</Step>
<Step title="Model/Auth">
- **Anthropic API key**: uses `ANTHROPIC_API_KEY` if present or prompts for a key, then saves it for daemon use.
- **Anthropic OAuth (Claude Code CLI)**: on macOS the wizard checks Keychain item "Claude Code-credentials" (choose "Always Allow" so launchd starts don't block); on Linux/Windows it reuses `~/.claude/.credentials.json` if present.
- **Anthropic OAuth (Claude Code CLI)**: on macOS onboarding checks Keychain item "Claude Code-credentials" (choose "Always Allow" so launchd starts don't block); on Linux/Windows it reuses `~/.claude/.credentials.json` if present.
- **Anthropic token (paste setup-token)**: run `claude setup-token` on any machine, then paste the token (you can name it; blank = default).
- **OpenAI Code (Codex) subscription (Codex CLI)**: if `~/.codex/auth.json` exists, the wizard can reuse it.
- **OpenAI Code (Codex) subscription (Codex CLI)**: if `~/.codex/auth.json` exists, onboarding can reuse it.
- **OpenAI Code (Codex) subscription (OAuth)**: browser flow; paste the `code#state`.
- Sets `agents.defaults.model` to `openai-codex/gpt-5.2` when model is unset or `openai/*`.
- **OpenAI API key**: uses `OPENAI_API_KEY` if present or prompts for a key, then stores it in auth profiles.
@ -55,7 +55,7 @@ For a high-level overview, see [Setup Wizard](/start/wizard).
- More detail: [Moonshot AI (Kimi + Kimi Coding)](/providers/moonshot)
- **Skip**: no auth configured yet.
- Pick a default model from detected options (or enter provider/model manually). For best quality and lower prompt-injection risk, choose the strongest latest-generation model available in your provider stack.
- Wizard runs a model check and warns if the configured model is unknown or missing auth.
- Onboarding runs a model check and warns if the configured model is unknown or missing auth.
- API key storage mode defaults to plaintext auth-profile values. Use `--secret-input-mode ref` to store env-backed refs instead (for example `keyRef: { source: "env", provider: "default", id: "OPENAI_API_KEY" }`).
- OAuth credentials live in `~/.openclaw/credentials/oauth.json`; auth profiles live in `~/.openclaw/agents/<agentId>/agent/auth-profiles.json` (API keys + OAuth).
- More detail: [/concepts/oauth](/concepts/oauth)
@ -106,7 +106,7 @@ For a high-level overview, see [Setup Wizard](/start/wizard).
- macOS: LaunchAgent
- Requires a logged-in user session; for headless, use a custom LaunchDaemon (not shipped).
- Linux (and Windows via WSL2): systemd user unit
- Wizard attempts to enable lingering via `loginctl enable-linger <user>` so the Gateway stays up after logout.
- Onboarding attempts to enable lingering via `loginctl enable-linger <user>` so the Gateway stays up after logout.
- May prompt for sudo (writes `/var/lib/systemd/linger`); it tries without sudo first.
- **Runtime selection:** Node (recommended; required for WhatsApp/Telegram). Bun is **not recommended**.
- If token auth requires a token and `gateway.auth.token` is SecretRef-managed, daemon install validates it but does not persist resolved plaintext token values into supervisor service environment metadata.
@ -128,8 +128,8 @@ For a high-level overview, see [Setup Wizard](/start/wizard).
</Steps>
<Note>
If no GUI is detected, the wizard prints SSH port-forward instructions for the Control UI instead of opening a browser.
If the Control UI assets are missing, the wizard attempts to build them; fallback is `pnpm ui:build` (auto-installs UI deps).
If no GUI is detected, onboarding prints SSH port-forward instructions for the Control UI instead of opening a browser.
If the Control UI assets are missing, onboarding attempts to build them; fallback is `pnpm ui:build` (auto-installs UI deps).
</Note>
## Non-interactive mode
@ -183,12 +183,12 @@ openclaw agents add work \
## Gateway wizard RPC
The Gateway exposes the wizard flow over RPC (`wizard.start`, `wizard.next`, `wizard.cancel`, `wizard.status`).
The Gateway exposes the onboarding flow over RPC (`wizard.start`, `wizard.next`, `wizard.cancel`, `wizard.status`).
Clients (macOS app, Control UI) can render steps without reimplementing onboarding logic.
## Signal setup (signal-cli)
The wizard can install `signal-cli` from GitHub releases:
Onboarding can install `signal-cli` from GitHub releases:
- Downloads the appropriate release asset.
- Stores it under `~/.openclaw/tools/signal-cli/<version>/`.
@ -223,12 +223,12 @@ Typical fields in `~/.openclaw/openclaw.json`:
WhatsApp credentials go under `~/.openclaw/credentials/whatsapp/<accountId>/`.
Sessions are stored under `~/.openclaw/agents/<agentId>/sessions/`.
Some channels are delivered as plugins. When you pick one during setup, the wizard
Some channels are delivered as plugins. When you pick one during setup, onboarding
will prompt to install it (npm or a local path) before it can be configured.
## Related docs
- Wizard overview: [Setup Wizard](/start/wizard)
- Onboarding overview: [Onboarding (CLI)](/start/wizard)
- macOS app onboarding: [Onboarding](/start/onboarding)
- Config reference: [Gateway configuration](/gateway/configuration)
- Providers: [WhatsApp](/channels/whatsapp), [Telegram](/channels/telegram), [Discord](/channels/discord), [Google Chat](/channels/googlechat), [Signal](/channels/signal), [BlueBubbles](/channels/bluebubbles) (iMessage), [iMessage](/channels/imessage) (legacy)

View File

@ -52,13 +52,13 @@ Check your Node version with `node --version` if you are unsure.
</Note>
</Step>
<Step title="Run the setup wizard">
<Step title="Run onboarding">
```bash
openclaw onboard --install-daemon
```
The wizard configures auth, gateway settings, and optional channels.
See [Setup Wizard](/start/wizard) for details.
Onboarding configures auth, gateway settings, and optional channels.
See [Onboarding (CLI)](/start/wizard) for details.
</Step>
<Step title="Check the Gateway">
@ -114,8 +114,8 @@ Full environment variable reference: [Environment vars](/help/environment).
## Go deeper
<Columns>
<Card title="Setup Wizard (details)" href="/start/wizard">
Full CLI wizard reference and advanced options.
<Card title="Onboarding (CLI)" href="/start/wizard">
Full CLI onboarding reference and advanced options.
</Card>
<Card title="macOS app onboarding" href="/start/onboarding">
First run flow for the macOS app.

View File

@ -19,7 +19,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
- [Getting Started](/start/getting-started)
- [Quick start](/start/quickstart)
- [Onboarding](/start/onboarding)
- [Wizard](/start/wizard)
- [Onboarding (CLI)](/start/wizard)
- [Setup](/start/setup)
- [Dashboard (local Gateway)](http://127.0.0.1:18789/)
- [Help](/help)

View File

@ -14,21 +14,21 @@ and how you prefer to configure providers.
## Choose your onboarding path
- **CLI wizard** for macOS, Linux, and Windows (via WSL2).
- **CLI onboarding** for macOS, Linux, and Windows (via WSL2).
- **macOS app** for a guided first run on Apple silicon or Intel Macs.
## CLI setup wizard
## CLI onboarding
Run the wizard in a terminal:
Run onboarding in a terminal:
```bash
openclaw onboard
```
Use the CLI wizard when you want full control of the Gateway, workspace,
Use CLI onboarding when you want full control of the Gateway, workspace,
channels, and skills. Docs:
- [Setup Wizard (CLI)](/start/wizard)
- [Onboarding (CLI)](/start/wizard)
- [`openclaw onboard` command](/cli/onboard)
## macOS app onboarding
@ -41,7 +41,7 @@ Use the OpenClaw app when you want a fully guided setup on macOS. Docs:
If you need an endpoint that is not listed, including hosted providers that
expose standard OpenAI or Anthropic APIs, choose **Custom Provider** in the
CLI wizard. You will be asked to:
CLI onboarding. You will be asked to:
- Pick OpenAI-compatible, Anthropic-compatible, or **Unknown** (auto-detect).
- Enter a base URL and API key (if required by the provider).

View File

@ -16,7 +16,7 @@ Quick start is now part of [Getting Started](/start/getting-started).
<Card title="Getting Started" href="/start/getting-started">
Install OpenClaw and run your first chat in minutes.
</Card>
<Card title="Onboarding Wizard" href="/start/wizard">
Full CLI wizard reference and advanced options.
<Card title="Onboarding (CLI)" href="/start/wizard">
Full CLI onboarding reference and advanced options.
</Card>
</Columns>

View File

@ -10,7 +10,7 @@ title: "Setup"
<Note>
If you are setting up for the first time, start with [Getting Started](/start/getting-started).
For wizard details, see [Onboarding Wizard](/start/wizard).
For onboarding details, see [Onboarding (CLI)](/start/wizard).
</Note>
Last updated: 2026-01-01

View File

@ -33,7 +33,7 @@ openclaw onboard --non-interactive \
Add `--json` for a machine-readable summary.
Use `--secret-input-mode ref` to store env-backed refs in auth profiles instead of plaintext values.
Interactive selection between env refs and configured provider refs (`file` or `exec`) is available in the setup wizard flow.
Interactive selection between env refs and configured provider refs (`file` or `exec`) is available in the onboarding flow.
In non-interactive `ref` mode, provider env vars must be set in the process environment.
Passing inline key flags without the matching env var now fails fast.
@ -210,6 +210,6 @@ Notes:
## Related docs
- Onboarding hub: [Setup Wizard (CLI)](/start/wizard)
- Onboarding hub: [Onboarding (CLI)](/start/wizard)
- Full reference: [CLI Setup Reference](/start/wizard-cli-reference)
- Command reference: [`openclaw onboard`](/cli/onboard)

View File

@ -10,7 +10,7 @@ sidebarTitle: "CLI reference"
# CLI Setup Reference
This page is the full reference for `openclaw onboard`.
For the short guide, see [Setup Wizard (CLI)](/start/wizard).
For the short guide, see [Onboarding (CLI)](/start/wizard).
## What the wizard does
@ -294,6 +294,6 @@ Signal setup behavior:
## Related docs
- Onboarding hub: [Setup Wizard (CLI)](/start/wizard)
- Onboarding hub: [Onboarding (CLI)](/start/wizard)
- Automation and scripts: [CLI Automation](/start/wizard-cli-automation)
- Command reference: [`openclaw onboard`](/cli/onboard)

View File

@ -1,15 +1,15 @@
---
summary: "CLI setup wizard: guided setup for gateway, workspace, channels, and skills"
summary: "CLI onboarding: guided setup for gateway, workspace, channels, and skills"
read_when:
- Running or configuring the setup wizard
- Running or configuring CLI onboarding
- Setting up a new machine
title: "Setup Wizard (CLI)"
title: "Onboarding (CLI)"
sidebarTitle: "Onboarding: CLI"
---
# Setup Wizard (CLI)
# Onboarding (CLI)
The setup wizard is the **recommended** way to set up OpenClaw on macOS,
CLI onboarding is the **recommended** way to set up OpenClaw on macOS,
Linux, or Windows (via WSL2; strongly recommended).
It configures a local Gateway or a remote Gateway connection, plus channels, skills,
and workspace defaults in one guided flow.
@ -35,7 +35,7 @@ openclaw agents add <name>
</Note>
<Tip>
The setup wizard includes a web search step where you can pick a provider
CLI onboarding includes a web search step where you can pick a provider
(Perplexity, Brave, Gemini, Grok, or Kimi) and paste your API key so the agent
can use `web_search`. You can also configure this later with
`openclaw configure --section web`. Docs: [Web tools](/tools/web).
@ -43,7 +43,7 @@ can use `web_search`. You can also configure this later with
## QuickStart vs Advanced
The wizard starts with **QuickStart** (defaults) vs **Advanced** (full control).
Onboarding starts with **QuickStart** (defaults) vs **Advanced** (full control).
<Tabs>
<Tab title="QuickStart (defaults)">
@ -61,7 +61,7 @@ The wizard starts with **QuickStart** (defaults) vs **Advanced** (full control).
</Tab>
</Tabs>
## What the wizard configures
## What onboarding configures
**Local mode (default)** walks you through these steps:
@ -84,9 +84,9 @@ The wizard starts with **QuickStart** (defaults) vs **Advanced** (full control).
7. **Skills** — Installs recommended skills and optional dependencies.
<Note>
Re-running the wizard does **not** wipe anything unless you explicitly choose **Reset** (or pass `--reset`).
Re-running onboarding does **not** wipe anything unless you explicitly choose **Reset** (or pass `--reset`).
CLI `--reset` defaults to config, credentials, and sessions; use `--reset-scope full` to include workspace.
If the config is invalid or contains legacy keys, the wizard asks you to run `openclaw doctor` first.
If the config is invalid or contains legacy keys, onboarding asks you to run `openclaw doctor` first.
</Note>
**Remote mode** only configures the local client to connect to a Gateway elsewhere.
@ -95,7 +95,7 @@ It does **not** install or change anything on the remote host.
## Add another agent
Use `openclaw agents add <name>` to create a separate agent with its own workspace,
sessions, and auth profiles. Running without `--workspace` launches the wizard.
sessions, and auth profiles. Running without `--workspace` launches onboarding.
What it sets:
@ -106,7 +106,7 @@ What it sets:
Notes:
- Default workspaces follow `~/.openclaw/workspace-<agentId>`.
- Add `bindings` to route inbound messages (the wizard can do this).
- Add `bindings` to route inbound messages (onboarding can do this).
- Non-interactive flags: `--model`, `--agent-dir`, `--bind`, `--non-interactive`.
## Full reference
@ -115,7 +115,7 @@ For detailed step-by-step breakdowns and config outputs, see
[CLI Setup Reference](/start/wizard-cli-reference).
For non-interactive examples, see [CLI Automation](/start/wizard-cli-automation).
For the deeper technical reference, including RPC details, see
[Wizard Reference](/reference/wizard).
[Onboarding Reference](/reference/wizard).
## Related docs

View File

@ -97,6 +97,96 @@ The important design boundary:
That split lets OpenClaw validate config, explain missing/disabled plugins, and
build UI/schema hints before the full runtime is active.
## Capability ownership model
OpenClaw treats a native plugin as the ownership boundary for a **company** or a
**feature**, not as a grab bag of unrelated integrations.
That means:
- a company plugin should usually own all of that company's OpenClaw-facing
surfaces
- a feature plugin should usually own the full feature surface it introduces
- channels should consume shared core capabilities instead of re-implementing
provider behavior ad hoc
Examples:
- the bundled `openai` plugin owns OpenAI model-provider behavior and OpenAI
speech + media-understanding behavior
- the bundled `elevenlabs` plugin owns ElevenLabs speech behavior
- the bundled `microsoft` plugin owns Microsoft speech behavior
- the bundled `google`, `minimax`, `mistral`, `moonshot`, and `zai` plugins own
their media-understanding backends
- the `voice-call` plugin is a feature plugin: it owns call transport, tools,
CLI, routes, and runtime, but it consumes core TTS/STT capability instead of
inventing a second speech stack
The intended end state is:
- OpenAI lives in one plugin even if it spans text models, speech, images, and
future video
- another vendor can do the same for its own surface area
- channels do not care which vendor plugin owns the provider; they consume the
shared capability contract exposed by core
This is the key distinction:
- **plugin** = ownership boundary
- **capability** = core contract that multiple plugins can implement or consume
So if OpenClaw adds a new domain such as video, the first question is not
"which provider should hardcode video handling?" The first question is "what is
the core video capability contract?" Once that contract exists, vendor plugins
can register against it and channel/feature plugins can consume it.
If the capability does not exist yet, the right move is usually:
1. define the missing capability in core
2. expose it through the plugin API/runtime in a typed way
3. wire channels/features against that capability
4. let vendor plugins register implementations
This keeps ownership explicit while avoiding core behavior that depends on a
single vendor or a one-off plugin-specific code path.
### Capability layering
Use this mental model when deciding where code belongs:
- **core capability layer**: shared orchestration, policy, fallback, config
merge rules, delivery semantics, and typed contracts
- **vendor plugin layer**: vendor-specific APIs, auth, model catalogs, speech
synthesis, image generation, future video backends, usage endpoints
- **channel/feature plugin layer**: Slack/Discord/voice-call/etc. integration
that consumes core capabilities and presents them on a surface
For example, TTS follows this shape:
- core owns reply-time TTS policy, fallback order, prefs, and channel delivery
- `openai`, `elevenlabs`, and `microsoft` own synthesis implementations
- `voice-call` consumes the telephony TTS runtime helper
That same pattern should be preferred for future capabilities.
### Capability example: video understanding
OpenClaw already treats image/audio/video understanding as one shared
capability. The same ownership model applies there:
1. core defines the media-understanding contract
2. vendor plugins register `describeImage`, `transcribeAudio`, and
`describeVideo` as applicable
3. channels and feature plugins consume the shared core behavior instead of
wiring directly to vendor code
That avoids baking one provider's video assumptions into core. The plugin owns
the vendor surface; core owns the capability contract and fallback behavior.
If OpenClaw adds a new domain later, such as video generation, use the same
sequence again: define the core capability first, then let vendor plugins
register implementations against it.
## Compatible bundles
OpenClaw also recognizes two compatible external bundle layouts:
@ -124,18 +214,23 @@ plugins:
OpenClaw skill loader
- supported now: Claude bundle `settings.json` defaults for embedded Pi agent
settings (with shell override keys sanitized)
- supported now: bundle MCP config, merged into embedded Pi agent settings as
`mcpServers`, with supported stdio bundle MCP tools exposed during embedded
Pi agent turns
- supported now: Cursor `.cursor/commands/*.md` roots, mapped into the normal
OpenClaw skill loader
- supported now: Codex bundle hook directories that use the OpenClaw hook-pack
layout (`HOOK.md` + `handler.ts`/`handler.js`)
- detected but not wired yet: other declared bundle capabilities such as
agents, Claude hook automation, Cursor rules/hooks/MCP metadata, MCP/app/LSP
agents, Claude hook automation, Cursor rules/hooks metadata, app/LSP
metadata, output styles
That means bundle install/discovery/list/info/enablement all work, and bundle
skills, Claude command-skills, Claude bundle settings defaults, and compatible
Codex hook directories load when the bundle is enabled, but bundle runtime code
is not executed in-process.
Codex hook directories load when the bundle is enabled. Supported bundle MCP
servers may also run as subprocesses for embedded Pi tool calls when they use
supported stdio transport, but bundle runtime modules are not loaded
in-process.
Bundle hook support is limited to the normal OpenClaw hook directory format
(`HOOK.md` plus `handler.ts`/`handler.js` under the declared hook roots).
@ -193,6 +288,8 @@ Important trust note:
- Model Studio provider catalog — bundled as `modelstudio` (enabled by default)
- Moonshot provider runtime — bundled as `moonshot` (enabled by default)
- NVIDIA provider catalog — bundled as `nvidia` (enabled by default)
- ElevenLabs speech provider — bundled as `elevenlabs` (enabled by default)
- Microsoft speech provider — bundled as `microsoft` (enabled by default; legacy `edge` input maps here)
- OpenAI provider runtime — bundled as `openai` (enabled by default; owns both `openai` and `openai-codex`)
- OpenCode Go provider capabilities — bundled as `opencode-go` (enabled by default)
- OpenCode Zen provider capabilities — bundled as `opencode` (enabled by default)
@ -218,6 +315,8 @@ Native OpenClaw plugins can register:
- Gateway HTTP routes
- Agent tools
- CLI commands
- Speech providers
- Web search providers
- Background services
- Context engines
- Provider auth flows and model catalogs
@ -229,6 +328,63 @@ Native OpenClaw plugins can register:
Native OpenClaw plugins run **inprocess** with the Gateway, so treat them as trusted code.
Tool authoring guide: [Plugin agent tools](/plugins/agent-tools).
Think of these registrations as **capability claims**. A plugin is not supposed
to reach into random internals and "just make it work." It should register
against explicit surfaces that OpenClaw understands, validates, and can expose
consistently across config, onboarding, status, docs, and runtime behavior.
## Contracts and enforcement
The plugin API surface is intentionally typed and centralized in
`OpenClawPluginApi`. That contract defines the supported registration points and
the runtime helpers a plugin may rely on.
Why this matters:
- plugin authors get one stable internal standard
- core can reject duplicate ownership such as two plugins registering the same
provider id
- startup can surface actionable diagnostics for malformed registration
- contract tests can enforce bundled-plugin ownership and prevent silent drift
There are two layers of enforcement:
1. **runtime registration enforcement**
The plugin registry validates registrations as plugins load. Examples:
duplicate provider ids, duplicate speech provider ids, and malformed
registrations produce plugin diagnostics instead of undefined behavior.
2. **contract tests**
Bundled plugins are captured in contract registries during test runs so
OpenClaw can assert ownership explicitly. Today this is used for model
providers, speech providers, web search providers, and bundled registration
ownership.
The practical effect is that OpenClaw knows, up front, which plugin owns which
surface. That lets core and channels compose seamlessly because ownership is
declared, typed, and testable rather than implicit.
### What belongs in a contract
Good plugin contracts are:
- typed
- small
- capability-specific
- owned by core
- reusable by multiple plugins
- consumable by channels/features without vendor knowledge
Bad plugin contracts are:
- vendor-specific policy hidden in core
- one-off plugin escape hatches that bypass the registry
- channel code reaching straight into a vendor implementation
- ad hoc runtime objects that are not part of `OpenClawPluginApi` or
`api.runtime`
When in doubt, raise the abstraction level: define the capability first, then
let plugins plug into it.
## Provider runtime hooks
Provider plugins now have two layers:
@ -519,25 +675,103 @@ to think of as short-lived performance caches, not persistence.
## Runtime helpers
Plugins can access selected core helpers via `api.runtime`. For telephony TTS:
Plugins can access selected core helpers via `api.runtime`. For TTS:
```ts
const clip = await api.runtime.tts.textToSpeech({
text: "Hello from OpenClaw",
cfg: api.config,
});
const result = await api.runtime.tts.textToSpeechTelephony({
text: "Hello from OpenClaw",
cfg: api.config,
});
const voices = await api.runtime.tts.listVoices({
provider: "elevenlabs",
cfg: api.config,
});
```
Notes:
- Uses core `messages.tts` configuration (OpenAI or ElevenLabs).
- `textToSpeech` returns the normal core TTS output payload for file/voice-note surfaces.
- Uses core `messages.tts` configuration and provider selection.
- Returns PCM audio buffer + sample rate. Plugins must resample/encode for providers.
- Edge TTS is not supported for telephony.
- `listVoices` is optional per provider. Use it for vendor-owned voice pickers or setup flows.
- Voice listings can include richer metadata such as locale, gender, and personality tags for provider-aware pickers.
- OpenAI and ElevenLabs support telephony today. Microsoft does not.
For STT/transcription, plugins can call:
Plugins can also register speech providers via `api.registerSpeechProvider(...)`.
```ts
const { text } = await api.runtime.stt.transcribeAudioFile({
api.registerSpeechProvider({
id: "acme-speech",
label: "Acme Speech",
isConfigured: ({ config }) => Boolean(config.messages?.tts),
synthesize: async (req) => {
return {
audioBuffer: Buffer.from([]),
outputFormat: "mp3",
fileExtension: ".mp3",
voiceCompatible: false,
};
},
});
```
Notes:
- Keep TTS policy, fallback, and reply delivery in core.
- Use speech providers for vendor-owned synthesis behavior.
- Legacy Microsoft `edge` input is normalized to the `microsoft` provider id.
- The preferred ownership model is company-oriented: one vendor plugin can own
text, speech, image, and future media providers as OpenClaw adds those
capability contracts.
For image/audio/video understanding, plugins register one typed
media-understanding provider instead of a generic key/value bag:
```ts
api.registerMediaUnderstandingProvider({
id: "google",
capabilities: ["image", "audio", "video"],
describeImage: async (req) => ({ text: "..." }),
transcribeAudio: async (req) => ({ text: "..." }),
describeVideo: async (req) => ({ text: "..." }),
});
```
Notes:
- Keep orchestration, fallback, config, and channel wiring in core.
- Keep vendor behavior in the provider plugin.
- Additive expansion should stay typed: new optional methods, new optional
result fields, new optional capabilities.
- If OpenClaw adds a new capability such as video generation later, define the
core capability contract first, then let vendor plugins register against it.
For media-understanding runtime helpers, plugins can call:
```ts
const image = await api.runtime.mediaUnderstanding.describeImageFile({
filePath: "/tmp/inbound-photo.jpg",
cfg: api.config,
agentDir: "/tmp/agent",
});
const video = await api.runtime.mediaUnderstanding.describeVideoFile({
filePath: "/tmp/inbound-video.mp4",
cfg: api.config,
});
```
For audio transcription, plugins can use either the media-understanding runtime
or the older STT alias:
```ts
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({
filePath: "/tmp/inbound-audio.ogg",
cfg: api.config,
// Optional when MIME cannot be inferred reliably:
@ -547,8 +781,37 @@ const { text } = await api.runtime.stt.transcribeAudioFile({
Notes:
- `api.runtime.mediaUnderstanding.*` is the preferred shared surface for
image/audio/video understanding.
- Uses core media-understanding audio configuration (`tools.media.audio`) and provider fallback order.
- Returns `{ text: undefined }` when no transcription output is produced (for example skipped/unsupported input).
- `api.runtime.stt.transcribeAudioFile(...)` remains as a compatibility alias.
For web search, plugins can consume the shared runtime helper instead of
reaching into the agent tool wiring:
```ts
const providers = api.runtime.webSearch.listProviders({
config: api.config,
});
const result = await api.runtime.webSearch.search({
config: api.config,
args: {
query: "OpenClaw plugin runtime helpers",
count: 5,
},
});
```
Plugins can also register web-search providers via
`api.registerWebSearchProvider(...)`.
Notes:
- Keep provider selection, credential resolution, and shared request semantics in core.
- Use web-search providers for vendor-specific search transports.
- `api.runtime.webSearch.*` is the preferred shared surface for feature/channel plugins that need search behavior without depending on the agent tool wrapper.
## Gateway HTTP routes
@ -1110,12 +1373,109 @@ Plugins export either:
- `on(...)` for typed lifecycle hooks
- `registerChannel`
- `registerProvider`
- `registerSpeechProvider`
- `registerMediaUnderstandingProvider`
- `registerWebSearchProvider`
- `registerHttpRoute`
- `registerCommand`
- `registerCli`
- `registerContextEngine`
- `registerService`
In practice, `register(api)` is also where a plugin declares **ownership**.
That ownership should map cleanly to either:
- a vendor surface such as OpenAI, ElevenLabs, or Microsoft
- a feature surface such as Voice Call
Avoid splitting one vendor's capabilities across unrelated plugins unless there
is a strong product reason to do so. The default should be one plugin per
vendor/feature, with core capability contracts separating shared orchestration
from vendor-specific behavior.
## Adding a new capability
When a plugin needs behavior that does not fit the current API, do not bypass
the plugin system with a private reach-in. Add the missing capability.
Recommended sequence:
1. define the core contract
Decide what shared behavior core should own: policy, fallback, config merge,
lifecycle, channel-facing semantics, and runtime helper shape.
2. add typed plugin registration/runtime surfaces
Extend `OpenClawPluginApi` and/or `api.runtime` with the smallest useful
typed seam.
3. wire core + channel/feature consumers
Channels and feature plugins should consume the new capability through core,
not by importing a vendor implementation directly.
4. register vendor implementations
Vendor plugins then register their backends against the capability.
5. add contract coverage
Add tests so ownership and registration shape stay explicit over time.
This is how OpenClaw stays opinionated without becoming hardcoded to one
provider's worldview.
### Capability checklist
When you add a new capability, the implementation should usually touch these
surfaces together:
- core contract types in `src/<capability>/types.ts`
- core runner/runtime helper in `src/<capability>/runtime.ts`
- plugin API registration surface in `src/plugins/types.ts`
- plugin registry wiring in `src/plugins/registry.ts`
- plugin runtime exposure in `src/plugins/runtime/*` when feature/channel
plugins need to consume it
- capture/test helpers in `src/test-utils/plugin-registration.ts`
- ownership/contract assertions in `src/plugins/contracts/registry.ts`
- operator/plugin docs in `docs/`
If one of those surfaces is missing, that is usually a sign the capability is
not fully integrated yet.
### Capability template
Minimal pattern:
```ts
// core contract
export type VideoGenerationProviderPlugin = {
id: string;
label: string;
generateVideo: (req: VideoGenerationRequest) => Promise<VideoGenerationResult>;
};
// plugin API
api.registerVideoGenerationProvider({
id: "openai",
label: "OpenAI",
async generateVideo(req) {
return await generateOpenAiVideo(req);
},
});
// shared runtime helper for feature/channel plugins
const clip = await api.runtime.videoGeneration.generateFile({
prompt: "Show the robot walking through the lab.",
cfg,
});
```
Contract test pattern:
```ts
expect(findVideoGenerationProviderIdsForPlugin("openai")).toEqual(["openai"]);
```
That keeps the rule simple:
- core owns the capability contract + orchestration
- vendor plugins own vendor implementations
- feature/channel plugins consume runtime helpers
- contract tests keep ownership explicit
Context engine plugins can also register a runtime-owned context manager:
```ts

View File

@ -9,26 +9,27 @@ title: "Text-to-Speech"
# Text-to-speech (TTS)
OpenClaw can convert outbound replies into audio using ElevenLabs, OpenAI, or Edge TTS.
OpenClaw can convert outbound replies into audio using ElevenLabs, Microsoft, or OpenAI.
It works anywhere OpenClaw can send audio; Telegram gets a round voice-note bubble.
## Supported services
- **ElevenLabs** (primary or fallback provider)
- **Microsoft** (primary or fallback provider; current bundled implementation uses `node-edge-tts`, default when no API keys)
- **OpenAI** (primary or fallback provider; also used for summaries)
- **Edge TTS** (primary or fallback provider; uses `node-edge-tts`, default when no API keys)
### Edge TTS notes
### Microsoft speech notes
Edge TTS uses Microsoft Edge's online neural TTS service via the `node-edge-tts`
library. It's a hosted service (not local), uses Microsofts endpoints, and does
not require an API key. `node-edge-tts` exposes speech configuration options and
output formats, but not all options are supported by the Edge service. citeturn2search0
The bundled Microsoft speech provider currently uses Microsoft Edge's online
neural TTS service via the `node-edge-tts` library. It's a hosted service (not
local), uses Microsoft endpoints, and does not require an API key.
`node-edge-tts` exposes speech configuration options and output formats, but
not all options are supported by the service. Legacy config and directive input
using `edge` still works and is normalized to `microsoft`.
Because Edge TTS is a public web service without a published SLA or quota, treat it
as best-effort. If you need guaranteed limits and support, use OpenAI or ElevenLabs.
Microsoft's Speech REST API documents a 10minute audio limit per request; Edge TTS
does not publish limits, so assume similar or lower limits. citeturn0search3
Because this path is a public web service without a published SLA or quota,
treat it as best-effort. If you need guaranteed limits and support, use OpenAI
or ElevenLabs.
## Optional keys
@ -37,8 +38,9 @@ If you want OpenAI or ElevenLabs:
- `ELEVENLABS_API_KEY` (or `XI_API_KEY`)
- `OPENAI_API_KEY`
Edge TTS does **not** require an API key. If no API keys are found, OpenClaw defaults
to Edge TTS (unless disabled via `messages.tts.edge.enabled=false`).
Microsoft speech does **not** require an API key. If no API keys are found,
OpenClaw defaults to Microsoft (unless disabled via
`messages.tts.microsoft.enabled=false` or `messages.tts.edge.enabled=false`).
If multiple providers are configured, the selected provider is used first and the others are fallback options.
Auto-summary uses the configured `summaryModel` (or `agents.defaults.model.primary`),
@ -58,7 +60,7 @@ so that provider must also be authenticated if you enable summaries.
No. AutoTTS is **off** by default. Enable it in config with
`messages.tts.auto` or per session with `/tts always` (alias: `/tts on`).
Edge TTS **is** enabled by default once TTS is on, and is used automatically
Microsoft speech **is** enabled by default once TTS is on, and is used automatically
when no OpenAI or ElevenLabs API keys are available.
## Config
@ -118,15 +120,15 @@ Full schema is in [Gateway configuration](/gateway/configuration).
}
```
### Edge TTS primary (no API key)
### Microsoft primary (no API key)
```json5
{
messages: {
tts: {
auto: "always",
provider: "edge",
edge: {
provider: "microsoft",
microsoft: {
enabled: true,
voice: "en-US-MichelleNeural",
lang: "en-US",
@ -139,13 +141,13 @@ Full schema is in [Gateway configuration](/gateway/configuration).
}
```
### Disable Edge TTS
### Disable Microsoft speech
```json5
{
messages: {
tts: {
edge: {
microsoft: {
enabled: false,
},
},
@ -205,9 +207,10 @@ Then run:
- `tagged` only sends audio when the reply includes `[[tts]]` tags.
- `enabled`: legacy toggle (doctor migrates this to `auto`).
- `mode`: `"final"` (default) or `"all"` (includes tool/block replies).
- `provider`: `"elevenlabs"`, `"openai"`, or `"edge"` (fallback is automatic).
- `provider`: speech provider id such as `"elevenlabs"`, `"microsoft"`, or `"openai"` (fallback is automatic).
- If `provider` is **unset**, OpenClaw prefers `openai` (if key), then `elevenlabs` (if key),
otherwise `edge`.
otherwise `microsoft`.
- Legacy `provider: "edge"` still works and is normalized to `microsoft`.
- `summaryModel`: optional cheap model for auto-summary; defaults to `agents.defaults.model.primary`.
- Accepts `provider/model` or a configured model alias.
- `modelOverrides`: allow the model to emit TTS directives (on by default).
@ -227,15 +230,16 @@ Then run:
- `elevenlabs.applyTextNormalization`: `auto|on|off`
- `elevenlabs.languageCode`: 2-letter ISO 639-1 (e.g. `en`, `de`)
- `elevenlabs.seed`: integer `0..4294967295` (best-effort determinism)
- `edge.enabled`: allow Edge TTS usage (default `true`; no API key).
- `edge.voice`: Edge neural voice name (e.g. `en-US-MichelleNeural`).
- `edge.lang`: language code (e.g. `en-US`).
- `edge.outputFormat`: Edge output format (e.g. `audio-24khz-48kbitrate-mono-mp3`).
- See Microsoft Speech output formats for valid values; not all formats are supported by Edge.
- `edge.rate` / `edge.pitch` / `edge.volume`: percent strings (e.g. `+10%`, `-5%`).
- `edge.saveSubtitles`: write JSON subtitles alongside the audio file.
- `edge.proxy`: proxy URL for Edge TTS requests.
- `edge.timeoutMs`: request timeout override (ms).
- `microsoft.enabled`: allow Microsoft speech usage (default `true`; no API key).
- `microsoft.voice`: Microsoft neural voice name (e.g. `en-US-MichelleNeural`).
- `microsoft.lang`: language code (e.g. `en-US`).
- `microsoft.outputFormat`: Microsoft output format (e.g. `audio-24khz-48kbitrate-mono-mp3`).
- See Microsoft Speech output formats for valid values; not all formats are supported by the bundled Edge-backed transport.
- `microsoft.rate` / `microsoft.pitch` / `microsoft.volume`: percent strings (e.g. `+10%`, `-5%`).
- `microsoft.saveSubtitles`: write JSON subtitles alongside the audio file.
- `microsoft.proxy`: proxy URL for Microsoft speech requests.
- `microsoft.timeoutMs`: request timeout override (ms).
- `edge.*`: legacy alias for the same Microsoft settings.
## Model-driven overrides (default on)
@ -260,7 +264,7 @@ Here you go.
Available directive keys (when enabled):
- `provider` (`openai` | `elevenlabs` | `edge`, requires `allowProvider: true`)
- `provider` (registered speech provider id, for example `openai`, `elevenlabs`, or `microsoft`; requires `allowProvider: true`)
- `voice` (OpenAI voice) or `voiceId` (ElevenLabs)
- `model` (OpenAI TTS model or ElevenLabs model id)
- `stability`, `similarityBoost`, `style`, `speed`, `useSpeakerBoost`
@ -319,13 +323,12 @@ These override `messages.tts.*` for that host.
- 48kHz / 64kbps is a good voice-note tradeoff and required for the round bubble.
- **Other channels**: MP3 (`mp3_44100_128` from ElevenLabs, `mp3` from OpenAI).
- 44.1kHz / 128kbps is the default balance for speech clarity.
- **Edge TTS**: uses `edge.outputFormat` (default `audio-24khz-48kbitrate-mono-mp3`).
- `node-edge-tts` accepts an `outputFormat`, but not all formats are available
from the Edge service. citeturn2search0
- Output format values follow Microsoft Speech output formats (including Ogg/WebM Opus). citeturn1search0
- **Microsoft**: uses `microsoft.outputFormat` (default `audio-24khz-48kbitrate-mono-mp3`).
- The bundled transport accepts an `outputFormat`, but not all formats are available from the service.
- Output format values follow Microsoft Speech output formats (including Ogg/WebM Opus).
- Telegram `sendVoice` accepts OGG/MP3/M4A; use OpenAI/ElevenLabs if you need
guaranteed Opus voice notes. citeturn1search1
- If the configured Edge output format fails, OpenClaw retries with MP3.
- If the configured Microsoft output format fails, OpenClaw retries with MP3.
OpenAI/ElevenLabs formats are fixed; Telegram expects Opus for voice-note UX.

View File

@ -28,7 +28,7 @@ Auth is supplied during the WebSocket handshake via:
- `connect.params.auth.token`
- `connect.params.auth.password`
The dashboard settings panel keeps a token for the current browser tab session and selected gateway URL; passwords are not persisted.
The setup wizard generates a gateway token by default, so paste it here on first connect.
Onboarding generates a gateway token by default, so paste it here on first connect.
## Device pairing (first connection)

View File

@ -324,22 +324,22 @@ openclaw [--dev] [--profile <name>] <command>
选项:
- `--workspace <dir>`:智能体工作区路径(默认 `~/.openclaw/workspace`)。
- `--wizard`:运行设置向导。
- `--non-interactive`:无提示运行导。
- `--mode <local|remote>`导模式。
- `--wizard`:运行新手引导。
- `--non-interactive`:无提示运行新手引导。
- `--mode <local|remote>`新手引导模式。
- `--remote-url <url>`:远程 Gateway 网关 URL。
- `--remote-token <token>`:远程 Gateway 网关 token。
只要存在任意导标志(`--non-interactive`, `--mode`, `--remote-url`, `--remote-token`),就会自动运行导。
只要存在任意新手引导标志(`--non-interactive`, `--mode`, `--remote-url`, `--remote-token`),就会自动运行新手引导。
### `onboard`
用于设置 gateway、工作区和 Skills 的交互式导。
用于设置 gateway、工作区和 Skills 的交互式新手引导。
选项:
- `--workspace <dir>`
- `--reset`(在运行导前重置配置 + 凭据 + 会话)
- `--reset`(在运行新手引导前重置配置 + 凭据 + 会话)
- `--reset-scope <config|config+creds+sessions|full>`(默认 `config+creds+sessions`;使用 `full` 还会删除工作区)
- `--non-interactive`
- `--mode <local|remote>`

View File

@ -1,7 +1,7 @@
---
read_when:
- 你想通过引导式设置来配置 Gateway 网关、工作区、身份验证、渠道和 Skills
summary: "`openclaw onboard` 的 CLI 参考(交互式设置向导)"
summary: "`openclaw onboard` 的 CLI 参考(交互式新手引导)"
title: onboard
x-i18n:
generated_at: "2026-03-16T06:21:32Z"
@ -14,11 +14,11 @@ x-i18n:
# `openclaw onboard`
交互式设置向导(本地或远程 Gateway 网关设置)。
交互式新手引导(本地或远程 Gateway 网关设置)。
## 相关指南
- CLI 新手引导中心:[设置向导CLI](/start/wizard)
- CLI 新手引导中心:[CLI 新手引导](/start/wizard)
- 新手引导概览:[新手引导概览](/start/onboarding-overview)
- CLI 新手引导参考:[CLI 设置参考](/start/wizard-cli-reference)
- CLI 自动化:[CLI 自动化](/start/wizard-cli-automation)

View File

@ -1,6 +1,6 @@
---
read_when:
- 你正在进行首次运行设置,但不使用完整的设置向
- 你正在进行首次运行设置,但不使用完整的 CLI 新手引
- 你想设置默认工作区路径
summary: "`openclaw setup` 的 CLI 参考(初始化配置 + 工作区)"
title: setup
@ -20,7 +20,7 @@ x-i18n:
相关内容:
- 入门指南:[入门指南](/start/getting-started)
- 向导:[新手引导](/start/onboarding)
- CLI 新手引导:[CLI 新手引导](/start/wizard)
## 示例
@ -29,7 +29,7 @@ openclaw setup
openclaw setup --workspace ~/.openclaw/workspace
```
通过 setup 运行导:
通过 setup 运行新手引导:
```bash
openclaw setup --wizard

View File

@ -39,7 +39,7 @@ x-i18n:
- [如何在 VPS 上安装 OpenClaw](#how-do-i-install-openclaw-on-a-vps)
- [云/VPS 安装指南在哪里?](#where-are-the-cloudvps-install-guides)
- [可以让 OpenClaw 自行更新吗?](#can-i-ask-openclaw-to-update-itself)
- [新手引导向导具体做了什么?](#what-does-the-onboarding-wizard-actually-do)
- [新手引导具体做了什么?](#新手引导具体做了什么)
- [运行 OpenClaw 需要 Claude 或 OpenAI 订阅吗?](#do-i-need-a-claude-or-openai-subscription-to-run-this)
- [能否使用 Claude Max 订阅而不需要 API 密钥?](#can-i-use-claude-max-subscription-without-an-api-key)
- [Anthropic "setup-token" 认证如何工作?](#how-does-anthropic-setuptoken-auth-work)
@ -310,14 +310,14 @@ openclaw doctor
### 安装和设置 OpenClaw 的推荐方式是什么
仓库推荐从源码运行并使用新手引导向导
仓库推荐从源码运行并使用新手引导:
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
openclaw onboard --install-daemon
```
导还可以自动构建 UI 资源。新手引导后,通常在端口 **18789** 上运行 Gateway 网关。
新手引导还可以自动构建 UI 资源。新手引导后,通常在端口 **18789** 上运行 Gateway 网关。
从源码安装(贡献者/开发者):
@ -334,7 +334,7 @@ openclaw onboard
### 新手引导后如何打开仪表板
向导现在会在新手引导完成后立即使用带令牌的仪表板 URL 打开浏览器,并在摘要中打印完整链接(带令牌)。保持该标签页打开;如果没有自动启动,请在同一台机器上复制/粘贴打印的 URL。令牌保持在本地主机上——不会从浏览器获取任何内容。
新手引导现在会在完成后立即使用带令牌的仪表板 URL 打开浏览器,并在摘要中打印完整链接(带令牌)。保持该标签页打开;如果没有自动启动,请在同一台机器上复制/粘贴打印的 URL。令牌保持在本地主机上不会从浏览器获取任何内容。
### 如何在本地和远程环境中验证仪表板令牌
@ -562,7 +562,7 @@ curl -fsSL https://openclaw.ai/install.sh | bash -s -- --install-method git
### 如何在 Linux 上安装 OpenClaw
简短回答:按照 Linux 指南操作,然后运行新手引导向导
简短回答:按照 Linux 指南操作,然后运行新手引导。
- Linux 快速路径 + 服务安装:[Linux](/platforms/linux)。
- 完整指南:[入门](/start/getting-started)。
@ -614,7 +614,7 @@ openclaw gateway restart
文档:[更新](/cli/update)、[更新指南](/install/updating)。
### 新手引导向导具体做了什么
### 新手引导具体做了什么
`openclaw onboard` 是推荐的设置路径。在**本地模式**下,它引导你完成:
@ -642,7 +642,7 @@ Claude Pro/Max 订阅**不包含 API 密钥**,因此这是订阅账户的正
### Anthropic setup-token 认证如何工作
`claude setup-token` 通过 Claude Code CLI 生成一个**令牌字符串**(在 Web 控制台中不可用)。你可以在**任何机器**上运行它。在导中选择 **Anthropic token (paste setup-token)** 或使用 `openclaw models auth paste-token --provider anthropic` 粘贴。令牌作为 **anthropic** 提供商的认证配置文件存储,像 API 密钥一样使用(无自动刷新)。更多详情:[OAuth](/concepts/oauth)。
`claude setup-token` 通过 Claude Code CLI 生成一个**令牌字符串**(在 Web 控制台中不可用)。你可以在**任何机器**上运行它。在新手引导中选择 **Anthropic token (paste setup-token)** 或使用 `openclaw models auth paste-token --provider anthropic` 粘贴。令牌作为 **anthropic** 提供商的认证配置文件存储,像 API 密钥一样使用(无自动刷新)。更多详情:[OAuth](/concepts/oauth)。
### 在哪里获取 Anthropic setup-token
@ -652,7 +652,7 @@ Claude Pro/Max 订阅**不包含 API 密钥**,因此这是订阅账户的正
claude setup-token
```
复制它打印的令牌,然后在导中选择 **Anthropic token (paste setup-token)**。如果你想在 Gateway 网关主机上运行,使用 `openclaw models auth setup-token --provider anthropic`。如果你在其他地方运行了 `claude setup-token`,在 Gateway 网关主机上使用 `openclaw models auth paste-token --provider anthropic` 粘贴。参阅 [Anthropic](/providers/anthropic)。
复制它打印的令牌,然后在新手引导中选择 **Anthropic token (paste setup-token)**。如果你想在 Gateway 网关主机上运行,使用 `openclaw models auth setup-token --provider anthropic`。如果你在其他地方运行了 `claude setup-token`,在 Gateway 网关主机上使用 `openclaw models auth paste-token --provider anthropic` 粘贴。参阅 [Anthropic](/providers/anthropic)。
### 是否支持 Claude 订阅认证Claude Pro/Max
@ -673,13 +673,13 @@ claude setup-token
### Codex 认证如何工作
OpenClaw 通过 OAuthChatGPT 登录)支持 **OpenAI Code (Codex)**导可以运行 OAuth 流程,并在适当时将默认模型设置为 `openai-codex/gpt-5.2`。参阅[模型提供商](/concepts/model-providers)和[导](/start/wizard)。
OpenClaw 通过 OAuthChatGPT 登录)支持 **OpenAI Code (Codex)**新手引导可以运行 OAuth 流程,并在适当时将默认模型设置为 `openai-codex/gpt-5.2`。参阅[模型提供商](/concepts/model-providers)和[CLI 新手引导](/start/wizard)。
### 是否支持 OpenAI 订阅认证Codex OAuth
是的。OpenClaw 完全支持 **OpenAI Code (Codex) 订阅 OAuth**。新手引导向导可以为你运行 OAuth 流程。
是的。OpenClaw 完全支持 **OpenAI Code (Codex) 订阅 OAuth**。新手引导可以为你运行 OAuth 流程。
参阅 [OAuth](/concepts/oauth)、[模型提供商](/concepts/model-providers)和[导](/start/wizard)。
参阅 [OAuth](/concepts/oauth)、[模型提供商](/concepts/model-providers)和[CLI 新手引导](/start/wizard)。
### 如何设置 Gemini CLI OAuth
@ -1632,7 +1632,7 @@ openclaw onboard --install-daemon
注意:
- 新手引导向导在看到现有配置时也提供**重置**选项。参阅[导](/start/wizard)。
- 新手引导在看到现有配置时也提供**重置**选项。参阅[CLI 新手引导](/start/wizard)。
- 如果你使用了配置文件(`--profile` / `OPENCLAW_PROFILE`),重置每个状态目录(默认为 `~/.openclaw-<profile>`)。
- 开发重置:`openclaw gateway --dev --reset`(仅限开发;清除开发配置 + 凭据 + 会话 + 工作区)。

View File

@ -40,7 +40,7 @@ x-i18n:
<Card title="入门指南" href="/start/getting-started" icon="rocket">
安装 OpenClaw 并在几分钟内启动 Gateway 网关。
</Card>
<Card title="运行导" href="/start/wizard" icon="sparkles">
<Card title="运行新手引导" href="/start/wizard" icon="sparkles">
通过 `openclaw onboard` 和配对流程进行引导式设置。
</Card>
<Card title="打开控制界面" href="/web/control-ui" icon="layout-dashboard">

View File

@ -60,13 +60,13 @@ x-i18n:
</Note>
</Step>
<Step title="运行设置向导">
<Step title="运行新手引导">
```bash
openclaw onboard --install-daemon
```
导会配置认证、Gateway 网关设置和可选渠道。
详情请参见 [Setup Wizard](/start/wizard)。
新手引导会配置认证、Gateway 网关设置和可选渠道。
详情请参见 [CLI 新手引导](/start/wizard)。
</Step>
<Step title="检查 Gateway 网关">
@ -122,8 +122,8 @@ x-i18n:
## 深入了解
<Columns>
<Card title="设置向导(详情)" href="/start/wizard">
完整的 CLI 导参考和高级选项。
<Card title="CLI 新手引导" href="/start/wizard">
完整的 CLI 新手引导参考和高级选项。
</Card>
<Card title="macOS 应用新手引导" href="/start/onboarding">
macOS 应用的首次运行流程。

View File

@ -26,7 +26,7 @@ x-i18n:
- [入门指南](/start/getting-started)
- [快速开始](/start/quickstart)
- [新手引导](/start/onboarding)
- [导](/start/wizard)
- [CLI 新手引导](/start/wizard)
- [安装配置](/start/setup)
- [仪表盘(本地 Gateway 网关)](http://127.0.0.1:18789/)
- [帮助](/help)

View File

@ -21,21 +21,21 @@ OpenClaw 支持多种新手引导路径,具体取决于 Gateway 网关运行
## 选择你的新手引导路径
- 适用于 macOS、Linux 和 Windows通过 WSL2**CLI 导**。
- 适用于 macOS、Linux 和 Windows通过 WSL2**CLI 新手引导**。
- 适用于 Apple silicon 或 Intel Mac 的 **macOS 应用**,提供引导式首次运行体验。
## CLI 设置向
## CLI 新手引
在终端中运行导:
在终端中运行新手引导:
```bash
openclaw onboard
```
当你希望完全控制 Gateway 网关、工作区、
渠道和 Skills 时,请使用 CLI 导。文档:
渠道和 Skills 时,请使用 CLI 新手引导。文档:
- [设置向导CLI](/start/wizard)
- [CLI 新手引导](/start/wizard)
- [`openclaw onboard` 命令](/cli/onboard)
## macOS 应用新手引导
@ -48,7 +48,7 @@ openclaw onboard
如果你需要一个未列出的端点,包括那些
公开标准 OpenAI 或 Anthropic API 的托管提供商,请在
CLI 向导中选择 **Custom Provider**。系统会要求你:
在 CLI 新手引导中选择 **Custom Provider**。系统会要求你:
- 选择兼容 OpenAI、兼容 Anthropic**Unknown**(自动检测)。
- 输入基础 URL 和 API 密钥(如果提供商需要)。

View File

@ -1,10 +1,10 @@
---
read_when:
- 运行或配置设置向
- 运行或配置 CLI 新手引
- 设置一台新机器
sidebarTitle: "Onboarding: CLI"
summary: CLI 设置向导:用于 Gateway 网关、工作区、渠道和 Skills 的引导式设置
title: 设置向导CLI
summary: CLI 新手引导:用于 Gateway 网关、工作区、渠道和 Skills 的引导式设置
title: CLI 新手引导
x-i18n:
generated_at: "2026-03-16T06:28:38Z"
model: gpt-5.4
@ -14,9 +14,9 @@ x-i18n:
workflow: 15
---
# 设置向导CLI
# CLI 新手引导
设置向导是在 macOS、
CLI 新手引导是在 macOS、
Linux 或 Windows通过 WSL2强烈推荐上设置 OpenClaw 的**推荐**方式。
它可在一次引导式流程中配置本地 Gateway 网关或远程 Gateway 网关连接以及渠道、Skills
和工作区默认值。
@ -42,7 +42,7 @@ openclaw agents add <name>
</Note>
<Tip>
设置向导包含一个 web search 步骤,你可以选择一个提供商
CLI 新手引导包含一个 web search 步骤,你可以选择一个提供商
Perplexity、Brave、Gemini、Grok 或 Kimi并粘贴你的 API 密钥,以便智能体
可以使用 `web_search`。你也可以稍后通过
`openclaw configure --section web` 进行配置。文档:[Web 工具](/tools/web)。
@ -50,7 +50,7 @@ openclaw agents add <name>
## 快速开始与高级模式
导开始时会让你选择**快速开始**(默认值)或**高级模式**(完全控制)。
新手引导开始时会让你选择**快速开始**(默认值)或**高级模式**(完全控制)。
<Tabs>
<Tab title="快速开始(默认值)">
@ -68,7 +68,7 @@ openclaw agents add <name>
</Tab>
</Tabs>
## 导会配置什么
## 新手引导会配置什么
**本地模式(默认)**会引导你完成以下步骤:
@ -91,9 +91,9 @@ openclaw agents add <name>
7. **Skills** —— 安装推荐的 Skills 和可选依赖项。
<Note>
重新运行导**不会**清除任何内容,除非你显式选择 **Reset**(或传入 `--reset`)。
重新运行新手引导**不会**清除任何内容,除非你显式选择 **Reset**(或传入 `--reset`)。
CLI `--reset` 默认会重置配置、凭证和会话;如需包含工作区,请使用 `--reset-scope full`
如果配置无效或包含旧版键,导会先要求你运行 `openclaw doctor`
如果配置无效或包含旧版键,新手引导会先要求你运行 `openclaw doctor`
</Note>
**远程模式**只会配置本地客户端以连接到其他地方的 Gateway 网关。
@ -102,7 +102,7 @@ CLI `--reset` 默认会重置配置、凭证和会话;如需包含工作区,
## 添加另一个智能体
使用 `openclaw agents add <name>` 创建一个单独的智能体,它拥有自己的工作区、
会话和认证配置文件。不带 `--workspace` 运行会启动导。
会话和认证配置文件。不带 `--workspace` 运行会启动新手引导。
它会设置:
@ -113,7 +113,7 @@ CLI `--reset` 默认会重置配置、凭证和会话;如需包含工作区,
说明:
- 默认工作区遵循 `~/.openclaw/workspace-<agentId>`
- 添加 `bindings` 以路由入站消息(导可以完成这项操作)。
- 添加 `bindings` 以路由入站消息(新手引导可以完成这项操作)。
- 非交互式标志:`--model`、`--agent-dir`、`--bind`、`--non-interactive`。
## 完整参考
@ -122,7 +122,7 @@ CLI `--reset` 默认会重置配置、凭证和会话;如需包含工作区,
[CLI 设置参考](/start/wizard-cli-reference)。
有关非交互式示例,请参见 [CLI 自动化](/start/wizard-cli-automation)。
有关更深入的技术参考(包括 RPC 细节),请参见
[导参考](/reference/wizard)。
[新手引导参考](/reference/wizard)。
## 相关文档

View File

@ -1,7 +1,7 @@
import fs from "node:fs";
import { chmod, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import path from "node:path";
import { resolvePreferredOpenClawTmpDir } from "../../../../src/infra/tmp-openclaw-dir.js";
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/infra-runtime";
import type { ResolvedAcpxPluginConfig } from "../config.js";
import { ACPX_PINNED_VERSION } from "../config.js";
import { AcpxRuntime } from "../runtime.js";

View File

@ -1,3 +1,5 @@
import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
import { parseDurationMs } from "openclaw/plugin-sdk/cli-runtime";
import {
emptyPluginConfigSchema,
type OpenClawPluginApi,
@ -7,25 +9,26 @@ import {
} from "openclaw/plugin-sdk/core";
import {
CLAUDE_CLI_PROFILE_ID,
applyAuthProfileConfig,
buildTokenProfileId,
createProviderApiKeyAuthMethod,
ensureApiKeyFromOptionEnvOrPrompt,
listProfilesForProvider,
upsertAuthProfile,
} from "../../src/agents/auth-profiles.js";
import { suggestOAuthProfileIdForLegacyDefault } from "../../src/agents/auth-profiles/repair.js";
import type { AuthProfileStore } from "../../src/agents/auth-profiles/types.js";
import { normalizeModelCompat } from "../../src/agents/model-compat.js";
import { formatCliCommand } from "../../src/cli/command-format.js";
import { parseDurationMs } from "../../src/cli/parse-duration.js";
import {
normalizeApiKeyInput,
suggestOAuthProfileIdForLegacyDefault,
type AuthProfileStore,
type ProviderAuthResult,
normalizeSecretInput,
normalizeSecretInputModeInput,
promptSecretRefForSetup,
resolveSecretInputModeForEnvSelection,
} from "../../src/commands/auth-choice.apply-helpers.js";
import { buildTokenProfileId, validateAnthropicSetupToken } from "../../src/commands/auth-token.js";
import { applyAuthProfileConfig } from "../../src/commands/onboard-auth.js";
import { fetchClaudeUsage } from "../../src/infra/provider-usage.fetch.js";
import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js";
import type { ProviderAuthResult } from "../../src/plugins/types.js";
import { normalizeSecretInput } from "../../src/utils/normalize-secret-input.js";
upsertAuthProfile,
validateAnthropicSetupToken,
validateApiKeyInput,
} from "openclaw/plugin-sdk/provider-auth";
import { normalizeModelCompat } from "openclaw/plugin-sdk/provider-models";
import { fetchClaudeUsage } from "openclaw/plugin-sdk/provider-usage";
import { anthropicMediaUnderstandingProvider } from "./media-understanding-provider.js";
const PROVIDER_ID = "anthropic";
const DEFAULT_ANTHROPIC_MODEL = "anthropic/claude-sonnet-4-6";
@ -394,6 +397,7 @@ const anthropicPlugin = {
profileId: ctx.profileId,
}),
});
api.registerMediaUnderstandingProvider(anthropicMediaUnderstandingProvider);
},
};

View File

@ -0,0 +1,12 @@
import {
describeImageWithModel,
describeImagesWithModel,
type MediaUnderstandingProvider,
} from "openclaw/plugin-sdk/media-understanding";
export const anthropicMediaUnderstandingProvider: MediaUnderstandingProvider = {
id: "anthropic",
capabilities: ["image"],
describeImage: describeImageWithModel,
describeImages: describeImagesWithModel,
};

View File

@ -1,13 +1,12 @@
import {
applyAccountNameToChannelSection,
migrateBaseNameToDefaultAccount,
normalizeAccountId,
patchScopedAccountConfig,
} from "../../../src/channels/plugins/setup-helpers.js";
import { setTopLevelChannelDmPolicyWithAllowFrom } from "../../../src/channels/plugins/setup-wizard-helpers.js";
import type { ChannelSetupAdapter } from "../../../src/channels/plugins/types.adapters.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import type { DmPolicy } from "../../../src/config/types.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/session-key.js";
prepareScopedSetupConfig,
setTopLevelChannelDmPolicyWithAllowFrom,
type ChannelSetupAdapter,
type DmPolicy,
type OpenClawConfig,
} from "openclaw/plugin-sdk/setup";
import { applyBlueBubblesConnectionConfig } from "./config-apply.js";
const channel = "bluebubbles" as const;
@ -38,7 +37,7 @@ export function setBlueBubblesAllowFrom(
export const blueBubblesSetupAdapter: ChannelSetupAdapter = {
resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
applyAccountName: ({ cfg, accountId, name }) =>
applyAccountNameToChannelSection({
prepareScopedSetupConfig({
cfg,
channelKey: channel,
accountId,
@ -57,19 +56,13 @@ export const blueBubblesSetupAdapter: ChannelSetupAdapter = {
return null;
},
applyAccountConfig: ({ cfg, accountId, input }) => {
const namedConfig = applyAccountNameToChannelSection({
const next = prepareScopedSetupConfig({
cfg,
channelKey: channel,
accountId,
name: input.name,
migrateBaseName: true,
});
const next =
accountId !== DEFAULT_ACCOUNT_ID
? migrateBaseNameToDefaultAccount({
cfg: namedConfig,
channelKey: channel,
})
: namedConfig;
return applyBlueBubblesConnectionConfig({
cfg: next,
accountId,

View File

@ -1,14 +1,14 @@
import {
DEFAULT_ACCOUNT_ID,
formatDocsLink,
mergeAllowFromEntries,
resolveSetupAccountId,
} from "../../../src/channels/plugins/setup-wizard-helpers.js";
import type { ChannelSetupDmPolicy } from "../../../src/channels/plugins/setup-wizard-types.js";
import type { ChannelSetupWizard } from "../../../src/channels/plugins/setup-wizard.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import type { DmPolicy } from "../../../src/config/types.js";
import { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js";
import { formatDocsLink } from "../../../src/terminal/links.js";
import type { WizardPrompter } from "../../../src/wizard/prompts.js";
type ChannelSetupDmPolicy,
type ChannelSetupWizard,
type DmPolicy,
type OpenClawConfig,
type WizardPrompter,
} from "openclaw/plugin-sdk/setup";
import {
listBlueBubblesAccountIds,
resolveBlueBubblesAccount,

View File

@ -1,10 +1,9 @@
import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core";
import {
createPluginBackedWebSearchProvider,
getTopLevelCredentialValue,
setTopLevelCredentialValue,
} from "../../src/agents/tools/web-search-plugin-factory.js";
import { emptyPluginConfigSchema } from "../../src/plugins/config-schema.js";
import type { OpenClawPluginApi } from "../../src/plugins/types.js";
} from "openclaw/plugin-sdk/provider-web-search";
const bravePlugin = {
id: "brave",

View File

@ -1,10 +1,7 @@
import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core";
import {
buildBytePlusCodingProvider,
buildBytePlusProvider,
} from "../../src/agents/models-config.providers.static.js";
import { ensureModelAllowlistEntry } from "../../src/commands/model-allowlist.js";
import { createProviderApiKeyAuthMethod } from "../../src/plugins/provider-api-key-auth.js";
import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth";
import { ensureModelAllowlistEntry } from "openclaw/plugin-sdk/provider-onboard";
import { buildBytePlusCodingProvider, buildBytePlusProvider } from "./provider-catalog.js";
const PROVIDER_ID = "byteplus";
const BYTEPLUS_DEFAULT_MODEL_REF = "byteplus-plan/ark-code-latest";

View File

@ -0,0 +1,24 @@
import {
buildBytePlusModelDefinition,
BYTEPLUS_BASE_URL,
BYTEPLUS_CODING_BASE_URL,
BYTEPLUS_CODING_MODEL_CATALOG,
BYTEPLUS_MODEL_CATALOG,
type ModelProviderConfig,
} from "openclaw/plugin-sdk/provider-models";
export function buildBytePlusProvider(): ModelProviderConfig {
return {
baseUrl: BYTEPLUS_BASE_URL,
api: "openai-completions",
models: BYTEPLUS_MODEL_CATALOG.map(buildBytePlusModelDefinition),
};
}
export function buildBytePlusCodingProvider(): ModelProviderConfig {
return {
baseUrl: BYTEPLUS_CODING_BASE_URL,
api: "openai-completions",
models: BYTEPLUS_CODING_MODEL_CATALOG.map(buildBytePlusModelDefinition),
};
}

View File

@ -1,25 +1,27 @@
import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core";
import { upsertAuthProfile } from "../../src/agents/auth-profiles.js";
import { ensureAuthProfileStore, listProfilesForProvider } from "../../src/agents/auth-profiles.js";
import {
applyAuthProfileConfig,
buildApiKeyCredential,
coerceSecretRef,
ensureApiKeyFromOptionEnvOrPrompt,
ensureAuthProfileStore,
listProfilesForProvider,
normalizeApiKeyInput,
normalizeOptionalSecretInput,
resolveNonEnvSecretRefApiKeyMarker,
type SecretInput,
upsertAuthProfile,
validateApiKeyInput,
} from "openclaw/plugin-sdk/provider-auth";
import {
buildCloudflareAiGatewayModelDefinition,
resolveCloudflareAiGatewayBaseUrl,
} from "../../src/agents/cloudflare-ai-gateway.js";
import { resolveNonEnvSecretRefApiKeyMarker } from "../../src/agents/model-auth-markers.js";
import {
normalizeApiKeyInput,
validateApiKeyInput,
} from "../../src/commands/auth-choice.api-key.js";
import { ensureApiKeyFromOptionEnvOrPrompt } from "../../src/commands/auth-choice.apply-helpers.js";
import { buildApiKeyCredential } from "../../src/commands/onboard-auth.credentials.js";
} from "openclaw/plugin-sdk/provider-models";
import {
applyCloudflareAiGatewayConfig,
applyAuthProfileConfig,
buildCloudflareAiGatewayConfigPatch,
CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF,
} from "../../src/commands/onboard-auth.js";
import type { SecretInput } from "../../src/config/types.secrets.js";
import { coerceSecretRef } from "../../src/config/types.secrets.js";
import { normalizeOptionalSecretInput } from "../../src/utils/normalize-secret-input.js";
} from "./onboard.js";
const PROVIDER_ID = "cloudflare-ai-gateway";
const PROVIDER_ENV_VAR = "CLOUDFLARE_AI_GATEWAY_API_KEY";
@ -53,30 +55,6 @@ function resolveMetadataFromCredential(
};
}
function buildCloudflareConfigPatch(params: { accountId: string; gatewayId: string }) {
const baseUrl = resolveCloudflareAiGatewayBaseUrl(params);
return {
models: {
providers: {
[PROVIDER_ID]: {
baseUrl,
api: "anthropic-messages" as const,
models: [buildCloudflareAiGatewayModelDefinition()],
},
},
},
agents: {
defaults: {
models: {
[CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF]: {
alias: "Cloudflare AI Gateway",
},
},
},
},
};
}
async function resolveCloudflareGatewayMetadataInteractive(ctx: {
accountId?: string;
gatewayId?: string;
@ -180,7 +158,7 @@ const cloudflareAiGatewayPlugin = {
),
},
],
configPatch: buildCloudflareConfigPatch(metadata),
configPatch: buildCloudflareAiGatewayConfigPatch(metadata),
defaultModel: CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF,
};
},

View File

@ -0,0 +1,93 @@
import {
buildCloudflareAiGatewayModelDefinition,
CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF,
resolveCloudflareAiGatewayBaseUrl,
} from "openclaw/plugin-sdk/provider-models";
import {
applyAgentDefaultModelPrimary,
applyProviderConfigWithDefaultModel,
type OpenClawConfig,
} from "openclaw/plugin-sdk/provider-onboard";
export { CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF };
export function buildCloudflareAiGatewayConfigPatch(params: {
accountId: string;
gatewayId: string;
}) {
const baseUrl = resolveCloudflareAiGatewayBaseUrl(params);
return {
models: {
providers: {
"cloudflare-ai-gateway": {
baseUrl,
api: "anthropic-messages" as const,
models: [buildCloudflareAiGatewayModelDefinition()],
},
},
},
agents: {
defaults: {
models: {
[CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF]: {
alias: "Cloudflare AI Gateway",
},
},
},
},
};
}
export function applyCloudflareAiGatewayProviderConfig(
cfg: OpenClawConfig,
params?: { accountId?: string; gatewayId?: string },
): OpenClawConfig {
const models = { ...cfg.agents?.defaults?.models };
models[CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF] = {
...models[CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF],
alias: models[CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF]?.alias ?? "Cloudflare AI Gateway",
};
const existingProvider = cfg.models?.providers?.["cloudflare-ai-gateway"] as
| { baseUrl?: unknown }
| undefined;
const baseUrl =
params?.accountId && params?.gatewayId
? resolveCloudflareAiGatewayBaseUrl({
accountId: params.accountId,
gatewayId: params.gatewayId,
})
: typeof existingProvider?.baseUrl === "string"
? existingProvider.baseUrl
: undefined;
if (!baseUrl) {
return {
...cfg,
agents: {
...cfg.agents,
defaults: {
...cfg.agents?.defaults,
models,
},
},
};
}
return applyProviderConfigWithDefaultModel(cfg, {
agentModels: models,
providerId: "cloudflare-ai-gateway",
api: "anthropic-messages",
baseUrl,
defaultModel: buildCloudflareAiGatewayModelDefinition(),
});
}
export function applyCloudflareAiGatewayConfig(
cfg: OpenClawConfig,
params?: { accountId?: string; gatewayId?: string },
): OpenClawConfig {
return applyAgentDefaultModelPrimary(
applyCloudflareAiGatewayProviderConfig(cfg, params),
CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF,
);
}

View File

@ -1,13 +1,13 @@
import {
hasConfiguredSecretInput,
normalizeSecretInputString,
} from "openclaw/plugin-sdk/config-runtime";
import type { DiscordAccountConfig } from "../../../src/config/types.js";
import {
DEFAULT_ACCOUNT_ID,
normalizeAccountId,
type OpenClawConfig,
type DiscordAccountConfig,
} from "openclaw/plugin-sdk/discord";
import {
hasConfiguredSecretInput,
normalizeSecretInputString,
} from "../../../src/config/types.secrets.js";
} from "../../../src/plugin-sdk-internal/accounts.js";
import {
mergeDiscordAccountConfig,
resolveDefaultDiscordAccountId,

View File

@ -1,12 +1,11 @@
import type {
OpenClawConfig,
DiscordAccountConfig,
DiscordActionConfig,
} from "openclaw/plugin-sdk/discord";
import { createAccountActionGate } from "../../../src/channels/plugins/account-action-gate.js";
import { createAccountListHelpers } from "../../../src/channels/plugins/account-helpers.js";
import { resolveAccountEntry } from "../../../src/routing/account-lookup.js";
import { normalizeAccountId } from "../../../src/routing/session-key.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import type { DiscordAccountConfig, DiscordActionConfig } from "../../../src/config/types.js";
import {
createAccountActionGate,
createAccountListHelpers,
normalizeAccountId,
resolveAccountEntry,
} from "../../../src/plugin-sdk-internal/accounts.js";
import { resolveDiscordToken } from "./token.js";
export type ResolvedDiscordAccount = {

View File

@ -4,13 +4,13 @@ import {
readNumberParam,
readStringArrayParam,
readStringParam,
} from "../../../../src/agents/tools/common.js";
} from "openclaw/plugin-sdk/agent-runtime";
import {
isDiscordModerationAction,
readDiscordModerationCommand,
} from "../../../../src/agents/tools/discord-actions-moderation-shared.js";
import { handleDiscordAction } from "../../../../src/agents/tools/discord-actions.js";
import type { ChannelMessageActionContext } from "../../../../src/channels/plugins/types.js";
} from "openclaw/plugin-sdk/agent-runtime";
import { handleDiscordAction } from "openclaw/plugin-sdk/agent-runtime";
import type { ChannelMessageActionContext } from "openclaw/plugin-sdk/channel-runtime";
type Ctx = Pick<
ChannelMessageActionContext,

View File

@ -3,13 +3,13 @@ import {
readNumberParam,
readStringArrayParam,
readStringParam,
} from "../../../../src/agents/tools/common.js";
import { readDiscordParentIdParam } from "../../../../src/agents/tools/discord-actions-shared.js";
import { handleDiscordAction } from "../../../../src/agents/tools/discord-actions.js";
import { resolveReactionMessageId } from "../../../../src/channels/plugins/actions/reaction-message-id.js";
import type { ChannelMessageActionContext } from "../../../../src/channels/plugins/types.js";
import { normalizeInteractiveReply } from "../../../../src/interactive/payload.js";
import { readBooleanParam } from "../../../../src/plugin-sdk/boolean-param.js";
} from "openclaw/plugin-sdk/agent-runtime";
import { readDiscordParentIdParam } from "openclaw/plugin-sdk/agent-runtime";
import { handleDiscordAction } from "openclaw/plugin-sdk/agent-runtime";
import { readBooleanParam } from "openclaw/plugin-sdk/boolean-param";
import { resolveReactionMessageId } from "openclaw/plugin-sdk/channel-runtime";
import type { ChannelMessageActionContext } from "openclaw/plugin-sdk/channel-runtime";
import { normalizeInteractiveReply } from "openclaw/plugin-sdk/channel-runtime";
import { buildDiscordInteractiveComponents } from "../shared-interactive.js";
import { resolveDiscordChannelId } from "../targets.js";
import { tryHandleDiscordMessageActionGuildAdmin } from "./handle-action.guild-admin.js";

View File

@ -1,5 +1,9 @@
import { resolveFetch } from "../../../src/infra/fetch.js";
import { resolveRetryConfig, retryAsync, type RetryConfig } from "../../../src/infra/retry.js";
import { resolveFetch } from "openclaw/plugin-sdk/infra-runtime";
import {
resolveRetryConfig,
retryAsync,
type RetryConfig,
} from "openclaw/plugin-sdk/infra-runtime";
const DISCORD_API_BASE = "https://discord.com/api/v10";
const DISCORD_API_RETRY_DEFAULTS = {

View File

@ -1,6 +1,9 @@
import type { OpenClawConfig } from "../../../src/config/config.js";
import type { DiscordGuildChannelConfig, DiscordGuildEntry } from "../../../src/config/types.js";
import { isRecord } from "../../../src/utils.js";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import type {
DiscordGuildChannelConfig,
DiscordGuildEntry,
} from "openclaw/plugin-sdk/config-runtime";
import { isRecord } from "openclaw/plugin-sdk/text-runtime";
import { inspectDiscordAccount } from "./account-inspect.js";
import { fetchChannelPermissionsDiscord } from "./send.js";

View File

@ -1,12 +1,12 @@
import {
createUnionActionGate,
listTokenSourcedAccounts,
} from "../../../src/channels/plugins/actions/shared.js";
} from "openclaw/plugin-sdk/channel-runtime";
import type {
ChannelMessageActionAdapter,
ChannelMessageActionName,
} from "../../../src/channels/plugins/types.js";
import type { DiscordActionConfig } from "../../../src/config/types.discord.js";
} from "openclaw/plugin-sdk/channel-runtime";
import type { DiscordActionConfig } from "openclaw/plugin-sdk/config-runtime";
import { createDiscordActionGate, listEnabledDiscordAccounts } from "./accounts.js";
import { handleDiscordMessageAction } from "./actions/handle-action.js";

View File

@ -1,46 +1,12 @@
import { createScopedChannelConfigBase } from "openclaw/plugin-sdk/compat";
import {
createScopedAccountConfigAccessors,
formatAllowFromLowercase,
} from "openclaw/plugin-sdk/compat";
import {
buildChannelConfigSchema,
DiscordConfigSchema,
getChatChannelMeta,
type ChannelPlugin,
} from "openclaw/plugin-sdk/discord";
import { inspectDiscordAccount } from "./account-inspect.js";
import {
listDiscordAccountIds,
resolveDefaultDiscordAccountId,
resolveDiscordAccount,
type ResolvedDiscordAccount,
} from "./accounts.js";
import { createDiscordSetupWizardProxy, discordSetupAdapter } from "./setup-core.js";
async function loadDiscordChannelRuntime() {
return await import("./channel.runtime.js");
}
const discordConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }) => resolveDiscordAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedDiscordAccount) => account.config.dm?.allowFrom,
formatAllowFrom: (allowFrom) => formatAllowFromLowercase({ allowFrom }),
resolveDefaultTo: (account: ResolvedDiscordAccount) => account.config.defaultTo,
});
const discordConfigBase = createScopedChannelConfigBase({
sectionKey: "discord",
listAccountIds: listDiscordAccountIds,
resolveAccount: (cfg, accountId) => resolveDiscordAccount({ cfg, accountId }),
inspectAccount: (cfg, accountId) => inspectDiscordAccount({ cfg, accountId }),
defaultAccountId: resolveDefaultDiscordAccountId,
clearBaseFields: ["token", "name"],
});
const discordSetupWizard = createDiscordSetupWizardProxy(async () => ({
discordSetupWizard: (await loadDiscordChannelRuntime()).discordSetupWizard,
}));
import { type ResolvedDiscordAccount } from "./accounts.js";
import { discordConfigAccessors, discordConfigBase, discordSetupWizard } from "./plugin-shared.js";
import { discordSetupAdapter } from "./setup-core.js";
export const discordSetupPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
id: "discord",

View File

@ -1,13 +1,15 @@
import { Separator, TextDisplay } from "@buape/carbon";
import { createScopedChannelConfigBase } from "openclaw/plugin-sdk/compat";
import {
buildAccountScopedAllowlistConfigEditor,
resolveLegacyDmAllowlistConfigPaths,
} from "openclaw/plugin-sdk/allowlist-config-edit";
import {
buildAccountScopedDmSecurityPolicy,
collectOpenProviderGroupPolicyWarnings,
collectOpenGroupPolicyConfiguredRouteWarnings,
createScopedAccountConfigAccessors,
formatAllowFromLowercase,
} from "openclaw/plugin-sdk/compat";
collectOpenProviderGroupPolicyWarnings,
} from "openclaw/plugin-sdk/channel-config-helpers";
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime";
import { normalizeMessageChannel } from "openclaw/plugin-sdk/channel-runtime";
import {
buildAgentSessionKey,
resolveThreadSessionKeys,
@ -31,13 +33,9 @@ import {
type ChannelPlugin,
type OpenClawConfig,
} from "openclaw/plugin-sdk/discord";
import { resolveOutboundSendDep } from "../../../src/infra/outbound/send-deps.js";
import { normalizeMessageChannel } from "../../../src/utils/message-channel.js";
import { inspectDiscordAccount } from "./account-inspect.js";
import {
listDiscordAccountIds,
resolveDiscordAccount,
resolveDefaultDiscordAccountId,
type ResolvedDiscordAccount,
} from "./accounts.js";
import { collectDiscordAuditChannelIds } from "./audit.js";
@ -50,11 +48,12 @@ import {
normalizeDiscordMessagingTarget,
normalizeDiscordOutboundTarget,
} from "./normalize.js";
import { discordConfigAccessors, discordConfigBase, discordSetupWizard } from "./plugin-shared.js";
import type { DiscordProbe } from "./probe.js";
import { resolveDiscordUserAllowlist } from "./resolve-users.js";
import { getDiscordRuntime } from "./runtime.js";
import { fetchChannelPermissionsDiscord } from "./send.js";
import { createDiscordSetupWizardProxy, discordSetupAdapter } from "./setup-core.js";
import { discordSetupAdapter } from "./setup-core.js";
import { collectDiscordStatusIssues } from "./status-issues.js";
import { parseDiscordTarget } from "./targets.js";
import { DiscordUiContainer } from "./ui.js";
@ -66,10 +65,6 @@ type DiscordSendFn = ReturnType<
const meta = getChatChannelMeta("discord");
const REQUIRED_DISCORD_PERMISSIONS = ["ViewChannel", "SendMessages"] as const;
async function loadDiscordChannelRuntime() {
return await import("./channel.runtime.js");
}
function formatDiscordIntents(intents?: {
messageContent?: string;
guildMembers?: string;
@ -304,26 +299,6 @@ function resolveDiscordOutboundSessionRoute(params: {
};
}
const discordConfigAccessors = createScopedAccountConfigAccessors({
resolveAccount: ({ cfg, accountId }) => resolveDiscordAccount({ cfg, accountId }),
resolveAllowFrom: (account: ResolvedDiscordAccount) => account.config.dm?.allowFrom,
formatAllowFrom: (allowFrom) => formatAllowFromLowercase({ allowFrom }),
resolveDefaultTo: (account: ResolvedDiscordAccount) => account.config.defaultTo,
});
const discordConfigBase = createScopedChannelConfigBase({
sectionKey: "discord",
listAccountIds: listDiscordAccountIds,
resolveAccount: (cfg, accountId) => resolveDiscordAccount({ cfg, accountId }),
inspectAccount: (cfg, accountId) => inspectDiscordAccount({ cfg, accountId }),
defaultAccountId: resolveDefaultDiscordAccountId,
clearBaseFields: ["token", "name"],
});
const discordSetupWizard = createDiscordSetupWizardProxy(async () => ({
discordSetupWizard: (await loadDiscordChannelRuntime()).discordSetupWizard,
}));
export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
id: "discord",
meta: {
@ -375,14 +350,7 @@ export const discordPlugin: ChannelPlugin<ResolvedDiscordAccount> = {
channelId: "discord",
normalize: ({ cfg, accountId, values }) =>
discordConfigAccessors.formatAllowFrom!({ cfg, accountId, allowFrom: values }),
resolvePaths: (scope) =>
scope === "dm"
? {
readPaths: [["allowFrom"], ["dm", "allowFrom"]],
writePath: ["allowFrom"],
cleanupPaths: [["dm", "allowFrom"]],
}
: null,
resolvePaths: resolveLegacyDmAllowlistConfigPaths,
}),
},
security: {

View File

@ -1,4 +1,4 @@
import { chunkMarkdownTextWithMode, type ChunkMode } from "../../../src/auto-reply/chunk.js";
import { chunkMarkdownTextWithMode, type ChunkMode } from "openclaw/plugin-sdk/reply-runtime";
export type ChunkDiscordTextOpts = {
/** Max characters per Discord message. Default: 2000. */

View File

@ -1,8 +1,8 @@
import { RequestClient } from "@buape/carbon";
import { loadConfig } from "../../../src/config/config.js";
import { createDiscordRetryRunner, type RetryRunner } from "../../../src/infra/retry-policy.js";
import type { RetryConfig } from "../../../src/infra/retry.js";
import { normalizeAccountId } from "../../../src/routing/session-key.js";
import { loadConfig } from "openclaw/plugin-sdk/config-runtime";
import { createDiscordRetryRunner, type RetryRunner } from "openclaw/plugin-sdk/infra-runtime";
import type { RetryConfig } from "openclaw/plugin-sdk/infra-runtime";
import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
import {
mergeDiscordAccountConfig,
resolveDiscordAccount,

View File

@ -1,4 +1,4 @@
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/account-id.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing";
const DISCORD_DIRECTORY_CACHE_MAX_ENTRIES = 4000;
const DISCORD_DISCRIMINATOR_SUFFIX = /#\d{4}$/;

View File

@ -1,5 +1,5 @@
import type { DirectoryConfigParams } from "../../../src/channels/plugins/directory-config.js";
import type { ChannelDirectoryEntry } from "../../../src/channels/plugins/types.js";
import type { DirectoryConfigParams } from "openclaw/plugin-sdk/channel-runtime";
import type { ChannelDirectoryEntry } from "openclaw/plugin-sdk/channel-runtime";
import { resolveDiscordAccount } from "./accounts.js";
import { fetchDiscord } from "./api.js";
import { rememberDiscordDirectoryUser } from "./directory-cache.js";

View File

@ -1,7 +1,7 @@
import { resolveTextChunkLimit } from "../../../src/auto-reply/chunk.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import { resolveAccountEntry } from "../../../src/routing/account-lookup.js";
import { normalizeAccountId } from "../../../src/routing/session-key.js";
import { type OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime";
import { resolveAccountEntry } from "openclaw/plugin-sdk/routing";
import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
import { DISCORD_TEXT_CHUNK_LIMIT } from "./outbound-adapter.js";
const DEFAULT_DISCORD_DRAFT_STREAM_MIN = 200;

View File

@ -1,6 +1,6 @@
import type { RequestClient } from "@buape/carbon";
import { Routes } from "discord-api-types/v10";
import { createFinalizableDraftLifecycle } from "../../../src/channels/draft-stream-controls.js";
import { createFinalizableDraftLifecycle } from "openclaw/plugin-sdk/channel-runtime";
/** Discord messages cap at 2000 characters. */
const DISCORD_STREAM_MAX_CHARS = 2000;

View File

@ -1,6 +1,6 @@
import type { ReplyPayload } from "../../../src/auto-reply/types.js";
import type { OpenClawConfig } from "../../../src/config/config.js";
import { getExecApprovalReplyMetadata } from "../../../src/infra/exec-approval-reply.js";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { getExecApprovalReplyMetadata } from "openclaw/plugin-sdk/infra-runtime";
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
import { resolveDiscordAccount } from "./accounts.js";
export function isDiscordExecApprovalClientEnabled(params: {

View File

@ -1,6 +1,6 @@
import type { EventEmitter } from "node:events";
import { logVerbose } from "../../../src/globals.js";
import type { RuntimeEnv } from "../../../src/runtime.js";
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
type GatewayEmitter = Pick<EventEmitter, "on" | "removeListener">;

View File

@ -1,5 +1,5 @@
import type { MockFn } from "openclaw/plugin-sdk/test-utils";
import { vi } from "vitest";
import type { MockFn } from "../../../src/test-utils/vitest-mock-fn.js";
export const sendMock: MockFn = vi.fn();
export const reactMock: MockFn = vi.fn();
@ -15,8 +15,8 @@ vi.mock("./send.js", () => ({
},
}));
vi.mock("../../../src/auto-reply/dispatch.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../../src/auto-reply/dispatch.js")>();
vi.mock("openclaw/plugin-sdk/reply-runtime", async (importOriginal) => {
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/reply-runtime")>();
return {
...actual,
dispatchInboundMessage: (...args: unknown[]) => dispatchMock(...args),
@ -36,10 +36,10 @@ function createPairingStoreMocks() {
};
}
vi.mock("../../../src/pairing/pairing-store.js", () => createPairingStoreMocks());
vi.mock("openclaw/plugin-sdk/conversation-runtime", () => createPairingStoreMocks());
vi.mock("../../../src/config/sessions.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../../src/config/sessions.js")>();
vi.mock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => {
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/config-runtime")>();
return {
...actual,
resolveStorePath: vi.fn(() => "/tmp/openclaw-sessions.json"),

View File

@ -18,41 +18,41 @@ import {
} from "@buape/carbon";
import type { APIStringSelectComponent } from "discord-api-types/v10";
import { ButtonStyle, ChannelType } from "discord-api-types/v10";
import { resolveHumanDelayConfig } from "../../../../src/agents/identity.js";
import { resolveChunkMode, resolveTextChunkLimit } from "../../../../src/auto-reply/chunk.js";
import {
formatInboundEnvelope,
resolveEnvelopeFormatOptions,
} from "../../../../src/auto-reply/envelope.js";
import { finalizeInboundContext } from "../../../../src/auto-reply/reply/inbound-context.js";
import { dispatchReplyWithBufferedBlockDispatcher } from "../../../../src/auto-reply/reply/provider-dispatcher.js";
import { createReplyReferencePlanner } from "../../../../src/auto-reply/reply/reply-reference.js";
import { resolveCommandAuthorizedFromAuthorizers } from "../../../../src/channels/command-gating.js";
import { createReplyPrefixOptions } from "../../../../src/channels/reply-prefix.js";
import { recordInboundSession } from "../../../../src/channels/session.js";
import type { OpenClawConfig } from "../../../../src/config/config.js";
import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js";
import { resolveMarkdownTableMode } from "../../../../src/config/markdown-tables.js";
import { readSessionUpdatedAt, resolveStorePath } from "../../../../src/config/sessions.js";
import type { DiscordAccountConfig } from "../../../../src/config/types.discord.js";
import { logVerbose } from "../../../../src/globals.js";
import { enqueueSystemEvent } from "../../../../src/infra/system-events.js";
import { logDebug, logError } from "../../../../src/logger.js";
import { getAgentScopedMediaLocalRoots } from "../../../../src/media/local-roots.js";
import { issuePairingChallenge } from "../../../../src/pairing/pairing-challenge.js";
import { upsertChannelPairingRequest } from "../../../../src/pairing/pairing-store.js";
import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
import { resolveCommandAuthorizedFromAuthorizers } from "openclaw/plugin-sdk/channel-runtime";
import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime";
import { recordInboundSession } from "openclaw/plugin-sdk/channel-runtime";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime";
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime";
import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/config-runtime";
import type { DiscordAccountConfig } from "openclaw/plugin-sdk/config-runtime";
import { issuePairingChallenge } from "openclaw/plugin-sdk/conversation-runtime";
import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
import {
buildPluginBindingResolvedText,
parsePluginBindingApprovalCustomId,
resolvePluginConversationBindingApproval,
} from "../../../../src/plugins/conversation-binding.js";
import { dispatchPluginInteractiveHandler } from "../../../../src/plugins/interactive.js";
import { resolveAgentRoute } from "../../../../src/routing/resolve-route.js";
import { createNonExitingRuntime, type RuntimeEnv } from "../../../../src/runtime.js";
} from "openclaw/plugin-sdk/conversation-runtime";
import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime";
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
import { dispatchPluginInteractiveHandler } from "openclaw/plugin-sdk/plugin-runtime";
import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-runtime";
import {
formatInboundEnvelope,
resolveEnvelopeFormatOptions,
} from "openclaw/plugin-sdk/reply-runtime";
import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime";
import { dispatchReplyWithBufferedBlockDispatcher } from "openclaw/plugin-sdk/reply-runtime";
import { createReplyReferencePlanner } from "openclaw/plugin-sdk/reply-runtime";
import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
import { createNonExitingRuntime, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
import {
readStoreAllowFromForDmPolicy,
resolvePinnedMainDmOwnerFromAllowlist,
} from "../../../../src/security/dm-policy-shared.js";
} from "openclaw/plugin-sdk/security-runtime";
import { logDebug, logError } from "openclaw/plugin-sdk/text-runtime";
import { resolveDiscordMaxLinesPerMessage } from "../accounts.js";
import { resolveDiscordComponentEntry, resolveDiscordModalEntry } from "../components-registry.js";
import {

View File

@ -1,12 +1,12 @@
import type { Guild, User } from "@buape/carbon";
import type { AllowlistMatch } from "../../../../src/channels/allowlist-match.js";
import type { AllowlistMatch } from "openclaw/plugin-sdk/channel-runtime";
import {
buildChannelKeyCandidates,
resolveChannelEntryMatchWithFallback,
resolveChannelMatchConfig,
type ChannelMatchSource,
} from "../../../../src/channels/channel-config.js";
import { evaluateGroupRouteAccessForPolicy } from "../../../../src/plugin-sdk/group-access.js";
} from "openclaw/plugin-sdk/channel-runtime";
import { evaluateGroupRouteAccessForPolicy } from "openclaw/plugin-sdk/group-access";
import { formatDiscordUserTag } from "./format.js";
export type DiscordAllowList = {

View File

@ -6,12 +6,12 @@ import {
resolveProfilesUnavailableReason,
type AuthProfileFailureReason,
type AuthProfileStore,
} from "../../../../src/agents/auth-profiles.js";
} from "openclaw/plugin-sdk/agent-runtime";
import type {
DiscordAccountConfig,
DiscordAutoPresenceConfig,
} from "../../../../src/config/config.js";
import { warn } from "../../../../src/globals.js";
} from "openclaw/plugin-sdk/config-runtime";
import { warn } from "openclaw/plugin-sdk/runtime-env";
import { resolveDiscordPresenceUpdate } from "./presence.js";
const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4;

View File

@ -1,4 +1,4 @@
import type { DiscordSlashCommandConfig } from "../../../../src/config/types.discord.js";
import type { DiscordSlashCommandConfig } from "openclaw/plugin-sdk/config-runtime";
export function resolveDiscordSlashCommandConfig(
raw?: DiscordSlashCommandConfig,

View File

@ -1,9 +1,9 @@
import { resolveCommandAuthorizedFromAuthorizers } from "../../../../src/channels/command-gating.js";
import { resolveCommandAuthorizedFromAuthorizers } from "openclaw/plugin-sdk/channel-runtime";
import {
readStoreAllowFromForDmPolicy,
resolveDmGroupAccessWithLists,
type DmGroupAccessDecision,
} from "../../../../src/security/dm-policy-shared.js";
} from "openclaw/plugin-sdk/security-runtime";
import { normalizeDiscordAllowList, resolveDiscordAllowListMatch } from "./allow-list.js";
const DISCORD_ALLOW_LIST_PREFIXES = ["discord:", "user:", "pk:"];

View File

@ -1,5 +1,5 @@
import { issuePairingChallenge } from "../../../../src/pairing/pairing-challenge.js";
import { upsertChannelPairingRequest } from "../../../../src/pairing/pairing-store.js";
import { issuePairingChallenge } from "openclaw/plugin-sdk/conversation-runtime";
import { upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
import type { DiscordDmCommandAccess } from "./dm-command-auth.js";
export async function handleDiscordDmCommandDecision(params: {

View File

@ -10,30 +10,24 @@ import {
type TopLevelComponents,
} from "@buape/carbon";
import { ButtonStyle, Routes } from "discord-api-types/v10";
import type { OpenClawConfig } from "../../../../src/config/config.js";
import { loadSessionStore, resolveStorePath } from "../../../../src/config/sessions.js";
import type { DiscordExecApprovalConfig } from "../../../../src/config/types.discord.js";
import { GatewayClient } from "../../../../src/gateway/client.js";
import { createOperatorApprovalsGatewayClient } from "../../../../src/gateway/operator-approvals-client.js";
import type { EventFrame } from "../../../../src/gateway/protocol/index.js";
import { resolveExecApprovalCommandDisplay } from "../../../../src/infra/exec-approval-command-display.js";
import { getExecApprovalApproverDmNoticeText } from "../../../../src/infra/exec-approval-reply.js";
import { normalizeMessageChannel } from "openclaw/plugin-sdk/channel-runtime";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { loadSessionStore, resolveStorePath } from "openclaw/plugin-sdk/config-runtime";
import type { DiscordExecApprovalConfig } from "openclaw/plugin-sdk/config-runtime";
import { GatewayClient } from "openclaw/plugin-sdk/gateway-runtime";
import { createOperatorApprovalsGatewayClient } from "openclaw/plugin-sdk/gateway-runtime";
import type { EventFrame } from "openclaw/plugin-sdk/gateway-runtime";
import { resolveExecApprovalCommandDisplay } from "openclaw/plugin-sdk/infra-runtime";
import { getExecApprovalApproverDmNoticeText } from "openclaw/plugin-sdk/infra-runtime";
import type {
ExecApprovalDecision,
ExecApprovalRequest,
ExecApprovalResolved,
} from "../../../../src/infra/exec-approvals.js";
import { logDebug, logError } from "../../../../src/logger.js";
import {
normalizeAccountId,
resolveAgentIdFromSessionKey,
} from "../../../../src/routing/session-key.js";
import type { RuntimeEnv } from "../../../../src/runtime.js";
import {
compileSafeRegex,
testRegexWithBoundedInput,
} from "../../../../src/security/safe-regex.js";
import { normalizeMessageChannel } from "../../../../src/utils/message-channel.js";
} from "openclaw/plugin-sdk/infra-runtime";
import { normalizeAccountId, resolveAgentIdFromSessionKey } from "openclaw/plugin-sdk/routing";
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
import { compileSafeRegex, testRegexWithBoundedInput } from "openclaw/plugin-sdk/security-runtime";
import { logDebug, logError } from "openclaw/plugin-sdk/text-runtime";
import { createDiscordClient, stripUndefinedFields } from "../send.shared.js";
import { DiscordUiContainer } from "../ui.js";

View File

@ -1,11 +1,11 @@
import { GatewayIntents, GatewayPlugin } from "@buape/carbon/gateway";
import type { APIGatewayBotInfo } from "discord-api-types/v10";
import { HttpsProxyAgent } from "https-proxy-agent";
import type { DiscordAccountConfig } from "openclaw/plugin-sdk/config-runtime";
import { danger } from "openclaw/plugin-sdk/runtime-env";
import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
import { ProxyAgent, fetch as undiciFetch } from "undici";
import WebSocket from "ws";
import type { DiscordAccountConfig } from "../../../../src/config/types.js";
import { danger } from "../../../../src/globals.js";
import type { RuntimeEnv } from "../../../../src/runtime.js";
const DISCORD_GATEWAY_BOT_URL = "https://discord.com/api/v10/gateway/bot";
const DEFAULT_DISCORD_GATEWAY_URL = "wss://gateway.discord.gg/";
@ -20,7 +20,7 @@ type DiscordGatewayFetch = (
) => Promise<DiscordGatewayMetadataResponse>;
export function resolveDiscordGatewayIntents(
intentsConfig?: import("../../../../src/config/types.discord.js").DiscordIntentsConfig,
intentsConfig?: import("openclaw/plugin-sdk/config-runtime").DiscordIntentsConfig,
): number {
let intents =
GatewayIntents.Guilds |

View File

@ -1,4 +1,4 @@
import { buildUntrustedChannelMetadata } from "../../../../src/security/channel-metadata.js";
import { buildUntrustedChannelMetadata } from "openclaw/plugin-sdk/security-runtime";
import {
resolveDiscordOwnerAllowFrom,
type DiscordChannelConfigResolved,

View File

@ -1,7 +1,7 @@
import { createRunStateMachine } from "../../../../src/channels/run-state-machine.js";
import { danger } from "../../../../src/globals.js";
import { formatDurationSeconds } from "../../../../src/infra/format-time/format-duration.ts";
import { KeyedAsyncQueue } from "../../../../src/plugin-sdk/keyed-async-queue.js";
import { createRunStateMachine } from "openclaw/plugin-sdk/channel-runtime";
import { formatDurationSeconds } from "openclaw/plugin-sdk/infra-runtime";
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
import { danger } from "openclaw/plugin-sdk/runtime-env";
import { materializeDiscordInboundJob, type DiscordInboundJob } from "./inbound-job.js";
import type { RuntimeEnv } from "./message-handler.preflight.types.js";
import { processDiscordMessage } from "./message-handler.process.js";

View File

@ -8,16 +8,16 @@ import {
ThreadUpdateListener,
type User,
} from "@buape/carbon";
import type { OpenClawConfig } from "../../../../src/config/config.js";
import { danger, logVerbose } from "../../../../src/globals.js";
import { formatDurationSeconds } from "../../../../src/infra/format-time/format-duration.ts";
import { enqueueSystemEvent } from "../../../../src/infra/system-events.js";
import { createSubsystemLogger } from "../../../../src/logging/subsystem.js";
import { resolveAgentRoute } from "../../../../src/routing/resolve-route.js";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { formatDurationSeconds } from "openclaw/plugin-sdk/infra-runtime";
import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime";
import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
import {
readStoreAllowFromForDmPolicy,
resolveDmGroupAccessWithLists,
} from "../../../../src/security/dm-policy-shared.js";
} from "openclaw/plugin-sdk/security-runtime";
import {
isDiscordGroupAllowedByPolicy,
normalizeDiscordAllowList,
@ -36,11 +36,9 @@ import { isThreadArchived } from "./thread-bindings.discord-api.js";
import { closeDiscordThreadSessions } from "./thread-session-close.js";
import { normalizeDiscordListenerTimeoutMs, runDiscordTaskWithTimeout } from "./timeouts.js";
type LoadedConfig = ReturnType<typeof import("../../../../src/config/config.js").loadConfig>;
type RuntimeEnv = import("../../../../src/runtime.js").RuntimeEnv;
type Logger = ReturnType<
typeof import("../../../../src/logging/subsystem.js").createSubsystemLogger
>;
type LoadedConfig = ReturnType<typeof import("openclaw/plugin-sdk/config-runtime").loadConfig>;
type RuntimeEnv = import("openclaw/plugin-sdk/runtime-env").RuntimeEnv;
type Logger = ReturnType<typeof import("openclaw/plugin-sdk/runtime-env").createSubsystemLogger>;
export type DiscordMessageEvent = Parameters<MessageCreateListener["handle"]>[0];

View File

@ -1,5 +1,5 @@
import type { MockFn } from "openclaw/plugin-sdk/test-utils";
import { vi } from "vitest";
import type { MockFn } from "../../../../src/test-utils/vitest-mock-fn.js";
export const preflightDiscordMessageMock: MockFn = vi.fn();
export const processDiscordMessageMock: MockFn = vi.fn();

View File

@ -1,5 +1,5 @@
import { ChannelType } from "@buape/carbon";
import type { OpenClawConfig } from "../../../../src/config/config.js";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import type { preflightDiscordMessage } from "./message-handler.preflight.js";
import { createNoopThreadBindingManager } from "./thread-bindings.js";
@ -90,7 +90,7 @@ export function createDiscordPreflightArgs(params: {
discordConfig: params.discordConfig,
accountId: "default",
token: "token",
runtime: {} as import("../../../../src/runtime.js").RuntimeEnv,
runtime: {} as import("openclaw/plugin-sdk/runtime-env").RuntimeEnv,
botUserId: params.botUserId ?? "openclaw-bot",
guildHistories: new Map(),
historyLimit: 0,

View File

@ -1,36 +1,33 @@
import { ChannelType, MessageType, type User } from "@buape/carbon";
import { formatAllowlistMatchMeta } from "openclaw/plugin-sdk/channel-runtime";
import { resolveControlCommandGate } from "openclaw/plugin-sdk/channel-runtime";
import { logInboundDrop } from "openclaw/plugin-sdk/channel-runtime";
import { resolveMentionGatingWithBypass } from "openclaw/plugin-sdk/channel-runtime";
import { loadConfig } from "openclaw/plugin-sdk/config-runtime";
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime";
import {
ensureConfiguredAcpRouteReady,
resolveConfiguredAcpRoute,
} from "../../../../src/acp/persistent-bindings.route.js";
import { hasControlCommand } from "../../../../src/auto-reply/command-detection.js";
import { shouldHandleTextCommands } from "../../../../src/auto-reply/commands-registry.js";
import {
recordPendingHistoryEntryIfEnabled,
type HistoryEntry,
} from "../../../../src/auto-reply/reply/history.js";
import {
buildMentionRegexes,
matchesMentionWithExplicit,
} from "../../../../src/auto-reply/reply/mentions.js";
import { formatAllowlistMatchMeta } from "../../../../src/channels/allowlist-match.js";
import { resolveControlCommandGate } from "../../../../src/channels/command-gating.js";
import { logInboundDrop } from "../../../../src/channels/logging.js";
import { resolveMentionGatingWithBypass } from "../../../../src/channels/mention-gating.js";
import { loadConfig } from "../../../../src/config/config.js";
import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js";
import { logVerbose, shouldLogVerbose } from "../../../../src/globals.js";
import { recordChannelActivity } from "../../../../src/infra/channel-activity.js";
} from "openclaw/plugin-sdk/conversation-runtime";
import {
getSessionBindingService,
type SessionBindingRecord,
} from "../../../../src/infra/outbound/session-binding-service.js";
import { enqueueSystemEvent } from "../../../../src/infra/system-events.js";
import { logDebug } from "../../../../src/logger.js";
import { getChildLogger } from "../../../../src/logging.js";
import { buildPairingReply } from "../../../../src/pairing/pairing-messages.js";
import { isPluginOwnedSessionBindingRecord } from "../../../../src/plugins/conversation-binding.js";
import { DEFAULT_ACCOUNT_ID } from "../../../../src/routing/session-key.js";
} from "openclaw/plugin-sdk/conversation-runtime";
import { buildPairingReply } from "openclaw/plugin-sdk/conversation-runtime";
import { isPluginOwnedSessionBindingRecord } from "openclaw/plugin-sdk/conversation-runtime";
import { recordChannelActivity } from "openclaw/plugin-sdk/infra-runtime";
import { enqueueSystemEvent } from "openclaw/plugin-sdk/infra-runtime";
import { hasControlCommand } from "openclaw/plugin-sdk/reply-runtime";
import { shouldHandleTextCommands } from "openclaw/plugin-sdk/reply-runtime";
import {
recordPendingHistoryEntryIfEnabled,
type HistoryEntry,
} from "openclaw/plugin-sdk/reply-runtime";
import { buildMentionRegexes, matchesMentionWithExplicit } from "openclaw/plugin-sdk/reply-runtime";
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing";
import { logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
import { getChildLogger } from "openclaw/plugin-sdk/runtime-env";
import { logDebug } from "openclaw/plugin-sdk/text-runtime";
import { fetchPluralKitMessageInfo } from "../pluralkit.js";
import { sendMessageDiscord } from "../send.js";
import {

View File

@ -1,8 +1,8 @@
import type { ChannelType, Client, User } from "@buape/carbon";
import type { HistoryEntry } from "../../../../src/auto-reply/reply/history.js";
import type { ReplyToMode } from "../../../../src/config/config.js";
import type { SessionBindingRecord } from "../../../../src/infra/outbound/session-binding-service.js";
import type { resolveAgentRoute } from "../../../../src/routing/resolve-route.js";
import type { ReplyToMode } from "openclaw/plugin-sdk/config-runtime";
import type { SessionBindingRecord } from "openclaw/plugin-sdk/conversation-runtime";
import type { HistoryEntry } from "openclaw/plugin-sdk/reply-runtime";
import type { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
import type { DiscordChannelConfigResolved, DiscordGuildEntryResolved } from "./allow-list.js";
import type { DiscordChannelInfo } from "./message-utils.js";
import type { DiscordThreadBindingLookup } from "./reply-delivery.js";
@ -11,15 +11,17 @@ import type { DiscordSenderIdentity } from "./sender-identity.js";
export type { DiscordSenderIdentity } from "./sender-identity.js";
import type { DiscordThreadChannel } from "./threading.js";
export type LoadedConfig = ReturnType<typeof import("../../../../src/config/config.js").loadConfig>;
export type RuntimeEnv = import("../../../../src/runtime.js").RuntimeEnv;
export type LoadedConfig = ReturnType<
typeof import("openclaw/plugin-sdk/config-runtime").loadConfig
>;
export type RuntimeEnv = import("openclaw/plugin-sdk/runtime-env").RuntimeEnv;
export type DiscordMessageEvent = import("./listeners.js").DiscordMessageEvent;
type DiscordMessagePreflightSharedFields = {
cfg: LoadedConfig;
discordConfig: NonNullable<
import("../../../../src/config/config.js").OpenClawConfig["channels"]
import("openclaw/plugin-sdk/config-runtime").OpenClawConfig["channels"]
>["discord"];
accountId: string;
token: string;

View File

@ -1,40 +1,40 @@
import { ChannelType, type RequestClient } from "@buape/carbon";
import { resolveAckReaction, resolveHumanDelayConfig } from "../../../../src/agents/identity.js";
import { EmbeddedBlockChunker } from "../../../../src/agents/pi-embedded-block-chunker.js";
import { resolveChunkMode } from "../../../../src/auto-reply/chunk.js";
import { dispatchInboundMessage } from "../../../../src/auto-reply/dispatch.js";
import {
formatInboundEnvelope,
resolveEnvelopeFormatOptions,
} from "../../../../src/auto-reply/envelope.js";
import {
buildPendingHistoryContextFromMap,
clearHistoryEntriesIfEnabled,
} from "../../../../src/auto-reply/reply/history.js";
import { finalizeInboundContext } from "../../../../src/auto-reply/reply/inbound-context.js";
import { createReplyDispatcherWithTyping } from "../../../../src/auto-reply/reply/reply-dispatcher.js";
import type { ReplyPayload } from "../../../../src/auto-reply/types.js";
import { shouldAckReaction as shouldAckReactionGate } from "../../../../src/channels/ack-reactions.js";
import { logTypingFailure, logAckFailure } from "../../../../src/channels/logging.js";
import { createReplyPrefixOptions } from "../../../../src/channels/reply-prefix.js";
import { recordInboundSession } from "../../../../src/channels/session.js";
import { resolveAckReaction, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
import { EmbeddedBlockChunker } from "openclaw/plugin-sdk/agent-runtime";
import { shouldAckReaction as shouldAckReactionGate } from "openclaw/plugin-sdk/channel-runtime";
import { logTypingFailure, logAckFailure } from "openclaw/plugin-sdk/channel-runtime";
import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime";
import { recordInboundSession } from "openclaw/plugin-sdk/channel-runtime";
import {
createStatusReactionController,
DEFAULT_TIMING,
type StatusReactionAdapter,
} from "../../../../src/channels/status-reactions.js";
import { createTypingCallbacks } from "../../../../src/channels/typing.js";
import { isDangerousNameMatchingEnabled } from "../../../../src/config/dangerous-name-matching.js";
import { resolveDiscordPreviewStreamMode } from "../../../../src/config/discord-preview-streaming.js";
import { resolveMarkdownTableMode } from "../../../../src/config/markdown-tables.js";
import { readSessionUpdatedAt, resolveStorePath } from "../../../../src/config/sessions.js";
import { danger, logVerbose, shouldLogVerbose } from "../../../../src/globals.js";
import { convertMarkdownTables } from "../../../../src/markdown/tables.js";
import { getAgentScopedMediaLocalRoots } from "../../../../src/media/local-roots.js";
import { buildAgentSessionKey } from "../../../../src/routing/resolve-route.js";
import { resolveThreadSessionKeys } from "../../../../src/routing/session-key.js";
import { stripReasoningTagsFromText } from "../../../../src/shared/text/reasoning-tags.js";
import { truncateUtf16Safe } from "../../../../src/utils.js";
} from "openclaw/plugin-sdk/channel-runtime";
import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime";
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime";
import { resolveDiscordPreviewStreamMode } from "openclaw/plugin-sdk/config-runtime";
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime";
import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/config-runtime";
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
import { resolveChunkMode } from "openclaw/plugin-sdk/reply-runtime";
import { dispatchInboundMessage } from "openclaw/plugin-sdk/reply-runtime";
import {
formatInboundEnvelope,
resolveEnvelopeFormatOptions,
} from "openclaw/plugin-sdk/reply-runtime";
import {
buildPendingHistoryContextFromMap,
clearHistoryEntriesIfEnabled,
} from "openclaw/plugin-sdk/reply-runtime";
import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-runtime";
import { createReplyDispatcherWithTyping } from "openclaw/plugin-sdk/reply-runtime";
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
import { buildAgentSessionKey } from "openclaw/plugin-sdk/routing";
import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
import { convertMarkdownTables } from "openclaw/plugin-sdk/text-runtime";
import { stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-runtime";
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-runtime";
import { resolveDiscordMaxLinesPerMessage } from "../accounts.js";
import { chunkDiscordTextWithMode } from "../chunk.js";
import { resolveDiscordDraftStreamingChunking } from "../draft-chunking.js";

Some files were not shown because too many files have changed in this diff Show More