Merge branch 'main' into refactor/improve-error-messages
This commit is contained in:
commit
953a401c2f
@ -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`
|
||||
|
||||
64
.github/workflows/ci.yml
vendored
64
.github/workflows/ci.yml
vendored
@ -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
|
||||
@ -270,7 +273,9 @@ jobs:
|
||||
use-sticky-disk: "false"
|
||||
|
||||
- name: Run changed extension tests
|
||||
run: pnpm test:extension ${{ matrix.extension }}
|
||||
env:
|
||||
OPENCLAW_CHANGED_EXTENSION: ${{ matrix.extension }}
|
||||
run: pnpm test:extension "$OPENCLAW_CHANGED_EXTENSION"
|
||||
|
||||
# Types, lint, and format check.
|
||||
check:
|
||||
@ -299,8 +304,8 @@ jobs:
|
||||
- name: Enforce safe external URL opening policy
|
||||
run: pnpm lint:ui:no-raw-window-open
|
||||
|
||||
startup-memory:
|
||||
name: "startup-memory"
|
||||
build-smoke:
|
||||
name: "build-smoke"
|
||||
needs: [docs-scope, changed-scope]
|
||||
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
|
||||
runs-on: blacksmith-16vcpu-ubuntu-2404
|
||||
@ -319,9 +324,43 @@ jobs:
|
||||
- name: Build dist
|
||||
run: pnpm build
|
||||
|
||||
- name: Smoke test CLI launcher help
|
||||
run: node openclaw.mjs --help
|
||||
|
||||
- name: Smoke test CLI launcher status json
|
||||
run: node openclaw.mjs status --json --timeout 1
|
||||
|
||||
- name: Check CLI startup memory
|
||||
run: pnpm test:startup:memory
|
||||
|
||||
gateway-watch-regression:
|
||||
name: "gateway-watch-regression"
|
||||
needs: [docs-scope, changed-scope]
|
||||
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
|
||||
runs-on: blacksmith-16vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: false
|
||||
|
||||
- name: Setup Node environment
|
||||
uses: ./.github/actions/setup-node-env
|
||||
with:
|
||||
install-bun: "false"
|
||||
use-sticky-disk: "false"
|
||||
|
||||
- name: Run gateway watch regression harness
|
||||
run: pnpm test:gateway:watch-regression
|
||||
|
||||
- name: Upload gateway watch regression artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: gateway-watch-regression
|
||||
path: .local/gateway-watch-regression/
|
||||
retention-days: 7
|
||||
|
||||
# Validate docs (format, lint, broken links) only when docs files changed.
|
||||
check-docs:
|
||||
needs: [docs-scope]
|
||||
@ -449,21 +488,30 @@ jobs:
|
||||
run: pre-commit run --all-files detect-private-key
|
||||
|
||||
- name: Audit changed GitHub workflows with zizmor
|
||||
env:
|
||||
BASE_SHA: ${{ github.event_name == 'push' && github.event.before || github.event.pull_request.base.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ "${{ github.event_name }}" = "push" ]; then
|
||||
BASE="${{ github.event.before }}"
|
||||
else
|
||||
BASE="${{ github.event.pull_request.base.sha }}"
|
||||
if [ -z "${BASE_SHA:-}" ] || [ "${BASE_SHA}" = "0000000000000000000000000000000000000000" ]; then
|
||||
echo "No usable base SHA detected; skipping zizmor."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mapfile -t workflow_files < <(git diff --name-only "$BASE" HEAD -- '.github/workflows/*.yml' '.github/workflows/*.yaml')
|
||||
if ! git cat-file -e "${BASE_SHA}^{commit}" 2>/dev/null; then
|
||||
echo "Base SHA ${BASE_SHA} is unavailable; skipping zizmor."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mapfile -t workflow_files < <(
|
||||
git diff --name-only "${BASE_SHA}" HEAD -- '.github/workflows/*.yml' '.github/workflows/*.yaml'
|
||||
)
|
||||
if [ "${#workflow_files[@]}" -eq 0 ]; then
|
||||
echo "No workflow changes detected; skipping zizmor."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
printf 'Auditing workflow files:\n%s\n' "${workflow_files[@]}"
|
||||
pre-commit run zizmor --files "${workflow_files[@]}"
|
||||
|
||||
- name: Audit production dependencies
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@ pnpm-lock.yaml
|
||||
bun.lock
|
||||
bun.lockb
|
||||
coverage
|
||||
__openclaw_vitest__/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.tsbuildinfo
|
||||
|
||||
47
CHANGELOG.md
47
CHANGELOG.md
@ -7,6 +7,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Changes
|
||||
|
||||
- Commands/btw: add `/btw` side questions for quick tool-less answers about the current session without changing future session context, with dismissible in-session TUI answers and explicit BTW replies on external channels. (#45444) Thanks @ngutman.
|
||||
- Gateway/docs: clarify that empty URL input allowlists are treated as unset, document `allowUrl: false` as the deny-all switch, and add regression coverage for the normalization path.
|
||||
- Sandbox/runtime: add pluggable sandbox backends, ship an OpenShell backend with `mirror` and `remote` workspace modes, and make sandbox list/recreate/prune backend-aware instead of Docker-only.
|
||||
- Sandbox/SSH: add a core SSH sandbox backend with secret-backed key, certificate, and known_hosts inputs, move shared remote exec/filesystem tooling into core, and keep OpenShell focused on sandbox lifecycle plus optional `mirror` mode.
|
||||
- Web tools/Firecrawl: add Firecrawl as an `onboard`/configure search provider via a bundled plugin, expose explicit `firecrawl_search` and `firecrawl_scrape` tools, and align core `web_fetch` fallback behavior with Firecrawl base-URL/env fallback plus guarded endpoint fetches.
|
||||
@ -18,6 +19,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Android/mobile: add a system-aware dark theme across onboarding and post-onboarding screens so the app follows the device theme through setup, chat, and voice flows. (#46249) Thanks @sibbl.
|
||||
- Feishu/ACP: add current-conversation ACP and subagent session binding for supported DMs and topic conversations, including completion delivery back to the originating Feishu conversation. (#46819) Thanks @Takhoffman.
|
||||
- Plugins/marketplaces: add Claude marketplace registry resolution, `plugin@marketplace` installs, marketplace listing, and update support, plus Docker E2E coverage for local and official marketplace flows. (#48058) Thanks @vincentkoc.
|
||||
- Commands/plugins: add owner-gated `/plugins` and `/plugin` chat commands for plugin list/show and enable/disable flows, alongside explicit `commands.plugins` config gating. Thanks @vincentkoc.
|
||||
- Feishu/cards: add structured interactive approval and quick-action launcher cards, preserve callback user and conversation context through routing, and keep legacy card-action fallback behavior so common actions can run without typing raw commands. (#47873) Thanks @Takhoffman.
|
||||
- Feishu/streaming: add `onReasoningStream` and `onReasoningEnd` support to streaming cards, so `/reasoning stream` renders thinking tokens as markdown blockquotes in the same card — matching the Telegram channel's reasoning lane behavior. (#46029) Thanks @day253.
|
||||
- Feishu/cards: add identity-aware structured card headers and note footers for Feishu replies and direct sends, while keeping that presentation wired through the shared outbound identity path. (#29938) Thanks @nszhsl.
|
||||
@ -30,10 +32,17 @@ 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.
|
||||
- Plugins/testing: add a public `openclaw/plugin-sdk/testing` seam for plugin-author test helpers, and move bundled-extension-only test bridges out of `extensions/` into private repo test helpers.
|
||||
- Plugins/Chutes: add a bundled Chutes provider with plugin-owned OAuth/API-key auth, dynamic model discovery, and default-on extension wiring. (#41416) Thanks @Veightor.
|
||||
- Plugins/binding: add `onConversationBindingResolved(...)` so plugins can react immediately after bind approvals or denies without blocking channel interaction acknowledgements. (#48678) Thanks @huntharo.
|
||||
|
||||
### Breaking
|
||||
|
||||
- Browser/Chrome MCP: remove the legacy Chrome extension relay path, bundled extension assets, `driver: "extension"`, and `browser.relayBindHost`. Run `openclaw doctor --fix` to migrate host-local browser config to `existing-session` / `user`; Docker, headless, sandbox, and remote browser flows still use raw CDP. (#47893) Thanks @vincentkoc.
|
||||
- Plugins/runtime: remove the public `openclaw/extension-api` surface with no compatibility shim. Bundled plugins must use injected runtime for host-side operations (for example `api.runtime.agent.runEmbeddedPiAgent`) and any remaining direct imports must come from narrow `openclaw/plugin-sdk/*` subpaths instead of the monolithic SDK root.
|
||||
- Tools/image generation: standardize the stock image create/edit path on the core `image_generate` tool. The old `nano-banana-pro` docs/examples are gone; if you previously copied that sample-skill config, switch to `agents.defaults.imageGenerationModel` for built-in image generation or install a separate third-party skill explicitly.
|
||||
|
||||
### Fixes
|
||||
|
||||
@ -69,6 +78,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Feishu/actions: expand the runtime action surface with message read/edit, explicit thread replies, pinning, and operator-facing chat/member inspection so Feishu can operate more of the workspace directly. (#47968) Thanks @Takhoffman.
|
||||
- Feishu/topic threads: fetch full thread context, including prior bot replies, when starting a topic-thread session so follow-up turns in Feishu topics keep the right conversation state. (#45254) Thanks @Coobiw.
|
||||
- Feishu/media: keep native image, file, audio, and video/media handling aligned across outbound sends, inbound downloads, thread replies, directory/action aliases, and capability docs so unsupported areas are explicit instead of implied. (#47968) Thanks @Takhoffman.
|
||||
- Feishu/webhooks: harden signed webhook verification to use constant-time signature comparison and keep malformed short signatures fail-closed in webhook E2E coverage.
|
||||
- WhatsApp/reconnect: restore the append recency filter in the extension inbox monitor and handle protobuf `Long` timestamps correctly, so fresh post-reconnect append messages are processed while stale history sync stays suppressed. (#42588) Thanks @MonkeyLeeT.
|
||||
- WhatsApp/login: wait for pending creds writes before reopening after Baileys `515` pairing restarts in both QR login and `channels login` flows, and keep the restart coverage pinned to the real wrapped error shape plus per-account creds queues. (#27910) Thanks @asyncjason.
|
||||
- Telegram/message send: forward `--force-document` through the `sendPayload` path as well as `sendMedia`, so Telegram payload sends with `channelData` keep uploading images as documents instead of silently falling back to compressed photo sends. (#47119) Thanks @thepagent.
|
||||
@ -77,7 +87,9 @@ 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.
|
||||
- Gateway/watch mode: restart on bundled-plugin package and manifest metadata changes, rebuild `dist` for extension source and `tsdown.config.ts` changes, and still ignore extension docs. (#47571) Thanks @gumadeiras.
|
||||
- Gateway/watch mode: recreate bundled plugin runtime metadata after clean or stale `dist` states, so `pnpm gateway:watch` no longer fails on missing `dist/extensions/*/openclaw.plugin.json` manifests after a rebuild. Thanks @gumadeiras.
|
||||
@ -91,6 +103,9 @@ Docs: https://docs.openclaw.ai
|
||||
- Docs/Mintlify: fix MDX marker syntax on Perplexity, Model Providers, Moonshot, and exec approvals pages so local docs preview no longer breaks rendering or leaves stale pages unpublished. (#46695) Thanks @velvet-shark.
|
||||
- Gateway/config validation: stop treating the implicit default memory slot as a required explicit plugin config, so startup no longer fails with `plugins.slots.memory: plugin not found: memory-core` when `memory-core` was only inferred. (#47494) Thanks @ngutman.
|
||||
- Tlon: honor explicit empty allowlists and defer cite expansion. (#46788) Thanks @zpbrent and @vincentkoc.
|
||||
- Tlon/DM auth: defer cited-message expansion until after DM authorization and owner command handling, so unauthorized DMs and owner approval/admin commands no longer trigger cross-channel cite fetches before the deny or command path.
|
||||
- Docs/security audit: spell out that `gateway.controlUi.allowedOrigins: ["*"]` is an explicit allow-all browser-origin policy and should be avoided outside tightly controlled local testing.
|
||||
- Gateway/auth: clear self-declared scopes for device-less trusted-proxy Control UI sessions so proxy-authenticated connects cannot claim admin or secrets scopes without a bound device identity.
|
||||
- Nodes/pending actions: re-check queued foreground actions against the current node command policy before returning them to the node. (#46815) Thanks @zpbrent and @vincentkoc.
|
||||
- Node/startup: remove leftover debug `console.log("node host PATH: ...")` that printed the resolved PATH on every `openclaw node run` invocation. (#46515) Fixes #46411. Thanks @ademczuk.
|
||||
- CLI/completion: reduce recursive completion-script string churn and fix nested PowerShell command-path matching so generated nested completions resolve on PowerShell too. (#45537) Thanks @yiShanXin and @vincentkoc.
|
||||
@ -101,6 +116,27 @@ Docs: https://docs.openclaw.ai
|
||||
- Control UI/model switching: preserve the selected provider prefix when switching models from the chat dropdown, so multi-provider setups no longer send `anthropic/gpt-5.2`-style mismatches when the user picked `openai/gpt-5.2`. (#47581) Thanks @chrishham.
|
||||
- Control UI/storage: scope persisted settings keys by gateway base path, with migration from the legacy shared key, so multiple gateways under one domain stop overwriting each other's dashboard preferences. (#47932) Thanks @bobBot-claw.
|
||||
- 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.
|
||||
- ACP/acpx: keep plugin-local backend installs under `extensions/acpx` in live repo checkouts so rebuilds no longer delete the runtime binary, and avoid package-lock churn during runtime repair.
|
||||
- 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.
|
||||
- macOS/exec approvals: harden exec-host request HMAC verification to use a timing-safe compare and keep malformed or truncated signatures fail-closed in focused IPC auth coverage.
|
||||
- Gateway/exec approvals: surface requested env override keys in gateway-host approval prompts so operators can review surviving env context without inheriting noisy base host env.
|
||||
- Telegram/network: preserve sticky IPv4 fallback state across polling restarts so hosts with unstable IPv6 to `api.telegram.org` stop re-triggering repeated Telegram timeouts after each restart. (#48282) Thanks @yassinebkr.
|
||||
- Plugins/subagents: forward per-run provider and model overrides through gateway plugin subagent dispatch so plugin-launched agent delegations honor explicit model selection again. (#48277) Thanks @jalehman.
|
||||
- Agents/compaction: write minimal boundary summaries for empty preparations while keeping split-turn prefixes on the normal path, so no-summarizable-message sessions stop retriggering the safeguard loop. (#42215) thanks @lml2468.
|
||||
|
||||
### Fixes
|
||||
|
||||
- Agents/bootstrap warnings: move bootstrap truncation warnings out of the system prompt and into the per-turn prompt body so prompt-cache reuse stays stable when truncation warnings appear or disappear. (#48753) Thanks @scoootscooob and @obviyus.
|
||||
- Telegram/DM topic session keys: route named-account DM topics through the same per-account base session key across inbound messages, native commands, and session-state lookups so `/status` and thread recovery stop creating phantom `agent:main:main:thread:...` sessions. (#48204) Thanks @vincentkoc.
|
||||
- macOS/node service startup: use `openclaw node start/stop --json` from the Mac app instead of the removed `openclaw service node ...` command shape, so current CLI installs expose the full node exec surface again. (#46843) Fixes #43171. Thanks @Br1an67.
|
||||
- macOS/launch at login: stop emitting `KeepAlive` for the desktop app launch agent so OpenClaw no longer relaunches immediately after a manual quit while launch at login remains enabled. (#40213) Thanks @stablegenius49.
|
||||
- ACP/gateway startup: use direct Telegram and Discord startup/status helpers instead of routing probes through the plugin runtime, and prepend the selected daemon Node bin dir to service PATH so plugin-local installs can still find `npm` and `pnpm`.
|
||||
- ACP/configured bindings: reinitialize configured ACP sessions that are stuck in `error` state instead of reusing the failed runtime.
|
||||
- Mattermost/DM send: retry transient direct-channel creation failures for DM deliveries, with configurable backoff and per-request timeout. (#42398) Thanks @JonathanJing.
|
||||
- Telegram/network: unify API and media fetches under the same sticky IPv4 and pinned-IP fallback chain, and re-validate pinned override addresses against SSRF policy. (#49148) Thanks @obviyus.
|
||||
|
||||
## 2026.3.13
|
||||
|
||||
@ -179,6 +215,7 @@ 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.
|
||||
- Hooks/after_compaction: forward `sessionFile` for direct/manual compaction events and add `sessionFile` plus `sessionKey` to wired auto-compaction hook context so plugins receive the session metadata already declared in the hook types. (#40781) Thanks @jarimustonen.
|
||||
|
||||
## 2026.3.12
|
||||
|
||||
@ -270,6 +307,13 @@ Docs: https://docs.openclaw.ai
|
||||
- Agents/Anthropic replay: drop replayed assistant thinking blocks for native Anthropic and Bedrock Claude providers so persisted follow-up turns no longer fail on stored thinking blocks. (#44843) Thanks @jmcte.
|
||||
- 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.
|
||||
|
||||
- Control UI/auth: restore one-time legacy `?token=` imports for shared Control UI links while keeping `#token=` preferred, and carry pending query tokens through gateway URL confirmation so compatibility links still authenticate after confirmation. (#43979) Thanks @stim64045-spec.
|
||||
- Plugins/context engines: retry legacy lifecycle calls once without `sessionKey` when older plugins reject that field, memoize legacy mode after the first strict-schema fallback, and preserve non-compat runtime errors without retry. (#44779) thanks @hhhhao28.
|
||||
|
||||
## 2026.3.11
|
||||
|
||||
@ -412,6 +456,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Memory/QMD Windows: fail closed when `qmd.cmd` or `mcporter.cmd` wrappers cannot be resolved to a direct entrypoint, so memory search no longer falls back to shell execution on Windows.
|
||||
- macOS/remote gateway: stop PortGuardian from killing Docker Desktop and other external listeners on the gateway port in remote mode, so containerized and tunneled gateway setups no longer lose their port-forward owner on app startup. (#6755) Thanks @teslamint.
|
||||
- Feishu/streaming recovery: clear stale `streamingStartPromise` when card creation fails (HTTP 400) so subsequent messages can retry streaming instead of silently dropping all future replies. Fixes #43322.
|
||||
- Exec/env sandbox: block JVM agent injection (`JAVA_TOOL_OPTIONS`, `_JAVA_OPTIONS`, `JDK_JAVA_OPTIONS`), Python breakpoint hijack (`PYTHONBREAKPOINT`), and .NET startup hooks (`DOTNET_STARTUP_HOOKS`) from the host exec environment. (#49025)
|
||||
|
||||
## 2026.3.8
|
||||
|
||||
@ -1200,7 +1245,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Signal/Sync message null-handling: treat `syncMessage` presence (including `null`) as sync envelope traffic so replayed sentTranscript payloads cannot bypass loop guards after daemon restart. Landed from contributor PR #31138 by @Sid-Qin. Thanks @Sid-Qin.
|
||||
- Infra/fs-safe: sanitize directory-read failures so raw `EISDIR` text never leaks to messaging surfaces, with regression tests for both root-scoped and direct safe reads. Landed from contributor PR #31205 by @polooooo. Thanks @polooooo.
|
||||
|
||||
## Unreleased
|
||||
## 2026.2.27
|
||||
|
||||
### Changes
|
||||
|
||||
|
||||
@ -91,7 +91,10 @@ 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`
|
||||
- For targeted shared-surface work, use `pnpm test:contracts:channels` or `pnpm test:contracts:plugins`
|
||||
- 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)
|
||||
|
||||
14
README.md
14
README.md
@ -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 you’re 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)
|
||||
|
||||
@ -81,22 +81,23 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
|
||||
return self.html("Not Found", title: "Canvas: 404")
|
||||
}
|
||||
|
||||
// Directory traversal guard: served files must live under the session root.
|
||||
let standardizedRoot = sessionRoot.standardizedFileURL
|
||||
let standardizedFile = fileURL.standardizedFileURL
|
||||
guard standardizedFile.path.hasPrefix(standardizedRoot.path) else {
|
||||
// Resolve symlinks before enforcing the session-root boundary so links inside
|
||||
// the canvas tree cannot escape to arbitrary host files.
|
||||
let resolvedRoot = sessionRoot.resolvingSymlinksInPath().standardizedFileURL
|
||||
let resolvedFile = fileURL.resolvingSymlinksInPath().standardizedFileURL
|
||||
guard self.isFileURL(resolvedFile, withinDirectory: resolvedRoot) else {
|
||||
return self.html("Forbidden", title: "Canvas: 403")
|
||||
}
|
||||
|
||||
do {
|
||||
let data = try Data(contentsOf: standardizedFile)
|
||||
let mime = CanvasScheme.mimeType(forExtension: standardizedFile.pathExtension)
|
||||
let servedPath = standardizedFile.path
|
||||
let data = try Data(contentsOf: resolvedFile)
|
||||
let mime = CanvasScheme.mimeType(forExtension: resolvedFile.pathExtension)
|
||||
let servedPath = resolvedFile.path
|
||||
canvasLogger.debug(
|
||||
"served \(session, privacy: .public)/\(path, privacy: .public) -> \(servedPath, privacy: .public)")
|
||||
return CanvasResponse(mime: mime, data: data)
|
||||
} catch {
|
||||
let failedPath = standardizedFile.path
|
||||
let failedPath = resolvedFile.path
|
||||
let errorText = error.localizedDescription
|
||||
canvasLogger
|
||||
.error(
|
||||
@ -145,6 +146,11 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
|
||||
return nil
|
||||
}
|
||||
|
||||
private func isFileURL(_ fileURL: URL, withinDirectory rootURL: URL) -> Bool {
|
||||
let rootPath = rootURL.path.hasSuffix("/") ? rootURL.path : rootURL.path + "/"
|
||||
return fileURL.path == rootURL.path || fileURL.path.hasPrefix(rootPath)
|
||||
}
|
||||
|
||||
private func html(_ body: String, title: String = "Canvas") -> CanvasResponse {
|
||||
let html = """
|
||||
<!doctype html>
|
||||
|
||||
@ -89,6 +89,20 @@ private func readLineFromHandle(_ handle: FileHandle, maxBytes: Int) throws -> S
|
||||
return String(data: lineData, encoding: .utf8)
|
||||
}
|
||||
|
||||
func timingSafeHexStringEquals(_ lhs: String, _ rhs: String) -> Bool {
|
||||
let lhsBytes = Array(lhs.utf8)
|
||||
let rhsBytes = Array(rhs.utf8)
|
||||
guard lhsBytes.count == rhsBytes.count else {
|
||||
return false
|
||||
}
|
||||
|
||||
var diff: UInt8 = 0
|
||||
for index in lhsBytes.indices {
|
||||
diff |= lhsBytes[index] ^ rhsBytes[index]
|
||||
}
|
||||
return diff == 0
|
||||
}
|
||||
|
||||
enum ExecApprovalsSocketClient {
|
||||
private struct TimeoutError: LocalizedError {
|
||||
var message: String
|
||||
@ -854,7 +868,7 @@ private final class ExecApprovalsSocketServer: @unchecked Sendable {
|
||||
error: ExecHostError(code: "INVALID_REQUEST", message: "expired request", reason: "ttl"))
|
||||
}
|
||||
let expected = self.hmacHex(nonce: request.nonce, ts: request.ts, requestJson: request.requestJson)
|
||||
if expected != request.hmac {
|
||||
if !timingSafeHexStringEquals(expected, request.hmac) {
|
||||
return ExecHostResponse(
|
||||
type: "exec-res",
|
||||
id: request.id,
|
||||
|
||||
@ -23,7 +23,12 @@ enum HostEnvSecurityPolicy {
|
||||
"PS4",
|
||||
"GCONV_PATH",
|
||||
"IFS",
|
||||
"SSLKEYLOGFILE"
|
||||
"SSLKEYLOGFILE",
|
||||
"JAVA_TOOL_OPTIONS",
|
||||
"_JAVA_OPTIONS",
|
||||
"JDK_JAVA_OPTIONS",
|
||||
"PYTHONBREAKPOINT",
|
||||
"DOTNET_STARTUP_HOOKS"
|
||||
]
|
||||
|
||||
static let blockedOverrideKeys: Set<String> = [
|
||||
|
||||
@ -26,7 +26,12 @@ enum LaunchAgentManager {
|
||||
}
|
||||
|
||||
private static func writePlist(bundlePath: String) {
|
||||
let plist = """
|
||||
let plist = self.plistContents(bundlePath: bundlePath)
|
||||
try? plist.write(to: self.plistURL, atomically: true, encoding: .utf8)
|
||||
}
|
||||
|
||||
static func plistContents(bundlePath: String) -> String {
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
@ -41,8 +46,6 @@ enum LaunchAgentManager {
|
||||
<string>\(FileManager().homeDirectoryForCurrentUser.path)</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
@ -55,7 +58,6 @@ enum LaunchAgentManager {
|
||||
</dict>
|
||||
</plist>
|
||||
"""
|
||||
try? plist.write(to: self.plistURL, atomically: true, encoding: .utf8)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
|
||||
@ -6,7 +6,7 @@ enum NodeServiceManager {
|
||||
|
||||
static func start() async -> String? {
|
||||
let result = await self.runServiceCommandResult(
|
||||
["node", "start"],
|
||||
["start"],
|
||||
timeout: 20,
|
||||
quiet: false)
|
||||
if let error = self.errorMessage(from: result, treatNotLoadedAsError: true) {
|
||||
@ -18,7 +18,7 @@ enum NodeServiceManager {
|
||||
|
||||
static func stop() async -> String? {
|
||||
let result = await self.runServiceCommandResult(
|
||||
["node", "stop"],
|
||||
["stop"],
|
||||
timeout: 15,
|
||||
quiet: false)
|
||||
if let error = self.errorMessage(from: result, treatNotLoadedAsError: false) {
|
||||
@ -30,6 +30,14 @@ enum NodeServiceManager {
|
||||
}
|
||||
|
||||
extension NodeServiceManager {
|
||||
private static func serviceCommand(_ args: [String]) -> [String] {
|
||||
CommandResolver.openclawCommand(
|
||||
subcommand: "node",
|
||||
extraArgs: self.withJsonFlag(args),
|
||||
// Service management must always run locally, even if remote mode is configured.
|
||||
configRoot: ["gateway": ["mode": "local"]])
|
||||
}
|
||||
|
||||
private struct CommandResult {
|
||||
let success: Bool
|
||||
let payload: Data?
|
||||
@ -52,11 +60,7 @@ extension NodeServiceManager {
|
||||
timeout: Double,
|
||||
quiet: Bool) async -> CommandResult
|
||||
{
|
||||
let command = CommandResolver.openclawCommand(
|
||||
subcommand: "service",
|
||||
extraArgs: self.withJsonFlag(args),
|
||||
// Service management must always run locally, even if remote mode is configured.
|
||||
configRoot: ["gateway": ["mode": "local"]])
|
||||
let command = self.serviceCommand(args)
|
||||
var env = ProcessInfo.processInfo.environment
|
||||
env["PATH"] = CommandResolver.preferredPaths().joined(separator: ":")
|
||||
let response = await ShellExecutor.runDetailed(command: command, cwd: nil, env: env, timeout: timeout)
|
||||
@ -136,3 +140,11 @@ extension NodeServiceManager {
|
||||
TextSummarySupport.summarizeLastLine(text)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
extension NodeServiceManager {
|
||||
static func _testServiceCommand(_ args: [String]) -> [String] {
|
||||
self.serviceCommand(args)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -515,6 +515,8 @@ public struct PollParams: Codable, Sendable {
|
||||
public struct AgentParams: Codable, Sendable {
|
||||
public let message: String
|
||||
public let agentid: String?
|
||||
public let provider: String?
|
||||
public let model: String?
|
||||
public let to: String?
|
||||
public let replyto: String?
|
||||
public let sessionid: String?
|
||||
@ -542,6 +544,8 @@ public struct AgentParams: Codable, Sendable {
|
||||
public init(
|
||||
message: String,
|
||||
agentid: String?,
|
||||
provider: String?,
|
||||
model: String?,
|
||||
to: String?,
|
||||
replyto: String?,
|
||||
sessionid: String?,
|
||||
@ -568,6 +572,8 @@ public struct AgentParams: Codable, Sendable {
|
||||
{
|
||||
self.message = message
|
||||
self.agentid = agentid
|
||||
self.provider = provider
|
||||
self.model = model
|
||||
self.to = to
|
||||
self.replyto = replyto
|
||||
self.sessionid = sessionid
|
||||
@ -596,6 +602,8 @@ public struct AgentParams: Codable, Sendable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case message
|
||||
case agentid = "agentId"
|
||||
case provider
|
||||
case model
|
||||
case to
|
||||
case replyto = "replyTo"
|
||||
case sessionid = "sessionId"
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
import Testing
|
||||
@testable import OpenClaw
|
||||
|
||||
struct ExecApprovalsSocketAuthTests {
|
||||
@Test
|
||||
func `timing safe hex compare matches equal strings`() {
|
||||
#expect(timingSafeHexStringEquals(String(repeating: "a", count: 64), String(repeating: "a", count: 64)))
|
||||
}
|
||||
|
||||
@Test
|
||||
func `timing safe hex compare rejects mismatched strings`() {
|
||||
let expected = String(repeating: "a", count: 63) + "b"
|
||||
let provided = String(repeating: "a", count: 63) + "c"
|
||||
#expect(!timingSafeHexStringEquals(expected, provided))
|
||||
}
|
||||
|
||||
@Test
|
||||
func `timing safe hex compare rejects different length strings`() {
|
||||
#expect(!timingSafeHexStringEquals(String(repeating: "a", count: 64), "deadbeef"))
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import OpenClaw
|
||||
|
||||
struct LaunchAgentManagerTests {
|
||||
@Test func `launch at login plist does not keep app alive after manual quit`() throws {
|
||||
let plist = LaunchAgentManager.plistContents(bundlePath: "/Applications/OpenClaw.app")
|
||||
let data = try #require(plist.data(using: .utf8))
|
||||
let object = try #require(
|
||||
PropertyListSerialization.propertyList(from: data, format: nil) as? [String: Any]
|
||||
)
|
||||
|
||||
#expect(object["RunAtLoad"] as? Bool == true)
|
||||
#expect(object["KeepAlive"] == nil)
|
||||
|
||||
let args = try #require(object["ProgramArguments"] as? [String])
|
||||
#expect(args == ["/Applications/OpenClaw.app/Contents/MacOS/OpenClaw"])
|
||||
}
|
||||
}
|
||||
@ -216,6 +216,32 @@ struct LowCoverageHelperTests {
|
||||
#expect(handler._testTextEncodingName(for: "application/octet-stream") == nil)
|
||||
}
|
||||
|
||||
@Test @MainActor func `canvas scheme handler blocks symlink escapes`() throws {
|
||||
let root = FileManager().temporaryDirectory
|
||||
.appendingPathComponent("canvas-\(UUID().uuidString)", isDirectory: true)
|
||||
defer { try? FileManager().removeItem(at: root) }
|
||||
try FileManager().createDirectory(at: root, withIntermediateDirectories: true)
|
||||
|
||||
let session = root.appendingPathComponent("main", isDirectory: true)
|
||||
try FileManager().createDirectory(at: session, withIntermediateDirectories: true)
|
||||
|
||||
let outside = root.deletingLastPathComponent().appendingPathComponent("canvas-secret-\(UUID().uuidString).txt")
|
||||
defer { try? FileManager().removeItem(at: outside) }
|
||||
try "top-secret".write(to: outside, atomically: true, encoding: .utf8)
|
||||
|
||||
let symlink = session.appendingPathComponent("index.html")
|
||||
try FileManager().createSymbolicLink(at: symlink, withDestinationURL: outside)
|
||||
|
||||
let handler = CanvasSchemeHandler(root: root)
|
||||
let url = try #require(CanvasScheme.makeURL(session: "main", path: "index.html"))
|
||||
let response = handler._testResponse(for: url)
|
||||
let body = String(data: response.data, encoding: .utf8) ?? ""
|
||||
|
||||
#expect(response.mime == "text/html")
|
||||
#expect(body.contains("Forbidden"))
|
||||
#expect(!body.contains("top-secret"))
|
||||
}
|
||||
|
||||
@Test @MainActor func `menu context card injector inserts and finds index`() {
|
||||
let injector = MenuContextCardInjector()
|
||||
let menu = NSMenu()
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import OpenClaw
|
||||
|
||||
@Suite(.serialized) struct NodeServiceManagerTests {
|
||||
@Test func `builds node service commands with current CLI shape`() throws {
|
||||
let tmp = try makeTempDirForTests()
|
||||
CommandResolver.setProjectRoot(tmp.path)
|
||||
|
||||
let openclawPath = tmp.appendingPathComponent("node_modules/.bin/openclaw")
|
||||
try makeExecutableForTests(at: openclawPath)
|
||||
|
||||
let start = NodeServiceManager._testServiceCommand(["start"])
|
||||
#expect(start == [openclawPath.path, "node", "start", "--json"])
|
||||
|
||||
let stop = NodeServiceManager._testServiceCommand(["stop"])
|
||||
#expect(stop == [openclawPath.path, "node", "stop", "--json"])
|
||||
}
|
||||
}
|
||||
@ -515,6 +515,8 @@ public struct PollParams: Codable, Sendable {
|
||||
public struct AgentParams: Codable, Sendable {
|
||||
public let message: String
|
||||
public let agentid: String?
|
||||
public let provider: String?
|
||||
public let model: String?
|
||||
public let to: String?
|
||||
public let replyto: String?
|
||||
public let sessionid: String?
|
||||
@ -542,6 +544,8 @@ public struct AgentParams: Codable, Sendable {
|
||||
public init(
|
||||
message: String,
|
||||
agentid: String?,
|
||||
provider: String?,
|
||||
model: String?,
|
||||
to: String?,
|
||||
replyto: String?,
|
||||
sessionid: String?,
|
||||
@ -568,6 +572,8 @@ public struct AgentParams: Codable, Sendable {
|
||||
{
|
||||
self.message = message
|
||||
self.agentid = agentid
|
||||
self.provider = provider
|
||||
self.model = model
|
||||
self.to = to
|
||||
self.replyto = replyto
|
||||
self.sessionid = sessionid
|
||||
@ -596,6 +602,8 @@ public struct AgentParams: Codable, Sendable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case message
|
||||
case agentid = "agentId"
|
||||
case provider
|
||||
case model
|
||||
case to
|
||||
case replyto = "replyTo"
|
||||
case sessionid = "sessionId"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5104}
|
||||
{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5457}
|
||||
{"recordType":"path","path":"acp","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"ACP","help":"ACP runtime controls for enabling dispatch, selecting backends, constraining allowed agent targets, and tuning streamed turn projection behavior.","hasChildren":true}
|
||||
{"recordType":"path","path":"acp.allowedAgents","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"ACP Allowed Agents","help":"Allowlist of ACP target agent ids permitted for ACP runtime sessions. Empty means no additional allowlist restriction.","hasChildren":true}
|
||||
{"recordType":"path","path":"acp.allowedAgents.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
@ -150,6 +150,10 @@
|
||||
{"recordType":"path","path":"agents.defaults.humanDelay.maxMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"Human Delay Max (ms)","help":"Maximum delay in ms for custom humanDelay (default: 2500).","hasChildren":false}
|
||||
{"recordType":"path","path":"agents.defaults.humanDelay.minMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Human Delay Min (ms)","help":"Minimum delay in ms for custom humanDelay (default: 800).","hasChildren":false}
|
||||
{"recordType":"path","path":"agents.defaults.humanDelay.mode","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Human Delay Mode","help":"Delay style for block replies (\"off\", \"natural\", \"custom\").","hasChildren":false}
|
||||
{"recordType":"path","path":"agents.defaults.imageGenerationModel","kind":"core","type":["object","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"agents.defaults.imageGenerationModel.fallbacks","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["media","reliability"],"label":"Image Generation Model Fallbacks","help":"Ordered fallback image-generation models (provider/model).","hasChildren":true}
|
||||
{"recordType":"path","path":"agents.defaults.imageGenerationModel.fallbacks.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"agents.defaults.imageGenerationModel.primary","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["media"],"label":"Image Generation Model","help":"Optional image-generation model (provider/model) used by the shared image generation capability.","hasChildren":false}
|
||||
{"recordType":"path","path":"agents.defaults.imageMaxDimensionPx","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["media","performance"],"label":"Image Max Dimension (px)","help":"Max image side length in pixels when sanitizing transcript/tool-result image payloads (default: 1200).","hasChildren":false}
|
||||
{"recordType":"path","path":"agents.defaults.imageModel","kind":"core","type":["object","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"agents.defaults.imageModel.fallbacks","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["media","models","reliability"],"label":"Image Model Fallbacks","help":"Ordered fallback image models (provider/model).","hasChildren":true}
|
||||
@ -1047,6 +1051,17 @@
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.elevenlabs.voiceSettings.useSpeakerBoost","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.maxTextLength","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.lang","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.outputFormat","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.pitch","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.proxy","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.rate","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.saveSubtitles","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.timeoutMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.voice","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.volume","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.mode","kind":"channel","type":"string","required":false,"enumValues":["final","all"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.modelOverrides","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.modelOverrides.allowModelId","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
@ -1068,7 +1083,7 @@
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.openai.speed","kind":"channel","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.openai.voice","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.prefsPath","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.provider","kind":"channel","type":"string","required":false,"enumValues":["elevenlabs","openai","edge"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.provider","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.summaryModel","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.timeoutMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.ackReaction","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
@ -1302,6 +1317,17 @@
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.elevenlabs.voiceSettings.useSpeakerBoost","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.maxTextLength","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.lang","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.outputFormat","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.pitch","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.proxy","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.rate","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.saveSubtitles","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.timeoutMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.voice","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.volume","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.mode","kind":"channel","type":"string","required":false,"enumValues":["final","all"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.modelOverrides","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.modelOverrides.allowModelId","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
@ -1323,7 +1349,7 @@
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.openai.speed","kind":"channel","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.openai.voice","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.prefsPath","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.provider","kind":"channel","type":"string","required":false,"enumValues":["elevenlabs","openai","edge"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.provider","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.summaryModel","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.discord.voice.tts.timeoutMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"channels.feishu","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Feishu","help":"飞书/Lark enterprise messaging.","hasChildren":true}
|
||||
@ -3431,12 +3457,14 @@
|
||||
{"recordType":"path","path":"commands.bashForegroundMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Bash Foreground Window (ms)","help":"How long bash waits before backgrounding (default: 2000; 0 backgrounds immediately).","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.config","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Allow /config","help":"Allow /config chat command to read/write config on disk (default: false).","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.debug","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Allow /debug","help":"Allow /debug chat command for runtime-only overrides (default: false).","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.mcp","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Allow /mcp","help":"Allow /mcp chat command to manage OpenClaw MCP server config under mcp.servers (default: false).","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.native","kind":"core","type":["boolean","string"],"required":true,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Native Commands","help":"Registers native slash/menu commands with channels that support command registration (Discord, Slack, Telegram). Keep enabled for discoverability unless you intentionally run text-only command workflows.","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.nativeSkills","kind":"core","type":["boolean","string"],"required":true,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Native Skill Commands","help":"Registers native skill commands so users can invoke skills directly from provider command menus where supported. Keep aligned with your skill policy so exposed commands match what operators expect.","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.ownerAllowFrom","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Command Owners","help":"Explicit owner allowlist for owner-only tools/commands. Use channel-native IDs (optionally prefixed like \"whatsapp:+15551234567\"). '*' is ignored.","hasChildren":true}
|
||||
{"recordType":"path","path":"commands.ownerAllowFrom.*","kind":"core","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"commands.ownerDisplay","kind":"core","type":"string","required":true,"enumValues":["raw","hash"],"defaultValue":"raw","deprecated":false,"sensitive":false,"tags":["access"],"label":"Owner ID Display","help":"Controls how owner IDs are rendered in the system prompt. Allowed values: raw, hash. Default: raw.","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.ownerDisplaySecret","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":true,"tags":["access","auth","security"],"label":"Owner ID Hash Secret","help":"Optional secret used to HMAC hash owner IDs when ownerDisplay=hash. Prefer env substitution.","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.plugins","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Allow /plugins","help":"Allow /plugins chat command to list discovered plugins and toggle plugin enablement in config (default: false).","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.restart","kind":"core","type":"boolean","required":true,"defaultValue":true,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Allow Restart","help":"Allow /restart and gateway restart tool actions (default: true).","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.text","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Text Commands","help":"Enables text-command parsing in chat input in addition to native command surfaces where available. Keep this enabled for compatibility across channels that do not support native command registration.","hasChildren":false}
|
||||
{"recordType":"path","path":"commands.useAccessGroups","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Use Access Groups","help":"Enforce access-group allowlists/policies for commands.","hasChildren":false}
|
||||
@ -3551,11 +3579,11 @@
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["media","network"],"label":"OpenAI Chat Completions Image Limits","help":"Image fetch/validation controls for OpenAI-compatible `image_url` parts.","hasChildren":true}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.allowedMimes","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access","media","network"],"label":"OpenAI Chat Completions Image MIME Allowlist","help":"Allowed MIME types for `image_url` parts (case-insensitive list).","hasChildren":true}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.allowedMimes.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.allowUrl","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access","media","network"],"label":"OpenAI Chat Completions Allow Image URLs","help":"Allow server-side URL fetches for `image_url` parts (default: false; data URIs remain supported).","hasChildren":false}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.allowUrl","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access","media","network"],"label":"OpenAI Chat Completions Allow Image URLs","help":"Allow server-side URL fetches for `image_url` parts (default: false; data URIs remain supported). Set this to `false` to disable URL fetching entirely.","hasChildren":false}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.maxBytes","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["media","network","performance"],"label":"OpenAI Chat Completions Image Max Bytes","help":"Max bytes per fetched/decoded `image_url` image (default: 10MB).","hasChildren":false}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.maxRedirects","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["media","network","performance","storage"],"label":"OpenAI Chat Completions Image Max Redirects","help":"Max HTTP redirects allowed when fetching `image_url` URLs (default: 3).","hasChildren":false}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.timeoutMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["media","network","performance"],"label":"OpenAI Chat Completions Image Timeout (ms)","help":"Timeout in milliseconds for `image_url` URL fetches (default: 10000).","hasChildren":false}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.urlAllowlist","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access","media","network"],"label":"OpenAI Chat Completions Image URL Allowlist","help":"Optional hostname allowlist for `image_url` URL fetches; supports exact hosts and `*.example.com` wildcards.","hasChildren":true}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.urlAllowlist","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access","media","network"],"label":"OpenAI Chat Completions Image URL Allowlist","help":"Optional hostname allowlist for `image_url` URL fetches; supports exact hosts and `*.example.com` wildcards. Empty or omitted lists mean no hostname allowlist restriction.","hasChildren":true}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.urlAllowlist.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.maxBodyBytes","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["network","performance"],"label":"OpenAI Chat Completions Max Body Bytes","help":"Max request body size in bytes for `/v1/chat/completions` (default: 20MB).","hasChildren":false}
|
||||
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.maxImageParts","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["media","network","performance"],"label":"OpenAI Chat Completions Max Image Parts","help":"Max number of `image_url` parts accepted from the latest user message (default: 8).","hasChildren":false}
|
||||
@ -3737,6 +3765,18 @@
|
||||
{"recordType":"path","path":"logging.redactPatterns","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["observability","privacy"],"label":"Custom Redaction Patterns","help":"Additional custom redact regex patterns applied to log output before emission/storage. Use this to mask org-specific tokens and identifiers not covered by built-in redaction rules.","hasChildren":true}
|
||||
{"recordType":"path","path":"logging.redactPatterns.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"logging.redactSensitive","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["observability","privacy"],"label":"Sensitive Data Redaction Mode","help":"Sensitive redaction mode: \"off\" disables built-in masking, while \"tools\" redacts sensitive tool/config payload fields. Keep \"tools\" in shared logs unless you have isolated secure log sinks.","hasChildren":false}
|
||||
{"recordType":"path","path":"mcp","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"MCP","help":"Global MCP server definitions managed by OpenClaw. Embedded Pi and other runtime adapters can consume these servers without storing them inside Pi-owned project settings.","hasChildren":true}
|
||||
{"recordType":"path","path":"mcp.servers","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"MCP Servers","help":"Named MCP server definitions. OpenClaw stores them in its own config and runtime adapters decide which transports are supported at execution time.","hasChildren":true}
|
||||
{"recordType":"path","path":"mcp.servers.*","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"mcp.servers.*.*","kind":"core","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"mcp.servers.*.args","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"mcp.servers.*.args.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"mcp.servers.*.command","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"mcp.servers.*.cwd","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"mcp.servers.*.env","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"mcp.servers.*.env.*","kind":"core","type":["boolean","number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"mcp.servers.*.url","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"mcp.servers.*.workingDirectory","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"media","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Media","help":"Top-level media behavior shared across providers and tools that handle inbound files. Keep defaults unless you need stable filenames for external processing pipelines or longer-lived inbound media retention.","hasChildren":true}
|
||||
{"recordType":"path","path":"media.preserveFilenames","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Preserve Media Filenames","help":"When enabled, uploaded media keeps its original filename instead of a generated temp-safe name. Turn this on when downstream automations depend on stable names, and leave off to reduce accidental filename leakage.","hasChildren":false}
|
||||
{"recordType":"path","path":"media.ttlHours","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Media Retention TTL (hours)","help":"Optional retention window in hours for persisted inbound media cleanup across the full media tree. Leave unset to preserve legacy behavior, or set values like 24 (1 day) or 168 (7 days) when you want automatic cleanup.","hasChildren":false}
|
||||
@ -3867,6 +3907,17 @@
|
||||
{"recordType":"path","path":"messages.tts.elevenlabs.voiceSettings.useSpeakerBoost","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.enabled","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.maxTextLength","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.microsoft","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"messages.tts.microsoft.enabled","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.microsoft.lang","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.microsoft.outputFormat","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.microsoft.pitch","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.microsoft.proxy","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.microsoft.rate","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.microsoft.saveSubtitles","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.microsoft.timeoutMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.microsoft.voice","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.microsoft.volume","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.mode","kind":"core","type":"string","required":false,"enumValues":["final","all"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.modelOverrides","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"messages.tts.modelOverrides.allowModelId","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
@ -3888,7 +3939,7 @@
|
||||
{"recordType":"path","path":"messages.tts.openai.speed","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.openai.voice","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.prefsPath","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.provider","kind":"core","type":"string","required":false,"enumValues":["elevenlabs","openai","edge"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.provider","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.summaryModel","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"messages.tts.timeoutMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"meta","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Metadata","help":"Metadata fields automatically maintained by OpenClaw to record write/version history for this config file. Keep these values system-managed and avoid manual edits unless debugging migration history.","hasChildren":true}
|
||||
@ -3969,6 +4020,10 @@
|
||||
{"recordType":"path","path":"plugins.entries.*.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Enabled","help":"Per-plugin enablement override for a specific entry, applied on top of global plugin policy (restart required). Use this to stage plugin rollout gradually across environments.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.*.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.*.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.*.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.*.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.*.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.*.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.acpx","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"ACPX Runtime","help":"ACP runtime backend powered by acpx with configurable command path and version policy. (plugin: acpx)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.acpx.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"ACPX Runtime Config","help":"Plugin-defined config payload for acpx.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.acpx.config.command","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"acpx Command","help":"Optional path/command override for acpx (for example /home/user/repos/acpx/dist/cli.js). Leave unset to use plugin-local bundled acpx.","hasChildren":false}
|
||||
@ -3989,52 +4044,92 @@
|
||||
{"recordType":"path","path":"plugins.entries.acpx.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable ACPX Runtime","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.acpx.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.acpx.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.acpx.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.acpx.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.acpx.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.acpx.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.amazon-bedrock","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/amazon-bedrock-provider","help":"OpenClaw Amazon Bedrock provider plugin (plugin: amazon-bedrock)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.amazon-bedrock.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/amazon-bedrock-provider Config","help":"Plugin-defined config payload for amazon-bedrock.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.amazon-bedrock.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/amazon-bedrock-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.amazon-bedrock.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.amazon-bedrock.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.amazon-bedrock.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.amazon-bedrock.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.amazon-bedrock.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.amazon-bedrock.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.anthropic","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/anthropic-provider","help":"OpenClaw Anthropic provider plugin (plugin: anthropic)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.anthropic.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/anthropic-provider Config","help":"Plugin-defined config payload for anthropic.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.anthropic.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/anthropic-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.anthropic.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.anthropic.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.anthropic.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.anthropic.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.anthropic.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.anthropic.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.bluebubbles","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/bluebubbles","help":"OpenClaw BlueBubbles channel plugin (plugin: bluebubbles)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.bluebubbles.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/bluebubbles Config","help":"Plugin-defined config payload for bluebubbles.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.bluebubbles.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/bluebubbles","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.bluebubbles.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.bluebubbles.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.bluebubbles.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.bluebubbles.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.bluebubbles.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.bluebubbles.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.brave","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/brave-plugin","help":"OpenClaw Brave plugin (plugin: brave)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.brave.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/brave-plugin Config","help":"Plugin-defined config payload for brave.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.brave.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/brave-plugin","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.brave.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.brave.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.brave.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.brave.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.brave.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.brave.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.byteplus","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/byteplus-provider","help":"OpenClaw BytePlus provider plugin (plugin: byteplus)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.byteplus.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/byteplus-provider Config","help":"Plugin-defined config payload for byteplus.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.byteplus.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/byteplus-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.byteplus.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.byteplus.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.byteplus.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.byteplus.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.byteplus.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.byteplus.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/cloudflare-ai-gateway-provider","help":"OpenClaw Cloudflare AI Gateway provider plugin (plugin: cloudflare-ai-gateway)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/cloudflare-ai-gateway-provider Config","help":"Plugin-defined config payload for cloudflare-ai-gateway.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/cloudflare-ai-gateway-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.copilot-proxy","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/copilot-proxy","help":"OpenClaw Copilot Proxy provider plugin (plugin: copilot-proxy)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.copilot-proxy.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/copilot-proxy Config","help":"Plugin-defined config payload for copilot-proxy.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.copilot-proxy.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/copilot-proxy","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.copilot-proxy.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.copilot-proxy.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.copilot-proxy.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.copilot-proxy.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.copilot-proxy.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.copilot-proxy.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.device-pair","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Device Pairing","help":"Generate setup codes and approve device pairing requests. (plugin: device-pair)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.device-pair.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Device Pairing Config","help":"Plugin-defined config payload for device-pair.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.device-pair.config.publicUrl","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Gateway URL","help":"Public WebSocket URL used for /pair setup codes (ws/wss or http/https).","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.device-pair.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Device Pairing","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.device-pair.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.device-pair.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.device-pair.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.device-pair.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.device-pair.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.device-pair.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.diagnostics-otel","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["observability"],"label":"@openclaw/diagnostics-otel","help":"OpenClaw diagnostics OpenTelemetry exporter (plugin: diagnostics-otel)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.diagnostics-otel.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["observability"],"label":"@openclaw/diagnostics-otel Config","help":"Plugin-defined config payload for diagnostics-otel.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.diagnostics-otel.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["observability"],"label":"Enable @openclaw/diagnostics-otel","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.diagnostics-otel.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.diagnostics-otel.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.diagnostics-otel.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.diagnostics-otel.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.diagnostics-otel.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.diagnostics-otel.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.diffs","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Diffs","help":"Read-only diff viewer and file renderer for agents. (plugin: diffs)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.diffs.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Diffs Config","help":"Plugin-defined config payload for diffs.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.diffs.config.defaults","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
@ -4062,66 +4157,127 @@
|
||||
{"recordType":"path","path":"plugins.entries.diffs.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Diffs","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.diffs.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.diffs.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.diffs.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.diffs.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.diffs.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.diffs.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.discord","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/discord","help":"OpenClaw Discord channel plugin (plugin: discord)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.discord.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/discord Config","help":"Plugin-defined config payload for discord.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.discord.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/discord","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.discord.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.discord.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.discord.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.discord.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.discord.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.discord.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.elevenlabs","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/elevenlabs-speech","help":"OpenClaw ElevenLabs speech plugin (plugin: elevenlabs)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.elevenlabs.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/elevenlabs-speech Config","help":"Plugin-defined config payload for elevenlabs.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.elevenlabs.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/elevenlabs-speech","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.elevenlabs.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.elevenlabs.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.elevenlabs.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.elevenlabs.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.elevenlabs.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.elevenlabs.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.feishu","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/feishu","help":"OpenClaw Feishu/Lark channel plugin (community maintained by @m1heng) (plugin: feishu)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.feishu.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/feishu Config","help":"Plugin-defined config payload for feishu.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.feishu.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/feishu","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.feishu.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.feishu.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.feishu.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.feishu.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.feishu.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.feishu.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.firecrawl","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/firecrawl-plugin","help":"OpenClaw Firecrawl plugin (plugin: firecrawl)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.firecrawl.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/firecrawl-plugin Config","help":"Plugin-defined config payload for firecrawl.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.firecrawl.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/firecrawl-plugin","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.firecrawl.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.firecrawl.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.firecrawl.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.firecrawl.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.firecrawl.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.firecrawl.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.github-copilot","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/github-copilot-provider","help":"OpenClaw GitHub Copilot provider plugin (plugin: github-copilot)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.github-copilot.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/github-copilot-provider Config","help":"Plugin-defined config payload for github-copilot.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.github-copilot.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/github-copilot-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.github-copilot.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.github-copilot.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.github-copilot.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.github-copilot.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.github-copilot.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.github-copilot.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.google","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/google-plugin","help":"OpenClaw Google plugin (plugin: google)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.google.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/google-plugin Config","help":"Plugin-defined config payload for google.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.google.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/google-plugin","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.google.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.google.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.google.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.google.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.google.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.google.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.googlechat","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/googlechat","help":"OpenClaw Google Chat channel plugin (plugin: googlechat)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.googlechat.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/googlechat Config","help":"Plugin-defined config payload for googlechat.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.googlechat.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/googlechat","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.googlechat.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.googlechat.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.googlechat.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.googlechat.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.googlechat.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.googlechat.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.huggingface","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/huggingface-provider","help":"OpenClaw Hugging Face provider plugin (plugin: huggingface)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.huggingface.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/huggingface-provider Config","help":"Plugin-defined config payload for huggingface.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.huggingface.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/huggingface-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.huggingface.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.huggingface.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.huggingface.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.huggingface.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.huggingface.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.huggingface.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.imessage","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/imessage","help":"OpenClaw iMessage channel plugin (plugin: imessage)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.imessage.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/imessage Config","help":"Plugin-defined config payload for imessage.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.imessage.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/imessage","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.imessage.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.imessage.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.imessage.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.imessage.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.imessage.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.imessage.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.irc","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/irc","help":"OpenClaw IRC channel plugin (plugin: irc)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.irc.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/irc Config","help":"Plugin-defined config payload for irc.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.irc.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/irc","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.irc.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.irc.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.irc.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.irc.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.irc.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.irc.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kilocode","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kilocode-provider","help":"OpenClaw Kilo Gateway provider plugin (plugin: kilocode)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.kilocode.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kilocode-provider Config","help":"Plugin-defined config payload for kilocode.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kilocode.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/kilocode-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kilocode.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.kilocode.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kimi-coding","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kimi-coding-provider","help":"OpenClaw Kimi Coding provider plugin (plugin: kimi-coding)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.kimi-coding.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kimi-coding-provider Config","help":"Plugin-defined config payload for kimi-coding.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kimi-coding.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/kimi-coding-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kimi-coding.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.kimi-coding.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kilocode.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.kilocode.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.kilocode.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kilocode.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kimi","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kimi-provider","help":"OpenClaw Kimi provider plugin (plugin: kimi)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.kimi.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kimi-provider Config","help":"Plugin-defined config payload for kimi.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kimi.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/kimi-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kimi.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.kimi.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kimi.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.kimi.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.kimi.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.kimi.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.line","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/line","help":"OpenClaw LINE channel plugin (plugin: line)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.line.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/line Config","help":"Plugin-defined config payload for line.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.line.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/line","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.line.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.line.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.line.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.line.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.line.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.line.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.llm-task","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"LLM Task","help":"Generic JSON-only LLM tool for structured tasks callable from workflows. (plugin: llm-task)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.llm-task.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"LLM Task Config","help":"Plugin-defined config payload for llm-task.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.llm-task.config.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
@ -4134,26 +4290,46 @@
|
||||
{"recordType":"path","path":"plugins.entries.llm-task.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable LLM Task","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.llm-task.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.llm-task.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.llm-task.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.llm-task.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.llm-task.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.llm-task.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.lobster","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Lobster","help":"Typed workflow tool with resumable approvals. (plugin: lobster)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.lobster.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Lobster Config","help":"Plugin-defined config payload for lobster.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.lobster.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Lobster","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.lobster.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.lobster.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.lobster.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.lobster.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.lobster.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.lobster.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.matrix","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/matrix","help":"OpenClaw Matrix channel plugin (plugin: matrix)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.matrix.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/matrix Config","help":"Plugin-defined config payload for matrix.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.matrix.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/matrix","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.matrix.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.matrix.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.matrix.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.matrix.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.matrix.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.matrix.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.mattermost","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/mattermost","help":"OpenClaw Mattermost channel plugin (plugin: mattermost)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.mattermost.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/mattermost Config","help":"Plugin-defined config payload for mattermost.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.mattermost.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/mattermost","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.mattermost.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.mattermost.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.mattermost.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.mattermost.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.mattermost.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.mattermost.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.memory-core","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/memory-core","help":"OpenClaw core memory search plugin (plugin: memory-core)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.memory-core.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/memory-core Config","help":"Plugin-defined config payload for memory-core.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.memory-core.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/memory-core","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.memory-core.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.memory-core.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.memory-core.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.memory-core.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.memory-core.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.memory-core.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.memory-lancedb","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"@openclaw/memory-lancedb","help":"OpenClaw LanceDB-backed long-term memory plugin with auto-recall/capture (plugin: memory-lancedb)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.memory-lancedb.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"@openclaw/memory-lancedb Config","help":"Plugin-defined config payload for memory-lancedb.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.memory-lancedb.config.autoCapture","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Auto-Capture","help":"Automatically capture important information from conversations","hasChildren":false}
|
||||
@ -4168,76 +4344,145 @@
|
||||
{"recordType":"path","path":"plugins.entries.memory-lancedb.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Enable @openclaw/memory-lancedb","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.memory-lancedb.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.memory-lancedb.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.memory-lancedb.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.memory-lancedb.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.memory-lancedb.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.memory-lancedb.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.microsoft","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/microsoft-speech","help":"OpenClaw Microsoft speech plugin (plugin: microsoft)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.microsoft.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/microsoft-speech Config","help":"Plugin-defined config payload for microsoft.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.microsoft.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/microsoft-speech","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.microsoft.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.microsoft.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.microsoft.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.microsoft.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.microsoft.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.microsoft.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.minimax","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"@openclaw/minimax-provider","help":"OpenClaw MiniMax provider and OAuth plugin (plugin: minimax)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.minimax.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"@openclaw/minimax-provider Config","help":"Plugin-defined config payload for minimax.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.minimax.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"Enable @openclaw/minimax-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.minimax.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.minimax.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.minimax.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.minimax.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.minimax.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.minimax.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.mistral","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/mistral-provider","help":"OpenClaw Mistral provider plugin (plugin: mistral)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.mistral.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/mistral-provider Config","help":"Plugin-defined config payload for mistral.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.mistral.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/mistral-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.mistral.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.mistral.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.mistral.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.mistral.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.mistral.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.mistral.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.modelstudio","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/modelstudio-provider","help":"OpenClaw Model Studio provider plugin (plugin: modelstudio)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.modelstudio.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/modelstudio-provider Config","help":"Plugin-defined config payload for modelstudio.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.modelstudio.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/modelstudio-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.modelstudio.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.modelstudio.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.modelstudio.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.modelstudio.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.modelstudio.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.modelstudio.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.moonshot","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/moonshot-provider","help":"OpenClaw Moonshot provider plugin (plugin: moonshot)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.moonshot.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/moonshot-provider Config","help":"Plugin-defined config payload for moonshot.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.moonshot.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/moonshot-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.moonshot.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.moonshot.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.moonshot.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.moonshot.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.moonshot.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.moonshot.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.msteams","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/msteams","help":"OpenClaw Microsoft Teams channel plugin (plugin: msteams)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.msteams.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/msteams Config","help":"Plugin-defined config payload for msteams.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.msteams.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/msteams","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.msteams.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.msteams.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.msteams.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.msteams.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.msteams.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.msteams.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nextcloud-talk","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nextcloud-talk","help":"OpenClaw Nextcloud Talk channel plugin (plugin: nextcloud-talk)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nextcloud-talk.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nextcloud-talk Config","help":"Plugin-defined config payload for nextcloud-talk.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nextcloud-talk.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/nextcloud-talk","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nextcloud-talk.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nextcloud-talk.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nextcloud-talk.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nextcloud-talk.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nextcloud-talk.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nextcloud-talk.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nostr","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nostr","help":"OpenClaw Nostr channel plugin for NIP-04 encrypted DMs (plugin: nostr)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nostr.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nostr Config","help":"Plugin-defined config payload for nostr.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nostr.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/nostr","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nostr.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nostr.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nostr.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nostr.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nostr.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nostr.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nvidia","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nvidia-provider","help":"OpenClaw NVIDIA provider plugin (plugin: nvidia)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nvidia.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nvidia-provider Config","help":"Plugin-defined config payload for nvidia.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nvidia.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/nvidia-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nvidia.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nvidia.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nvidia.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nvidia.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.nvidia.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.nvidia.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.ollama","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/ollama-provider","help":"OpenClaw Ollama provider plugin (plugin: ollama)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.ollama.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/ollama-provider Config","help":"Plugin-defined config payload for ollama.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.ollama.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/ollama-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.ollama.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.ollama.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.ollama.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.ollama.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.ollama.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.ollama.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.open-prose","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"OpenProse","help":"OpenProse VM skill pack with a /prose slash command. (plugin: open-prose)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.open-prose.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"OpenProse Config","help":"Plugin-defined config payload for open-prose.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.open-prose.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable OpenProse","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.open-prose.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.open-prose.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.open-prose.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.open-prose.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.open-prose.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.open-prose.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openai","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/openai-provider","help":"OpenClaw OpenAI provider plugins (plugin: openai)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openai.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/openai-provider Config","help":"Plugin-defined config payload for openai.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openai.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/openai-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openai.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openai.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openai.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openai.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openai.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openai.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.opencode","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/opencode-provider","help":"OpenClaw OpenCode Zen provider plugin (plugin: opencode)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.opencode-go","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/opencode-go-provider","help":"OpenClaw OpenCode Go provider plugin (plugin: opencode-go)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.opencode-go.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/opencode-go-provider Config","help":"Plugin-defined config payload for opencode-go.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.opencode-go.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/opencode-go-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.opencode-go.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.opencode-go.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.opencode-go.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.opencode-go.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.opencode-go.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.opencode-go.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.opencode.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/opencode-provider Config","help":"Plugin-defined config payload for opencode.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.opencode.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/opencode-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.opencode.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.opencode.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.opencode.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.opencode.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.opencode.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.opencode.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openrouter","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/openrouter-provider","help":"OpenClaw OpenRouter provider plugin (plugin: openrouter)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openrouter.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/openrouter-provider Config","help":"Plugin-defined config payload for openrouter.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openrouter.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/openrouter-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openrouter.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openrouter.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openrouter.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openrouter.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openrouter.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openrouter.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openshell","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"OpenShell Sandbox","help":"Sandbox backend powered by OpenShell with mirrored local workspaces and SSH-based command execution. (plugin: openshell)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openshell.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"OpenShell Sandbox Config","help":"Plugin-defined config payload for openshell.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openshell.config.autoProviders","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Auto-create Providers","help":"When enabled, pass --auto-providers during sandbox create.","hasChildren":false}
|
||||
@ -4255,61 +4500,109 @@
|
||||
{"recordType":"path","path":"plugins.entries.openshell.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable OpenShell Sandbox","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openshell.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openshell.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openshell.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openshell.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.openshell.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.openshell.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.perplexity","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/perplexity-plugin","help":"OpenClaw Perplexity plugin (plugin: perplexity)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.perplexity.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/perplexity-plugin Config","help":"Plugin-defined config payload for perplexity.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.perplexity.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/perplexity-plugin","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.perplexity.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.perplexity.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.perplexity.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.perplexity.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.perplexity.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.perplexity.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.phone-control","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Phone Control","help":"Arm/disarm high-risk phone node commands (camera/screen/writes) with an optional auto-expiry. (plugin: phone-control)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.phone-control.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Phone Control Config","help":"Plugin-defined config payload for phone-control.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.phone-control.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Phone Control","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.phone-control.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.phone-control.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.phone-control.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.phone-control.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.phone-control.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.phone-control.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.qianfan","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/qianfan-provider","help":"OpenClaw Qianfan provider plugin (plugin: qianfan)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.qianfan.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/qianfan-provider Config","help":"Plugin-defined config payload for qianfan.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.qianfan.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/qianfan-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.qianfan.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.qianfan.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.qianfan.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.qianfan.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.qianfan.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.qianfan.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.qwen-portal-auth","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"qwen-portal-auth","help":"Plugin entry for qwen-portal-auth.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"qwen-portal-auth Config","help":"Plugin-defined config payload for qwen-portal-auth.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable qwen-portal-auth","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.sglang","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/sglang-provider","help":"OpenClaw SGLang provider plugin (plugin: sglang)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.sglang.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/sglang-provider Config","help":"Plugin-defined config payload for sglang.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.sglang.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/sglang-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.sglang.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.sglang.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.sglang.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.sglang.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.sglang.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.sglang.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.signal","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/signal","help":"OpenClaw Signal channel plugin (plugin: signal)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.signal.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/signal Config","help":"Plugin-defined config payload for signal.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.signal.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/signal","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.signal.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.signal.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.signal.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.signal.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.signal.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.signal.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.slack","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/slack","help":"OpenClaw Slack channel plugin (plugin: slack)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.slack.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/slack Config","help":"Plugin-defined config payload for slack.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.slack.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/slack","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.slack.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.slack.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.slack.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.slack.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.slack.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.slack.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.synology-chat","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/synology-chat","help":"Synology Chat channel plugin for OpenClaw (plugin: synology-chat)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.synology-chat.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/synology-chat Config","help":"Plugin-defined config payload for synology-chat.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.synology-chat.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/synology-chat","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.synology-chat.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.synology-chat.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.synology-chat.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.synology-chat.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.synology-chat.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.synology-chat.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.synthetic","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/synthetic-provider","help":"OpenClaw Synthetic provider plugin (plugin: synthetic)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.synthetic.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/synthetic-provider Config","help":"Plugin-defined config payload for synthetic.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.synthetic.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/synthetic-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.synthetic.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.synthetic.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.synthetic.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.synthetic.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.synthetic.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.synthetic.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.talk-voice","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Talk Voice","help":"Manage Talk voice selection (list/set). (plugin: talk-voice)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.talk-voice.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Talk Voice Config","help":"Plugin-defined config payload for talk-voice.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.talk-voice.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Talk Voice","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.talk-voice.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.talk-voice.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.talk-voice.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.talk-voice.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.talk-voice.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.talk-voice.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.telegram","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/telegram","help":"OpenClaw Telegram channel plugin (plugin: telegram)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.telegram.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/telegram Config","help":"Plugin-defined config payload for telegram.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.telegram.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/telegram","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.telegram.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.telegram.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.telegram.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.telegram.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.telegram.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.telegram.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.thread-ownership","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Thread Ownership","help":"Prevents multiple agents from responding in the same Slack thread. Uses HTTP calls to the slack-forwarder ownership API. (plugin: thread-ownership)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.thread-ownership.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Thread Ownership Config","help":"Plugin-defined config payload for thread-ownership.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.thread-ownership.config.abTestChannels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"A/B Test Channels","help":"Slack channel IDs where thread ownership is enforced","hasChildren":true}
|
||||
@ -4318,36 +4611,64 @@
|
||||
{"recordType":"path","path":"plugins.entries.thread-ownership.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Enable Thread Ownership","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.thread-ownership.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.thread-ownership.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.thread-ownership.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.thread-ownership.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.thread-ownership.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.thread-ownership.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.tlon","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/tlon","help":"OpenClaw Tlon/Urbit channel plugin (plugin: tlon)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.tlon.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/tlon Config","help":"Plugin-defined config payload for tlon.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.tlon.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/tlon","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.tlon.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.tlon.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.tlon.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.tlon.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.tlon.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.tlon.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.together","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/together-provider","help":"OpenClaw Together provider plugin (plugin: together)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.together.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/together-provider Config","help":"Plugin-defined config payload for together.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.together.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/together-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.together.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.together.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.together.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.together.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.together.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.together.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.twitch","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/twitch","help":"OpenClaw Twitch channel plugin (plugin: twitch)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.twitch.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/twitch Config","help":"Plugin-defined config payload for twitch.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.twitch.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/twitch","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.twitch.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.twitch.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.twitch.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.twitch.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.twitch.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.twitch.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.venice","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/venice-provider","help":"OpenClaw Venice provider plugin (plugin: venice)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.venice.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/venice-provider Config","help":"Plugin-defined config payload for venice.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.venice.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/venice-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.venice.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.venice.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.venice.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.venice.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.venice.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.venice.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/vercel-ai-gateway-provider","help":"OpenClaw Vercel AI Gateway provider plugin (plugin: vercel-ai-gateway)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/vercel-ai-gateway-provider Config","help":"Plugin-defined config payload for vercel-ai-gateway.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/vercel-ai-gateway-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.vllm","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/vllm-provider","help":"OpenClaw vLLM provider plugin (plugin: vllm)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.vllm.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/vllm-provider Config","help":"Plugin-defined config payload for vllm.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.vllm.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/vllm-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.vllm.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.vllm.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.vllm.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.vllm.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.vllm.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.vllm.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/voice-call","help":"OpenClaw voice-call plugin (plugin: voice-call)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/voice-call Config","help":"Plugin-defined config payload for voice-call.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.config.allowFrom","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Inbound Allowlist","hasChildren":true}
|
||||
@ -4449,7 +4770,7 @@
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.openai.speed","kind":"plugin","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.openai.voice","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced","media"],"label":"OpenAI TTS Voice","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.prefsPath","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.provider","kind":"plugin","type":"string","required":false,"enumValues":["openai","elevenlabs","edge"],"deprecated":false,"sensitive":false,"tags":["advanced","media"],"label":"TTS Provider Override","help":"Deep-merges with messages.tts (Edge is ignored for calls).","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.provider","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced","media"],"label":"TTS Provider Override","help":"Deep-merges with messages.tts (Microsoft is ignored for calls).","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.summaryModel","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.timeoutMs","kind":"plugin","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.config.tunnel","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
@ -4469,41 +4790,73 @@
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/voice-call","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.voice-call.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.volcengine","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/volcengine-provider","help":"OpenClaw Volcengine provider plugin (plugin: volcengine)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.volcengine.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/volcengine-provider Config","help":"Plugin-defined config payload for volcengine.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.volcengine.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/volcengine-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.volcengine.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.volcengine.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.volcengine.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.volcengine.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.volcengine.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.volcengine.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.whatsapp","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/whatsapp","help":"OpenClaw WhatsApp channel plugin (plugin: whatsapp)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.whatsapp.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/whatsapp Config","help":"Plugin-defined config payload for whatsapp.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.whatsapp.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/whatsapp","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.whatsapp.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.whatsapp.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.whatsapp.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.whatsapp.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.whatsapp.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.whatsapp.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.xai","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/xai-plugin","help":"OpenClaw xAI plugin (plugin: xai)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.xai.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/xai-plugin Config","help":"Plugin-defined config payload for xai.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.xai.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/xai-plugin","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.xai.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.xai.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.xai.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.xai.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.xai.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.xai.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.xiaomi","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/xiaomi-provider","help":"OpenClaw Xiaomi provider plugin (plugin: xiaomi)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.xiaomi.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/xiaomi-provider Config","help":"Plugin-defined config payload for xiaomi.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.xiaomi.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/xiaomi-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.xiaomi.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.xiaomi.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.xiaomi.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.xiaomi.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.xiaomi.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.xiaomi.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zai","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zai-provider","help":"OpenClaw Z.AI provider plugin (plugin: zai)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zai.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zai-provider Config","help":"Plugin-defined config payload for zai.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zai.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/zai-provider","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zai.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zai.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zai.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zai.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zai.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zai.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zalo","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zalo","help":"OpenClaw Zalo channel plugin (plugin: zalo)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zalo.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zalo Config","help":"Plugin-defined config payload for zalo.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zalo.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/zalo","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zalo.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zalo.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zalo.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zalo.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zalo.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zalo.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zalouser","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zalouser","help":"OpenClaw Zalo Personal Account plugin via native zca-js integration (plugin: zalouser)","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zalouser.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zalouser Config","help":"Plugin-defined config payload for zalouser.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zalouser.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/zalouser","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zalouser.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zalouser.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zalouser.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zalouser.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.entries.zalouser.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.entries.zalouser.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
|
||||
{"recordType":"path","path":"plugins.installs","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Install Records","help":"CLI-managed install metadata (used by `openclaw plugins update` to locate install sources).","hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.installs.*","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
|
||||
{"recordType":"path","path":"plugins.installs.*.installedAt","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Install Time","help":"ISO timestamp of last install/update.","hasChildren":false}
|
||||
|
||||
@ -47,6 +47,10 @@
|
||||
"source": "Quick Start",
|
||||
"target": "快速开始"
|
||||
},
|
||||
{
|
||||
"source": "Capability Cookbook",
|
||||
"target": "能力扩展手册"
|
||||
},
|
||||
{
|
||||
"source": "Setup Wizard Reference",
|
||||
"target": "设置向导参考"
|
||||
|
||||
@ -38,6 +38,7 @@ Every request must include the hook token. Prefer headers:
|
||||
- `Authorization: Bearer <token>` (recommended)
|
||||
- `x-openclaw-token: <token>`
|
||||
- Query-string tokens are rejected (`?token=...` returns `400`).
|
||||
- Treat `hooks.token` holders as full-trust callers for the hook ingress surface on that gateway. Hook payload content is still untrusted, but this is not a separate non-owner auth boundary.
|
||||
|
||||
## Endpoints
|
||||
|
||||
@ -205,6 +206,7 @@ curl -X POST http://127.0.0.1:18789/hooks/gmail \
|
||||
|
||||
- Keep hook endpoints behind loopback, tailnet, or trusted reverse proxy.
|
||||
- Use a dedicated hook token; do not reuse gateway auth tokens.
|
||||
- Prefer a dedicated hook agent with strict `tools.profile` and sandboxing so hook ingress has a narrower blast radius.
|
||||
- Repeated auth failures are rate-limited per client address to slow brute-force attempts.
|
||||
- If you use multi-agent routing, set `hooks.allowedAgentIds` to limit explicit `agentId` selection.
|
||||
- Keep `hooks.allowRequestSessionKey=false` unless you require caller-selected sessions.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -191,6 +191,35 @@ OpenClaw resolves them **user-first**:
|
||||
|
||||
If you need deterministic behavior, always use the explicit prefixes (`user:<id>` / `channel:<id>`).
|
||||
|
||||
## DM channel retry
|
||||
|
||||
When OpenClaw sends to a Mattermost DM target and needs to resolve the direct channel first, it
|
||||
retries transient direct-channel creation failures by default.
|
||||
|
||||
Use `channels.mattermost.dmChannelRetry` to tune that behavior globally for the Mattermost plugin,
|
||||
or `channels.mattermost.accounts.<id>.dmChannelRetry` for one account.
|
||||
|
||||
```json5
|
||||
{
|
||||
channels: {
|
||||
mattermost: {
|
||||
dmChannelRetry: {
|
||||
maxRetries: 3,
|
||||
initialDelayMs: 1000,
|
||||
maxDelayMs: 10000,
|
||||
timeoutMs: 30000,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- This applies only to DM channel creation (`/api/v4/channels/direct`), not every Mattermost API call.
|
||||
- Retries apply to transient failures such as rate limits, 5xx responses, and network or timeout errors.
|
||||
- 4xx client errors other than `429` are treated as permanent and are not retried.
|
||||
|
||||
## Reactions (message tool)
|
||||
|
||||
- Use `message action=react` with `channel=mattermost`.
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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).
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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>`
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -21,7 +21,7 @@ Related:
|
||||
|
||||
```bash
|
||||
openclaw plugins list
|
||||
openclaw plugins info <id>
|
||||
openclaw plugins inspect <id>
|
||||
openclaw plugins enable <id>
|
||||
openclaw plugins disable <id>
|
||||
openclaw plugins uninstall <id>
|
||||
@ -31,6 +31,8 @@ openclaw plugins update --all
|
||||
openclaw plugins marketplace list <marketplace>
|
||||
```
|
||||
|
||||
`info` is an alias for `inspect`.
|
||||
|
||||
Bundled plugins ship with OpenClaw but start disabled. Use `plugins enable` to
|
||||
activate them.
|
||||
|
||||
@ -148,3 +150,26 @@ marketplace installs.
|
||||
When a stored integrity hash exists and the fetched artifact hash changes,
|
||||
OpenClaw prints a warning and asks for confirmation before proceeding. Use
|
||||
global `--yes` to bypass prompts in CI/non-interactive runs.
|
||||
|
||||
### Inspect
|
||||
|
||||
```bash
|
||||
openclaw plugins inspect <id>
|
||||
openclaw plugins inspect <id> --json
|
||||
```
|
||||
|
||||
Deep introspection for a single plugin. Shows identity, load status, source,
|
||||
plugin shape, registered capabilities, hooks, tools, commands, services,
|
||||
gateway methods, HTTP routes, policy flags, diagnostics, and install metadata.
|
||||
|
||||
Plugin shape is derived from actual registration behavior:
|
||||
|
||||
- **plain-capability** — one capability type registered
|
||||
- **hybrid-capability** — multiple capability types registered
|
||||
- **hook-only** — only hooks, no capabilities or surfaces
|
||||
- **non-capability** — tools/commands/services but no capabilities
|
||||
|
||||
The `--json` flag outputs a machine-readable report suitable for scripting and
|
||||
auditing.
|
||||
|
||||
`info` is an alias for `inspect`.
|
||||
|
||||
@ -30,7 +30,7 @@ This is for cooperative/shared inbox hardening. A single Gateway shared by mutua
|
||||
It also emits `security.trust_model.multi_user_heuristic` when config suggests likely shared-user ingress (for example open DM/group policy, configured group targets, or wildcard sender rules), and reminds you that OpenClaw is a personal-assistant trust model by default.
|
||||
For intentional shared-user setups, the audit guidance is to sandbox all sessions, keep filesystem access workspace-scoped, and keep personal/private identities or credentials off that runtime.
|
||||
It also warns when small models (`<=300B`) are used without sandboxing and with web/browser tools enabled.
|
||||
For webhook ingress, it warns when `hooks.defaultSessionKey` is unset, when request `sessionKey` overrides are enabled, and when overrides are enabled without `hooks.allowedSessionKeyPrefixes`.
|
||||
For webhook ingress, it warns when `hooks.token` reuses the Gateway token, when `hooks.defaultSessionKey` is unset, when `hooks.allowedAgentIds` is unrestricted, when request `sessionKey` overrides are enabled, and when overrides are enabled without `hooks.allowedSessionKeyPrefixes`.
|
||||
It also warns when sandbox Docker settings are configured while sandbox mode is off, when `gateway.nodes.denyCommands` uses ineffective pattern-like/unknown entries (exact node command-name matching only, not shell-text filtering), when `gateway.nodes.allowCommands` explicitly enables dangerous node commands, when global `tools.profile="minimal"` is overridden by agent tool profiles, when open groups expose runtime/filesystem tools without sandbox/workspace guards, and when installed extension plugin tools may be reachable under permissive tool policy.
|
||||
It also flags `gateway.allowRealIpFallback=true` (header-spoofing risk if proxies are misconfigured) and `discovery.mdns.mode="full"` (metadata leakage via mDNS TXT records).
|
||||
It also warns when sandbox browser uses Docker `bridge` network without `sandbox.browser.cdpSourceRange`.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
---
|
||||
summary: "CLI reference for `openclaw setup` (initialize config + workspace)"
|
||||
read_when:
|
||||
- You’re doing first-run setup without the full setup wizard
|
||||
- You’re 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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -97,6 +97,17 @@ compaction and can run alongside it.
|
||||
|
||||
See [OpenAI provider](/providers/openai) for model params and overrides.
|
||||
|
||||
## Custom context engines
|
||||
|
||||
Compaction behavior is owned by the active
|
||||
[context engine](/concepts/context-engine). The legacy engine uses the built-in
|
||||
summarization described above. Plugin engines (selected via
|
||||
`plugins.slots.contextEngine`) can implement any compaction strategy — DAG
|
||||
summaries, vector retrieval, incremental condensation, etc.
|
||||
|
||||
When a plugin engine sets `ownsCompaction: true`, OpenClaw delegates all
|
||||
compaction decisions to the engine and does not run built-in auto-compaction.
|
||||
|
||||
## Tips
|
||||
|
||||
- Use `/compact` when sessions feel stale or context is bloated.
|
||||
|
||||
250
docs/concepts/context-engine.md
Normal file
250
docs/concepts/context-engine.md
Normal file
@ -0,0 +1,250 @@
|
||||
---
|
||||
summary: "Context engine: pluggable context assembly, compaction, and subagent lifecycle"
|
||||
read_when:
|
||||
- You want to understand how OpenClaw assembles model context
|
||||
- You are switching between the legacy engine and a plugin engine
|
||||
- You are building a context engine plugin
|
||||
title: "Context Engine"
|
||||
---
|
||||
|
||||
# Context Engine
|
||||
|
||||
A **context engine** controls how OpenClaw builds model context for each run.
|
||||
It decides which messages to include, how to summarize older history, and how
|
||||
to manage context across subagent boundaries.
|
||||
|
||||
OpenClaw ships with a built-in `legacy` engine. Plugins can register
|
||||
alternative engines that replace the entire context pipeline.
|
||||
|
||||
## Quick start
|
||||
|
||||
Check which engine is active:
|
||||
|
||||
```bash
|
||||
openclaw doctor
|
||||
# or inspect config directly:
|
||||
cat ~/.openclaw/openclaw.json | jq '.plugins.slots.contextEngine'
|
||||
```
|
||||
|
||||
### Installing a context engine plugin
|
||||
|
||||
Context engine plugins are installed like any other OpenClaw plugin. Install
|
||||
first, then select the engine in the slot:
|
||||
|
||||
```bash
|
||||
# Install from npm
|
||||
openclaw plugins install @martian-engineering/lossless-claw
|
||||
|
||||
# Or install from a local path (for development)
|
||||
openclaw plugins install -l ./my-context-engine
|
||||
```
|
||||
|
||||
Then enable the plugin and select it as the active engine in your config:
|
||||
|
||||
```json5
|
||||
// openclaw.json
|
||||
{
|
||||
plugins: {
|
||||
slots: {
|
||||
contextEngine: "lossless-claw", // must match the plugin's registered engine id
|
||||
},
|
||||
entries: {
|
||||
"lossless-claw": {
|
||||
enabled: true,
|
||||
// Plugin-specific config goes here (see the plugin's docs)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Restart the gateway after installing and configuring.
|
||||
|
||||
To switch back to the built-in engine, set `contextEngine` to `"legacy"` (or
|
||||
remove the key entirely — `"legacy"` is the default).
|
||||
|
||||
## How it works
|
||||
|
||||
Every time OpenClaw runs a model prompt, the context engine participates at
|
||||
four lifecycle points:
|
||||
|
||||
1. **Ingest** — called when a new message is added to the session. The engine
|
||||
can store or index the message in its own data store.
|
||||
2. **Assemble** — called before each model run. The engine returns an ordered
|
||||
set of messages (and an optional `systemPromptAddition`) that fit within
|
||||
the token budget.
|
||||
3. **Compact** — called when the context window is full, or when the user runs
|
||||
`/compact`. The engine summarizes older history to free space.
|
||||
4. **After turn** — called after a run completes. The engine can persist state,
|
||||
trigger background compaction, or update indexes.
|
||||
|
||||
### Subagent lifecycle (optional)
|
||||
|
||||
OpenClaw currently calls one subagent lifecycle hook:
|
||||
|
||||
- **onSubagentEnded** — clean up when a subagent session completes or is swept.
|
||||
|
||||
The `prepareSubagentSpawn` hook is part of the interface for future use, but
|
||||
the runtime does not invoke it yet.
|
||||
|
||||
### System prompt addition
|
||||
|
||||
The `assemble` method can return a `systemPromptAddition` string. OpenClaw
|
||||
prepends this to the system prompt for the run. This lets engines inject
|
||||
dynamic recall guidance, retrieval instructions, or context-aware hints
|
||||
without requiring static workspace files.
|
||||
|
||||
## The legacy engine
|
||||
|
||||
The built-in `legacy` engine preserves OpenClaw's original behavior:
|
||||
|
||||
- **Ingest**: no-op (the session manager handles message persistence directly).
|
||||
- **Assemble**: pass-through (the existing sanitize → validate → limit pipeline
|
||||
in the runtime handles context assembly).
|
||||
- **Compact**: delegates to the built-in summarization compaction, which creates
|
||||
a single summary of older messages and keeps recent messages intact.
|
||||
- **After turn**: no-op.
|
||||
|
||||
The legacy engine does not register tools or provide a `systemPromptAddition`.
|
||||
|
||||
When no `plugins.slots.contextEngine` is set (or it's set to `"legacy"`), this
|
||||
engine is used automatically.
|
||||
|
||||
## Plugin engines
|
||||
|
||||
A plugin can register a context engine using the plugin API:
|
||||
|
||||
```ts
|
||||
export default function register(api) {
|
||||
api.registerContextEngine("my-engine", () => ({
|
||||
info: {
|
||||
id: "my-engine",
|
||||
name: "My Context Engine",
|
||||
ownsCompaction: true,
|
||||
},
|
||||
|
||||
async ingest({ sessionId, message, isHeartbeat }) {
|
||||
// Store the message in your data store
|
||||
return { ingested: true };
|
||||
},
|
||||
|
||||
async assemble({ sessionId, messages, tokenBudget }) {
|
||||
// Return messages that fit the budget
|
||||
return {
|
||||
messages: buildContext(messages, tokenBudget),
|
||||
estimatedTokens: countTokens(messages),
|
||||
systemPromptAddition: "Use lcm_grep to search history...",
|
||||
};
|
||||
},
|
||||
|
||||
async compact({ sessionId, force }) {
|
||||
// Summarize older context
|
||||
return { ok: true, compacted: true };
|
||||
},
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
Then enable it in config:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
slots: {
|
||||
contextEngine: "my-engine",
|
||||
},
|
||||
entries: {
|
||||
"my-engine": {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### The ContextEngine interface
|
||||
|
||||
Required members:
|
||||
|
||||
| Member | Kind | Purpose |
|
||||
| ------------------ | -------- | -------------------------------------------------------- |
|
||||
| `info` | Property | Engine id, name, version, and whether it owns compaction |
|
||||
| `ingest(params)` | Method | Store a single message |
|
||||
| `assemble(params)` | Method | Build context for a model run (returns `AssembleResult`) |
|
||||
| `compact(params)` | Method | Summarize/reduce context |
|
||||
|
||||
`assemble` returns an `AssembleResult` with:
|
||||
|
||||
- `messages` — the ordered messages to send to the model.
|
||||
- `estimatedTokens` (required, `number`) — the engine's estimate of total
|
||||
tokens in the assembled context. OpenClaw uses this for compaction threshold
|
||||
decisions and diagnostic reporting.
|
||||
- `systemPromptAddition` (optional, `string`) — prepended to the system prompt.
|
||||
|
||||
Optional members:
|
||||
|
||||
| Member | Kind | Purpose |
|
||||
| ------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------- |
|
||||
| `bootstrap(params)` | Method | Initialize engine state for a session. Called once when the engine first sees a session (e.g., import history). |
|
||||
| `ingestBatch(params)` | Method | Ingest a completed turn as a batch. Called after a run completes, with all messages from that turn at once. |
|
||||
| `afterTurn(params)` | Method | Post-run lifecycle work (persist state, trigger background compaction). |
|
||||
| `prepareSubagentSpawn(params)` | Method | Set up shared state for a child session. |
|
||||
| `onSubagentEnded(params)` | Method | Clean up after a subagent ends. |
|
||||
| `dispose()` | Method | Release resources. Called during gateway shutdown or plugin reload — not per-session. |
|
||||
|
||||
### ownsCompaction
|
||||
|
||||
When `info.ownsCompaction` is `true`, the engine manages its own compaction
|
||||
lifecycle. OpenClaw will not trigger the built-in auto-compaction; instead it
|
||||
delegates entirely to the engine's `compact()` method. The engine may also
|
||||
run compaction proactively in `afterTurn()`.
|
||||
|
||||
When `false` or unset, OpenClaw's built-in auto-compaction logic runs
|
||||
alongside the engine.
|
||||
|
||||
## Configuration reference
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
slots: {
|
||||
// Select the active context engine. Default: "legacy".
|
||||
// Set to a plugin id to use a plugin engine.
|
||||
contextEngine: "legacy",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The slot is exclusive at run time — only one registered context engine is
|
||||
resolved for a given run or compaction operation. Other enabled
|
||||
`kind: "context-engine"` plugins can still load and run their registration
|
||||
code; `plugins.slots.contextEngine` only selects which registered engine id
|
||||
OpenClaw resolves when it needs a context engine.
|
||||
|
||||
## Relationship to compaction and memory
|
||||
|
||||
- **Compaction** is one responsibility of the context engine. The legacy engine
|
||||
delegates to OpenClaw's built-in summarization. Plugin engines can implement
|
||||
any compaction strategy (DAG summaries, vector retrieval, etc.).
|
||||
- **Memory plugins** (`plugins.slots.memory`) are separate from context engines.
|
||||
Memory plugins provide search/retrieval; context engines control what the
|
||||
model sees. They can work together — a context engine might use memory
|
||||
plugin data during assembly.
|
||||
- **Session pruning** (trimming old tool results in-memory) still runs
|
||||
regardless of which context engine is active.
|
||||
|
||||
## Tips
|
||||
|
||||
- Use `openclaw doctor` to verify your engine is loading correctly.
|
||||
- If switching engines, existing sessions continue with their current history.
|
||||
The new engine takes over for future runs.
|
||||
- Engine errors are logged and surfaced in diagnostics. If a plugin engine
|
||||
fails to register or the selected engine id cannot be resolved, OpenClaw
|
||||
does not fall back automatically; runs fail until you fix the plugin or
|
||||
switch `plugins.slots.contextEngine` back to `"legacy"`.
|
||||
- For development, use `openclaw plugins install -l ./my-engine` to link a
|
||||
local plugin directory without copying.
|
||||
|
||||
See also: [Compaction](/concepts/compaction), [Context](/concepts/context),
|
||||
[Plugins](/tools/plugin), [Plugin manifest](/plugins/manifest).
|
||||
@ -157,7 +157,8 @@ By default, OpenClaw uses the built-in `legacy` context engine for assembly and
|
||||
compaction. If you install a plugin that provides `kind: "context-engine"` and
|
||||
select it with `plugins.slots.contextEngine`, OpenClaw delegates context
|
||||
assembly, `/compact`, and related subagent context lifecycle hooks to that
|
||||
engine instead.
|
||||
engine instead. See [Context Engine](/concepts/context-engine) for the full
|
||||
pluggable interface, lifecycle hooks, and configuration.
|
||||
|
||||
## What `/context` actually reports
|
||||
|
||||
|
||||
@ -32,6 +32,10 @@ For model selection rules, see [/concepts/models](/concepts/models).
|
||||
`supportsXHighThinking`, `resolveDefaultThinkingLevel`,
|
||||
`isModernModelRef`, `prepareRuntimeAuth`, `resolveUsageAuth`, and
|
||||
`fetchUsageSnapshot`.
|
||||
- Note: provider runtime `capabilities` is shared runner metadata (provider
|
||||
family, transcript/tooling quirks, transport/cache hints). It is not the
|
||||
same as the [public capability model](/tools/plugin#public-capability-model)
|
||||
which describes what a plugin registers (text inference, speech, etc.).
|
||||
|
||||
## Plugin-owned provider behavior
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@ Related:
|
||||
|
||||
- `agents.defaults.models` is the allowlist/catalog of models OpenClaw can use (plus aliases).
|
||||
- `agents.defaults.imageModel` is used **only when** the primary model can’t accept images.
|
||||
- `agents.defaults.imageGenerationModel` is used by the shared image-generation capability. If omitted, `image_generate` can still infer a provider default from compatible auth-backed image-generation plugins.
|
||||
- Per-agent defaults can override `agents.defaults.model` via `agents.list[].model` plus bindings (see [/concepts/multi-agent](/concepts/multi-agent)).
|
||||
|
||||
## Quick model policy
|
||||
@ -34,9 +35,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 don’t want to hand-edit config, run the setup wizard:
|
||||
If you don’t want to hand-edit config, run onboarding:
|
||||
|
||||
```bash
|
||||
openclaw onboard
|
||||
@ -49,6 +50,7 @@ subscription** (OAuth) and **Anthropic** (API key or `claude setup-token`).
|
||||
|
||||
- `agents.defaults.model.primary` and `agents.defaults.model.fallbacks`
|
||||
- `agents.defaults.imageModel.primary` and `agents.defaults.imageModel.fallbacks`
|
||||
- `agents.defaults.imageGenerationModel.primary` and `agents.defaults.imageGenerationModel.fallbacks`
|
||||
- `agents.defaults.models` (allowlist + aliases + provider params)
|
||||
- `models.providers` (custom providers written into `models.json`)
|
||||
|
||||
|
||||
@ -59,6 +59,10 @@
|
||||
"source": "/compaction",
|
||||
"destination": "/concepts/compaction"
|
||||
},
|
||||
{
|
||||
"source": "/context-engine",
|
||||
"destination": "/concepts/context-engine"
|
||||
},
|
||||
{
|
||||
"source": "/cron",
|
||||
"destination": "/cron-jobs"
|
||||
@ -952,6 +956,7 @@
|
||||
"concepts/agent-loop",
|
||||
"concepts/system-prompt",
|
||||
"concepts/context",
|
||||
"concepts/context-engine",
|
||||
"concepts/agent-workspace",
|
||||
"concepts/oauth"
|
||||
]
|
||||
|
||||
@ -49,7 +49,7 @@ openclaw models status
|
||||
openclaw doctor
|
||||
```
|
||||
|
||||
If you’d rather not manage env vars yourself, the setup wizard can store
|
||||
If you’d 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`,
|
||||
|
||||
@ -434,7 +434,7 @@ Save to `~/.openclaw/openclaw.json` and you can DM the bot from that number.
|
||||
nodeManager: "npm",
|
||||
},
|
||||
entries: {
|
||||
"nano-banana-pro": {
|
||||
"image-lab": {
|
||||
enabled: true,
|
||||
apiKey: "GEMINI_KEY_HERE",
|
||||
env: { GEMINI_API_KEY: "GEMINI_KEY_HERE" },
|
||||
|
||||
@ -875,6 +875,10 @@ Time format in system prompt. Default: `auto` (OS preference).
|
||||
primary: "openrouter/qwen/qwen-2.5-vl-72b-instruct:free",
|
||||
fallbacks: ["openrouter/google/gemini-2.0-flash-vision:free"],
|
||||
},
|
||||
imageGenerationModel: {
|
||||
primary: "openai/gpt-image-1",
|
||||
fallbacks: ["google/gemini-3.1-flash-image-preview"],
|
||||
},
|
||||
pdfModel: {
|
||||
primary: "anthropic/claude-opus-4-6",
|
||||
fallbacks: ["openai/gpt-5-mini"],
|
||||
@ -899,6 +903,9 @@ Time format in system prompt. Default: `auto` (OS preference).
|
||||
- `imageModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
||||
- Used by the `image` tool path as its vision-model config.
|
||||
- Also used as fallback routing when the selected/default model cannot accept image input.
|
||||
- `imageGenerationModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
||||
- Used by the shared image-generation capability and any future tool/plugin surface that generates images.
|
||||
- If omitted, `image_generate` can still infer a best-effort provider default from compatible auth-backed image-generation providers.
|
||||
- `pdfModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
||||
- Used by the `pdf` tool for model routing.
|
||||
- If omitted, the PDF tool falls back to `imageModel`, then to best-effort provider defaults.
|
||||
@ -2365,7 +2372,7 @@ See [Local Models](/gateway/local-models). TL;DR: run MiniMax M2.5 via LM Studio
|
||||
nodeManager: "npm", // npm | pnpm | yarn
|
||||
},
|
||||
entries: {
|
||||
"nano-banana-pro": {
|
||||
"image-lab": {
|
||||
apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" }, // or plaintext string
|
||||
env: { GEMINI_API_KEY: "GEMINI_KEY_HERE" },
|
||||
},
|
||||
@ -2413,6 +2420,8 @@ See [Local Models](/gateway/local-models). TL;DR: run MiniMax M2.5 via LM Studio
|
||||
- `plugins.entries.<id>.apiKey`: plugin-level API key convenience field (when supported by the plugin).
|
||||
- `plugins.entries.<id>.env`: plugin-scoped env var map.
|
||||
- `plugins.entries.<id>.hooks.allowPromptInjection`: when `false`, core blocks `before_prompt_build` and ignores prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride`. Applies to native plugin hooks and supported bundle-provided hook directories.
|
||||
- `plugins.entries.<id>.subagent.allowModelOverride`: explicitly trust this plugin to request per-run `provider` and `model` overrides for background subagent runs.
|
||||
- `plugins.entries.<id>.subagent.allowedModels`: optional allowlist of canonical `provider/model` targets for trusted subagent overrides. Use `"*"` only when you intentionally want to allow any model.
|
||||
- `plugins.entries.<id>.config`: plugin-defined config object (validated by native OpenClaw plugin schema when available).
|
||||
- Enabled Claude bundle plugins can also contribute embedded Pi defaults from `settings.json`; OpenClaw applies those as sanitized agent settings, not as raw OpenClaw config patches.
|
||||
- `plugins.slots.memory`: pick the active memory plugin id, or `"none"` to disable memory plugins.
|
||||
@ -2606,6 +2615,8 @@ See [Plugins](/tools/plugin).
|
||||
- `gateway.http.endpoints.responses.maxUrlParts`
|
||||
- `gateway.http.endpoints.responses.files.urlAllowlist`
|
||||
- `gateway.http.endpoints.responses.images.urlAllowlist`
|
||||
Empty allowlists are treated as unset; use `gateway.http.endpoints.responses.files.allowUrl=false`
|
||||
and/or `gateway.http.endpoints.responses.images.allowUrl=false` to disable URL fetching.
|
||||
- Optional response hardening header:
|
||||
- `gateway.http.securityHeaders.strictTransportSecurity` (set only for HTTPS origins you control; see [Trusted Proxy Auth](/gateway/trusted-proxy-auth#tls-termination-and-hsts))
|
||||
|
||||
@ -2950,7 +2961,7 @@ Notes:
|
||||
|
||||
## Wizard
|
||||
|
||||
Metadata written by CLI wizards (`onboard`, `configure`, `doctor`):
|
||||
Metadata written by CLI guided setup flows (`onboard`, `configure`, `doctor`):
|
||||
|
||||
```json5
|
||||
{
|
||||
|
||||
@ -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>
|
||||
@ -597,11 +597,11 @@ Rules:
|
||||
},
|
||||
skills: {
|
||||
entries: {
|
||||
"nano-banana-pro": {
|
||||
"image-lab": {
|
||||
apiKey: {
|
||||
source: "file",
|
||||
provider: "filemain",
|
||||
id: "/skills/entries/nano-banana-pro/apiKey",
|
||||
id: "/skills/entries/image-lab/apiKey",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -144,6 +144,8 @@ URL fetch defaults:
|
||||
- Optional hostname allowlists are supported per input type (`files.urlAllowlist`, `images.urlAllowlist`).
|
||||
- Exact host: `"cdn.example.com"`
|
||||
- Wildcard subdomains: `"*.assets.example.com"` (does not match apex)
|
||||
- Empty or omitted allowlists mean no hostname allowlist restriction.
|
||||
- To disable URL-based fetches entirely, set `files.allowUrl: false` and/or `images.allowUrl: false`.
|
||||
|
||||
## File + image limits (config)
|
||||
|
||||
|
||||
@ -243,7 +243,10 @@ High-signal `checkId` values you will most likely see in real deployments (not e
|
||||
| `gateway.real_ip_fallback_enabled` | warn/critical | Trusting `X-Real-IP` fallback can enable source-IP spoofing via proxy misconfig | `gateway.allowRealIpFallback`, `gateway.trustedProxies` | no |
|
||||
| `discovery.mdns_full_mode` | warn/critical | mDNS full mode advertises `cliPath`/`sshPort` metadata on local network | `discovery.mdns.mode`, `gateway.bind` | no |
|
||||
| `config.insecure_or_dangerous_flags` | warn | Any insecure/dangerous debug flags enabled | multiple keys (see finding detail) | no |
|
||||
| `hooks.token_reuse_gateway_token` | critical | Hook ingress token also unlocks Gateway auth | `hooks.token`, `gateway.auth.token` | no |
|
||||
| `hooks.token_too_short` | warn | Easier brute force on hook ingress | `hooks.token` | no |
|
||||
| `hooks.default_session_key_unset` | warn | Hook agent runs fan out into generated per-request sessions | `hooks.defaultSessionKey` | no |
|
||||
| `hooks.allowed_agent_ids_unrestricted` | warn/critical | Authenticated hook callers may route to any configured agent | `hooks.allowedAgentIds` | no |
|
||||
| `hooks.request_session_key_enabled` | warn/critical | External caller can choose sessionKey | `hooks.allowRequestSessionKey` | no |
|
||||
| `hooks.request_session_key_prefixes_missing` | warn/critical | No bound on external session key shapes | `hooks.allowedSessionKeyPrefixes` | no |
|
||||
| `logging.redact_off` | warn | Sensitive values leak to logs/status | `logging.redactSensitive` | yes |
|
||||
@ -355,6 +358,7 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
- If the gateway itself terminates HTTPS, you can set `gateway.http.securityHeaders.strictTransportSecurity` to emit the HSTS header from OpenClaw responses.
|
||||
- Detailed deployment guidance is in [Trusted Proxy Auth](/gateway/trusted-proxy-auth#tls-termination-and-hsts).
|
||||
- For non-loopback Control UI deployments, `gateway.controlUi.allowedOrigins` is required by default.
|
||||
- `gateway.controlUi.allowedOrigins: ["*"]` is an explicit allow-all browser-origin policy, not a hardened default. Avoid it outside tightly controlled local testing.
|
||||
- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` enables Host-header origin fallback mode; treat it as a dangerous operator-selected policy.
|
||||
- Treat DNS rebinding and proxy-host header behavior as deployment hardening concerns; keep `trustedProxies` tight and avoid exposing the gateway directly to the public internet.
|
||||
|
||||
@ -568,6 +572,8 @@ tool calls. Reduce the blast radius by:
|
||||
- For OpenResponses URL inputs (`input_file` / `input_image`), set tight
|
||||
`gateway.http.endpoints.responses.files.urlAllowlist` and
|
||||
`gateway.http.endpoints.responses.images.urlAllowlist`, and keep `maxUrlParts` low.
|
||||
Empty allowlists are treated as unset; use `files.allowUrl: false` / `images.allowUrl: false`
|
||||
if you want to disable URL fetching entirely.
|
||||
- Enabling sandboxing and strict tool allowlists for any agent that touches untrusted input.
|
||||
- Keeping secrets out of prompts; pass them via env/config on the gateway host instead.
|
||||
|
||||
@ -738,7 +744,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 (fail‑closed).
|
||||
|
||||
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:
|
||||
|
||||
@ -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).
|
||||
|
||||
|
||||
@ -360,9 +360,33 @@ If you want to rely on env keys (e.g. exported in your `~/.profile`), run local
|
||||
- Enable: `BYTEPLUS_API_KEY=... BYTEPLUS_LIVE_TEST=1 pnpm test:live src/agents/byteplus.live.test.ts`
|
||||
- Optional model override: `BYTEPLUS_CODING_MODEL=ark-code-latest`
|
||||
|
||||
## Image generation live
|
||||
|
||||
- Test: `src/image-generation/runtime.live.test.ts`
|
||||
- Command: `pnpm test:live src/image-generation/runtime.live.test.ts`
|
||||
- Scope:
|
||||
- Enumerates every registered image-generation provider plugin
|
||||
- Loads missing provider env vars from your login shell (`~/.profile`) before probing
|
||||
- Uses live/env API keys ahead of stored auth profiles by default, so stale test keys in `auth-profiles.json` do not mask real shell credentials
|
||||
- Skips providers with no usable auth/profile/model
|
||||
- Runs the stock image-generation variants through the shared runtime capability:
|
||||
- `google:flash-generate`
|
||||
- `google:pro-generate`
|
||||
- `google:pro-edit`
|
||||
- `openai:default-generate`
|
||||
- Current bundled providers covered:
|
||||
- `openai`
|
||||
- `google`
|
||||
- Optional narrowing:
|
||||
- `OPENCLAW_LIVE_IMAGE_GENERATION_PROVIDERS="openai,google"`
|
||||
- `OPENCLAW_LIVE_IMAGE_GENERATION_MODELS="openai/gpt-image-1,google/gemini-3.1-flash-image-preview"`
|
||||
- `OPENCLAW_LIVE_IMAGE_GENERATION_CASES="google:flash-generate,google:pro-edit"`
|
||||
- Optional auth behavior:
|
||||
- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` to force profile-store auth and ignore env-only overrides
|
||||
|
||||
## 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 +397,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 +411,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
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -22,7 +22,7 @@ curl -fsSL https://openclaw.ai/install.sh | bash
|
||||
|
||||
Notes:
|
||||
|
||||
- Add `--no-onboard` if you don’t want the setup wizard to run again.
|
||||
- Add `--no-onboard` if you don’t want onboarding to run again.
|
||||
- For **source installs**, use:
|
||||
|
||||
```bash
|
||||
|
||||
@ -10,6 +10,10 @@ title: "Media Understanding"
|
||||
|
||||
OpenClaw can **summarize inbound media** (image/audio/video) before the reply pipeline runs. It auto‑detects 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: pre‑digest 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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 deep‑merges 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
|
||||
|
||||
@ -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).
|
||||
|
||||
@ -213,7 +213,33 @@ Notes:
|
||||
|
||||
Related docs: [Plugins](/tools/plugin), [Channels](/channels/index), [Configuration](/gateway/configuration).
|
||||
|
||||
## Implemented channel-owned seams
|
||||
## Capability plan alignment
|
||||
|
||||
The plugin SDK refactor now aligns with the public capability model documented
|
||||
in [Plugins](/tools/plugin#public-capability-model).
|
||||
|
||||
Key decisions:
|
||||
|
||||
- Capabilities are the public plugin model. Registration is explicit and typed.
|
||||
- Legacy hook-only plugins remain supported without migration.
|
||||
- Plugin shapes (plain-capability, hybrid-capability, hook-only, non-capability)
|
||||
are classified from actual registration behavior.
|
||||
- `openclaw plugins inspect` provides canonical deep introspection for any
|
||||
loaded plugin, showing shape, capabilities, hooks, tools, and diagnostics.
|
||||
- Export boundary: export capabilities, not implementation convenience. Trim
|
||||
non-contract helper exports.
|
||||
|
||||
Required test matrix for the capability model:
|
||||
|
||||
- hook-only legacy plugin fixture
|
||||
- plain capability plugin fixture
|
||||
- hybrid capability plugin fixture
|
||||
- real-world legacy hook-style plugin fixture
|
||||
- `before_agent_start` still works
|
||||
- typed hooks remain additive
|
||||
- capability usage and plugin shape are inspectable
|
||||
|
||||
## Implemented channel-owned capabilities
|
||||
|
||||
Recent refactor work widened the channel plugin contract so core can stop owning
|
||||
channel-specific UX and routing behavior:
|
||||
@ -234,5 +260,5 @@ channel-specific UX and routing behavior:
|
||||
config mutation/removal
|
||||
- `allowlist.supportsScope`: channel-owned allowlist scope advertisement
|
||||
|
||||
These hooks should be preferred over new `channel === "discord"` / `telegram`
|
||||
branches in shared core flows.
|
||||
These capabilities should be preferred over new `channel === "discord"` /
|
||||
`telegram` branches in shared core flows.
|
||||
|
||||
@ -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 re‑implementing 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)
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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).
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
112
docs/tools/capability-cookbook.md
Normal file
112
docs/tools/capability-cookbook.md
Normal file
@ -0,0 +1,112 @@
|
||||
---
|
||||
summary: "Cookbook for adding a new shared capability to OpenClaw"
|
||||
read_when:
|
||||
- Adding a new core capability and plugin seam
|
||||
- Deciding whether code belongs in core, a vendor plugin, or a feature plugin
|
||||
- Wiring a new runtime helper for channels or tools
|
||||
title: "Capability Cookbook"
|
||||
---
|
||||
|
||||
# Capability Cookbook
|
||||
|
||||
Use this when OpenClaw needs a new domain such as image generation, video
|
||||
generation, or some future vendor-backed feature area.
|
||||
|
||||
The rule:
|
||||
|
||||
- plugin = ownership boundary
|
||||
- capability = shared core contract
|
||||
|
||||
That means you should not start by wiring a vendor directly into a channel or a
|
||||
tool. Start by defining the capability.
|
||||
|
||||
## When to create a capability
|
||||
|
||||
Create a new capability when all of these are true:
|
||||
|
||||
1. more than one vendor could plausibly implement it
|
||||
2. channels, tools, or feature plugins should consume it without caring about
|
||||
the vendor
|
||||
3. core needs to own fallback, policy, config, or delivery behavior
|
||||
|
||||
If the work is vendor-only and no shared contract exists yet, stop and define
|
||||
the contract first.
|
||||
|
||||
## The standard sequence
|
||||
|
||||
1. Define the typed core contract.
|
||||
2. Add plugin registration for that contract.
|
||||
3. Add a shared runtime helper.
|
||||
4. Wire one real vendor plugin as proof.
|
||||
5. Move feature/channel consumers onto the runtime helper.
|
||||
6. Add contract tests.
|
||||
7. Document the operator-facing config and ownership model.
|
||||
|
||||
## What goes where
|
||||
|
||||
Core:
|
||||
|
||||
- request/response types
|
||||
- provider registry + resolution
|
||||
- fallback behavior
|
||||
- config schema and labels/help
|
||||
- runtime helper surface
|
||||
|
||||
Vendor plugin:
|
||||
|
||||
- vendor API calls
|
||||
- vendor auth handling
|
||||
- vendor-specific request normalization
|
||||
- registration of the capability implementation
|
||||
|
||||
Feature/channel plugin:
|
||||
|
||||
- calls `api.runtime.*` or the matching `plugin-sdk/*-runtime` helper
|
||||
- never calls a vendor implementation directly
|
||||
|
||||
## File checklist
|
||||
|
||||
For a new capability, expect to touch these areas:
|
||||
|
||||
- `src/<capability>/types.ts`
|
||||
- `src/<capability>/...registry/runtime.ts`
|
||||
- `src/plugins/types.ts`
|
||||
- `src/plugins/registry.ts`
|
||||
- `src/plugins/captured-registration.ts`
|
||||
- `src/plugins/contracts/registry.ts`
|
||||
- `src/plugins/runtime/types-core.ts`
|
||||
- `src/plugins/runtime/index.ts`
|
||||
- `src/plugin-sdk/<capability>.ts`
|
||||
- `src/plugin-sdk/<capability>-runtime.ts`
|
||||
- one or more `extensions/<vendor>/...`
|
||||
- config/docs/tests
|
||||
|
||||
## Example: image generation
|
||||
|
||||
Image generation follows the standard shape:
|
||||
|
||||
1. core defines `ImageGenerationProvider`
|
||||
2. core exposes `registerImageGenerationProvider(...)`
|
||||
3. core exposes `runtime.imageGeneration.generate(...)`
|
||||
4. the `openai` and `google` plugins register vendor-backed implementations
|
||||
5. future vendors can register the same contract without changing channels/tools
|
||||
|
||||
The config key is separate from vision-analysis routing:
|
||||
|
||||
- `agents.defaults.imageModel` = analyze images
|
||||
- `agents.defaults.imageGenerationModel` = generate images
|
||||
|
||||
Keep those separate so fallback and policy remain explicit.
|
||||
|
||||
## Review checklist
|
||||
|
||||
Before shipping a new capability, verify:
|
||||
|
||||
- no channel/tool imports vendor code directly
|
||||
- the runtime helper is the shared path
|
||||
- at least one contract test asserts bundled ownership
|
||||
- config docs name the new model/config key
|
||||
- plugin docs explain the ownership boundary
|
||||
|
||||
If a PR skips the capability layer and hardcodes vendor behavior into a
|
||||
channel/tool, send it back and define the contract first.
|
||||
@ -400,6 +400,31 @@ Notes:
|
||||
- Only available when `agents.defaults.imageModel` is configured (primary or fallbacks), or when an implicit image model can be inferred from your default model + configured auth (best-effort pairing).
|
||||
- Uses the image model directly (independent of the main chat model).
|
||||
|
||||
### `image_generate`
|
||||
|
||||
Generate one or more images with the configured or inferred image-generation model.
|
||||
|
||||
Core parameters:
|
||||
|
||||
- `action` (optional: `generate` or `list`; default `generate`)
|
||||
- `prompt` (required)
|
||||
- `image` or `images` (optional reference image path/URL for edit mode)
|
||||
- `model` (optional provider/model override)
|
||||
- `size` (optional size hint)
|
||||
- `resolution` (optional `1K|2K|4K` hint)
|
||||
- `count` (optional, `1-4`, default `1`)
|
||||
|
||||
Notes:
|
||||
|
||||
- Available when `agents.defaults.imageGenerationModel` is configured, or when OpenClaw can infer a compatible image-generation default from your enabled providers plus available auth.
|
||||
- Explicit `agents.defaults.imageGenerationModel` still wins over any inferred default.
|
||||
- Use `action: "list"` to inspect registered providers, default models, supported model ids, sizes, resolutions, and edit support.
|
||||
- Returns local `MEDIA:<path>` lines so channels can deliver the generated files directly.
|
||||
- Uses the image-generation model directly (independent of the main chat model).
|
||||
- Google-backed flows support reference-image edits plus explicit `1K|2K|4K` resolution hints.
|
||||
- When editing and `resolution` is omitted, OpenClaw infers a draft/final resolution from the input image size.
|
||||
- This is the built-in replacement for the old sample `nano-banana-pro` skill workflow. Use `agents.defaults.imageGenerationModel`, not `skills.entries`, for stock image generation.
|
||||
|
||||
### `pdf`
|
||||
|
||||
Analyze one or more PDF documents.
|
||||
|
||||
@ -69,6 +69,97 @@ OpenClaw resolves known Claude marketplace names from
|
||||
`~/.claude/plugins/known_marketplaces.json`. You can also pass an explicit
|
||||
marketplace source with `--marketplace`.
|
||||
|
||||
## Conversation binding callbacks
|
||||
|
||||
Plugins that bind a conversation can now react when an approval is resolved.
|
||||
|
||||
Use `api.onConversationBindingResolved(...)` to receive a callback after a bind
|
||||
request is approved or denied:
|
||||
|
||||
```ts
|
||||
export default {
|
||||
id: "my-plugin",
|
||||
register(api) {
|
||||
api.onConversationBindingResolved(async (event) => {
|
||||
if (event.status === "approved") {
|
||||
// A binding now exists for this plugin + conversation.
|
||||
console.log(event.binding?.conversationId);
|
||||
return;
|
||||
}
|
||||
|
||||
// The request was denied; clear any local pending state.
|
||||
console.log(event.request.conversation.conversationId);
|
||||
});
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Callback payload fields:
|
||||
|
||||
- `status`: `"approved"` or `"denied"`
|
||||
- `decision`: `"allow-once"`, `"allow-always"`, or `"deny"`
|
||||
- `binding`: the resolved binding for approved requests
|
||||
- `request`: the original request summary, detach hint, sender id, and
|
||||
conversation metadata
|
||||
|
||||
This callback is notification-only. It does not change who is allowed to bind a
|
||||
conversation, and it runs after core approval handling finishes.
|
||||
|
||||
## Public capability model
|
||||
|
||||
Capabilities are the public plugin model. Every native OpenClaw plugin
|
||||
registers against one or more capability types:
|
||||
|
||||
| Capability | Registration method | Example plugins |
|
||||
|---|---|---|
|
||||
| Text inference | `api.registerProvider(...)` | `openai`, `anthropic` |
|
||||
| Speech | `api.registerSpeechProvider(...)` | `elevenlabs`, `microsoft` |
|
||||
| Media understanding | `api.registerMediaUnderstandingProvider(...)` | `openai`, `google` |
|
||||
| Image generation | `api.registerImageGenerationProvider(...)` | `openai`, `google` |
|
||||
| Web search | `api.registerWebSearchProvider(...)` | `google` |
|
||||
| Channel / messaging | `api.registerChannel(...)` | `msteams`, `matrix` |
|
||||
|
||||
A plugin that registers zero capabilities but provides hooks, tools, or
|
||||
services is a **legacy hook-only** plugin. That shape is still fully supported.
|
||||
|
||||
### Plugin shapes
|
||||
|
||||
OpenClaw classifies every loaded plugin into a shape based on its actual
|
||||
registration behavior (not just static metadata):
|
||||
|
||||
- **plain-capability** — registers exactly one capability type (for example a
|
||||
provider-only plugin like `mistral`)
|
||||
- **hybrid-capability** — registers multiple capability types (for example
|
||||
`openai` owns text inference, speech, media understanding, and image
|
||||
generation)
|
||||
- **hook-only** — registers only hooks (typed or custom), no capabilities,
|
||||
tools, commands, or services
|
||||
- **non-capability** — registers tools, commands, services, or routes but no
|
||||
capabilities
|
||||
|
||||
Use `openclaw plugins inspect <id>` to see a plugin's shape and capability
|
||||
breakdown. See [CLI reference](/cli/plugins#inspect) for details.
|
||||
|
||||
### Capability labels
|
||||
|
||||
Plugin capabilities use two stability labels:
|
||||
|
||||
- `public` — stable, documented, and safe to depend on
|
||||
- `experimental` — may change between releases
|
||||
|
||||
### Legacy hooks
|
||||
|
||||
The `before_agent_start` hook remains supported as a compatibility path for
|
||||
hook-only plugins. Legacy real-world plugins still depend on it.
|
||||
|
||||
Direction:
|
||||
|
||||
- keep it working
|
||||
- document it as legacy
|
||||
- prefer `before_model_resolve` for model/provider override work
|
||||
- prefer `before_prompt_build` for prompt mutation work
|
||||
- remove only after real usage drops and fixture coverage proves migration safety
|
||||
|
||||
## Architecture
|
||||
|
||||
OpenClaw's plugin system has four layers:
|
||||
@ -97,6 +188,171 @@ 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 + image-generation behavior
|
||||
- the bundled `elevenlabs` plugin owns ElevenLabs speech behavior
|
||||
- the bundled `microsoft` plugin owns Microsoft speech behavior
|
||||
- the bundled `google` plugin owns Google model-provider behavior plus Google
|
||||
media-understanding + image-generation + web-search behavior
|
||||
- the bundled `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.
|
||||
|
||||
### Multi-capability company plugin example
|
||||
|
||||
A company plugin should feel cohesive from the outside. If OpenClaw has shared
|
||||
contracts for models, speech, media understanding, and web search, a vendor can
|
||||
own all of its surfaces in one place:
|
||||
|
||||
```ts
|
||||
import type { OpenClawPluginDefinition } from "openclaw/plugin-sdk";
|
||||
import {
|
||||
buildOpenAISpeechProvider,
|
||||
createPluginBackedWebSearchProvider,
|
||||
describeImageWithModel,
|
||||
transcribeOpenAiCompatibleAudio,
|
||||
} from "openclaw/plugin-sdk";
|
||||
|
||||
const plugin: OpenClawPluginDefinition = {
|
||||
id: "exampleai",
|
||||
name: "ExampleAI",
|
||||
register(api) {
|
||||
api.registerProvider({
|
||||
id: "exampleai",
|
||||
// auth/model catalog/runtime hooks
|
||||
});
|
||||
|
||||
api.registerSpeechProvider(
|
||||
buildOpenAISpeechProvider({
|
||||
id: "exampleai",
|
||||
// vendor speech config
|
||||
}),
|
||||
);
|
||||
|
||||
api.registerMediaUnderstandingProvider({
|
||||
id: "exampleai",
|
||||
capabilities: ["image", "audio", "video"],
|
||||
async describeImage(req) {
|
||||
return describeImageWithModel({
|
||||
provider: "exampleai",
|
||||
model: req.model,
|
||||
input: req.input,
|
||||
});
|
||||
},
|
||||
async transcribeAudio(req) {
|
||||
return transcribeOpenAiCompatibleAudio({
|
||||
provider: "exampleai",
|
||||
model: req.model,
|
||||
input: req.input,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
api.registerWebSearchProvider(
|
||||
createPluginBackedWebSearchProvider({
|
||||
id: "exampleai-search",
|
||||
// credential + fetch logic
|
||||
}),
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default plugin;
|
||||
```
|
||||
|
||||
What matters is not the exact helper names. The shape matters:
|
||||
|
||||
- one plugin owns the vendor surface
|
||||
- core still owns the capability contracts
|
||||
- channels and feature plugins consume `api.runtime.*` helpers, not vendor code
|
||||
- contract tests can assert that the plugin registered the capabilities it
|
||||
claims to own
|
||||
|
||||
### 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.
|
||||
|
||||
Need a concrete rollout checklist? See
|
||||
[Capability Cookbook](/tools/capability-cookbook).
|
||||
|
||||
## Compatible bundles
|
||||
|
||||
OpenClaw also recognizes two compatible external bundle layouts:
|
||||
@ -124,18 +380,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 +454,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)
|
||||
@ -212,16 +475,24 @@ Native OpenClaw plugins are **TypeScript modules** loaded at runtime via jiti.
|
||||
**Config validation does not execute plugin code**; it uses the plugin manifest
|
||||
and JSON Schema instead. See [Plugin manifest](/plugins/manifest).
|
||||
|
||||
Native OpenClaw plugins can register:
|
||||
Native OpenClaw plugins can register capabilities and surfaces:
|
||||
|
||||
- Gateway RPC methods
|
||||
- Gateway HTTP routes
|
||||
**Capabilities** (public plugin model):
|
||||
|
||||
- Text inference providers (model catalogs, auth, runtime hooks)
|
||||
- Speech providers
|
||||
- Media understanding providers
|
||||
- Image generation providers
|
||||
- Web search providers
|
||||
- Channel / messaging connectors
|
||||
|
||||
**Surfaces** (supporting infrastructure):
|
||||
|
||||
- Gateway RPC methods and HTTP routes
|
||||
- Agent tools
|
||||
- CLI commands
|
||||
- Background services
|
||||
- Context engines
|
||||
- Provider auth flows and model catalogs
|
||||
- Provider runtime hooks for dynamic model ids, transport normalization, capability metadata, stream wrapping, cache TTL policy, missing-auth hints, built-in model suppression, catalog augmentation, runtime auth exchange, and usage/billing auth + snapshot resolution
|
||||
- Optional config validation
|
||||
- **Skills** (by listing `skills` directories in the plugin manifest)
|
||||
- **Auto-reply commands** (execute without invoking the AI agent)
|
||||
@ -229,6 +500,106 @@ Native OpenClaw plugins can register:
|
||||
Native OpenClaw plugins run **in‑process** 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.
|
||||
|
||||
## Export boundary
|
||||
|
||||
OpenClaw exports capabilities, not implementation convenience.
|
||||
|
||||
Keep capability registration public. Trim non-contract helper exports:
|
||||
|
||||
- bundled-plugin-specific helper subpaths
|
||||
- runtime plumbing subpaths not intended as public API
|
||||
- vendor-specific convenience helpers
|
||||
- setup/onboarding helpers that are implementation details
|
||||
|
||||
## Plugin inspection
|
||||
|
||||
Use `openclaw plugins inspect <id>` for deep plugin introspection. This is the
|
||||
canonical command for understanding a plugin's shape and registration behavior.
|
||||
|
||||
```bash
|
||||
openclaw plugins inspect openai
|
||||
openclaw plugins inspect openai --json
|
||||
```
|
||||
|
||||
The inspect report shows:
|
||||
|
||||
- identity, load status, source, and root
|
||||
- plugin shape (plain-capability, hybrid-capability, hook-only, non-capability)
|
||||
- capability mode and registered capabilities
|
||||
- hooks (typed and custom), tools, commands, services
|
||||
- channel registration
|
||||
- config policy flags
|
||||
- diagnostics
|
||||
- whether the plugin uses the legacy `before_agent_start` hook
|
||||
- install metadata
|
||||
|
||||
Classification comes from actual registration behavior, not just static
|
||||
metadata.
|
||||
|
||||
Summary commands remain summary-focused:
|
||||
|
||||
- `plugins list` — compact inventory
|
||||
- `plugins status` — operational summary
|
||||
- `doctor` — issue-focused diagnostics
|
||||
- `plugins inspect` — deep detail
|
||||
|
||||
## Provider runtime hooks
|
||||
|
||||
Provider plugins now have two layers:
|
||||
@ -519,25 +890,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 +996,57 @@ 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.
|
||||
|
||||
Plugins can also launch background subagent runs through `api.runtime.subagent`:
|
||||
|
||||
```ts
|
||||
const result = await api.runtime.subagent.run({
|
||||
sessionKey: "agent:main:subagent:search-helper",
|
||||
message: "Expand this query into focused follow-up searches.",
|
||||
provider: "openai",
|
||||
model: "gpt-4.1-mini",
|
||||
deliver: false,
|
||||
});
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `provider` and `model` are optional per-run overrides, not persistent session changes.
|
||||
- OpenClaw only honors those override fields for trusted callers.
|
||||
- For plugin-owned fallback runs, operators must opt in with `plugins.entries.<id>.subagent.allowModelOverride: true`.
|
||||
- Use `plugins.entries.<id>.subagent.allowedModels` to restrict trusted plugins to specific canonical `provider/model` targets, or `"*"` to allow any target explicitly.
|
||||
- Untrusted plugin subagent runs still work, but override requests are rejected instead of silently falling back.
|
||||
|
||||
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
|
||||
|
||||
@ -587,8 +1085,28 @@ Notes:
|
||||
Use SDK subpaths instead of the monolithic `openclaw/plugin-sdk` import when
|
||||
authoring plugins:
|
||||
|
||||
- `openclaw/plugin-sdk/core` for generic plugin APIs, provider auth types, and shared helpers such as routing/session utilities and logger-backed runtimes.
|
||||
- `openclaw/plugin-sdk/compat` for bundled/internal plugin code that needs broader shared runtime helpers than `core`.
|
||||
- `openclaw/plugin-sdk/core` for the smallest generic plugin-facing contract.
|
||||
- Domain subpaths such as `openclaw/plugin-sdk/channel-config-helpers`,
|
||||
`openclaw/plugin-sdk/channel-config-schema`,
|
||||
`openclaw/plugin-sdk/channel-policy`,
|
||||
`openclaw/plugin-sdk/lazy-runtime`,
|
||||
`openclaw/plugin-sdk/reply-history`,
|
||||
`openclaw/plugin-sdk/routing`,
|
||||
`openclaw/plugin-sdk/runtime-store`, and
|
||||
`openclaw/plugin-sdk/directory-runtime` for shared runtime/config helpers.
|
||||
- `openclaw/plugin-sdk/compat` remains as a legacy migration surface for older
|
||||
external plugins. Bundled plugins should not use it, and non-test imports emit
|
||||
a one-time deprecation warning outside test environments.
|
||||
- Bundled extension internals remain private. External plugins should use only
|
||||
`openclaw/plugin-sdk/*` subpaths. OpenClaw core/test code may use the repo
|
||||
public seams under `extensions/<id>/index.js`, `api.js`, `runtime-api.js`,
|
||||
`setup-entry.js`, and narrowly scoped files such as `login-qr-api.js`. Never
|
||||
import `extensions/<id>/src/*` from core or from another extension.
|
||||
- Repo seam split:
|
||||
`extensions/<id>/api.js` is the helper/types barrel,
|
||||
`extensions/<id>/runtime-api.js` is the runtime-only barrel,
|
||||
`extensions/<id>/index.js` is the bundled plugin entry,
|
||||
and `extensions/<id>/setup-entry.js` is the setup plugin entry.
|
||||
- `openclaw/plugin-sdk/telegram` for Telegram channel plugin types and shared channel-facing helpers. Built-in Telegram implementation internals stay private to the bundled extension.
|
||||
- `openclaw/plugin-sdk/discord` for Discord channel plugin types and shared channel-facing helpers. Built-in Discord implementation internals stay private to the bundled extension.
|
||||
- `openclaw/plugin-sdk/slack` for Slack channel plugin types and shared channel-facing helpers. Built-in Slack implementation internals stay private to the bundled extension.
|
||||
@ -649,8 +1167,8 @@ Compatibility note:
|
||||
|
||||
- `openclaw/plugin-sdk` remains supported for existing external plugins.
|
||||
- New and migrated bundled plugins should use channel or extension-specific
|
||||
subpaths; use `core` for generic surfaces and `compat` only when broader
|
||||
shared helpers are required.
|
||||
subpaths; use `core` plus explicit domain subpaths for generic surfaces, and
|
||||
treat `compat` as migration-only.
|
||||
|
||||
## Read-only channel inspection
|
||||
|
||||
@ -1110,12 +1628,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
|
||||
|
||||
@ -24,7 +24,7 @@ All skills-related configuration lives under `skills` in `~/.openclaw/openclaw.j
|
||||
nodeManager: "npm", // npm | pnpm | yarn | bun (Gateway runtime still Node; bun not recommended)
|
||||
},
|
||||
entries: {
|
||||
"nano-banana-pro": {
|
||||
"image-lab": {
|
||||
enabled: true,
|
||||
apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" }, // or plaintext string
|
||||
env: {
|
||||
@ -38,6 +38,10 @@ All skills-related configuration lives under `skills` in `~/.openclaw/openclaw.j
|
||||
}
|
||||
```
|
||||
|
||||
For built-in image generation/editing, prefer `agents.defaults.imageGenerationModel`
|
||||
plus the core `image_generate` tool. `skills.entries.*` is only for custom or
|
||||
third-party skill workflows.
|
||||
|
||||
## Fields
|
||||
|
||||
- `allowBundled`: optional allowlist for **bundled** skills only. When set, only
|
||||
|
||||
@ -81,8 +81,8 @@ that up as `<workspace>/skills` on the next session.
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: nano-banana-pro
|
||||
description: Generate or edit images via Gemini 3 Pro Image
|
||||
name: image-lab
|
||||
description: Generate or edit images via a provider-backed image workflow
|
||||
---
|
||||
```
|
||||
|
||||
@ -109,8 +109,8 @@ OpenClaw **filters skills at load time** using `metadata` (single-line JSON):
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: nano-banana-pro
|
||||
description: Generate or edit images via Gemini 3 Pro Image
|
||||
name: image-lab
|
||||
description: Generate or edit images via a provider-backed image workflow
|
||||
metadata:
|
||||
{
|
||||
"openclaw":
|
||||
@ -194,7 +194,7 @@ Bundled/managed skills can be toggled and supplied with env values:
|
||||
{
|
||||
skills: {
|
||||
entries: {
|
||||
"nano-banana-pro": {
|
||||
"image-lab": {
|
||||
enabled: true,
|
||||
apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" }, // or plaintext string
|
||||
env: {
|
||||
@ -214,6 +214,10 @@ Bundled/managed skills can be toggled and supplied with env values:
|
||||
|
||||
Note: if the skill name contains hyphens, quote the key (JSON5 allows quoted keys).
|
||||
|
||||
If you want stock image generation/editing inside OpenClaw itself, use the core
|
||||
`image_generate` tool with `agents.defaults.imageGenerationModel` instead of a
|
||||
bundled skill. Skill examples here are for custom or third-party workflows.
|
||||
|
||||
Config keys match the **skill name** by default. If a skill defines
|
||||
`metadata.openclaw.skillKey`, use that key under `skills.entries`.
|
||||
|
||||
|
||||
@ -36,6 +36,8 @@ They run immediately, are stripped before the model sees the message, and the re
|
||||
bash: false,
|
||||
bashForegroundMs: 2000,
|
||||
config: false,
|
||||
mcp: false,
|
||||
plugins: false,
|
||||
debug: false,
|
||||
restart: false,
|
||||
allowFrom: {
|
||||
@ -59,6 +61,8 @@ They run immediately, are stripped before the model sees the message, and the re
|
||||
- `commands.bash` (default `false`) enables `! <cmd>` to run host shell commands (`/bash <cmd>` is an alias; requires `tools.elevated` allowlists).
|
||||
- `commands.bashForegroundMs` (default `2000`) controls how long bash waits before switching to background mode (`0` backgrounds immediately).
|
||||
- `commands.config` (default `false`) enables `/config` (reads/writes `openclaw.json`).
|
||||
- `commands.mcp` (default `false`) enables `/mcp` (reads/writes OpenClaw-managed MCP config under `mcp.servers`).
|
||||
- `commands.plugins` (default `false`) enables `/plugins` (plugin discovery/status plus enable/disable toggles).
|
||||
- `commands.debug` (default `false`) enables `/debug` (runtime-only overrides).
|
||||
- `commands.allowFrom` (optional) sets a per-provider allowlist for command authorization. When configured, it is the
|
||||
only authorization source for commands and directives (channel allowlists/pairing and `commands.useAccessGroups`
|
||||
@ -90,6 +94,8 @@ Text + native (when enabled):
|
||||
- `/steer <id|#> <message>` (steer a running sub-agent immediately: in-run when possible, otherwise abort current work and restart on the steer message)
|
||||
- `/tell <id|#> <message>` (alias for `/steer`)
|
||||
- `/config show|get|set|unset` (persist config to disk, owner-only; requires `commands.config: true`)
|
||||
- `/mcp show|get|set|unset` (manage OpenClaw MCP server config, owner-only; requires `commands.mcp: true`)
|
||||
- `/plugins list|show|get|enable|disable` (inspect discovered plugins and toggle enablement, owner-only for writes; requires `commands.plugins: true`)
|
||||
- `/debug show|set|unset|reset` (runtime overrides, owner-only; requires `commands.debug: true`)
|
||||
- `/usage off|tokens|full|cost` (per-response usage footer or local cost summary)
|
||||
- `/tts off|always|inbound|tagged|status|provider|limit|summary|audio` (control TTS; see [/tts](/tts))
|
||||
@ -214,6 +220,44 @@ Notes:
|
||||
- Config is validated before write; invalid changes are rejected.
|
||||
- `/config` updates persist across restarts.
|
||||
|
||||
## MCP updates
|
||||
|
||||
`/mcp` writes OpenClaw-managed MCP server definitions under `mcp.servers`. Owner-only. Disabled by default; enable with `commands.mcp: true`.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
/mcp show
|
||||
/mcp show context7
|
||||
/mcp set context7={"command":"uvx","args":["context7-mcp"]}
|
||||
/mcp unset context7
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `/mcp` stores config in OpenClaw config, not Pi-owned project settings.
|
||||
- Runtime adapters decide which transports are actually executable.
|
||||
|
||||
## Plugin updates
|
||||
|
||||
`/plugins` lets operators inspect discovered plugins and toggle enablement in config. Read-only flows can use `/plugin` as an alias. Disabled by default; enable with `commands.plugins: true`.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
/plugins
|
||||
/plugins list
|
||||
/plugin show context7
|
||||
/plugins enable context7
|
||||
/plugins disable context7
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `/plugins list` and `/plugins show` use real plugin discovery against the current workspace plus on-disk config.
|
||||
- `/plugins enable|disable` updates plugin config only; it does not install or uninstall plugins.
|
||||
- After enable/disable changes, restart the gateway to apply them.
|
||||
|
||||
## Surface notes
|
||||
|
||||
- **Text commands** run in the normal chat session (DMs share `main`, groups have their own session).
|
||||
|
||||
75
docs/tts.md
75
docs/tts.md
@ -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 Microsoft’s 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. citeturn2search0
|
||||
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 10‑minute audio limit per request; Edge TTS
|
||||
does not publish limits, so assume similar or lower limits. citeturn0search3
|
||||
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. Auto‑TTS 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. citeturn2search0
|
||||
- Output format values follow Microsoft Speech output formats (including Ogg/WebM Opus). citeturn1search0
|
||||
- **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. citeturn1search1
|
||||
- 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.
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -242,7 +242,7 @@ http://localhost:5173/?gatewayUrl=wss://<gateway-host>:18789#token=<gateway-toke
|
||||
Notes:
|
||||
|
||||
- `gatewayUrl` is stored in localStorage after load and removed from the URL.
|
||||
- `token` is imported from the URL fragment, stored in sessionStorage for the current browser tab session and selected gateway URL, and stripped from the URL; it is not stored in localStorage.
|
||||
- `token` is preferably imported from the URL fragment, stored in sessionStorage for the current browser tab session and selected gateway URL, and stripped from the URL; legacy `?token=` query params are also imported once for compatibility and then removed.
|
||||
- `password` is kept in memory only.
|
||||
- When `gatewayUrl` is set, the UI does not fall back to config or environment credentials.
|
||||
Provide `token` (or `password`) explicitly. Missing explicit credentials is an error.
|
||||
@ -250,6 +250,9 @@ Notes:
|
||||
- `gatewayUrl` is only accepted in a top-level window (not embedded) to prevent clickjacking.
|
||||
- Non-loopback Control UI deployments must set `gateway.controlUi.allowedOrigins`
|
||||
explicitly (full origins). This includes remote dev setups.
|
||||
- Do not use `gateway.controlUi.allowedOrigins: ["*"]` except for tightly controlled
|
||||
local testing. It means allow any browser origin, not “match whatever host I am
|
||||
using.”
|
||||
- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` enables
|
||||
Host-header origin fallback mode, but it is a dangerous security mode.
|
||||
|
||||
|
||||
@ -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>`
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 通过 OAuth(ChatGPT 登录)支持 **OpenAI Code (Codex)**。向导可以运行 OAuth 流程,并在适当时将默认模型设置为 `openai-codex/gpt-5.2`。参阅[模型提供商](/concepts/model-providers)和[向导](/start/wizard)。
|
||||
OpenClaw 通过 OAuth(ChatGPT 登录)支持 **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`(仅限开发;清除开发配置 + 凭据 + 会话 + 工作区)。
|
||||
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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 应用的首次运行流程。
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 密钥(如果提供商需要)。
|
||||
|
||||
@ -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)。
|
||||
|
||||
## 相关文档
|
||||
|
||||
|
||||
519
experiments/acp-pluginification-architecture-plan.md
Normal file
519
experiments/acp-pluginification-architecture-plan.md
Normal file
@ -0,0 +1,519 @@
|
||||
# Bindings Capability Architecture Plan
|
||||
|
||||
Status: in progress
|
||||
|
||||
## Summary
|
||||
|
||||
The goal is not to move all ACP code out of core.
|
||||
|
||||
The goal is to make `bindings` a small core capability, keep the ACP session kernel in core, and move ACP-specific binding policy plus codex app server policy out of core.
|
||||
|
||||
That gives us a lightweight core without hiding core semantics behind plugin indirection.
|
||||
|
||||
## Current Conclusion
|
||||
|
||||
The current architecture should converge on this split:
|
||||
|
||||
- Core owns the generic binding capability.
|
||||
- Core owns the generic ACP session kernel.
|
||||
- Channel plugins own channel-specific binding semantics.
|
||||
- ACP backend plugins own runtime protocol details.
|
||||
- Product-level consumers like ACP configured bindings and the codex app server sit on top of the binding capability instead of hardcoding their own binding plumbing.
|
||||
|
||||
This is different from "everything becomes a plugin".
|
||||
|
||||
## Why This Changed
|
||||
|
||||
The current codebase already shows that there are really three different layers:
|
||||
|
||||
- binding and conversation ownership
|
||||
- long-lived session and runtime-handle orchestration
|
||||
- product-specific turn logic
|
||||
|
||||
Those layers should not all be forced into one runtime engine.
|
||||
|
||||
Today the duplication is mostly in the execution/control-plane shape, not in storage or binding plumbing:
|
||||
|
||||
- the main harness has its own turn engine
|
||||
- ACP has its own session control plane
|
||||
- the codex app server plugin path likely owns its own app-level turn engine outside this repo
|
||||
|
||||
The right move is to share the stable control-plane contracts, not to force all three into one giant executor.
|
||||
|
||||
## Verified Current State
|
||||
|
||||
### Generic binding pieces already exist
|
||||
|
||||
- `src/infra/outbound/session-binding-service.ts` already provides a generic binding store and adapter model.
|
||||
- `src/plugins/conversation-binding.ts` already lets plugins request a conversation binding and stores plugin-owned binding metadata.
|
||||
- `src/plugins/types.ts` already exposes plugin-facing binding APIs.
|
||||
- `src/plugins/types.ts` already exposes the generic `inbound_claim` hook.
|
||||
|
||||
### ACP is only partially pluginified
|
||||
|
||||
- `src/channels/plugins/configured-binding-registry.ts` now owns generic configured binding compilation and lookup.
|
||||
- `src/channels/plugins/binding-routing.ts` and `src/channels/plugins/binding-targets.ts` now own the generic route and target lifecycle seams.
|
||||
- ACP now plugs into that seam through `src/channels/plugins/acp-configured-binding-consumer.ts` and `src/channels/plugins/acp-stateful-target-driver.ts`.
|
||||
- `src/acp/persistent-bindings.lifecycle.ts` still owns configured ACP ensure and reset behavior.
|
||||
- runtime-created plugin conversation bindings still use a separate path in `src/plugins/conversation-binding.ts`.
|
||||
|
||||
### Codex app server is already closer to the desired shape
|
||||
|
||||
From this repo's side, the codex app server path is much thinner:
|
||||
|
||||
- a plugin binds a conversation
|
||||
- core stores that binding
|
||||
- inbound dispatch targets the plugin's `inbound_claim` hook
|
||||
|
||||
What core does not provide for the codex app server path is an ACP-like shared session kernel. If the app server needs retries, long-lived runtime handles, cancellation, or session health logic, it must own that itself today.
|
||||
|
||||
## The Durable Split
|
||||
|
||||
### 1. Core Binding Capability
|
||||
|
||||
This should become the primary shared seam.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- canonical `ConversationRef`
|
||||
- binding record storage
|
||||
- configured binding compilation
|
||||
- runtime-created binding storage
|
||||
- fast binding lookup on inbound
|
||||
- binding touch/unbind lifecycle
|
||||
- generic dispatch handoff to the binding target
|
||||
|
||||
What core binding capability must not own:
|
||||
|
||||
- Discord thread rules
|
||||
- Telegram topic rules
|
||||
- Feishu chat rules
|
||||
- ACP session orchestration
|
||||
- codex app server business logic
|
||||
|
||||
### 2. Core Stateful Target Kernel
|
||||
|
||||
This is the small generic kernel for long-lived bound targets.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- ensure target ready
|
||||
- run turn
|
||||
- cancel turn
|
||||
- close target
|
||||
- reset target
|
||||
- status and health
|
||||
- persistence of target metadata
|
||||
- retries and runtime-handle safety
|
||||
- per-target serialization and concurrency
|
||||
|
||||
ACP is the first real implementation of this shape.
|
||||
|
||||
This kernel should stay in core because it is mandatory infrastructure and has strict startup, reset, and recovery semantics.
|
||||
|
||||
### 3. Channel Binding Providers
|
||||
|
||||
Each channel plugin should own the meaning of "this channel conversation maps to this binding rule".
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- normalize configured binding targets
|
||||
- normalize inbound conversations
|
||||
- match inbound conversations against compiled bindings
|
||||
- define channel-specific matching priority
|
||||
- optionally provide binding description text for status and logs
|
||||
|
||||
This is where Discord channel vs thread logic, Telegram topic rules, and Feishu conversation rules belong.
|
||||
|
||||
### 4. Product Consumers
|
||||
|
||||
Bindings are a shared capability. Different products should consume it differently.
|
||||
|
||||
ACP configured bindings:
|
||||
|
||||
- compile config rules
|
||||
- resolve a target session
|
||||
- ensure the ACP session is ready through the ACP kernel
|
||||
|
||||
Codex app server:
|
||||
|
||||
- create runtime-requested bindings
|
||||
- claim inbound messages through plugin hooks
|
||||
- optionally adopt the shared stateful target contract later if it really needs long-lived session orchestration
|
||||
|
||||
Main harness:
|
||||
|
||||
- does not need to become "a binding product"
|
||||
- may eventually share small lifecycle contracts, but it should not be forced into the same engine as ACP
|
||||
|
||||
## The Key Architectural Decision
|
||||
|
||||
The shared abstraction should be:
|
||||
|
||||
- `bindings` as the capability
|
||||
- `stateful target drivers` as an optional lower-level contract
|
||||
|
||||
The shared abstraction should not be:
|
||||
|
||||
- "one runtime engine for main harness, ACP, and codex app server"
|
||||
|
||||
That would overfit very different systems into one executor.
|
||||
|
||||
## Stable Nouns
|
||||
|
||||
Core should understand only stable nouns.
|
||||
|
||||
The stable nouns are:
|
||||
|
||||
- `ConversationRef`
|
||||
- `BindingRule`
|
||||
- `CompiledBinding`
|
||||
- `BindingResolution`
|
||||
- `BindingTargetDescriptor`
|
||||
- `StatefulTargetDriver`
|
||||
- `StatefulTargetHandle`
|
||||
|
||||
ACP, codex app server, and future products should compile down to those nouns instead of leaking product-specific routing rules through core.
|
||||
|
||||
## Proposed Capability Model
|
||||
|
||||
### Binding capability
|
||||
|
||||
The binding capability should support both configured bindings and runtime-created bindings.
|
||||
|
||||
Required operations:
|
||||
|
||||
- compile configured bindings at startup or reload
|
||||
- resolve a binding from an inbound `ConversationRef`
|
||||
- create a runtime binding
|
||||
- touch and unbind an existing binding
|
||||
- dispatch a resolved binding to its target
|
||||
|
||||
### Binding target descriptor
|
||||
|
||||
A resolved binding should point to a typed target descriptor rather than ad hoc ACP- or plugin-specific metadata blobs.
|
||||
|
||||
The descriptor should be able to represent at least:
|
||||
|
||||
- plugin-owned inbound claim targets
|
||||
- stateful target drivers
|
||||
|
||||
That means the same binding capability can support both:
|
||||
|
||||
- codex app server plugin-bound conversations
|
||||
- ACP configured bindings
|
||||
|
||||
without pretending they are the same product.
|
||||
|
||||
### Stateful target driver
|
||||
|
||||
This is the reusable control-plane contract for long-lived bound targets.
|
||||
|
||||
Required operations:
|
||||
|
||||
- `ensureReady`
|
||||
- `runTurn`
|
||||
- `cancel`
|
||||
- `close`
|
||||
- `reset`
|
||||
- `status`
|
||||
- `health`
|
||||
|
||||
ACP should remain the first built-in driver.
|
||||
|
||||
If the codex app server later proves that it also needs durable session handles, it can either:
|
||||
|
||||
- use a driver that consumes this contract, or
|
||||
- keep its own product-owned runtime if that remains simpler
|
||||
|
||||
That should be a product decision, not something forced by the binding capability.
|
||||
|
||||
## Why ACP Kernel Stays In Core
|
||||
|
||||
ACP's kernel should remain in core because session lifecycle, persistence, retries, cancellation, and runtime-handle safety are generic platform machinery.
|
||||
|
||||
Those concerns are not channel-specific, and they are not codex-app-server-specific.
|
||||
|
||||
If we move that machinery into an ordinary plugin, we create circular bootstrapping:
|
||||
|
||||
- channels need it during startup and inbound routing
|
||||
- reset and recovery need it when plugins may already be degraded
|
||||
- failure semantics become special-case core logic anyway
|
||||
|
||||
If we later wrap it in a "built-in capability module", that is still effectively core.
|
||||
|
||||
## What Should Move Out Of Core
|
||||
|
||||
The following should move out of ACP-shaped core code:
|
||||
|
||||
- channel-specific configured binding matching
|
||||
- channel-specific binding target normalization
|
||||
- channel-specific recovery UX
|
||||
- ACP-specific route wrapping helpers as named ACP seams
|
||||
- codex app server fallback policy beyond generic plugin-bound dispatch behavior
|
||||
|
||||
The following should stay:
|
||||
|
||||
- generic binding storage and dispatch
|
||||
- generic ACP control plane
|
||||
- generic stateful target driver contract
|
||||
|
||||
## Current Problems To Remove
|
||||
|
||||
### Residual cleanup is now small
|
||||
|
||||
Most ACP-era compatibility names are gone from the generic seam.
|
||||
|
||||
The remaining cleanup is smaller:
|
||||
|
||||
- `src/acp/persistent-bindings.ts` compatibility barrel can be deleted once tests stop importing it
|
||||
- ACP-named tests and mocks can be renamed over time for consistency
|
||||
- docs should stop describing already-removed ACP wrappers as if they still exist
|
||||
|
||||
### Configured binding implementation is still too monolithic
|
||||
|
||||
`src/channels/plugins/configured-binding-registry.ts` still mixes:
|
||||
|
||||
- registry compilation
|
||||
- cache invalidation
|
||||
- inbound matching
|
||||
- materialization of binding targets
|
||||
- session-key reverse lookup
|
||||
|
||||
That file is now generic, but still too large and too coupled.
|
||||
|
||||
### Runtime-created plugin bindings still use a separate stack
|
||||
|
||||
`src/plugins/conversation-binding.ts` is still a separate implementation path for plugin-created bindings.
|
||||
|
||||
That means configured bindings and runtime-created bindings share storage, but not one consistent capability layer.
|
||||
|
||||
### Generic registries still hardcode ACP as a built-in
|
||||
|
||||
`src/channels/plugins/configured-binding-consumers.ts` and `src/channels/plugins/stateful-target-drivers.ts` still import ACP directly.
|
||||
|
||||
That is acceptable for now, but the clean final shape is to keep ACP built in while registering it from a dedicated bootstrap point instead of wiring it inside the generic registry files.
|
||||
|
||||
## Target Contracts
|
||||
|
||||
### Channel binding provider contract
|
||||
|
||||
Conceptually, each channel plugin should support:
|
||||
|
||||
- `compileConfiguredBinding(binding, cfg) -> CompiledBinding | null`
|
||||
- `resolveInboundConversation(event) -> ConversationRef | null`
|
||||
- `matchInboundConversation(compiledBinding, conversation) -> BindingMatch | null`
|
||||
- `describeBinding(compiledBinding) -> string | undefined`
|
||||
|
||||
### Binding capability contract
|
||||
|
||||
Core should support:
|
||||
|
||||
- `compileConfiguredBindings(cfg, plugins) -> CompiledBindingRegistry`
|
||||
- `resolveBinding(conversationRef) -> BindingResolution | null`
|
||||
- `createRuntimeBinding(target, conversationRef, metadata) -> BindingRecord`
|
||||
- `touchBinding(bindingId)`
|
||||
- `unbindBinding(bindingId | target)`
|
||||
- `dispatchResolvedBinding(bindingResolution, inboundEvent)`
|
||||
|
||||
### Stateful target driver contract
|
||||
|
||||
Core should support:
|
||||
|
||||
- `ensureReady(targetRef, cfg)`
|
||||
- `runTurn(targetRef, input)`
|
||||
- `cancel(targetRef, reason)`
|
||||
- `close(targetRef, reason)`
|
||||
- `reset(targetRef, reason)`
|
||||
- `status(targetRef)`
|
||||
- `health(targetRef)`
|
||||
|
||||
## File-Level Transition Plan
|
||||
|
||||
### Keep
|
||||
|
||||
- `src/infra/outbound/session-binding-service.ts`
|
||||
- `src/acp/control-plane/*`
|
||||
- `extensions/acpx/*`
|
||||
|
||||
### Generalize
|
||||
|
||||
- `src/plugins/conversation-binding.ts`
|
||||
- fold runtime-created plugin bindings into the same generic binding capability instead of keeping a separate implementation stack
|
||||
- `src/channels/plugins/configured-binding-registry.ts`
|
||||
- split into compiler, matcher, and session-key resolution modules with a thin facade
|
||||
- `src/channels/plugins/types.adapters.ts`
|
||||
- finish removing ACP-era aliases after the deprecation window
|
||||
- `src/plugin-sdk/conversation-runtime.ts`
|
||||
- export only the generic binding capability surfaces
|
||||
- `src/acp/persistent-bindings.lifecycle.ts`
|
||||
- either become a generic stateful target driver consumer or be renamed to ACP driver-specific lifecycle code
|
||||
|
||||
### Shrink Or Delete
|
||||
|
||||
- `src/acp/persistent-bindings.ts`
|
||||
- delete the compatibility barrel once tests import the real modules directly
|
||||
- `src/acp/persistent-bindings.resolve.ts`
|
||||
- keep only while ACP-specific compatibility helpers are still useful to internal callers
|
||||
- ACP-named test files
|
||||
- rename over time once the behavior is stable and there is no risk of mixing behavioral and naming churn
|
||||
|
||||
## Recommended Refactor Order
|
||||
|
||||
### Completed groundwork
|
||||
|
||||
The current branch has already completed most of the first migration wave:
|
||||
|
||||
- stable generic binding nouns exist
|
||||
- configured bindings compile through a generic registry
|
||||
- inbound routing goes through generic binding resolution
|
||||
- configured binding lookup no longer performs fallback plugin discovery
|
||||
- ACP is expressed as a configured-binding consumer plus a built-in stateful target driver
|
||||
|
||||
The remaining work is cleanup and unification, not first-principles redesign.
|
||||
|
||||
### Phase 1: Freeze the nouns
|
||||
|
||||
Introduce and document the stable binding and target types:
|
||||
|
||||
- `ConversationRef`
|
||||
- `CompiledBinding`
|
||||
- `BindingResolution`
|
||||
- `BindingTargetDescriptor`
|
||||
- `StatefulTargetDriver`
|
||||
|
||||
Do this before more movement so the rest of the refactor has firm vocabulary.
|
||||
|
||||
### Phase 2: Promote bindings to a first-class core capability
|
||||
|
||||
Refactor the existing generic binding store into an explicit capability layer.
|
||||
|
||||
Requirements:
|
||||
|
||||
- runtime-created bindings stay supported
|
||||
- configured bindings become first-class
|
||||
- lookup becomes channel-agnostic
|
||||
|
||||
### Phase 3: Compile configured bindings at startup and reload
|
||||
|
||||
Move configured binding compilation off the inbound hot path.
|
||||
|
||||
Requirements:
|
||||
|
||||
- load enabled channel plugins once
|
||||
- compile configured bindings once
|
||||
- rebuild on config or plugin reload
|
||||
- inbound path becomes pure registry lookup
|
||||
|
||||
### Phase 4: Expand the channel provider seam
|
||||
|
||||
Replace the ACP-specific adapter shape with a generic channel binding provider contract.
|
||||
|
||||
Requirements:
|
||||
|
||||
- channel plugins own normalization and matching
|
||||
- core no longer knows channel-specific configured binding rules
|
||||
|
||||
### Phase 5: Re-express ACP as a binding consumer plus built-in stateful target driver
|
||||
|
||||
Move ACP configured binding policy to the new binding capability while keeping ACP runtime orchestration in core.
|
||||
|
||||
Requirements:
|
||||
|
||||
- ACP configured bindings resolve through the generic binding registry
|
||||
- ACP target readiness uses the ACP driver contract
|
||||
- ACP-specific naming disappears from generic binding code
|
||||
|
||||
### Phase 6: Finish residual ACP cleanup
|
||||
|
||||
Remove the last compatibility leftovers and stale naming.
|
||||
|
||||
Requirements:
|
||||
|
||||
- delete `src/acp/persistent-bindings.ts`
|
||||
- rename ACP-named tests where that improves clarity without changing behavior
|
||||
- keep docs synchronized with the actual generic seam instead of the earlier transition state
|
||||
|
||||
### Phase 7: Split the configured binding registry by responsibility
|
||||
|
||||
Refactor `src/channels/plugins/configured-binding-registry.ts` into smaller modules.
|
||||
|
||||
Suggested split:
|
||||
|
||||
- compiler module
|
||||
- inbound matcher module
|
||||
- session-key reverse lookup module
|
||||
- thin public facade
|
||||
|
||||
Requirements:
|
||||
|
||||
- caching behavior remains unchanged
|
||||
- matching behavior remains unchanged
|
||||
- session-key resolution behavior remains unchanged
|
||||
|
||||
### Phase 8: Keep codex app server on the same binding capability
|
||||
|
||||
Do not force the codex app server into ACP semantics.
|
||||
|
||||
Requirements:
|
||||
|
||||
- codex app server keeps runtime-created bindings through the same binding capability
|
||||
- inbound claim remains the default delivery path
|
||||
- only adopt the stateful target driver seam if the app server truly needs long-lived target orchestration
|
||||
- `src/plugins/conversation-binding.ts` stops being a separate binding stack and becomes a consumer of the generic binding capability
|
||||
|
||||
### Phase 9: Decouple built-in ACP registration from generic registry files
|
||||
|
||||
Keep ACP built in, but stop importing it directly from the generic registry modules.
|
||||
|
||||
Requirements:
|
||||
|
||||
- `src/channels/plugins/configured-binding-consumers.ts` no longer hardcodes ACP imports
|
||||
- `src/channels/plugins/stateful-target-drivers.ts` no longer hardcodes ACP imports
|
||||
- ACP still registers by default during normal startup
|
||||
- generic registry files remain product-agnostic
|
||||
|
||||
### Phase 10: Remove ACP-shaped compatibility facades
|
||||
|
||||
Once all call sites are on the generic capability:
|
||||
|
||||
- delete ACP-shaped routing helpers
|
||||
- delete hot-path plugin bootstrapping logic
|
||||
- keep only thin compatibility exports if external plugins still need a deprecation window
|
||||
|
||||
## Success Criteria
|
||||
|
||||
The architecture is done when all of these are true:
|
||||
|
||||
- no inbound configured-binding resolution performs plugin discovery
|
||||
- no channel-specific binding semantics remain in generic core binding code
|
||||
- ACP still uses a core session kernel
|
||||
- codex app server and ACP both sit on top of the same binding capability
|
||||
- the binding capability can represent both configured and runtime-created bindings
|
||||
- runtime-created plugin bindings do not use a separate implementation stack
|
||||
- long-lived target orchestration is shared through a small core driver contract
|
||||
- generic registry files do not import ACP directly
|
||||
- ACP-era alias names are gone from the generic/plugin SDK surface
|
||||
- the main harness is not forced into the ACP engine
|
||||
- external plugins can use the same capability without internal imports
|
||||
|
||||
## Non-Goals
|
||||
|
||||
These are not goals of the remaining refactor:
|
||||
|
||||
- moving the ACP session kernel into an ordinary plugin
|
||||
- forcing the main harness, ACP, and codex app server into one executor
|
||||
- making every channel implement its own retry and session-safety logic
|
||||
- keeping ACP-shaped naming in the long-term generic binding layer
|
||||
|
||||
## Bottom Line
|
||||
|
||||
The right 20-year split is:
|
||||
|
||||
- bindings are the shared core capability
|
||||
- ACP session orchestration remains a small built-in core kernel
|
||||
- channel plugins own binding semantics
|
||||
- backend plugins own runtime protocol details
|
||||
- product consumers like ACP configured bindings and codex app server build on the same binding capability without being forced into one runtime engine
|
||||
|
||||
That is the leanest core that still has honest boundaries.
|
||||
@ -39,6 +39,25 @@ describe("acpx plugin config parsing", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("prefers the workspace plugin root for dist/extensions/acpx bundles", () => {
|
||||
const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), "acpx-root-workspace-"));
|
||||
const workspacePluginRoot = path.join(repoRoot, "extensions", "acpx");
|
||||
const bundledPluginRoot = path.join(repoRoot, "dist", "extensions", "acpx");
|
||||
try {
|
||||
fs.mkdirSync(workspacePluginRoot, { recursive: true });
|
||||
fs.mkdirSync(bundledPluginRoot, { recursive: true });
|
||||
fs.writeFileSync(path.join(workspacePluginRoot, "package.json"), "{}\n", "utf8");
|
||||
fs.writeFileSync(path.join(workspacePluginRoot, "openclaw.plugin.json"), "{}\n", "utf8");
|
||||
fs.writeFileSync(path.join(bundledPluginRoot, "package.json"), "{}\n", "utf8");
|
||||
fs.writeFileSync(path.join(bundledPluginRoot, "openclaw.plugin.json"), "{}\n", "utf8");
|
||||
|
||||
const moduleUrl = pathToFileURL(path.join(bundledPluginRoot, "index.js")).href;
|
||||
expect(resolveAcpxPluginRoot(moduleUrl)).toBe(workspacePluginRoot);
|
||||
} finally {
|
||||
fs.rmSync(repoRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("resolves bundled acpx with pinned version by default", () => {
|
||||
const resolved = resolveAcpxPluginConfig({
|
||||
rawConfig: {
|
||||
|
||||
@ -13,14 +13,18 @@ export const ACPX_PINNED_VERSION = "0.1.16";
|
||||
export const ACPX_VERSION_ANY = "any";
|
||||
const ACPX_BIN_NAME = process.platform === "win32" ? "acpx.cmd" : "acpx";
|
||||
|
||||
export function resolveAcpxPluginRoot(moduleUrl: string = import.meta.url): string {
|
||||
function isAcpxPluginRoot(dir: string): boolean {
|
||||
return (
|
||||
fs.existsSync(path.join(dir, "openclaw.plugin.json")) &&
|
||||
fs.existsSync(path.join(dir, "package.json"))
|
||||
);
|
||||
}
|
||||
|
||||
function resolveNearestAcpxPluginRoot(moduleUrl: string): string {
|
||||
let cursor = path.dirname(fileURLToPath(moduleUrl));
|
||||
for (let i = 0; i < 3; i += 1) {
|
||||
// Bundled entries live at the plugin root while source files still live under src/.
|
||||
if (
|
||||
fs.existsSync(path.join(cursor, "openclaw.plugin.json")) &&
|
||||
fs.existsSync(path.join(cursor, "package.json"))
|
||||
) {
|
||||
if (isAcpxPluginRoot(cursor)) {
|
||||
return cursor;
|
||||
}
|
||||
const parent = path.dirname(cursor);
|
||||
@ -32,10 +36,29 @@ export function resolveAcpxPluginRoot(moduleUrl: string = import.meta.url): stri
|
||||
return path.resolve(path.dirname(fileURLToPath(moduleUrl)), "..");
|
||||
}
|
||||
|
||||
function resolveWorkspaceAcpxPluginRoot(currentRoot: string): string | null {
|
||||
if (
|
||||
path.basename(currentRoot) !== "acpx" ||
|
||||
path.basename(path.dirname(currentRoot)) !== "extensions" ||
|
||||
path.basename(path.dirname(path.dirname(currentRoot))) !== "dist"
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const workspaceRoot = path.resolve(currentRoot, "..", "..", "..", "extensions", "acpx");
|
||||
return isAcpxPluginRoot(workspaceRoot) ? workspaceRoot : null;
|
||||
}
|
||||
|
||||
export function resolveAcpxPluginRoot(moduleUrl: string = import.meta.url): string {
|
||||
const resolvedRoot = resolveNearestAcpxPluginRoot(moduleUrl);
|
||||
// In a live repo checkout, dist/ can be rebuilt out from under the running gateway.
|
||||
// Prefer the stable source plugin root when a built extension is running beside it.
|
||||
return resolveWorkspaceAcpxPluginRoot(resolvedRoot) ?? resolvedRoot;
|
||||
}
|
||||
|
||||
export const ACPX_PLUGIN_ROOT = resolveAcpxPluginRoot();
|
||||
export const ACPX_BUNDLED_BIN = path.join(ACPX_PLUGIN_ROOT, "node_modules", ".bin", ACPX_BIN_NAME);
|
||||
export function buildAcpxLocalInstallCommand(version: string = ACPX_PINNED_VERSION): string {
|
||||
return `npm install --omit=dev --no-save acpx@${version}`;
|
||||
return `npm install --omit=dev --no-save --package-lock=false acpx@${version}`;
|
||||
}
|
||||
export const ACPX_LOCAL_INSTALL_COMMAND = buildAcpxLocalInstallCommand();
|
||||
|
||||
|
||||
@ -85,7 +85,13 @@ describe("acpx ensure", () => {
|
||||
});
|
||||
expect(spawnAndCollectMock.mock.calls[1]?.[0]).toMatchObject({
|
||||
command: "npm",
|
||||
args: ["install", "--omit=dev", "--no-save", `acpx@${ACPX_PINNED_VERSION}`],
|
||||
args: [
|
||||
"install",
|
||||
"--omit=dev",
|
||||
"--no-save",
|
||||
"--package-lock=false",
|
||||
`acpx@${ACPX_PINNED_VERSION}`,
|
||||
],
|
||||
cwd: "/plugin",
|
||||
stripProviderAuthEnvVars,
|
||||
});
|
||||
|
||||
@ -233,7 +233,13 @@ export async function ensureAcpx(params: {
|
||||
|
||||
const install = await spawnAndCollect({
|
||||
command: "npm",
|
||||
args: ["install", "--omit=dev", "--no-save", `acpx@${installVersion}`],
|
||||
args: [
|
||||
"install",
|
||||
"--omit=dev",
|
||||
"--no-save",
|
||||
"--package-lock=false",
|
||||
`acpx@${installVersion}`,
|
||||
],
|
||||
cwd: pluginRoot,
|
||||
stripProviderAuthEnvVars: params.stripProviderAuthEnvVars,
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { chmod, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
@ -64,6 +64,58 @@ describe("resolveSpawnCommand", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("routes node shebang wrappers through the current node runtime on posix", async () => {
|
||||
const dir = await createTempDir();
|
||||
const scriptPath = path.join(dir, "acpx");
|
||||
await writeFile(scriptPath, "#!/usr/bin/env node\nconsole.log('ok')\n", "utf8");
|
||||
await chmod(scriptPath, 0o755);
|
||||
|
||||
const resolved = resolveSpawnCommand(
|
||||
{
|
||||
command: scriptPath,
|
||||
args: ["--help"],
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
platform: "linux",
|
||||
env: {},
|
||||
execPath: "/custom/node",
|
||||
},
|
||||
);
|
||||
|
||||
expect(resolved).toEqual({
|
||||
command: "/custom/node",
|
||||
args: [scriptPath, "--help"],
|
||||
});
|
||||
});
|
||||
|
||||
it("routes PATH-resolved node shebang wrappers through the current node runtime on posix", async () => {
|
||||
const dir = await createTempDir();
|
||||
const binDir = path.join(dir, "bin");
|
||||
const scriptPath = path.join(binDir, "acpx");
|
||||
await mkdir(binDir, { recursive: true });
|
||||
await writeFile(scriptPath, "#!/usr/bin/env node\nconsole.log('ok')\n", "utf8");
|
||||
await chmod(scriptPath, 0o755);
|
||||
|
||||
const resolved = resolveSpawnCommand(
|
||||
{
|
||||
command: "acpx",
|
||||
args: ["--help"],
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
platform: "linux",
|
||||
env: { PATH: binDir },
|
||||
execPath: "/custom/node",
|
||||
},
|
||||
);
|
||||
|
||||
expect(resolved).toEqual({
|
||||
command: "/custom/node",
|
||||
args: [scriptPath, "--help"],
|
||||
});
|
||||
});
|
||||
|
||||
it("routes .js command execution through node on windows", () => {
|
||||
const resolved = resolveSpawnCommand(
|
||||
{
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process";
|
||||
import { existsSync } from "node:fs";
|
||||
import { accessSync, constants as fsConstants, existsSync, readFileSync, statSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import type {
|
||||
WindowsSpawnProgram,
|
||||
WindowsSpawnProgramCandidate,
|
||||
@ -57,11 +58,76 @@ const DEFAULT_RUNTIME: SpawnRuntime = {
|
||||
execPath: process.execPath,
|
||||
};
|
||||
|
||||
function isExecutableFile(filePath: string, platform: NodeJS.Platform): boolean {
|
||||
try {
|
||||
const stat = statSync(filePath);
|
||||
if (!stat.isFile()) {
|
||||
return false;
|
||||
}
|
||||
if (platform === "win32") {
|
||||
return true;
|
||||
}
|
||||
accessSync(filePath, fsConstants.X_OK);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveExecutableFromPath(command: string, runtime: SpawnRuntime): string | undefined {
|
||||
const pathEnv = runtime.env.PATH ?? runtime.env.Path;
|
||||
if (!pathEnv) {
|
||||
return undefined;
|
||||
}
|
||||
for (const entry of pathEnv.split(path.delimiter).filter(Boolean)) {
|
||||
const candidate = path.join(entry, command);
|
||||
if (isExecutableFile(candidate, runtime.platform)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function resolveNodeShebangScriptPath(command: string, runtime: SpawnRuntime): string | undefined {
|
||||
const commandPath =
|
||||
path.isAbsolute(command) || command.includes(path.sep)
|
||||
? command
|
||||
: resolveExecutableFromPath(command, runtime);
|
||||
if (!commandPath || !isExecutableFile(commandPath, runtime.platform)) {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
const firstLine = readFileSync(commandPath, "utf8").split(/\r?\n/, 1)[0] ?? "";
|
||||
if (/^#!.*(?:\/usr\/bin\/env\s+node\b|\/node(?:js)?\b)/.test(firstLine)) {
|
||||
return commandPath;
|
||||
}
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function resolveSpawnCommand(
|
||||
params: { command: string; args: string[] },
|
||||
options?: SpawnCommandOptions,
|
||||
runtime: SpawnRuntime = DEFAULT_RUNTIME,
|
||||
): ResolvedSpawnCommand {
|
||||
if (runtime.platform !== "win32") {
|
||||
const nodeShebangScript = resolveNodeShebangScriptPath(params.command, runtime);
|
||||
if (nodeShebangScript) {
|
||||
options?.onResolved?.({
|
||||
command: params.command,
|
||||
cacheHit: false,
|
||||
strictWindowsCmdWrapper: options?.strictWindowsCmdWrapper === true,
|
||||
resolution: "direct",
|
||||
});
|
||||
return {
|
||||
command: runtime.execPath,
|
||||
args: [nodeShebangScript, ...params.args],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const strictWindowsCmdWrapper = options?.strictWindowsCmdWrapper === true;
|
||||
const cacheKey = params.command;
|
||||
const cachedProgram = options?.cache;
|
||||
|
||||
@ -154,6 +154,90 @@ describe("AcpxRuntime", () => {
|
||||
expect(resumeArgs[resumeFlagIndex + 1]).toBe(resumeSessionId);
|
||||
});
|
||||
|
||||
it("replaces dead named sessions returned by sessions ensure", async () => {
|
||||
process.env.MOCK_ACPX_STATUS_STATUS = "dead";
|
||||
process.env.MOCK_ACPX_STATUS_SUMMARY = "queue owner unavailable";
|
||||
try {
|
||||
const { runtime, logPath } = await createMockRuntimeFixture();
|
||||
const sessionKey = "agent:codex:acp:dead-session";
|
||||
|
||||
const handle = await runtime.ensureSession({
|
||||
sessionKey,
|
||||
agent: "codex",
|
||||
mode: "persistent",
|
||||
});
|
||||
|
||||
expect(handle.backend).toBe("acpx");
|
||||
const logs = await readMockRuntimeLogEntries(logPath);
|
||||
const ensureIndex = logs.findIndex((entry) => entry.kind === "ensure");
|
||||
const statusIndex = logs.findIndex((entry) => entry.kind === "status");
|
||||
const newIndex = logs.findIndex((entry) => entry.kind === "new");
|
||||
expect(ensureIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(statusIndex).toBeGreaterThan(ensureIndex);
|
||||
expect(newIndex).toBeGreaterThan(statusIndex);
|
||||
} finally {
|
||||
delete process.env.MOCK_ACPX_STATUS_STATUS;
|
||||
delete process.env.MOCK_ACPX_STATUS_SUMMARY;
|
||||
}
|
||||
});
|
||||
|
||||
it("reuses a live named session when sessions ensure exits before returning identifiers", async () => {
|
||||
process.env.MOCK_ACPX_ENSURE_EXIT_1 = "1";
|
||||
process.env.MOCK_ACPX_STATUS_STATUS = "alive";
|
||||
try {
|
||||
const { runtime, logPath } = await createMockRuntimeFixture();
|
||||
const sessionKey = "agent:codex:acp:ensure-fallback-alive";
|
||||
|
||||
const handle = await runtime.ensureSession({
|
||||
sessionKey,
|
||||
agent: "codex",
|
||||
mode: "persistent",
|
||||
});
|
||||
|
||||
expect(handle.backend).toBe("acpx");
|
||||
expect(handle.acpxRecordId).toBe("rec-" + sessionKey);
|
||||
const logs = await readMockRuntimeLogEntries(logPath);
|
||||
const ensureIndex = logs.findIndex((entry) => entry.kind === "ensure");
|
||||
const statusIndex = logs.findIndex((entry) => entry.kind === "status");
|
||||
const newIndex = logs.findIndex((entry) => entry.kind === "new");
|
||||
expect(ensureIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(statusIndex).toBeGreaterThan(ensureIndex);
|
||||
expect(newIndex).toBe(-1);
|
||||
} finally {
|
||||
delete process.env.MOCK_ACPX_ENSURE_EXIT_1;
|
||||
delete process.env.MOCK_ACPX_STATUS_STATUS;
|
||||
}
|
||||
});
|
||||
|
||||
it("creates a fresh named session when sessions ensure exits and status is dead", async () => {
|
||||
process.env.MOCK_ACPX_ENSURE_EXIT_1 = "1";
|
||||
process.env.MOCK_ACPX_STATUS_STATUS = "dead";
|
||||
process.env.MOCK_ACPX_STATUS_SUMMARY = "queue owner unavailable";
|
||||
try {
|
||||
const { runtime, logPath } = await createMockRuntimeFixture();
|
||||
const sessionKey = "agent:codex:acp:ensure-fallback-dead";
|
||||
|
||||
const handle = await runtime.ensureSession({
|
||||
sessionKey,
|
||||
agent: "codex",
|
||||
mode: "persistent",
|
||||
});
|
||||
|
||||
expect(handle.backend).toBe("acpx");
|
||||
const logs = await readMockRuntimeLogEntries(logPath);
|
||||
const ensureIndex = logs.findIndex((entry) => entry.kind === "ensure");
|
||||
const statusIndex = logs.findIndex((entry) => entry.kind === "status");
|
||||
const newIndex = logs.findIndex((entry) => entry.kind === "new");
|
||||
expect(ensureIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(statusIndex).toBeGreaterThan(ensureIndex);
|
||||
expect(newIndex).toBeGreaterThan(statusIndex);
|
||||
} finally {
|
||||
delete process.env.MOCK_ACPX_ENSURE_EXIT_1;
|
||||
delete process.env.MOCK_ACPX_STATUS_STATUS;
|
||||
delete process.env.MOCK_ACPX_STATUS_SUMMARY;
|
||||
}
|
||||
});
|
||||
|
||||
it("serializes text plus image attachments into ACP prompt blocks", async () => {
|
||||
const { runtime, logPath } = await createMockRuntimeFixture();
|
||||
|
||||
|
||||
@ -92,6 +92,26 @@ function formatAcpxExitMessage(params: {
|
||||
return stderr || `acpx exited with code ${params.exitCode ?? "unknown"}`;
|
||||
}
|
||||
|
||||
function summarizeLogText(text: string, maxChars = 240): string {
|
||||
const normalized = text.trim().replace(/\s+/g, " ");
|
||||
if (!normalized) {
|
||||
return "";
|
||||
}
|
||||
if (normalized.length <= maxChars) {
|
||||
return normalized;
|
||||
}
|
||||
return `${normalized.slice(0, maxChars)}...`;
|
||||
}
|
||||
|
||||
function findSessionIdentifierEvent(events: AcpxJsonObject[]): AcpxJsonObject | undefined {
|
||||
return events.find(
|
||||
(event) =>
|
||||
asOptionalString(event.agentSessionId) ||
|
||||
asOptionalString(event.acpxSessionId) ||
|
||||
asOptionalString(event.acpxRecordId),
|
||||
);
|
||||
}
|
||||
|
||||
export function encodeAcpxRuntimeHandleState(state: AcpxHandleState): string {
|
||||
const payload = Buffer.from(JSON.stringify(state), "utf8").toString("base64url");
|
||||
return `${ACPX_RUNTIME_HANDLE_PREFIX}${payload}`;
|
||||
@ -252,6 +272,146 @@ export class AcpxRuntime implements AcpRuntime {
|
||||
this.healthy = result.ok;
|
||||
}
|
||||
|
||||
private async createNamedSession(params: {
|
||||
agent: string;
|
||||
cwd: string;
|
||||
sessionName: string;
|
||||
resumeSessionId?: string;
|
||||
}): Promise<AcpxJsonObject[]> {
|
||||
const command = params.resumeSessionId
|
||||
? [
|
||||
"sessions",
|
||||
"new",
|
||||
"--name",
|
||||
params.sessionName,
|
||||
"--resume-session",
|
||||
params.resumeSessionId,
|
||||
]
|
||||
: ["sessions", "new", "--name", params.sessionName];
|
||||
return await this.runControlCommand({
|
||||
args: await this.buildVerbArgs({
|
||||
agent: params.agent,
|
||||
cwd: params.cwd,
|
||||
command,
|
||||
}),
|
||||
cwd: params.cwd,
|
||||
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
||||
});
|
||||
}
|
||||
|
||||
private async shouldReplaceEnsuredSession(params: {
|
||||
sessionName: string;
|
||||
agent: string;
|
||||
cwd: string;
|
||||
}): Promise<boolean> {
|
||||
const args = await this.buildVerbArgs({
|
||||
agent: params.agent,
|
||||
cwd: params.cwd,
|
||||
command: ["status", "--session", params.sessionName],
|
||||
});
|
||||
let events: AcpxJsonObject[];
|
||||
try {
|
||||
events = await this.runControlCommand({
|
||||
args,
|
||||
cwd: params.cwd,
|
||||
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
||||
ignoreNoSession: true,
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession status probe failed: session=${params.sessionName} cwd=${params.cwd} error=${summarizeLogText(error instanceof Error ? error.message : String(error)) || "<empty>"}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
const noSession = events.some((event) => toAcpxErrorEvent(event)?.code === "NO_SESSION");
|
||||
if (noSession) {
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession replacing missing named session: session=${params.sessionName} cwd=${params.cwd}`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
const detail = events.find((event) => !toAcpxErrorEvent(event));
|
||||
const status = asTrimmedString(detail?.status)?.toLowerCase();
|
||||
if (status === "dead") {
|
||||
const summary = summarizeLogText(asOptionalString(detail?.summary) ?? "");
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession replacing dead named session: session=${params.sessionName} cwd=${params.cwd} status=${status} summary=${summary || "<empty>"}`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async recoverEnsureFailure(params: {
|
||||
sessionName: string;
|
||||
agent: string;
|
||||
cwd: string;
|
||||
error: unknown;
|
||||
}): Promise<AcpxJsonObject[] | null> {
|
||||
const errorMessage = summarizeLogText(
|
||||
params.error instanceof Error ? params.error.message : String(params.error),
|
||||
);
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession probing named session after ensure failure: session=${params.sessionName} cwd=${params.cwd} error=${errorMessage || "<empty>"}`,
|
||||
);
|
||||
const args = await this.buildVerbArgs({
|
||||
agent: params.agent,
|
||||
cwd: params.cwd,
|
||||
command: ["status", "--session", params.sessionName],
|
||||
});
|
||||
let events: AcpxJsonObject[];
|
||||
try {
|
||||
events = await this.runControlCommand({
|
||||
args,
|
||||
cwd: params.cwd,
|
||||
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
||||
ignoreNoSession: true,
|
||||
});
|
||||
} catch (statusError) {
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession status fallback failed: session=${params.sessionName} cwd=${params.cwd} error=${summarizeLogText(statusError instanceof Error ? statusError.message : String(statusError)) || "<empty>"}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const noSession = events.some((event) => toAcpxErrorEvent(event)?.code === "NO_SESSION");
|
||||
if (noSession) {
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession creating named session after ensure failure and missing status: session=${params.sessionName} cwd=${params.cwd}`,
|
||||
);
|
||||
return await this.createNamedSession({
|
||||
agent: params.agent,
|
||||
cwd: params.cwd,
|
||||
sessionName: params.sessionName,
|
||||
});
|
||||
}
|
||||
|
||||
const detail = events.find((event) => !toAcpxErrorEvent(event));
|
||||
const status = asTrimmedString(detail?.status)?.toLowerCase();
|
||||
if (status === "dead") {
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession replacing dead named session after ensure failure: session=${params.sessionName} cwd=${params.cwd}`,
|
||||
);
|
||||
return await this.createNamedSession({
|
||||
agent: params.agent,
|
||||
cwd: params.cwd,
|
||||
sessionName: params.sessionName,
|
||||
});
|
||||
}
|
||||
|
||||
if (status === "alive" || findSessionIdentifierEvent(events)) {
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession reusing live named session after ensure failure: session=${params.sessionName} cwd=${params.cwd} status=${status || "unknown"}`,
|
||||
);
|
||||
return events;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async ensureSession(input: AcpRuntimeEnsureInput): Promise<AcpRuntimeHandle> {
|
||||
const sessionName = asTrimmedString(input.sessionKey);
|
||||
if (!sessionName) {
|
||||
@ -264,45 +424,80 @@ export class AcpxRuntime implements AcpRuntime {
|
||||
const cwd = asTrimmedString(input.cwd) || this.config.cwd;
|
||||
const mode = input.mode;
|
||||
const resumeSessionId = asTrimmedString(input.resumeSessionId);
|
||||
const ensureSubcommand = resumeSessionId
|
||||
? ["sessions", "new", "--name", sessionName, "--resume-session", resumeSessionId]
|
||||
: ["sessions", "ensure", "--name", sessionName];
|
||||
const ensureCommand = await this.buildVerbArgs({
|
||||
agent,
|
||||
cwd,
|
||||
command: ensureSubcommand,
|
||||
});
|
||||
|
||||
let events = await this.runControlCommand({
|
||||
args: ensureCommand,
|
||||
cwd,
|
||||
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
||||
});
|
||||
let ensuredEvent = events.find(
|
||||
(event) =>
|
||||
asOptionalString(event.agentSessionId) ||
|
||||
asOptionalString(event.acpxSessionId) ||
|
||||
asOptionalString(event.acpxRecordId),
|
||||
);
|
||||
|
||||
if (!ensuredEvent && !resumeSessionId) {
|
||||
const newCommand = await this.buildVerbArgs({
|
||||
let events: AcpxJsonObject[];
|
||||
if (resumeSessionId) {
|
||||
events = await this.createNamedSession({
|
||||
agent,
|
||||
cwd,
|
||||
command: ["sessions", "new", "--name", sessionName],
|
||||
sessionName,
|
||||
resumeSessionId,
|
||||
});
|
||||
events = await this.runControlCommand({
|
||||
args: newCommand,
|
||||
cwd,
|
||||
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
||||
});
|
||||
ensuredEvent = events.find(
|
||||
(event) =>
|
||||
asOptionalString(event.agentSessionId) ||
|
||||
asOptionalString(event.acpxSessionId) ||
|
||||
asOptionalString(event.acpxRecordId),
|
||||
} else {
|
||||
try {
|
||||
events = await this.runControlCommand({
|
||||
args: await this.buildVerbArgs({
|
||||
agent,
|
||||
cwd,
|
||||
command: ["sessions", "ensure", "--name", sessionName],
|
||||
}),
|
||||
cwd,
|
||||
fallbackCode: "ACP_SESSION_INIT_FAILED",
|
||||
});
|
||||
} catch (error) {
|
||||
const recovered = await this.recoverEnsureFailure({
|
||||
sessionName,
|
||||
agent,
|
||||
cwd,
|
||||
error,
|
||||
});
|
||||
if (!recovered) {
|
||||
throw error;
|
||||
}
|
||||
events = recovered;
|
||||
}
|
||||
}
|
||||
if (events.length === 0) {
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession returned no events after sessions ensure: session=${sessionName} agent=${agent} cwd=${cwd}`,
|
||||
);
|
||||
}
|
||||
let ensuredEvent = findSessionIdentifierEvent(events);
|
||||
|
||||
if (
|
||||
ensuredEvent &&
|
||||
!resumeSessionId &&
|
||||
(await this.shouldReplaceEnsuredSession({
|
||||
sessionName,
|
||||
agent,
|
||||
cwd,
|
||||
}))
|
||||
) {
|
||||
events = await this.createNamedSession({
|
||||
agent,
|
||||
cwd,
|
||||
sessionName,
|
||||
});
|
||||
if (events.length === 0) {
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession returned no events after replacing dead session: session=${sessionName} agent=${agent} cwd=${cwd}`,
|
||||
);
|
||||
}
|
||||
ensuredEvent = findSessionIdentifierEvent(events);
|
||||
}
|
||||
|
||||
if (!ensuredEvent && !resumeSessionId) {
|
||||
events = await this.createNamedSession({
|
||||
agent,
|
||||
cwd,
|
||||
sessionName,
|
||||
});
|
||||
if (events.length === 0) {
|
||||
this.logger?.warn?.(
|
||||
`acpx ensureSession returned no events after sessions new: session=${sessionName} agent=${agent} cwd=${cwd}`,
|
||||
);
|
||||
}
|
||||
ensuredEvent = findSessionIdentifierEvent(events);
|
||||
}
|
||||
if (!ensuredEvent) {
|
||||
throw new AcpRuntimeError(
|
||||
"ACP_SESSION_INIT_FAILED",
|
||||
|
||||
@ -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";
|
||||
@ -76,6 +76,17 @@ const setValue = command === "set" ? String(args[commandIndex + 2] || "") : "";
|
||||
|
||||
if (command === "sessions" && args[commandIndex + 1] === "ensure") {
|
||||
writeLog({ kind: "ensure", agent, args, sessionName: ensureName });
|
||||
if (process.env.MOCK_ACPX_ENSURE_EXIT_1 === "1") {
|
||||
emitJson({
|
||||
jsonrpc: "2.0",
|
||||
id: null,
|
||||
error: {
|
||||
code: -32603,
|
||||
message: "mock ensure failure",
|
||||
},
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
if (process.env.MOCK_ACPX_ENSURE_EMPTY === "1") {
|
||||
emitJson({ action: "session_ensured", name: ensureName });
|
||||
} else {
|
||||
@ -173,11 +184,14 @@ if (command === "set") {
|
||||
|
||||
if (command === "status") {
|
||||
writeLog({ kind: "status", agent, args, sessionName: sessionFromOption });
|
||||
const status = process.env.MOCK_ACPX_STATUS_STATUS || (sessionFromOption ? "alive" : "no-session");
|
||||
const summary = process.env.MOCK_ACPX_STATUS_SUMMARY || "";
|
||||
emitJson({
|
||||
acpxRecordId: sessionFromOption ? "rec-" + sessionFromOption : null,
|
||||
acpxSessionId: sessionFromOption ? "sid-" + sessionFromOption : null,
|
||||
agentSessionId: sessionFromOption ? "inner-" + sessionFromOption : null,
|
||||
status: sessionFromOption ? "alive" : "no-session",
|
||||
status,
|
||||
...(summary ? { summary } : {}),
|
||||
pid: 4242,
|
||||
uptime: 120,
|
||||
});
|
||||
@ -382,6 +396,9 @@ export async function readMockRuntimeLogEntries(
|
||||
export async function cleanupMockRuntimeFixtures(): Promise<void> {
|
||||
delete process.env.MOCK_ACPX_LOG;
|
||||
delete process.env.MOCK_ACPX_CONFIG_SHOW_AGENTS;
|
||||
delete process.env.MOCK_ACPX_ENSURE_EXIT_1;
|
||||
delete process.env.MOCK_ACPX_STATUS_STATUS;
|
||||
delete process.env.MOCK_ACPX_STATUS_SUMMARY;
|
||||
sharedMockCliScriptPath = null;
|
||||
logFileSequence = 0;
|
||||
while (tempDirs.length > 0) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { registerSingleProviderPlugin } from "../../src/test-utils/plugin-registration.js";
|
||||
import { registerSingleProviderPlugin } from "../../test/helpers/extensions/plugin-registration.js";
|
||||
import amazonBedrockPlugin from "./index.js";
|
||||
|
||||
describe("amazon-bedrock provider plugin", () => {
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import { emptyPluginConfigSchema, type OpenClawPluginApi } from "openclaw/plugin-sdk/core";
|
||||
import { definePluginEntry } from "openclaw/plugin-sdk/core";
|
||||
|
||||
const PROVIDER_ID = "amazon-bedrock";
|
||||
const CLAUDE_46_MODEL_RE = /claude-(?:opus|sonnet)-4(?:\.|-)6(?:$|[-.])/i;
|
||||
|
||||
const amazonBedrockPlugin = {
|
||||
export default definePluginEntry({
|
||||
id: PROVIDER_ID,
|
||||
name: "Amazon Bedrock Provider",
|
||||
description: "Bundled Amazon Bedrock provider policy plugin",
|
||||
configSchema: emptyPluginConfigSchema(),
|
||||
register(api: OpenClawPluginApi) {
|
||||
register(api) {
|
||||
api.registerProvider({
|
||||
id: PROVIDER_ID,
|
||||
label: "Amazon Bedrock",
|
||||
@ -18,6 +17,4 @@ const amazonBedrockPlugin = {
|
||||
CLAUDE_46_MODEL_RE.test(modelId.trim()) ? "adaptive" : undefined,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default amazonBedrockPlugin;
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user