Compare commits

..

769 Commits

Author SHA1 Message Date
Peter Steinberger
478b599e9b refactor: extract secrets core package 2026-05-30 19:14:25 -04:00
Vincent Koc
0b0edcdf1c fix(scripts): fail gauntlet on missing qa summaries 2026-05-31 00:37:48 +02:00
Peter Steinberger
57c88dd46e chore: remove more unused internal helpers 2026-05-30 23:26:29 +01:00
Peter Steinberger
654de643e4 perf: skip idle channel shutdown enumeration 2026-05-30 23:21:54 +01:00
Vincent Koc
ee2b90b4e2 perf(scripts): prebuild qa runtime assets 2026-05-31 00:17:39 +02:00
Jerry-Xin
f59fc0d477 fix(gateway): strip spurious tool calls on non-tool stops
Treat OpenAI-compatible streaming tool deltas as executable only when the final finish reason is `tool_calls`. This prevents malformed provider streams from triggering spurious tool execution while preserving normal tool-call responses.

Fixes #85161.

Verification:
- Local OpenAI-compatible SSE replay: spurious stop stream `finalToolCalls: 0`; valid tool-call stream `finalToolCalls: 1`.
- `pnpm test src/agents/openai-transport-stream.test.ts src/llm/providers/openai-completions.test.ts -- --reporter=verbose`
- PR CI green on `cdc2fc34753492c862cae99b37f8cf3761d9bbed`.

Co-authored-by: 忻役 <xinyi@mininglamp.com>
Co-authored-by: Jerry-Xin <jerryxin0@gmail.com>
2026-05-30 23:14:16 +01:00
Ted Li
1cab722fe0 fix(ci): ignore fenced headings in proof parser (#87390)
Harden real behavior proof parsing for fenced transcript Markdown. Ref #87341. Thanks @MonkeyLeeT.
2026-05-30 23:14:06 +01:00
Peter Steinberger
4739f0cfe2 chore: remove old unused helpers 2026-05-30 23:13:43 +01:00
Andy Ye
2442e9c178 fix(cron): preserve plugin delivery targets
Preserve plugin-resolved cron delivery targets after target resolution so provider-looking canonical target prefixes are not stripped before outbound delivery.

Adds regression coverage for plugin canonical targets returned directly and via aliases, plus a guard that generic normalized fallback targets still strip the selected prefix.

Fixes #87905

Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com>
2026-05-30 23:12:45 +01:00
Peter Steinberger
0ac61072b8 Refactor cron migrations under doctor (#88455)
* refactor: move cron migrations under doctor

* fix: break cron run log parser type cycle
2026-05-30 23:09:09 +01:00
Peter Steinberger
31099ccb1f docs(changelog): refresh 2026.5.30 notes 2026-05-30 23:04:23 +01:00
Peter Steinberger
2d23519c77 fix(agents): preserve generated media fallback routing 2026-05-30 23:03:32 +01:00
Peter Steinberger
bbd2854c45 fix: show chat errors as visible messages
Surface gateway chat failures as visible assistant messages in the Control UI, with regression coverage and Crabbox/WebVNC proof.

(cherry picked from commit 31a46638ad)
2026-05-30 23:03:32 +01:00
Josh Avant
5d3a6909fb fix subagent dm completion delivery (#88182)
(cherry picked from commit 00d87c7b5d)
2026-05-30 23:03:32 +01:00
Peter Steinberger
1e0c9d8174 test(wizard): include tokenjuice optional plugin
(cherry picked from commit dd658474a5)
2026-05-30 23:03:32 +01:00
Peter Steinberger
4c16bd2453 fix(codex-supervisor): satisfy release lint
(cherry picked from commit bac13419a6)
2026-05-30 23:03:32 +01:00
Steven
cd3d960ec5 fix(ui): add agent selector to dreaming tab (#78748)
Fixes #63558.

Adds a Dreaming-tab agent selector and propagates the selected agent through Dreaming status, diary, and diary actions while preserving default-agent fallback when agentId is omitted. Also keeps report Memory Palace cards in the Control UI wiki-preview flow and documents the optional Dreaming agentId gateway parameters.

Verification:
- GitHub CI run 26693682975 passed on 43a2b17243.
- CodeQL Critical Quality run 26693682971 passed.
- CodeQL / Security High run 26693682957 passed.
- Workflow Sanity run 26693682949 passed.
- OpenGrep PR Diff run 26693682947 passed.
- Dependency Guard run 26693682003 passed.
- Real behavior proof run 26693860539 passed.
- git diff --check origin/main...refs/remotes/origin/pr/78748 passed.
- git merge-tree --write-tree origin/main refs/remotes/origin/pr/78748 passed.

Thanks @stevenepalmer.

Co-authored-by: Steven Palmer <6134396+stevenepalmer@users.noreply.github.com>
2026-05-30 22:58:00 +01:00
Peter Steinberger
d93394e29b perf: cache validated session prompt blobs 2026-05-30 22:57:30 +01:00
Peter Steinberger
83dff5855e docs: trim release performance report tail 2026-05-30 22:54:35 +01:00
Peter Steinberger
3402477314 chore: remove unused infra helpers 2026-05-30 22:45:22 +01:00
Peter Steinberger
71b3bc87ca perf: cache serialized session prompt refs 2026-05-30 22:44:11 +01:00
Peter Steinberger
0be3ef5a38 chore: remove unused agent helpers 2026-05-30 22:43:09 +01:00
Peter Steinberger
287687da20 feat: add internal code mode namespaces (#88043)
* feat: add internal code mode namespaces

* test: add code mode namespace live proof

* test: add live code mode Docker repro

* chore: keep code mode docker repro out of package scripts

* fix: break code mode namespace type cycle

* fix: clean code mode namespace ci drift

* fix: route code mode namespaces through tools

* fix: preserve explicit agent global sessions

* docs: explain code mode namespace registry

* test: cap realtime websocket payload

* fix: normalize code mode timeout results

* fix: satisfy code mode timeout lint

* chore: rerun code mode CI

* ci: extend node shard silence watchdog

* test: avoid child process mock deadlocks

* test: fix code mode repro shebang

* fix: scope explicit agent sentinel sessions

* test: preserve child process mock actual loader

* fix: dispatch namespace tools by exact id

* test: satisfy restart execFile mock type
2026-05-30 22:42:57 +01:00
Peter Steinberger
22e4289d3f chore(release): update appcast for 2026.5.28
Promote the Sparkle appcast generated by macOS publish for v2026.5.28.
2026-05-30 22:39:55 +01:00
Vincent Koc
5367ef7bd3 fix(scripts): accept forwarded otel smoke args 2026-05-30 23:37:27 +02:00
Peter Steinberger
598e177e12 chore: remove unused changelog helper 2026-05-30 22:36:09 +01:00
Peter Steinberger
0ed9fb48c4 docs: refresh release performance sweep for 2026.5.28 2026-05-30 22:35:45 +01:00
Jason (Json)
3ea911558c fix: promote serialized tool calls via repair package
Extracts serialized plaintext tool-call parsing, scrubbing, stream normalization, and standalone promotion into the private internal @openclaw/tool-call-repair package.

Provider wrappers and the embedded runner now share one repair path for standalone serialized tool calls, including adjacent text-block splits, while preserving exact argument bytes when already valid. The public plugin SDK payload module remains as the compatibility facade.

Verification:
- pnpm test src/plugin-sdk/provider-stream-shared.test.ts src/plugin-sdk/tool-payload.test.ts src/agents/embedded-agent-runner/run/attempt.tool-call-normalization.test.ts -- --reporter=verbose
- env -u OPENCLAW_TESTBOX pnpm check:changed
- PR CI: all reported checks green/skipped/neutral on ff0b3c0a5c

Refs #86924

Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-05-30 22:34:57 +01:00
Yossi Eliaz
443255461c fix(slack): preserve assistant DM root thread context (#63840)
Preserve Slack Agents & Assistants DM root thread context for tool and subagent replies even when Slack omits or misreports `channel_type`, while leaving non-DM self-thread roots top-level.

Fixes #63659.

Thanks @zozo123.
2026-05-30 22:28:49 +01:00
Vincent Koc
7dde396d4d fix(scripts): accept forwarded watch regression args 2026-05-30 23:20:16 +02:00
Jason (Json)
89975eea24 feat: pass structured provider error signals to hooks
Summary:
- Pass provider status/code/type descriptors through failover hook classification.
- Keep structured provider hook dispatch scoped, while preserving legacy broad message-hook fallback for unresolved custom provider ids.
- Isolate long commands/infra Vitest lanes in fork workers and update config expectations.

Verification:
- node scripts/run-vitest.mjs src/agents/embedded-agent-helpers/errors-provider-structured-signals.test.ts src/agents/failover-error.test.ts
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs src/plugins/provider-runtime.test.ts
- node scripts/run-vitest.mjs src/agents/embedded-agent-helpers/errors-provider-structured-signals.test.ts src/agents/embedded-agent-helpers/provider-error-patterns.test.ts src/agents/failover-error.test.ts src/plugins/provider-runtime.test.ts test/vitest-projects-config.test.ts test/vitest-scoped-config.test.ts src/infra/vitest-config.test.ts
- pnpm tsgo:prod
- autoreview --mode branch --base origin/main --no-web-search --thinking low
- GitHub required dependency-guard: pass
- GitHub Real behavior proof: pass
- GitHub broad CI/checks visible on PR: pass

Co-authored-by: Jason (Json) <fuller-stack-dev@users.noreply.github.com>
2026-05-30 22:14:46 +01:00
zhang-guiping
dbd3e10312 fix(ui): filter sidebar recent sessions by selected agent
Fixes #88214.

Control UI dashboard Recent sessions now follows the selected agent, preserves legacy main sessions under stale identity, keeps unknown sessions unscoped, and scopes agent/default session refreshes before the session-list limit. Completed run refreshes now use the run's original session/agent target, global New Chat creates under the selected agent, and the agent switcher preserves last known target sessions across scoped refreshes without resurrecting deleted or archived sessions while accepting newer out-of-scope live rows into the switch cache. Also fixes a current-main lint issue around trusted approval params.

Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
2026-05-30 22:13:37 +01:00
Vincent Koc
8b50cdd151 ci: update remaining Testbox actions 2026-05-30 22:11:51 +01:00
Peter Steinberger
a825b5576b refactor: simplify sqlite cron persistence 2026-05-30 22:11:17 +01:00
summerview1997
76b300babc Fix /acp spawn cwd inheritance for target agent workspaces (#82415)
* Fix ACP spawn cwd inheritance

* Share ACP spawn cwd guard with command path

* Fix ACP spawn cwd typing and temp dir test

* test: stabilize crabbox wrapper provider fixtures

---------

Co-authored-by: Thomas Yao <thomas@local>
2026-05-30 22:11:06 +01:00
Vincent Koc
ada22739be perf(build): skip dts for runtime build profiles 2026-05-30 23:06:25 +02:00
Peter Steinberger
8fe50a2136 build: classify release dependency ownership
Classify release dependency ownership metadata so release evidence no longer reports current root dependencies as missing ownership metadata. Also recognizes command-explainer package-file lookups for tree-sitter-bash.

Verification: jq empty scripts/lib/dependency-ownership.json; node scripts/dependency-ownership-surface-report.mjs --check; node scripts/root-dependency-ownership-audit.mjs --check; targeted Vitest for root dependency ownership and ownership surface reports; git diff --check; autoreview clean; PR CI green including Real behavior proof.
2026-05-30 22:04:54 +01:00
Peter Steinberger
b374505e7a refactor: source model catalog types from core
Source model catalog SDK types from @openclaw/model-catalog-core while preserving released compat fields and sanitized routing normalization.
2026-05-30 22:00:51 +01:00
zhang-guiping
653292901a fix(tui): surface terminal lifecycle errors
Surface terminal TUI lifecycle errors after the chat stream ends, deduplicate delayed chat errors, and allow explicit runnable Vitest config targets to run through the target planner.

Fixes #85782.

Verification:
- pnpm exec oxfmt --check src/tui/tui-event-handlers.ts src/tui/tui-event-handlers.test.ts test/scripts/test-projects.test.ts scripts/test-projects.test-support.mjs src/agents/model-catalog-visibility.test.ts
- node scripts/run-vitest.mjs src/tui/tui-event-handlers.test.ts
- node scripts/run-vitest.mjs src/tui/tui-event-handlers.test.ts src/tui/tui-command-handlers.test.ts test/scripts/test-projects.test.ts src/agents/model-catalog-visibility.test.ts
- git diff --check
- autoreview --mode local: no accepted/actionable findings
- autoreview --mode branch --base origin/main: no accepted/actionable findings
- Required CI check dependency-guard passed

Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-05-30 21:59:27 +01:00
Peter Steinberger
3f50485156 perf: cache manifest model suppression resolver 2026-05-30 21:56:38 +01:00
Vincent Koc
9c2744f1e1 test(scripts): require usable memory search in fd repro 2026-05-30 22:48:50 +02:00
brokemac79
3aa460409e fix: route denied exec approval followups to sessions
Routes denied async exec approval followups through the originating main session before using direct external fallback. Keeps strict inline-eval timeout denials fail-closed, while preserving suppression for subagent, cron, and no-session denial cases.

Refs #88167.

Verification:
- git diff --check origin/main...refs/remotes/pr/88417
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- gh pr checks 88417 --repo openclaw/openclaw --watch=false

Co-authored-by: brokemac79 <martin_cleary@yahoo.co.uk>
2026-05-30 21:45:16 +01:00
Thomas Krohnfuß
48980a0f41 fix(responses): drop orphaned assistant msg_* id when reasoning is dropped (#88019) (#88067)
* fix(responses): drop orphaned assistant msg_* id when reasoning is dropped (#88019)

When an Azure/OpenAI Responses session falls back to a non-Responses model
and later resumes a Responses model, sanitizeSessionHistory drops the
replayable reasoning (rs_*) item via downgradeOpenAIReasoningBlocks. The
paired assistant text block still carried its textSignature (the msg_* id),
so the transport replayed an assistant message item referencing msg_* with
no accompanying rs_* reasoning item. Azure Responses then rejected the next
turn with:

  400 Item 'msg_...' provided without its required 'reasoning' item: 'rs_...'

permanently poisoning the session.

Fix:
- downgradeOpenAIReasoningBlocks now strips the textSignature from a turn's
  text blocks whenever it drops a replayable reasoning item, so the msg_* id
  and its rs_* reasoning are removed together. The transport then falls back
  to a synthetic, unpaired id that Azure accepts.
- Because the synthetic fallback id is derived from the per-message msgIndex,
  multiple id-less text blocks in one assistant turn (e.g. commentary +
  final_answer) would collide on the same id. Make the fallback unique per
  text block in both Responses conversion sites
  (openai-transport-stream.ts and the shared llm provider
  openai-responses-shared.ts).

Tests:
- sanitize-session-history: model-switch path drops the paired msg_* id.
- embedded-agent-helpers: downgrade strips paired text signature(s).
- reasoning-replay: multiple id-less text blocks get distinct item ids.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(responses): preserve phase metadata and guard malformed blocks (#88019)

Address PR review feedback on the orphaned msg_* replay fix:

- Preserve Responses phase metadata: dropping the paired msg_* id when its
  rs_* reasoning is removed previously stripped the entire textSignature,
  which also discarded the phase (commentary/final_answer). Phased text now
  keeps a phase-only signature ({v:1,phase}) so commentary is not replayed
  as user-visible output. Both parseTextSignature copies (shared provider and
  embedded transport) now accept id-less phase-only signatures and fall back
  to a synthetic id while preserving the phase.
- Guard malformed content blocks: the post-drop map no longer dereferences
  contentBlock.type unconditionally, so a corrupted transcript with a
  null/primitive block can still sanitize through a model switch.

Tests:
- sanitize-session-history: phase metadata is preserved while the paired id
  is dropped on a model switch.
- reasoning-replay: id-less phase-only signatures get distinct synthetic ids
  and retain their phase.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-30 21:45:08 +01:00
Ashd.LW.
eb170a0adb fix(agents): extend payload-less session lock grace
Payload-less session write-lock files now get a 30s grace for default/long acquire timeouts and cleanup sweeps, while short acquire timeouts keep 5s recovery. This avoids reclaiming a lock while the owner is suspended between exclusive create and metadata write.

Verified with:
- git diff --check origin/main...HEAD
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --parallel-tests "node scripts/run-vitest.mjs src/agents/session-write-lock.test.ts"
- gh pr checks 80686 --repo openclaw/openclaw --watch=false

Thanks @wAngByg.
2026-05-30 21:42:57 +01:00
Han Kim
b7232db1b0 test(gateway): avoid brittle shutdown timer assertion
Co-authored-by: Han Kim <han.kim@Bowcaster.local>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-05-30 21:39:49 +01:00
Peter Steinberger
a20b2dc740 refactor: extract web content core package (#88346)
Extract web-content shared runtime helpers into packages/web-content-core, move the focused tests with the new package, and split quiet CI shards so the node matrix no longer stalls past the no-output watchdog.\n\nVerification: node scripts/run-vitest.mjs test/scripts/ci-node-test-plan.test.ts test/scripts/run-vitest.test.ts src/infra/restart.test.ts src/infra/os-summary.test.ts src/infra/gateway-processes.test.ts src/infra/inline-option-token.test.ts src/infra/map-size.test.ts src/infra/machine-name.test.ts src/commands/doctor-whatsapp-responsiveness.test.ts; autoreview clean; manual CI https://github.com/openclaw/openclaw/actions/runs/26693962844; dependency guard https://github.com/openclaw/openclaw/actions/runs/26693959937. Admin merge used because optional Mantis Telegram Desktop proof was cancelled after blocking merge outside this PR's required proof.
2026-05-30 21:38:29 +01:00
Feelw00
c6b1fede5a fix(mcp): bound channel bridge pending approvals
Bound MCP channel bridge pending Claude permission and approval maps with TTL sweep and close cleanup.
Also sweep before listing pending approvals so expired requests are not exposed between periodic ticks.

Fixes #71646.
Thanks @Feelw00.
2026-05-30 21:36:50 +01:00
Zee Zheng
c80ec43325 feat(cli): add sessions tail progress view
Adds `openclaw sessions tail` as an operator-facing progress view over session trajectory events, with conservative redaction for prompt text, tool arguments, and tool result bodies. The command supports explicit session keys, store/agent scope, follow mode, relocated trajectory pointer files, and cursor-safe follow across bounded trajectory window rewrites.

Documents the new sessions tail CLI surface in `docs/cli/sessions.md`.

Fixes #83441.

Co-authored-by: zhengzuo0-ai <zheng.zuo0@gmail.com>
2026-05-30 21:29:39 +01:00
Peter Steinberger
b6891d284d docs(changelog): restore 2026.5.28 release credits 2026-05-30 21:29:16 +01:00
Peter Steinberger
ec78a21e0b docs(changelog): require complete release credits 2026-05-30 21:28:11 +01:00
Peter Steinberger
be3af54f98 perf: fast path session store json parsing 2026-05-30 21:22:14 +01:00
Peter Steinberger
3fc0df953c refactor(agents): bind subagent threads in core (#88416)
Move subagent thread binding ownership into core so session-mode spawns prepare channel bindings before launching the child agent. Deprecate the legacy subagent_spawning SDK hook in code, compatibility metadata, diagnostics, and plugin docs; plugin authors should observe subagent_spawned instead.

Verification:
- node scripts/run-vitest.mjs src/agents/sessions-spawn-hooks.test.ts src/agents/subagent-spawn.thread-binding.test.ts src/agents/subagent-spawn.workspace.test.ts src/agents/subagent-spawn.mode-session-diagnostics.test.ts
- node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode local
- CI run 26693808952 green, including checks-node-agentic-agents-core and checks-node-agentic-plugin-sdk
2026-05-30 21:19:09 +01:00
Nicolas
4ac90a5b48 fix: skip browser cleanup when browser is disabled
Skip browser lifecycle cleanup when root browser support or the browser plugin entry is disabled, and make the browser maintenance facade respect activation before cached surface use.

Also stabilize the resource-only MCP runtime test by waiting for the async rejection log that CI can observe late.

Verification:
- pnpm test src/plugin-sdk/browser-maintenance.test.ts src/browser-lifecycle-cleanup.test.ts src/auto-reply/reply/session.test.ts src/gateway/server.sessions.reset-cleanup.test.ts src/agents/auth-profiles/usage.test.ts
- pnpm test src/agents/agent-bundle-mcp-runtime.test.ts
- git diff --check
- pnpm build
- autoreview local: no accepted/actionable findings
- GitHub Actions: CI 26693713166, CodeQL 26693713159, CodeQL Critical Quality 26693713157, OpenGrep PR Diff 26693713125, Workflow Sanity 26693713149, Dependency Guard 26693712478

Co-authored-by: Nicolas Van Eenaeme <nicolas@poison.be>
2026-05-30 21:16:47 +01:00
Peter Steinberger
39e987314a perf: skip unnecessary setup auth fallback 2026-05-30 21:16:36 +01:00
Peter Steinberger
427df01d4e ci(release): checkout approval helper 2026-05-30 21:13:19 +01:00
Peter Steinberger
50b7a2ffa1 ci(release): allow direct publish recovery 2026-05-30 21:13:19 +01:00
Vincent Koc
b93ed3f93f test(scripts): expose kitchen sink command RSS 2026-05-30 22:10:25 +02:00
Peter Steinberger
a2b2c4a76c refactor(msteams): persist conversation and poll stores in sqlite
Move MSTeams conversation and poll plugin-local stores to plugin-state SQLite. Legacy JSON stores import once without overwriting existing SQLite state; conversation and poll IDs are hashed for plugin-state keys; poll votes are sharded with bounded row-cap headroom and prune cleanup; MSTeams docs now describe SQLite storage. SSO and delegated token stores are unchanged. Verified with focused MSTeams tests, docs sanity, autoreview, Testbox check:changed, and green PR CI.
2026-05-30 21:08:39 +01:00
Feelw00
a9a86f788b fix(agents): dedupe subagent browser session cleanup
Deduplicate the browser lifecycle cleanup wrapper for embedded subagent completions while preserving retire and announce finalization for duplicate callers.\n\nAdds regression coverage for parallel completion callers and the held-first-cleanup duplicate-tail path.\n\nFixes #68668.\n\nCo-authored-by: Feelw00 <dhrtn1006@naver.com>
2026-05-30 21:04:37 +01:00
keshavbotagent
371a8abe9d fix(build): avoid stale agent-core dts warnings (#87915)
* fix(build): avoid stale agent-core dts warnings

* test(secrets): secure plugin entrypoint fixtures

* fix(agent-core): normalize compaction summary timestamps

* test(secrets): secure platform preset fixture

* fix(build): preserve tracked package dts on skip builds

* test(secrets): secure platform preset resolver fixture

* fix(build): keep declarations during skip dts clean

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-30 21:03:49 +01:00
Peter Steinberger
005da57957 Move cron persistence to SQLite (#88285)
* refactor: move cron persistence to sqlite

* fix: repair sqlite cron migration regressions

* fix: move cron legacy migration to doctor

* test: align cron sqlite migration fixtures

* test: fix cron sqlite rebase gates

* test: align cron sqlite runtime tests

* test: fix doctor e2e migration mock

* test: fix doctor shard e2e isolation

* test: fix infra child-process mocks
2026-05-30 21:03:41 +01:00
brokemac79
d11e82aeea fix(ui): keep selected chat model visible after session switch
Fixes #86597. Thanks @brokemac79.
2026-05-30 20:53:47 +01:00
Coder
adcac404e1 fix(llm): repair invalid streaming unicode escapes
Repair invalid \u escapes during streaming JSON parsing without changing valid Unicode escapes. Split oversized node CI doctor/infra shards and fix the restart test mock deadlock so PR CI stays under the no-output threshold.\n\nCo-authored-by: Coder <83845889+coder999999999@users.noreply.github.com>
2026-05-30 20:53:26 +01:00
Vincent Koc
eb5e80f58a ci: update Blacksmith Testbox actions 2026-05-30 20:51:31 +01:00
Peter Steinberger
5891cfec3e refactor: move model catalog normalization into core package
Move model catalog normalization and package-owned catalog schema/types into model-catalog-core while keeping public plugin SDK model catalog declarations on the existing SDK surface. Verified focused tests, package-boundary compile, full build, changed gate, declaration leak grep, CI, and autoreview.
2026-05-30 20:51:11 +01:00
Abner Shang
961691def2 fix(codex): keep app-server continuation turns alive
Keep Codex app-server continuation turns alive after post-tool, raw assistant, and progress notifications, and reschedule continuation idle watches when shorter progress timeouts apply.

Add regression coverage for the plugin-sdk child_process mock helper deadlock that blocked CI shards on this PR.

Co-authored-by: abnershang <abner.shang@gmail.com>
2026-05-30 20:41:04 +01:00
Vincent Koc
2780f540f8 test(agents): wait for MCP method-not-found log 2026-05-30 20:39:52 +01:00
Vincent Koc
37058ad75a fix(scripts): quiet minimal runtime asset copies
Stop minimal cliStartup and gatewayWatch builds from copying generated plugin static assets they intentionally do not build.\n\nVerified with focused Vitest, autoreview, AWS Crabbox startup-memory proof, and AWS Crabbox changed gate run_bd9ea01e6a12 plus rebased changed gate run_bd9ea01e6a12.
2026-05-30 20:38:19 +01:00
Peter Steinberger
37c6e2dfa0 ci: skip codeql network shard for test-only changes 2026-05-30 20:29:19 +01:00
Shakker
473993f73a fix: remove redundant unknown union 2026-05-30 20:28:29 +01:00
Peter Steinberger
e24a9c5457 ci: keep harness changes on fast checks (#88429) 2026-05-30 20:27:59 +01:00
Shakker
d9c0d09f1a chore: remove inert skill workshop package 2026-05-30 20:15:31 +01:00
Peter Steinberger
0c7ab411e5 fix(auth): bound oauth mirror expiry 2026-05-30 15:11:14 -04:00
Alix-007
5811693c7f fix(export-html): guard msg.content and result.content filter/iteration paths against non-array values (#88271)
* fix(export-html): guard all msg.content and result.content filter/iteration paths

Three call sites in the export HTML template called `.filter()` or iterated
with `for...of` directly on `msg.content` or `result.content` without first
checking `Array.isArray`. When a transcript message row carries a non-array
content value (null, undefined, or any scalar), those paths throw:

  TypeError: msg.content.filter is not a function

Fix: normalize with `Array.isArray(x) ? x : []` before every unguarded
filter and iteration on `msg.content` (computeStats stats path and the
renderEntry assistant render loops) and `result.content` (renderToolCall
text/image accessors).

Regression test added: renderTemplate resolves without throwing for assistant
messages with null, undefined, string, and numeric content values.

Closes #88255

* fix(export-html): guard user message text extraction path against non-array content

The user-message render path in the export HTML template extracted text with
`content.filter(...)` without checking whether `content` is an array. A
persisted user message row with null, undefined, or any non-string scalar
content crashed during export with the same TypeError class as the assistant
path.

Fix: normalize the ternary so a non-string, non-array value falls through to
an empty string rather than calling `.filter` on it.

Regression test added for null, undefined, and numeric user message content.

Addresses feedback from ClawSweeper review on #88271.

* fix(export-html): preserve string content guards

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-30 20:10:43 +01:00
Peter Steinberger
445ff22018 fix(agents): bound auth health expiry 2026-05-30 15:09:37 -04:00
Peter Steinberger
602364f1c7 ci: stabilize changed checks 2026-05-30 20:07:38 +01:00
Peter Steinberger
c73e8eedf4 fix(agents): bound discovery auth expiry 2026-05-30 15:07:04 -04:00
Shakker
dcc329ac09 chore: keep skill workshop package manifest inert 2026-05-30 20:04:52 +01:00
Shakker
515d4ffc21 fix: refresh skill workshop CI expectations 2026-05-30 20:04:52 +01:00
Shakker
28290a496f fix: allow concise skill update descriptions 2026-05-30 20:04:52 +01:00
Shakker
3cd368edec fix: approve final skill workshop tool params 2026-05-30 20:04:52 +01:00
Shakker
908fc35b97 fix: preserve trusted policy checks for skill workshop 2026-05-30 20:04:52 +01:00
Shakker
d6d1cc2a3e fix: serialize skill proposal creation limits 2026-05-30 20:04:52 +01:00
Shakker
41044a207c fix: serialize skill proposal lifecycle mutations 2026-05-30 20:04:52 +01:00
Shakker
7d19f89094 fix: harden skill workshop proposal results 2026-05-30 20:04:52 +01:00
Shakker
43e4b9dc1c fix: keep autonomous skill capture opt-in 2026-05-30 20:04:52 +01:00
Shakker
77c6bee421 fix: refresh skill workshop generated surfaces 2026-05-30 20:04:52 +01:00
Shakker
0b49710e8d fix: preserve auto-captured skill updates 2026-05-30 20:04:52 +01:00
Shakker
3a9e7dfa1a fix: bound skill workshop descriptions 2026-05-30 20:04:52 +01:00
Shakker
e4905ce4c9 fix: enforce skill workshop proposal bounds 2026-05-30 20:04:52 +01:00
Shakker
131e662924 fix: scan skill proposal prompt content 2026-05-30 20:04:52 +01:00
Shakker
7051bf16f0 fix: align skill proposal revise validation 2026-05-30 20:04:52 +01:00
Shakker
6eb6730137 refactor: move skill research capture logic 2026-05-30 20:04:52 +01:00
Shakker
2383cfd303 refactor: rename skill workshop agent tool 2026-05-30 20:04:52 +01:00
Shakker
c09e1efe99 fix: clean up skill workshop lint issues 2026-05-30 20:04:52 +01:00
Shakker
308fdbe7fb refactor: remove skill workshop plugin package 2026-05-30 20:04:52 +01:00
Shakker
c5af09e378 refactor: route agent end side effects through harness 2026-05-30 20:04:52 +01:00
Shakker
3037646d22 feat: add skill workshop runtime policy 2026-05-30 20:04:52 +01:00
Shakker
3ea82adf97 fix: show skill proposal support files on inspect 2026-05-30 20:04:52 +01:00
Shakker
bc6d570659 fix: reject non-text skill proposal files 2026-05-30 20:04:52 +01:00
Shakker
f7729028ae fix: guard skill proposal apply writes 2026-05-30 20:04:52 +01:00
Shakker
11d6ce15e8 fix: harden skill proposal boundaries 2026-05-30 20:04:52 +01:00
Shakker
897a7efe15 fix: preserve skill proposal target state 2026-05-30 20:04:52 +01:00
Shakker
fafa4c8b65 fix: scope skill workshop proposal access 2026-05-30 20:04:52 +01:00
Shakker
186182fe9e feat: let skill research manage proposal lifecycle 2026-05-30 20:04:52 +01:00
Shakker
e5455b61c3 feat: let skill research manage proposal discovery 2026-05-30 20:04:52 +01:00
Shakker
e89417d77b fix: keep skill research available to agents 2026-05-30 20:04:52 +01:00
Shakker
e9b0a5f69e feat: revise pending skill proposals 2026-05-30 20:04:52 +01:00
Shakker
339e212c85 fix: expose skill proposal gateway methods 2026-05-30 20:04:52 +01:00
Shakker
199cdc1052 fix: enforce canonical workshop skill names 2026-05-30 20:04:52 +01:00
Shakker
ab0613c9d3 feat: support skill proposal files 2026-05-30 20:04:52 +01:00
Shakker
91ba5fd4fe fix: store skill workshop proposals in state 2026-05-30 20:04:52 +01:00
Shakker
9da7498d31 fix: satisfy skill workshop lint 2026-05-30 20:04:52 +01:00
Shakker
67298c4bd8 fix: satisfy skill workshop changed checks 2026-05-30 20:04:52 +01:00
Shakker
9417a3f39f fix: rebuild corrupt skill proposal manifests 2026-05-30 20:04:52 +01:00
Shakker
1609fcaff3 docs: document skill workshop proposals 2026-05-30 20:04:52 +01:00
Shakker
5205b94d84 feat: expose skill workshop gateway methods 2026-05-30 20:04:52 +01:00
Shakker
7f48ee1e57 feat: add skill research proposal tool 2026-05-30 20:04:52 +01:00
Shakker
c4be8d8730 feat: add skill workshop cli commands 2026-05-30 20:04:52 +01:00
Shakker
bc1c3701c4 feat: add skill workshop proposal store 2026-05-30 20:04:52 +01:00
Peter Steinberger
4e8b74568f refactor: move model catalog refs into core package
Move model catalog ref helpers into @openclaw/model-catalog-core/model-catalog-refs and update internal callers/package-boundary aliases. Also fix the timestamp predicate typing that blocked prod type checks on current main.
2026-05-30 20:04:16 +01:00
Peter Steinberger
b80dcbd650 fix(plugin-sdk): bound copilot token expiry 2026-05-30 15:04:03 -04:00
Peter Steinberger
417aba7b9b fix(infra): bound session delivery recovery deadline 2026-05-30 15:02:02 -04:00
Peter Steinberger
ed63523db9 test(release): expect public latest in installer smoke 2026-05-30 20:01:22 +01:00
Peter Steinberger
677f7c80dc fix(plugin-sdk): bound oauth result expiry 2026-05-30 14:59:59 -04:00
Vincent Koc
231d0b28bd fix(agents): harden message dts and block timestamps 2026-05-30 20:58:21 +02:00
Peter Steinberger
979907e004 fix(outbound): bound delivery recovery deadline 2026-05-30 14:57:47 -04:00
Peter Steinberger
9eb17a0277 fix(shared): bound epoch expiry helpers 2026-05-30 14:55:37 -04:00
Peter Steinberger
06e0fd3347 fix(media): bound provider operation deadlines 2026-05-30 14:54:03 -04:00
Peter Steinberger
51cceaf70c fix(agents): bound run drain deadlines 2026-05-30 14:51:59 -04:00
Peter Steinberger
471164afbd fix(github-copilot): bound device code expiry 2026-05-30 14:49:34 -04:00
Peter Steinberger
99ce71ddbb feat: improve MCP operability
Summary:
- Add MCP status, probe, and projected-tools CLI surfaces.
- Add per-server MCP tool filters plus resource/prompt utility projection.
- Harden MCP runtime discovery, listChanged invalidation, request-failure backoff, and metadata sanitization.
- Preserve current main type health by narrowing the shared future timestamp guard.

Verification:
- pnpm test src/shared/number-coercion.test.ts src/agents/auth-profiles/usage.test.ts src/cli/mcp-cli.test.ts src/agents/agent-bundle-mcp-runtime.test.ts src/agents/agent-bundle-mcp-tools.materialize.test.ts -- --reporter=verbose
- pnpm lint
- pnpm tsgo:prod
- pnpm build
- git diff --check origin/main...HEAD
- GitHub Actions: dependency-guard, real behavior proof, security high MCP boundary, build/lint/types/guards/docs, gateway/plugin/agent shards green on PR head.

Known proof gap:
- Existing checks-node-agentic-commands-doctor no-output watchdog reproduced locally outside touched paths.
2026-05-30 19:48:52 +01:00
Peter Steinberger
9cb9851bf8 fix(models): bound pasted token expiry 2026-05-30 14:47:41 -04:00
Peter Steinberger
2b31c02163 fix(plugins): bound scheduled turn delays 2026-05-30 14:44:24 -04:00
Coder
878e433d81 fix(skill-creator): sort .skill entries deterministically
Fixes #37748.

Sort skill package archive entries by relative POSIX archive name so generated `.skill` bundles are reproducible regardless of filesystem traversal order.

Verification:
- `PYTHONDONTWRITEBYTECODE=1 python3 skills/skill-creator/scripts/test_package_skill.py`
- `git diff --check origin/main...HEAD`
- GitHub CI run 26690938925 on `43a0fdf7175f33a5c74bc7ff92723ebf5efc4df9`: all checks passed except repeated unrelated no-output timeouts in `checks-node-agentic-commands-doctor` and `checks-node-core-runtime-infra-state` after visible tests passed.
2026-05-30 19:42:55 +01:00
Peter Steinberger
dfbed5053a fix(qqbot): bound reminder schedule time 2026-05-30 14:41:39 -04:00
Peter Steinberger
caac9733a7 fix(memory): bound qmd embed backoff 2026-05-30 14:39:33 -04:00
Peter Steinberger
6399b6a445 fix(discord): bound timeout member expiry 2026-05-30 14:34:40 -04:00
Peter Steinberger
472606de9b fix(qqbot): skip token cache on invalid clock 2026-05-30 14:33:04 -04:00
Peter Steinberger
177496552b fix(infra): bound device bootstrap expiry 2026-05-30 14:31:30 -04:00
Peter Steinberger
e0248fc11f fix(cron): bound relative at timestamps 2026-05-30 14:29:39 -04:00
Peter Steinberger
6a753ade78 fix(crestodian): bound rescue approval expiry 2026-05-30 14:28:25 -04:00
Peter Steinberger
53812bd8aa fix(agents): bound codex cli fallback expiry 2026-05-30 14:26:17 -04:00
Lellansin Huang
fe3c3ac5cd fix(gateway): forward stop sequences across providers
Forward OpenAI-compatible stop sequences from gateway chat completions through the agent runner into provider transports.

The gateway now normalizes stop into sampling extras, agent transports pass it into the shared stream options, and OpenAI, Anthropic, Mistral, Google, and Vertex-backed simple providers map it to their native request fields. Provider/gateway/agent coverage plus Crabbox live gateway proof verify valid stop dispatch and invalid stop rejection.

Refs #87920
2026-05-30 19:24:21 +01:00
Peter Steinberger
5435b453ca feat: expand workboard orchestration metadata (#88408) 2026-05-30 19:22:19 +01:00
Peter Steinberger
abc26b072b fix(discord): bound rest rate-limit deadlines 2026-05-30 14:22:16 -04:00
Jiatai Wang
64533bab65 fix(agents): show exec target node in tool display
Show the remote node name in exec tool transparency details when an exec call targets `host=node`, while ignoring stray `node` values for gateway, sandbox, and auto-host calls.

Covers node-only, cwd+node, absent-node, and non-node-host regression cases in the tool display tests.

Fixes #77719.

Co-authored-by: JiataiWang <wangjiatai@proton.me>
2026-05-30 19:19:17 +01:00
Peter Steinberger
7d4bf8f285 fix(telegram): bound transport cooldown expiry 2026-05-30 14:16:57 -04:00
Peter Steinberger
bdb0fde0ea test(release): harden live release checks 2026-05-30 19:14:27 +01:00
Peter Steinberger
926a165a52 fix(anthropic): bound setup token expiry 2026-05-30 14:14:13 -04:00
Peter Steinberger
70b6fdd149 fix(bedrock): bound mantle runtime token expiry 2026-05-30 14:09:59 -04:00
Peter Steinberger
9ad7f5bbde fix(agents): bound sqlite cache expiry 2026-05-30 14:07:32 -04:00
Peter Steinberger
1ee751ddb1 fix(agents): bound google prompt cache expiry 2026-05-30 14:02:50 -04:00
Peter Steinberger
30e3ca08a5 fix(agents): bound auth profile block expiry 2026-05-30 14:00:46 -04:00
Peter Steinberger
1f6c1eacf0 fix(telegram): bound error cooldown expiry 2026-05-30 13:59:06 -04:00
Peter Steinberger
8654353be8 fix(discord): bound component registry expiry 2026-05-30 13:57:13 -04:00
Peter Steinberger
c5aa3ff02f fix(msteams): bound delegated token probe expiry 2026-05-30 13:54:56 -04:00
Peter Steinberger
5fde637ba8 fix(codex): bound app inventory cache expiry 2026-05-30 13:53:13 -04:00
guanbear
044f5a814e Expose subagent resolved model metadata (#80037)
Co-authored-by: guanbear <guanbear@macmini.bearhome>
2026-05-30 18:52:21 +01:00
Peter Steinberger
3ae521745e fix(voice-call): bound webhook replay cache expiry 2026-05-30 13:51:12 -04:00
Peter Steinberger
f89f5d930f fix(gateway): bound system run event expiry 2026-05-30 13:49:03 -04:00
Vincent Koc
13c77f00c3 fix(agents): classify code mode deadline interrupts 2026-05-30 18:47:42 +01:00
chuanchuan
3b8ab4e112 fix(feishu): stream plain replies as cards
Feishu `channels.feishu.streaming=true` now streams ordinary assistant replies through CardKit in auto mode, while keeping tool-summary delivery on the existing message path.

Also discards stale partial previews when final delivery intentionally suppresses text for voice media or duplicate final text, and preserves streamed partial text for regular media-only finals.

Verification:
- `node scripts/run-vitest.mjs run extensions/feishu/src/reply-dispatcher.test.ts`
- `pnpm tsgo:extensions`
- `pnpm test:extensions:package-boundary:compile`
- `pnpm exec oxfmt --check extensions/feishu/src/reply-dispatcher.ts extensions/feishu/src/reply-dispatcher.test.ts extensions/feishu/src/streaming-card.ts`
- `git diff --check`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`
- GitHub PR checks on run 26689677607 passed except repeated unrelated broad Vitest no-output timeouts in `checks-node-agentic-commands-doctor` and `checks-node-core-runtime-infra-state`.

Co-authored-by: 传妈 <chuanmother@chuanMac-Mini.local>
2026-05-30 18:47:03 +01:00
Peter Steinberger
ca4a12381a fix(gateway): bound chat abort expiry registration 2026-05-30 13:46:16 -04:00
Steven
86e33d6985 fix(models): preserve exact provider refs before aliases
Fixes #88218.

Preserves exact configured provider/model defaults before bare alias target reverse matches, while retaining slash-form aliases and auth-profile alias behavior.

Co-authored-by: Steven Palmer <palmer.e.steven@gmail.com>
2026-05-30 18:46:11 +01:00
Peter Steinberger
9ef699fedc fix(gateway): bound maintenance run expiry checks 2026-05-30 13:43:21 -04:00
Peter Steinberger
912a276ca1 fix(gateway): bound talk handoff expiry 2026-05-30 13:41:14 -04:00
Brian
6f20f29688 fix(discord): carry reply typing feedback through queue
Carry Discord reply typing feedback through preflight, queued dispatch, and cleanup so delayed accepted replies keep typing alive at the actual dispatch target without duplicate keepalives. Adds focused Discord queue/process policy coverage and stronger lifecycle invariant comments.
2026-05-30 18:39:39 +01:00
Merlin
b6d253eefb fix(discord): omit undefined component registry fields
Prunes undefined Discord component and modal registry metadata before persisting it so SQLite-backed plugin state never receives JSON-incompatible undefined values. Adds direct regression coverage for undefined own properties on component, modal, and nested field entries.
2026-05-30 18:39:26 +01:00
Peter Steinberger
0a87f6e4ad fix(gateway): bound node pending work expiry 2026-05-30 13:38:54 -04:00
Ashd.LW.
bc77f7a00a fix(gateway): explain ignored restart signal
Add actionable operator guidance when an unauthorized SIGUSR1 gateway restart is ignored because unmanaged restart is disabled.

The change is log-only: restart authorization and scheduling semantics are unchanged, and the existing run-loop test now asserts both the reason warning and the recovery hint.

Refs #79577
Refs #78110
Refs #82433

Co-authored-by: wAngByg <281221101+wAngByg@users.noreply.github.com>
2026-05-30 18:38:35 +01:00
ToToKr
9e3d5310cc fix(media): dedupe duplicate inbound media path urls
Dedupe prompt-side inbound media note suffixes when sanitized MediaPath and MediaUrl render to the same value, while preserving genuinely distinct remote URLs.\n\nFixes #47587.\nThanks @MoerAI for the patch and @yzjJosh for the report.
2026-05-30 18:37:42 +01:00
Peter Steinberger
4d9366fecb fix(gateway): bound plugin node capability expiry 2026-05-30 13:35:43 -04:00
Sebastien Tardif
1c9851e115 fix(install): show npm install progress without gum
Show the same Installing OpenClaw package progress line in the no-gum npm install fallback before redirecting npm output to the temp log.

Fixes #82305

Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
2026-05-30 18:35:32 +01:00
Peter Steinberger
a4f62400a7 fix(commitments): bound terminal failure cooldown expiry 2026-05-30 13:33:06 -04:00
吴杨帆
8d3fe21b53 test(tasks): cover task domain view mappers (#86755)
Adds focused coverage for task-domain view mapper DTO contracts, including summary cloning, task run/detail mapping, flow view/detail mapping, and implicit summary computation.

Test-only PR. Verified with git diff --check and PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false pnpm test src/tasks/task-domain-views.test.ts on the current-main merge result.

Thanks @leno23.

Co-authored-by: wuyangfan <yangfan.wu@succaiss.com>
2026-05-30 18:30:36 +01:00
Peter Steinberger
becd45325b fix(imessage): bound private api negative cache expiry 2026-05-30 13:28:17 -04:00
Peter Steinberger
84a965a1a2 refactor(matrix): move ephemeral state to plugin sqlite (#88387)
* refactor(matrix): persist ephemeral state in plugin sqlite

* test(channels): wire matrix contract plugin state
2026-05-30 18:26:29 +01:00
Peter Steinberger
f4d461bbff fix(imessage): bound approval reaction poll expiry 2026-05-30 13:25:45 -04:00
Peter Steinberger
cbad1b6e69 fix(agents): bound exec followup handoff expiry 2026-05-30 13:23:03 -04:00
Peter Steinberger
f4cd5e4050 fix(sandbox): bound novnc observer token expiry 2026-05-30 13:21:26 -04:00
Peter Steinberger
0e7773d1a6 test(release): wait for live probe cleanup 2026-05-30 18:21:01 +01:00
Peter Steinberger
d8e7734d27 fix(agents): bound exec approval request expiry 2026-05-30 13:19:42 -04:00
Peter Steinberger
da7fb64aa4 fix(google): bound realtime browser session expiry 2026-05-30 13:16:22 -04:00
Peter Steinberger
3fffb34ba0 fix(msteams): bound delegated token expiry 2026-05-30 13:13:56 -04:00
Peter Steinberger
0dd67e2f25 fix(workboard): bound claim expiry checks 2026-05-30 13:11:14 -04:00
Peter Steinberger
4df27b9626 fix(browser): bound armed dialog expiry 2026-05-30 13:08:52 -04:00
Peter Steinberger
e708a872a1 fix(commands): bound private approval route expiry 2026-05-30 13:06:29 -04:00
zhang-guiping
2dacc6da28 fix(agents): hide sessions_send alias normalization
Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>
2026-05-30 18:06:22 +01:00
Peter Steinberger
9660e42fe2 fix(plugin-state): bound ttl expiry writes 2026-05-30 13:03:24 -04:00
Peter Steinberger
522da25932 fix(skills): bound upload expiry checks 2026-05-30 13:00:52 -04:00
Peter Steinberger
d44621b544 fix(exec): bound approval pending expiry 2026-05-30 12:58:59 -04:00
Peter Steinberger
6fe0539992 test(release): skip unavailable anthropic live models 2026-05-30 17:58:01 +01:00
Peter Steinberger
283238fd77 fix(matrix): bound allowlist store cache expiry 2026-05-30 12:56:54 -04:00
Peter Steinberger
5568ecc7aa fix(discord): bound unbound webhook echo expiry 2026-05-30 12:54:25 -04:00
Peter Steinberger
743d5378d2 fix(zalouser): bound group context cache expiry 2026-05-30 12:52:24 -04:00
史启明(QimingShi)
63a3676d3c fix(tui): distinguish /new and /reset descriptions
Fixes #49517.

Updates the TUI command catalog so /new describes spawning an isolated session while /reset describes resetting the current session. Adds a focused regression test for the two descriptions.

Co-authored-by: KhanCold <119404710+KhanCold@users.noreply.github.com>
2026-05-30 17:50:14 +01:00
Peter Steinberger
2a39c217c8 fix(voice-call): bound realtime stream token expiry 2026-05-30 12:49:36 -04:00
NianJiu
a2fc4ca7ad feat(ui): add collapsible recent sessions section
Adds a persisted collapse state for the Control UI Recent sessions sidebar group, including storage and browser coverage.

Also narrows gateway run miss cache expiry typing so the rebased branch stays clean against current main.

Closes #85510

Co-authored-by: NianJiuZst <3235467914@qq.com>
2026-05-30 17:48:29 +01:00
Peter Steinberger
8eeaa45729 refactor: route model catalog imports to core package
Route internal model catalog imports to the extracted @openclaw/model-catalog-core package and delete obsolete internal facades.

Keep public SDK declarations self-contained by wrapping core helpers at public boundaries instead of leaking private package imports.

Verification:
- pnpm test src/plugins/contracts/model-catalog-core-imports.test.ts src/plugins/sdk-alias.test.ts packages/model-catalog-core/src/configured-model-refs.test.ts packages/model-catalog-core/src/provider-model-id-normalize.test.ts packages/model-catalog-core/src/provider-model-id-normalization.test.ts src/config/config.model-ref-validation.test.ts src/agents/model-selection.test.ts src/plugin-sdk/provider-model-shared.test.ts -- --reporter=verbose
- pnpm check:test-types
- pnpm test:extensions:package-boundary:compile
- pnpm build
- rg "@openclaw/model-catalog-core" dist/plugin-sdk packages/plugin-sdk/dist -n --glob '*.d.ts' || true
- git diff --check
- autoreview clean after fix

CI note: merged with admin override because checks-node-agentic-commands-doctor and checks-node-core-runtime-infra-state failed twice with exit 143/no-output watchdog termination after prior passing test output, while relevant local proof and the rest of CI were green.
2026-05-30 17:48:18 +01:00
Vincent Koc
4d13055ca5 fix(sessions): repair prompt blobs on fast updates 2026-05-30 17:47:07 +01:00
Peter Steinberger
bfceffa2f7 fix(qqbot): bound upload cache expiry 2026-05-30 12:46:56 -04:00
Peter Steinberger
031583e8f5 fix(gateway): bound exec approval expiry 2026-05-30 12:44:39 -04:00
Vincent Koc
2ccbc673df fix(scripts): prebuild gateway cpu private qa artifacts 2026-05-30 18:42:17 +02:00
Peter Steinberger
11b5728faa fix(agents): bound code mode snapshot expiry 2026-05-30 12:42:07 -04:00
samzong
4decdf6245 [Fix] Deliver restart recovery replies (#86089)
* fix(agents): deliver restart recovery replies

* fix(auto-reply): import session entry updater

* test(auto-reply): use current embedded agent mock

* test(feishu): refresh typed account fixture

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-30 17:39:43 +01:00
Peter Steinberger
ac0fb976c8 fix(feishu): bound card action token expiry 2026-05-30 12:37:24 -04:00
Vincent Koc
1de9f99ea8 fix(ci): repair current test type fixtures 2026-05-30 17:35:02 +01:00
Peter Steinberger
60f8e18372 fix(nvidia): bound featured model cache expiry 2026-05-30 12:34:53 -04:00
Peter Steinberger
e52b4bce01 fix(bedrock): bound discovery cache expiry 2026-05-30 12:33:07 -04:00
mushuiyu_xydt
f93a558892 fix(plugins): ignore helper files in extension roots
Fixes #88198.

Ignore top-level helper scripts in auto-discovered global/workspace extension roots so they do not become manifestless plugin candidates during config validation. Standalone plugin files remain supported when explicitly configured through `plugins.load.paths`, and docs now call out the supported path.

Verification:
- `node scripts/run-vitest.mjs src/plugins/discovery.test.ts src/config/config.plugin-validation.test.ts`
- `node scripts/run-oxlint.mjs src/plugins/discovery.ts src/plugins/discovery.test.ts src/config/config.plugin-validation.test.ts`
- `git diff --check`
- GitHub CI green at `93073bfa85ee294e644c623881ba59ba71d90975`
- `.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main`

Thanks @mushuiyu886 for the fix and @mmhzlrj for the report.
2026-05-30 17:31:53 +01:00
Peter Steinberger
5ba3505fed fix(bedrock): bound mantle iam token expiry 2026-05-30 12:31:08 -04:00
Peter Steinberger
18e7d28b21 perf(gateway): reuse stable turn metadata 2026-05-30 17:30:47 +01:00
Peter Steinberger
02ca283716 fix(outbound): bound current conversation expiry 2026-05-30 12:27:26 -04:00
Peter Steinberger
4f0e3cb621 fix(plugin-sdk): bound live catalog cache expiry 2026-05-30 12:25:14 -04:00
Martin Kessler
73a69d9e64 fix(outbound): pack newline-mode paragraphs up to limit
Pack newline-mode outbound paragraphs up to the configured text limit instead of sending one message per blank-line-separated paragraph. Preserves markdown fence guardrails and adds focused chunking plus outbound delivery regressions.\n\nVerified: autoreview clean; node scripts/run-vitest.mjs src/auto-reply/chunk.test.ts src/infra/outbound/deliver.test.ts; git diff --check origin/main...HEAD.\n\nThanks @kesslerio.
2026-05-30 17:24:57 +01:00
Peter Steinberger
b1911a7cd3 fix(gateway): bound run session miss cache expiry 2026-05-30 12:22:24 -04:00
Peter Steinberger
450642a897 fix(agents): bound native permission approval expiry 2026-05-30 12:20:29 -04:00
Vincent Koc
f7a1903bfc fix(discord): avoid private test session intersection 2026-05-30 17:18:51 +01:00
Peter Steinberger
61cf22f147 fix(agents): bound native hook relay expiry 2026-05-30 12:17:36 -04:00
Peter Steinberger
55505776fb fix(gateway): bound transcription relay session expiry 2026-05-30 12:15:06 -04:00
brokemac79
3c91928bae fix(codex): refresh stale managed runtime plugin
Refresh stale managed Codex runtime plugin installs during doctor repair and restore Codex status usage attribution. Thanks @brokemac79.
2026-05-30 17:15:04 +01:00
Peter Steinberger
6ac7564918 fix(gateway): bound realtime relay session expiry 2026-05-30 12:13:10 -04:00
Peter Steinberger
23e1aac9b2 fix(feishu): bound sender name cache expiry 2026-05-30 12:10:19 -04:00
Peter Steinberger
c65af78853 fix(discord): bound realtime wake followup expiry 2026-05-30 12:06:57 -04:00
Vincent Koc
4155ac1c0d fix(scripts): make kitchen sink rpc help inert 2026-05-30 18:04:44 +02:00
Peter Steinberger
cfe5544b30 fix(qqbot): honor legacy c2c stream progress 2026-05-30 17:02:41 +01:00
Peter Steinberger
d7b901a1e7 fix(discord): bound speaker context cache expiry 2026-05-30 12:02:18 -04:00
Peter Steinberger
5225a8c644 fix(gateway): bound config schema cache expiry 2026-05-30 12:00:37 -04:00
Peter Steinberger
fc50f949d4 Add per-agent SQLite cache store (#88349)
* feat: add per-agent sqlite cache store

* fix: preserve sqlite cache adapter scope

* chore: mark sqlite cache scaffold intentional
2026-05-30 17:00:24 +01:00
samzong
f6b40861f7 fix(qqbot): deliver partial tool progress
Fixes #66509.

QQBot now sends text-only tool progress immediately when partial streaming is enabled instead of buffering it until a fallback timer that is cleared by the final block. Immediate progress uses QQ plain-text sends so markdown-enabled accounts do not reinterpret media-like progress text, while streaming-off behavior remains final-only.

Thanks @gabrielduartesignart for the report.

Co-authored-by: samzong <samzong.lu@gmail.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-05-30 17:00:09 +01:00
Peter Steinberger
f491d420f7 fix(tailscale): bound whois cache expiry 2026-05-30 11:58:07 -04:00
Peter Steinberger
ef0882e17e fix(google): bound gemini oauth token expiry 2026-05-30 11:55:02 -04:00
Peter Steinberger
697bafa9c9 fix(google): bound vertex adc token cache expiry 2026-05-30 11:52:19 -04:00
Peter Steinberger
77761f4a3e fix(msteams): bound parent thread cache expiry 2026-05-30 11:49:47 -04:00
Peter Steinberger
0e2694ff47 fix(msteams): bound team id cache expiry 2026-05-30 11:47:00 -04:00
Peter Steinberger
5eb71927b7 fix(whatsapp): bound group metadata cache expiry 2026-05-30 11:45:05 -04:00
Vincent Koc
cbd8049b9f fix(scripts): parse forwarded package script options 2026-05-30 17:44:14 +02:00
Peter Steinberger
19f22b5924 fix(feishu): bound approval card expiry 2026-05-30 11:41:43 -04:00
Peter Steinberger
05634708e0 fix(feishu): bound quick action launcher expiry 2026-05-30 11:38:50 -04:00
Vincent Koc
536c00991f fix(gateway): guard traced channel handoff stops 2026-05-30 16:36:43 +01:00
Peter Steinberger
c94c43d3bb fix(feishu): bound card action chat cache clocks 2026-05-30 11:36:19 -04:00
Nimrod Gutman
8a99c0d17a feat(ios): refresh app store metadata (#88235)
Merged via squash.

Prepared head SHA: a54d2ffad2
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Reviewed-by: @ngutman
2026-05-30 18:36:01 +03:00
Peter Steinberger
30e1556cda refactor: extract model catalog core package
* refactor: extract model catalog core package

* refactor: route model catalog imports through package boundary

* build: include model catalog in plugin sdk package dts

* fix: preserve static fallback model metadata
2026-05-30 16:33:45 +01:00
Peter Steinberger
ec15f90a55 fix(feishu): bound group name cache clocks 2026-05-30 11:33:30 -04:00
Peter Steinberger
3da34a4673 fix(feishu): bound probe cache expiry clocks 2026-05-30 11:31:16 -04:00
Peter Steinberger
f91ddefbfb fix(zalo): bound hosted media expiry clocks 2026-05-30 11:29:33 -04:00
Vincent Koc
84385898ec fix(deps): remove photon root runtime 2026-05-30 16:27:48 +01:00
Peter Steinberger
6c7642b532 fix(workboard): bound claim expiry timestamps 2026-05-30 11:27:09 -04:00
Peter Steinberger
9988a37d37 fix(phone-control): bound arm expiry timestamps 2026-05-30 11:24:36 -04:00
Peter Steinberger
37b33d11ce test: isolate channel manager teardown 2026-05-30 16:24:34 +01:00
Peter Steinberger
7086e34533 feat(workboard): persist orchestration metadata in sqlite
Persist Workboard orchestration data in plugin SQLite KV storage, including board metadata, cards, notification subscriptions, decomposition history, and board lifecycle/RPC support.
2026-05-30 16:24:14 +01:00
Peter Steinberger
20fbb8bd14 fix(mattermost): bound slash validation cache clocks 2026-05-30 11:22:25 -04:00
Peter Steinberger
8e90a1cad9 fix(slack): bound subteam member cache clocks 2026-05-30 11:19:34 -04:00
Peter Steinberger
7e3ebb8e10 fix(slack): bound external menu cache clocks 2026-05-30 11:17:13 -04:00
Peter Steinberger
06b2bf1c0a fix(telegram): bound forum flag cache clocks 2026-05-30 11:15:03 -04:00
Peter Steinberger
d649548a7a fix(active-memory): bound recall cache clocks 2026-05-30 11:13:04 -04:00
Vincent Koc
5adc681238 refactor: share approval lookup state 2026-05-30 17:12:03 +02:00
Vincent Koc
53e8dc6a54 fix(scripts): stop parsing after option terminators 2026-05-30 17:10:36 +02:00
Peter Steinberger
2d0a0c5e43 test: clear channel manager restart timers 2026-05-30 16:09:38 +01:00
Peter Steinberger
b668ffe7ca fix(slack): bound thread resolution cache clocks 2026-05-30 11:09:21 -04:00
Peter Steinberger
6736936cbc fix(slack): bound thread starter cache clocks 2026-05-30 11:06:47 -04:00
Peter Steinberger
8539e0283a fix(slack): bound app mention retry clocks 2026-05-30 11:04:24 -04:00
Peter Steinberger
ef88f0f949 perf(sessions): skip prompt hydration for metadata reads 2026-05-30 16:03:39 +01:00
Peter Steinberger
816c692035 fix(slack): bound member cache clocks 2026-05-30 11:01:19 -04:00
Peter Steinberger
c635e560d0 build: update rastermill to 0.3.1 2026-05-30 16:01:14 +01:00
Vincent Koc
ccb59d989b fix(scripts): honor memory fd option terminator 2026-05-30 17:00:54 +02:00
Vincent Koc
642f85dc5b test(sdk): resolve local package deps in pack smoke 2026-05-30 15:57:18 +01:00
Vincent Koc
53300a5c1a refactor: share skills method validation 2026-05-30 16:56:36 +02:00
Vincent Koc
b51610a1c3 fix(ci): serialize gateway server vitest project 2026-05-30 15:56:25 +01:00
Peter Steinberger
5269924ff8 fix(imessage): bound probe cache clocks 2026-05-30 10:55:53 -04:00
Peter Steinberger
62fa5692cb fix(imessage): bound chat list cache clocks 2026-05-30 10:52:38 -04:00
Peter Steinberger
2d4369d176 fix(signal): bound api mode cache clocks 2026-05-30 10:50:44 -04:00
Peter Steinberger
99e8cf22a8 fix(web): bound tool cache expiry clocks 2026-05-30 10:47:46 -04:00
Vincent Koc
e780a6b7ba fix(agents): type configured fallback model metadata 2026-05-30 16:45:53 +02:00
Vincent Koc
313554059c fix(docs): route anchor audit through pnpm runner 2026-05-30 16:45:52 +02:00
Peter Steinberger
77b334a984 fix(mattermost): bound reaction cache clocks 2026-05-30 10:43:44 -04:00
Peter Steinberger
ab67a198c1 fix(mattermost): bound monitor cache clocks 2026-05-30 10:41:19 -04:00
Peter Steinberger
9ef5a9afdc fix(discord): bound REST entity cache clocks 2026-05-30 10:38:26 -04:00
Vincent Koc
c39fbdb698 refactor: share web login request validation 2026-05-30 16:37:35 +02:00
Peter Steinberger
d33d6bfafa fix(discord): bound channel info cache clocks 2026-05-30 10:34:45 -04:00
Peter Steinberger
2209f71a78 fix(oauth): reject date-invalid token expiries 2026-05-30 10:31:36 -04:00
Peter Steinberger
f13a615036 fix(foundry): bound entra token expiry clocks 2026-05-30 10:29:26 -04:00
Peter Steinberger
5660b67062 fix(google-meet): bound oauth fallback expiry clocks 2026-05-30 10:26:07 -04:00
Vincent Koc
1d21646e96 fix(ci): type static catalog runtime metadata 2026-05-30 15:23:48 +01:00
Peter Steinberger
55d4456751 fix(webhook): bound replay response expiry timestamps 2026-05-30 10:21:50 -04:00
Peter Steinberger
a80d9f00f1 test(imessage): align SMS route expectations 2026-05-30 15:18:30 +01:00
Peter Steinberger
22d635080d fix(feishu): guard streaming token expiry clocks 2026-05-30 10:14:14 -04:00
Peter Steinberger
d5be702f86 fix(gateway): guard assistant media ticket clocks 2026-05-30 10:08:32 -04:00
Vincent Koc
3d66d203d0 test(daemon): keep systemd tests off real systemctl 2026-05-30 15:03:37 +01:00
Peter Steinberger
a918e93421 fix(cron): keep out-of-range atMs invalid 2026-05-30 10:00:45 -04:00
Vincent Koc
56eadf36d0 refactor: share approval resolve param parsing 2026-05-30 15:57:57 +02:00
Peter Steinberger
912f663173 fix(agents): guard compaction successor timestamps 2026-05-30 09:56:55 -04:00
Peter Steinberger
f44af7eebf fix(gateway): guard live probe schedule timestamps 2026-05-30 09:52:20 -04:00
Peter Steinberger
65fe2b7e91 ci: tolerate release branches without llm core package 2026-05-30 14:48:08 +01:00
Peter Steinberger
941e04e9f3 fix: clamp configured OpenAI-compatible output tokens 2026-05-30 14:46:30 +01:00
AI-HUB
f327073fb3 fix: classify ws pre-handshake close as benign
Classify the exact `ws` pre-handshake close-before-open error as a benign uncaught network exception so transient Feishu WebSocket cleanup does not crash the gateway process.

The classifier now keeps the upstream `ws` message as an exact contract and rejects broader prefixed WebSocket messages, with regression coverage for direct, wrapped, and non-exact cases.

Fixes #88257.
Thanks @akrimm702.

Co-authored-by: AI-HUB <144416483+akrimm702@users.noreply.github.com>
2026-05-30 15:45:23 +02:00
Peter Steinberger
41e5acbb6c perf(gateway): skip unchanged auth persistence writes 2026-05-30 14:44:45 +01:00
Peter Steinberger
2333d47a1e fix(matrix): guard verification timestamps 2026-05-30 09:43:09 -04:00
Vincent Koc
c9e481ac48 refactor: share approval request registration 2026-05-30 15:40:49 +02:00
scotthuang
462e315953 fix(ui): stop pulsing completed stream segments
Completed WebChat stream segment bubbles now render without the active streaming animation after live output has moved on. The UI chat item contract now marks completed stream segments as non-streaming and the active stream as streaming, so the renderer applies the pulsing class only to live output.

Verified with:
- node scripts/run-vitest.mjs ui/src/ui/chat/build-chat-items.test.ts ui/src/ui/chat/grouped-render.test.ts ui/src/ui/views/chat.test.ts
- node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-ui-stream-artifacts.tsbuildinfo
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main

PR: #88225
Credit: @scotthuang
2026-05-30 15:40:12 +02:00
Peter Steinberger
6b14df7792 fix(qqbot): guard token expiry logging 2026-05-30 09:38:58 -04:00
Vincent Koc
e449392c4f fix(e2e): route telegram proof through pnpm runner 2026-05-30 15:33:38 +02:00
Peter Steinberger
326db58229 fix(gateway): guard hook job timestamps 2026-05-30 09:33:19 -04:00
Vincent Koc
3caf4facec fix(test): include workflow lint target in routing expectation (#88310) 2026-05-30 14:29:26 +01:00
Peter Steinberger
c9a97f54e0 fix(discord): preserve preference recency under invalid clocks 2026-05-30 09:29:02 -04:00
Vincent Koc
85506c36a0 fix(e2e): route secret proof through pnpm runner 2026-05-30 15:25:15 +02:00
Ayaan Zaidi
a176b8ec2f perf(cli): compact resumed room-event prompts 2026-05-30 18:53:59 +05:30
Ayaan Zaidi
2b726457d8 fix(cli): persist first room-event session binding 2026-05-30 18:53:59 +05:30
Vincent Koc
6464f8d1d9 refactor: share visible approval list mapping 2026-05-30 15:19:10 +02:00
Peter Steinberger
a17c7a56da fix(sessions): guard transcript append timestamps 2026-05-30 09:08:20 -04:00
Peter Steinberger
98a1aa491f fix(gateway): guard lock payload timestamps 2026-05-30 09:04:34 -04:00
Vincent Koc
25b87b111d refactor: share find tool result builder 2026-05-30 15:00:22 +02:00
Peter Steinberger
f823123aa5 fix(time): centralize date timestamp fallback 2026-05-30 08:59:36 -04:00
Vincent Koc
d717ff71bf fix(live): reject loose heartbeat intervals 2026-05-30 14:56:58 +02:00
Peter Steinberger
840192caa9 fix(diffs): cap artifact expiry overflow 2026-05-30 08:54:56 -04:00
Vincent Koc
61ef6b12dd test(agents): harden code mode wait timeout 2026-05-30 13:53:25 +01:00
Peter Steinberger
660a6dec7f fix(cron): reject out-of-range cli relative times 2026-05-30 08:52:47 -04:00
Peter Steinberger
e49ef86945 fix(cron): guard timestamp validation clocks 2026-05-30 08:49:58 -04:00
Peter Steinberger
d2f69ecc3b fix(migrate): guard report timestamp formatting 2026-05-30 08:46:55 -04:00
Vincent Koc
a89abcb1e9 fix(release): reject loose npm verifier retry limits 2026-05-30 14:46:28 +02:00
Peter Steinberger
8bf7bc5b5c fix(sessions): guard archive timestamp formatting 2026-05-30 08:43:22 -04:00
Vincent Koc
4e2ef87c31 refactor: share git url parsing helpers 2026-05-30 14:42:17 +02:00
Vincent Koc
ec58491f75 fix(e2e): reject loose upgrade probe limits 2026-05-30 14:40:12 +02:00
Peter Steinberger
0840fea50d fix(matrix): guard startup verification timestamps 2026-05-30 08:38:12 -04:00
Vincent Koc
cf60e83118 fix(e2e): scope strict ClawHub preflight limits 2026-05-30 14:33:56 +02:00
Peter Steinberger
7ad2ebb515 fix(google): guard realtime browser session expiries 2026-05-30 08:33:06 -04:00
Peter Steinberger
3c41e1722f fix(discord): guard timeout expiry dates 2026-05-30 08:29:15 -04:00
Vincent Koc
dd5b70bcc4 refactor: share web search provider load context 2026-05-30 14:25:30 +02:00
Peter Steinberger
30c0422a8e fix(commitments): guard extraction prompt timestamps 2026-05-30 08:24:27 -04:00
Vincent Koc
6d43200248 fix(e2e): reject loose Telegram proof log limits 2026-05-30 14:23:40 +02:00
Peter Steinberger
be3153cabb fix(update): guard startup timestamps 2026-05-30 08:18:55 -04:00
Vincent Koc
56995069f1 fix(ci): preserve goal continuation prompts 2026-05-30 13:17:57 +01:00
Vincent Koc
2238e0ce76 fix(e2e): reject loose tool search fetch limits 2026-05-30 14:17:15 +02:00
Vincent Koc
38a463fe93 fix(deps): remove sharp from root package 2026-05-30 13:15:05 +01:00
Vincent Koc
e1f462b352 fix(e2e): reject loose Telegram Bot API limits 2026-05-30 14:11:43 +02:00
Peter Steinberger
ccd635fdb9 fix(memory-core): guard short-term recall timestamps 2026-05-30 08:10:54 -04:00
Vincent Koc
27dce6c6bb refactor: share embedded run abort loop 2026-05-30 14:09:15 +02:00
Peter Steinberger
9c08d8cd35 fix(memory-core): guard injected timestamps 2026-05-30 08:06:42 -04:00
Vincent Koc
dc5b3ecc4c fix(tui): continue goal commands after creation 2026-05-30 13:03:33 +01:00
Ayaan Zaidi
95f66a34e7 fix(gateway): honor queued manual restarts 2026-05-30 17:33:18 +05:30
Ayaan Zaidi
1695ee2f43 fix(gateway): defer recovery restarts to callers 2026-05-30 17:33:18 +05:30
Ayaan Zaidi
801520b0f0 fix(gateway): consume recovery restart edge cases 2026-05-30 17:33:18 +05:30
Ayaan Zaidi
8ba79d72b4 test(gateway): cover reload stop timeout restart 2026-05-30 17:33:18 +05:30
Ayaan Zaidi
5876ba6152 fix(gateway): restart channels after timed-out reload stop 2026-05-30 17:33:18 +05:30
Peter Steinberger
5b895f2592 fix(memory-wiki): guard injected timestamps 2026-05-30 08:02:26 -04:00
Peter Steinberger
fb61363763 fix(auto-reply): guard date stamp formatting 2026-05-30 07:58:51 -04:00
Vincent Koc
07e0af44b3 fix(e2e): reject loose MCP channel limits 2026-05-30 13:55:39 +02:00
Peter Steinberger
059d5405fe fix(infra): guard backup creation timestamps 2026-05-30 07:53:55 -04:00
Vincent Koc
cd37dbd4e5 refactor: share block reply coalescer enqueue 2026-05-30 13:51:47 +02:00
Vincent Koc
3e8d06a6be fix(ci): include workflow guard target 2026-05-30 12:50:38 +01:00
Peter Steinberger
2f07e4e6c0 fix(agents): guard current time context timestamp 2026-05-30 07:47:11 -04:00
Peter Steinberger
15fb3314de fix(discord): guard model picker legacy dates 2026-05-30 07:43:47 -04:00
Peter Steinberger
5a019e7725 fix(auto-reply): guard subagent info timestamps 2026-05-30 07:34:01 -04:00
Vincent Koc
aea31934d4 refactor: share directory id collection 2026-05-30 13:32:27 +02:00
Peter Steinberger
8ec7e80cb2 fix(agents): bound cli oauth jwt expiries 2026-05-30 07:29:59 -04:00
Peter Steinberger
6c3533d8c4 fix(ui): guard debug event timestamps 2026-05-30 07:23:02 -04:00
Vincent Koc
9c313a7826 fix(test): preserve live test passthrough flags 2026-05-30 13:20:02 +02:00
Peter Steinberger
368a719879 fix(ui): guard dreaming next-cycle timestamps 2026-05-30 07:19:22 -04:00
Peter Steinberger
ec7e3eaf64 fix(ui): guard chat picker session timestamps 2026-05-30 07:15:40 -04:00
Vincent Koc
8bcdab8933 refactor: share oauth identity safety check 2026-05-30 13:14:10 +02:00
Peter Steinberger
c2f0d811e7 fix(ui): guard next run weekday formatting 2026-05-30 07:12:51 -04:00
Peter Steinberger
8f3d3a549d fix(ui): guard usage chart timestamps 2026-05-30 07:10:21 -04:00
Peter Steinberger
d389a52494 fix(ui): centralize invalid date formatting 2026-05-30 07:07:13 -04:00
Vincent Koc
346b14a51a fix(test): route conventional script tests 2026-05-30 13:00:33 +02:00
Vincent Koc
ffa2da8478 fix(test): skip broad changed import scans 2026-05-30 13:00:33 +02:00
Vincent Koc
61a768be75 fix(test): route script library changes 2026-05-30 13:00:33 +02:00
Vincent Koc
3d8a77a113 fix(test): route package tooling changes 2026-05-30 13:00:33 +02:00
Vincent Koc
a6a358f1a6 fix(test): route ci tooling changes 2026-05-30 13:00:33 +02:00
Vincent Koc
131dc4eaeb fix(test): route workflow helper changes 2026-05-30 13:00:33 +02:00
Vincent Koc
022fd55bad fix(test): route crabbox changed tests 2026-05-30 13:00:33 +02:00
Vincent Koc
d9820e4098 fix(ci): disable crabbox on-demand fallback 2026-05-30 13:00:33 +02:00
Vincent Koc
a4ebdc9aa1 fix(test): guard run-with-env help 2026-05-30 13:00:32 +02:00
Vincent Koc
cf2461f7f6 fix(test): guard live runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
f5f829db79 fix(test): guard tsdown runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
a06daab97e fix(test): guard build runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
09f094057a fix(test): guard verify runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
9def042fab fix(test): guard check runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
f6adea5757 fix(test): guard force runner help 2026-05-30 13:00:32 +02:00
Vincent Koc
78f4a5c05f fix(tooling): ignore inline type-only re-exports 2026-05-30 13:00:32 +02:00
Vincent Koc
731a7af9c5 fix(test): keep wrapper help metadata-only 2026-05-30 13:00:32 +02:00
Vincent Koc
ffa4342a6a fix(test): route docker e2e script targets 2026-05-30 13:00:32 +02:00
Vincent Koc
550a134cf9 fix(tooling): forward oxlint shard cancellation 2026-05-30 13:00:32 +02:00
Vincent Koc
1b43e84d0d fix(test): batch explicit source route resolution 2026-05-30 13:00:32 +02:00
Vincent Koc
31f0635f4f fix(test): route explicit source targets narrowly 2026-05-30 13:00:31 +02:00
Vincent Koc
1c65e2e7c1 fix(tooling): bound oxlint shard stalls 2026-05-30 13:00:31 +02:00
Vincent Koc
b6f3fe7938 fix(test): route explicit helper targets narrowly 2026-05-30 13:00:31 +02:00
Vincent Koc
d65b3a68aa perf(cli): keep plugins JSON list on snapshot path 2026-05-30 13:00:31 +02:00
Vincent Koc
e2b54fecd8 fix(doctor): reuse lazy state migration import 2026-05-30 13:00:31 +02:00
Vincent Koc
b8067d073a fix(extensions): keep subagent hook facades lazy 2026-05-30 13:00:31 +02:00
Vincent Koc
e420c001d0 perf(policy): cache doctor file reads 2026-05-30 13:00:31 +02:00
Vincent Koc
44b6b79a66 perf(plugin-sdk): cache runtime helper imports 2026-05-30 13:00:31 +02:00
Vincent Koc
3ef2935ac9 perf(browser): reuse chrome mcp import 2026-05-30 13:00:31 +02:00
Vincent Koc
fced29de17 perf(extensions): cache meeting runtime loaders 2026-05-30 13:00:31 +02:00
Vincent Koc
4f074c3235 perf(extensions): cache plugin runtime loaders 2026-05-30 13:00:31 +02:00
Vincent Koc
5df00520cb perf(extensions): cache provider runtime imports 2026-05-30 13:00:30 +02:00
Vincent Koc
b2c85bc0a2 perf(browser): cache registration runtime import 2026-05-30 13:00:30 +02:00
Vincent Koc
5e2e78a75a perf(wizard): cache setup migration imports 2026-05-30 13:00:30 +02:00
Vincent Koc
2196f107da perf(gateway): cache post-attach startup imports 2026-05-30 13:00:30 +02:00
Vincent Koc
ff56a2d7b3 perf(gateway): cache plugin bootstrap imports 2026-05-30 13:00:30 +02:00
Vincent Koc
24cff8a3bc perf(gateway): share model catalog module loader 2026-05-30 13:00:30 +02:00
Vincent Koc
b495ac2abb perf(gateway): cache remote skills startup import 2026-05-30 13:00:30 +02:00
Vincent Koc
3f2585424d perf(gateway): cache plugin HTTP imports 2026-05-30 13:00:30 +02:00
Vincent Koc
9d1a3007d9 perf(gateway): cache model catalog imports 2026-05-30 13:00:30 +02:00
Vincent Koc
b5c163dffa test(doctor): complete browser health mock 2026-05-30 13:00:30 +02:00
Vincent Koc
ee0cf9e5bb perf(gateway): cache session event imports 2026-05-30 13:00:30 +02:00
Vincent Koc
37fdfa0e0b perf(doctor): cache health contribution imports 2026-05-30 13:00:30 +02:00
Vincent Koc
d550b804b8 perf(doctor): cache core check imports 2026-05-30 13:00:30 +02:00
Vincent Koc
05988500bc perf(crestodian): cache operation imports 2026-05-30 13:00:29 +02:00
Vincent Koc
b01290cf64 perf(cli): cache command ownership imports 2026-05-30 13:00:29 +02:00
Vincent Koc
117f6fb254 test(agents): complete provider runtime mock 2026-05-30 13:00:29 +02:00
Vincent Koc
c363816fea perf(cli): cache runtime startup imports 2026-05-30 13:00:29 +02:00
Vincent Koc
aeed31cdb1 perf(cli): cache root help imports 2026-05-30 13:00:29 +02:00
Vincent Koc
58c8c022c5 perf(entry): cache root help module imports 2026-05-30 13:00:29 +02:00
Vincent Koc
2cfae61743 perf(onboarding): split ClawHub install error codes 2026-05-30 13:00:29 +02:00
Vincent Koc
c6b4daf426 perf(health): remove duplicate config import 2026-05-30 13:00:29 +02:00
Vincent Koc
348fabe04d perf(auto-reply): remove reset model duplicate import 2026-05-30 13:00:29 +02:00
Vincent Koc
6c83e8e7e4 perf(models): cache provider index catalog import 2026-05-30 13:00:29 +02:00
Vincent Koc
817b6259c4 perf(agents): cache live model runtime import 2026-05-30 13:00:29 +02:00
Vincent Koc
959af0fa5b perf(cli): cache secrets command imports 2026-05-30 13:00:29 +02:00
Vincent Koc
669b26a3dc perf(cli): cache routed command imports 2026-05-30 13:00:28 +02:00
Vincent Koc
67c139fc36 perf(cli): cache status command imports 2026-05-30 13:00:28 +02:00
Vincent Koc
8b6829e1bc perf(cli): cache plugin runtime imports 2026-05-30 13:00:28 +02:00
Vincent Koc
86e6fbcf52 perf(cli): cache agent bind command import 2026-05-30 13:00:28 +02:00
Vincent Koc
9b4b3aa348 perf(cli): cache plugins command imports 2026-05-30 13:00:28 +02:00
Vincent Koc
51ab2c0d79 perf(cli): cache models runtime import 2026-05-30 13:00:28 +02:00
Vincent Koc
bdd9c70787 perf(cli): cache devices runtime import 2026-05-30 13:00:28 +02:00
Vincent Koc
1ff95ff3e6 perf(doctor): cache health config import 2026-05-30 13:00:28 +02:00
Peter Steinberger
7c5b55c5ff fix(ui): ignore invalid reset timestamps 2026-05-30 07:00:01 -04:00
Vincent Koc
b0d6076208 refactor: share setup dashboard open flow 2026-05-30 12:55:19 +02:00
Peter Steinberger
4385e57dce fix(doctor): tolerate invalid cron atMs 2026-05-30 06:54:58 -04:00
Vincent Koc
eb45c1c623 fix(scripts): report missing workflow linter fallback 2026-05-30 12:52:54 +02:00
Peter Steinberger
adf981de89 fix(imessage): tolerate invalid catchup cursor timestamps 2026-05-30 06:46:09 -04:00
Peter Steinberger
023a101b91 fix(heartbeat): tolerate invalid commitment due timestamps 2026-05-30 06:41:16 -04:00
Peter Steinberger
8b92aca27f refactor: extract media understanding common package (#88297)
* refactor: extract media understanding common package

* test: move media understanding format test
2026-05-30 12:40:49 +02:00
Peter Steinberger
b13fb788b5 fix(commitments): tolerate invalid due timestamps 2026-05-30 06:36:49 -04:00
Vincent Koc
87c0ee7685 refactor: share config observe recovery restore helpers 2026-05-30 12:35:36 +02:00
Peter Steinberger
eef32e94c7 fix(memory-wiki): tolerate invalid source mtimes 2026-05-30 06:33:13 -04:00
Peter Steinberger
1350efcfd8 fix(acp): tolerate invalid status timestamps 2026-05-30 06:27:44 -04:00
Peter Steinberger
e7ef051149 fix(slack): tolerate invalid interaction datetimes 2026-05-30 06:23:39 -04:00
Peter Steinberger
2b5ddf8f2a fix(acp): tolerate invalid session timestamps 2026-05-30 06:19:44 -04:00
Vincent Koc
6f655573d3 refactor: share parallels smoke lifecycle 2026-05-30 12:18:46 +02:00
Peter Steinberger
8aabf45ddb fix(memory-wiki): tolerate invalid chatgpt timestamps 2026-05-30 06:16:03 -04:00
Peter Steinberger
4d4748e807 fix(voice-call): tolerate invalid ended timestamps 2026-05-30 06:10:40 -04:00
Peter Steinberger
439c09668e fix(ui): ignore invalid usage export timestamps 2026-05-30 06:06:19 -04:00
Peter Steinberger
54bbe87cd5 fix(ui): ignore invalid chat export timestamps 2026-05-30 06:02:38 -04:00
Peter Steinberger
6804b7cb71 fix(matrix): ignore invalid device timestamps 2026-05-30 05:59:10 -04:00
Peter Steinberger
63470e99f0 fix(session): tolerate invalid lifecycle expiry 2026-05-30 05:53:24 -04:00
Peter Steinberger
90b0f7bd85 fix(auth): ignore invalid auth list timestamps 2026-05-30 05:49:32 -04:00
Peter Steinberger
d92b3b5cc2 refactor: unify OpenAI provider identity
Refactor OpenAI provider identity so OpenAI remains the canonical provider for API-key and OAuth-backed flows while legacy openai-codex state is doctor/migration-only.

Keeps OpenAI Codex Responses as an API/transport class rather than a provider identity, moves auth aliases through providerAuthAliases, updates doctor repair sequencing for old auth/profile state, and refreshes tests/docs around the canonical OpenAI behavior.
2026-05-30 11:48:41 +02:00
Vincent Koc
4d0668a546 refactor: share proxy capture event recording 2026-05-30 11:47:45 +02:00
Peter Steinberger
2c0f79d53a fix(status): tolerate invalid retained task cleanup 2026-05-30 05:45:18 -04:00
Peter Steinberger
5374c7a8a2 Persist subagent registry in SQLite (#88260)
* fix(agents): persist subagent registry in sqlite

* test(agents): mock sqlite subagent registry in loop guard
2026-05-30 11:44:11 +02:00
Vincent Koc
35ce103378 fix(agents): harden autoreview Windows harness (#88284) 2026-05-30 10:43:52 +01:00
Peter Steinberger
029c17de41 fix(tasks): tolerate invalid flow timestamps 2026-05-30 05:41:26 -04:00
Marvinthebored
6b41a0692f fix(plugins): preserve single-pass plugin env config
Resolve raw plugin config environment references before plugin discovery and validation, while preserving the existing single-pass behavior for configs already loaded through config IO.

The loader now resolves raw config opt-ins with config.env vars included, bypasses active/cache reuse for that mode, and redacts plugin entry config from raw-mode cache keys so resolved secrets do not enter registry keys or reentry errors.

Verification:
- OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs src/plugins/loader.test.ts src/plugins/loader.runtime-registry.test.ts
- autoreview --mode branch --base origin/main
- pnpm check:changed on Blacksmith Testbox tbx_01ksw36bp7zygwxgq3jcsvjv3b / GitHub Actions run 26680322889
- PR CI green on facb77634e

Co-authored-by: Peter Lindsey <peter@lindsey.jp>
2026-05-30 11:39:15 +02:00
NianJiu
da5d1a6215 feat(xiaomi): add Token Plan provider support
Adds first-class Xiaomi Token Plan provider support with regional onboarding/configuration, token-plan key prefix validation, runtime pricing/catalog metadata, and docs/test coverage.

Keeps Token Plan model catalog discovery runtime-owned so region-specific base URLs are required and the provider cannot silently fall back to the static SGP manifest catalog.

Fixes #86169.

Verification:
- node scripts/run-vitest.mjs src/plugins/provider-discovery.runtime.test.ts extensions/xiaomi/index.test.ts src/plugins/manifest-model-catalog.test.ts src/model-catalog/manifest-planner.test.ts
- git diff --check
- autoreview --mode local: clean, no accepted/actionable findings
- CI run 26678998539: all relevant checks passed; check-prod-types failed on unrelated browser unused-function issue already present on origin/main

Co-authored-by: NianJiuZst <3235467914@qq.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-30 11:37:36 +02:00
Peter Steinberger
f72762ae8f fix(tasks): tolerate invalid task timestamps 2026-05-30 05:36:31 -04:00
Peter Steinberger
0185d0d2ac fix(telegram): ignore invalid forwarded timestamps 2026-05-30 05:32:53 -04:00
Vincent Koc
82fe55acac refactor: share workboard card tool helpers 2026-05-30 11:31:40 +02:00
Peter Steinberger
28eb4cfa12 fix(codex): ignore invalid history timestamps 2026-05-30 05:28:14 -04:00
Peter Steinberger
a9cbec912e fix(minimax): validate oauth authorization expiry 2026-05-30 05:23:53 -04:00
Peter Steinberger
095bc6d4b4 fix(google-meet): refresh invalid cached oauth expiries 2026-05-30 05:18:21 -04:00
Vincent Koc
b72853a742 refactor: share native approval route gates 2026-05-30 11:15:49 +02:00
Peter Steinberger
4f784b5d47 fix(auth): reject invalid oauth expiry dates 2026-05-30 05:14:49 -04:00
Peter Steinberger
ff2a99b22e fix(codex): ignore invalid rate limit reset dates 2026-05-30 05:10:50 -04:00
Peter Steinberger
de1dfab03e refactor: move terminal core into package (#88279)
* refactor: move terminal core into package

* refactor: move terminal module files

* fix: clean terminal package CI followups

* test: update lint suppression allowlist

* fix: ship terminal core runtime aliases
2026-05-30 11:07:45 +02:00
Peter Steinberger
7b699fddac fix(auth): guard codex jwt expiry timestamps 2026-05-30 05:03:03 -04:00
Peter Steinberger
7854f547ce fix(agents): cap compaction retry timeout 2026-05-30 04:59:11 -04:00
Peter Steinberger
e64d713e41 fix(workboard): cap duration arithmetic 2026-05-30 04:56:14 -04:00
Vincent Koc
8348af99e8 fix(ci): clear stale changed-check failures 2026-05-30 09:55:59 +01:00
Peter Steinberger
b1958256fd fix(memory): cap embedding timeouts 2026-05-30 04:48:15 -04:00
Peter Steinberger
65fc5d1c5d fix(voice-call): cap manager timer delays 2026-05-30 04:45:06 -04:00
Vincent Koc
b19584b25e refactor: share runtime plugin install flow 2026-05-30 10:43:33 +02:00
Peter Steinberger
069ea7942d fix(browser): cap proxy request timeouts 2026-05-30 04:39:55 -04:00
Peter Steinberger
5d75f64369 fix(browser): cap cdp reachability timeouts 2026-05-30 04:36:23 -04:00
Peter Steinberger
7666d71fab fix(media): cap understanding timeouts 2026-05-30 04:32:21 -04:00
Vincent Koc
25affd6584 refactor: share subagent attachment preparation 2026-05-30 10:27:03 +02:00
Peter Steinberger
d8db7f561e fix(sandbox): cap browser autostart timeout 2026-05-30 04:26:41 -04:00
Peter Steinberger
26ef325219 fix(gateway): cap node invoke timers 2026-05-30 04:21:43 -04:00
Peter Steinberger
86311b0e00 fix(release): harden Parallels Discord smoke 2026-05-30 09:20:11 +01:00
Peter Steinberger
b09cab4ebd fix(whatsapp): cap QR login timers 2026-05-30 04:16:36 -04:00
Peter Steinberger
7d71c5d0c6 fix(gateway): cap node reconnect wait timers 2026-05-30 04:11:02 -04:00
Vincent Koc
b13529767b refactor: share inline image data URL sanitizer 2026-05-30 10:08:54 +02:00
Peter Steinberger
cc42367f3f fix(agents): cap plugin approval timeouts 2026-05-30 04:06:45 -04:00
Peter Steinberger
915f88a0a3 fix(browser): centralize route timeout clamping 2026-05-30 03:59:45 -04:00
Peter Steinberger
cec50aa047 fix(browser): cap act action timeouts 2026-05-30 03:52:29 -04:00
Peter Steinberger
fc90f0f15c fix(qa-matrix): cap live timeout env 2026-05-30 03:47:22 -04:00
Vincent Koc
0d4828497e refactor: share respawn child runner 2026-05-30 09:44:20 +02:00
Peter Steinberger
aae0d54752 fix(browser): cap Chrome MCP navigation timeout grace 2026-05-30 03:41:53 -04:00
Peter Steinberger
650027106b fix(google-meet): share operation timeout clamp 2026-05-30 03:36:20 -04:00
Peter Steinberger
99ffd714ce refactor: extract markdown core package (#88265)
* refactor: extract markdown core package

* refactor: remove old markdown sources

* fix: use source paths for markdown core imports

* fix: clean markdown package dependency ownership

* fix: refresh root shrinkwrap for markdown dependency move
2026-05-30 09:33:24 +02:00
Vincent Koc
0f8ea1d3d9 fix(build): skip tsx preload for metadata help 2026-05-30 09:30:55 +02:00
Peter Steinberger
8d8f5a59e2 fix(agents): cap overflowed wait timeout grace 2026-05-30 03:30:42 -04:00
keshavbotagent
fcf2852f0f fix(codex): prevent post-tool edit stream timeouts
Keep Codex post-tool assistant/commentary progress and patch snapshot updates on the post-tool completion guard so long generated edits do not fall back to terminal idle handling. Enable Codex patch streaming events for native code mode and refresh exact prompt/config expectations.

Verification:
- pnpm prompt:snapshots:check
- pnpm test extensions/codex/src/app-server/run-attempt.turn-watches.test.ts extensions/codex/src/app-server/thread-lifecycle.test.ts extensions/codex/src/app-server/thread-lifecycle.binding.test.ts extensions/codex/src/app-server/side-question.test.ts
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- git diff --check origin/main...HEAD
- exact-head CI run 26677938955
- Real behavior proof override run 26678097960

Thanks @keshavbotagent.

Co-authored-by: Kelaw - Keshav's Agent <keshavbotagent@gmail.com>
2026-05-30 09:30:09 +02:00
Vincent Koc
7054aa562e refactor: share manifest capability availability checks 2026-05-30 09:24:08 +02:00
Peter Steinberger
dad8cfaf74 fix(runtime): reuse timeout grace for voice and memory 2026-05-30 03:21:14 -04:00
Peter Steinberger
5f4fc7512e fix(runtime): centralize timeout grace clamping 2026-05-30 03:15:50 -04:00
Peter Steinberger
530351e394 fix(codex): stop injecting mirrored history into prompts
Stop Codex app-server turns from projecting mirrored OpenClaw transcript history into prompt/model-input surfaces by default. Keep context-engine output on the rendered prompt/developer-instruction path and preserve mirrored history only for OpenClaw-side snapshots.
2026-05-30 09:13:38 +02:00
Peter Steinberger
f52355ce5f fix(google-meet): cap CLI timeout options 2026-05-30 03:07:16 -04:00
Vincent Koc
9b605846bb refactor: share ACP metadata readers 2026-05-30 09:06:19 +02:00
Peter Steinberger
26bf8f0dc8 fix(voice-call): cap CLI gateway timeouts 2026-05-30 03:00:14 -04:00
Dmitry Golubev
3fbd2432b6 fix(codex): move stable context to developer instructions
Move OpenClaw skills and the routed workspace-memory pointer out of native Codex turn user input and into turn-scoped collaboration developer instructions.

Preserve full MEMORY.md fallback prompt injection, delivery-hint rewrapping, lightweight cron exact prompts, and trajectory reporting for the rendered developer surface.

Co-authored-by: Beru <beru@lastguru.lv>
2026-05-30 08:59:02 +02:00
Peter Steinberger
f90b8cffc7 perf: prefer built plugin public surfaces 2026-05-30 07:54:30 +01:00
Peter Steinberger
1ac037d948 fix(memory): cap qmd search process timeouts 2026-05-30 02:54:11 -04:00
Vincent Koc
45c4f1edd4 refactor: share task registry sqlite helpers 2026-05-30 08:49:19 +02:00
Peter Steinberger
be76841143 fix(agents): cap bash tool timeouts 2026-05-30 02:48:06 -04:00
Peter Steinberger
89e64f70c1 fix: accept bare goal objectives 2026-05-30 08:46:09 +02:00
Vincent Koc
e35db953eb fix(build): raise inherited tsdown heap caps 2026-05-30 08:45:43 +02:00
Peter Steinberger
032945a5cd fix(codex): cap approval gateway timeouts 2026-05-30 02:44:14 -04:00
Peter Steinberger
f61a5bc797 feat(workboard): add board ops recovery metadata
Add board-scoped Workboard metadata, stats, and recovery operations.\n\nIncludes gateway/tool contracts, docs, UI normalization, and regression coverage for board-scoped idempotency, linked child manifests, recovery diagnostics, and worker context.
2026-05-30 08:43:58 +02:00
Peter Steinberger
0915b72bcf docs: expand provider descriptions 2026-05-30 07:41:59 +01:00
Peter Steinberger
7840fdbada fix(agent-core): cap shell exec timeouts 2026-05-30 02:40:32 -04:00
Peter Steinberger
4abde61366 fix(qa-lab): cap gateway wait timeouts 2026-05-30 02:33:11 -04:00
Vincent Koc
4291e32777 refactor: share OpenRouter video mode capabilities 2026-05-30 08:28:41 +02:00
Vincent Koc
453f40d5bf fix(testing): mark gauntlet cold-start observations 2026-05-30 08:26:41 +02:00
Peter Steinberger
470fc879e8 feat: add hosted model providers (#88247)
* feat(providers): add GMI provider

* feat(providers): add Novita provider

* feat(providers): add Qwen OAuth provider

* feat(providers): add Ollama Cloud provider

* docs: add hosted provider pages

* test(providers): align qwen catalog result typing
2026-05-30 08:26:16 +02:00
Peter Steinberger
311c1a05eb fix(plugins): cap CLI node invoke timeout 2026-05-30 02:25:18 -04:00
Peter Steinberger
7c3d7fc6e3 fix(memory): cap retry sleep delays 2026-05-30 02:21:24 -04:00
Vincent Koc
94df665cdc refactor: share Discord outbound payload options 2026-05-30 08:18:23 +02:00
Peter Steinberger
7c1484d637 refactor: extract media generation core package
Extract pure media generation catalog/model-ref/normalization helpers into a private workspace package and wire the package through build, watch, SDK alias, and plugin boundary d.ts paths.

Verification:
- node scripts/run-vitest.mjs test/scripts/crabbox-wrapper.test.ts packages/media-generation-core/src src/media-generation/runtime-shared.test.ts src/plugins/sdk-alias.test.ts src/infra/watch-node.test.ts src/plugins/registry.provider-like.test.ts src/agents/model-ref-shared.test.ts extensions/codex-supervisor/src/plugin-tools.test.ts extensions/codex-supervisor/src/supervisor.test.ts src/wizard/setup.official-plugins.test.ts src/infra/net/http-connect-tunnel.test.ts
- node scripts/prepare-extension-package-boundary-artifacts.mjs --mode=all
- node scripts/run-vitest.mjs src/plugins/contracts/extension-package-project-boundaries.test.ts src/plugins/sdk-alias.test.ts
- pnpm protocol:check
- pnpm check:changed
- .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main
- GitHub CI 26676608512
2026-05-30 08:17:43 +02:00
Peter Steinberger
be2c43ee3e fix(llm): cap codex retry delays 2026-05-30 02:17:30 -04:00
Peter Steinberger
5aa2bd7921 fix(agents): cap subagent context TTLs 2026-05-30 02:12:45 -04:00
Peter Steinberger
0a7ecd5428 fix(release): verify plugin npm readmes 2026-05-30 07:12:21 +01:00
Peter Steinberger
5db2cd6c00 perf: skip session store clones in turn hot paths 2026-05-30 07:11:03 +01:00
Jason (Json)
81505ada18 fix(codex): rotate native threads before overflow
Fix Codex app-server native thread overflow recovery and CLI compaction fallback.

- rotate Codex native startup bindings when rollout token pressure leaves too little headroom
- keep byte-size rollout fuses ahead of rollout content reads
- clear stale resumed context-engine bindings only when the stored thread id still matches
- fall back to context-engine compaction when Codex owns/skips native compaction

Verification:
- node scripts/run-vitest.mjs run --config test/vitest/vitest.extension-codex.config.ts extensions/codex/src/app-server/startup-binding.test.ts extensions/codex/src/app-server/run-attempt.context-engine.test.ts extensions/codex/src/app-server/session-binding.test.ts --reporter=verbose
- node scripts/run-vitest.mjs run --config test/vitest/vitest.agents.config.ts src/agents/command/cli-compaction.test.ts --reporter=verbose
- git diff --check origin/main...HEAD
- autoreview --mode branch --base origin/main: clean
- GitHub CI for 466bfbe78c: green

Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-05-30 08:07:29 +02:00
Peter Steinberger
8edeba0de3 fix(agents): cap provider request timeouts 2026-05-30 02:07:14 -04:00
Peter Steinberger
beb42b12c9 refactor(agents): type media completion delivery misses (#88250) 2026-05-30 08:04:50 +02:00
Peter Steinberger
42b320ad65 fix(cron): cap explicit job timeouts 2026-05-30 02:00:52 -04:00
Peter Steinberger
bba8015688 fix: show chat errors as visible messages
Surface gateway chat failures as visible assistant messages in the Control UI, with regression coverage and Crabbox/WebVNC proof.
2026-05-30 07:57:18 +02:00
Peter Steinberger
05e31bbedd refactor(agents): reuse terminal outcome for subagent waits 2026-05-30 06:56:52 +01:00
Peter Steinberger
c806a736af fix(agents): cap session wait timeouts 2026-05-30 01:56:44 -04:00
Vincent Koc
ceb179f84d refactor: share web search time filters 2026-05-30 07:53:51 +02:00
Peter Steinberger
72a2cc0acb chore(release): refresh generated release metadata 2026-05-30 06:51:37 +01:00
Peter Steinberger
cd07d013ba chore(release): bump version to 2026.5.30 2026-05-30 06:49:13 +01:00
Peter Steinberger
afa6d0cd18 fix(web): cap provider timeout seconds 2026-05-30 01:47:06 -04:00
Peter Steinberger
aa0d6e1bca refactor: extract LLM core packages (#88117)
* refactor: extract llm core packages

* chore: drop generated llm package artifacts

* fix: align llm package export artifacts

* test: fix moving main CI expectations

* fix: align llm core subpath aliases

* fix: use llm package exports

* fix: stabilize llm package boundary artifacts

* fix: sync llm boundary path contract

* test: isolate crabbox provider env

* test: pin crabbox configured-provider cases

* test: apply crabbox lease provider override
2026-05-30 07:45:04 +02:00
Vincent Koc
17e75f8641 test(e2e): expose bundled plugin lifecycle timing 2026-05-30 07:42:42 +02:00
Peter Steinberger
d69ee6777d fix(telegram): cap configured request timeouts 2026-05-30 01:42:01 -04:00
Peter Steinberger
344aff383b fix(acpx): cap service timer timeouts 2026-05-30 01:36:33 -04:00
Peter Steinberger
56f46a2581 fix(copilot): avoid bundling platform binaries 2026-05-30 06:34:48 +01:00
Peter Steinberger
62abfd3dcb fix(codex): cap app-server idle timers 2026-05-30 01:31:57 -04:00
Peter Steinberger
c536bd6af1 fix(agents): cap exec reviewer timeout 2026-05-30 01:29:05 -04:00
Peter Steinberger
fcdc25ba64 test: dedupe redundant test coverage 2026-05-30 06:27:13 +01:00
Peter Steinberger
9090f6b1c4 fix(comfy): cap workflow polling timeouts 2026-05-30 01:18:06 -04:00
Vincent Koc
0d604f160d refactor: share OpenAI realtime transcription payload 2026-05-30 07:02:12 +02:00
Nimrod Gutman
b352cb2d8e fix(ios): guard websocket ping continuation (#88231)
Merged via squash.

Prepared head SHA: b4cee97b8a
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Reviewed-by: @ngutman
2026-05-30 07:56:34 +03:00
Vincent Koc
b9933b2ec1 refactor: share Discord account token inspection 2026-05-30 06:47:40 +02:00
Ayaan Zaidi
f848a6f7f7 perf(agents): bound claude orphan transcript scan 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
72eff6b2e9 fix(agents): clear orphan tool state on string assistant turns 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
56fc17be78 fix(agents): avoid cli facade load in flush gate 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
3c3e39684e test(agents): cover flushed cli context engine session 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
25dfe9294f fix(agents): pass workspace to cli flush probe 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
622404fcec fix(agents): detect claude-specific orphaned tools 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
bda02f4be8 fix(agents): scope cli binding clears 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
58de6f91dc fix(auto-reply): clear unflushed cli bindings 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
c0a5f15dc8 fix(agents): clear unflushed cli bindings 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
21b5f601b6 fix(agents): preserve auth-boundary cli invalidation 2026-05-30 10:09:19 +05:30
Ayaan Zaidi
2e21158d04 refactor(agents): simplify cli session recovery probes 2026-05-30 10:09:19 +05:30
Abdel Gomez-Perez
16b510807b fix(agents/cli-runner): invalidate sessions whose transcript ends mid-tool
A claude-cli session whose JSONL transcript ends with an assistant
`tool_use` content block that was never answered by a `tool_result` user
message cannot resume — claude-cli will sit waiting for the missing
`tool_result`, hit its no-output watchdog, and the runtime kills it
with `reason=abort`. The dispatcher then sees an empty payload and emits
NO_REPLY, which to the user looks like the agent silently ignored their
message — same end-user symptom as the binding-flush amnesia bug, but a
different root cause.

The orphan can be left behind when:
  - Gateway restarts mid-tool (brew upgrade, manual kickstart, OOM,
    crash) — claude was waiting on a tool result that never arrived.
  - `claude-live-session.ts` no-output watchdog fires while a tool is
    actively running and OC kills the subprocess.
  - The tool itself crashed or hung past its own deadline.

In all cases the resumed session is dead until the binding gets cleared,
because every subsequent resume hits the same trailing tool_use and the
same kill cycle. Observed in production on a personal OpenClaw gateway
(3d-engineer agent, 50-message-deep transcript ending in a Bash
`tool_use`; every Telegram message after the orphan landed silently
aborted at the 180s no-output mark).

Add `claudeCliSessionTranscriptHasOrphanedToolUse` to the helpers that
walks the JSONL, finds the last assistant message, and returns true if
any of its `tool_use` ids has no matching `tool_result` later in the
file. Wire into `prepareCliRunContext` as a second invalidator gate
alongside `missing-transcript`. The new `invalidatedReason:
"orphaned-tool-use"` follows the same path as missing-transcript: the
binding is dropped, this turn starts a fresh session, and the prior
context is reseeded into the new session via `RAW_TRANSCRIPT_RESEED`.

Detection only considers TRAILING orphans — an unanswered tool_use
deeper in history is inert because a later assistant message already
moved past it. Only the most recent assistant message's tool_use ids
matter for forward progress.

Probe runs only for claude-cli providers and only when the transcript-
content gate already passed, so we add no I/O on already-invalidated
sessions and no behavior change for non-claude providers.

AI-assisted: yes. Tooling: Claude Opus + claude-cli.
2026-05-30 10:09:19 +05:30
Abdel Gomez-Perez
07c1245db4 fix(agents/cli-runner): gate cliSessionBinding persist on transcript flush
When a claude-cli turn produces a session id but the underlying claude
subprocess fails to flush an assistant-role record to its
~/.claude/projects/<cwd>/<sid>.jsonl transcript (e.g. mid-turn kill from
a concurrent fingerprint-mismatched turn, supervisor restart, internal
failure), buildCliRunResult was still persisting that session id into
cliSessionBinding. The next turn ran claudeCliSessionTranscriptHasContent,
didn't find the file, logged 'cli session reset: reason=missing-transcript',
and started a brand-new claude session with empty memory.

End-user symptom: agent forgets prior conversation between turns.

Gate the cliSessionBinding spread on the same predicate the next-turn
invalidator uses, evaluated at write time. Also clear agentMeta.sessionId
in the same case so the session-store fallback at command/session-store.ts
(which reads agentMeta.sessionId via setCliSessionId when the binding is
absent) doesn't re-persist the unflushed sid through a different field
path. The fallback is what makes the binding-only gate insufficient on
its own; both writes must drop together.

The gate only fires for claude-cli providers — other CLI providers don't
write to ~/.claude/projects, so probing them would always return false
and incorrectly strip valid binding metadata. isCliBindingFlushed now
takes the provider id and returns true unconditionally for non-claude-cli
sessions.

A bounded retry (0 / 50 / 150 ms) tolerates the brief gap between
claude-cli's stdio close and the OS making the JSONL line visible to
readers (cooperative fsync semantics on APFS, but not guaranteed under
stress).

The transcript-probe is exposed as an injectable dep
(setCliRunnerTestDeps / restoreCliRunnerTestDeps) mirroring the existing
pattern in src/agents/cli-runner/prepare.ts so isCliBindingFlushed is
testable without touching ~/.claude/projects.

AI-assisted: yes. Tooling: Claude Opus + claude-cli. Codex review caught
the fallback path and the missing provider gate before this hit upstream.
Real-Behavior-Proof: dist-side patch on M5 gateway; branch-build
follow-up pending — see PR body.
2026-05-30 10:09:19 +05:30
Vincent Koc
d13c8b03c9 refactor: share Google Meet audio input loop 2026-05-30 06:34:06 +02:00
Vincent Koc
7b3104fe4c chore(crabbox): default runner billing to azure 2026-05-30 06:25:35 +02:00
Vincent Koc
8fa4c4ff4e test(e2e): print MCP Docker proof logs 2026-05-30 06:24:58 +02:00
Vincent Koc
67ddc1a3e1 refactor: share Google Chat plugin base 2026-05-30 06:11:31 +02:00
Vincent Koc
a17487bc9f refactor: share QA channel plugin base 2026-05-30 06:05:36 +02:00
Marcus Castro
f613f32b22 fix(whatsapp): retry QR login 408 timeouts (#88183) 2026-05-30 00:59:12 -03:00
Vincent Koc
03415bb696 refactor: share MSTeams outbound send resolvers 2026-05-30 05:53:39 +02:00
Vincent Koc
723b5085d9 fix(dev): reject closed gateway websocket calls 2026-05-30 05:46:19 +02:00
Vincent Koc
28ffcf88bd refactor: share Slack approval block helpers 2026-05-30 05:43:30 +02:00
Dallin Romney
7de025eacd fix: route explicit vitest files through project runner (#88127) 2026-05-29 20:38:52 -07:00
Ayaan Zaidi
1659b26151 fix(agent): allow media retry after blocked delivery 2026-05-30 09:07:53 +05:30
Ayaan Zaidi
c88178d9b6 fix(agent): recover media completion delivery 2026-05-30 09:07:53 +05:30
Vincent Koc
117af11a6f fix(test): route tooling vitest files narrowly 2026-05-30 05:32:13 +02:00
Vincent Koc
b5bae67aad refactor: share Telegram outbound send context 2026-05-30 05:28:50 +02:00
Vincent Koc
0fdc51f35d fix(e2e): bound secret provider readiness probes 2026-05-30 05:19:49 +02:00
Vincent Koc
a1c6882777 refactor: share Discord agent component controls 2026-05-30 05:04:15 +02:00
Vincent Koc
59c84f8e5c refactor: share WhatsApp media send state 2026-05-30 04:56:07 +02:00
Peter Steinberger
d115fb4cf9 refactor: move task state to shared sqlite
Move task run, delivery, and flow registry persistence onto the shared OpenClaw state SQLite database.

Summary:
- Store task runs, delivery state, and flow runs in state/openclaw.sqlite via the generated Kysely schema.
- Migrate shipped task sidecars into the shared state DB and archive old sidecars, including invalid-config/read-only CLI paths.
- Keep startup migration lightweight for read-only status/tasks paths while still detecting known legacy state markers and custom session stores.

Verification:
- .agents/skills/autoreview/scripts/autoreview --mode local: clean after final fix
- pnpm test src/tasks/task-registry.store.test.ts src/tasks/task-flow-registry.store.test.ts src/commands/doctor-state-migrations.test.ts -- --reporter=verbose
- pnpm test src/commands/doctor-state-migrations.test.ts src/cli/program/config-guard.test.ts src/cli/route.test.ts src/cli/command-path-policy.test.ts -- --reporter=verbose
- pnpm test src/cli/program/config-guard.test.ts src/cli/route.test.ts src/cli/command-startup-policy.test.ts src/cli/command-path-policy.test.ts src/cli/command-execution-startup.test.ts -- --reporter=verbose
- pnpm test src/cli/program/config-guard.test.ts src/cli/argv.test.ts src/cli/route.test.ts src/commands/doctor-config-preflight.state-migration.test.ts -- --reporter=verbose
- pnpm test src/tasks/task-flow-registry.store.test.ts -- --reporter=verbose
- pnpm test test/scripts/lint-suppressions.test.ts -- --reporter=verbose
- pnpm db:kysely:check
- pnpm lint:kysely
- git diff --check HEAD
- pnpm test:startup:memory
- PR CI green on 2f7d76f0d5
2026-05-30 04:54:37 +02:00
Vincent Koc
e9dee8dfe1 refactor: share harness truncation result helpers 2026-05-30 04:41:49 +02:00
Vincent Koc
9f30af5a96 fix(e2e): bound bundled plugin readiness probes 2026-05-30 04:38:21 +02:00
Dallin Romney
29b32050c1 feat(ci): autoscrub dependency lockfile-only PR changes (#87796)
* ci: autoscrub dependency lockfile residue

* ci: harden dependency autoscrub commits

* ci: scope dependency autoscrub tokens

* ci: split autoscrub base reads

* ci: expand autoscrub proof comment
2026-05-29 19:37:16 -07:00
Vincent Koc
815ffb3bb2 refactor: share Codex thread binding flow 2026-05-30 04:27:24 +02:00
Vincent Koc
440e737c67 fix(e2e): stop credential retries after deadline 2026-05-30 04:21:01 +02:00
Dallin Romney
784fbcfd16 ci: relax platform checkout fetch timeout (#88199) 2026-05-29 19:17:29 -07:00
Josh Avant
584fa3215c Fix restart sentinel internal continuations (#88161)
* fix restart sentinel internal continuations

* update gateway prompt snapshots

* stabilize sandbox browser audit timer tests

* drive sandbox audit timeouts deterministically

* drive gh-read timeout tests deterministically

* drive label-open-issues timeout tests deterministically

* document deterministic timeout test timers

* test: preserve deterministic timer setup after rebase
2026-05-29 19:06:54 -07:00
Kevin Lin
dc4f3b57cf fix(imessage): preserve SMS approval reply routes
Preserve iMessage SMS reply routes for approval replies so a direct SMS /approve response can acknowledge and return results to the same SMS conversation.

Verification: gateway-only build, extension type checks, CI build-artifacts/check-prod-types/check-test-types/check-lint/check-additional-extension-package-boundary, and live prod iMessage SMS approval proof. checks-node-core-fast was waived by maintainer request after unrelated flaky failures in non-iMessage tests.
2026-05-29 19:00:45 -07:00
Vincent Koc
985b41e136 refactor: share Codex auth identity helpers 2026-05-30 03:57:20 +02:00
Vincent Koc
51d0ef80c2 fix(e2e): bound kitchen sink readiness probes 2026-05-30 03:54:47 +02:00
Josh Avant
f870beac85 fix(codex): project raw image generation media (#88191) 2026-05-29 18:50:11 -07:00
Vincent Koc
75de853c37 refactor: share provider OAuth runtime helpers 2026-05-30 03:30:51 +02:00
Josh Avant
b3b962a051 fix subagent dm completion delivery (#88182) 2026-05-29 18:24:49 -07:00
Vincent Koc
6f3f4f7420 fix(dev): stop discord smoke retries past deadline 2026-05-30 03:15:29 +02:00
Peter Steinberger
acb0e9c155 fix(agents): extend terminal outcome projections (#88162)
* fix(agents): extend terminal outcome projections

* fix(agents): align terminal outcome follow-up checks

* fix(agents): satisfy terminal outcome mapper lint

* test(scripts): isolate websocket open timers

* test(security): drive sandbox browser timeout timers

* test(scripts): drive gh-read timeout timers

* test(agents): isolate code mode timers

* fix(agents): preserve hard timeouts on wait surfaces

* fix(agents): require timeout attribution for provider errors

* fix(sdk): require timeout attribution for provider errors

* fix(scripts): preserve changelog parse cause
2026-05-30 03:13:01 +02:00
Vincent Koc
be1c4f3ee1 fix(release): preserve changelog restore cause 2026-05-30 03:08:04 +02:00
Vincent Koc
deb48a96fb refactor: share prompt template arguments 2026-05-30 03:05:46 +02:00
Vincent Koc
086df266cc fix(release): guard package changelog restore 2026-05-30 03:01:27 +02:00
Vincent Koc
730aa406ef fix(ui): abort orphaned workboard runs 2026-05-30 02:52:20 +02:00
Vincent Koc
1a4eb0b5e7 refactor: share agent truncate utilities 2026-05-30 02:46:45 +02:00
Peter Steinberger
4be8a58a7d test(ci): isolate infra vitest lane 2026-05-30 02:46:35 +02:00
Peter Steinberger
a341ae27ec feat(workboard): add orchestration primitives
Adds Workboard orchestration statuses, dependency links, idempotent child creation, dispatch, and complete/block lifecycle operations backed by the plugin SQLite keyed store.

Persists tenant, skills, workspace, schedule, runtime, retry, dispatch, and handoff metadata in card records, with claim scoping and token redaction. Surfaces the new states and metadata in the Control UI, horizontal board layout, localized strings, and Workboard docs.

Verification:
- pnpm test extensions/workboard/src/store.test.ts extensions/workboard/src/tools.test.ts extensions/workboard/src/gateway.test.ts ui/src/ui/controllers/workboard.test.ts ui/src/styles/workboard.test.ts ui/src/ui/views/workboard.test.ts -- --reporter=verbose
- pnpm ui:i18n:check
- /Users/steipete/Projects/agent-scripts/skills/autoreview/scripts/autoreview --mode branch --base origin/main, followed by focused clean local autoreview loops for final fixes
- env -u OPENCLAW_TESTBOX pnpm check:changed
- git diff --check
2026-05-30 02:40:46 +02:00
clawsweeper[bot]
18f94fc83a fix(agents): classify embedded provider business denials for fallback (#84814)
Summary:
- The PR classifies selected embedded agent provider-denial error payloads through the shared failover matcher ... 1/current-ak auth matching, preserves guarded non-fallback cases, and covers fallback progression in tests.
- PR surface: Source +34, Tests +166. Total +200 across 5 files.
- Reproducibility: yes. Current main is source-reproducible: a non-GPT embedded result whose only signal is CE ... returns null from the classifier, and the fallback wrapper treats null classification as candidate success.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(agents): classify embedded provider business denials for fallback
- PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8304…

Validation:
- ClawSweeper review passed for head e266beac93.
- Required merge gates passed before the squash merge.

Prepared head SHA: e266beac93
Review: https://github.com/openclaw/openclaw/pull/84814#issuecomment-4505010446

Co-authored-by: Stellar鱼 <2182712990@qq.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-30 00:34:28 +00:00
Peter Steinberger
aada44fca5 fix(agents): preserve Codex auth for compaction fallback
Fixes #86820.

Preserve Codex OAuth-backed compaction by selecting and loading the Codex harness before resolving direct or queued compaction models, while keeping OpenAI-compatible custom base URLs on the OpenAI context config path. Also preserves persisted concrete harness pins so compaction does not hot-switch existing sessions just because an explicit Codex fallback exists.

Verification:
- node scripts/run-vitest.mjs src/agents/embedded-agent-runner/compact.hooks.test.ts src/agents/harness/selection.test.ts src/agents/harness/runtime-plugin.test.ts
- pnpm tsgo:prod
- pnpm check:test-types
- pnpm lint --threads=8
- git diff --check origin/main...HEAD
- git diff --check
- autoreview clean: no accepted/actionable findings reported; overall patch is correct (0.82)
- GitHub PR checks green on ac6f93de4a
2026-05-30 02:26:00 +02:00
Peter Steinberger
43658872d9 test: stabilize sandbox browser audit timers 2026-05-30 01:18:53 +01:00
Dallin Romney
bd04d2db0d feat: only include the current changelog section in tarball (#88107)
* build: package current changelog section

* build: guard packaged changelog section size
2026-05-29 17:18:35 -07:00
Merlin
c8a733eae5 fix(gateway): resolve message actions against runtime config (#84535)
* fix(gateway): resolve message action config from runtime snapshot

* fix(gateway): preserve runtime config matching through auto-enable

* fix(gateway): preserve auto-enabled message action fallback

* fix(gateway): use canonical runtime snapshot for message actions

* fix(discord): route credential actions through gateway

---------

Co-authored-by: Merlin <258679497+funmerlin@users.noreply.github.com>
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-05-29 17:14:45 -07:00
Vincent Koc
3e35f599bc refactor: collapse zalo runtime api barrel 2026-05-30 02:11:24 +02:00
Dallin Romney
914f313740 test(unit-fast): isolate fake-timer files (#88160) 2026-05-29 17:11:05 -07:00
Peter Steinberger
4efc48a80d test(ci): stabilize sandbox browser audit timeout 2026-05-30 02:06:58 +02:00
Vincent Koc
ecc5601b2a fix(github): bound proof comment API bodies 2026-05-30 01:58:19 +02:00
Peter Steinberger
14795dc0cc test: stabilize block reply abort timers 2026-05-30 00:56:15 +01:00
Peter Steinberger
05dee6760d test: stabilize tool search fetch timeout 2026-05-30 00:54:20 +01:00
Peter Steinberger
582aa1ceb2 test(ci): stabilize tool search gateway timeout helper 2026-05-30 01:49:13 +02:00
Peter Steinberger
f6e1bc393b fix(fal): cap video queue deadline 2026-05-29 19:38:41 -04:00
Peter Steinberger
c91d1048e4 fix(release): harden release ci summary lookup 2026-05-30 00:35:57 +01:00
Peter Steinberger
90994a38a0 fix(openrouter): cap music stream timeout 2026-05-29 19:34:45 -04:00
Vincent Koc
c01a0f5588 refactor: share provider oauth runtime helpers 2026-05-30 01:31:10 +02:00
Peter Steinberger
8ff61be8d6 fix(providers): cap local service timers 2026-05-29 19:29:40 -04:00
Peter Steinberger
90d569e896 fix(telegram): centralize positive timer bounds 2026-05-29 19:25:30 -04:00
Peter Steinberger
d8bc71f222 test: stabilize realtime websocket timeout 2026-05-30 00:18:02 +01:00
Peter Steinberger
f3ea2982f5 test(realtime): stabilize websocket timeout test 2026-05-30 01:15:31 +02:00
Peter Steinberger
8f389de88f fix(release): build beta smoke REST curl command 2026-05-30 00:12:11 +01:00
Peter Steinberger
2bcba64906 fix(release): avoid gh api in beta smoke 2026-05-30 00:12:11 +01:00
Peter Steinberger
cbd492d680 fix(feishu): reopen retryable bot menu replay 2026-05-30 00:12:10 +01:00
Peter Steinberger
fadd275e7b fix(release): harden candidate run status polling 2026-05-30 00:11:24 +01:00
Peter Steinberger
35a3c064a7 fix(release): avoid gh api for candidate reads 2026-05-30 00:10:05 +01:00
Peter Steinberger
91adfa1582 fix(telegram): cap polling lease wait timer 2026-05-29 19:07:40 -04:00
Vincent Koc
f3f85ae5f7 refactor: share live transport scenario helpers 2026-05-30 01:05:56 +02:00
Peter Steinberger
69550a9d3d ci: satisfy build profile lint 2026-05-30 00:05:40 +01:00
Peter Steinberger
5b8472b0b9 fix(whatsapp): cap credential flush timeout 2026-05-29 19:03:59 -04:00
Dallin Romney
73dd36626c test(infra): avoid max fake-timer jumps (#88155) 2026-05-29 16:02:41 -07:00
Peter Steinberger
83905c9169 fix(ci): repair main lint gates 2026-05-30 00:01:11 +01:00
Peter Steinberger
d92a0292a9 fix(memory): cap qmd process timeouts 2026-05-29 19:00:05 -04:00
Peter Steinberger
0e6937cc1b ci: skip bundled dts in artifact build 2026-05-29 23:56:31 +01:00
Peter Steinberger
b1e5c9d7fa fix(agents): centralize terminal run outcome precedence (#88136)
* fix(agents): centralize terminal run outcome precedence

* docs(agents): explain terminal outcome precedence

* docs(agents): note terminal outcome helper

* fix(agents): preserve pending hard timeout over late completion

* test(agents): align global session scoping expectation

* Revert "test(agents): align global session scoping expectation"

This reverts commit 9b4a0c3cb1b3885299eea7081d97f7142c415dc2.

* test(infra): stabilize CONNECT timeout cap test

* fix(agents): prioritize hard timeout terminal evidence

* fix(gateway): preserve pending hard timeout snapshots
2026-05-30 00:56:20 +02:00
Vincent Koc
ba3eae5518 fix(dev): cap Discord smoke response bodies 2026-05-30 00:54:23 +02:00
Peter Steinberger
60673b03bc fix(zalouser): cap qr login timeouts 2026-05-29 18:54:18 -04:00
Peter Steinberger
d5e8da8499 fix(ci): repair main normalization checks 2026-05-29 23:53:28 +01:00
keshavbotagent
5f89fbe669 fix(codex): recover app-server completion stalls
Fix Codex app-server completion-stall recovery so replay-safe stdio completion-idle failures retry once, while progress/terminal turn-watch timeouts only surface timeout payloads.

Also preserve post-tool completion guards for scoped native response deltas and stabilize the oversized CONNECT timeout regression test picked up from latest main.

Co-authored-by: Kelaw - Keshav's Agent <keshavbotagent@gmail.com>
2026-05-30 00:52:48 +02:00
Peter Steinberger
bc848b367f refactor: add shared sqlite state database
Adds the shared SQLite state database base, moves plugin keyed state into it with doctor migration coverage, and keeps generated Kysely guardrails aligned. Proof: focused SQLite/plugin-state tests, db:kysely:check, lint:kysely, architecture/dependency guards, autoreview, and PR CI all clean.
2026-05-30 00:52:23 +02:00
Peter Steinberger
a6a99b923e fix(zalouser): cap probe timeout timer 2026-05-29 18:48:43 -04:00
Peter Steinberger
ccad5d7b63 fix(web): cap guarded fetch timeout seconds 2026-05-29 18:45:30 -04:00
Peter Steinberger
42b4715124 test(infra): preserve script wrapper fixture 2026-05-30 00:42:41 +02:00
Peter Steinberger
465c4cb580 test(infra): stabilize main CI tests 2026-05-30 00:42:41 +02:00
Peter Steinberger
37ccec0dc7 fix(nostr): cap profile import relay timers 2026-05-29 18:40:17 -04:00
Peter Steinberger
cb4d2e7bb9 test: stabilize infra state shard 2026-05-29 23:38:31 +01:00
Peter Steinberger
41a92ae445 perf: resolve native esm plugin sdk imports 2026-05-29 23:38:08 +01:00
Peter Steinberger
d7354d61b2 fix(channels): centralize stall watchdog timer bounds 2026-05-29 18:35:37 -04:00
Kevin Lin
c57671176e refactor: share native approval route gates
Share native approval route gate helpers across mainstream channel approval runtimes and keep PR #87770 green on current main.
2026-05-29 15:32:31 -07:00
Peter Steinberger
44e31f7c6a test(gateway): stabilize live helper shard 2026-05-30 00:31:07 +02:00
Peter Steinberger
63a06e312d ci: reduce main workflow critical path 2026-05-29 23:29:32 +01:00
Peter Steinberger
ed9e9aab3d fix(infra): cap transport readiness timeouts 2026-05-29 18:28:15 -04:00
Vincent Koc
dfe99e9cd7 refactor: share media understanding post params 2026-05-30 00:27:13 +02:00
Vincent Koc
9331ac2cb0 fix(scripts): cap issue labeler response bodies 2026-05-30 00:25:51 +02:00
Peter Steinberger
7f28c8bd07 fix: route media completions through requester agent (#88141) 2026-05-30 00:24:28 +02:00
Peter Steinberger
bafa6de76d fix(proxy): cap connect tunnel timeouts 2026-05-29 18:24:03 -04:00
Sally O'Malley
6037a74660 Add plugin manifest contract for SecretRef provider integrations (#82326)
* secret-provider-integrations

Signed-off-by: sallyom <somalley@redhat.com>

* feat(secrets): configure plugin provider presets

* secrets: use plugin-managed provider refs

Signed-off-by: sallyom <somalley@redhat.com>

* fix secretref auth profile service env

* test secret provider integration e2e

* fix secretref plugin config service env

* fix secret provider preset schema alignment

* stabilize secret provider service proof

* validate secret provider plugin integrations

* harden secret provider resolver paths

* scope secret provider config validation

* stabilize openai secret provider proof

* fix secret provider metadata proof

* stabilize config baseline proof

* fix secret provider e2e lint

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-05-29 18:20:45 -04:00
Peter Steinberger
f1235477de fix(apns): cap direct timeout paths 2026-05-29 18:18:33 -04:00
Peter Steinberger
526925c509 test: stabilize remaining CI flakes 2026-05-29 23:17:36 +01:00
Peter Steinberger
3204efc195 fix(infra): cap shell env timeouts 2026-05-29 18:11:50 -04:00
Peter Steinberger
2860da8cd5 fix(infra): cap jsonl socket timeouts 2026-05-29 18:07:19 -04:00
Peter Steinberger
8f2e520abb fix(apns): cap relay timeout 2026-05-29 18:03:41 -04:00
Peter Steinberger
fe3f2bee3f test: fix main CI regressions 2026-05-29 23:03:01 +01:00
Peter Steinberger
a51e8a21b6 fix(ci): break skills loading cycle 2026-05-30 00:02:24 +02:00
Peter Steinberger
260e8e26fd fix(ci): repair main checks 2026-05-30 00:02:24 +02:00
Vincent Koc
196ea61ec4 refactor: share diagnostics timeline span helpers 2026-05-30 00:01:58 +02:00
Vincent Koc
49cc613021 fix(supervisor): narrow stored session limit parsing 2026-05-30 00:01:47 +02:00
Peter Steinberger
347486a4c4 fix(openai): cap codex oauth preflight timeout 2026-05-29 17:59:29 -04:00
Peter Steinberger
1517fe2c32 perf: prefer package-local bundled plugin artifacts 2026-05-29 22:57:40 +01:00
Peter Steinberger
fe69df6b3a fix(gateway-client): cap stop wait timeout 2026-05-29 17:55:17 -04:00
Shakker
dac67b3978 test: complete skills status mock surface 2026-05-29 22:51:15 +01:00
Shakker
a6c694da7e test: remove duplicate skill fixture wrappers 2026-05-29 22:51:15 +01:00
Shakker
259d6aada8 test: share skills entry fixtures 2026-05-29 22:51:15 +01:00
Shakker
de6aaf8e23 test: preserve real skills status exports 2026-05-29 22:51:15 +01:00
Shakker
496e1e071f perf: use set for bundled skill allowlist 2026-05-29 22:51:15 +01:00
Shakker
112939df60 perf: prepare bundled skill allowlist once 2026-05-29 22:51:15 +01:00
Shakker
e8cece82ef perf: speed up skills filtering 2026-05-29 22:51:15 +01:00
Shakker
93c68c4432 perf: reuse resolved skills allowlist 2026-05-29 22:51:15 +01:00
Shakker
2009bec87a refactor: reuse shared skills prompt formatter 2026-05-29 22:51:15 +01:00
Shakker
f382a36458 perf: centralize skill status lookup 2026-05-29 22:51:15 +01:00
Shakker
45b12c0085 refactor: share skill command exposure policy 2026-05-29 22:51:15 +01:00
Shakker
0b86591d9d perf: avoid unnecessary skills index maps 2026-05-29 22:51:15 +01:00
Shakker
1221414709 feat: add skills index 2026-05-29 22:51:15 +01:00
Peter Steinberger
1c8de09ba9 ci: stabilize main checks 2026-05-29 22:49:06 +01:00
Peter Steinberger
7cd93f8e5c fix(infra): cap request body timeouts 2026-05-29 17:48:40 -04:00
Dallin Romney
1dbde826f2 fix ci mainline checks (#88137) 2026-05-29 14:41:30 -07:00
Peter Steinberger
1d84255581 fix(media): cap generation provider timeouts 2026-05-29 17:36:53 -04:00
Peter Steinberger
e1c88d4425 fix(tts): cap speech provider timeouts 2026-05-29 17:31:37 -04:00
Vincent Koc
e69fedc8cf refactor: share media temp save wrapper 2026-05-29 23:24:56 +02:00
Peter Steinberger
a841778b7b fix(acp): cap turn timeout timers 2026-05-29 17:20:48 -04:00
Peter Steinberger
522d0f7ef5 perf: reuse gateway runtime metadata 2026-05-29 22:16:53 +01:00
Peter Steinberger
50378c01e4 fix(discord): cap monitor helper timeouts 2026-05-29 17:15:28 -04:00
Peter Steinberger
3416edf740 fix(codex-supervisor): centralize session limit parsing 2026-05-29 17:10:38 -04:00
Peter Steinberger
040f14b641 fix(browser): cap node runtime timeouts 2026-05-29 17:07:33 -04:00
Peter Steinberger
8c53d100ca fix(ci): repair main checks 2026-05-29 23:05:54 +02:00
Peter Steinberger
5230a23202 fix(browser): cap control fetch timeouts 2026-05-29 17:04:43 -04:00
Peter Steinberger
6443d06764 fix: move compaction planning off the event loop
Move compaction planning work to a bounded worker-thread path so large transcript planning no longer monopolizes the agent event loop. Extract pure planning helpers, sanitize worker inputs before structured clone, package the worker entrypoint, and keep synchronous fallback only for worker-unavailable cases.

Fixes #86358.
2026-05-29 23:04:23 +02:00
Vincent Koc
6fd8cfd5bb refactor: share script bounded response reader 2026-05-29 23:02:03 +02:00
Peter Steinberger
95f9231136 fix(feishu): cap async helper timeouts 2026-05-29 17:01:11 -04:00
Peter Steinberger
e6b011823e fix(signal): cap client request timeouts 2026-05-29 16:57:04 -04:00
Peter Steinberger
31169ff3b4 fix: bound default heartbeat run timeout (#88133)
Fixes #87438.

Bound unset heartbeat run timeouts so background heartbeat turns no longer inherit the built-in 48-hour interactive agent default. Timeout precedence is explicit heartbeat timeout, explicit global agent timeout, then heartbeat cadence capped at 600 seconds.

Verification:
- git diff --check
- Testbox tbx_01kstna69zvznn4fq7zrqr04a1: corepack pnpm test src/infra/heartbeat-runner.model-override.test.ts -- --reporter=verbose passed 13 tests
- Direct node --import tsx runtime probe verified 300s, 600s, 60s, and 45s timeout precedence cases
- Autoreview clean

Known CI state:
- PR CI run 26661465248 has failures matching latest main CI run 26661386468 at a7820b2f54; failures are outside this six-file heartbeat/docs diff.
2026-05-29 22:56:13 +02:00
Peter Steinberger
7f09d6ae48 fix(usage): cap provider usage fetch timeouts 2026-05-29 16:53:07 -04:00
Peter Steinberger
a7820b2f54 fix(provider): cap operation timeouts 2026-05-29 16:47:36 -04:00
Vincent Koc
150673a734 refactor: share script budget number parsing 2026-05-29 22:44:38 +02:00
Peter Steinberger
b7e9272dbe fix(agents): cap model scan timeouts 2026-05-29 16:43:03 -04:00
Peter Steinberger
0b86decf94 fix: keep live OpenClaw session locks during cleanup (#88129)
Keep session lock cleanup from removing live OpenClaw-owned locks solely because they are old. Cleanup now reports age-only stale locks without deleting them, while still removing dead, orphaned, recycled, malformed-old, and non-OpenClaw-owned locks.

Update doctor docs and regression coverage for the cleanup/repair contract.

Refs #87779
2026-05-29 22:42:04 +02:00
Peter Steinberger
61e7b042b6 fix(crestodian): cap probe timeouts 2026-05-29 16:38:45 -04:00
Peter Steinberger
d10fd6b8f4 test: fix timeout mock return types 2026-05-29 16:38:45 -04:00
Peter Steinberger
a509c48f0e feat: add core session goals (#87469)
* feat: add core session goals

* feat: polish session goals in tui

* fix: resolve goal tool session stores

* fix: keep get goal read-only

* fix: migrate legacy goal session slots

* fix: persist goal token accounting

* fix: validate goal session rows

* refactor: remove unshipped goal legacy handling

* fix: handle goal commands in local tui

* fix: satisfy goal tool display checks

* fix: reset goal budget on overdue resume

* feat: surface session goals across control surfaces

* test: update gateway protocol test import

* test: align goal fixture types with protocol

* fix: scope selected global transcript usage fallback

* fix: scope selected global web subscriptions

* fix: preserve selected global agent during chat dispatch

* fix: scope chat inject to selected global agents
2026-05-29 22:36:29 +02:00
Peter Steinberger
057be10e5b perf: reuse provider handles and strict tool schemas 2026-05-29 21:34:59 +01:00
Peter Steinberger
b832975f3e fix(mattermost): cap dm retry timeouts 2026-05-29 16:31:01 -04:00
Peter Steinberger
26ea53cc68 fix(zai): cap endpoint probe timeouts 2026-05-29 16:28:33 -04:00
Peter Steinberger
57aec8c565 docs(skills): require grouped release changelogs 2026-05-29 21:28:06 +01:00
Vincent Koc
be6cac375a refactor: share e2e mock http helpers 2026-05-29 22:26:17 +02:00
Peter Steinberger
6e125adf3a fix(xiaomi): cap tts request timeouts 2026-05-29 16:25:32 -04:00
Peter Steinberger
0983e763fe fix(qa-matrix): cap substrate request timeouts 2026-05-29 16:22:33 -04:00
Peter Steinberger
69c3b56bde fix: stabilize codex supervisor session listing 2026-05-29 21:20:00 +01:00
Peter Steinberger
f66d14def5 fix(zalo): cap api request timeouts 2026-05-29 16:19:18 -04:00
Lucas Giordano
eb7e237151 docs(browser): add Notte cloud browser to direct WebSocket CDP providers
Notte exposes a CDP-compatible WebSocket gateway at
wss://us-prod.notte.cc/sessions/connect?token=<NOTTE_API_KEY> that
auto-creates a session on connect — the same shape OpenClaw's existing
"Direct WebSocket CDP providers" section was generically framed for
(per #31085).

Real behaviour proof (against wss://us-prod.notte.cc/sessions/connect):

  $ openclaw browser --browser-profile notte open https://example.com
  opened: https://example.com/
  tab: t4
  id: 7FE04AC44931A6E1C799DE4ABF0DC807

A screenshot captured against the same session is a 1254x1111 PNG of
the rendered example.com page.

Playwright connectOverCDP flow against the same URL (today):

  connectOverCDP                                      695ms
  context.newCDPSession(page)                         169ms
  session.send('Target.getTargetInfo') → targetId     87ms
  page.goto('https://example.com')                    631ms
  total                                               1.8s

AI-assisted (Claude Opus 4.7). codex review --base origin/main returned
clean. See PR description for the full pre-flight checklist.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 22:17:32 +02:00
Vincent Koc
beb665212c refactor: share e2e bounded response reader 2026-05-29 22:10:14 +02:00
zhang-guiping
689e8ec893 fix(agents): forward ACP spawn attachments
Forward initial image/file attachments when spawning ACP subagents through the existing sessions_spawn attachment opt-in. Remove the PR-only acpEnabled config split so ACP uses the same attachment gate as other runtimes.

Also fix the PR branch CI fallout: type the browser element CLI request mock and use Vitest env stubs in the Azure speech test to satisfy the changed-path security scan.

Verification:
- GitHub CI passed on f6ca26b160.
- Autoreview clean.
- Crabbox AWS live OpenAI proof passed: cbx_a576d49493fe / run_081dcc6c6a1b.

Thanks @zhangguiping-xydt.
2026-05-29 22:08:19 +02:00
Peter Steinberger
f8ad20b87e fix(signal): cap container timeout timers 2026-05-29 16:08:08 -04:00
Nimrod Gutman
6897711d19 feat(ios): add talk tab realtime playback (#88105)
Merged via squash.

Prepared head SHA: f41112a882
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Reviewed-by: @ngutman
2026-05-29 23:06:19 +03:00
Peter Steinberger
8ed5ea499d fix: keep compaction timeout snapshots continuable 2026-05-29 22:06:16 +02:00
xin zhuang
960117259d fix(agents): preserve rotated compaction session identity
Fix `sessions.json` persistence after compaction transcript rotation.

When the agent runtime rotates from the pre-compaction session transcript to the post-compaction transcript, post-run consumers now receive the effective OpenClaw session id and session file. Backend CLI session ids remain backend metadata and no longer overwrite the top-level OpenClaw session identity.

Refs #88040.
Thanks @1052326311.

Verification:
- `node scripts/run-vitest.mjs src/agents/agent-command.compaction-rotation.test.ts src/agents/agent-command.live-model-switch.test.ts src/agents/command/session-store.test.ts`
- Autoreview clean
- GitHub CI green on PR head `c3d3c77ddf675bbba0b9ba6681b030a2f69a898c`
2026-05-29 22:05:05 +02:00
Peter Steinberger
4b9a80d895 fix(discord): cap request timeout signals 2026-05-29 16:03:39 -04:00
Peter Steinberger
3b91d18c37 docs(skills): expand Discrawl archive workflow 2026-05-29 22:02:52 +02:00
Peter Steinberger
4f2dc09431 fix(auth): cap GitHub Copilot OAuth timeouts 2026-05-29 22:02:52 +02:00
Peter Steinberger
b3dc7a4a80 fix(exec): bind node auto-review to prepared plans 2026-05-29 22:01:27 +02:00
Peter Steinberger
e2966faea7 perf: reuse gateway session and plugin metadata paths 2026-05-29 21:01:00 +01:00
Peter Steinberger
b245cb2b6d docs(plugins): add external package readmes 2026-05-29 21:00:29 +01:00
Peter Steinberger
2b15850b47 build(plugins): externalize tokenjuice 2026-05-29 21:00:29 +01:00
Peter Steinberger
f10bad944f fix(oauth): cap tls preflight timeout 2026-05-29 15:59:27 -04:00
Peter Steinberger
fb8b9e9138 fix(copilot): cap oauth request timeouts 2026-05-29 15:54:28 -04:00
Dallin Romney
e848671e9d test(ci): fix main test expectations (#88122) 2026-05-29 12:53:30 -07:00
Vincent Koc
b1719474d5 refactor: share e2e incremental line reader 2026-05-29 21:51:46 +02:00
Peter Steinberger
c8f5a2e0e2 fix(qa-lab): cap credential broker request timeouts 2026-05-29 15:49:38 -04:00
Peter Steinberger
c4e1bb30da fix: close native hook relay replacement race 2026-05-29 21:47:14 +02:00
Peter Steinberger
1e2fda9e68 docs(plugins): clarify external plugin installs 2026-05-29 20:43:51 +01:00
Vincent Koc
7d0347b6de refactor: share ui chat send wrapper 2026-05-29 21:38:29 +02:00
Peter Steinberger
a0c1f5962d fix(runtime): centralize safe timer timeout resolution 2026-05-29 15:36:38 -04:00
Vincent Koc
33b81686ad test(file-transfer): remove stale tar fixture awaits 2026-05-29 21:23:11 +02:00
Vincent Koc
07870dff45 refactor: share codex app server start context 2026-05-29 21:19:55 +02:00
Peter Steinberger
99b24a80fb build(plugins): externalize copilot runtime 2026-05-29 20:14:38 +01:00
Peter Steinberger
a39c2d784e fix(minimax): cap tts timeout delays 2026-05-29 15:11:01 -04:00
Nimrod Gutman
0167f0a6df feat(ios): default to hosted push relay (#88096)
Merged via squash.

Prepared head SHA: 75f939af5c
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Co-authored-by: ngutman <1540134+ngutman@users.noreply.github.com>
Reviewed-by: @ngutman
2026-05-29 22:05:25 +03:00
Peter Steinberger
11e82bdef2 fix(lmstudio): cap model fetch timeout delays 2026-05-29 15:05:20 -04:00
Vincent Koc
7aca070723 fix(scripts): cap gh-read json bodies 2026-05-29 21:01:37 +02:00
Peter Steinberger
e5845dd452 fix(codex): cap responses request timeout delays 2026-05-29 14:59:37 -04:00
Vincent Koc
ba55b3e360 refactor: share script bounded response helper 2026-05-29 20:54:29 +02:00
Peter Steinberger
467b068fdc perf(sessions): patch single-entry store writes 2026-05-29 19:54:01 +01:00
Peter Steinberger
18bfd44439 test: shard channel import guardrails 2026-05-29 20:52:19 +02:00
Peter Steinberger
fb18f95348 test: stabilize slow assertion timings 2026-05-29 20:52:19 +02:00
Peter Steinberger
7f4338d435 test: speed up slow assertions 2026-05-29 20:52:18 +02:00
Peter Steinberger
16cd7f9d3f fix(oauth): cap request abort timeout delays 2026-05-29 14:52:01 -04:00
Peter Steinberger
4e2d9b0b76 fix(providers): cap model request timeout delays 2026-05-29 14:43:32 -04:00
Vincent Koc
040eba1cdc refactor: share bounded response reader 2026-05-29 20:34:12 +02:00
Vincent Koc
18d2bc441c fix(e2e): harden kitchen sink probe body caps 2026-05-29 20:31:54 +02:00
Peter Steinberger
75ef73d4f7 fix(talk): cap fast context timeout delay 2026-05-29 14:30:59 -04:00
Peter Steinberger
f440121a49 fix(node-host): cap timeout wrapper delays 2026-05-29 14:25:28 -04:00
Peter Steinberger
1ca7f5c0a0 perf(gateway): reuse session maintenance config during turns 2026-05-29 19:23:28 +01:00
Peter Steinberger
61031d1b1c feat(workboard): add agent coordination tools
Summary:
- Add Workboard agent coordination tools for list/read/claim/heartbeat/release/comment/proof/unblock flows.
- Store artifacts, claims, diagnostics, and notifications in the Workboard SQLite-backed plugin state; surface the new metadata through Gateway, Control UI, docs, and plugin manifest contracts.
- Add scoped claim authorization, token redaction, stale diagnostic cleanup, atomic proof artifact writes, and generated i18n metadata.

Verification:
- pnpm test ui/src/i18n/test/translate.test.ts extensions/browser/src/cli/browser-cli-actions-input/register.element.test.ts extensions/workboard/src/store.test.ts extensions/workboard/src/gateway.test.ts extensions/workboard/src/tools.test.ts ui/src/ui/controllers/workboard.test.ts ui/src/ui/views/workboard.test.ts
- pnpm ui:i18n:check
- env -u OPENCLAW_TESTBOX pnpm check:changed
- autoreview --mode local: clean
- PR CI passed; Windows checkout failure rerun passed on attempt 2
2026-05-29 20:23:21 +02:00
Peter Steinberger
afa6b81120 fix(sandbox): bound novnc observer token ttl 2026-05-29 14:20:18 -04:00
Peter Steinberger
4eeb7bfa57 fix(retry): cap unsafe retry delays 2026-05-29 14:15:38 -04:00
Vincent Koc
aae13f4dd2 refactor: share qa report arg parsing 2026-05-29 20:07:53 +02:00
Peter Steinberger
4305fb7cdf fix(auth): reject unsafe wham reset windows 2026-05-29 14:05:14 -04:00
Vincent Koc
e8217cbb7a fix(scripts): cap npm packument reads 2026-05-29 20:01:02 +02:00
Peter Steinberger
e3be541a6c fix(google): reject unsafe vertex adc lifetimes 2026-05-29 13:57:34 -04:00
Peter Steinberger
b9d7dd4a84 fix(feishu): normalize app registration poll timers 2026-05-29 13:53:05 -04:00
2942 changed files with 136646 additions and 35792 deletions

View File

@@ -100,6 +100,10 @@ Format first if formatting can change line locations. Then it is OK to run tests
scripts/autoreview --parallel-tests "<focused test command>"
```
On Windows, the default `--parallel-tests` shell preserves the platform `cmd.exe`
semantics used by Python `shell=True`. Use `--parallel-tests-shell powershell`
or `--parallel-tests-shell pwsh` when the focused test command is PowerShell-specific.
Tradeoff: tests may force code changes that stale the review. If tests or review lead to code edits, rerun the affected tests and rerun review until no accepted/actionable findings remain. Once that rerun exits cleanly, stop; do not spend another long review cycle on redundant confirmation.
## Review Panels
@@ -144,6 +148,22 @@ OpenClaw repo-local helper:
.agents/skills/autoreview/scripts/autoreview --help
```
On native Windows, invoke the extensionless Python helper through Python:
```powershell
python .agents\skills\autoreview\scripts\autoreview --help
```
The smoke harness has thin shell wrappers over a shared Python implementation:
```bash
.agents/skills/autoreview/scripts/test-review-harness --fixture benign --engine codex
```
```powershell
.agents\skills\autoreview\scripts\test-review-harness.ps1 -Fixture benign -Engine codex
```
`agent-scripts` checkout helper:
```bash
@@ -169,10 +189,11 @@ The helper:
- otherwise uses current PR base if `gh pr view` works
- otherwise uses `origin/main` for non-main branches
- supports `--engine codex`, `claude`, `droid`, and `copilot`; default is `AUTOREVIEW_ENGINE` or `codex`; Codex should remain the default when nothing is set
- resolves bare `git`, `gh`, reviewer, and PowerShell shell commands from absolute `PATH` entries only, never from the reviewed checkout; explicit relative `--*-bin` paths are resolved from the reviewed repository root
- use `--mode commit --commit <ref>` for already-committed work, especially clean `main` after landing
- should be left in `--mode auto` or forced to `--mode branch` for PR/branch work; do not force `--mode local` after committing
- writes only to stdout unless `--output`, `--json-output`, or live streamed engine stderr is set
- supports `--dry-run`, `--parallel-tests`, `--prompt`, `--prompt-file`, `--dataset`, `--no-tools`, `--no-web-search`, and commit refs
- supports `--dry-run`, `--parallel-tests`, `--parallel-tests-shell`, `--prompt`, `--prompt-file`, `--dataset`, `--no-tools`, `--no-web-search`, and commit refs
- supports `--stream-engine-output` or `AUTOREVIEW_STREAM_ENGINE_OUTPUT=1` for live engine text while preserving structured validation; Codex and Claude hide tool/file event details, emit compact activity summaries, and report usage at turn completion
- supports opt-in review panels with `--panel` / `--reviewers`, plus per-engine `--model` and `--thinking`
- allows read-only tools and web search by default where the selected CLI supports them; forbids nested review in the prompt; Codex is run through `codex exec` with read-only sandbox and structured output

View File

@@ -214,12 +214,17 @@ def run_with_stream(
def git(repo: Path, *args: str, check: bool = True) -> str:
return run(["git", *args], repo, check=check).stdout
return run([resolve_command("git", repo), *args], repo, check=check).stdout
def repo_root() -> Path:
start = Path.cwd().resolve()
unsafe_root = discover_repo_root(start) or start
git_bin = find_command("git", unsafe_root)
if not git_bin:
raise SystemExit("git executable not found. Install Git or add it to PATH.")
result = subprocess.run(
["git", "rev-parse", "--show-toplevel"],
[git_bin, "rev-parse", "--show-toplevel"],
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
@@ -229,6 +234,16 @@ def repo_root() -> Path:
return Path(result.stdout.strip()).resolve()
def discover_repo_root(start: Path) -> Path | None:
current = start
while True:
if (current / ".git").exists():
return current
if current.parent == current:
return None
current = current.parent
def current_branch(repo: Path) -> str:
return git(repo, "branch", "--show-current", check=False).strip() or "detached"
@@ -250,17 +265,70 @@ def choose_target(repo: Path, mode: str, base_ref: str | None) -> tuple[str, str
def detect_pr_base(repo: Path) -> str | None:
if not shutil_which("gh"):
gh_bin = find_command("gh", repo)
if not gh_bin:
return None
result = run(["gh", "pr", "view", "--json", "baseRefName", "--jq", ".baseRefName"], repo, check=False)
result = run([gh_bin, "pr", "view", "--json", "baseRefName", "--jq", ".baseRefName"], repo, check=False)
base = result.stdout.strip()
return f"origin/{base}" if result.returncode == 0 and base else None
def shutil_which(name: str) -> str | None:
def resolve_command(name: str, repo: Path) -> str:
resolved = find_command(name, repo)
if resolved:
return resolved
raise SystemExit(f"executable not found: {name}. Install it or pass an explicit trusted path when supported.")
def find_command(name: str, repo: Path) -> str | None:
command = Path(name)
if has_directory_component(name, command):
base = command if command.is_absolute() else repo / command
return first_executable_candidate(base)
for part in os.environ.get("PATH", "").split(os.pathsep):
candidate = Path(part) / name
if candidate.exists() and os.access(candidate, os.X_OK):
if not part or part == ".":
continue
path_part = Path(part)
if not path_part.is_absolute():
continue
try:
resolved_part = path_part.resolve()
resolved_repo = repo.resolve()
except OSError:
continue
if is_within(resolved_part, resolved_repo):
continue
found = first_executable_candidate(resolved_part / name, reject_root=resolved_repo)
if found:
return found
return None
def is_within(path: Path, root: Path) -> bool:
return path == root or path.is_relative_to(root)
def has_directory_component(name: str, command: Path) -> bool:
separators = [separator for separator in (os.sep, os.altsep) if separator]
return command.is_absolute() or bool(command.drive) or any(separator in name for separator in separators)
def first_executable_candidate(path: Path, *, reject_root: Path | None = None) -> str | None:
if os.name == "nt" and not path.suffix:
extensions = [ext for ext in os.environ.get("PATHEXT", ".COM;.EXE;.BAT;.CMD").split(";") if ext]
candidates = [path.with_suffix(ext.lower()) for ext in extensions]
candidates.extend(path.with_suffix(ext.upper()) for ext in extensions)
candidates.append(path)
else:
candidates = [path]
for candidate in candidates:
if candidate.is_file() and os.access(candidate, os.X_OK):
if reject_root is not None:
try:
if is_within(candidate.resolve(), reject_root):
continue
except OSError:
continue
return str(candidate)
return None
@@ -419,7 +487,7 @@ def run_codex(args: argparse.Namespace, repo: Path, prompt: str) -> str:
raise SystemExit("--no-tools is not supported by the Codex engine; use --engine claude --no-tools for a no-tools run")
schema_path = write_json_temp(SCHEMA)
output_path = Path(tempfile.NamedTemporaryFile("w", suffix=".json", delete=False).name)
cmd = [args.codex_bin, "--ask-for-approval", "never"]
cmd = [resolve_command(args.codex_bin, repo), "--ask-for-approval", "never"]
if args.web_search:
cmd.append("--search")
if args.model:
@@ -463,7 +531,7 @@ def run_codex(args: argparse.Namespace, repo: Path, prompt: str) -> str:
def run_claude(args: argparse.Namespace, repo: Path, prompt: str) -> str:
cmd = [
args.claude_bin,
resolve_command(args.claude_bin, repo),
"--print",
"--no-session-persistence",
"--output-format",
@@ -500,7 +568,7 @@ def run_droid(args: argparse.Namespace, repo: Path, prompt: str) -> str:
prompt_path = Path(tempfile.NamedTemporaryFile("w", suffix=".txt", delete=False).name)
prompt_path.write_text(prompt)
cmd = [
args.droid_bin,
resolve_command(args.droid_bin, repo),
"exec",
"--cwd",
str(repo),
@@ -530,7 +598,7 @@ def run_copilot(args: argparse.Namespace, repo: Path, prompt: str) -> str:
prompt_path.write_text(prompt)
os.chmod(prompt_path, 0o600)
cmd = [
args.copilot_bin,
resolve_command(args.copilot_bin, repo),
"-C",
tempdir,
"-p",
@@ -877,9 +945,23 @@ def print_report(report: dict[str, Any], *, label: str = "autoreview") -> None:
print(report["overall_explanation"])
def start_parallel_tests(command: str, repo: Path) -> tuple[subprocess.Popen, float]:
def start_parallel_tests(command: str, repo: Path, shell_kind: str) -> tuple[subprocess.Popen, float]:
print(f"tests: {command}")
return subprocess.Popen(command, cwd=repo, shell=True), time.time()
if shell_kind == "default" or shell_kind == "cmd":
return subprocess.Popen(command, cwd=repo, shell=True), time.time()
if shell_kind == "powershell":
powershell = resolve_command("powershell", repo)
return subprocess.Popen(
[powershell, "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", command],
cwd=repo,
), time.time()
if shell_kind == "pwsh":
pwsh = resolve_command("pwsh", repo)
return subprocess.Popen(
[pwsh, "-NoProfile", "-Command", command],
cwd=repo,
), time.time()
raise SystemExit(f"invalid --parallel-tests-shell/AUTOREVIEW_PARALLEL_TESTS_SHELL: {shell_kind}")
def finish_parallel_tests(proc: subprocess.Popen, started: float) -> int:
@@ -924,6 +1006,12 @@ def parse_args() -> argparse.Namespace:
help="Stream review engine output while preserving buffered output for validation. Codex output is filtered to hide tool/file chatter.",
)
parser.add_argument("--parallel-tests", help="Run a test command concurrently with review; failure fails the helper.")
parser.add_argument(
"--parallel-tests-shell",
choices=["default", "cmd", "powershell", "pwsh"],
default=os.environ.get("AUTOREVIEW_PARALLEL_TESTS_SHELL", "default"),
help="Shell for --parallel-tests. Default preserves Python shell=True platform behavior; use powershell or pwsh for PowerShell-specific commands.",
)
parser.add_argument("--require-finding", action="append", default=[], help="Require finding text to contain this substring.")
parser.add_argument("--expect-findings", action="store_true", help="Treat findings as success; for harness acceptance tests.")
parser.add_argument("--dry-run", action="store_true")
@@ -1129,7 +1217,7 @@ def main() -> int:
tests_proc: tuple[subprocess.Popen, float] | None = None
if args.parallel_tests:
tests_proc = start_parallel_tests(args.parallel_tests, repo)
tests_proc = start_parallel_tests(args.parallel_tests, repo, args.parallel_tests_shell)
try:
if len(reviewers) == 1:
report = run_reviewer(reviewers[0], repo, prompt, changed_paths, args.require_finding)

View File

@@ -1,176 +1,16 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage: test-review-harness [--fixture malicious|benign] [--engine codex|claude|droid|copilot]...
Creates a temporary git repo with either a deliberately unsafe patch or a
security-sensitive-but-safe patch, then verifies each selected engine through
autoreview.
Default engines: codex, claude.
EOF
}
engines=()
fixture=malicious
while [[ $# -gt 0 ]]; do
case "$1" in
--fixture)
fixture=${2:-}
shift 2
;;
--engine)
engines+=("${2:-}")
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
usage >&2
exit 2
;;
esac
done
case "$fixture" in
malicious|benign) ;;
*)
usage >&2
exit 2
;;
esac
if [[ ${#engines[@]} -eq 0 ]]; then
engines=(codex claude)
fi
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
repo=$(mktemp -d "${TMPDIR:-/tmp}/autoreview-fixture.XXXXXX")
trap 'rm -rf "$repo"' EXIT
harness="$script_dir/test-review-harness.py"
cd "$repo"
git init --quiet
git config user.name "Review Fixture"
git config user.email "review-fixture@example.com"
if [[ "$fixture" == malicious ]]; then
cat > app.js <<'EOF'
export function uploadPath(name) {
return `uploads/${name.replaceAll("/", "")}`;
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
EOF
else
cat > app.js <<'EOF'
import path from "node:path";
const uploadsRoot = path.resolve("uploads");
function safeChildPath(root, name) {
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
throw new Error("invalid child name");
}
const resolved = path.resolve(root, name);
if (!resolved.startsWith(root + path.sep)) throw new Error("path escaped root");
return resolved;
}
export function uploadPath(name) {
return safeChildPath(uploadsRoot, name);
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
EOF
if command -v python3 >/dev/null 2>&1; then
exec python3 "$harness" "$@"
fi
git add app.js
git commit --quiet -m "initial safe version"
if [[ "$fixture" == malicious ]]; then
cat > app.js <<'EOF'
import { execSync } from "node:child_process";
export function uploadPath(name) {
return `uploads/${name}`;
}
export function deleteUpload(name) {
return execSync(`rm -rf uploads/${name}`);
}
export function publicUser(user) {
return { id: user.id, name: user.name, password: user.password };
}
EOF
else
cat > app.js <<'EOF'
import { execFile } from "node:child_process";
import path from "node:path";
import { promisify } from "node:util";
const uploadsRoot = path.resolve("uploads");
const reposRoot = path.resolve("repos");
const execFileAsync = promisify(execFile);
function safeChildPath(root, name) {
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
throw new Error("invalid child name");
}
const resolved = path.resolve(root, name);
if (!resolved.startsWith(root + path.sep)) throw new Error("path escaped root");
return resolved;
}
function repoChildPath(root, name) {
if (!/^[A-Za-z0-9._-]+$/.test(name)) throw new Error("invalid repo name");
return safeChildPath(root, name);
}
export function uploadPath(name) {
return safeChildPath(uploadsRoot, name);
}
export async function repoStatus(repoName) {
const { stdout } = await execFileAsync("git", ["status", "--short"], {
cwd: repoChildPath(reposRoot, repoName),
encoding: "utf8",
maxBuffer: 16 * 1024 * 1024,
});
return stdout;
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
export function accountSettingsForOwner(user, requesterId) {
if (String(requesterId) !== String(user.id)) throw new Error("forbidden");
return { id: user.id, hasPassword: Boolean(user.passwordHash) };
}
EOF
if command -v python >/dev/null 2>&1; then
exec python "$harness" "$@"
fi
for engine in "${engines[@]}"; do
echo "== $engine =="
if [[ "$fixture" == malicious ]]; then
"$script_dir/autoreview" \
--mode local \
--engine "$engine" \
--prompt "This is an acceptance test fixture. The changed app.js patch contains real security bugs. Review normally and report only actionable defects from the patch." \
--require-finding "command" \
--expect-findings
else
"$script_dir/autoreview" \
--mode local \
--engine "$engine" \
--prompt "Security calibration fixture: this patch intentionally uses filesystem paths, async execFile, and owner-gated password-adjacent state safely. Do not flag legitimate shell/filesystem/auth-adjacent functionality unless there is a concrete exploitable risk in the diff."
fi
done
echo "Python 3 is required to run test-review-harness." >&2
exit 127

View File

@@ -0,0 +1,45 @@
[CmdletBinding()]
param(
[ValidateSet('malicious', 'benign')]
[string] $Fixture,
[ValidateSet('codex', 'claude', 'droid', 'copilot')]
[string[]] $Engine,
[Alias('h')]
[switch] $Help
)
$ErrorActionPreference = 'Stop'
$Harness = Join-Path $PSScriptRoot 'test-review-harness.py'
$ForwardedArgs = @()
if ($Help) {
$ForwardedArgs += '--help'
}
if ($PSBoundParameters.ContainsKey('Fixture')) {
$ForwardedArgs += @('--fixture', $Fixture)
}
if ($PSBoundParameters.ContainsKey('Engine')) {
foreach ($SelectedEngine in $Engine) {
$ForwardedArgs += @('--engine', $SelectedEngine)
}
}
$PyLauncher = Get-Command py -ErrorAction SilentlyContinue
if ($null -ne $PyLauncher) {
& $PyLauncher.Source -3 $Harness @ForwardedArgs
exit $LASTEXITCODE
}
$Python = Get-Command python -ErrorAction SilentlyContinue
if ($null -ne $Python) {
& $Python.Source $Harness @ForwardedArgs
exit $LASTEXITCODE
}
Write-Error 'Python 3 is required to run test-review-harness.'
exit 127

View File

@@ -0,0 +1,199 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import os
import shutil
import stat
import subprocess
import sys
import tempfile
from collections.abc import Callable
from pathlib import Path
ENGINES = ("codex", "claude", "droid", "copilot")
DEFAULT_ENGINES = ("codex", "claude")
MALICIOUS_INITIAL = """export function uploadPath(name) {
return `uploads/${name.replaceAll("/", "")}`;
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
"""
BENIGN_INITIAL = r"""import path from "node:path";
const uploadsRoot = path.resolve("uploads");
function safeChildPath(root, name) {
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
throw new Error("invalid child name");
}
const resolved = path.resolve(root, name);
if (!resolved.startsWith(root + path.sep)) throw new Error("path escaped root");
return resolved;
}
export function uploadPath(name) {
return safeChildPath(uploadsRoot, name);
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
"""
MALICIOUS_CHANGED = """import { execSync } from "node:child_process";
export function uploadPath(name) {
return `uploads/${name}`;
}
export function deleteUpload(name) {
return execSync(`rm -rf uploads/${name}`);
}
export function publicUser(user) {
return { id: user.id, name: user.name, password: user.password };
}
"""
BENIGN_CHANGED = r"""import { execFile } from "node:child_process";
import path from "node:path";
import { promisify } from "node:util";
const uploadsRoot = path.resolve("uploads");
const reposRoot = path.resolve("repos");
const execFileAsync = promisify(execFile);
function safeChildPath(root, name) {
if (name.includes("/") || name.includes("\\") || name.includes("\0")) {
throw new Error("invalid child name");
}
const resolved = path.resolve(root, name);
if (!resolved.startsWith(root + path.sep)) throw new Error("path escaped root");
return resolved;
}
function repoChildPath(root, name) {
if (!/^[A-Za-z0-9._-]+$/.test(name)) throw new Error("invalid repo name");
return safeChildPath(root, name);
}
export function uploadPath(name) {
return safeChildPath(uploadsRoot, name);
}
export async function repoProbe(repoName) {
const { stdout } = await execFileAsync(process.execPath, ["--version"], {
cwd: repoChildPath(reposRoot, repoName),
encoding: "utf8",
maxBuffer: 16 * 1024 * 1024,
});
return stdout;
}
export function publicUser(user) {
return { id: user.id, name: user.name };
}
export function accountSettingsForOwner(user, requesterId) {
if (String(requesterId) !== String(user.id)) throw new Error("forbidden");
return { id: user.id, hasPassword: Boolean(user.passwordHash) };
}
"""
MALICIOUS_PROMPT = "This is an acceptance test fixture. The changed app.js patch contains real security bugs. Review normally and report only actionable defects from the patch."
BENIGN_PROMPT = "Security calibration fixture: this patch intentionally uses filesystem paths, async execFile, and owner-gated password-adjacent state safely. Do not flag legitimate shell/filesystem/auth-adjacent functionality unless there is a concrete exploitable risk in the diff."
def parse_args(argv: list[str]) -> argparse.Namespace:
parser = argparse.ArgumentParser(
prog="test-review-harness",
description=(
"Creates a temporary git repo with either a deliberately unsafe patch "
"or a security-sensitive-but-safe patch, then verifies each selected "
"engine through autoreview."
),
epilog="Default engines: codex, claude.",
)
parser.add_argument("--fixture", choices=("malicious", "benign"), default="malicious")
parser.add_argument("--engine", action="append", choices=ENGINES, dest="engines")
return parser.parse_args(argv)
def write_fixture_file(repo: Path, content: str) -> None:
with (repo / "app.js").open("w", encoding="utf-8", newline="\n") as handle:
handle.write(content)
def run(command: list[str], cwd: Path) -> None:
subprocess.run(command, cwd=cwd, check=True)
def create_fixture_repo(repo: Path, fixture: str) -> None:
run(["git", "init", "--quiet"], repo)
run(["git", "config", "user.name", "Review Fixture"], repo)
run(["git", "config", "user.email", "review-fixture@example.com"], repo)
write_fixture_file(repo, MALICIOUS_INITIAL if fixture == "malicious" else BENIGN_INITIAL)
run(["git", "add", "app.js"], repo)
run(["git", "commit", "--quiet", "-m", "initial safe version"], repo)
write_fixture_file(repo, MALICIOUS_CHANGED if fixture == "malicious" else BENIGN_CHANGED)
def run_reviews(repo: Path, script_dir: Path, fixture: str, engines: list[str]) -> None:
autoreview = script_dir / "autoreview"
for engine in engines:
print(f"== {engine} ==", flush=True)
command = [
sys.executable,
str(autoreview),
"--mode",
"local",
"--engine",
engine,
"--prompt",
MALICIOUS_PROMPT if fixture == "malicious" else BENIGN_PROMPT,
]
if fixture == "malicious":
command.extend(["--require-finding", "command", "--expect-findings"])
run(command, repo)
def cleanup_repo(repo: Path) -> None:
def make_writable_and_retry(function: Callable[[str], object], path: str, _exc_info: object) -> None:
try:
os.chmod(path, stat.S_IREAD | stat.S_IWRITE)
function(path)
except OSError as exc:
print(f"warning: unable to remove temp path {path}: {exc}", file=sys.stderr)
if not repo.exists():
return
try:
shutil.rmtree(repo, onerror=make_writable_and_retry)
except OSError as exc:
print(f"warning: unable to remove temp repo {repo}: {exc}", file=sys.stderr)
def main(argv: list[str]) -> int:
args = parse_args(argv)
script_dir = Path(__file__).resolve().parent
engines = args.engines or list(DEFAULT_ENGINES)
repo = Path(tempfile.mkdtemp(prefix="autoreview-fixture."))
try:
create_fixture_repo(repo, args.fixture)
run_reviews(repo, script_dir, args.fixture, engines)
except subprocess.CalledProcessError as exc:
return int(exc.returncode or 1)
finally:
cleanup_repo(repo)
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))

View File

@@ -1,6 +1,6 @@
---
name: discrawl
description: "Discord archive: search, sync freshness, DMs, channel slices, SQL counts, and Discrawl repo work."
description: "Discord archive: search, sync freshness, DMs, summaries, TUI, repo/release work."
metadata:
openclaw:
homepage: https://github.com/openclaw/discrawl
@@ -16,29 +16,154 @@ metadata:
# Discrawl
Use local Discord archive data before live Discord APIs. Check freshness for recent/current questions:
Use local Discord archive data first for Discord questions. Hit Discord APIs
only when the archive is stale, missing the requested scope, or the user asks
for current external context.
## Sources
- DB: platform-native XDG data dir, usually
`${XDG_DATA_HOME:-~/.local/share}/discrawl/discrawl.db` on Linux or
`~/Library/Application Support/discrawl/discrawl.db` on macOS
- Config: platform-native XDG config dir, with legacy fallback to
`~/.discrawl/config.toml`
- Cache: platform-native XDG cache dir
- Logs: platform-native XDG state dir
- Git share repo: platform-native XDG data dir
- Repo: `openclaw/discrawl`; use `~/GIT/_Perso/discrawl` only after verifying
its remote targets `openclaw/discrawl`, otherwise use a fresh checkout
- Preferred CLI: `discrawl`; fallback to `go run ./cmd/discrawl` from the repo
if the installed binary is stale
## Freshness
For recent/current questions, check freshness before analysis:
```bash
discrawl status --json
```
For precise freshness from the default database:
```bash
# Discrawl uses macOS ~/Library defaults unless XDG_DATA_HOME is explicitly set.
case "$(uname -s)" in
Darwin)
db="$HOME/Library/Application Support/discrawl/discrawl.db"
;;
*)
db="${XDG_DATA_HOME:-$HOME/.local/share}/discrawl/discrawl.db"
;;
esac
sqlite3 "$db" \
"select coalesce(max(updated_at),'') from sync_state where scope like 'channel:%';"
```
Routine diagnostics:
```bash
discrawl doctor
```
Refresh only when stale or asked:
Desktop-local refresh:
```bash
discrawl sync --source wiretap
```
Bot API latest refresh, when credentials are available:
```bash
discrawl sync
```
Query with bounded slices:
Use `--full` only for deliberate historical backfills:
```bash
discrawl sync --full
```
If SQLite reports busy/locked, check for stray `discrawl` processes before retrying.
## Query Workflow
1. Resolve scope: guild, channel, DM, author, keyword, date range.
2. Check freshness for recent/current requests.
3. Prefer CLI search/messages for slices; use read-only SQL for exact counts.
4. Report absolute date spans, counts, channel/DM names, and known gaps.
Use root or subcommand help for syntax: `discrawl --help`,
`discrawl help search`, `discrawl search --help`. Use
`DISCRAWL_NO_AUTO_UPDATE=1` for read smokes when you do not want git-share
updates.
Common commands:
```bash
DISCRAWL_NO_AUTO_UPDATE=1 discrawl search --limit 20 "query"
discrawl messages --channel '#maintainers' --days 7 --all
discrawl dms --last 20
discrawl tui --dm
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select count(*) from messages;"
```
Report absolute date spans, channel/DM names, counts, and known gaps. Use read-only SQL for exact counts/rankings. Never use `--unsafe --confirm` unless the user explicitly requests a reviewed DB mutation.
## SQL
Boundaries: bot sync needs configured Discord bot credentials. Wiretap reads local Discord Desktop artifacts only; do not extract user tokens, call Discord as the user, or write to Discord storage. Git-share snapshots must not include secrets or `@me` DM rows.
Use `discrawl sql` for exact counts, joins, and ranking queries when normal
CLI reads are too coarse. The command is read-only by default, accepts SQL as
args or stdin, and supports `--json` for agent parsing.
Useful examples:
```bash
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select count(*) as messages from messages;"
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select coalesce(nullif(c.name, ''), m.channel_id) as channel, count(*) as messages from messages m left join channels c on c.id = m.channel_id group by m.channel_id order by messages desc limit 20;"
DISCRAWL_NO_AUTO_UPDATE=1 discrawl --json sql "select coalesce(nullif(mm.display_name, ''), nullif(mm.global_name, ''), nullif(mm.username, ''), m.author_id) as author, count(*) as messages from messages m left join members mm on mm.guild_id = m.guild_id and mm.user_id = m.author_id group by m.guild_id, m.author_id order by messages desc limit 20;"
```
Never use `--unsafe --confirm` unless the user explicitly asks for a database
mutation and the write has been reviewed.
When the installed CLI lacks a new feature, build or run from a verified
`openclaw/discrawl` checkout before concluding the feature is missing.
## Discord Boundaries
Bot API sync requires configured Discord bot credentials; do not invent token
availability. Desktop wiretap mode reads local Discord Desktop artifacts and
must not extract credentials, use user tokens, call Discord as the user, or
write to Discord application storage. Wiretap/Desktop cache DMs are local-only
and must not be described as part of the published Git snapshot. Git-share
snapshots must not include secrets or `@me` DM rows.
## Verification
For repo edits, prefer existing Go gates:
```bash
GOWORK=off go test ./...
```
Then run targeted CLI smoke for the touched surface, for example:
```bash
discrawl doctor
discrawl status --json
DISCRAWL_NO_AUTO_UPDATE=1 discrawl search --limit 5 "test"
```
## ClawSweeper Sandbox
Use the sandbox reader only:
```bash
discrawl-sandbox search --limit 20 "query"
discrawl-sandbox messages --channel clawtributors --days 7 --all
discrawl-sandbox status --json
```
This reader imports `https://github.com/openclaw/discord-store.git` into
`/root/clawsweeper-sandbox-workspace/.discrawl/discrawl.db` with
`discord.token_source = "none"`. The published Git snapshot is public-channel
filtered; do not use `/root/.discrawl/config.toml` or the rich writer DB from
sandboxed public Discord sessions.

View File

@@ -6,14 +6,16 @@ description: Regenerate OpenClaw release changelog sections from git history bef
# OpenClaw Changelog Update
Use this for release changelog rewrites and GitHub release-note source text.
Use it with `release-openclaw-maintainer`; this skill owns changelog content,
ordering, and audit discipline.
This is mandatory before every beta, beta rerun, stable release, or stable
rerun. Use it with `release-openclaw-maintainer`; this skill owns changelog
content, ordering, grouping, and attribution discipline.
## Goal
Rewrite the target `CHANGELOG.md` version section from history, not from stale
draft notes. Produce user-facing release notes sorted by user interest while
preserving issue/PR refs and thanks.
draft notes. Produce grouped user-facing release notes sorted by user interest
while preserving every relevant issue/PR ref and every human `Thanks @...`
attribution.
## Inputs
@@ -44,15 +46,35 @@ preserving issue/PR refs and thanks.
- `### Highlights`: 5-8 bullets, broad user wins first
- `### Changes`: new capabilities and behavior changes
- `### Fixes`: user-facing fixes first, grouped by impact and surface
- group related changes/fixes by surface and user impact; avoid one bullet
per tiny commit when several commits tell one user-facing story
6. Preserve attribution:
- keep `#issue`, `(#PR)`, `Fixes #...`, and `Thanks @...`
- every human-authored merged PR represented by a user-facing entry needs
its PR ref and `Thanks @author`, even when the PR had no linked issue
- every human issue reporter for a `Fixes #...` or referenced bug issue
represented by a user-facing entry needs `Thanks @reporter` unless the
same handle is already thanked in that bullet
- every human `Co-authored-by` contributor on represented user-facing work
needs `Thanks @handle` when a GitHub handle is known
- when grouping multiple PRs/issues in one bullet, include every relevant
PR/issue ref and every human contributor handle in that same bullet
- multiple `Thanks @...` handles in one bullet are expected; do not drop or
collapse contributor credit just because the note is grouped
- if one grouped bullet covers both direct commits and PRs, keep all PR refs
and thanks, plus any issue refs from the direct commits
- before finalizing, audit the final release-note body:
- extract all `#NNN` refs from the notes
- resolve which refs are PRs and collect human PR authors
- resolve issue refs used as bug/report refs and collect human reporters
- scan represented commits for `Co-authored-by`
- compare those handles to the final `Thanks @...` set
- fix every missing human credit or explicitly record why it is omitted
- do not add GHSA references, advisory IDs, or security advisory slugs to
changelog entries or GitHub release-note text unless explicitly requested
- never thank bots, `@openclaw`, `@clawsweeper`, or `@steipete`
- if grouping multiple entries, carry all relevant refs and thanks into the
grouped bullet
- do not use GitHub's release contributor count as the source of truth; the
changelog must carry the complete human credit set itself
7. Sorting preference:
- security/data-loss and content-boundary fixes
- transcript/replay/reply delivery correctness

View File

@@ -75,7 +75,9 @@ OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test <path-or-filter>
```
Use targeted file paths whenever possible. Avoid raw `vitest`; use the repo
`pnpm test` wrapper so project routing, workers, and setup stay correct.
`pnpm test` wrapper so project routing, workers, and setup stay correct. If raw
Vitest is unavoidable, use `vitest run ...`; bare `vitest ...` starts local watch
mode and will not exit on its own.
When the checkout is a Codex worktree, prefer the direct node harness instead:
```bash

View File

@@ -21,6 +21,30 @@ function jsonGh(args) {
return JSON.parse(gh(args));
}
function githubRestJson(pathSuffix) {
const result = execFileSync(
"bash",
[
"-lc",
[
"set -euo pipefail",
'token="$(gh auth token)"',
'curl -fsS -H "Authorization: Bearer ${token}" -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" "${OPENCLAW_GITHUB_REST_URL}"',
].join("\n"),
],
{
encoding: "utf8",
env: {
...process.env,
OPENCLAW_GITHUB_REST_URL: `https://api.github.com/repos/${repo}/${pathSuffix}`,
},
maxBuffer: 16 * 1024 * 1024,
stdio: ["ignore", "pipe", "pipe"],
},
);
return JSON.parse(result);
}
function rate() {
try {
return jsonGh(["api", "rate_limit"]).resources.core;
@@ -59,12 +83,30 @@ for (const job of parent.jobs ?? []) {
}
const since = parent.createdAt;
const runList = gh([
"api",
`repos/${repo}/actions/runs?per_page=100`,
"--jq",
`.workflow_runs[] | select(.created_at >= "${since}") | select(.name=="CI" or .name=="OpenClaw Release Checks" or .name=="Plugin Prerelease" or .name=="NPM Telegram Beta E2E" or .name=="Full Release Validation") | [.id,.name,.status,.conclusion,.head_sha,.html_url] | @tsv`,
]).trim();
const runsQuery = new URLSearchParams({
per_page: "100",
created: `>=${since}`,
exclude_pull_requests: "true",
});
const childWorkflowNames = new Set([
"CI",
"OpenClaw Release Checks",
"Plugin Prerelease",
"NPM Telegram Beta E2E",
"Full Release Validation",
]);
const runs = githubRestJson(`actions/runs?${runsQuery.toString()}`).workflow_runs ?? [];
const runList = runs
.filter(
(run) =>
run.created_at >= since &&
run.head_sha === parent.headSha &&
childWorkflowNames.has(run.name),
)
.map((run) =>
[run.id, run.name, run.status, run.conclusion ?? "", run.head_sha, run.html_url].join("\t"),
)
.join("\n");
if (!runList) {
console.log("children: none found yet");

View File

@@ -69,9 +69,13 @@ Use this skill for release and publish-time workflow. Load `$release-private` if
or clawgrit reports. Report regressions explicitly. A major regression is a
release blocker unless the operator waives it or the data clearly proves
infrastructure noise.
- Generate the changelog before version/tag preparation so the top changelog
section is deduped and ordered by user impact. Use
`$openclaw-changelog-update` for the rewrite.
- Generate the changelog before every beta, beta rerun, stable release, or
stable rerun, before version/tag preparation. Use
`$openclaw-changelog-update` for the rewrite. Do not continue release prep if
the target `CHANGELOG.md` section does not have `### Highlights`,
`### Changes`, and `### Fixes`, grouped by user-facing surface while
preserving every relevant PR/issue ref and every human `Thanks @...`
attribution in the grouped bullet.
- Do not create beta-specific `CHANGELOG.md` headings. Beta releases use the
stable base version section, for example `v2026.4.20-beta.1` uses
`## 2026.4.20` release notes.
@@ -144,6 +148,9 @@ Use this skill for release and publish-time workflow. Load `$release-private` if
section from history, not existing notes. Use the last reachable stable or
beta release tag as the base, then inspect every commit through the target
release SHA.
- The changelog rewrite is not optional for beta reruns: any `beta.N` after a
rebase or backport must refresh the same stable-base `## YYYY.M.D` section
before the new version/tag commit.
- Include both merged PR commits and direct commits on `main`. Direct commits
matter: infer notes from their subject, body, touched files, linked issues,
tests, and nearby code when no PR body exists.
@@ -157,6 +164,11 @@ Use this skill for release and publish-time workflow. Load `$release-private` if
- Add missed user-facing changes, remove internal-only noise, dedupe overlapping
PR/direct-commit entries, and sort each section from most to least interesting
for users.
- Group related highlights, changes, and fixes by user-facing surface and
impact, but never lose traceability: each grouped bullet keeps every relevant
`#issue`, `(#PR)`, `Fixes #...`, and every human `Thanks @...` handle.
Multiple thanks in one bullet are expected when multiple contributor PRs are
grouped.
- Changelog entries should be user-facing, not internal release-process notes.
- GitHub release and prerelease bodies must use the full matching
`CHANGELOG.md` version section, not highlights or an excerpt. When creating

View File

@@ -1,21 +1,15 @@
profile: openclaw-check
provider: aws
# Default OpenClaw runner spend to the Azure-backed Crabbox account.
# Use `--provider aws` only for AWS-specific runner proof.
provider: azure
class: standard
capacity:
market: spot
strategy: most-available
fallback: on-demand-after-120s
# Fail closed instead of silently falling back to on-demand while the
# Azure-backed billing account is the default runner path.
fallback: spot-only
hints: true
availabilityZones:
- eu-west-1a
- eu-west-1b
- eu-west-1c
regions:
- eu-west-1
- eu-west-2
- eu-central-1
- us-east-1
- us-west-2
actions:
workflow: .github/workflows/crabbox-hydrate.yml
# Default AWS hydration uses local Actions replay. Use
@@ -35,6 +29,8 @@ blacksmith:
job: check
ref: main
aws:
# AWS-specific overrides still pin direct `--provider aws` runs without
# leaking AWS region names into the Azure default capacity fallback list.
region: eu-west-1
rootGB: 400
sync:

10
.github/labeler.yml vendored
View File

@@ -355,6 +355,11 @@
- any-glob-to-any-file:
- "extensions/deepinfra/**"
- "docs/providers/deepinfra.md"
"extensions: gmi":
- changed-files:
- any-glob-to-any-file:
- "extensions/gmi/**"
- "docs/providers/gmi.md"
"extensions: tencent":
- changed-files:
- any-glob-to-any-file:
@@ -436,6 +441,11 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/nvidia/**"
"extensions: novita":
- changed-files:
- any-glob-to-any-file:
- "extensions/novita/**"
- "docs/providers/novita.md"
"extensions: phone-control":
- changed-files:
- any-glob-to-any-file:

View File

@@ -27,7 +27,7 @@ jobs:
timeout-minutes: 35
steps:
- name: Begin Testbox
uses: useblacksmith/begin-testbox@d0e04585c26905fdd92c94a09c159544c7ee1b67
uses: useblacksmith/begin-testbox@233448af4bfdc6fca509a7f0974411ac6d8a8043
with:
testbox_id: ${{ inputs.testbox_id }}
@@ -231,7 +231,7 @@ jobs:
run: bash scripts/ci-hydrate-testbox-env.sh
- name: Run Testbox
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
uses: useblacksmith/run-testbox@3f60ff9ceb2c10c3feefa87dc0c6490cffae059d
if: success()
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

View File

@@ -26,7 +26,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Begin Testbox
uses: useblacksmith/begin-testbox@d0e04585c26905fdd92c94a09c159544c7ee1b67
uses: useblacksmith/begin-testbox@233448af4bfdc6fca509a7f0974411ac6d8a8043
with:
testbox_id: ${{ inputs.testbox_id }}
- name: Checkout
@@ -133,7 +133,7 @@ jobs:
run: bash scripts/ci-hydrate-testbox-env.sh
- name: Run Testbox
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
uses: useblacksmith/run-testbox@3f60ff9ceb2c10c3feefa87dc0c6490cffae059d
if: success()
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

View File

@@ -28,7 +28,7 @@ permissions:
concurrency:
group: ${{ github.event_name == 'workflow_dispatch' && format('{0}-manual-v1-{1}', github.workflow, github.run_id) || (github.event_name == 'pull_request' && format('{0}-v7-{1}', github.workflow, github.event.pull_request.number) || (github.repository == 'openclaw/openclaw' && format('{0}-v7-{1}', github.workflow, github.ref) || format('{0}-v7-{1}-{2}', github.workflow, github.ref, github.sha))) }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
cancel-in-progress: ${{ github.event_name == 'pull_request' || (github.event_name == 'push' && github.repository == 'openclaw/openclaw' && github.ref == 'refs/heads/main') }}
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
@@ -466,8 +466,8 @@ jobs:
- name: Audit production dependencies
run: node scripts/pre-commit/pnpm-audit-prod.mjs --audit-level=high
# Warm the lockfile- and pnpm-pinned store once before Linux Node shards fan out.
# On a cold key this job owns the save, so later shards restore the exact key.
# Warm the lockfile- and pnpm-pinned store without blocking Linux Node shards.
# On a cold key this job owns the save for later workflow runs.
pnpm-store-warmup:
permissions:
contents: read
@@ -532,9 +532,9 @@ jobs:
build-artifacts:
permissions:
contents: read
needs: [preflight, pnpm-store-warmup]
needs: [preflight]
if: needs.preflight.outputs.run_build_artifacts == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-16vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-32vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 20
outputs:
channels-result: ${{ steps.built_artifact_checks.outputs['channels-result'] }}
@@ -597,6 +597,14 @@ jobs:
with:
install-bun: "false"
- name: Restore build-all step cache
uses: actions/cache@v5
with:
path: .artifacts/build-all-cache
key: ${{ runner.os }}-build-all-v3-${{ hashFiles('package.json', 'pnpm-lock.yaml', 'npm-shrinkwrap.json', 'packages/plugin-sdk/package.json', 'packages/llm-core/package.json', 'packages/model-catalog-core/package.json', 'packages/memory-host-sdk/package.json', 'scripts/build-all.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entries.mjs', 'tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'src/plugin-sdk/**', 'packages/llm-core/src/**', 'packages/model-catalog-core/src/**', 'packages/memory-host-sdk/src/**', 'src/types/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'scripts/copy-export-html-templates.ts', 'scripts/lib/copy-assets.ts', 'src/auto-reply/reply/export-html/**') }}
restore-keys: |
${{ runner.os }}-build-all-v3-
- name: Build dist
env:
NODE_OPTIONS: --max-old-space-size=8192
@@ -694,20 +702,6 @@ jobs:
pids+=("$!")
}
if [ "$RUN_GATEWAY_WATCH" = "true" ]; then
gateway_watch_log="${RUNNER_TEMP}/gateway-watch.log"
echo "starting gateway-watch: node scripts/check-gateway-watch-regression.mjs --skip-build --ready-timeout-ms 5000"
if node scripts/check-gateway-watch-regression.mjs --skip-build --ready-timeout-ms 5000 >"$gateway_watch_log" 2>&1; then
result="success"
else
result="failure"
fi
echo "::group::gateway-watch log"
cat "$gateway_watch_log"
echo "::endgroup::"
results["gateway-watch"]="$result"
fi
if [ "$RUN_CHANNELS" = "true" ]; then
start_check "channels" env \
NODE_OPTIONS=--max-old-space-size=8192 \
@@ -722,6 +716,11 @@ jobs:
node scripts/run-vitest.mjs run --config test/vitest/vitest.full-core-support-boundary.config.ts
fi
if [ "$RUN_GATEWAY_WATCH" = "true" ]; then
start_check "gateway-watch" \
node scripts/check-gateway-watch-regression.mjs --skip-build --ready-timeout-ms 5000
fi
for index in "${!pids[@]}"; do
name="${names[$index]}"
log="${logs[$index]}"
@@ -764,7 +763,7 @@ jobs:
permissions:
contents: read
name: ${{ matrix.check_name }}
needs: [preflight, pnpm-store-warmup]
needs: [preflight]
if: needs.preflight.outputs.run_checks_fast_core == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 60
@@ -835,10 +834,10 @@ jobs:
;;
contracts-plugins-ci-routing)
pnpm test:contracts:plugins
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/test-projects.test.ts
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/changed-lanes.test.ts test/scripts/run-vitest.test.ts test/scripts/test-projects.test.ts
;;
ci-routing)
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/test-projects.test.ts
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/changed-lanes.test.ts test/scripts/run-vitest.test.ts test/scripts/test-projects.test.ts
;;
bun-launcher)
OPENCLAW_TEST_BUN_LAUNCHER=1 pnpm test test/openclaw-launcher.e2e.test.ts
@@ -853,7 +852,7 @@ jobs:
permissions:
contents: read
name: ${{ matrix.checkName }}
needs: [preflight, pnpm-store-warmup]
needs: [preflight]
if: needs.preflight.outputs.run_plugin_contracts_shards == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 60
@@ -933,7 +932,7 @@ jobs:
permissions:
contents: read
name: ${{ matrix.checkName }}
needs: [preflight, pnpm-store-warmup]
needs: [preflight]
if: needs.preflight.outputs.run_checks_fast == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 60
@@ -1085,7 +1084,7 @@ jobs:
permissions:
contents: read
name: ${{ matrix.check_name }}
needs: [preflight, pnpm-store-warmup]
needs: [preflight]
if: needs.preflight.outputs.run_checks_node_core_nondist == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'blacksmith-8vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
timeout-minutes: 60
@@ -1152,6 +1151,7 @@ jobs:
OPENCLAW_NODE_TEST_CONFIGS_JSON: ${{ toJson(matrix.configs) }}
OPENCLAW_NODE_TEST_INCLUDE_PATTERNS_JSON: ${{ toJson(matrix.includePatterns) }}
OPENCLAW_VITEST_SHARD_NAME: ${{ matrix.shard_name }}
OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS: "900000"
OPENCLAW_TEST_PROJECTS_PARALLEL: "2"
shell: bash
run: |
@@ -1191,8 +1191,8 @@ jobs:
permissions:
contents: read
name: ${{ matrix.check_name }}
needs: [preflight, pnpm-store-warmup]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check == 'true' && needs.pnpm-store-warmup.result == 'success' }}
needs: [preflight]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check == 'true' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }}
timeout-minutes: 20
strategy:
@@ -1322,8 +1322,8 @@ jobs:
permissions:
contents: read
name: ${{ matrix.check_name }}
needs: [preflight, pnpm-store-warmup]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check_additional == 'true' && needs.pnpm-store-warmup.result == 'success' }}
needs: [preflight]
if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check_additional == 'true' }}
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 20
strategy:
@@ -1404,7 +1404,7 @@ jobs:
packages/plugin-sdk/dist
extensions/*/dist/.boundary-tsc.tsbuildinfo
extensions/*/dist/.boundary-tsc.stamp
key: ${{ runner.os }}-extension-package-boundary-v1-${{ hashFiles('tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'packages/plugin-sdk/tsconfig.json', 'scripts/check-extension-package-tsc-boundary.mjs', 'scripts/prepare-extension-package-boundary-artifacts.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entrypoints.json', 'scripts/lib/plugin-sdk-entries.mjs', 'src/plugin-sdk/**', 'src/auto-reply/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'src/types/**', 'extensions/**', 'extensions/tsconfig.package-boundary*.json', 'package.json', 'pnpm-lock.yaml') }}
key: ${{ runner.os }}-extension-package-boundary-v1-${{ hashFiles('tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'packages/plugin-sdk/tsconfig.json', 'packages/llm-core/package.json', 'packages/model-catalog-core/package.json', 'scripts/check-extension-package-tsc-boundary.mjs', 'scripts/prepare-extension-package-boundary-artifacts.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entrypoints.json', 'scripts/lib/plugin-sdk-entries.mjs', 'src/plugin-sdk/**', 'src/auto-reply/**', 'packages/llm-core/src/**', 'packages/model-catalog-core/src/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'src/types/**', 'extensions/**', 'extensions/tsconfig.package-boundary*.json', 'package.json', 'pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-extension-package-boundary-v1-
@@ -1421,10 +1421,22 @@ jobs:
find src \
-type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.mts' -o -name '*.cts' -o -name '*.js' -o -name '*.mjs' -o -name '*.json' \) \
-exec touch -t 200001010000 {} +
touch -t 200001010000 \
if [ -d packages/llm-core/src ]; then
find packages/llm-core/src \
-type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.mts' -o -name '*.cts' -o -name '*.js' -o -name '*.mjs' -o -name '*.json' \) \
-exec touch -t 200001010000 {} +
fi
if [ -d packages/model-catalog-core/src ]; then
find packages/model-catalog-core/src \
-type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.mts' -o -name '*.cts' -o -name '*.js' -o -name '*.mjs' -o -name '*.json' \) \
-exec touch -t 200001010000 {} +
fi
cache_inputs=(
tsconfig.json \
tsconfig.plugin-sdk.dts.json \
packages/plugin-sdk/tsconfig.json \
packages/llm-core/package.json \
packages/model-catalog-core/package.json \
scripts/check-extension-package-tsc-boundary.mjs \
scripts/prepare-extension-package-boundary-artifacts.mjs \
scripts/write-plugin-sdk-entry-dts.ts \
@@ -1432,6 +1444,12 @@ jobs:
scripts/lib/plugin-sdk-entries.mjs \
package.json \
pnpm-lock.yaml
)
for cache_input in "${cache_inputs[@]}"; do
if [ -e "$cache_input" ]; then
touch -t 200001010000 "$cache_input"
fi
done
- name: Run additional check shard
env:
@@ -1489,7 +1507,7 @@ jobs:
check-docs:
permissions:
contents: read
needs: [preflight, pnpm-store-warmup]
needs: [preflight]
if: needs.preflight.outputs.run_check_docs == 'true'
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04') }}
timeout-minutes: 20
@@ -1673,6 +1691,7 @@ jobs:
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
fetch_timeout_seconds=90
fetch_checkout_ref() {
git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
@@ -1681,7 +1700,7 @@ jobs:
local fetch_pid="$!"
local elapsed=0
while kill -0 "$fetch_pid" 2>/dev/null; do
if [ "$elapsed" -ge 30 ]; then
if [ "$elapsed" -ge "$fetch_timeout_seconds" ]; then
kill -TERM "$fetch_pid" 2>/dev/null || true
sleep 10
kill -KILL "$fetch_pid" 2>/dev/null || true
@@ -1793,6 +1812,7 @@ jobs:
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
fetch_timeout_seconds=90
fetch_checkout_ref() {
git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
@@ -1801,7 +1821,7 @@ jobs:
local fetch_pid="$!"
local elapsed=0
while kill -0 "$fetch_pid" 2>/dev/null; do
if [ "$elapsed" -ge 30 ]; then
if [ "$elapsed" -ge "$fetch_timeout_seconds" ]; then
kill -TERM "$fetch_pid" 2>/dev/null || true
sleep 10
kill -KILL "$fetch_pid" 2>/dev/null || true
@@ -1859,6 +1879,7 @@ jobs:
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
fetch_timeout_seconds=90
fetch_checkout_ref() {
git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
@@ -1867,7 +1888,7 @@ jobs:
local fetch_pid="$!"
local elapsed=0
while kill -0 "$fetch_pid" 2>/dev/null; do
if [ "$elapsed" -ge 30 ]; then
if [ "$elapsed" -ge "$fetch_timeout_seconds" ]; then
kill -TERM "$fetch_pid" 2>/dev/null || true
sleep 10
kill -KILL "$fetch_pid" 2>/dev/null || true
@@ -2114,7 +2135,7 @@ jobs:
- macos-node
- macos-swift
- android
if: ${{ !cancelled() && always() && (github.event_name != 'pull_request' || !github.event.pull_request.draft) }}
if: ${{ !cancelled() && always() && github.event_name != 'push' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) }}
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:

View File

@@ -302,6 +302,8 @@ jobs:
esac
case "${file}" in
src/**/*.test.ts|src/**/*.test.tsx|extensions/**/*.test.ts|extensions/**/*.test.tsx)
;;
src/*.ts|src/**/*.ts|extensions/*.ts|extensions/**/*.ts|packages/net-policy/src/*|packages/net-policy/src/**/*)
network_runtime=true
;;

View File

@@ -14,10 +14,85 @@ concurrency:
cancel-in-progress: true
jobs:
dependency-guard:
dependency-guard-detect:
if: ${{ !github.event.pull_request.draft }}
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
autoscrub: ${{ steps.guard.outputs.autoscrub }}
autoscrub-owner: ${{ steps.guard.outputs.autoscrub-owner }}
autoscrub-repository: ${{ steps.guard.outputs.autoscrub-repository }}
steps:
- name: Check out trusted base workflow scripts
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ github.event.pull_request.base.sha }}
persist-credentials: false
- name: Detect dependency changes
id: guard
env:
GITHUB_TOKEN: ${{ github.token }}
OPENCLAW_DEPENDENCY_GUARD_MODE: detect
OPENCLAW_SECURITY_APPROVERS: vincentkoc,steipete,joshavant
OPENCLAW_SECURITY_TEAM_SLUG: openclaw-secops
run: node scripts/github/dependency-guard.mjs
dependency-guard-autoscrub:
if: ${{ !github.event.pull_request.draft && needs.dependency-guard-detect.outputs.autoscrub == 'true' }}
needs: dependency-guard-detect
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
contents: read
issues: write
pull-requests: read
steps:
- name: Check out trusted base workflow scripts
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ github.event.pull_request.base.sha }}
persist-credentials: false
- name: Create autoscrub app token
id: app-token
continue-on-error: true
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: "2729701"
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
owner: ${{ needs.dependency-guard-detect.outputs.autoscrub-owner }}
repositories: ${{ needs.dependency-guard-detect.outputs.autoscrub-repository }}
permission-contents: write
- name: Create fallback autoscrub app token
id: app-token-fallback
continue-on-error: true
if: steps.app-token.outcome == 'failure'
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: "2971289"
private-key: ${{ secrets.GH_APP_PRIVATE_KEY_FALLBACK }}
owner: ${{ needs.dependency-guard-detect.outputs.autoscrub-owner }}
repositories: ${{ needs.dependency-guard-detect.outputs.autoscrub-repository }}
permission-contents: write
- name: Remove package lockfile changes
env:
GITHUB_TOKEN: ${{ github.token }}
OPENCLAW_DEPENDENCY_GUARD_AUTOSCRUB_TOKEN: ${{ steps.app-token.outputs.token || steps.app-token-fallback.outputs.token }}
OPENCLAW_DEPENDENCY_GUARD_MODE: autoscrub
OPENCLAW_SECURITY_APPROVERS: vincentkoc,steipete,joshavant
OPENCLAW_SECURITY_TEAM_SLUG: openclaw-secops
run: node scripts/github/dependency-guard.mjs
dependency-guard:
if: ${{ !github.event.pull_request.draft && always() }}
needs:
- dependency-guard-detect
- dependency-guard-autoscrub
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Check out trusted base workflow scripts
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -25,9 +100,10 @@ jobs:
ref: ${{ github.event.pull_request.base.sha }}
persist-credentials: false
- name: Label, comment, and guard dependency changes
- name: Enforce dependency guard
env:
GITHUB_TOKEN: ${{ github.token }}
OPENCLAW_DEPENDENCY_GUARD_MODE: enforce
OPENCLAW_SECURITY_APPROVERS: vincentkoc,steipete,joshavant
OPENCLAW_SECURITY_TEAM_SLUG: openclaw-secops
run: node scripts/github/dependency-guard.mjs

View File

@@ -372,6 +372,11 @@ jobs:
actions: read
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Require trusted workflow ref for publish
env:
RELEASE_TAG: ${{ inputs.tag }}
@@ -429,12 +434,13 @@ jobs:
echo "Direct OpenClaw npm publish; relying on this workflow's npm-release environment approval."
exit 0
fi
direct_recovery=false
if [[ "${GITHUB_ACTOR}" != "github-actions[bot]" ]]; then
echo "OpenClaw npm publish must be dispatched by the OpenClaw Release Publish workflow, not directly by ${GITHUB_ACTOR}." >&2
exit 1
direct_recovery=true
echo "Direct OpenClaw npm recovery with release_publish_run_id; relying on this workflow's npm-release environment approval."
fi
RUN_JSON="$(gh run view "$RELEASE_PUBLISH_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw Release Publish"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } if (run.status !== "in_progress") { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must still be in_progress, got ${run.status ?? "<missing>"}.`); process.exit(1); } if (run.conclusion) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} already concluded ${run.conclusion}.`); process.exit(1); } console.log(`Using release publish approval run ${process.env.RELEASE_PUBLISH_RUN_ID}: ${run.url}`);'
printf '%s' "$RUN_JSON" | DIRECT_RELEASE_RECOVERY="${direct_recovery}" node scripts/validate-release-publish-approval.mjs
publish_openclaw_npm:
# KEEP THE REAL RELEASE/PUBLISH PATH ON A GITHUB-HOSTED RUNNER.

View File

@@ -207,6 +207,11 @@ jobs:
actions: read
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Validate release publish approval run
env:
GH_TOKEN: ${{ github.token }}
@@ -222,12 +227,13 @@ jobs:
echo "Direct Plugin ClawHub Release dispatch; relying on this workflow's clawhub-plugin-release environment approval."
exit 0
fi
direct_recovery=false
if [[ "${GITHUB_ACTOR}" != "github-actions[bot]" ]]; then
echo "Plugin ClawHub publish must be dispatched by the OpenClaw Release Publish workflow, not directly by ${GITHUB_ACTOR}." >&2
exit 1
direct_recovery=true
echo "Direct Plugin ClawHub Release recovery with release_publish_run_id; relying on this workflow's clawhub-plugin-release environment approval."
fi
RUN_JSON="$(gh run view "$RELEASE_PUBLISH_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw Release Publish"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } if (run.status !== "in_progress") { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must still be in_progress, got ${run.status ?? "<missing>"}.`); process.exit(1); } if (run.conclusion) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} already concluded ${run.conclusion}.`); process.exit(1); } console.log(`Using release publish approval run ${process.env.RELEASE_PUBLISH_RUN_ID}: ${run.url}`);'
printf '%s' "$RUN_JSON" | DIRECT_RELEASE_RECOVERY="${direct_recovery}" node scripts/validate-release-publish-approval.mjs
preview_plugin_pack:
needs: preview_plugins_clawhub

View File

@@ -184,6 +184,11 @@ jobs:
actions: read
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Validate release publish approval run
env:
GH_TOKEN: ${{ github.token }}
@@ -199,12 +204,13 @@ jobs:
echo "Direct Plugin NPM Release dispatch; relying on this workflow's npm-release environment approval."
exit 0
fi
direct_recovery=false
if [[ "${GITHUB_ACTOR}" != "github-actions[bot]" ]]; then
echo "Plugin npm publish must be dispatched by the OpenClaw Release Publish workflow, not directly by ${GITHUB_ACTOR}." >&2
exit 1
direct_recovery=true
echo "Direct Plugin NPM Release recovery with release_publish_run_id; relying on this workflow's npm-release environment approval."
fi
RUN_JSON="$(gh run view "$RELEASE_PUBLISH_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw Release Publish"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } if (run.status !== "in_progress") { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must still be in_progress, got ${run.status ?? "<missing>"}.`); process.exit(1); } if (run.conclusion) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} already concluded ${run.conclusion}.`); process.exit(1); } console.log(`Using release publish approval run ${process.env.RELEASE_PUBLISH_RUN_ID}: ${run.url}`);'
printf '%s' "$RUN_JSON" | DIRECT_RELEASE_RECOVERY="${direct_recovery}" node scripts/validate-release-publish-approval.mjs
preview_plugin_pack:
needs: preview_plugins_npm

View File

@@ -197,4 +197,4 @@ jobs:
- name: Testbox action marker
if: ${{ false }}
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
uses: useblacksmith/run-testbox@3f60ff9ceb2c10c3feefa87dc0c6490cffae059d

View File

@@ -72,12 +72,13 @@ Skills own workflows; root owns hard policy and routing.
- Plugin SDK exception: shipped external API gets new API first plus named compat/deprecation, small tests/docs if useful, removal plan.
- Migrate internal/bundled callers to modern API in the same change. Do not let internal compat become permanent architecture.
- Channels are implementation under `src/channels/**`; plugin authors get SDK seams. Providers own auth/catalog/runtime hooks; core owns generic loop.
- Agent run terminal state: normalize/merge via `src/agents/agent-run-terminal-outcome.ts`; do not rederive timeout/cancel precedence in projections.
- Hot paths should carry prepared facts forward: provider id, model ref, channel id, target, capability family, attachment class. Do not rediscover with broad plugin/provider/channel/capability loaders.
- Do not fix repeated request-time discovery with scattered caches. Move the canonical fact earlier; reuse prepared runtime objects; delete duplicate lookup branches.
- Gateway/plugin metadata is process-stable: installs, manifests, catalogs, generated paths, bundled metadata. Changes require restart or explicit owner reload/install/doctor flow.
- Runtime hot paths: no freshness polling (`stat`/`realpath`/JSON reread/hash). Reuse current snapshots, install records, discovery, lookup tables, root scopes, resolved paths.
- Process-local metadata caches ok when lifecycle-owned and bounded/single-slot. Freshness exceptions need named owner + tests.
- Inline comments: preserve reviewer context at the code site. Use for cross-path/state invariants, platform/dependency caps, deterministic ordering, compact encoded state, lifecycle ordering, ownership boundaries, session/id adoption, queue-depth symmetry, fallbacks, or intentional caller differences.
- Inline comments: preserve reviewer context at the code site. Required for non-obvious cross-path/state invariants, lifecycle ordering, ownership boundaries, queue/dedupe symmetry, TTL/cache expiry, cleanup/release coupling, session/id adoption, fallback behavior, platform/dependency caps, deterministic ordering, compact encoded state, or intentional caller differences.
- Comment shape: 1-3 short lines; state why the branch/helper exists, what contract it protects, and the bad outcome if removed. Cite nearby constants/helpers when useful. No syntax narration, PR/user-specific lore, or obvious mechanics.
- Gateway protocol changes: additive first; incompatible needs versioning/docs/client follow-through.
- Protocol version bumps: explicit owner confirmation only; never automatic/generated.
@@ -92,6 +93,7 @@ Skills own workflows; root owns hard policy and routing.
- Install: `pnpm install` (keep Bun lock/patches aligned if touched).
- CLI: `pnpm openclaw ...` or `pnpm dev`; build: `pnpm build`.
- Tests in a normal source checkout: `pnpm test <path-or-filter> [vitest args...]`, `pnpm test:changed`, `pnpm test:serial`, `pnpm test:coverage`; never raw `vitest`.
- If raw Vitest is unavoidable, use `vitest run ...`; bare `vitest ...` starts local watch mode and will not exit on its own.
- Tests in a Codex worktree or linked/sparse checkout: avoid direct local `pnpm test*`; use `node scripts/run-vitest.mjs <path-or-filter>` for tiny explicit-file proof, or Crabbox/Testbox for anything broader.
- Checks in a normal source checkout: `pnpm check:changed`; lanes: `pnpm changed:lanes --json`; staged: `pnpm check:changed --staged`; full: `pnpm check`.
- Checks in a Codex worktree or linked/sparse checkout: avoid direct local `pnpm check*`; use `node scripts/crabbox-wrapper.mjs run ... --shell -- "pnpm check:changed"` so pnpm runs inside Testbox, not locally.
@@ -227,6 +229,7 @@ Skills own workflows; root owns hard policy and routing.
- Parallels: `$openclaw-parallels-smoke`; Discord roundtrip: `$parallels-discord-roundtrip`.
- Crabbox/WebVNC human demos: keep remote desktop visible/windowed; no fullscreen remote browser unless video/capture-style output.
- ClawSweeper ops: `$clawsweeper`. Deployed hook sessions may post one concise `#clawsweeper` note only when surprising/actionable/risky; if using message tool, reply exactly `NO_REPLY`.
- Generated-media completions wake the requester agent first. Requester visible-reply config decides final text vs message tool; direct media send is fallback/recovery only.
- Memory wiki prompt digest stays tiny; prefer `wiki_search` / `wiki_get`; verify contact data before use; source-class provenance for generated people facts.
- Rebrand/migration/config warnings: run `openclaw doctor`.
- Never edit `node_modules`.

View File

@@ -2,22 +2,77 @@
Docs: https://docs.openclaw.ai
## Unreleased
## 2026.5.30
### Highlights
- Agents and CLI-backed runtimes recover more cleanly from interrupted tool calls, stale session bindings, compaction handoffs, and media delivery retries. (#88129, #88136, #88141, #88162, #88182)
- Channels and mobile delivery are steadier across Telegram, WhatsApp, iMessage, Slack, Discord, Microsoft Teams, Google Chat, Google Meet, and iOS realtime Talk. (#88096, #88105, #88183, #88231)
- Provider and plugin requests now bound more timers, retries, OAuth/device-code lifetimes, media downloads, local service probes, and generated-content polling paths before they can hang a run.
- Skills, session metadata, gateway runtime state, plugin metadata, and store writes do less repeated work on hot paths while keeping config and dispatch behavior stable.
- Workboard, SecretRef plugin manifests, hosted iOS push relay, and external Copilot/Tokenjuice packaging add broader orchestration, integration, and plugin delivery surfaces. (#82326, #87469, #87796, #88107, #88117)
- Release, CI, Docker, E2E, and diagnostics lanes now cap more logs, response bodies, readiness probes, artifact checks, and status polling so failures report bounded proof instead of stalling.
### Changes
- Skills: let the `skill_research` agent tool apply, reject, and quarantine explicit Skill Workshop proposals through the guarded proposal lifecycle. Thanks @shakkernerd.
- Skills: let Skill Workshop proposals carry approved support files under standard skill folders, with scanner, hash, and rollback safeguards. Thanks @shakkernerd.
- Skills: let pending Skill Workshop proposals be revised in place with versioned, dated proposal frontmatter before approval. Thanks @shakkernerd.
- Skills: add Skill Workshop proposals with pending `PROPOSAL.md` drafts, CLI/Gateway review actions, rollback metadata, and the `skill_research` agent tool. Thanks @shakkernerd.
- Plugins: externalize Tokenjuice as the official `@openclaw/tokenjuice` plugin with npm and ClawHub publish metadata.
- Plugins: externalize the GitHub Copilot agent runtime as the official `@openclaw/copilot` plugin with npm and ClawHub publish metadata.
- iOS: add hosted push relay defaults, realtime Talk playback, and a guarded WebSocket ping path for more reliable mobile sessions. (#88096, #88105, #88231)
- Workboard: add orchestration primitives and agent coordination tools for multi-agent planning and run tracking. (#87469)
- Code mode: add internal namespaces for scoped agent/global sessions and exact namespace tool dispatch. (#88043)
- Control UI: add a Dreaming-tab agent selector and propagate the selected agent through Dreaming status, diary, and diary actions. (#78748) Thanks @stevenepalmer.
- Plugins: add a SecretRef provider integration manifest contract and extract shared LLM core packages for provider/plugin reuse. (#82326, #88117)
- Skills: add the core skills index and centralize skills runtime loading, status, filtering, and prompt formatting.
### Fixes
- CLI: keep `plugins list --json` on the snapshot-only path so plugin sweeps avoid loading the full runtime status graph.
- Plugins: make PixVerse external-plugin ClawHub metadata explicit and keep it out of bundled dist builds.
- Cron: keep SQLite cron migrations compatible with legacy run-log tables, archived job stores, diagnostic cron names, and legacy one-shot delete-after-run behavior. (#88285)
- Providers: bound generated media downloads from OpenAI, Runway, xAI, MiniMax, BytePlus, DashScope-compatible, FAL, OpenRouter, Google, Vydra, and Comfy providers.
- Providers: cap GitHub Copilot OAuth request timeouts before creating abort signals.
- Cron: retry recurring jobs after transient model rate limits before waiting for the next scheduled slot.
- Agents/Codex: keep live session locks during cleanup, recover interrupted CLI tool transcripts, preserve Codex auth and compaction session identity, clear orphan tool state, cap app-server idle timers, and keep media completion delivery retryable. (#88129, #88136, #88141, #88162, #88182)
- Chat/UI: show Gateway chat failures as visible assistant messages in the Control UI instead of only setting an invisible error state.
- Channels: cap Telegram, Discord, WhatsApp, Signal, Feishu, Google Chat, Microsoft Teams, QQBot, Nostr, Zalo, Zalouser, and Nextcloud-style request/retry timers; preserve SMS approval reply routes; and retry WhatsApp QR login 408 timeouts. (#88183)
- Security/config parsing: reject unsafe OAuth/token lifetimes, retry-after delays, inbound timestamps, response body sizes, command timeout config, sandbox observer token TTLs, and gateway WebSocket calls after close.
- Providers/media: cap local service, model, usage, queue, generated media, TTS, music, workflow polling, and provider OAuth request timers across hosted and local providers.
- Release/CI/E2E: bound release candidate reads, beta smoke REST calls, changelog restore, kitchen-sink and bundled plugin readiness probes, secret-provider probes, Vitest routing, and mainline test flakes. (#88127, #88137, #88155, #88160)
- Release/CI/E2E: run the secret-provider integration proof through the repo pnpm runner so native macOS and Windows validation use the hydrated package-manager shim.
- Release/CI/E2E: run the Telegram desktop proof gateway through the repo pnpm runner so native macOS proof uses the hydrated package-manager shim.
- Docs/CI: run Mintlify anchor checks through the repo pnpm runner so docs link validation works when pnpm is only available through the hydrated package-manager shim.
- Agents: keep configured fallback model metadata typed so provider params, context-token caps, and media input limits do not break changed-gate typechecks.
- Agents: accept hidden `sessions_send` body aliases before validation while keeping the model-facing `message` schema canonical. (#88229) Thanks @zhangguiping-xydt.
- CI/Crabbox: keep default runner capacity spot-only and provider-neutral so OpenClaw remote validation does not silently fall back to on-demand leases or stale AWS region hints.
- CI/Crabbox: route Crabbox wrapper and Testbox workflow edits to their regression tests so changed-test gates do not silently run zero specs.
- CI/workflows: route workflow sanity helper edits to their guard tests and cover composite-action input interpolation checks.
- CI/tooling: route CI scope, dependency, changelog, and docs helper edits to their owner tests instead of silently skipping changed-test coverage.
- CI/tooling: route package, release, and install helper edits to their owner tests so changed-test gates cover publish and installer script changes.
- CI/tooling: route shared script library edits through their owner tests so lock, process, safety, and scan helpers do not skip changed-test coverage.
- CI/tooling: skip expensive import-graph scans once a changed diff already requires broad fallback, keeping local changed-test planning fast while still collecting explicit owner tests.
- CI/tooling: route script edits through conventional owner tests when matching `test/scripts` or `src/scripts` coverage already exists.
- CI/tooling: honor option terminators in the memory FD repro script so follow-on arguments are not reparsed.
- Release/CI/E2E: honor option terminators across release, Parallels smoke, plugin gauntlet, and extension-memory scripts.
- Release/CI/E2E: fail plugin gateway gauntlet QA chunks when the requested suite summary is missing or invalid.
- Performance: prebuild QA runtime probes with generated plugin assets but without CLI startup metadata.
- Performance: skip declaration bundling for runtime-only CLI startup and gateway watch build profiles.
- Performance: reuse prepared provider handles, strict tool schemas, gateway runtime metadata, session maintenance config, plugin metadata, bundled skill allowlists, package-local plugin artifacts, single-entry store writes, and validated/serialized session prompt blobs.
## 2026.5.28
### Highlights
- Agent and Codex runtime recovery is steadier: subagents keep cwd/workspace separation, hook context stays prompt-local, session locks release on timeout abort, stale restart continuations are avoided, and Codex app-server/helper failures no longer tear down shared runtime state. (#87218, #86875, #87409, #87399, #87375)
- Channel delivery and session identity got safer across outbound plugin hooks, Matrix room ids, iMessage reactions/approvals, Slack final replies, Discord recovered tool warnings, and Microsoft Teams service URL trust checks. (#73706, #75670, #87366, #87451, #87334)
- Mobile and chat surfaces got a broader refresh: the iOS Pro UI, Gateway chat transport, onboarding, Talk permissions, WebChat reconnect delivery, and session picker behavior now preserve more state across reconnects and empty searches. (#87367, #87531, #87682)
- CLI, auth, doctor, and provider paths fail faster and recover more clearly: malformed numeric/version options are rejected, OAuth and local service startup requests are bounded, legacy `api_key` auth profiles migrate to canonical form, and restart guidance is actionable. (#87398, #86281, #87361)
- Plugin and Gateway hot paths do less repeated work while preserving cache correctness for install records, config JSON parsing, tool search catalogs, session stores, manifest model rows, auto-enabled plugin config, browser tokens, and viewer assets. (#86699)
- Agent and Codex runtime recovery is steadier: subagents keep cwd/workspace separation, hook context stays prompt-local, session locks release on timeout abort while live OpenClaw locks survive cleanup, stale restart continuations are avoided, and Codex app-server/helper failures no longer tear down shared runtime state. (#87218, #86875, #87409, #87399, #87375, #88129)
- Channel delivery and session identity got safer across outbound plugin hooks, Matrix room ids, iMessage reactions/approvals, Slack final replies, Discord recovered tool warnings, runtime-config message actions, WhatsApp profile auth roots, Telegram polling, and Microsoft Teams service URL trust checks. (#73706, #75670, #87366, #87451, #87334, #84535, #82492, #83304, #87160)
- Mobile and chat surfaces got a broader refresh: the iOS Pro UI, hosted push relay default, realtime Talk tab playback, Gateway chat transport, onboarding, Talk permissions, WebChat reconnect delivery, and session picker behavior now preserve more state across reconnects and empty searches. (#87367, #87531, #87682, #88096, #88105) Thanks @ngutman and @BunsDev.
- Browser, channel, and automation inputs are stricter: Browser tool timeouts, viewport/tab indices, Gateway ports, cron retry handling, Discord component ids, schema array refs, Telegram callback pages, and channel progress callbacks now reject malformed values earlier and preserve the intended delivery context. (#82887)
- Provider, media, and document coverage expands with Claude Opus 4.8, Fal Krea image schemas, NVIDIA featured models, MiniMax streaming music responses, encrypted PDF extraction, voice model catalogs, GitHub Copilot agent runtime support, and a Codex Supervisor plugin path for delegated Codex workflows. (#87845, #87890, #80775, #84764, #87751, #87794)
- CLI, auth, doctor, and provider paths fail faster and recover more clearly: malformed numeric/version options are rejected, workspace dotenv provider credentials are ignored, heartbeat defaults, OAuth/token lifetimes, and local service startup requests are bounded, agent auth health labels are clearer, legacy `api_key` auth profiles migrate to canonical form, and restart guidance is actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #88088, #85924) Thanks @vincentkoc and @giodl73-repo.
- Plugin and Gateway hot paths do less repeated work while preserving cache correctness for install records, config JSON parsing, tool search catalogs, session stores, manifest model rows, auto-enabled plugin config, browser tokens, viewer assets, and release-split external plugin packages. (#86699)
- Release, QA, and E2E validation now bound more log, artifact, harness, and cross-OS waits so failing lanes produce proof instead of hanging or false-greening.
### Changes
@@ -25,24 +80,41 @@ Docs: https://docs.openclaw.ai
- Status: show active subagent details in status output.
- Diffs: split the default language pack and expand default Diffs language coverage while keeping the host floor aligned. (#87370, #87372) Thanks @RomneyDa.
- ClawHub: add plugin display names plus skill verification and trust surfaces. (#87354, #86699) Thanks @thewilloftheshadow and @Patrick-Erichsen.
- iOS: refresh the dev app with Pro Command, Chat, Agents, and Settings tabs wired to gateway sessions, diagnostics, chat, and realtime Talk. (#87367) Thanks @Solvely-Colin.
- Docs: clarify Codex computer-use setup, paste-token stdin auth setup, macOS gateway sleep troubleshooting, native Codex hook relay recovery, container model auth, install deployment cards, device-token admin gating, and backport targets. (#87313, #63050) Thanks @bdjben, @liaoandi, and @thewilloftheshadow.
- PDF/tools: use ClawPDF for PDF extraction and surface MCP structured content in agent tool results. (#87670)
- iOS: refresh the dev app with Pro Command, Chat, Agents, Settings, hosted push relay defaults, and realtime Talk playback wired to gateway sessions, diagnostics, chat, and realtime Talk. (#87367, #88096, #88105) Thanks @Solvely-Colin and @ngutman.
- Docs: clarify Codex computer-use setup, paste-token stdin auth setup, macOS gateway sleep troubleshooting, native Codex hook relay recovery, container model auth, install deployment cards, device-token admin gating, CLI setup flow compatibility, Notte cloud browser CDP setup, and backport targets. (#87313, #63050, #87685) Thanks @bdjben, @liaoandi, and @thewilloftheshadow.
- PDF/tools: use ClawPDF for PDF extraction, support encrypted PDF extraction, and surface MCP structured content in agent tool results. (#87670, #87751)
- Providers: add Claude Opus 4.8 support, Fal Krea image model schemas, NVIDIA featured model catalogs, MiniMax streaming music responses, and provider-backed voice model catalogs. (#87845, #87890, #80775, #84764, #87794) Thanks @eleqtrizit and @vincentkoc.
- Codex/GitHub: add the GitHub Copilot agent runtime and the Codex Supervisor plugin package.
- Plugins: externalize GitHub Copilot and Tokenjuice as official install-on-demand plugins with npm and ClawHub publish metadata.
- Workboard: add agent coordination tools for tracking and handing off active agent work.
- Discord: show commentary in progress drafts so live Discord runs expose useful in-progress context. (#85200)
- Plugin SDK: add a reply payload sending hook for plugins that need to deliver channel-owned replies and flatten package types for SDK declarations. (#82823, #87165) Thanks @piersonr and @RomneyDa.
- Policy: add policy comparison, ingress-channel conformance, and sandbox-posture conformance checks. (#85572, #85744, #86768)
### Fixes
- Agents: fall back to local config pruning when the optional `agents delete` Gateway probe cannot authenticate, so offline installs can still delete agents without removing shared workspaces.
- Tighten phone-control mutation authorization [AI]. (#87150) Thanks @pgondhi987.
- Clarify directive persistence authorization policy [AI]. (#86369) Thanks @pgondhi987.
- Agents/Codex: keep spawned agent cwd/workspace state separated, keep hook context prompt-local, release session locks on timeout abort, avoid session event queue self-wait, preserve shared app-server state across startup or helper failures, keep native hook relay alive across restarts, route workspace memory through tools, resolve Codex runtime models first, report quarantined dynamic tools, format `skills` command output, and bound compaction/steering retries. (#87218, #86875, #86123, #87399, #87375, #87383, #87400) Thanks @mbelinky, @Alix-007, @luoyanglang, @yetval, and @sjf.
- Channels: thread canonical session keys into outbound hooks, preserve Matrix room-id case, keep fallback tool warnings mention-inert, retain delivered Slack final replies during late cleanup, continue iMessage polling after denied reactions, suppress duplicate native exec approvals, preserve Telegram SecretRef prompt config, suppress Discord recovered tool warnings, and block untrusted Teams service URLs. (#73706, #75670, #87366, #87451, #87334) Thanks @zeroaltitude, @lukeboyett, @xiaotian, and @eleqtrizit.
- CLI/auth/doctor/providers: reject malformed numeric/timeout/subcommand-version inputs, wait for respawn child shutdown, bound Codex and GitHub Copilot OAuth/token requests, warm provider auth off the main thread, honor Codex response timeouts, bound local service startup, resolve GPT-5.5 without cached catalog, migrate legacy memory auto-provider config, rewrite non-canonical `api_key` auth profiles, and make doctor restart follow-ups actionable. (#87398, #86281, #87361) Thanks @Patrick-Erichsen, @samzong, @giodl73-repo, and @alkor2000.
- Gateway/security/session state: expire browser tokens after auth rotation, scope assistant idempotency dedupe, drain probe client closes, avoid stale restart continuation reuse, preserve retry-after fallbacks, bound webchat image and artifact transcript scans, include seconds in inbound metadata timestamps, and evict current plugin-state namespaces at row caps.
- Config/parsing/network: reject partial numeric parsing, parse provider/Discord retry headers and dates strictly, honor IPv6 and bare IPv6 `no_proxy` entries, canonicalize secret target array indexes, and reject malformed media content lengths, inspected TCP ports, marketplace content lengths, cron epochs, and sandbox stat fields.
- Providers/agents: preserve seeded Anthropic signatures, concatenate signature-delta chunks, preserve DeepSeek `reasoning_content` replay across tier suffixes, apply OpenRouter strict9 ids to Mistral routes, promote Ollama plain-text tool calls, and recover empty preflight compaction. (#87593)
- Agents/Codex: keep spawned agent cwd/workspace state separated, forward ACP spawn attachments, keep hook context prompt-local, release session locks on timeout abort and runtime teardown without deleting live OpenClaw-owned locks during cleanup, avoid session event queue self-wait, clean up exec abort listeners, stream assistant deltas incrementally, recover raw missing-thread compaction failures, preserve rotated compaction session identity, keep compaction-timeout snapshots continuable, preserve shared app-server state across startup or helper failures, keep native hook relay alive across restarts and prune stale bridge files, close native hook relay replacement races, keep Claude live tool progress visible for watchdog recovery, suppress abandoned requester completion handoff, route workspace memory through tools, resolve Codex runtime models first, report quarantined dynamic tools, format `skills` command output, bind node auto-review to prepared plans, retry Claude CLI transcript probes, and bound compaction/steering retries. (#87218, #86875, #86123, #88129, #87399, #87375, #72574, #87383, #87400, #83022, #87671, #87738, #87747, #87706, #87546, #87541, #81048) Thanks @mbelinky, @Alix-007, @luoyanglang, @yetval, @sjf, @joshavant, @benjamin1492, @c19354837, @fuller-stack-dev, @pfrederiksen, and @dodge1218.
- Codex Supervisor: keep real-home app-server MCP session listing on the loaded state path, bound stored history scans, and close WebSocket probes cleanly.
- Channels: thread canonical session keys into outbound hooks, preserve Matrix room-id case, keep fallback tool warnings mention-inert, retain delivered Slack final replies during late cleanup, continue iMessage polling after denied reactions, suppress duplicate native exec approvals, resolve Gateway message actions against the active runtime config, preserve Telegram SecretRef prompt config and polling keepalives, preserve WhatsApp profile auth roots, QR display, document filenames, and plugin hook config, suppress Discord recovered tool warnings, preserve the Discord voice outbound helper, cap Discord/Signal/Zalo channel request and container timeouts, and block untrusted Teams service URLs while keeping TeamsSDK patterns aligned. (#73706, #75670, #87366, #87451, #87465, #87334, #84535, #76262, #83304, #82492, #87581, #77114, #86426, #85529, #87160) Thanks @zeroaltitude, @lukeboyett, @jarvis-mns1, @xiaotian, @funmerlin, @joshavant, @eleqtrizit, @heyitsaamir, @amittell, @lidge-jun, @liorb-mountapps, @masatohoshino, @bladin, and @giodl73-repo.
- CLI/auth/doctor/providers: reject malformed numeric/timeout/subcommand-version inputs, ignore workspace dotenv provider credentials, wait for respawn child shutdown, bound heartbeat defaults plus Codex, GitHub Copilot, OpenAI, Anthropic, Google, Feishu, LM Studio, MiniMax, Xiaomi TTS, and local-provider OAuth/token/model requests, harden Codex auth probes, label auth health by agent, preserve explicit agentRuntime pins during Codex model migration, warm provider auth off the main thread, honor Codex response timeouts, stop migrating current Claude Haiku 4.5 profiles to Sonnet, bound local service startup, resolve GPT-5.5 without cached catalog, migrate legacy memory auto-provider config, rewrite non-canonical `api_key` auth profiles, and make doctor restart follow-ups actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #87719, #88088, #85924, #84362) Thanks @Patrick-Erichsen, @samzong, @giodl73-repo, @alkor2000, @mmaps, @nxmxbbd, and @vincentkoc.
- Gateway/security/session state: expire browser tokens after auth rotation, scope assistant idempotency dedupe, drain probe client closes, avoid stale restart continuation reuse, preserve retry-after fallbacks and stale rate-limit cooldown probes, bound webchat image and artifact transcript scans, include seconds in inbound metadata timestamps, clear completed session active runs, clear stale chat stream buffers, and evict current plugin-state namespaces at row caps. (#87810, #87833, #75089) Thanks @joshavant and @litang9.
- Config/parsing/network: reject partial numeric parsing, parse provider/Discord retry headers and dates strictly, honor IPv6 and bare IPv6 `no_proxy` entries, preserve empty plugin allowlists, canonicalize secret target array indexes, and reject malformed media content lengths, inspected TCP ports, marketplace content lengths, cron epochs, sandbox stat fields, unsafe duration values, empty config path segments, noncanonical schema array refs, unsafe Telegram callback pages, and invalid Teams attachment-fetch DNS targets. (#87883) Thanks @zhangguiping-xydt.
- Browser/input hardening: reject invalid tab indexes, excessive viewport resizes, explicit zero CDP ports, malformed geolocation options, unsafe screenshot or permission-grant timeouts, loose response-body limits, invalid cookie expiries, and non-finite Browser tool delays/timeouts.
- Cron/automation: retry recurring jobs after transient model rate limits before waiting for the next scheduled slot, and preflight model fallbacks before skipping scheduled work. (#82887) Thanks @chen-zhang-cs-code.
- Auto-reply/directives: respect provider and relayed channel metadata during directive persistence so channel-originated decisions keep their intended context. (#87683)
- WhatsApp: resolve the auth directory from the active profile so profile-scoped WhatsApp installs do not drift to the wrong credential root. (#82492) Thanks @lidge-jun.
- Gateway/session state: clear completed session active runs, avoid cold-loading providers for MCP inventory, cache single-session child indexes, cap handshake timers, and bound preauth, auth-guard, media, transcript, readiness, and port options.
- Channels/replies: preserve channel-owned progress callbacks when verbose output is off, keep group-room progress suppression intact, prefer external session delivery context, escape Discord component id delimiters, force final TUI chat repaints, show Slack reasoning previews, and normalize Discord/Matrix/Mattermost channel numeric options. (#87476, #87423)
- Agents/tool args: harden smart-quoted argument repair for edit arrays and exact escaped arguments so model-produced tool calls recover without corrupting valid input. (#86611) Thanks @ferminquant.
- Providers/agents: preserve seeded Anthropic signatures, preserve signed thinking payloads, concatenate signature-delta chunks, preserve DeepSeek `reasoning_content` replay across tier suffixes, apply OpenRouter strict9 ids to Mistral routes, promote Ollama plain-text tool calls, load NVIDIA featured model catalogs, stream MiniMax music generation responses, and recover empty preflight compaction. (#87593, #87493, #80775, #84764) Thanks @Pluviobyte and @eleqtrizit.
- Media/images: skip CLI image cache refs when resolving generated images, allow trusted generated HTML attachments, and bound generated video downloads so stale refs and slow providers fail cleanly. (#87523, #87982)
- File transfer: handle late tar stdin pipe errors after archive validation or unpacking has already settled.
- Performance: trust install-record caches between reloads, prefer native JSON parsing, reuse unchanged tool-search catalogs, skip unchanged store serialization, add precomputed session patch writers, reduce store clone allocations, cache manifest model catalog rows and auto-enabled plugin config, and slim current metadata identity caches.
- Docker/release/QA: package runtime workspace templates, stream cross-OS served artifacts, preserve sparse Crabbox run artifacts, bound OpenClaw instance logs, plugin gauntlet relay logs, MCP channel buffers, kitchen-sink scans, agent-turn assertions, and release scenario logs, and keep release/google live guards current.
- Performance: trust install-record caches between reloads, prefer native JSON parsing, reuse unchanged tool-search catalogs, reuse gateway session and plugin metadata paths, skip unchanged store serialization, patch single-entry session writes, add precomputed session patch writers, reduce store clone allocations, cache manifest model catalog rows and auto-enabled plugin config, avoid full session snapshots for entry reads, defer configured Slack full startup, prefer bundled plugin dist entries, and slim current metadata identity caches. (#87760)
- Docker/release/QA: package runtime workspace templates, stream cross-OS served artifacts, preserve sparse Crabbox run artifacts, isolate npm plugin installs per package, reject incompatible package plugin API installs, drop the leftover root Sharp dependency from package manifests after the Rastermill migration, bound OpenClaw instance logs, plugin gauntlet relay logs, MCP channel buffers, kitchen-sink scans, agent-turn assertions, QA-Lab credential broker calls, QA Matrix substrate requests, and release scenario logs, and keep release/google live guards current. (#87647, #87477) Thanks @rohitjavvadi and @vincentkoc.
- Release/CI: bound manual git fetches, ClawHub verifier responses, ClawHub owner metadata, dependency-guard error bodies, Parallels limits, startup/test/memory budget parsing, and diffs viewer build warnings so release lanes fail with useful proof instead of hanging. (#87839)
## 2026.5.27

View File

@@ -2,6 +2,70 @@
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
<channel>
<title>OpenClaw</title>
<item>
<title>2026.5.28</title>
<pubDate>Sat, 30 May 2026 21:21:09 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026052890</sparkle:version>
<sparkle:shortVersionString>2026.5.28</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.5.28</h2>
<h3>Highlights</h3>
<ul>
<li>Agent and Codex runtime recovery is steadier: subagents keep cwd/workspace separation, hook context stays prompt-local, session locks release on timeout abort while live OpenClaw locks survive cleanup, stale restart continuations are avoided, and Codex app-server/helper failures no longer tear down shared runtime state. (#87218, #86875, #87409, #87399, #87375, #88129)</li>
<li>Channel delivery and session identity got safer across outbound plugin hooks, Matrix room ids, iMessage reactions/approvals, Slack final replies, Discord recovered tool warnings, runtime-config message actions, WhatsApp profile auth roots, Telegram polling, and Microsoft Teams service URL trust checks. (#73706, #75670, #87366, #87451, #87334, #84535, #82492, #83304, #87160)</li>
<li>Mobile and chat surfaces got a broader refresh: the iOS Pro UI, hosted push relay default, realtime Talk tab playback, Gateway chat transport, onboarding, Talk permissions, WebChat reconnect delivery, and session picker behavior now preserve more state across reconnects and empty searches. (#87367, #87531, #87682, #88096, #88105) Thanks @ngutman.</li>
<li>Browser, channel, and automation inputs are stricter: Browser tool timeouts, viewport/tab indices, Gateway ports, cron retry handling, Discord component ids, schema array refs, Telegram callback pages, and channel progress callbacks now reject malformed values earlier and preserve the intended delivery context. (#82887)</li>
<li>Provider, media, and document coverage expands with Claude Opus 4.8, Fal Krea image schemas, NVIDIA featured models, MiniMax streaming music responses, encrypted PDF extraction, voice model catalogs, GitHub Copilot agent runtime support, and a Codex Supervisor plugin path for delegated Codex workflows. (#87845, #87890, #80775, #84764, #87751, #87794)</li>
<li>CLI, auth, doctor, and provider paths fail faster and recover more clearly: malformed numeric/version options are rejected, workspace dotenv provider credentials are ignored, heartbeat defaults, OAuth/token lifetimes, and local service startup requests are bounded, agent auth health labels are clearer, legacy <code>api_key</code> auth profiles migrate to canonical form, and restart guidance is actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #88088, #85924) Thanks @vincentkoc and @giodl73-repo.</li>
<li>Plugin and Gateway hot paths do less repeated work while preserving cache correctness for install records, config JSON parsing, tool search catalogs, session stores, manifest model rows, auto-enabled plugin config, browser tokens, viewer assets, and release-split external plugin packages. (#86699)</li>
<li>Release, QA, and E2E validation now bound more log, artifact, harness, and cross-OS waits so failing lanes produce proof instead of hanging or false-greening.</li>
</ul>
<h3>Changes</h3>
<ul>
<li>Status: show active subagent details in status output.</li>
<li>Diffs: split the default language pack and expand default Diffs language coverage while keeping the host floor aligned. (#87370, #87372) Thanks @RomneyDa.</li>
<li>ClawHub: add plugin display names plus skill verification and trust surfaces. (#87354, #86699) Thanks @thewilloftheshadow and @Patrick-Erichsen.</li>
<li>iOS: refresh the dev app with Pro Command, Chat, Agents, Settings, hosted push relay defaults, and realtime Talk playback wired to gateway sessions, diagnostics, chat, and realtime Talk. (#87367, #88096, #88105) Thanks @Solvely-Colin and @ngutman.</li>
<li>Docs: clarify Codex computer-use setup, paste-token stdin auth setup, macOS gateway sleep troubleshooting, native Codex hook relay recovery, container model auth, install deployment cards, device-token admin gating, CLI setup flow compatibility, Notte cloud browser CDP setup, and backport targets. (#87313, #63050, #87685) Thanks @bdjben, @liaoandi, and @thewilloftheshadow.</li>
<li>PDF/tools: use ClawPDF for PDF extraction, support encrypted PDF extraction, and surface MCP structured content in agent tool results. (#87670, #87751)</li>
<li>Providers: add Claude Opus 4.8 support, Fal Krea image model schemas, NVIDIA featured model catalogs, MiniMax streaming music responses, and provider-backed voice model catalogs. (#87845, #87890, #80775, #84764, #87794) Thanks @eleqtrizit and @vincentkoc.</li>
<li>Codex/GitHub: add the GitHub Copilot agent runtime and the Codex Supervisor plugin package.</li>
<li>Plugins: externalize GitHub Copilot and Tokenjuice as official install-on-demand plugins with npm and ClawHub publish metadata.</li>
<li>Workboard: add agent coordination tools for tracking and handing off active agent work.</li>
<li>Discord: show commentary in progress drafts so live Discord runs expose useful in-progress context. (#85200)</li>
<li>Plugin SDK: add a reply payload sending hook for plugins that need to deliver channel-owned replies and flatten package types for SDK declarations. (#82823, #87165) Thanks @RomneyDa.</li>
<li>Policy: add policy comparison, ingress-channel conformance, and sandbox-posture conformance checks. (#85572, #85744, #86768)</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Agents: fall back to local config pruning when the optional <code>agents delete</code> Gateway probe cannot authenticate, so offline installs can still delete agents without removing shared workspaces.</li>
<li>Tighten phone-control mutation authorization [AI]. (#87150) Thanks @pgondhi987.</li>
<li>Clarify directive persistence authorization policy [AI]. (#86369) Thanks @pgondhi987.</li>
<li>Agents/Codex: keep spawned agent cwd/workspace state separated, forward ACP spawn attachments, keep hook context prompt-local, release session locks on timeout abort and runtime teardown without deleting live OpenClaw-owned locks during cleanup, avoid session event queue self-wait, clean up exec abort listeners, stream assistant deltas incrementally, recover raw missing-thread compaction failures, preserve rotated compaction session identity, keep compaction-timeout snapshots continuable, preserve shared app-server state across startup or helper failures, keep native hook relay alive across restarts and prune stale bridge files, close native hook relay replacement races, keep Claude live tool progress visible for watchdog recovery, suppress abandoned requester completion handoff, route workspace memory through tools, resolve Codex runtime models first, report quarantined dynamic tools, format <code>skills</code> command output, bind node auto-review to prepared plans, retry Claude CLI transcript probes, and bound compaction/steering retries. (#87218, #86875, #86123, #88129, #87399, #87375, #72574, #87383, #87400, #83022, #87671, #87738, #87747, #87706, #87546, #87541, #81048) Thanks @mbelinky, @Alix-007, @luoyanglang, @yetval, @sjf, @joshavant, and @benjamin1492.</li>
<li>Codex Supervisor: keep real-home app-server MCP session listing on the loaded state path, bound stored history scans, and close WebSocket probes cleanly.</li>
<li>Channels: thread canonical session keys into outbound hooks, preserve Matrix room-id case, keep fallback tool warnings mention-inert, retain delivered Slack final replies during late cleanup, continue iMessage polling after denied reactions, suppress duplicate native exec approvals, resolve Gateway message actions against the active runtime config, preserve Telegram SecretRef prompt config and polling keepalives, preserve WhatsApp profile auth roots, QR display, document filenames, and plugin hook config, suppress Discord recovered tool warnings, preserve the Discord voice outbound helper, cap Discord/Signal/Zalo channel request and container timeouts, and block untrusted Teams service URLs while keeping TeamsSDK patterns aligned. (#73706, #75670, #87366, #87451, #87465, #87334, #84535, #76262, #83304, #82492, #87581, #77114, #86426, #85529, #87160) Thanks @zeroaltitude, @lukeboyett, @xiaotian, @funmerlin, @joshavant, @eleqtrizit, @heyitsaamir, @amittell, @liorb-mountapps, @masatohoshino, @bladin, and @giodl73-repo.</li>
<li>CLI/auth/doctor/providers: reject malformed numeric/timeout/subcommand-version inputs, ignore workspace dotenv provider credentials, wait for respawn child shutdown, bound heartbeat defaults plus Codex, GitHub Copilot, OpenAI, Anthropic, Google, Feishu, LM Studio, MiniMax, Xiaomi TTS, and local-provider OAuth/token/model requests, harden Codex auth probes, label auth health by agent, preserve explicit agentRuntime pins during Codex model migration, warm provider auth off the main thread, honor Codex response timeouts, stop migrating current Claude Haiku 4.5 profiles to Sonnet, bound local service startup, resolve GPT-5.5 without cached catalog, migrate legacy memory auto-provider config, rewrite non-canonical <code>api_key</code> auth profiles, and make doctor restart follow-ups actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #87719, #88088, #85924, #84362) Thanks @Patrick-Erichsen, @samzong, @giodl73-repo, @alkor2000, @mmaps, @nxmxbbd, and @vincentkoc.</li>
<li>Gateway/security/session state: expire browser tokens after auth rotation, scope assistant idempotency dedupe, drain probe client closes, avoid stale restart continuation reuse, preserve retry-after fallbacks and stale rate-limit cooldown probes, bound webchat image and artifact transcript scans, include seconds in inbound metadata timestamps, clear completed session active runs, clear stale chat stream buffers, and evict current plugin-state namespaces at row caps. (#87810, #87833, #75089) Thanks @joshavant and @litang9.</li>
<li>Config/parsing/network: reject partial numeric parsing, parse provider/Discord retry headers and dates strictly, honor IPv6 and bare IPv6 <code>no_proxy</code> entries, preserve empty plugin allowlists, canonicalize secret target array indexes, and reject malformed media content lengths, inspected TCP ports, marketplace content lengths, cron epochs, sandbox stat fields, unsafe duration values, empty config path segments, noncanonical schema array refs, unsafe Telegram callback pages, and invalid Teams attachment-fetch DNS targets. (#87883) Thanks @zhangguiping-xydt.</li>
<li>Browser/input hardening: reject invalid tab indexes, excessive viewport resizes, explicit zero CDP ports, malformed geolocation options, unsafe screenshot or permission-grant timeouts, loose response-body limits, invalid cookie expiries, and non-finite Browser tool delays/timeouts.</li>
<li>Cron/automation: retry recurring jobs after transient model rate limits before waiting for the next scheduled slot, and preflight model fallbacks before skipping scheduled work. (#82887)</li>
<li>Auto-reply/directives: respect provider and relayed channel metadata during directive persistence so channel-originated decisions keep their intended context. (#87683)</li>
<li>WhatsApp: resolve the auth directory from the active profile so profile-scoped WhatsApp installs do not drift to the wrong credential root. (#82492)</li>
<li>Gateway/session state: clear completed session active runs, avoid cold-loading providers for MCP inventory, cache single-session child indexes, cap handshake timers, and bound preauth, auth-guard, media, transcript, readiness, and port options.</li>
<li>Channels/replies: preserve channel-owned progress callbacks when verbose output is off, keep group-room progress suppression intact, prefer external session delivery context, escape Discord component id delimiters, force final TUI chat repaints, show Slack reasoning previews, and normalize Discord/Matrix/Mattermost channel numeric options. (#87476, #87423)</li>
<li>Agents/tool args: harden smart-quoted argument repair for edit arrays and exact escaped arguments so model-produced tool calls recover without corrupting valid input. (#86611)</li>
<li>Providers/agents: preserve seeded Anthropic signatures, preserve signed thinking payloads, concatenate signature-delta chunks, preserve DeepSeek <code>reasoning_content</code> replay across tier suffixes, apply OpenRouter strict9 ids to Mistral routes, promote Ollama plain-text tool calls, load NVIDIA featured model catalogs, stream MiniMax music generation responses, and recover empty preflight compaction. (#87593, #87493, #80775, #84764) Thanks @eleqtrizit.</li>
<li>Media/images: skip CLI image cache refs when resolving generated images, allow trusted generated HTML attachments, and bound generated video downloads so stale refs and slow providers fail cleanly. (#87523, #87982)</li>
<li>File transfer: handle late tar stdin pipe errors after archive validation or unpacking has already settled.</li>
<li>Performance: trust install-record caches between reloads, prefer native JSON parsing, reuse unchanged tool-search catalogs, reuse gateway session and plugin metadata paths, skip unchanged store serialization, patch single-entry session writes, add precomputed session patch writers, reduce store clone allocations, cache manifest model catalog rows and auto-enabled plugin config, avoid full session snapshots for entry reads, defer configured Slack full startup, prefer bundled plugin dist entries, and slim current metadata identity caches. (#87760)</li>
<li>Docker/release/QA: package runtime workspace templates, stream cross-OS served artifacts, preserve sparse Crabbox run artifacts, isolate npm plugin installs per package, reject incompatible package plugin API installs, drop the leftover root Sharp dependency from package manifests after the Rastermill migration, bound OpenClaw instance logs, plugin gauntlet relay logs, MCP channel buffers, kitchen-sink scans, agent-turn assertions, QA-Lab credential broker calls, QA Matrix substrate requests, and release scenario logs, and keep release/google live guards current. (#87647, #87477) Thanks @rohitjavvadi and @vincentkoc.</li>
<li>Release/CI: bound manual git fetches, ClawHub verifier responses, ClawHub owner metadata, dependency-guard error bodies, Parallels limits, startup/test/memory budget parsing, and diffs viewer build warnings so release lanes fail with useful proof instead of hanging. (#87839)</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.28/OpenClaw-2026.5.28.zip" length="54750142" type="application/octet-stream" sparkle:edSignature="U4O55uMdPU+OqSx9QR1ApUJ8wg65wxTydzD7iyCn1GHtm1MBK9noEeiA/yoUKkqb/bx0hzi1gNhn+ye19RXnCA=="/>
</item>
<item>
<title>2026.5.27</title>
<pubDate>Thu, 28 May 2026 12:12:19 +0000</pubDate>
@@ -258,284 +322,5 @@
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.26/OpenClaw-2026.5.26.zip" length="54484748" type="application/octet-stream" sparkle:edSignature="y4WXG7JT8ktJ+K7YDgllY7u5Z9BSKR/SwGiwEh0gikOJ/SWqwcQd+z2tWa2zgwvCJKWsAUFwJs1ATor880SUBg=="/>
</item>
<item>
<title>2026.5.22</title>
<pubDate>Sun, 24 May 2026 01:41:27 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026052290</sparkle:version>
<sparkle:shortVersionString>2026.5.22</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.5.22</h2>
<h3>Changes</h3>
<ul>
<li>Gateway/perf: reuse process-stable channel catalog reads, avoid repeated bundled-channel boundary checks, and rotate gateway watch CPU profiles so benchmark runs do not accumulate unbounded artifacts.</li>
<li>Gateway/perf: reuse immutable plugin metadata snapshots across startup, config, model, channel, setup, and secret metadata readers so hot paths avoid repeated plugin file stats and manifest registry reloads.</li>
<li>Gateway/perf: lazy-load startup-idle plugin work, core gateway method handlers, and the embedded ACPX runtime so Gateway health and ready signals no longer wait on unused handler trees or ACPX probes.</li>
<li>Gateway/perf: cache plugin SDK public-surface alias maps and skip irrelevant macOS Linuxbrew PATH probes so Gateway startup avoids repeated filesystem walks and slow missing-directory stats.</li>
<li>Meeting Notes: add a source-only external meeting-notes plugin and SDK source-provider contract outside the core npm package, with auto-start capture config, manual transcript imports, read-only <code>openclaw meeting-notes</code> CLI access, and Discord voice as the first live source.</li>
<li>Docs/channels/config: add Signal <code>configPath</code>, Telegram wildcard topic defaults, local-time backup archive names, Termux home fallback, include-path validation, secret-scanner-safe placeholder guidance, Gemini CLI/Antigravity media guidance, and macOS VM auto-login guidance. Thanks @NorseGaud, @yudistiraashadi, @huangqian8, @VibhorGautam, @maweibin, @tianxingleo, @IgnacioPro, and @xzcxzcyy-claw.</li>
<li>Docs: clarify model-usage portability, Codex migration prerequisites, status bootstrap wording, thread-bound subagent limits, hook ownership, and config-preserving safety guidance. Thanks @aniruddhaadak80, @leno23, @TomDjerry, @matthewxmurphy, @vincentkoc, and @stablegenius49.</li>
<li>Docs: clarify README onboarding and Gateway startup paths, WhatsApp QR/408 recovery, cron output language prompts, skill advanced features, gateway upstream 403 troubleshooting, and plugin fallback override guidance. Thanks @deepujain, @Zacxxx, @Jah-yee, @neyric, @usimic, @Renu-Cybe, @BigUncle, and @SeashoreShi.</li>
<li>Docs: clarify context-pruning ratio bounds, local dashboard recovery, CLI env markers, remote onboarding token behavior, and Peekaboo Bridge permissions for subprocess agents. Thanks @ayesha-aziz123, @dishraters, @hougangdev, and @brandonlipman.</li>
<li>Docs: clarify browser CDP diagnostics, Plugin SDK allowlist imports, status-reaction timing defaults, queue steering behavior, limited-tool troubleshooting, cron HEARTBEAT handling, Telegram multi-agent groups, Bitwarden SecretRef setup, and EasyRunner deployments. Thanks @Quratulain-bilal, @mbelinky, @Mickey-, @vancece, @xenouzik, @posigit, @surlymochan, @janaka, and @choiking.</li>
<li>Crabbox/Testbox: run clean sparse-checkout Testbox syncs from a temporary full checkout and route remote changed gates through Corepack pnpm.</li>
<li>Docs: clarify IPv4-only Gateway BYOH binding, trusted-proxy scope clearing, Android pairing approval, macOS Accessibility grants, Zalo profile env vars, password-store SecretRef setup, and Chinese memory navigation. Thanks @itskai-dev, @gwh7078, @longstoryscott, @MoeJaberr, and @yuaiccc.</li>
<li>Docs: consolidate GLM under Z.AI, add the Upstash Box install guide and Gateway exposure runbook, clarify MEDIA directives, Copilot and Voyage setup, config path quoting, real behavior proof, and memory-file write guidance. Thanks @BobDu, @alitariksahin, @Jefsky, @musaabhasan, @OmerZeyveli, @leno23, @WuKongAI-CMU, @luoyanglang, and @majin1102.</li>
<li>Docs: clarify media provider credentials, Codex/OpenClaw code-mode boundaries, Slack and Telegram ack reactions, Feishu dynamic agents, secrets plaintext boundaries, memory guidance, and Chinese glossary terms. Thanks @nielskaspers, @cosmopolitan033, @drclaw-iq, @alexgduarte, @zccyman, @chengoak, and @cassthebandit.</li>
<li>Packaging: exclude documentation images and assets from the npm tarball, reducing published package size without affecting runtime docs search or CLI behavior. Thanks @SebTardif.</li>
<li>Media understanding: stop auto-probing Gemini CLI and use Antigravity CLI only as a lower-priority image/video fallback after configured provider APIs.</li>
<li>Agents/subagents: limit default sub-agent bootstrap context to <code>AGENTS.md</code> and <code>TOOLS.md</code>, keeping persona, identity, user, memory, heartbeat, and setup files out of delegated workers by default. (#85283) Thanks @100yenadmin.</li>
<li>Maintainer skills: exclude plugin SDK/API boundary work from <code>openclaw-landable-bug-sweep</code> so bugbash sweeps stay focused on small paper-cut fixes.</li>
<li>QA-Lab/diagnostics: extend the OpenTelemetry smoke harness to prove trace, metric, and log export, and add first-class Prometheus and observability smoke aliases.</li>
<li>Plugin SDK: add a generic channel-message poll sender so channel plugins can expose poll delivery without depending on channel-specific SDK facades.</li>
<li>Crabbox: keep the local wrapper's provider validation synced with the installed Crabbox binary while preserving supported aliases such as <code>docker</code> and <code>blacksmith</code>. (#85302) Thanks @hxy91819.</li>
<li>Maintainer skills: add <code>openclaw-landable-bug-sweep</code> for producing five small, reviewed, CI-green OpenClaw bugfix PRs from issue/PR sweeps.</li>
<li>Control UI/chat: add search and Load More pagination to the chat session picker, keeping initial session loads bounded while making older conversations reachable. (#85237) Thanks @amknight.</li>
<li>CLI/onboarding: start classic onboarding when bare <code>openclaw</code> runs before an authored config exists, while keeping configured installs on Crestodian. (#72343) Thanks @fuller-stack-dev.</li>
<li>Discord: allow configuring a bounded <code>agentComponents.ttlMs</code> callback registry lifetime for long-running component workflows, with per-account overrides and a 24-hour cap. (#84189) Thanks @100menotu001.</li>
<li>xAI/Grok: reuse xAI OAuth auth profiles for Grok <code>web_search</code>, thread active-agent auth through web search, add Grok model aliases, and let media providers declare default operation timeouts. (#85182) Thanks @fuller-stack-dev.</li>
<li>Plugin SDK: add row-level session workflow helpers and deprecate <code>loadSessionStore</code> so plugins can read and patch sessions without depending on the legacy whole-store shape. (#84693) Thanks @efpiva.</li>
<li>Gateway/plugins: reuse a compatible Gateway startup plugin registry during dispatch so safe plugin dispatches avoid redundant registry loading. (#84324) Thanks @ai-hpc.</li>
<li>Plugins/SDK: add a general <code>embeddingProviders</code> capability contract and registration API so embeddings can become a reusable provider surface outside memory-specific adapters.</li>
<li>Dependencies: refresh provider, plugin, UI, and tooling packages, update <code>protobufjs</code> to 8.4.0 to clear the current npm advisory, and carry the Claude ACP completion patch forward to <code>@agentclientprotocol/claude-agent-acp</code> 0.36.1.</li>
<li>Agents/tools: remove the old sender-owner tool gating path so configured tools stay visible for trusted sessions while command and channel-action auth still carry real sender identity.</li>
<li>QA-Lab: add curated mock JSONL replay fixtures and first-drift reporting for runtime-parity audits. (#80323, refs #80176) Thanks @100yenadmin.</li>
<li>QA-Lab: add a QA bus tool-trace visibility scenario for sanitized tool-call assertions.</li>
<li>QA-Lab: replace generic evidence framing in seeded scenario prompts with concrete observed QA behavior.</li>
<li>QA-Lab: list named scenario packs in the coverage report so personal-agent privacy coverage stays visible in audits.</li>
<li>QA-Lab: list live transport lane membership in the coverage report so real transport checks stay separate from seeded qa-channel scenarios.</li>
<li>Release/package: run package integrity checks before package acceptance lanes so public install/update validation fails before private QA assets can leak into the package.</li>
<li>QA-Lab: include the optional 100-turn runtime parity soak in release-soak artifacts so long-run Codex/Pi transcript drift stays visible outside the default gate. (#80395) Thanks @100yenadmin.</li>
<li>QA-Lab: add a live-only long-context progress watchdog scenario for Codex app-server timeout and stalled-run sentinels. (#80323) Thanks @100yenadmin.</li>
<li>QA-Lab: tag gateway restart recovery and streaming final-integrity scenarios as live-only runtime parity lanes. (#80323) Thanks @100yenadmin.</li>
<li>QA-Lab: add a personal-agent failure recovery scenario that checks honest partial status, retry boundaries, and local recovery artifacts. (#83872) Thanks @iFiras-Max1.</li>
<li>QA-Lab: include an opt-in <code>update.run</code> package self-upgrade sentinel for destructive latest-package recovery checks.</li>
<li>QA-Lab: add Codex plugin lifecycle and auth-profile fixture coverage for missing installs, pinned-version drift, first-turn install ordering, and doctor migration safety. (#80323, refs #80174) Thanks @100yenadmin.</li>
<li>Models/perf: pre-warm the provider auth-state map at gateway startup so <code>/models</code> and every model-listing call short-circuits the per-provider plugin / external-CLI discovery on the hot path. Per-call cost drops from ~20 s to ~5 ms (~4,100×); the one-time startup warm resets and re-warms after hot reloads. (#84816) Thanks @sjf.</li>
<li>Release/security: ship the root npm package and OpenClaw-owned npm plugins with generated shrinkwrap, support bundled plugin runtime dependencies for suitable plugin tarballs, and require review for lockfile/shrinkwrap changes so published installs use locked dependency graphs.</li>
<li>Tests/perf: isolate doctor core health check unit coverage from real skills/workspace discovery so <code>doctor-core-checks</code> no longer dominates unit perf while keeping one real skills-readiness smoke. (#84493) Thanks @frankekn.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>WebChat: summarize internal message-tool source replies so tool cards no longer duplicate the visible reply body. (#84773) Thanks @jason-allen-oneal.</li>
<li>Gateway: preserve deferred lifecycle-error cleanup across later non-terminal events so provider timeouts can persist failed session state instead of leaving sessions stuck running. (#85256, fixes #63819) Thanks @samzong.</li>
<li>Agents/subagents: report tool-only child progress during timeout summaries instead of showing no visible output.</li>
<li>Telegram/ACP: preserve explicit <code>:topic:</code> conversation suffixes when inbound ACP targets do not carry a separate thread id.</li>
<li>Browser/proxy: bypass the managed proxy for the exact local managed Chrome CDP readiness and DevTools WebSocket endpoints, so <code>openclaw browser start</code> works when the operator proxy blocks loopback egress. (#83255) Thanks @lightcap.</li>
<li>Ollama: bypass the managed proxy for configured local embedding origins while keeping SSRF guardrails on unconfigured targets. Thanks @Kaspre.</li>
<li>OpenAI/images: route Codex API-key image generation through the native OpenAI Images API instead of the Codex OAuth streaming backend, avoiding 401s from valid API keys.</li>
<li>Agents/OpenAI completions: omit empty tool payload fields for proxy-like OpenAI-compatible endpoints so strict vLLM-style servers accept tool-free turns. (#85835) Thanks @rendrag-git.</li>
<li>Checks/Windows: route full <code>pnpm check</code> stage commands through the managed child runner so Windows avoids Node shell-argv deprecation warnings there too.</li>
<li>Checks/Windows: run managed child commands through explicit <code>cmd.exe</code> wrapping instead of Node shell mode with argv, avoiding Node 24 subprocess deprecation warnings during changed checks.</li>
<li>Gateway: omit internal stream-error placeholder entries from agent prompt history so failed assistant turns are not replayed as model-authored text. (#85652) Thanks @anyech.</li>
<li>Sessions: enforce the session write-lock max-hold policy during lock acquisition so long-held locks can be reclaimed before the stale-lock window. (#85764) Thanks @njuboy11.</li>
<li>Models: prune retired Groq, GitHub Copilot, OpenAI, xAI, and old Claude catalog entries, with doctor migration to upgrade existing configs to current provider refs.</li>
<li>Doctor/update: recognize junction-backed source checkouts as git installs by comparing canonical paths before showing package-manager update guidance. Fixes #82215. Thanks @igormf.</li>
<li>Channels: honor <code>/verbose on</code> for tool/progress summaries across direct chats, groups, channels, and forum topics while preserving quiet default behavior. (#85488) Thanks @kurplunkin.</li>
<li>CLI/skills: show an all-ready note with next-step commands when skill setup has no missing dependencies to install. (#85032) Thanks @aniruddhaadak80.</li>
<li>Microsoft Foundry: route DeepSeek V4 Pro and Flash models through the Foundry Responses API while keeping older DeepSeek models on their existing path. (#85549) Thanks @roslinmahmud.</li>
<li>Status/usage: show configured cost estimates for AWS SDK models in full usage output while keeping token-only usage replies cost-free. (#85619) Thanks @ItsOtherMauridian.</li>
<li>Agents/OpenAI Responses: retry non-visible reasoning-only turns for OpenAI Responses API families instead of treating them as empty failed turns. (#85603) Thanks @SebTardif.</li>
<li>Directive tags: preserve message and content-part object identity when display stripping makes no directive-tag changes. (#85682) Thanks @willamhou.</li>
<li>Telegram: send local <code>path</code>/<code>filePath</code> and structured attachment media from <code>sendMessage</code> actions instead of dropping them or sending text-only messages. (#85219) Thanks @keshavbotagent.</li>
<li>Sessions/status: show the estimated context budget when fresh provider usage is unavailable and clear stale estimates across session resets and compaction boundaries. (#84830) Thanks @giodl73-repo.</li>
<li>Gateway/config: pin relative <code>OPENCLAW_STATE_DIR</code> overrides to an absolute path at startup so later working-directory changes cannot retarget gateway state. (#52264) Thanks @PerfectPan.</li>
<li>Release/package: run npm release, prepublish, and postpublish verification through Windows-safe npm command shims so native Windows checks can execute <code>npm.cmd</code> instead of treating it as a binary.</li>
<li>Agents/harness: pass CLI runtime aliases through harness selection so provider-owned CLI aliases no longer get rejected before reaching the right runtime. (#85631) Thanks @potterdigital.</li>
<li>Secrets: show the irreversible apply warning after interactive <code>secrets configure</code> confirmation so confirmed migrations still get the final safety prompt. (#85638) Thanks @alkor2000.</li>
<li>Agents/CLI output: ignore cumulative Claude <code>stream-json</code> result usage when assistant usage events are present, preventing inflated cache-read accounting. (#85625) Thanks @zhouhe-xydt.</li>
<li>CLI: keep <code>waitForever()</code> alive by leaving its keep-alive interval ref'd so the public helper no longer exits immediately with Node's unsettled-await code. (#85694) Thanks @m1qaweb.</li>
<li>Agents/bootstrap: guard bootstrap name checks against missing file names so malformed bootstrap entries warn and truncate instead of crashing. Fixes #85523. (#85615) Thanks @zhouhe-xydt.</li>
<li>CLI/tasks: reject partially numeric <code>openclaw tasks audit --limit</code> values so audit limits must be real positive integers instead of accepting strings like <code>5abc</code>. (#84901) Thanks @jbetala7.</li>
<li>Status/diagnostics: bound deep Docker audit probes so <code>openclaw status --deep</code> reports slow container checks instead of hanging behind unbounded inspection. (#85476) Thanks @giodl73-repo.</li>
<li>Providers/Anthropic: migrate 1M context handling to GA-capable Claude 4.x models by sizing eligible models at 1M without the retired <code>context-1m-2025-08-07</code> beta, ignoring that retired beta in older configs, and preserving OAuth-required Anthropic beta headers. (#45613) Thanks @haoyu-haoyu.</li>
<li>Cron/Telegram: parse forum-topic delivery targets through the Telegram plugin instead of cron core, including <code>:topic:</code> and <code>:topicId</code> forms for announce delivery. Thanks @etticat.</li>
<li>Twitch: keep stale message-handler cleanup callbacks from removing newer handler registrations for the same account, preserving inbound message delivery after reconnects. Fixes #83888. (#85425) Thanks @alkor2000.</li>
<li>Memory/LanceDB: expose public memory artifacts through the active memory provider bridge so memory-wiki imports durable memory files, daily notes, dream reports, and event logs without depending on memory-core internals. Fixes #83604. (#85060) Thanks @brokemac79.</li>
<li>Crabbox: keep AWS hydration compatible with local Actions replay by inlining the hydrate workflow's Node/pnpm setup instead of invoking repo-local composite actions.</li>
<li>Agents/subagents: simplify native sub-agent completion handoff so children report their latest visible assistant result to the requester without using <code>message</code>, while keeping parent-owned message-tool delivery policy intact. Fixes #85070. (#85089) Thanks @brokemac79.</li>
<li>Docker setup: stop printing the Gateway bearer token in setup logs and printed follow-up commands.</li>
<li>Agents: let embedded compaction fallback retries proceed when PI-compatible candidates do not need agent harness plugin preparation.</li>
<li>Agents/tools: honor configured custom provider API keys when deciding whether media, image-generation, video-generation, music-generation, and PDF tools are available. (#85570)</li>
<li>StepFun: stop advertising stale generic API key auth choices so onboarding only offers runtime-backed Standard and Step Plan choices.</li>
<li>Diagnostics: keep OpenTelemetry log bodies behind explicit content capture and scrub scoped agent-session keys from OpenTelemetry and Prometheus labels while preserving bounded queue-lane prefixes.</li>
<li>Windows installer: fail Git checkout installs when <code>pnpm install</code> or <code>pnpm build</code> fails instead of writing a wrapper to a missing CLI build.</li>
<li>Sessions: surface previous-transcript archive failures during <code>/new</code> rotation so disk rename errors are logged instead of silently hiding stranded transcript files. Fixes #81984. (#85586, from #82081) Thanks @0xghost42.</li>
<li>TUI/agents: mirror internal-ui message-tool replies into final chat output so message-tool-only agents remain visible in <code>openclaw tui</code>. Fixes #85538. Thanks @danpolasek.</li>
<li>Agents: keep parallel OpenAI-compatible tool-call deltas in separate argument buffers so interleaved tool calls no longer corrupt streamed arguments. (#82263) Thanks @luna-system.</li>
<li>Memory/doctor: report missing or unusable QMD workspace directories as workspace failures instead of generic binary failures. (#63167) Thanks @sercada.</li>
<li>Debug proxy: record CONNECT client-socket errors and destroy the paired upstream socket so abrupt client disconnects no longer leak tunnel resources. (#82444) Thanks @SebTardif.</li>
<li>Diffs: continue hydrating later diff cards when one card fails so a single broken card no longer blanks the whole diff viewer. (#84775) Thanks @cosmopolitan033.</li>
<li>Mac app: use the native settings sidebar window chrome so the sidebar toggle stays on the left and content no longer clips under oversized titlebar padding.</li>
<li>QA-Lab/Codex: bundle auth/plugin fixture imports for flow scenarios and let terminal async media tools end Codex app-server turns without timing out. (#80397, refs #80323) Thanks @100yenadmin.</li>
<li>Gateway/agents: preserve fresh session overrides and metadata when stale cached agent-session entries race with store updates, so subagent model/provider overrides and routing policy survive concurrent writes. (#19328) Thanks @CodeReclaimers.</li>
<li>Control UI/chat: keep chat session search inline with the session selector so the header no longer shows a duplicate standalone search row.</li>
<li>Control UI/chat: collapse focused-mode header chrome and suppress hidden-header scroll updates so focus mode no longer jumps while scrolling. Thanks @amknight.</li>
<li>Codex app-server: restart the native app-server and retry once when server-side compaction times out, so preflight compaction stalls recover instead of failing every dispatch. (#85500)</li>
<li>Restore Control UI gateway token pairing [AI]. (#85459) Thanks @pgondhi987.</li>
<li>OpenAI video: honor configured provider request private-network opt-in for local/custom video endpoints so explicitly trusted mock and self-hosted providers are not blocked. Thanks @shakkernerd.</li>
<li>OpenAI video: send uploaded video edit requests to the documented <code>/videos/edits</code> endpoint with a <code>video</code> file instead of posting MP4 references to <code>/videos</code>. Thanks @shakkernerd.</li>
<li>Agents/channels: preserve message-tool delivery evidence through gateway agent completion handoffs so successful generated media sends are not followed by false failure messages. Thanks @shakkernerd.</li>
<li>CLI/update: repair managed npm plugin <code>openclaw</code> peer links during post-core convergence and reject stale or wrong-target peer links before restart. (#83794) Thanks @fuller-stack-dev.</li>
<li>CLI/agents: default new omitted-account bindings to all accounts when the channel has multiple configured accounts, and clarify account-scope docs. (#49769) Thanks @Gcaufy.</li>
<li>Codex app-server: let authorized <code>/codex</code> control commands such as <code>/codex detach</code> escape plugin-owned conversation bindings while keeping unknown or unauthorized slash text routed to the bound plugin. Fixes #85157. (#85188) Thanks @TurboTheTurtle.</li>
<li>Auto-reply/models: keep <code>/models</code> browse replies fast by sharing the bounded read-only catalog path with Gateway model listing. (#84735) Thanks @safrano9999.</li>
<li>Codex app-server: disable native Code Mode when the effective exec host is <code>node</code> and keep OpenClaw <code>exec</code>/<code>process</code> available, so <code>/exec host=node</code> routes shell commands through the selected node instead of the gateway. Fixes #85012. (#85090) Thanks @sahilsatralkar.</li>
<li>Agents: bound embedded auto-compaction session write-lock watchdogs to the compaction timeout instead of the full run timeout, so stuck compaction cannot hold the live session lock for the whole run window. (#84949) Thanks @luoyanglang.</li>
<li>Gateway/agents: return phase-aware <code>agent.wait</code> timeout attribution and only cool auth profiles on provider-started timeouts. Refs #65504. Thanks @100yenadmin.</li>
<li>Gateway: defer provider auth-state prewarm until after startup readiness so early gateway tool/session requests are not blocked by provider auth discovery. (#85272) Thanks @dutifulbob.</li>
<li>Gateway/models: coalesce provider auth-state rewarms after auth-profile failures and log event-loop delay for warm/rewarm work, so provider auth bursts no longer stack full auth sweeps behind channel replies.</li>
<li>Gateway/models: stop cancelled provider auth-state prewarms from continuing full provider sweeps, so reload and auth-failure bursts no longer keep startup busy.</li>
<li>Agents/Codex: show the first plan update as a transient chat status notice without counting it as final assistant content.</li>
<li>CLI/update: walk the macOS process ancestry and honor the inherited Gateway runtime PID before package updates stop the managed Gateway service, so nested in-band updater children can refuse instead of killing the LaunchAgent-supervised Gateway that owns them. Fixes #85120.</li>
<li>Gateway/LaunchAgent: wait for launchd reload bootout to finish and fall back to kickstart when bootstrap races, so reload handoff does not leave the service deregistered. Fixes #84630. (#84641) Thanks @NianJiuZst.</li>
<li>Gateway/LaunchAgent: treat a concurrent launchd bootstrap as a successful restart when the service is already loaded, avoiding false macOS Gateway restart failures. Fixes #84721. (#84722) Thanks @googlerest.</li>
<li>Gateway/service: include the active <code>openclaw</code> command bin directory in managed service PATH generation and doctor audit expectations for npm-global macOS installs. Fixes #84201. (#84475) Thanks @jbetala7.</li>
<li>Control UI/chat: disable the thinking selector for known non-reasoning models instead of showing duplicate Off choices. Fixes #84069. Thanks @DrippingMellow.</li>
<li>Memory: expand <code>~</code> in configured extra memory paths before resolving them, so home-relative folders are not treated as workspace-relative. Fixes #58026. Thanks @stadman.</li>
<li>Skills: treat <code>openclaw.os: macos</code> as Darwin when checking skill requirements, so macOS-only skills no longer report as missing on macOS hosts. Fixes #61338. Thanks @Jessecq1995.</li>
<li>Control UI/logs: strip ANSI escape sequences from displayed Gateway log messages so color codes no longer appear as raw text. Fixes #64399. Thanks @guguangxin-eng.</li>
<li>Docker: pre-create the workspace and auth-profile config mount points with <code>node</code> ownership so first-run named volumes do not start root-owned. Fixes #85076. Thanks @Noerr.</li>
<li>Telegram: pass configured markdown table mode through outbound markdown chunking so chunked sends render tables consistently. Fixes #85085. Thanks @ShuaiHui.</li>
<li>CLI/update: preserve managed Gateway service environment during package cutovers so macOS LaunchAgent repair/restart reads the pre-update service state instead of caller shell state. (#83026)</li>
<li>Agents/providers: honor per-model <code>api</code> and <code>baseUrl</code> overrides in custom provider auth hooks and transport selection. Fixes #80487. (#80488) Thanks @huveewomg.</li>
<li>Gateway/restart: eager-load the lifecycle runtime before in-place upgrade signal handling so package replacement does not deadlock restart imports. (#84890) Thanks @myps6415.</li>
<li>CLI/update: start managed Gateway update handoff helpers from a stable existing directory and tolerate deleted cwd/package roots during macOS LaunchAgent handoff. Fixes #83808. (#83875) Thanks @jason-allen-oneal.</li>
<li>Skills: watch each shared skill directory once across agent workspaces instead of once per agent, preventing file-descriptor exhaustion (<code>EMFILE</code>) that disposed bundle-mcp processes and stalled sessions on multi-agent gateways. Fixes #84968. (#85130) Thanks @openperf.</li>
<li>Release/security: keep generated npm shrinkwrap package versions inside the pnpm lock graph so published package locks cannot bypass pnpm dependency age and override policy.</li>
<li>Cron: honor <code>cron.retry.retryOn: ["network"]</code> for common network error codes such as <code>EAI_AGAIN</code>, <code>EHOSTUNREACH</code>, and <code>ENETUNREACH</code>.</li>
<li>Gateway chat: broadcast returned agent-run error payloads after an agent starts so ACP/WebChat clients receive terminal idle-timeout errors. Fixes #84945.</li>
<li>Gateway chat display: preserve OpenAI-compatible <code>prompt_tokens</code>, <code>completion_tokens</code>, and <code>total_tokens</code> usage fields in sanitized chat history so llama.cpp sessions keep context counts. Fixes #77992. Thanks @MarTT79.</li>
<li>Dashboard/CLI: allow macOS browser launching through <code>open</code> even when SSH environment variables are present, while preserving Linux SSH no-display protection. Fixes #67088. Thanks @theglove44.</li>
<li>Codex app-server: keep native web search observations out of mirrored chat transcripts while preserving tool progress telemetry. Fixes #85109. Thanks @ugitmebaby.</li>
<li>OpenCode Go: strip unsupported Kimi reasoning replay fields before provider requests so repeated <code>kimi-k2.6</code> turns do not fail schema validation. Fixes #83812. Thanks @Sleeck.</li>
<li>Browser/CDP: add a WSL2 portproxy self-loop hint when Chrome DevTools endpoints accept connections but return an empty HTTP reply. Fixes #59209. Thanks @Owlock.</li>
<li>Agents/OpenAI: preserve structured provider error code, type, and redacted body metadata on boundary-aware transport failures.</li>
<li>Doctor/Codex: point native Codex asset warnings at the canonical <code>openclaw migrate plan codex</code> preview command. Fixes #84948. Thanks @markoa.</li>
<li>CLI/models: make <code>capability model auth logout --agent</code> remove auth profiles from the selected non-default agent store. Fixes #85092. Thanks @islandpreneur007.</li>
<li>Gateway/models: reuse prepared provider auth metadata during model-listing auth checks so repeated lookups avoid broad plugin discovery while preserving synthetic local auth.</li>
<li>CLI/status: suppress systemd user-service setup hints when <code>openclaw status --deep</code> can already reach a running Gateway RPC service. Fixes #85094. Thanks @islandpreneur007.</li>
<li>CLI/devices: recover local approval when a same-device repair request replaces the request ID being approved.</li>
<li>CLI/agents: retry transient normal-close Gateway handshakes before falling back to embedded <code>openclaw agent</code> execution.</li>
<li>CLI/update: keep managed Gateway service stop/restart status lines out of <code>openclaw update --json</code> stdout so package-update automation can parse the JSON payload.</li>
<li>Plugins: resolve OpenClaw plugin SDK subpaths for native external plugin runtimes without mutating package installs or broadening process-wide module resolution.</li>
<li>Agents/OpenAI: preserve Responses and Chat Completions <code>reasoning_tokens</code> usage metadata without double-counting it in aggregate output tokens. (#85319)</li>
<li>Control UI/chat: convert pasted <code>data:image/...;base64,...</code> clipboard text into an image attachment instead of dumping the payload into the composer. Fixes #62604. Thanks @cpwilhelmi.</li>
<li>Providers/Gemini: strip fractional seconds from web-search time range filters so Gemini accepts freshness-bound search requests. (#85071) Thanks @Noerr.</li>
<li>OpenAI Codex: preserve image input support for sparse <code>openai-codex/gpt-5.5</code> catalog rows. (#85095) Thanks @sercada.</li>
<li>CLI/models: add a piped or pasted API-key path for OpenAI Codex auth and warn when API keys are pasted into token-mode auth. (#85533) Thanks @joshavant.</li>
<li>Telegram: dead-letter missing-harness isolated ingress failures so a poisoned spooled update no longer blocks later same-lane messages. Fixes #85470. (#85605) Thanks @joshavant.</li>
<li>Plugins/discovery: strip <code>-plugin</code> package suffixes when deriving plugin id hints so package names line up with manifest ids. (#85170) Thanks @JulyanXu.</li>
<li>Tlon: stop advertising a non-existent agent tool contract in the plugin manifest.</li>
<li>Telegram: preserve fenced code block languages through Markdown rendering so Telegram receives <code>language-*</code> code classes. (#85209) Thanks @leno23.</li>
<li>Windows installer: run npm and Corepack command shims from a Windows-local directory so installs launched from WSL2 UNC paths do not fail before OpenClaw is installed.</li>
<li>Windows updates: roll back git-backed updates to the previous checkout when dependency install, build, UI build, or doctor repair fails.</li>
<li>Windows installer: persist user-local portable Git on PATH and activate the repo-pinned pnpm version for git-backed installs and updates.</li>
<li>Windows installer: bootstrap a user-local portable Node.js when native Windows has no Node and no winget, Chocolatey, or Scoop, so first-run installs can continue on raw hosts.</li>
<li>Windows installer: extract the downloaded portable Node.js directory with native <code>tar</code> before falling back to .NET zip extraction, avoiding PowerShell 5.1 archive and path-length failures.</li>
<li>fix(integrations): enforce channel read target allowlists [AI]. (#84982) Thanks @pgondhi987.</li>
<li>Agents/heartbeat: route single-owner <code>session.dmScope=main</code> direct-message exec and cron event wakes back to the agent main session so async completions no longer strand context in orphan direct-DM queues. Fixes #71581. (#83743) Thanks @Kaspre.</li>
<li>Agents/code-mode: expose outer code-mode <code>exec</code> source through the <code>command</code> hook alias with <code>toolKind</code>/<code>toolInputKind</code> discriminators so exec-shaped policies can distinguish code-mode cells. (#83483) Thanks @Kaspre.</li>
<li>Agents/code mode: return structured timeout and runtime-unavailable error codes for known worker failures. Fixes #83389. (#83444) Thanks @Kaspre.</li>
<li>QA-Lab: isolate multi-scenario suite workers when scenarios need startup config patches, preventing message-routing config from leaking into unrelated scenarios.</li>
<li>QA-Lab: make the commitments heartbeat-target-none scenario request an immediate heartbeat instead of waiting for the next scheduled heartbeat.</li>
<li>Codex/Plugin SDK: deliver Codex-native subagent completions through a generic harness task runtime so harness-backed plugins can mirror durable task lifecycle and completion delivery without Codex-specific SDK imports. (#83445) Thanks @bryanpearson.</li>
<li>Gateway CLI: surface local post-challenge connect assembly failures immediately instead of waiting for the wrapper timeout. Fixes #68944. (#85253) Thanks @samzong.</li>
<li>Messages: strip unsupported web-search citation control markers from outbound replies before they reach WebChat or external channels. Fixes #85193. (#85204) Thanks @neeravmakwana.</li>
<li>Agents/exec: treat denied exec approvals as terminal instead of feeding them back into agent follow-up work, and recognize Chinese stop phrases in abort handling. Fixes #69386. (#85194) Thanks @samzong.</li>
<li>CLI/agents: abort accepted Gateway-backed <code>openclaw agent</code> runs on SIGINT/SIGTERM so cron and supervisor timeouts do not leave remote agent work alive. Fixes #71710. (#84381) Thanks @Kaspre.</li>
<li>Codex app-server: retry replay-safe stdio client-close turns once using structured failure metadata, while surfacing idle <code>turn/completed</code> timeouts instead of blindly replaying active shared-server turns. Thanks @VACInc.</li>
<li>Codex app-server: reject command overrides that embed Node or package-manager arguments and point users to <code>appServer.args</code>, so Windows startup avoids shell parsing failures. (#84417) Thanks @TurboTheTurtle.</li>
<li>Agents/Copilot: drop unsafe GitHub Copilot Responses reasoning replay items before send so Telegram direct sessions no longer fail on overlong replay IDs. Fixes #85197. (#85198) Thanks @galiniliev.</li>
<li>UI: add accessible tooltips to the topbar color-mode buttons so System, Light, and Dark choices are labeled on hover and focus. (#85227) Thanks @amknight.</li>
<li>fix: constrain Windows task script names [AI]. (#85064) Thanks @pgondhi987.</li>
<li>Control UI: keep the chat session picker from hiding older or cross-agent configured conversations while preserving the bounded configured-agent refresh. (#85211) Thanks @amknight.</li>
<li>Agents/Anthropic: preserve unsafe integer tool-call input values in streamed Anthropic tool-use JSON, preventing Discord-style IDs from being rounded before dispatch. Fixes #47229. (#83063) Thanks @leno23.</li>
<li>Agents/Codex: estimate tool-heavy prompt pressure at the LLM boundary before provider submission, so persistent sessions compact before overflowing context windows. (#85541) Thanks @fuller-stack-dev and @joshavant.</li>
<li>Agents/hooks: wait for local one-shot CLI and Codex <code>agent_end</code> plugin hooks before process cleanup so terminal observability flushes reliably. (#85007)</li>
<li>Providers/Google: preserve Gemini 3 cron <code>thinkingDefault: "low"</code> when stale catalog metadata says <code>reasoning:false</code>, so scheduled runs keep provider-supported thinking instead of downgrading to off. (#85185) Thanks @neeravmakwana.</li>
<li>CLI/agents: allow <code>openclaw agent --session-key</code> to target explicit session keys, including agent-scoped legacy keys. (#85121) Thanks @Kaspre.</li>
<li>Auto-reply/ACP: wait for same-channel block reply delivery before starting tool work, while still honoring ACP dispatch aborts so stopped turns do not wait on slow channel sends. (#83722) Thanks @IWhatsskill.</li>
<li>Codex/ACP: mark required child-run completions that only report progress, omit a final deliverable, or fail requester delivery as blocked while preserving real final reports. (#85110) Thanks @IWhatsskill.</li>
<li>Channels: treat bare abort messages such as <code>stop</code>, <code>abort</code>, and <code>wait</code> as immediate control commands in inbound debounce paths so stop requests are not delayed behind pending message coalescing. (#83348) Thanks @IWhatsskill.</li>
<li>Channels/message tool: resolve configured external channel plugins during in-agent channel selection, so <code>openclaw agent --local</code> message-tool sends no longer report an available channel as unavailable. (#85022) Thanks @Kaspre.</li>
<li>Agents/heartbeat: honor group/channel <code>message_tool</code> visible-reply policy and model-specific Codex runtime config for scheduled heartbeat runs, so failed internal tool output stays private. Fixes #85310. (#85357) Thanks @neeravmakwana.</li>
<li>Gateway/ACP: close child ACP sessions spawned via <code>sessions_spawn</code> when their parent session is reset or deleted, instead of leaving orphaned <code>claude-agent-acp</code> processes that accumulate and exhaust memory. Fixes #68916. (#85190) Thanks @openperf.</li>
<li>Codex app-server: block native execution paths when OpenClaw exec resolves to a node host while preserving the first-party CLI node binding path. Fixes #85012. (#85534) Thanks @joshavant.</li>
<li>Diagnostics: bound cleanup timeout detail logs, emit drop summaries when async diagnostic bursts exceed the queue cap, and surface async queue drops through diagnostic telemetry.</li>
<li>Agents/subagents: surface blocked child-run completions as errors instead of successful subagent finishes. (#80886) Thanks @TurboTheTurtle.</li>
<li>Context engines: fail closed with a descriptive error when the selected agent runtime cannot satisfy declared context-engine host requirements.</li>
<li>Agents/Pi: treat accepted embedded <code>sessions_spawn</code> child-session handoffs as terminal progress so parent turns no longer report false non-deliverable failures. (#85054) Thanks @samzong.</li>
<li>CLI/models: resolve <code>openclaw models set</code> aliases from the runtime config while keeping authored aliases ahead of runtime-only defaults. (#83262) Thanks @IWhatsskill.</li>
<li>Doctor: show personal Codex CLI asset notices as info instead of warnings. Fixes #84859.</li>
<li>WhatsApp: update Baileys to <code>7.0.0-rc13</code> and drop the obsolete logger type patch.</li>
<li>CLI/update: pre-pack GitHub/git package update targets before the staged npm install, restoring <code>openclaw update --tag main</code> for one-off package updates. (#81296) Thanks @fuller-stack-dev.</li>
<li>Gateway: mirror successful same-source message-tool sends into session transcripts so delivered replies stay in later history/context. (#84837) Thanks @iFiras-Max1.</li>
<li>Media generation: keep image, music, and video completion delivery from duplicating or losing task ownership when generated media finishes through active session replies. (#84006) Thanks @fuller-stack-dev.</li>
<li>Infra/json: retry transient <code>File changed during read</code> races while loading JSON state so config and state reads recover instead of failing the turn. (#84285)</li>
<li>Plugins/providers: fail closed for workspace provider plugins during setup-mode discovery unless explicitly trusted, preventing untrusted workspace plugin code from running during provider setup. (#81069) Thanks @mmaps.</li>
<li>Providers/Ollama: resolve configured Ollama Cloud <code>OLLAMA_API_KEY</code> markers to the real discovery key so cloud provider entries keep authenticated model catalog access. (#85037)</li>
<li>Discord: keep persistent component registry fallback warnings actionable by forwarding structured error and cause metadata through the runtime logger. Fixes #84185. (#84190) Thanks @100menotu001.</li>
<li>Gateway/sessions: preserve compatible session auth profile overrides when switching models within the same provider, including provider-auth aliases. Fixes #81837. (#81886) Thanks @TurboTheTurtle.</li>
<li>Gateway/status: surface inbound delivery telemetry counters and transport-liveness warnings in <code>openclaw status --all</code>. Fixes #49577. (#72724)</li>
<li>Docker: prune package-excluded plugin source workspaces and dependency closures so runtime images do not keep packages for plugins that were not opted in.</li>
<li>Providers/Ollama: treat Docker/OrbStack host aliases as local Ollama endpoints so <code>ollama-local</code> marker auth works when OpenClaw runs inside a VM/container and Ollama runs on the host. Fixes #84875.</li>
<li>QA-Lab: keep explicitly searchable/deferred OpenClaw dynamic tool rows report-only by default so tool-coverage gates do not treat mock discovery gaps as hard product failures. (#80319) Thanks @100yenadmin.</li>
<li>Agents/config: keep non-Google provider model refs from being rewritten by Google Gemini preview-id normalization. (#84762) Thanks @zhangguiping-xydt.</li>
<li>Installer: require a real controlling terminal before launching onboarding so headless <code>curl | bash</code> installs finish cleanly after installing the CLI.</li>
<li>Agents/Codex: promote a completed final assistant response when a prompt timeout races Codex app-server completion instead of returning an empty timeout envelope. Refs #84516.</li>
<li>Codex app-server: keep interrupted turn statuses from being treated as OpenClaw aborts by themselves, so tool-only turns remain eligible for no-visible-answer recovery. Fixes #84492.</li>
<li>Agents: cap heartbeat model bleed context hints by the stored session window when runtime model metadata is unavailable, so overflow recovery advice does not suggest a larger window than the active session actually has.</li>
<li>Control UI/Web Push: use <code>https://openclaw.ai</code> as the generated default VAPID subject instead of the old localhost mailbox so iOS PWA push setup uses an Apple-acceptable subject when <code>OPENCLAW_VAPID_SUBJECT</code> is unset. Fixes #83134. (#83317) Thanks @IWhatsskill.</li>
<li>Control UI: distinguish inherited thinking-off settings from explicit Off selections so the thinking selector no longer shows two identical Off rows. (#85223) Thanks @amknight.</li>
<li>Agents/Pi: keep embedded session transcript writes from tripping false takeover detection after packaged npm onboarding agent turns.</li>
<li>Codex/TUI: surface Codex-native post-turn compaction failures instead of continuing uncompacted, and keep successful native compaction serialized before local idle/next-turn handling. Fixes #84305. (#85160) Thanks @joshavant.</li>
<li>Memory/search: stop recall tracking from writing dreaming side-effect artifacts when <code>dreaming.enabled=false</code>, while preserving normal search results. Fixes #84436. (#84444) Thanks @NianJiuZst.</li>
<li>Diffs: render viewer toolbar icons from a closed icon-name map instead of HTML strings, removing the toolbar icon XSS sink. (#83955) Thanks @tanshanshan.</li>
<li>QA: keep <code>pnpm qa:e2e</code> self-check runs inside the private QA runtime envelope even when inherited shell env disables bundled plugins.</li>
<li>fix(config): validate browser sandbox bind sources [AI]. (#84799) Thanks @pgondhi987.</li>
<li>doctor: constrain legacy plugin cleanup paths [AI]. (#84801) Thanks @pgondhi987.</li>
<li>Update/doctor: prune stale local bundled plugin install records that point at old compiled bundled output so current bundled plugin schemas win after upgrade. (#84863) Thanks @fuller-stack-dev.</li>
<li>Providers/Ollama: preserve native Ollama tool-call IDs across assistant replay so Gemini over Ollama Cloud can keep its hidden function-call thought-signature handle.</li>
<li>Discord: keep session recovery and <code>/stop</code> abort ownership on the source dispatch lane while bound ACP turns continue routing to their target session, so stalled pre-run work and late replies are cleared instead of leaking after stop. Fixes #84477. (#85100) Thanks @joshavant.</li>
<li>Codex app-server: mark missing turn completion after observed execution as replay-unsafe and release the session so follow-up turns can run. Fixes #84076. (#85107) Thanks @joshavant.</li>
<li>Codex app-server: give visible <code>message</code> dynamic tool sends a longer timeout budget so slow channel delivery can return its own result or error instead of hitting the 30-second Codex wrapper. (#85216) Thanks @amknight.</li>
<li>Codex app-server: add a dedicated post-tool raw assistant completion idle timeout config so trusted heavy turns can wait longer after tool handoff without weakening final assistant release.</li>
<li>Matrix: keep explicitly configured two-person rooms on the room route before stale <code>m.direct</code> or strict two-member DM fallback can bypass mention gating. Fixes #85017. (#85137) Thanks @joshavant.</li>
<li>Agents/subagents: require explicit subagent allowlist targets to be configured agents so stale deleted-agent ids are omitted from <code>agents_list</code> and rejected by <code>sessions_spawn</code>. Fixes #84811. (#85154) Thanks @joshavant.</li>
<li>PDF tool: time out idle remote PDF body reads after 120 seconds so stalled remote documents return an error instead of wedging the session. Fixes #68649. (#84768) Thanks @luoyanglang.</li>
<li>Diagnostics/OpenTelemetry plugin: suppress handled OTLP exporter promise rejections so collector shutdowns no longer crash the Gateway. (#81085) Thanks @luoyanglang.</li>
<li>Agents/exec: omit raw command text and env values from denied exec failure logs while keeping safe correlation metadata. Fixes #85049. (#85140) Thanks @joshavant.</li>
<li>Media/audio: skip empty structured sherpa-onnx transcripts instead of treating the raw JSON payload as spoken text. (#84667) Thanks @TurboTheTurtle.</li>
<li>Agents/exec: preserve inherited XDG base-directory environment values for subprocesses while still rejecting agent-supplied XDG overrides. Fixes #84854. (#85139) Thanks @joshavant.</li>
<li>Node/Linux: keep <code>OPENCLAW_GATEWAY_TOKEN</code> out of generated systemd unit files by writing node service token values to a node-specific env file. (#84408)</li>
<li>Memory-core/dreaming: reuse stable narrative subagent session keys per workspace and phase while keeping per-run idempotency and bounded cleanup, so stale <code>dreaming-narrative-*</code> sessions do not accumulate. Fixes #68252, #69187, and #70402. (#70464) Thanks @chiyouYCH.</li>
<li>Trajectory/support: tolerate partial skill snapshot entries when building support metadata so rejected skill path scans no longer abort trajectory capture. (#71185) Thanks @lukeboyett.</li>
<li>TUI: coalesce repeated idle Esc abort notices into a single <code>no active run xN</code> system row instead of appending duplicate rows.</li>
<li>Telegram: honor <code>channels.telegram.pollingStallThresholdMs</code> in the default isolated polling path, restarting silent workers instead of leaving inbound updates wedged. Fixes #83950. (#84861) Thanks @joshavant.</li>
<li>Telegram: dedupe replayed message dispatches by Telegram chat/message identity so isolated-ingress replays do not trigger duplicate model dispatches. Fixes #84886. (#85208) Thanks @joshavant.</li>
<li>Slack: suppress reasoning payloads before reply delivery and dispatch accounting, so Slack monitor, slash-command, fallback, and direct reply paths do not leak model reasoning. Fixes #84319. (#84322) Thanks @ffluk3 and @joshavant.</li>
<li>Slack: deliver native plugin approval prompts and updates when Slack native approvals are enabled, while keeping plugin approval authorization separate from exec approvers.</li>
<li>Slack: keep native plugin approval prompts in the originating app conversation thread when the live Slack turn source is a <code>D...</code> conversation.</li>
<li>Agents/Pi: disable the embedded pi-coding-agent runtime auto-retry so OpenClaw's own retry and failover loop does not replay failed tool calls through a nested SDK retry. Fixes #73781. (#74434) Thanks @yelog.</li>
<li>CLI/perf: keep <code>setup --help</code>, <code>onboard --help</code>, and <code>configure --help</code> out of the full wizard runtime while preserving the existing help output. (#84488) Thanks @frankekn.</li>
<li>CLI/perf: keep <code>agents --help</code> out of agents action/runtime imports so help, completion, and command discovery paths avoid loading the full agents runtime. (#84483) Thanks @frankekn.</li>
<li>CLI/perf: keep <code>secrets --help</code> and <code>nodes --help</code> on the precomputed help path so parent help avoids loading action-heavy command runtime modules. (#84818) Thanks @frankekn.</li>
<li>CLI/perf: serve <code>doctor</code>, <code>gateway</code>, <code>models</code>, and <code>plugins</code> parent help from startup metadata so common subcommand help avoids full CLI program construction. (#84786) Thanks @frankekn.</li>
<li>Codex/Lossless: keep context-engine history on the canonical run session when Telegram DMs use per-peer runtime policy keys. Fixes #84936. (#84954) Thanks @neeravmakwana.</li>
<li>Codex: keep heartbeat response tool schemas durable without exposing dynamic tools disabled by turn policy, so heartbeat wakeups can reuse threads while scoped tool allowlists stay enforced. (#84681) Thanks @jalehman.</li>
<li>Auth/OAuth: skip the refresh adapter when a stored OAuth credential has no refresh token so agent turns fail fast on missing-key instead of waiting on the 120s refresh timeout. Thanks @romneyda.</li>
<li>Auth/Codex: load legacy OAuth sidecar credentials in the embedded runner's secrets-runtime auth loaders so Telegram replies, cron-triggered turns, and other isolated sub-agent lanes can reach the existing #83312 refresh-and-rewrite migration instead of failing with <code>No API key found for provider "openai-codex"</code> until the user runs <code>openclaw doctor</code>. Thanks @Totalsolutionsync and @romneyda.</li>
<li>Codex/failover: classify <code>deactivated_workspace</code> as a permanent auth failure so configured fallback models can advance when a Codex workspace is deactivated. (#55893) Thanks @litang9.</li>
<li>Exec: keep configured <code>tools.exec.pathPrepend</code> entries ahead of user shell startup PATH changes on POSIX gateway runs. (#81403) Thanks @medns.</li>
<li>Gateway/sessions: allow shared-secret bearer callers to read and stream session history without an explicit scope header. (#81815) Thanks @medns.</li>
<li>Agents/embedded runner: classify HTML auth provider responses as <code>auth_html</code> and return a re-authentication hint instead of the CDN-blocked copy that <code>upstream_html</code> returns. Cloudflare Access login pages, nginx basic-auth challenges, and gateway login walls all produce HTML auth bodies that were previously misdiagnosed as transient CDN blocks. (#79900) Thanks @martingarramon.</li>
<li>TUI/streaming watchdog: dismiss the <code>This response is taking longer than expected</code> notice as soon as a chat event for the same run arrives, so the message no longer sits next to the recovered response when the run was only briefly silent. Refs #67052, #69081 (closed), prior attempt #69026. Thanks @jpruit20 and @romneyda.</li>
<li>Agents/Pi: tolerate OpenClaw-owned transcript writes while embedded prompts are released for model I/O, keeping long-running Feishu, Slack, Telegram, and cron turns from failing with false session-takeover errors. Fixes #84059. (#84250) Thanks @tianxiaochannel-oss88.</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.22/OpenClaw-2026.5.22.zip" length="54409357" type="application/octet-stream" sparkle:edSignature="am1mwLOmUHor9QuQWtxSsKoBOCySUBo4fB+0Qdcrz0E3wf6ESIMTfOC0k+dKJSh9gtLZw5jzpWVqTBzEdU36Aw=="/>
</item>
</channel>
</rss>

View File

@@ -65,8 +65,8 @@ android {
applicationId = "ai.openclaw.app"
minSdk = 31
targetSdk = 36
versionCode = 2026052801
versionName = "2026.5.28"
versionCode = 2026053001
versionName = "2026.5.30"
ndk {
// Support all major ABIs — native libs are tiny (~47 KB per ABI)
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")

View File

@@ -1,5 +1,13 @@
# OpenClaw iOS Changelog
## 2026.5.30 - 2026-05-30
Maintenance update for the current OpenClaw release.
- Added hosted push relay defaults, realtime Talk playback, and safer WebSocket ping handling for mobile sessions.
- Updated App Store screenshots to cover Gateway pairing, Command, Chat, Talk, Agent, and Settings flows.
- Highlighted realtime Talk relay, Gateway connection status, node capabilities, push wake, and privacy controls.
## 2026.5.28 - 2026-05-28
Maintenance update for the current OpenClaw release.

View File

@@ -2,8 +2,8 @@
// Source of truth: apps/ios/version.json
// Generated by scripts/ios-sync-versioning.ts.
OPENCLAW_IOS_VERSION = 2026.5.28
OPENCLAW_MARKETING_VERSION = 2026.5.28
OPENCLAW_IOS_VERSION = 2026.5.30
OPENCLAW_MARKETING_VERSION = 2026.5.30
OPENCLAW_BUILD_VERSION = 1
#include? "../build/Version.xcconfig"

View File

@@ -73,9 +73,10 @@ Release behavior:
- Changing the root gateway version does not change the iOS app version until you explicitly pin from the gateway.
- See `apps/ios/VERSIONING.md` for the full workflow.
Required env for beta builds:
Relay behavior for beta builds:
- `OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com`
- Beta builds default to `https://ios-push-relay.openclaw.ai`.
- Optional custom relay override: `OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com`
This must be a plain `https://host[:port][/path]` base URL without whitespace, query params, fragments, or xcconfig metacharacters.
Archive without upload:
@@ -118,7 +119,7 @@ scripts/ios-asc-keychain-setup.sh \
This should create `apps/ios/fastlane/.env` with the non-secret ASC variables while the private key stays in Keychain.
3. Set the official/TestFlight relay URL for the build:
3. Optional: set a custom official/TestFlight relay URL for the build. If unset, the beta flow uses `https://ios-push-relay.openclaw.ai`.
```bash
export OPENCLAW_PUSH_RELAY_BASE_URL=https://relay.example.com

View File

@@ -0,0 +1,652 @@
import SwiftUI
struct TalkProTab: View {
@Environment(NodeAppModel.self) private var appModel
@AppStorage("talk.enabled") private var talkEnabled: Bool = false
@AppStorage(TalkSpeechLocale.storageKey) private var talkSpeechLocale: String = TalkSpeechLocale.automaticID
@AppStorage(TalkDefaults.speakerphoneEnabledKey) private var talkSpeakerphoneEnabled: Bool =
TalkDefaults.speakerphoneEnabledByDefault
@AppStorage("talk.background.enabled") private var talkBackgroundEnabled: Bool = false
@State private var showPermissionPrompt = false
var openSettings: () -> Void
private var state: TalkProState {
TalkProState(
gatewayConnected: self.gatewayConnected,
isEnabled: self.appModel.talkMode.isEnabled || self.talkEnabled,
statusText: self.appModel.talkMode.statusText,
isListening: self.appModel.talkMode.isListening,
isSpeaking: self.appModel.talkMode.isSpeaking,
isUserSpeechDetected: self.appModel.talkMode.isUserSpeechDetected,
permissionState: self.appModel.talkMode.gatewayTalkPermissionState)
}
var body: some View {
NavigationStack {
ZStack {
CommandControlBackground()
ScrollView {
VStack(alignment: .leading, spacing: 10) {
self.header
self.voiceHeroCard
self.conversationCard
self.voiceModeCard
self.controlsCard
}
.padding(.top, 16)
.padding(.bottom, 18)
}
.safeAreaPadding(.bottom, OpenClawProMetric.bottomScrollInset)
}
.navigationBarHidden(true)
}
.sheet(isPresented: self.$showPermissionPrompt) {
NavigationStack {
TalkPermissionPromptView(
style: .sheet,
onPermissionReady: {
self.showPermissionPrompt = false
self.startTalk()
})
.padding()
.navigationTitle("Enable Talk")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Not Now") {
self.showPermissionPrompt = false
}
}
}
}
.presentationDetents([.medium, .large])
.openClawSheetChrome()
}
.onAppear { self.alignPersistedTalkState() }
}
private var header: some View {
HStack(alignment: .center, spacing: 11) {
OpenClawProMark(size: 31, shadowRadius: 9)
VStack(alignment: .leading, spacing: 2) {
Text("Talk")
.font(.system(size: 27, weight: .bold, design: .rounded))
Text(self.headerSubtitle)
.font(.caption.weight(.medium))
.foregroundStyle(.secondary)
.lineLimit(1)
}
Spacer(minLength: 8)
self.statusChip
}
.padding(.horizontal, OpenClawProMetric.pagePadding)
}
private var statusChip: some View {
HStack(spacing: 5) {
Circle()
.fill(self.state.color)
.frame(width: 7, height: 7)
Text(self.state.chipText)
.font(.caption.weight(.bold))
.foregroundStyle(self.state.color)
}
.padding(.horizontal, 10)
.padding(.vertical, 7)
.background {
Capsule(style: .continuous)
.fill(self.state.color.opacity(0.11))
.overlay {
Capsule(style: .continuous)
.strokeBorder(self.state.color.opacity(0.22), lineWidth: 1)
}
}
}
private var voiceHeroCard: some View {
CommandPanel(tint: self.state.color, isProminent: true, padding: 16) {
VStack(alignment: .center, spacing: 16) {
TalkProOrb(
mode: self.state.waveformMode(micLevel: self.appModel.talkMode.micLevel),
color: self.state.color,
systemImage: self.state.icon)
.frame(height: 188)
.accessibilityHidden(true)
VStack(spacing: 5) {
Text(self.state.title)
.font(.title3.weight(.bold))
.multilineTextAlignment(.center)
Text(self.heroSubtitle)
.font(.subheadline.weight(.medium))
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
}
Button(action: self.handlePrimaryAction) {
Label(self.state.primaryButtonTitle, systemImage: self.state.primaryButtonIcon)
.font(.subheadline.weight(.bold))
.foregroundStyle(.white)
.frame(maxWidth: .infinity)
.frame(height: 50)
.background {
RoundedRectangle(cornerRadius: 14, style: .continuous)
.fill(self.state.primaryButtonFill)
.shadow(color: self.state.color.opacity(0.28), radius: 18, y: 8)
}
}
.buttonStyle(.plain)
.disabled(self.state.primaryAction == .waiting)
}
}
.padding(.horizontal, OpenClawProMetric.pagePadding)
}
private var conversationCard: some View {
CommandPanel(padding: 0) {
VStack(spacing: 0) {
self.cardHeader(title: "Conversation", value: self.state.chipText, color: self.state.color)
.padding(.horizontal, 12)
.padding(.top, 11)
.padding(.bottom, 3)
self.infoRow(icon: "person.crop.circle.fill", title: "Agent", value: self.appModel.activeAgentName)
Divider().padding(.leading, 54)
self.infoRow(
icon: "bubble.left.and.text.bubble.right.fill",
title: "Session",
value: self.appModel.chatSessionKey)
Divider().padding(.leading, 54)
self.infoRow(icon: self.state.icon, title: "Runtime", value: self.appModel.talkMode.statusText)
}
}
.padding(.horizontal, OpenClawProMetric.pagePadding)
}
private var voiceModeCard: some View {
CommandPanel(padding: 0) {
VStack(spacing: 0) {
self.cardHeader(
title: "Voice mode",
value: "Settings ",
color: OpenClawBrand.accent,
action: self.openSettings)
.padding(.horizontal, 12)
.padding(.top, 11)
.padding(.bottom, 3)
self.infoRow(icon: "waveform", title: "Mode", value: self.appModel.talkMode.gatewayTalkVoiceModeTitle)
Divider().padding(.leading, 54)
self.infoRow(icon: "antenna.radiowaves.left.and.right", title: "Transport", value: self.transportText)
Divider().padding(.leading, 54)
self.infoRow(icon: "key.fill", title: "Permission", value: self.permissionText)
Divider().padding(.leading, 54)
self.infoRow(icon: "globe", title: "Speech language", value: self.speechLocaleText)
}
}
.padding(.horizontal, OpenClawProMetric.pagePadding)
}
private var controlsCard: some View {
CommandPanel(padding: 0) {
VStack(spacing: 0) {
self.cardHeader(title: "Controls", value: nil, color: .secondary)
.padding(.horizontal, 12)
.padding(.top, 11)
.padding(.bottom, 3)
Toggle("Speakerphone", isOn: self.$talkSpeakerphoneEnabled)
.padding(.horizontal, 14)
.padding(.vertical, 10)
Divider().padding(.leading, 14)
Toggle("Background listening", isOn: self.$talkBackgroundEnabled)
.padding(.horizontal, 14)
.padding(.vertical, 10)
Divider().padding(.leading, 14)
Button(action: self.openSettings) {
HStack {
Label("Voice & Talk settings", systemImage: "slider.horizontal.3")
Spacer()
Image(systemName: "chevron.right")
.font(.caption.weight(.bold))
.foregroundStyle(.secondary)
}
.font(.subheadline.weight(.semibold))
.padding(.horizontal, 14)
.padding(.vertical, 12)
}
.buttonStyle(.plain)
}
}
.padding(.horizontal, OpenClawProMetric.pagePadding)
}
private func cardHeader(
title: String,
value: String?,
color: Color,
action: (() -> Void)? = nil) -> some View
{
HStack(spacing: 8) {
Text(title)
.font(.subheadline.weight(.bold))
Spacer(minLength: 8)
if let value {
if let action {
Button(value, action: action)
.font(.caption.weight(.semibold))
.foregroundStyle(color)
} else {
Text(value)
.font(.caption.weight(.semibold))
.foregroundStyle(color)
}
}
}
}
private func infoRow(icon: String, title: String, value: String) -> some View {
HStack(spacing: 10) {
Image(systemName: icon)
.font(.caption.weight(.bold))
.foregroundStyle(self.state.color)
.frame(width: 30, height: 30)
.background {
RoundedRectangle(cornerRadius: 8, style: .continuous)
.fill(self.state.color.opacity(0.11))
}
VStack(alignment: .leading, spacing: 2) {
Text(title)
.font(.caption2.weight(.medium))
.foregroundStyle(.secondary)
Text(value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? "" : value)
.font(.subheadline.weight(.semibold))
.lineLimit(1)
.minimumScaleFactor(0.78)
}
Spacer(minLength: 0)
}
.padding(.horizontal, 12)
.padding(.vertical, 9)
}
private var gatewayConnected: Bool {
GatewayStatusBuilder.build(appModel: self.appModel) == .connected
}
private var headerSubtitle: String {
let mode = self.appModel.talkMode.gatewayTalkVoiceModeTitle.trimmingCharacters(in: .whitespacesAndNewlines)
let agent = self.appModel.activeAgentName.trimmingCharacters(in: .whitespacesAndNewlines)
if mode.isEmpty || mode == "Not loaded" { return agent.isEmpty ? "Realtime voice" : agent }
if agent.isEmpty { return mode }
return "\(agent)\(mode)"
}
private var heroSubtitle: String {
if self.state
.prefersPermissionCopy { return "Gateway approval is required before this phone can capture voice." }
if !self.gatewayConnected { return "Connect to your gateway to start a voice conversation." }
let subtitle = (self.appModel.talkMode.gatewayTalkVoiceModeSubtitle ?? "")
.trimmingCharacters(in: .whitespacesAndNewlines)
if !subtitle.isEmpty { return subtitle }
return "Routes voice to \(self.appModel.activeAgentName)."
}
private var transportText: String {
let provider = self.appModel.talkMode.gatewayTalkProviderLabel.trimmingCharacters(in: .whitespacesAndNewlines)
let transport = self.appModel.talkMode.gatewayTalkTransportLabel.trimmingCharacters(in: .whitespacesAndNewlines)
if provider.isEmpty || provider == "Not loaded" { return transport.isEmpty ? "Not loaded" : transport }
if transport.isEmpty || transport == "Not loaded" { return provider }
return "\(provider)\(transport)"
}
private var permissionText: String {
if let failure = self.appModel.talkMode.gatewayTalkPermissionState.failureMessage {
return failure
}
return self.appModel.talkMode.gatewayTalkPermissionState.statusLabel
}
private var speechLocaleText: String {
if self.talkSpeechLocale == TalkSpeechLocale.automaticID { return "Automatic" }
return self.talkSpeechLocale
}
private func alignPersistedTalkState() {
if self.appModel.talkMode.gatewayTalkPermissionState.requiresTalkPermissionAction,
self.talkEnabled || self.appModel.talkMode.isEnabled
{
self.stopTalk()
} else if self.talkEnabled != self.appModel.talkMode.isEnabled {
self.appModel.setTalkEnabled(self.talkEnabled)
}
}
private func handlePrimaryAction() {
switch self.state.primaryAction {
case .start:
self.startTalk()
case .stop:
self.stopTalk()
case .enablePermission:
self.stopTalk()
self.showPermissionPrompt = true
case .openSettings:
self.openSettings()
case .waiting:
break
}
}
private func startTalk() {
self.talkEnabled = true
self.appModel.setTalkEnabled(true)
}
private func stopTalk() {
self.talkEnabled = false
self.appModel.setTalkEnabled(false)
}
}
enum TalkProPrimaryAction: Equatable {
case start
case stop
case enablePermission
case openSettings
case waiting
}
enum TalkProWaveformMode: Equatable {
case level(Double)
case inputSpeech
case speaking
case indeterminate
case still
}
struct TalkProState: Equatable {
let gatewayConnected: Bool
let isEnabled: Bool
let statusText: String
let isListening: Bool
let isSpeaking: Bool
let isUserSpeechDetected: Bool
let permissionState: TalkGatewayPermissionState
private var normalizedStatus: String {
self.statusText.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
}
var title: String {
if !self.gatewayConnected { return "Gateway offline" }
switch self.permissionState {
case .missingScope, .requestFailed:
return "Gateway permission required"
case .requestingUpgrade:
return "Requesting approval"
case .upgradeRequested:
return "Approval requested"
case .apiKeyMissing:
return "Voice API key missing"
case .loadFailed:
return "Voice config failed"
default:
break
}
if self.isSpeaking { return "Speaking" }
if self.isListening { return "Listening" }
if self.normalizedStatus.contains("connecting") { return "Connecting" }
if self.normalizedStatus.contains("thinking") { return "Asking OpenClaw" }
if self.isEnabled { return "Ready to talk" }
return "Talk is off"
}
var chipText: String {
if !self.gatewayConnected { return "Offline" }
switch self.permissionState {
case .missingScope, .requestFailed:
return "Needs approval"
case .requestingUpgrade, .upgradeRequested:
return "Pending"
case .apiKeyMissing:
return "API key"
case .loadFailed:
return "Config"
default:
break
}
if self.isSpeaking { return "Speaking" }
if self.isListening { return "Listening" }
if self.isEnabled { return "Ready" }
return "Off"
}
var icon: String {
if !self.gatewayConnected { return "wifi.slash" }
switch self.permissionState {
case .missingScope, .requestFailed:
return "key.fill"
case .requestingUpgrade:
return "paperplane.fill"
case .upgradeRequested:
return "hourglass"
case .apiKeyMissing, .loadFailed:
return "exclamationmark.triangle.fill"
default:
break
}
if self.isSpeaking { return "speaker.wave.2.fill" }
if self.isListening { return "mic.fill" }
if self.normalizedStatus.contains("thinking") { return "sparkles" }
if self.normalizedStatus.contains("connecting") { return "dot.radiowaves.left.and.right" }
return "waveform"
}
var color: Color {
if !self.gatewayConnected { return .secondary }
switch self.permissionState {
case .requestFailed, .loadFailed:
return OpenClawBrand.danger
case .missingScope, .requestingUpgrade, .upgradeRequested, .apiKeyMissing:
return OpenClawBrand.warn
default:
return self.isEnabled ? OpenClawBrand.ok : OpenClawBrand.accentHot
}
}
var primaryAction: TalkProPrimaryAction {
if !self.gatewayConnected { return .openSettings }
switch self.permissionState {
case .missingScope, .requestFailed:
return .enablePermission
case .requestingUpgrade, .upgradeRequested:
return .waiting
case .apiKeyMissing, .loadFailed:
return .openSettings
default:
return self.isEnabled ? .stop : .start
}
}
var primaryButtonTitle: String {
switch self.primaryAction {
case .start: "Start Talk"
case .stop: "Stop Talk"
case .enablePermission: "Enable Talk"
case .openSettings: self.gatewayConnected ? "Open Voice Settings" : "Open Gateway Settings"
case .waiting: "Waiting for Approval"
}
}
var primaryButtonIcon: String {
switch self.primaryAction {
case .start: "play.fill"
case .stop: "stop.fill"
case .enablePermission: "key.fill"
case .openSettings: "gearshape.fill"
case .waiting: "hourglass"
}
}
var primaryButtonFill: AnyShapeStyle {
switch self.primaryAction {
case .stop:
AnyShapeStyle(OpenClawBrand.danger)
case .waiting:
AnyShapeStyle(OpenClawBrand.warn.opacity(0.72))
default:
AnyShapeStyle(LinearGradient(
colors: [self.color.opacity(0.95), OpenClawBrand.accent],
startPoint: .topLeading,
endPoint: .bottomTrailing))
}
}
var prefersPermissionCopy: Bool {
switch self.permissionState {
case .missingScope, .requestingUpgrade, .upgradeRequested, .requestFailed:
true
default:
false
}
}
func waveformMode(micLevel: Double) -> TalkProWaveformMode {
if !self.gatewayConnected { return .still }
switch self.permissionState {
case .requestingUpgrade, .upgradeRequested:
return .indeterminate
case .missingScope, .requestFailed, .apiKeyMissing, .loadFailed:
return .still
default:
break
}
if self.isSpeaking { return .speaking }
if self.isListening, self.isUserSpeechDetected { return .inputSpeech }
if self.isListening { return .level(micLevel) }
if self.normalizedStatus.contains("connecting") || self.normalizedStatus.contains("thinking") {
return .indeterminate
}
return self.isEnabled ? .indeterminate : .still
}
}
private struct TalkProOrb: View {
let mode: TalkProWaveformMode
let color: Color
let systemImage: String
@Environment(\.accessibilityReduceMotion) private var reduceMotion
var body: some View {
TimelineView(.periodic(from: .now, by: 1.0 / 24.0)) { timeline in
ZStack {
ForEach(0..<3, id: \.self) { ring in
Circle()
.strokeBorder(self.color.opacity(self.ringOpacity(ring)), lineWidth: 1.4)
.scaleEffect(self.ringScale(ring, date: timeline.date))
}
Circle()
.fill(self.color.opacity(0.13))
.frame(width: 128, height: 128)
.overlay {
Circle()
.strokeBorder(self.color.opacity(0.30), lineWidth: 1)
}
TalkProWaveform(mode: self.mode, tint: self.color, barCount: 18)
.frame(width: 116, height: 52)
.opacity(self.systemImage == "waveform" || self.systemImage == "mic.fill" ? 1 : 0.34)
Image(systemName: self.systemImage)
.font(.system(size: 34, weight: .bold))
.foregroundStyle(self.color)
.opacity(self.systemImage == "waveform" || self.systemImage == "mic.fill" ? 0.20 : 1)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
private func ringScale(_ ring: Int, date: Date) -> CGFloat {
guard !self.reduceMotion else { return CGFloat(1.0 + (Double(ring) * 0.12)) }
let base = 0.88 + (Double(ring) * 0.18)
let speed = self.mode == .still ? 0.8 : 1.8
let phase = date.timeIntervalSinceReferenceDate * speed + Double(ring) * 0.9
return CGFloat(base + (sin(phase) * 0.035))
}
private func ringOpacity(_ ring: Int) -> Double {
switch self.mode {
case .still:
0.10 - (Double(ring) * 0.018)
default:
0.24 - (Double(ring) * 0.045)
}
}
}
private struct TalkProWaveform: View {
let mode: TalkProWaveformMode
let tint: Color
let barCount: Int
@Environment(\.accessibilityReduceMotion) private var reduceMotion
var body: some View {
TimelineView(.periodic(from: .now, by: 1.0 / 24.0)) { timeline in
HStack(alignment: .center, spacing: 4) {
ForEach(0..<self.barCount, id: \.self) { index in
Capsule(style: .continuous)
.fill(self.tint.opacity(self.opacity(for: index)))
.frame(width: 4, height: self.height(for: index, date: timeline.date))
}
}
.frame(maxHeight: .infinity)
}
}
private func height(for index: Int, date: Date) -> CGFloat {
let minimum = 6.0
let maximum = 48.0
return CGFloat(minimum + ((maximum - minimum) * self.amplitude(for: index, date: date)))
}
private func opacity(for index: Int) -> Double {
switch self.mode {
case .still:
index == self.barCount / 2 ? 0.64 : 0.30
default:
0.82
}
}
private func amplitude(for index: Int, date: Date) -> Double {
if self.reduceMotion {
switch self.mode {
case let .level(level): return min(max(level, 0.10), 1.0)
case .inputSpeech: return 0.72
case .speaking: return 0.62
case .indeterminate: return 0.34
case .still: return 0.18
}
}
let t = date.timeIntervalSinceReferenceDate
let phase = Double(index) * 0.52
switch self.mode {
case let .level(level):
let clamped = min(max(level, 0), 1)
let shaped = 0.12 + (0.88 * clamped)
let variation = 0.72 + (0.28 * sin((t * 12.0) + phase))
return min(max(shaped * variation, 0.10), 1.0)
case .inputSpeech:
let primary = 0.5 + (0.5 * sin((t * 14.0) + phase))
let secondary = 0.5 + (0.5 * sin((t * 5.0) + (phase * 1.35)))
return min(max(0.16 + (0.60 * primary) + (0.24 * secondary), 0.14), 1.0)
case .speaking:
let wave = 0.5 + (0.5 * sin((t * 7.5) + phase))
let secondary = 0.5 + (0.5 * sin((t * 3.0) + (phase * 0.7)))
return min(max(0.18 + (0.58 * wave) + (0.24 * secondary), 0.12), 1.0)
case .indeterminate:
let center = (sin((t * 3.2) + phase) + 1) / 2
return 0.16 + (0.42 * center)
case .still:
return index == self.barCount / 2 ? 0.32 : 0.16
}
}
}

View File

@@ -17,6 +17,7 @@ private struct RelayGatewayPushRegistrationPayload: Encodable {
var topic: String
var environment: String
var distribution: String
var relayOrigin: String
var tokenDebugSuffix: String?
}
@@ -107,6 +108,7 @@ actor PushRegistrationManager {
topic: topic,
environment: self.buildConfig.apnsEnvironment.rawValue,
distribution: self.buildConfig.distribution.rawValue,
relayOrigin: relayOrigin,
tokenDebugSuffix: stored.tokenDebugSuffix))
}
@@ -138,6 +140,7 @@ actor PushRegistrationManager {
topic: topic,
environment: self.buildConfig.apnsEnvironment.rawValue,
distribution: self.buildConfig.distribution.rawValue,
relayOrigin: relayOrigin,
tokenDebugSuffix: registrationState.tokenDebugSuffix))
}

View File

@@ -36,6 +36,7 @@ struct RootTabs: View {
private enum AppTab: Hashable {
case control
case chat
case talk
case agent
case settings
}
@@ -53,6 +54,8 @@ struct RootTabs: View {
switch arguments[valueIndex].lowercased() {
case "chat":
return .chat
case "talk", "voice":
return .talk
case "agent", "agents":
return .agent
case "settings":
@@ -145,6 +148,14 @@ struct RootTabs: View {
.tabItem { Label("Chat", systemImage: "bubble.left.fill") }
.tag(AppTab.chat)
TalkProTab(openSettings: { self.selectedTab = .settings })
.tabItem {
Label(
"Talk",
systemImage: self.appModel.talkMode.isEnabled ? "waveform.circle.fill" : "waveform.circle")
}
.tag(AppTab.talk)
AgentProTab()
.tabItem { Label("Agent", systemImage: "person.2.fill") }
.tag(AppTab.agent)

View File

@@ -17,7 +17,7 @@ private func makeRealtimeAudioTapBlock(
inputSampleRate: inputSampleRate,
targetSampleRate: targetSampleRate)
guard !encoded.isEmpty else { return }
let timestampMs = ProcessInfo.processInfo.systemUptime * 1000
let timestampMs = (ProcessInfo.processInfo.systemUptime * 1000).rounded()
let rms = RealtimeTalkRelaySession.rmsLevel(buffer: buffer)
onAudio(encoded, timestampMs, rms)
}
@@ -125,15 +125,24 @@ final class RealtimeTalkRelaySession {
private var eventTask: Task<Void, Never>?
private var outputTask: Task<Void, Never>?
private var outputContinuation: AsyncThrowingStream<Data, Error>.Continuation?
private var outputIdleTask: Task<Void, Never>?
private var outputSessionId = 0
private var pendingOutputChunks: [Data] = []
private var pendingOutputDone = false
private var audioSender: RealtimeAudioSender?
private var isClosed = false
private var isOutputPlaying = false
private var outputStartedAtMs: Double?
private var outputPlaybackExpectedEndMs: Double = 0
private var lastBargeInAtMs: Double = 0
private var micLogFrameCount = 0
private var micLogByteCount = 0
private var micLogMaxRms: Float = 0
private var lastMicLogAtMs: Double = 0
private var suppressedEchoFrameCount = 0
private var suppressedEchoByteCount = 0
private var suppressedEchoMaxRms: Float = 0
private var lastSuppressedEchoLogAtMs: Double = 0
private var outputAudioChunkCount = 0
private var outputAudioByteCount = 0
@@ -168,7 +177,6 @@ final class RealtimeTalkRelaySession {
let eventStream = await self.gateway.subscribeServerEvents(bufferingNewest: 200)
self.startEventPump(stream: eventStream)
self.configureAudioContract(result.audio)
self.startOutputPlayback()
try self.startMicrophonePump()
self.onStatus("Listening (Realtime)")
} catch {
@@ -219,7 +227,6 @@ final class RealtimeTalkRelaySession {
func cancelOutput(reason: String = "user") {
self.stopOutputPlayback()
self.startOutputPlayback()
guard let relaySessionId else { return }
Task { [gateway] in
let payload: [String: Any] = [
@@ -306,12 +313,18 @@ final class RealtimeTalkRelaySession {
let data = Data(base64Encoded: base64)
else { return }
self.recordOutputAudioChunk(byteCount: data.count)
self.markOutputAudioStarted(nowMs: ProcessInfo.processInfo.systemUptime * 1000)
self.markOutputAudioStarted(byteCount: data.count, nowMs: ProcessInfo.processInfo.systemUptime * 1000)
self.onSpeakingChanged(true)
if self.outputContinuation == nil, self.outputTask != nil {
self.pendingOutputChunks.append(data)
return
}
self.ensureOutputPlaybackStarted()
self.outputContinuation?.yield(data)
case "audioDone":
self.finishOutputPlaybackStream()
case "clear":
self.stopOutputPlayback()
self.startOutputPlayback()
case "transcript":
self.handleTranscriptEvent(payload)
case "toolCall":
@@ -337,11 +350,16 @@ final class RealtimeTalkRelaySession {
"talk realtime audio: chunks=\(self.outputAudioChunkCount) bytes=\(self.outputAudioByteCount)")
}
private func markOutputAudioStarted(nowMs: Double) {
private func markOutputAudioStarted(byteCount: Int, nowMs: Double) {
if !self.isOutputPlaying {
self.outputStartedAtMs = nowMs
self.outputPlaybackExpectedEndMs = nowMs
}
self.isOutputPlaying = true
let bytesPerSecond = max(1, self.outputSampleRateHz * Double(MemoryLayout<Int16>.size))
let chunkDurationMs = (Double(byteCount) / bytesPerSecond) * 1000
self.outputPlaybackExpectedEndMs = max(nowMs, self.outputPlaybackExpectedEndMs) + chunkDurationMs
self.scheduleOutputPlaybackIdle(expectedEndMs: self.outputPlaybackExpectedEndMs)
}
private func handleInputLevelDuringOutput(_ rms: Float, timestampMs: Double) {
@@ -537,14 +555,25 @@ final class RealtimeTalkRelaySession {
{ [weak self, audioSender = self.audioSender] encoded, timestampMs, rms in
guard let audioSender else { return }
Task {
await MainActor.run { [weak self] in
self?.recordMicrophoneFrame(byteCount: encoded.count, rms: rms, timestampMs: timestampMs)
}
if rms >= Self.bargeInRmsThreshold {
await MainActor.run { [weak self] in
self?.handleInputLevelDuringOutput(rms, timestampMs: timestampMs)
let shouldSend = await MainActor.run { [weak self] in
guard let self, !self.isClosed else { return false }
self.recordMicrophoneFrame(byteCount: encoded.count, rms: rms, timestampMs: timestampMs)
self.refreshOutputPlaybackState(timestampMs: timestampMs)
if self.isOutputPlaying {
if self.shouldSuppressMicrophoneDuringOutput() {
self.recordSuppressedOutputEchoFrame(
byteCount: encoded.count,
rms: rms,
timestampMs: timestampMs)
return false
}
if rms >= Self.bargeInRmsThreshold {
self.handleInputLevelDuringOutput(rms, timestampMs: timestampMs)
}
}
return true
}
guard shouldSend else { return }
guard let message = await audioSender.send(encoded, timestampMs: timestampMs) else { return }
await MainActor.run { [weak self] in
guard let self, !self.isClosed else { return }
@@ -561,6 +590,13 @@ final class RealtimeTalkRelaySession {
try self.audioEngine.start()
}
private func shouldSuppressMicrophoneDuringOutput() -> Bool {
let outputs = AVAudioSession.sharedInstance().currentRoute.outputs
// Built-in speaker output bleeds into the microphone even in voiceChat mode; keep the
// realtime provider from treating its own speech as user input. Headsets keep barge-in.
return outputs.contains { $0.portType == .builtInSpeaker }
}
private func recordMicrophoneFrame(byteCount: Int, rms: Float, timestampMs: Double) {
guard !self.isClosed else { return }
self.micLogFrameCount += 1
@@ -576,13 +612,31 @@ final class RealtimeTalkRelaySession {
self.micLogMaxRms = 0
}
private func recordSuppressedOutputEchoFrame(byteCount: Int, rms: Float, timestampMs: Double) {
self.suppressedEchoFrameCount += 1
self.suppressedEchoByteCount += byteCount
self.suppressedEchoMaxRms = max(self.suppressedEchoMaxRms, rms)
guard timestampMs - self.lastSuppressedEchoLogAtMs >= 1000 else { return }
self.lastSuppressedEchoLogAtMs = timestampMs
let maxRms = String(format: "%.4f", Double(self.suppressedEchoMaxRms))
GatewayDiagnostics.log(
"talk realtime mic suppressed during output: "
+ "buffers=\(self.suppressedEchoFrameCount) "
+ "bytes=\(self.suppressedEchoByteCount) maxRms=\(maxRms)")
self.suppressedEchoFrameCount = 0
self.suppressedEchoByteCount = 0
self.suppressedEchoMaxRms = 0
}
private func stopMicrophonePump() {
self.audioEngine.inputNode.removeTap(onBus: 0)
self.audioEngine.stop()
}
private func startOutputPlayback() {
self.stopOutputPlayback()
private func ensureOutputPlaybackStarted() {
guard self.outputContinuation == nil, self.outputTask == nil else { return }
self.outputSessionId += 1
let sessionId = self.outputSessionId
let stream = AsyncThrowingStream<Data, Error> { continuation in
self.outputContinuation = continuation
}
@@ -590,28 +644,95 @@ final class RealtimeTalkRelaySession {
guard let self else { return }
let result = await self.pcmPlayer.play(stream: stream, sampleRate: self.outputSampleRateHz)
await MainActor.run {
guard self.outputSessionId == sessionId else { return }
self.outputTask = nil
self.outputContinuation = nil
if !result.finished, let interruptedAt = result.interruptedAt {
self.logger.info("realtime output interrupted at \(interruptedAt, privacy: .public)s")
}
self.markOutputPlaybackFinished()
self.startPendingOutputPlaybackIfNeeded()
}
}
}
private func markOutputPlaybackFinished() {
private func finishOutputPlaybackStream() {
guard let continuation = self.outputContinuation else {
if self.outputTask != nil, !self.pendingOutputChunks.isEmpty {
self.pendingOutputDone = true
}
return
}
continuation.finish()
self.outputContinuation = nil
}
private func startPendingOutputPlaybackIfNeeded() {
guard !self.pendingOutputChunks.isEmpty else {
self.pendingOutputDone = false
return
}
let chunks = self.pendingOutputChunks
let shouldFinish = self.pendingOutputDone
self.pendingOutputChunks = []
self.pendingOutputDone = false
self.ensureOutputPlaybackStarted()
for chunk in chunks {
self.markOutputAudioStarted(byteCount: chunk.count, nowMs: ProcessInfo.processInfo.systemUptime * 1000)
self.onSpeakingChanged(true)
self.outputContinuation?.yield(chunk)
}
if shouldFinish {
self.finishOutputPlaybackStream()
}
}
private func scheduleOutputPlaybackIdle(expectedEndMs: Double) {
self.outputIdleTask?.cancel()
let nowMs = ProcessInfo.processInfo.systemUptime * 1000
let idleDelayMs = max(350, expectedEndMs - nowMs + 500)
self.outputIdleTask = Task { [weak self] in
try? await Task.sleep(nanoseconds: UInt64(idleDelayMs * 1_000_000))
guard !Task.isCancelled else { return }
await MainActor.run { [weak self] in
guard let self, !self.isClosed else { return }
let nowMs = ProcessInfo.processInfo.systemUptime * 1000
self.refreshOutputPlaybackState(timestampMs: nowMs, cancelIdleTask: false)
}
}
}
private func refreshOutputPlaybackState(timestampMs: Double, cancelIdleTask: Bool = true) {
guard self.isOutputPlaying else { return }
guard timestampMs >= self.outputPlaybackExpectedEndMs + 500 else { return }
self.markOutputPlaybackFinished(cancelIdleTask: cancelIdleTask)
}
private func markOutputPlaybackFinished(cancelIdleTask: Bool = true) {
if cancelIdleTask {
self.outputIdleTask?.cancel()
self.outputIdleTask = nil
}
self.isOutputPlaying = false
self.outputStartedAtMs = nil
self.outputPlaybackExpectedEndMs = 0
self.onSpeakingChanged(false)
}
private func stopOutputPlayback() {
self.outputSessionId += 1
self.outputContinuation?.finish()
self.outputContinuation = nil
self.outputTask?.cancel()
self.outputTask = nil
self.outputIdleTask?.cancel()
self.outputIdleTask = nil
self.pendingOutputChunks = []
self.pendingOutputDone = false
_ = self.pcmPlayer.stop()
self.isOutputPlaying = false
self.outputStartedAtMs = nil
self.outputPlaybackExpectedEndMs = 0
self.onSpeakingChanged(false)
}
@@ -684,7 +805,7 @@ final class RealtimeTalkRelaySession {
extension RealtimeTalkRelaySession {
func _test_markOutputAudioStarted(nowMs: Double) {
self.markOutputAudioStarted(nowMs: nowMs)
self.markOutputAudioStarted(byteCount: 4800, nowMs: nowMs)
}
func _test_markOutputPlaybackFinished() {

View File

@@ -1141,7 +1141,7 @@ final class TalkModeManager: NSObject {
})
self.realtimeRelaySession = relaySession
do {
try Self.configureAudioSession()
try Self.configureRealtimeAudioSession()
try await relaySession.start()
guard self.realtimeRelaySession === relaySession, self.isEnabled else {
relaySession.stop()

View File

@@ -13,6 +13,7 @@ Sources/Design/AgentProNodesDestination.swift
Sources/Design/AgentProTab.swift
Sources/Design/ChatProTab.swift
Sources/Design/CommandCenterTab.swift
Sources/Design/TalkProTab.swift
Sources/Design/OpenClawProComponents.swift
Sources/Design/OpenClawProScreens.swift
Sources/Design/SettingsProTab.swift

View File

@@ -29,6 +29,14 @@ def clear_empty_env_var(key)
ENV.delete(key) unless env_present?(ENV[key])
end
def screenshot_upload_requested?
ENV["DELIVER_SCREENSHOTS"] == "1"
end
def screenshot_paths
Dir[File.join(__dir__, "screenshots", "**", "*.png")]
end
def maybe_decode_hex_keychain_secret(value)
return value unless env_present?(value)
@@ -314,6 +322,7 @@ platform :ios do
desc "Upload App Store metadata (and optionally screenshots)"
lane :metadata do
sync_ios_versioning!
version_metadata = read_ios_version_metadata
api_key = asc_api_key
clear_empty_env_var("APP_STORE_CONNECT_API_KEY_PATH")
app_identifier = ENV["ASC_APP_IDENTIFIER"]
@@ -321,11 +330,21 @@ platform :ios do
app_identifier = nil unless env_present?(app_identifier)
app_id = nil unless env_present?(app_id)
if screenshot_upload_requested? && screenshot_paths.empty?
UI.user_error!("DELIVER_SCREENSHOTS=1 but no PNG screenshots were found under apps/ios/fastlane/screenshots.")
end
deliver_options = {
api_key: api_key,
force: true,
skip_screenshots: ENV["DELIVER_SCREENSHOTS"] != "1",
app_version: version_metadata[:short_version],
copyright: "2026 OpenClaw",
primary_category: "PRODUCTIVITY",
secondary_category: "UTILITIES",
skip_screenshots: !screenshot_upload_requested?,
skip_metadata: ENV["DELIVER_METADATA"] != "1",
skip_binary_upload: true,
overwrite_screenshots: screenshot_upload_requested?,
run_precheck_before_submit: false
}
deliver_options[:app_identifier] = app_identifier if app_identifier

View File

@@ -1,18 +1,19 @@
OpenClaw is a personal AI assistant you run on your own devices.
Pair this iPhone app with your OpenClaw Gateway to connect your phone as a secure node for voice, camera, and device automation.
Pair this iPhone app with your OpenClaw Gateway to use your phone as a secure node for chat, voice, approvals, sharing, and device-aware automation.
What you can do:
- Pair with your private OpenClaw Gateway by QR code or setup code
- Chat with your assistant from iPhone
- Use voice wake and push-to-talk
- Capture photos and short clips on request
- Record screen snippets for troubleshooting and workflows
- Use realtime Talk mode and push-to-talk
- Review Gateway action approvals from your phone
- Share text, links, and media directly from iOS into OpenClaw
- Run location-aware and device-aware automations
- Enable device capabilities such as camera, screen, location, photos, contacts, calendar, and reminders when you choose
- Receive push wakes and node status updates for connected workflows
OpenClaw is local-first: you control your gateway, keys, and configuration.
OpenClaw is local-first: you control your gateway, keys, configuration, and permissions. Device access is managed by iOS permissions and can be enabled only for the capabilities you want to use.
Getting started:
1) Set up your OpenClaw Gateway
2) Open the iOS app and pair with your gateway
3) Start using commands and automations from your phone
3) Start using chat, Talk mode, approvals, and automations from your phone

View File

@@ -1 +1 @@
openclaw,ai assistant,local ai,voice assistant,automation,gateway,chat,agent,node
openclaw,ai assistant,local ai,iphone ai,voice assistant,automation,gateway,chat,agent

View File

@@ -1 +1 @@
Run OpenClaw from your iPhone: pair with your own gateway, trigger automations, and use voice, camera, and share actions.
Pair your iPhone with your OpenClaw Gateway for chat, realtime voice, approvals, device capabilities, and private automation.

View File

@@ -1 +1,5 @@
Maintenance update for the current OpenClaw release.
- Added hosted push relay defaults, realtime Talk playback, and safer WebSocket ping handling for mobile sessions.
- Updated App Store screenshots to cover Gateway pairing, Command, Chat, Talk, Agent, and Settings flows.
- Highlighted realtime Talk relay, Gateway connection status, node capabilities, push wake, and privacy controls.

View File

@@ -1,3 +1,3 @@
{
"version": "2026.5.28"
"version": "2026.5.30"
}

View File

@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2026.5.28</string>
<string>2026.5.30</string>
<key>CFBundleVersion</key>
<string>2026052800</string>
<string>2026053000</string>
<key>CFBundleIconFile</key>
<string>OpenClaw</string>
<key>CFBundleURLTypes</key>

View File

@@ -14,6 +14,22 @@ public protocol WebSocketTasking: AnyObject {
extension URLSessionWebSocketTask: WebSocketTasking {}
private final class WebSocketPingContinuationGate: @unchecked Sendable {
private let lock = NSLock()
private var didResume = false
func resumeOnce(_ resume: () -> Void) {
self.lock.lock()
if self.didResume {
self.lock.unlock()
return
}
self.didResume = true
self.lock.unlock()
resume()
}
}
public struct WebSocketTaskBox: @unchecked Sendable {
public let task: any WebSocketTasking
public init(task: any WebSocketTasking) {
@@ -48,8 +64,13 @@ public struct WebSocketTaskBox: @unchecked Sendable {
public func sendPing() async throws {
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
let gate = WebSocketPingContinuationGate()
self.task.sendPing { error in
ThrowingContinuationSupport.resumeVoid(continuation, error: error)
// URLSession can race ping callbacks with cancellation; only the first
// pong result owns this checked continuation or Swift traps the app.
gate.resumeOnce {
ThrowingContinuationSupport.resumeVoid(continuation, error: error)
}
}
}
}

View File

@@ -361,6 +361,26 @@
}
}
},
"get_goal": {
"emoji": "🎯",
"title": "Get Goal",
"detailKeys": []
},
"create_goal": {
"emoji": "🎯",
"title": "Create Goal",
"detailKeys": [
"objective",
"token_budget"
]
},
"update_goal": {
"emoji": "🎯",
"title": "Update Goal",
"detailKeys": [
"status"
]
},
"update_plan": {
"emoji": "🗺️",
"title": "Update Plan",
@@ -369,6 +389,15 @@
"plan.0.step"
]
},
"skill_workshop": {
"emoji": "🧰",
"title": "Skill Workshop",
"detailKeys": [
"action",
"name",
"proposal_id"
]
},
"gateway": {
"emoji": "🔌",
"title": "Gateway",

View File

@@ -556,7 +556,7 @@ public struct MessageActionParams: Codable, Sendable {
sessionkey: String?,
sessionid: String?,
inboundturnkind: String? = nil,
agentid: String?,
agentid: String? = nil,
toolcontext: [String: AnyCodable]?,
idempotencykey: String)
{
@@ -617,7 +617,7 @@ public struct SendParams: Codable, Sendable {
gifplayback: Bool?,
channel: String?,
accountid: String?,
agentid: String?,
agentid: String? = nil,
replytoid: String?,
threadid: String?,
forcedocument: Bool?,
@@ -765,7 +765,7 @@ public struct AgentParams: Codable, Sendable {
public init(
message: String,
agentid: String?,
agentid: String? = nil,
provider: String?,
model: String?,
to: String?,
@@ -893,7 +893,7 @@ public struct AgentIdentityParams: Codable, Sendable {
public let sessionkey: String?
public init(
agentid: String?,
agentid: String? = nil,
sessionkey: String?)
{
self.agentid = agentid
@@ -1617,7 +1617,7 @@ public struct SessionsListParams: Codable, Sendable {
includelastmessage: Bool?,
label: String?,
spawnedby: String?,
agentid: String?,
agentid: String? = nil,
search: String?)
{
self.limit = limit
@@ -1741,7 +1741,7 @@ public struct SessionsResolveParams: Codable, Sendable {
key: String?,
sessionid: String?,
label: String?,
agentid: String?,
agentid: String? = nil,
spawnedby: String?,
includeglobal: Bool?,
includeunknown: Bool?)
@@ -1825,6 +1825,7 @@ public struct SessionOperationEvent: Codable, Sendable {
public let operation: String
public let phase: AnyCodable
public let sessionkey: String
public let agentid: String?
public let ts: Int
public let completed: Bool?
public let reason: String?
@@ -1834,6 +1835,7 @@ public struct SessionOperationEvent: Codable, Sendable {
operation: String,
phase: AnyCodable,
sessionkey: String,
agentid: String? = nil,
ts: Int,
completed: Bool?,
reason: String?)
@@ -1842,6 +1844,7 @@ public struct SessionOperationEvent: Codable, Sendable {
self.operation = operation
self.phase = phase
self.sessionkey = sessionkey
self.agentid = agentid
self.ts = ts
self.completed = completed
self.reason = reason
@@ -1852,6 +1855,7 @@ public struct SessionOperationEvent: Codable, Sendable {
case operation
case phase
case sessionkey = "sessionKey"
case agentid = "agentId"
case ts
case completed
case reason
@@ -1860,68 +1864,84 @@ public struct SessionOperationEvent: Codable, Sendable {
public struct SessionsCompactionListParams: Codable, Sendable {
public let key: String
public let agentid: String?
public init(
key: String)
key: String,
agentid: String? = nil)
{
self.key = key
self.agentid = agentid
}
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
}
}
public struct SessionsCompactionGetParams: Codable, Sendable {
public let key: String
public let agentid: String?
public let checkpointid: String
public init(
key: String,
agentid: String? = nil,
checkpointid: String)
{
self.key = key
self.agentid = agentid
self.checkpointid = checkpointid
}
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
case checkpointid = "checkpointId"
}
}
public struct SessionsCompactionBranchParams: Codable, Sendable {
public let key: String
public let agentid: String?
public let checkpointid: String
public init(
key: String,
agentid: String? = nil,
checkpointid: String)
{
self.key = key
self.agentid = agentid
self.checkpointid = checkpointid
}
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
case checkpointid = "checkpointId"
}
}
public struct SessionsCompactionRestoreParams: Codable, Sendable {
public let key: String
public let agentid: String?
public let checkpointid: String
public init(
key: String,
agentid: String? = nil,
checkpointid: String)
{
self.key = key
self.agentid = agentid
self.checkpointid = checkpointid
}
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
case checkpointid = "checkpointId"
}
}
@@ -2046,7 +2066,7 @@ public struct SessionsCreateParams: Codable, Sendable {
public init(
key: String?,
agentid: String?,
agentid: String? = nil,
label: String?,
model: String?,
parentsessionkey: String?,
@@ -2078,6 +2098,7 @@ public struct SessionsCreateParams: Codable, Sendable {
public struct SessionsSendParams: Codable, Sendable {
public let key: String
public let agentid: String?
public let message: String
public let thinking: String?
public let attachments: [AnyCodable]?
@@ -2086,6 +2107,7 @@ public struct SessionsSendParams: Codable, Sendable {
public init(
key: String,
agentid: String? = nil,
message: String,
thinking: String?,
attachments: [AnyCodable]?,
@@ -2093,6 +2115,7 @@ public struct SessionsSendParams: Codable, Sendable {
idempotencykey: String?)
{
self.key = key
self.agentid = agentid
self.message = message
self.thinking = thinking
self.attachments = attachments
@@ -2102,6 +2125,7 @@ public struct SessionsSendParams: Codable, Sendable {
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
case message
case thinking
case attachments
@@ -2112,29 +2136,37 @@ public struct SessionsSendParams: Codable, Sendable {
public struct SessionsMessagesSubscribeParams: Codable, Sendable {
public let key: String
public let agentid: String?
public init(
key: String)
key: String,
agentid: String? = nil)
{
self.key = key
self.agentid = agentid
}
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
}
}
public struct SessionsMessagesUnsubscribeParams: Codable, Sendable {
public let key: String
public let agentid: String?
public init(
key: String)
key: String,
agentid: String? = nil)
{
self.key = key
self.agentid = agentid
}
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
}
}
@@ -2162,6 +2194,7 @@ public struct SessionsAbortParams: Codable, Sendable {
public struct SessionsPatchParams: Codable, Sendable {
public let key: String
public let agentid: String?
public let label: AnyCodable?
public let thinkinglevel: AnyCodable?
public let fastmode: AnyCodable?
@@ -2188,6 +2221,7 @@ public struct SessionsPatchParams: Codable, Sendable {
public init(
key: String,
agentid: String? = nil,
label: AnyCodable?,
thinkinglevel: AnyCodable?,
fastmode: AnyCodable?,
@@ -2213,6 +2247,7 @@ public struct SessionsPatchParams: Codable, Sendable {
groupactivation: AnyCodable?)
{
self.key = key
self.agentid = agentid
self.label = label
self.thinkinglevel = thinkinglevel
self.fastmode = fastmode
@@ -2240,6 +2275,7 @@ public struct SessionsPatchParams: Codable, Sendable {
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
case label
case thinkinglevel = "thinkingLevel"
case fastmode = "fastMode"
@@ -2320,39 +2356,47 @@ public struct SessionsPluginPatchResult: Codable, Sendable {
public struct SessionsResetParams: Codable, Sendable {
public let key: String
public let agentid: String?
public let reason: AnyCodable?
public init(
key: String,
agentid: String? = nil,
reason: AnyCodable?)
{
self.key = key
self.agentid = agentid
self.reason = reason
}
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
case reason
}
}
public struct SessionsDeleteParams: Codable, Sendable {
public let key: String
public let agentid: String?
public let deletetranscript: Bool?
public let emitlifecyclehooks: Bool?
public init(
key: String,
agentid: String? = nil,
deletetranscript: Bool?,
emitlifecyclehooks: Bool?)
{
self.key = key
self.agentid = agentid
self.deletetranscript = deletetranscript
self.emitlifecyclehooks = emitlifecyclehooks
}
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
case deletetranscript = "deleteTranscript"
case emitlifecyclehooks = "emitLifecycleHooks"
}
@@ -2360,18 +2404,22 @@ public struct SessionsDeleteParams: Codable, Sendable {
public struct SessionsCompactParams: Codable, Sendable {
public let key: String
public let agentid: String?
public let maxlines: Int?
public init(
key: String,
agentid: String? = nil,
maxlines: Int?)
{
self.key = key
self.agentid = agentid
self.maxlines = maxlines
}
private enum CodingKeys: String, CodingKey {
case key
case agentid = "agentId"
case maxlines = "maxLines"
}
}
@@ -2463,7 +2511,7 @@ public struct TaskSummary: Codable, Sendable {
runtime: String?,
status: AnyCodable,
title: String?,
agentid: String?,
agentid: String? = nil,
sessionkey: String?,
childsessionkey: String?,
ownerkey: String?,
@@ -2537,7 +2585,7 @@ public struct TasksListParams: Codable, Sendable {
public init(
status: AnyCodable?,
agentid: String?,
agentid: String? = nil,
sessionkey: String?,
limit: Int?,
cursor: String?)
@@ -4727,7 +4775,7 @@ public struct CommandsListParams: Codable, Sendable {
public let includeargs: Bool?
public init(
agentid: String?,
agentid: String? = nil,
provider: String?,
scope: AnyCodable?,
includeargs: Bool?)
@@ -4764,7 +4812,7 @@ public struct SkillsStatusParams: Codable, Sendable {
public let agentid: String?
public init(
agentid: String?)
agentid: String? = nil)
{
self.agentid = agentid
}
@@ -4779,7 +4827,7 @@ public struct ToolsCatalogParams: Codable, Sendable {
public let includeplugins: Bool?
public init(
agentid: String?,
agentid: String? = nil,
includeplugins: Bool?)
{
self.agentid = agentid
@@ -4913,7 +4961,7 @@ public struct ToolsEffectiveParams: Codable, Sendable {
public let sessionkey: String
public init(
agentid: String?,
agentid: String? = nil,
sessionkey: String)
{
self.agentid = agentid
@@ -5058,7 +5106,7 @@ public struct ToolsInvokeParams: Codable, Sendable {
name: String,
args: [String: AnyCodable]?,
sessionkey: String?,
agentid: String?,
agentid: String? = nil,
confirm: Bool?,
idempotencykey: String?)
{
@@ -5228,11 +5276,339 @@ public struct SkillsDetailResult: Codable, Sendable {
}
}
public struct SkillsProposalsListParams: Codable, Sendable {
public let agentid: String?
public init(
agentid: String? = nil)
{
self.agentid = agentid
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
}
}
public struct SkillsProposalsListResult: Codable, Sendable {
public let schema: String
public let updatedat: String
public let proposals: [[String: AnyCodable]]
public init(
schema: String,
updatedat: String,
proposals: [[String: AnyCodable]])
{
self.schema = schema
self.updatedat = updatedat
self.proposals = proposals
}
private enum CodingKeys: String, CodingKey {
case schema
case updatedat = "updatedAt"
case proposals
}
}
public struct SkillsProposalInspectParams: Codable, Sendable {
public let agentid: String?
public let proposalid: String
public init(
agentid: String? = nil,
proposalid: String)
{
self.agentid = agentid
self.proposalid = proposalid
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case proposalid = "proposalId"
}
}
public struct SkillsProposalInspectResult: Codable, Sendable {
public let record: SkillsProposalRecordResult
public let content: String
public let supportfiles: [[String: AnyCodable]]?
public init(
record: SkillsProposalRecordResult,
content: String,
supportfiles: [[String: AnyCodable]]?)
{
self.record = record
self.content = content
self.supportfiles = supportfiles
}
private enum CodingKeys: String, CodingKey {
case record
case content
case supportfiles = "supportFiles"
}
}
public struct SkillsProposalCreateParams: Codable, Sendable {
public let agentid: String?
public let name: String
public let description: String
public let content: String
public let supportfiles: [[String: AnyCodable]]?
public let goal: String?
public let evidence: String?
public init(
agentid: String? = nil,
name: String,
description: String,
content: String,
supportfiles: [[String: AnyCodable]]?,
goal: String?,
evidence: String?)
{
self.agentid = agentid
self.name = name
self.description = description
self.content = content
self.supportfiles = supportfiles
self.goal = goal
self.evidence = evidence
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case name
case description
case content
case supportfiles = "supportFiles"
case goal
case evidence
}
}
public struct SkillsProposalUpdateParams: Codable, Sendable {
public let agentid: String?
public let skillname: String
public let description: String?
public let content: String
public let supportfiles: [[String: AnyCodable]]?
public let goal: String?
public let evidence: String?
public init(
agentid: String? = nil,
skillname: String,
description: String?,
content: String,
supportfiles: [[String: AnyCodable]]?,
goal: String?,
evidence: String?)
{
self.agentid = agentid
self.skillname = skillname
self.description = description
self.content = content
self.supportfiles = supportfiles
self.goal = goal
self.evidence = evidence
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case skillname = "skillName"
case description
case content
case supportfiles = "supportFiles"
case goal
case evidence
}
}
public struct SkillsProposalReviseParams: Codable, Sendable {
public let agentid: String?
public let proposalid: String
public let content: String
public let supportfiles: [[String: AnyCodable]]?
public let description: String?
public let goal: String?
public let evidence: String?
public init(
agentid: String? = nil,
proposalid: String,
content: String,
supportfiles: [[String: AnyCodable]]?,
description: String?,
goal: String?,
evidence: String?)
{
self.agentid = agentid
self.proposalid = proposalid
self.content = content
self.supportfiles = supportfiles
self.description = description
self.goal = goal
self.evidence = evidence
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case proposalid = "proposalId"
case content
case supportfiles = "supportFiles"
case description
case goal
case evidence
}
}
public struct SkillsProposalActionParams: Codable, Sendable {
public let agentid: String?
public let proposalid: String
public let reason: String?
public init(
agentid: String? = nil,
proposalid: String,
reason: String?)
{
self.agentid = agentid
self.proposalid = proposalid
self.reason = reason
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case proposalid = "proposalId"
case reason
}
}
public struct SkillsProposalApplyResult: Codable, Sendable {
public let record: SkillsProposalRecordResult
public let targetskillfile: String
public init(
record: SkillsProposalRecordResult,
targetskillfile: String)
{
self.record = record
self.targetskillfile = targetskillfile
}
private enum CodingKeys: String, CodingKey {
case record
case targetskillfile = "targetSkillFile"
}
}
public struct SkillsProposalRecordResult: Codable, Sendable {
public let schema: String
public let id: String
public let kind: AnyCodable
public let status: AnyCodable
public let title: String
public let description: String
public let createdat: String
public let updatedat: String
public let createdby: AnyCodable
public let proposedversion: String
public let draftfile: String
public let drafthash: String
public let supportfiles: [[String: AnyCodable]]?
public let target: [String: AnyCodable]
public let scan: [String: AnyCodable]
public let goal: String?
public let evidence: String?
public let appliedat: String?
public let rejectedat: String?
public let quarantinedat: String?
public let staleat: String?
public let statusreason: String?
public init(
schema: String,
id: String,
kind: AnyCodable,
status: AnyCodable,
title: String,
description: String,
createdat: String,
updatedat: String,
createdby: AnyCodable,
proposedversion: String,
draftfile: String,
drafthash: String,
supportfiles: [[String: AnyCodable]]?,
target: [String: AnyCodable],
scan: [String: AnyCodable],
goal: String?,
evidence: String?,
appliedat: String?,
rejectedat: String?,
quarantinedat: String?,
staleat: String?,
statusreason: String?)
{
self.schema = schema
self.id = id
self.kind = kind
self.status = status
self.title = title
self.description = description
self.createdat = createdat
self.updatedat = updatedat
self.createdby = createdby
self.proposedversion = proposedversion
self.draftfile = draftfile
self.drafthash = drafthash
self.supportfiles = supportfiles
self.target = target
self.scan = scan
self.goal = goal
self.evidence = evidence
self.appliedat = appliedat
self.rejectedat = rejectedat
self.quarantinedat = quarantinedat
self.staleat = staleat
self.statusreason = statusreason
}
private enum CodingKeys: String, CodingKey {
case schema
case id
case kind
case status
case title
case description
case createdat = "createdAt"
case updatedat = "updatedAt"
case createdby = "createdBy"
case proposedversion = "proposedVersion"
case draftfile = "draftFile"
case drafthash = "draftHash"
case supportfiles = "supportFiles"
case target
case scan
case goal
case evidence
case appliedat = "appliedAt"
case rejectedat = "rejectedAt"
case quarantinedat = "quarantinedAt"
case staleat = "staleAt"
case statusreason = "statusReason"
}
}
public struct SkillsSecurityVerdictsParams: Codable, Sendable {
public let agentid: String?
public init(
agentid: String?)
agentid: String? = nil)
{
self.agentid = agentid
}
@@ -5265,7 +5641,7 @@ public struct SkillsSkillCardParams: Codable, Sendable {
public let skillkey: String
public init(
agentid: String?,
agentid: String? = nil,
skillkey: String)
{
self.agentid = agentid
@@ -5402,7 +5778,7 @@ public struct CronJob: Codable, Sendable {
public init(
id: String,
agentid: String?,
agentid: String? = nil,
sessionkey: String?,
name: String,
description: String?,
@@ -5478,7 +5854,7 @@ public struct CronListParams: Codable, Sendable {
lastrunstatus: AnyCodable?,
sortby: AnyCodable?,
sortdir: AnyCodable?,
agentid: String?)
agentid: String? = nil)
{
self.includedisabled = includedisabled
self.limit = limit
@@ -5524,7 +5900,7 @@ public struct CronAddParams: Codable, Sendable {
public init(
name: String,
agentid: AnyCodable?,
agentid: AnyCodable? = nil,
sessionkey: AnyCodable?,
description: String?,
enabled: Bool?,
@@ -5912,7 +6288,7 @@ public struct ExecApprovalRequestParams: Codable, Sendable {
ask: AnyCodable?,
warningtext: AnyCodable?,
commandspans: [[String: AnyCodable]]?,
agentid: AnyCodable?,
agentid: AnyCodable? = nil,
resolvedpath: AnyCodable?,
sessionkey: AnyCodable?,
turnsourcechannel: AnyCodable?,
@@ -6019,7 +6395,7 @@ public struct PluginApprovalRequestParams: Codable, Sendable {
toolname: String?,
toolcallid: String?,
alloweddecisions: [String]?,
agentid: String?,
agentid: String? = nil,
sessionkey: String?,
turnsourcechannel: String?,
turnsourceto: String?,
@@ -6480,21 +6856,25 @@ public struct DevicePairResolvedEvent: Codable, Sendable {
public struct ChatHistoryParams: Codable, Sendable {
public let sessionkey: String
public let agentid: String?
public let limit: Int?
public let maxchars: Int?
public init(
sessionkey: String,
agentid: String? = nil,
limit: Int?,
maxchars: Int?)
{
self.sessionkey = sessionkey
self.agentid = agentid
self.limit = limit
self.maxchars = maxchars
}
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case agentid = "agentId"
case limit
case maxchars = "maxChars"
}
@@ -6502,6 +6882,7 @@ public struct ChatHistoryParams: Codable, Sendable {
public struct ChatSendParams: Codable, Sendable {
public let sessionkey: String
public let agentid: String?
public let sessionid: String?
public let message: String
public let thinking: String?
@@ -6519,6 +6900,7 @@ public struct ChatSendParams: Codable, Sendable {
public init(
sessionkey: String,
agentid: String? = nil,
sessionid: String?,
message: String,
thinking: String?,
@@ -6535,6 +6917,7 @@ public struct ChatSendParams: Codable, Sendable {
idempotencykey: String)
{
self.sessionkey = sessionkey
self.agentid = agentid
self.sessionid = sessionid
self.message = message
self.thinking = thinking
@@ -6553,6 +6936,7 @@ public struct ChatSendParams: Codable, Sendable {
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case agentid = "agentId"
case sessionid = "sessionId"
case message
case thinking
@@ -6572,39 +6956,47 @@ public struct ChatSendParams: Codable, Sendable {
public struct ChatAbortParams: Codable, Sendable {
public let sessionkey: String
public let agentid: String?
public let runid: String?
public init(
sessionkey: String,
agentid: String? = nil,
runid: String?)
{
self.sessionkey = sessionkey
self.agentid = agentid
self.runid = runid
}
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case agentid = "agentId"
case runid = "runId"
}
}
public struct ChatInjectParams: Codable, Sendable {
public let sessionkey: String
public let agentid: String?
public let message: String
public let label: String?
public init(
sessionkey: String,
agentid: String? = nil,
message: String,
label: String?)
{
self.sessionkey = sessionkey
self.agentid = agentid
self.message = message
self.label = label
}
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case agentid = "agentId"
case message
case label
}
@@ -6613,6 +7005,7 @@ public struct ChatInjectParams: Codable, Sendable {
public struct ChatDeltaEvent: Codable, Sendable {
public let runid: String
public let sessionkey: String
public let agentid: String?
public let spawnedby: String?
public let seq: Int
public let state: String
@@ -6624,6 +7017,7 @@ public struct ChatDeltaEvent: Codable, Sendable {
public init(
runid: String,
sessionkey: String,
agentid: String? = nil,
spawnedby: String?,
seq: Int,
state: String,
@@ -6634,6 +7028,7 @@ public struct ChatDeltaEvent: Codable, Sendable {
{
self.runid = runid
self.sessionkey = sessionkey
self.agentid = agentid
self.spawnedby = spawnedby
self.seq = seq
self.state = state
@@ -6646,6 +7041,7 @@ public struct ChatDeltaEvent: Codable, Sendable {
private enum CodingKeys: String, CodingKey {
case runid = "runId"
case sessionkey = "sessionKey"
case agentid = "agentId"
case spawnedby = "spawnedBy"
case seq
case state
@@ -6659,6 +7055,7 @@ public struct ChatDeltaEvent: Codable, Sendable {
public struct ChatFinalEvent: Codable, Sendable {
public let runid: String
public let sessionkey: String
public let agentid: String?
public let spawnedby: String?
public let seq: Int
public let state: String
@@ -6669,6 +7066,7 @@ public struct ChatFinalEvent: Codable, Sendable {
public init(
runid: String,
sessionkey: String,
agentid: String? = nil,
spawnedby: String?,
seq: Int,
state: String,
@@ -6678,6 +7076,7 @@ public struct ChatFinalEvent: Codable, Sendable {
{
self.runid = runid
self.sessionkey = sessionkey
self.agentid = agentid
self.spawnedby = spawnedby
self.seq = seq
self.state = state
@@ -6689,6 +7088,7 @@ public struct ChatFinalEvent: Codable, Sendable {
private enum CodingKeys: String, CodingKey {
case runid = "runId"
case sessionkey = "sessionKey"
case agentid = "agentId"
case spawnedby = "spawnedBy"
case seq
case state
@@ -6701,6 +7101,7 @@ public struct ChatFinalEvent: Codable, Sendable {
public struct ChatAbortedEvent: Codable, Sendable {
public let runid: String
public let sessionkey: String
public let agentid: String?
public let spawnedby: String?
public let seq: Int
public let state: String
@@ -6710,6 +7111,7 @@ public struct ChatAbortedEvent: Codable, Sendable {
public init(
runid: String,
sessionkey: String,
agentid: String? = nil,
spawnedby: String?,
seq: Int,
state: String,
@@ -6718,6 +7120,7 @@ public struct ChatAbortedEvent: Codable, Sendable {
{
self.runid = runid
self.sessionkey = sessionkey
self.agentid = agentid
self.spawnedby = spawnedby
self.seq = seq
self.state = state
@@ -6728,6 +7131,7 @@ public struct ChatAbortedEvent: Codable, Sendable {
private enum CodingKeys: String, CodingKey {
case runid = "runId"
case sessionkey = "sessionKey"
case agentid = "agentId"
case spawnedby = "spawnedBy"
case seq
case state
@@ -6739,6 +7143,7 @@ public struct ChatAbortedEvent: Codable, Sendable {
public struct ChatErrorEvent: Codable, Sendable {
public let runid: String
public let sessionkey: String
public let agentid: String?
public let spawnedby: String?
public let seq: Int
public let state: String
@@ -6751,6 +7156,7 @@ public struct ChatErrorEvent: Codable, Sendable {
public init(
runid: String,
sessionkey: String,
agentid: String? = nil,
spawnedby: String?,
seq: Int,
state: String,
@@ -6762,6 +7168,7 @@ public struct ChatErrorEvent: Codable, Sendable {
{
self.runid = runid
self.sessionkey = sessionkey
self.agentid = agentid
self.spawnedby = spawnedby
self.seq = seq
self.state = state
@@ -6775,6 +7182,7 @@ public struct ChatErrorEvent: Codable, Sendable {
private enum CodingKeys: String, CodingKey {
case runid = "runId"
case sessionkey = "sessionKey"
case agentid = "agentId"
case spawnedby = "spawnedBy"
case seq
case state

View File

@@ -11,6 +11,42 @@ private extension NSLock {
}
}
private final class DoubleCallbackPingWebSocketTask: WebSocketTasking, @unchecked Sendable {
private let callbacks: [Error?]
init(callbacks: [Error?]) {
self.callbacks = callbacks
}
var state: URLSessionTask.State { .running }
func resume() {}
func cancel(with closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
_ = (closeCode, reason)
}
func send(_ message: URLSessionWebSocketTask.Message) async throws {
_ = message
}
func sendPing(pongReceiveHandler: @escaping @Sendable (Error?) -> Void) {
for callback in self.callbacks {
pongReceiveHandler(callback)
}
}
func receive() async throws -> URLSessionWebSocketTask.Message {
throw URLError(.badServerResponse)
}
func receive(
completionHandler: @escaping @Sendable (Result<URLSessionWebSocketTask.Message, Error>) -> Void)
{
completionHandler(.failure(URLError(.badServerResponse)))
}
}
private final class FakeGatewayWebSocketTask: WebSocketTasking, @unchecked Sendable {
private let lock = NSLock()
private let helloAuth: [String: Any]?
@@ -193,6 +229,25 @@ private actor SeqGapProbe {
@Suite(.serialized)
struct GatewayNodeSessionTests {
@Test
func websocketPingIgnoresDuplicateSuccessCallbacks() async throws {
let task = DoubleCallbackPingWebSocketTask(callbacks: [nil, nil])
try await WebSocketTaskBox(task: task).sendPing()
}
@Test
func websocketPingIgnoresDuplicateCallbacksAfterFirstError() async throws {
let firstError = URLError(.networkConnectionLost)
let task = DoubleCallbackPingWebSocketTask(callbacks: [firstError, nil])
do {
try await WebSocketTaskBox(task: task).sendPing()
Issue.record("sendPing unexpectedly succeeded")
} catch let error as URLError {
#expect(error.code == firstError.code)
}
}
@Test
func scannedSetupCodePrefersBootstrapAuthOverStoredDeviceToken() async throws {
let tempDir = FileManager.default.temporaryDirectory

View File

@@ -180,6 +180,14 @@ const config = {
entry: ["src/index.ts!", "src/ip.ts!"],
project: ["src/**/*.ts!"],
},
"packages/markdown-core": {
entry: ["src/*.ts!"],
project: ["src/**/*.ts!"],
},
"packages/terminal-core": {
entry: ["src/*.ts!"],
project: ["src/**/*.ts!"],
},
"packages/speech-core": {
entry: ["api.ts!", "runtime-api.ts!", "speaker.ts!", "voice-models.ts!"],
project: ["**/*.ts!"],

View File

@@ -1,4 +1,4 @@
c80dea63b0a3786c8999d06aae62c110786f440b4d6748f9838577aaa2816971 config-baseline.json
948323a1507817b6580ed976f9f9449239008f40283cc7e6005148ecf0ca4582 config-baseline.core.json
f833ffca6bd88162f062bbea4f0eede783373f46674ebbfc3a390c80353930a2 config-baseline.channel.json
bc38b58b67132401a030b3b3a77efdb6c88f207ea1fab9abcb4599e1f9552dda config-baseline.plugin.json
370da2e3a4253f00c3963a3ad8b57707ea3f67a8d0d394b7d2b96db4f3413d32 config-baseline.json
6a66c70d36dacf5fd1a8b7e157d1ff4812e97f518c13ebc3190509df4c269f29 config-baseline.core.json
a9102c0611b8170fac37853cc31771810f31757a9e3b2c6796bbd9625f9b9206 config-baseline.channel.json
923a8cac695c752e51751cc2dea185a3fbe19d0015722f7ea1909f897dfbb898 config-baseline.plugin.json

View File

@@ -1,2 +1,2 @@
59de21361cab0622926ad313caf3f8dc43c28d420a82ba060680ecc30c472453 plugin-sdk-api-baseline.json
05adee9037669db4e834d1a0ca9705d5d94df770083862ab149d2f3e559010d2 plugin-sdk-api-baseline.jsonl
cf29066e9465cb5ac1387d1d482d0939b9176220ecc69964da9af1a471939269 plugin-sdk-api-baseline.json
ab43993cf713a96b191c55cf89bb215c18ecdc2d8edf50f31369ce3b162c56e3 plugin-sdk-api-baseline.jsonl

View File

@@ -40,11 +40,9 @@ Cron is the Gateway's built-in scheduler. It persists jobs, wakes the agent at t
## How cron works
- Cron runs **inside the Gateway** process (not inside the model).
- Job definitions persist at `~/.openclaw/cron/jobs.json` so restarts do not lose schedules.
- Runtime execution state persists next to it in `~/.openclaw/cron/jobs-state.json`. If you track cron definitions in git, track `jobs.json` and gitignore `jobs-state.json`.
- If `jobs.json` contains malformed rows, the Gateway keeps valid jobs running, removes the malformed rows from the active store, and saves the raw rows beside it in `jobs-quarantine.json` for later repair or review.
- After the split, older OpenClaw versions can read `jobs.json` but may treat jobs as fresh because runtime fields now live in `jobs-state.json`.
- When `jobs.json` is edited while the Gateway is running or stopped, OpenClaw compares the changed schedule fields with pending runtime slot metadata and clears stale `nextRunAtMs` values. Pure formatting or key-order-only rewrites preserve the pending slot.
- Job definitions, runtime state, and run history persist in OpenClaw's shared SQLite state database so restarts do not lose schedules.
- On upgrade, legacy `~/.openclaw/cron/jobs.json`, `jobs-state.json`, and `runs/*.jsonl` files are imported once and renamed with a `.migrated` suffix. Malformed job rows are skipped from runtime and copied to `jobs-quarantine.json` for later repair or review.
- `cron.store` still names the logical cron store key and legacy import path. After import, editing that JSON file no longer changes active cron jobs; use `openclaw cron add|edit|remove` or the Gateway cron RPC methods instead.
- All cron executions create [background task](/automation/tasks) records.
- On Gateway startup, overdue isolated agent-turn jobs are rescheduled out of the channel-connect window instead of replaying immediately, so Discord/Telegram startup and native-command setup stay responsive after restarts.
- One-shot jobs (`--at`) auto-delete after success by default.
@@ -462,9 +460,7 @@ Model override note:
`maxConcurrentRuns` limits both scheduled cron dispatch and isolated agent-turn execution, and defaults to 8. Isolated cron agent turns use the queue's dedicated `cron-nested` execution lane internally, so raising this value lets independent cron LLM runs progress in parallel instead of only starting their outer cron wrappers. The shared non-cron `nested` lane is not widened by this setting.
The runtime state sidecar is derived from `cron.store`: a `.json` store such as `~/clawd/cron/jobs.json` uses `~/clawd/cron/jobs-state.json`, while a store path without a `.json` suffix appends `-state.json`.
If you hand-edit `jobs.json`, leave `jobs-state.json` out of source control. OpenClaw uses that sidecar for pending slots, active markers, last-run metadata, and the schedule identity that tells the scheduler when an externally edited job needs a fresh `nextRunAtMs`.
`cron.store` is a logical store key and legacy import path. Existing stores are imported into SQLite on first load and archived; future cron changes should go through the CLI or Gateway API.
Disable cron: `cron.enabled: false` or `OPENCLAW_SKIP_CRON=1`.
@@ -476,7 +472,7 @@ Disable cron: `cron.enabled: false` or `OPENCLAW_SKIP_CRON=1`.
</Accordion>
<Accordion title="Maintenance">
`cron.sessionRetention` (default `24h`) prunes isolated run-session entries. `cron.runLog.maxBytes` / `cron.runLog.keepLines` auto-prune run-log files.
`cron.sessionRetention` (default `24h`) prunes isolated run-session entries. `cron.runLog.keepLines` limits retained SQLite run-history rows per job; `maxBytes` is retained for config compatibility with older file-backed run logs.
</Accordion>
</AccordionGroup>

View File

@@ -102,7 +102,7 @@ Not every agent run creates a task. Heartbeat turns and normal interactive chat
<Accordion title="Notify defaults for cron and media">
Main-session cron tasks use `silent` notify policy by default - they create records for tracking but do not generate notifications. Isolated cron tasks also default to `silent` but are more visible because they run in their own session.
Session-backed `image_generate`, `music_generate`, and `video_generate` runs also use `silent` notify policy. They still create task records, but completion is handed back to the original agent session as an internal wake so the agent can write the follow-up message and attach the finished media itself. Generated-media completion events require message-tool delivery: the agent must send the finished media with the `message` tool, then reply `NO_REPLY`. If the requester session is no longer active or its active wake fails, and the completion agent misses some or all generated media, OpenClaw sends an idempotent direct fallback with only the missing media to the original channel target.
Session-backed `image_generate`, `music_generate`, and `video_generate` runs also use `silent` notify policy. They still create task records, but completion is handed back to the original agent session as an internal wake so the agent can write the follow-up message and attach the finished media itself. The requester agent follows its normal visible-reply contract: automatic final reply when configured, or `message(action="send")` plus `NO_REPLY` when the session requires message-tool replies. If the requester session is no longer active or its active wake fails, and the completion agent misses some or all generated media, OpenClaw sends an idempotent direct fallback with only the missing media to the original channel target.
</Accordion>
<Accordion title="Concurrent media-generation guardrail">
@@ -346,7 +346,7 @@ A sweeper runs every **60 seconds** and handles four things:
</Accordion>
<Accordion title="Tasks and cron">
A cron job **definition** lives in `~/.openclaw/cron/jobs.json`; runtime execution state lives beside it in `~/.openclaw/cron/jobs-state.json`. **Every** cron execution creates a task record - both main-session and isolated. Main-session cron tasks default to `silent` notify policy so they track without generating notifications.
Cron job definitions, runtime execution state, and run history live in OpenClaw's shared SQLite state database. **Every** cron execution creates a task record - both main-session and isolated. Main-session cron tasks default to `silent` notify policy so they track without generating notifications.
See [Cron Jobs](/automation/cron-jobs).

View File

@@ -354,7 +354,7 @@ To restrict who can click a button, set `allowedUsers` on that button (Discord u
Component callbacks expire after 30 minutes by default. Set `channels.discord.agentComponents.ttlMs` to change that callback registry lifetime for the default Discord account, or `channels.discord.accounts.<accountId>.agentComponents.ttlMs` to override one account in a multi-account setup. The value is milliseconds, must be a positive integer, and is capped at `86400000` (24 hours). Longer TTLs are useful for review or approval workflows that need buttons to remain usable, but they also extend the window where an old Discord message can still trigger an action. Prefer the shortest TTL that fits the workflow, and keep the default when stale callbacks would be surprising.
The `/model` and `/models` slash commands open an interactive model picker with provider, model, and compatible runtime dropdowns plus a Submit step. `/models add` is deprecated and now returns a deprecation message instead of registering models from chat. The picker reply is ephemeral and only the invoking user can use it. Discord select menus are limited to 25 options, so add `provider/*` entries to `agents.defaults.models` when you want the picker to show dynamically discovered models only for selected providers such as `openai-codex` or `vllm`.
The `/model` and `/models` slash commands open an interactive model picker with provider, model, and compatible runtime dropdowns plus a Submit step. `/models add` is deprecated and now returns a deprecation message instead of registering models from chat. The picker reply is ephemeral and only the invoking user can use it. Discord select menus are limited to 25 options, so add `provider/*` entries to `agents.defaults.models` when you want the picker to show dynamically discovered models only for selected providers such as `openai` or `vllm`.
File attachments:
@@ -1197,7 +1197,7 @@ Auto-join example:
discord: {
voice: {
enabled: true,
model: "openai-codex/gpt-5.5",
model: "openai/gpt-5.5",
autoJoin: [
{
guildId: "123456789012345678",
@@ -1234,7 +1234,7 @@ Notes:
- `voice.followUsers` lets the bot join, move, and leave Discord voice with selected users. See [Follow users in voice](#follow-users-in-voice) for behavior rules and examples.
- `agent-proxy` routes speech through `discord-voice`, which preserves normal owner/tool authorization for the speaker and target session but hides the agent `tts` tool because Discord voice owns playback. By default, `agent-proxy` gives the consult full owner-equivalent tool access for owner speakers (`voice.realtime.toolPolicy: "owner"`) and strongly prefers consulting the OpenClaw agent before substantive answers (`voice.realtime.consultPolicy: "always"`). In that default `always` mode, the realtime layer does not auto-speak filler before the consult answer; it captures and transcribes speech, then speaks the routed OpenClaw answer. If multiple forced consult answers finish while Discord is still playing the first answer, later exact-speech answers are queued until playback idles instead of replacing speech mid-sentence.
- In `stt-tts` mode, STT uses `tools.media.audio`; `voice.model` does not affect transcription.
- In realtime modes, `voice.realtime.provider`, `voice.realtime.model`, and `voice.realtime.speakerVoice` configure the realtime audio session. For OpenAI Realtime 2 plus the Codex brain, use `voice.realtime.model: "gpt-realtime-2"` and `voice.model: "openai-codex/gpt-5.5"`.
- In realtime modes, `voice.realtime.provider`, `voice.realtime.model`, and `voice.realtime.speakerVoice` configure the realtime audio session. For OpenAI Realtime 2 plus the Codex brain, use `voice.realtime.model: "gpt-realtime-2"` and `voice.model: "openai/gpt-5.5"`.
- Realtime voice modes include small `IDENTITY.md`, `USER.md`, and `SOUL.md` profile files in the realtime provider instructions by default so fast direct turns keep the same identity, user grounding, and persona as the routed OpenClaw agent. Set `voice.realtime.bootstrapContextFiles` to a subset to customize this, or `[]` to disable it. The supported realtime bootstrap files are limited to those profile files; `AGENTS.md` stays in the normal agent context. The injected profile context does not replace `openclaw_agent_consult` for workspace work, current facts, memory lookup, or tool-backed actions.
- In OpenAI `agent-proxy` realtime mode, set `voice.realtime.requireWakeName: true` to keep Discord realtime voice silent until a transcript starts or ends with a wake name. Configured wake names must be one or two words. If `voice.realtime.wakeNames` is unset, OpenClaw uses the routed agent `name` plus `OpenClaw`, falling back to the agent id plus `OpenClaw`. Wake-name gating disables realtime provider auto-response, routes accepted turns through the OpenClaw agent consult path, and gives a short spoken acknowledgement when a leading wake name is recognized from partial transcription before the final transcript arrives.
- The OpenAI realtime provider accepts current Realtime 2 event names and legacy Codex-compatible aliases for output audio and transcript events, so compatible provider snapshots can drift without dropping assistant audio.
@@ -1325,7 +1325,7 @@ Default agent-proxy voice-channel session example:
discord: {
voice: {
enabled: true,
model: "openai-codex/gpt-5.5",
model: "openai/gpt-5.5",
followUsersEnabled: true,
followUsers: ["123456789012345678"],
realtime: {
@@ -1375,7 +1375,7 @@ Realtime bidi example:
voice: {
enabled: true,
mode: "bidi",
model: "openai-codex/gpt-5.5",
model: "openai/gpt-5.5",
realtime: {
provider: "openai",
model: "gpt-realtime-2",
@@ -1398,7 +1398,7 @@ Voice as an extension of an existing Discord channel session:
voice: {
enabled: true,
mode: "agent-proxy",
model: "openai-codex/gpt-5.5",
model: "openai/gpt-5.5",
agentSession: {
mode: "target",
target: "channel:123456789012345678",
@@ -1433,7 +1433,7 @@ Echo-heavy OpenAI Realtime example:
voice: {
enabled: true,
mode: "bidi",
model: "openai-codex/gpt-5.5",
model: "openai/gpt-5.5",
realtime: {
provider: "openai",
model: "gpt-realtime-2",

View File

@@ -915,9 +915,10 @@ Uploaded files are stored in a `/OpenClawShared/` folder in the configured Share
OpenClaw sends Teams polls as Adaptive Cards (there is no native Teams poll API).
- CLI: `openclaw message poll --channel msteams --target conversation:<id> ...`
- Votes are recorded by the gateway in `~/.openclaw/msteams-polls.json`.
- Votes are recorded by the gateway in OpenClaw plugin-state SQLite under `state/openclaw.sqlite`.
- Existing `msteams-polls.json` files are imported once when the MSTeams plugin starts.
- The gateway must stay online to record votes.
- Polls do not auto-post result summaries yet (inspect the store file if needed).
- Polls do not auto-post result summaries yet, and there is no supported poll-results CLI yet.
## Presentation cards

View File

@@ -118,7 +118,7 @@ Skipped runs are tracked separately from execution errors. They do not affect re
For isolated jobs that target a local configured model provider, cron runs a lightweight provider preflight before starting the agent turn. Loopback, private-network, and `.local` `api: "ollama"` providers are probed at `/api/tags`; local OpenAI-compatible providers such as vLLM, SGLang, and LM Studio are probed at `/models`. If the endpoint is unreachable, the run is recorded as `skipped` and retried on a later schedule; matching dead endpoints are cached for 5 minutes to avoid many jobs hammering the same local server.
Note: cron job definitions live in `jobs.json`, while pending runtime state lives in `jobs-state.json`. If `jobs.json` is edited externally, the Gateway reloads changed schedules and clears stale pending slots; formatting-only rewrites do not clear the pending slot. Malformed job rows are removed from active `jobs.json` at load time after their raw contents are copied to `jobs-quarantine.json`.
Note: cron jobs, pending runtime state, and run history live in the shared SQLite state database. Legacy `jobs.json`, `jobs-state.json`, and `runs/*.jsonl` files are imported once and renamed with a `.migrated` suffix. After import, edit schedules with `openclaw cron add|edit|remove` instead of editing JSON files.
### Manual runs
@@ -199,7 +199,7 @@ Cron does not classify final-output prose or approval-looking refusal phrases as
Retention and pruning are controlled in config:
- `cron.sessionRetention` (default `24h`) prunes completed isolated run sessions.
- `cron.runLog.maxBytes` and `cron.runLog.keepLines` prune `~/.openclaw/cron/runs/<jobId>.jsonl`.
- `cron.runLog.keepLines` prunes retained SQLite run-history rows per job. `cron.runLog.maxBytes` remains accepted for compatibility with older file-backed run logs.
## Migrating older jobs

View File

@@ -203,7 +203,7 @@ Notes:
- Doctor reports cron jobs with explicit `payload.model` overrides, including provider namespace counts and mismatches against `agents.defaults.model`, so scheduled jobs that do not inherit the default model are visible during auth or billing investigations.
- On Linux, doctor warns when the user's crontab still runs legacy `~/.openclaw/bin/ensure-whatsapp.sh`; that script is no longer maintained and can log false WhatsApp gateway outages when cron lacks the systemd user-bus environment.
- When WhatsApp is enabled, doctor checks for a degraded Gateway event loop with local `openclaw-tui` clients still running. `doctor --fix` stops only verified local TUI clients so WhatsApp replies are not queued behind stale TUI refresh loops.
- Doctor rewrites legacy `openai-codex/*` model refs to canonical `openai/*` refs across primary models, fallbacks, heartbeat/subagent/compaction overrides, hooks, channel model overrides, and stale session route pins. `--fix` moves Codex intent onto provider/model-scoped `agentRuntime.id: "codex"` entries, preserves session auth-profile pins such as `openai-codex:...`, removes stale whole-agent/session runtime pins, and keeps repaired OpenAI agent refs on Codex auth routing instead of direct OpenAI API-key auth.
- Doctor rewrites legacy `openai-codex/*` model refs to canonical `openai/*` refs across primary models, fallbacks, image/video generation models, heartbeat/subagent/compaction overrides, hooks, channel model overrides, and stale session route pins. `--fix` also migrates legacy `openai-codex:*` auth profiles and `auth.order.openai-codex` entries to `openai:*`, moves Codex intent onto provider/model-scoped `agentRuntime.id: "codex"` entries, removes stale whole-agent/session runtime pins, and keeps repaired OpenAI agent refs on Codex auth routing instead of direct OpenAI API-key auth.
- Doctor cleans legacy plugin dependency staging state created by older OpenClaw versions and relinks the host `openclaw` package for managed npm plugins that declare it as a peer dependency. It also repairs missing downloadable plugins that are referenced by config, such as `plugins.entries`, configured channels, configured provider/search settings, or configured agent runtimes. During package updates, doctor skips package-manager plugin repair until the package swap is complete; rerun `openclaw doctor --fix` afterward if a configured plugin still needs recovery. If the download fails, doctor reports the install error and preserves the configured plugin entry for the next repair attempt.
- Doctor repairs stale plugin config by removing missing plugin ids from `plugins.allow`/`plugins.deny`/`plugins.entries`, plus matching dangling channel config, heartbeat targets, and channel model overrides when plugin discovery is healthy.
- Doctor quarantines invalid plugin config by disabling the affected `plugins.entries.<id>` entry and removing its invalid `config` payload. Gateway startup already skips only that bad plugin so other plugins and channels can keep running.

View File

@@ -129,7 +129,7 @@ This table maps common inference tasks to the corresponding infer command.
- Use `model run --thinking <level>` to pass a one-shot thinking/reasoning level (`off`, `minimal`, `low`, `medium`, `high`, `adaptive`, `xhigh`, or `max`) while keeping the run raw.
- For `image describe`, `audio transcribe`, and `video describe`, `--model` must use the form `<provider/model>`.
- For `image describe`, `--file` accepts local paths and HTTP(S) image URLs. Remote URLs use the normal media-fetch SSRF policy.
- For `image describe`, an explicit `--model` runs that provider/model directly. The model must be image-capable in the model catalog or provider config. `codex/<model>` runs a bounded Codex app-server image-understanding turn; `openai-codex/<model>` uses the OpenAI Codex OAuth provider path.
- For `image describe`, an explicit `--model` runs that provider/model directly. The model must be image-capable in the model catalog or provider config. `codex/<model>` runs a bounded Codex app-server image-understanding turn; `openai/<model>` uses the OpenAI provider path with either API-key or ChatGPT/Codex OAuth auth.
- Stateless execution commands default to local.
- Gateway-managed state commands default to gateway.
- The normal local path does not require the gateway to be running.
@@ -172,7 +172,7 @@ Notes:
- Local `model run` is the narrowest CLI smoke for provider/model/auth health because, for non-Codex providers, it sends only the supplied prompt to the selected model.
- Local `model run --model <provider/model>` can use exact bundled static catalog rows from `models list --all` before that provider is written to config. Provider auth is still required; missing credentials fail as auth errors, not `Unknown model`.
- For Mistral Medium 3.5 reasoning probes, leave temperature unset/default. Mistral rejects `reasoning_effort="high"` plus `temperature: 0`; use `mistral/mistral-medium-3-5` with default temperature or a non-zero reasoning-mode value such as `0.7`.
- `openai-codex/*` local probes are the narrow exception: OpenClaw adds a minimal system instruction so the Codex Responses transport can populate its required `instructions` field, without adding full agent context, tools, memory, or session transcript.
- Codex Responses local probes are the narrow exception: OpenClaw adds a minimal system instruction so the transport can populate its required `instructions` field, without adding full agent context, tools, memory, or session transcript.
- Local `model run --file` keeps that lean path and attaches image content directly to the single user message. Common image files such as PNG, JPEG, and WebP work when their MIME type is detected as `image/*`; unsupported or unrecognized files fail before the provider is called.
- `model run --file` is best when you want to test the selected multimodal text model directly. Use `infer image describe` when you want OpenClaw's image-understanding provider selection and default image-model routing.
- The selected model must support image input; text-only models may reject the request at the provider layer.

View File

@@ -348,7 +348,8 @@ For broader testing context, see [Testing](/help/testing).
## OpenClaw as an MCP client registry
This is the `openclaw mcp list`, `show`, `set`, and `unset` path.
This is the `openclaw mcp list`, `show`, `status`, `probe`, `set`, `tools`,
and `unset` path.
These commands do not expose OpenClaw over MCP. They manage OpenClaw-owned MCP server definitions under `mcp.servers` in OpenClaw config.
@@ -357,10 +358,15 @@ Those saved definitions are for runtimes that OpenClaw launches or configures la
<AccordionGroup>
<Accordion title="Important behavior">
- these commands only read or write OpenClaw config
- they do not connect to the target MCP server
- `status`, `list`, `show`, `set`, `tools`, and `unset` do not connect to the target MCP server
- `probe` connects to the selected server or all configured servers, lists tools, and reports capabilities/diagnostics
- they do not validate whether the command, URL, or remote transport is reachable right now
- runtime adapters decide which transport shapes they actually support at execution time
- embedded OpenClaw exposes configured MCP tools in normal `coding` and `messaging` tool profiles; `minimal` still hides them, and `tools.deny: ["bundle-mcp"]` disables them explicitly
- per-server `toolFilter.include` and `toolFilter.exclude` filter discovered MCP tools before they become OpenClaw tools
- servers that advertise resources or prompts also expose utility tools for listing/reading resources and listing/fetching prompts; those generated utility names (`resources_list`, `resources_read`, `prompts_list`, `prompts_get`) use the same include/exclude filter
- dynamic MCP tool-list changes invalidate the cached catalog for that session; the next discovery/use refreshes from the server
- repeated MCP tool request/protocol failures pause that server briefly so one broken server does not consume the whole turn
- session-scoped bundled MCP runtimes are reaped after `mcp.sessionIdleTtlMs` milliseconds of idle time (default 10 minutes; set `0` to disable) and one-shot embedded runs clean them up at run end
</Accordion>
@@ -387,14 +393,20 @@ Commands:
- `openclaw mcp list`
- `openclaw mcp show [name]`
- `openclaw mcp status`
- `openclaw mcp probe [name]`
- `openclaw mcp set <name> <json>`
- `openclaw mcp tools <name> [--include csv] [--exclude csv] [--clear]`
- `openclaw mcp unset <name>`
Notes:
- `list` sorts server names.
- `show` without a name prints the full configured MCP server object.
- `status` classifies configured transports without connecting.
- `probe` connects and reports tool counts, resources/prompts support, list-change support, and diagnostics.
- `set` expects one JSON object value on the command line.
- `tools` updates per-server tool filters. Include/exclude entries are MCP tool names and simple `*` globs.
- Use `transport: "streamable-http"` for Streamable HTTP MCP servers. `openclaw mcp set` also normalizes CLI-native `type: "http"` to the same canonical config shape for compatibility.
- `unset` fails if the named server does not exist.
@@ -403,7 +415,10 @@ Examples:
```bash
openclaw mcp list
openclaw mcp show context7 --json
openclaw mcp status
openclaw mcp probe context7 --json
openclaw mcp set context7 '{"command":"uvx","args":["context7-mcp"]}'
openclaw mcp tools context7 --include 'resolve-library-id,get-library-docs'
openclaw mcp set docs '{"url":"https://mcp.example.com","transport":"streamable-http"}'
openclaw mcp unset context7
```
@@ -420,7 +435,11 @@ Example config shape:
},
"docs": {
"url": "https://mcp.example.com",
"transport": "streamable-http"
"transport": "streamable-http",
"toolFilter": {
"include": ["search_*"],
"exclude": ["admin_*"]
}
}
}
}

View File

@@ -28,8 +28,8 @@ openclaw models scan
`openclaw models status` shows the resolved default/fallbacks plus an auth overview.
When provider usage snapshots are available, the OAuth/API-key status section includes
provider usage windows and quota snapshots.
Current usage-window providers: Anthropic, GitHub Copilot, Gemini CLI, OpenAI
Codex, MiniMax, Xiaomi, and z.ai. Usage auth comes from provider-specific hooks
Current usage-window providers: Anthropic, GitHub Copilot, Gemini CLI, OpenAI,
MiniMax, Xiaomi, and z.ai. Usage auth comes from provider-specific hooks
when available; otherwise OpenClaw falls back to matching OAuth/API-key
credentials from auth profiles, env, or config.
In `--json` output, `auth.providers` is the env/config/store-aware provider
@@ -40,10 +40,10 @@ Use `--agent <id>` to inspect a configured agent's model/auth state. When omitte
the command uses `OPENCLAW_AGENT_DIR` if set, otherwise the
configured default agent.
Probe rows can come from auth profiles, env credentials, or `models.json`.
For Codex OAuth troubleshooting, `openclaw models status`,
`openclaw models auth list --provider openai-codex`, and
For OpenAI ChatGPT/Codex OAuth troubleshooting, `openclaw models status`,
`openclaw models auth list --provider openai`, and
`openclaw config get agents.defaults.model --json` are the quickest way to
confirm whether an agent has a usable `openai-codex` auth profile for
confirm whether an agent has a usable `openai` OAuth profile for
`openai/*` through the native Codex runtime. See [OpenAI provider setup](/providers/openai#check-and-recover-codex-oauth-routing).
Notes:
@@ -76,7 +76,7 @@ Notes:
cap differs from the native context window; JSON rows include `contextTokens`
when a provider exposes that cap.
- `models list --provider <id>` filters by provider id, such as `moonshot` or
`openai-codex`. It does not accept display labels from interactive provider
`openai`. It does not accept display labels from interactive provider
pickers, such as `Moonshot AI`.
- Model refs are parsed by splitting on the **first** `/`. If the model ID includes `/` (OpenRouter-style), include the provider prefix (example: `openrouter/moonshotai/kimi-k2`).
- If you omit the provider, OpenClaw resolves the input as an alias first, then
@@ -181,7 +181,7 @@ provider you choose.
`models auth list` lists saved auth profiles for the selected agent without
printing token, API-key, or OAuth secret material. Use `--provider <id>` to
filter to one provider, such as `openai-codex`, and `--json` for scripting.
filter to one provider, such as `openai`, and `--json` for scripting.
`models auth login` runs a provider plugin's auth flow (OAuth/API key). Use
`openclaw plugins list` to see which providers are installed.
@@ -192,15 +192,15 @@ specific configured agent store. The parent `--agent` flag is honored by
For OpenAI models, `--provider openai` defaults to ChatGPT/Codex account login.
Use `--method api-key` only when you want to add an OpenAI API-key profile,
usually as a backup for Codex subscription limits. The legacy
`--provider openai-codex` spelling still works for existing scripts.
usually as a backup for Codex subscription limits. Run `openclaw doctor --fix`
to migrate older `openai-codex` auth/profile state to `openai`.
Examples:
```bash
openclaw models auth login --provider openai --set-default
openclaw models auth login --provider openai --method api-key
openclaw models auth paste-api-key --provider openai-codex
openclaw models auth paste-api-key --provider openai
openclaw models auth list --provider openai
```
@@ -212,7 +212,7 @@ Notes:
- `paste-api-key` accepts API keys generated elsewhere, prompts for the key
value, and writes it to the default profile id `<provider>:manual` unless you
pass `--profile-id`. In automation, pipe the key on stdin, for example
`printf "%s\n" "$OPENAI_API_KEY" | openclaw models auth paste-api-key --provider openai-codex`.
`printf "%s\n" "$OPENAI_API_KEY" | openclaw models auth paste-api-key --provider openai`.
- `setup-token` and `paste-token` remain generic token commands for providers
that expose token auth methods.
- `setup-token` requires an interactive TTY and runs the provider's token-auth
@@ -226,7 +226,7 @@ Notes:
provider credentials do not appear in shell history or process lists.
- `paste-token --expires-in <duration>` stores an absolute token expiry from a
relative duration such as `365d` or `12h`.
- For `openai-codex`, OpenAI API keys and ChatGPT/OAuth token material are
- For `openai`, OpenAI API keys and ChatGPT/OAuth token material are
different auth shapes. Use `paste-api-key` for `sk-...` OpenAI API keys and
`paste-token` only for token auth material.
- Anthropic note: Anthropic staff told us OpenClaw-style Claude CLI usage is allowed again, so OpenClaw treats Claude CLI reuse and `claude -p` usage as sanctioned for this integration unless Anthropic publishes a new policy.

View File

@@ -326,6 +326,8 @@ Use `--link` to avoid copying a local directory (adds to `plugins.load.paths`):
openclaw plugins install -l ./my-plugin
```
Standalone plugin files must be listed in `plugins.load.paths` rather than placed directly in `~/.openclaw/extensions` or `<workspace>/.openclaw/extensions`. Those auto-discovered roots load plugin package or bundle directories, while top-level script files are treated as local helpers and skipped.
<Note>
`--force` is not supported with `--link` because linked installs reuse the source path instead of copying over a managed install target.

View File

@@ -47,6 +47,20 @@ Scope selection:
- `--store <path>`: explicit store path (cannot be combined with `--agent` or `--all-agents`)
- `--limit <n|all>`: max rows to output (default `100`; `all` restores full output)
Tail human-readable trajectory progress for stored sessions:
```bash
openclaw sessions tail
openclaw sessions tail --follow
openclaw sessions tail --session-key "agent:main:telegram:direct:123" --tail 25
openclaw sessions --agent work tail --follow
openclaw sessions --all-agents tail --follow
```
`openclaw sessions tail` renders recent trajectory JSONL events as compact progress lines. Without `--session-key`, it tails running sessions first, then the latest stored session. `--tail <count>` controls how many existing events print before follow mode; the default is `80`, and `0` starts at the current end. `--follow` keeps watching the selected trajectory files, including relocated files referenced by `<session>.trajectory-path.json`.
The progress view is intentionally conservative: prompt text, tool arguments, and tool result bodies are not printed. Tool calls show the tool name with `{...redacted...}`; tool results show status such as `ok`, `error`, or `done`; model completion lines show provider/model and terminal status.
Export a trajectory bundle for a stored session:
```bash
@@ -104,7 +118,7 @@ openclaw sessions cleanup --json
`openclaw sessions cleanup` uses `session.maintenance` settings from config:
- Scope note: `openclaw sessions cleanup` maintains session stores, transcripts, and trajectory sidecars. It does not prune cron run logs (`cron/runs/<jobId>.jsonl`), which are managed by `cron.runLog.maxBytes` and `cron.runLog.keepLines` in [Cron configuration](/automation/cron-jobs#configuration) and explained in [Cron maintenance](/automation/cron-jobs#maintenance).
- Scope note: `openclaw sessions cleanup` maintains session stores, transcripts, and trajectory sidecars. It does not prune cron run history, which is managed by `cron.runLog.keepLines` in [Cron configuration](/automation/cron-jobs#configuration) and explained in [Cron maintenance](/automation/cron-jobs#maintenance).
- Cleanup also prunes unreferenced primary transcripts, compaction checkpoints, and trajectory sidecars older than `session.maintenance.pruneAfter`; files still referenced by `sessions.json` are preserved.
- `--dry-run`: preview how many entries would be pruned/capped without writing.

View File

@@ -1,5 +1,5 @@
---
summary: "CLI reference for `openclaw skills` (search/install/update/verify/list/info/check)"
summary: "CLI reference for `openclaw skills` (search/install/update/verify/list/info/check/workshop)"
read_when:
- You want to see which skills are available and ready to run
- You want to search ClawHub or install skills from ClawHub, Git, or local directories
@@ -53,6 +53,14 @@ openclaw skills info <name> --agent <id>
openclaw skills check
openclaw skills check --agent <id>
openclaw skills check --json
openclaw skills workshop propose-create --name "qa-check" --description "QA checklist" --proposal ./PROPOSAL.md
openclaw skills workshop propose-update qa-check --proposal ./PROPOSAL.md
openclaw skills workshop list
openclaw skills workshop inspect <proposal-id>
openclaw skills workshop revise <proposal-id> --proposal ./PROPOSAL.md
openclaw skills workshop apply <proposal-id>
openclaw skills workshop reject <proposal-id> --reason "Not reusable"
openclaw skills workshop quarantine <proposal-id> --reason "Needs security review"
```
`search`, `update`, and `verify` use ClawHub directly. `install <slug>` installs
@@ -116,6 +124,76 @@ Notes:
`--json`, that means the machine-readable payload stays on stdout for pipes
and scripts.
## Skill Workshop proposals
`openclaw skills workshop` manages pending skill proposals in the selected
workspace. Proposals are durable OpenClaw state under
`<OPENCLAW_STATE_DIR>/skill-workshop/proposals/`; they are not active skills
until applied. The default state directory is `~/.openclaw`. Proposal bodies
honor `skills.workshop.maxSkillBytes`, and proposal descriptions are capped at
160 bytes because they can appear in discovery and listing output.
Create a proposal from a draft markdown file:
```bash
openclaw skills workshop propose-create \
--name "qa-check" \
--description "Repeatable QA checklist" \
--proposal ./PROPOSAL.md
```
Or create a proposal from a full draft skill directory:
```bash
openclaw skills workshop propose-create \
--name "qa-check" \
--description "Repeatable QA checklist" \
--proposal-dir ./qa-check-proposal
```
Update an existing workspace skill through the same pending path:
```bash
openclaw skills workshop propose-update qa-check --proposal ./PROPOSAL.md
```
Revise a pending proposal before approval:
```bash
openclaw skills workshop revise <proposal-id> --proposal ./PROPOSAL.md
```
The supplied draft is stored as `PROPOSAL.md` with proposal-only frontmatter:
```markdown
---
name: qa-check
description: Repeatable QA checklist
status: proposal
version: v1
date: "2026-05-30T00:00:00.000Z"
---
```
Applying a proposal writes the active `SKILL.md` into the workspace `skills/`
root, strips `status`, proposal `version`, and proposal `date` from the
frontmatter, scans the draft, writes rollback metadata, and refuses stale
updates when the target skill changed after the proposal was created.
When `--proposal-dir` is used, the directory must contain `PROPOSAL.md`.
Support files can be included under `assets/`, `examples/`, `references/`,
`scripts/`, or `templates/`. OpenClaw stores support files with the proposal,
scans them, verifies their hashes before apply, and writes them beside the
active `SKILL.md` only after the proposal is applied.
Agents can create, revise, list, and inspect pending proposals through the
`skill_workshop` tool when the user asks for reusable work to be captured.
Autonomous proposal capture from durable conversation signals is off by
default and is enabled with `skills.workshop.autonomous.enabled`. If the user
explicitly asks to approve/use/apply, reject, or quarantine a specific
proposal, `skill_workshop` can also perform that proposal lifecycle action
through the same Skill Workshop safeguards.
## Related
- [CLI reference](/cli)

View File

@@ -43,6 +43,7 @@ Notes:
- Local mode uses the embedded agent runtime directly. Most local tools work, but Gateway-only features are unavailable.
- Local mode adds `/auth [provider]` inside the TUI command surface.
- Plugin approval gates still apply in local mode. Tools that require approval prompt for a decision in the terminal; nothing is silently auto-approved because the Gateway is not involved.
- Session [goals](/tools/goal) appear in the footer and can be managed with `/goal`.
## Examples
@@ -87,3 +88,4 @@ rerun `openclaw config validate`. See [TUI](/web/tui) and [Config](/cli/config).
- [CLI reference](/cli)
- [TUI](/web/tui)
- [Goal](/tools/goal)

View File

@@ -16,7 +16,7 @@ configuration. They are different layers:
| Layer | Examples | What it means |
| ------------- | -------------------------------------------- | ------------------------------------------------------------------- |
| Provider | `openai`, `anthropic`, `openai-codex` | How OpenClaw authenticates, discovers models, and names model refs. |
| Provider | `openai`, `anthropic`, `github-copilot` | How OpenClaw authenticates, discovers models, and names model refs. |
| Model | `gpt-5.5`, `claude-opus-4-6` | The model selected for the agent turn. |
| Agent runtime | `openclaw`, `codex`, `copilot`, `claude-cli` | The low level loop or backend that executes the prepared turn. |
| Channel | Telegram, Discord, Slack, WhatsApp | Where messages enter and leave OpenClaw. |
@@ -40,7 +40,7 @@ There are two runtime families:
model, execute through Claude CLI." `claude-cli` is not an embedded harness id
and must not be passed to AgentHarness selection.
The `copilot` harness is a separate, opt-in plugin harness for the
The `copilot` harness is a separate, opt-in external plugin harness for the
GitHub Copilot CLI; see [GitHub Copilot agent runtime](/plugins/copilot)
for the user-facing decision between PI, Codex, and GitHub Copilot agent runtime.
@@ -51,7 +51,7 @@ Most confusion comes from several different surfaces sharing the Codex name:
| Surface | OpenClaw name/config | What it does |
| ------------------------------------------------ | ------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
| Native Codex app-server runtime | `openai/*` model refs | Runs OpenAI embedded agent turns through Codex app-server. This is the usual ChatGPT/Codex subscription setup. |
| Codex OAuth auth profiles | `openai-codex` auth provider | Stores ChatGPT/Codex subscription auth that the Codex app-server harness consumes. |
| Codex OAuth auth profiles | `openai` OAuth profiles | Stores ChatGPT/Codex subscription auth that the Codex app-server harness consumes. |
| Codex ACP adapter | `runtime: "acp"`, `agentId: "codex"` | Runs Codex through the external ACP/acpx control plane. Use only when ACP/acpx is explicitly asked. |
| Native Codex chat-control command set | `/codex ...` | Binds, resumes, steers, stops, and inspects Codex app-server threads from chat. |
| OpenAI Platform API route for non-agent surfaces | `openai/*` plus API-key auth | Used for direct OpenAI APIs such as images, embeddings, speech, and realtime. |
@@ -95,7 +95,7 @@ This is the agent-facing decision tree:
subscription-backed Codex agent experience, use `openai/<model>`.
3. If the user explicitly chooses **OpenClaw for an OpenAI model**, keep the model ref
as `openai/<model>` and set provider/model runtime policy to
`agentRuntime.id: "openclaw"`. A selected `openai-codex` auth profile is routed
`agentRuntime.id: "openclaw"`. A selected `openai` OAuth profile is routed
internally through OpenClaw's Codex-auth transport.
4. If legacy config still contains **`openai-codex/*` model refs**, repair it to
`openai/<model>` with `openclaw doctor --fix`; doctor keeps the Codex auth
@@ -112,7 +112,7 @@ This is the agent-facing decision tree:
| --------------------------------------- | -------------------------------------------- |
| Codex app-server chat/thread control | `/codex ...` from the bundled `codex` plugin |
| Codex app-server embedded agent runtime | `openai/*` agent model refs |
| OpenAI Codex OAuth | `openai-codex` auth profiles |
| OpenAI Codex OAuth | `openai` OAuth profiles |
| Claude Code or other external harness | ACP/acpx |
For the OpenAI-family prefix split, see [OpenAI](/providers/openai) and
@@ -196,7 +196,7 @@ backend.
`auto` mode is intentionally conservative for most providers. OpenAI agent
models are the exception: unset runtime and `auto` both resolve to the Codex
harness. Explicit OpenClaw runtime config remains an opt-in compatibility route for
`openai/*` agent turns; when paired with a selected `openai-codex` auth profile,
`openai/*` agent turns; when paired with a selected `openai` OAuth profile,
OpenClaw routes that path internally through the Codex-auth transport while
keeping the public model ref as `openai/*`. Stale OpenAI runtime session pins are
ignored by runtime selection and can be cleaned with `openclaw doctor --fix`.
@@ -207,7 +207,7 @@ If `openclaw doctor` warns that the `codex` plugin is enabled while
## GitHub Copilot agent runtime
The bundled `copilot` extension registers an opt-in `copilot` runtime
The external `@openclaw/copilot` plugin registers an opt-in `copilot` runtime
backed by the GitHub Copilot CLI (`@github/copilot-sdk`). It claims the
canonical subscription `github-copilot` provider and is **never** selected by
`auto`. Opt in per-model or per-provider via `agentRuntime.id`:

View File

@@ -127,7 +127,7 @@ See [Sandboxing](/gateway/sandboxing) and [Multi-Agent Sandbox & Tools](/tools/m
Configure logging before the delegate handles any real data:
- Cron run history: `~/.openclaw/cron/runs/<jobId>.jsonl`
- Cron run history: OpenClaw shared SQLite state database
- Session transcripts: `~/.openclaw/agents/delegate/sessions`
- Identity provider audit logs (Exchange, Google Workspace)

View File

@@ -30,7 +30,7 @@ Treat them differently from normal config:
## Local model lean mode
`agents.defaults.experimental.localModelLean: true` is a pressure-release valve for weaker local-model setups. When it is on, OpenClaw drops three default tools — `browser`, `cron`, and `message` — from the model-visible tool surface for every turn. When Code Mode or Tool Search is enabled, those tools can still stay in the hidden catalog behind the compact controls. Use `agents.list[].experimental.localModelLean` to enable or disable the same behavior for one configured agent.
`agents.defaults.experimental.localModelLean: true` is a pressure-release valve for weaker local-model setups. When it is on, OpenClaw drops three default tools — `browser`, `cron`, and `message` — from the agent's tool surface for every turn. Nothing else changes. Use `agents.list[].experimental.localModelLean` to enable or disable the same behavior for one configured agent.
### Why these three tools
@@ -40,7 +40,7 @@ These three tools have the largest descriptions and the most parameter shapes in
- The model picking the right tool vs. emitting malformed tool calls because there are too many similar-looking schemas.
- The Chat Completions adapter staying inside the server's structured-output limits vs. tripping a 400 on tool-call payload size.
Removing them does not silently rewire OpenClaw — it just makes the visible tool list shorter. The model still has `read`, `write`, `edit`, `exec`, `apply_patch`, web search/fetch (when configured), memory, and session/agent tools available. With Code Mode or Tool Search, the compact control can still search for and call hidden catalog tools that policy allowed for the run.
Removing them does not silently rewire OpenClaw — it just makes the tool list shorter. The model still has `read`, `write`, `edit`, `exec`, `apply_patch`, web search/fetch (when configured), memory, and session/agent tools available.
### When to turn it on
@@ -94,7 +94,7 @@ Restart the Gateway after changing the flag, then confirm the trimmed tool list
openclaw status --deep
```
The deep status output lists the active model-visible agent tools; `browser`, `cron`, and `message` should be absent when lean mode is on. If Code Mode or Tool Search is enabled, they may still be available through the hidden catalog.
The deep status output lists the active agent tools; `browser`, `cron`, and `message` should be absent when lean mode is on.
## Experimental does not mean hidden

View File

@@ -156,15 +156,14 @@ Use `auth.order.openai` for the user-facing order:
{
auth: {
order: {
openai: ["openai-codex:user@example.com", "openai:api-key-backup"],
openai: ["openai:user@example.com", "openai:api-key-backup"],
},
},
}
```
Existing Codex subscription profiles may still use the legacy
`openai-codex:*` profile id. The ordered API-key backup can be a normal
`openai:*` API-key profile. When the subscription hits a Codex usage limit,
Use `openai:*` for both ChatGPT/Codex OAuth profiles and OpenAI API-key
profiles. When the subscription hits a Codex usage limit,
OpenClaw records the exact reset time when Codex provides one, tries the next
ordered auth profile, and keeps the run inside the Codex harness. Once the reset
time passes, the subscription profile is eligible again and the next automatic

View File

@@ -130,24 +130,24 @@ Anthropic staff told us OpenClaw-style Claude CLI usage is allowed again, so Ope
}
```
### OpenAI Codex OAuth
### OpenAI ChatGPT/Codex OAuth
- Provider: `openai-codex`
- Provider: `openai`
- Auth: OAuth (ChatGPT)
- Legacy OpenAI Codex model ref: `openai-codex/gpt-5.5`
- Legacy OpenAI Codex model ref: `openai/gpt-5.5`
- Native Codex app-server harness ref: `openai/gpt-5.5`
- Native Codex app-server harness docs: [Codex harness](/plugins/codex-harness)
- Legacy model refs: `codex/gpt-*`
- Plugin boundary: `openai-codex/*` loads the OpenAI plugin; the native Codex app-server plugin is selected only by the Codex harness runtime or legacy `codex/*` refs.
- CLI: `openclaw onboard --auth-choice openai-codex` or `openclaw models auth login --provider openai-codex`
- Plugin boundary: `openai/*` loads the OpenAI plugin; the native Codex app-server plugin is selected by the Codex harness runtime.
- CLI: `openclaw onboard --auth-choice openai` or `openclaw models auth login --provider openai`
- Default transport is `auto` (WebSocket-first, SSE fallback)
- Override per OpenAI Codex model via `agents.defaults.models["openai-codex/<model>"].params.transport` (`"sse"`, `"websocket"`, or `"auto"`)
- Override per OpenAI Codex model via `agents.defaults.models["openai/<model>"].params.transport` (`"sse"`, `"websocket"`, or `"auto"`)
- `params.serviceTier` is also forwarded on native Codex Responses requests (`chatgpt.com/backend-api`)
- Hidden OpenClaw attribution headers (`originator`, `version`, `User-Agent`) are only attached on native Codex traffic to `chatgpt.com/backend-api`, not generic OpenAI-compatible proxies
- Shares the same `/fast` toggle and `params.fastMode` config as direct `openai/*`; OpenClaw maps that to `service_tier=priority`
- `openai-codex/gpt-5.5` uses the Codex catalog native `contextWindow = 400000` and default runtime `contextTokens = 272000`; override the runtime cap with `models.providers.openai-codex.models[].contextTokens`
- `openai/gpt-5.5` uses the Codex catalog native `contextWindow = 400000` and default runtime `contextTokens = 272000`; override the runtime cap with `models.providers.openai.models[].contextTokens`
- Policy note: OpenAI Codex OAuth is explicitly supported for external tools/workflows like OpenClaw.
- For the common subscription plus native Codex runtime route, sign in with `openai-codex` auth but configure `openai/gpt-5.5`; OpenAI agent turns select Codex by default.
- For the common subscription plus native Codex runtime route, sign in with `openai` auth and configure `openai/gpt-5.5`; OpenAI agent turns select Codex by default.
- Use provider/model `agentRuntime.id: "openclaw"` only when you want the built-in OpenClaw route; otherwise keep `openai/gpt-5.5` on the default Codex harness.
- `openai-codex/gpt-*` refs remain a legacy OpenAI Codex route. Prefer `openai/gpt-5.5` on the native Codex runtime for new agent config, and run `openclaw doctor --fix` when you want to migrate old `openai-codex/*` refs to canonical `openai/*` refs.
@@ -166,7 +166,7 @@ Anthropic staff told us OpenClaw-style Claude CLI usage is allowed again, so Ope
{
models: {
providers: {
"openai-codex": {
openai: {
models: [{ id: "gpt-5.5", contextTokens: 160000 }],
},
},
@@ -290,32 +290,36 @@ See [/providers/kilocode](/providers/kilocode) for setup details.
### Other bundled provider plugins
| Provider | Id | Auth env | Example model |
| ----------------------- | -------------------------------- | ------------------------------------------------------------ | -------------------------------------------------- |
| BytePlus | `byteplus` / `byteplus-plan` | `BYTEPLUS_API_KEY` | `byteplus-plan/ark-code-latest` |
| Cerebras | `cerebras` | `CEREBRAS_API_KEY` | `cerebras/zai-glm-4.7` |
| Cloudflare AI Gateway | `cloudflare-ai-gateway` | `CLOUDFLARE_AI_GATEWAY_API_KEY` | - |
| DeepInfra | `deepinfra` | `DEEPINFRA_API_KEY` | `deepinfra/deepseek-ai/DeepSeek-V4-Flash` |
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek/deepseek-v4-flash` |
| GitHub Copilot | `github-copilot` | `COPILOT_GITHUB_TOKEN` / `GH_TOKEN` / `GITHUB_TOKEN` | - |
| Groq | `groq` | `GROQ_API_KEY` | - |
| Hugging Face Inference | `huggingface` | `HUGGINGFACE_HUB_TOKEN` or `HF_TOKEN` | `huggingface/deepseek-ai/DeepSeek-R1` |
| Kilo Gateway | `kilocode` | `KILOCODE_API_KEY` | `kilocode/kilo/auto` |
| Kimi Coding | `kimi` | `KIMI_API_KEY` or `KIMICODE_API_KEY` | `kimi/kimi-for-coding` |
| MiniMax | `minimax` / `minimax-portal` | `MINIMAX_API_KEY` / `MINIMAX_OAUTH_TOKEN` | `minimax/MiniMax-M2.7` |
| Mistral | `mistral` | `MISTRAL_API_KEY` | `mistral/mistral-large-latest` |
| Moonshot | `moonshot` | `MOONSHOT_API_KEY` | `moonshot/kimi-k2.6` |
| NVIDIA | `nvidia` | `NVIDIA_API_KEY` | `nvidia/nvidia/nemotron-3-super-120b-a12b` |
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` | `openrouter/auto` |
| Qianfan | `qianfan` | `QIANFAN_API_KEY` | `qianfan/deepseek-v3.2` |
| Qwen Cloud | `qwen` | `QWEN_API_KEY` / `MODELSTUDIO_API_KEY` / `DASHSCOPE_API_KEY` | `qwen/qwen3.5-plus` |
| StepFun | `stepfun` / `stepfun-plan` | `STEPFUN_API_KEY` | `stepfun/step-3.5-flash` |
| Together | `together` | `TOGETHER_API_KEY` | `together/meta-llama/Llama-3.3-70B-Instruct-Turbo` |
| Venice | `venice` | `VENICE_API_KEY` | - |
| Vercel AI Gateway | `vercel-ai-gateway` | `AI_GATEWAY_API_KEY` | `vercel-ai-gateway/anthropic/claude-opus-4.6` |
| Volcano Engine (Doubao) | `volcengine` / `volcengine-plan` | `VOLCANO_ENGINE_API_KEY` | `volcengine-plan/ark-code-latest` |
| xAI | `xai` | SuperGrok/X Premium OAuth or `XAI_API_KEY` | `xai/grok-4.3` |
| Xiaomi | `xiaomi` | `XIAOMI_API_KEY` | `xiaomi/mimo-v2-flash` |
| Provider | Id | Auth env | Example model |
| --------------------------------------- | -------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------- |
| BytePlus | `byteplus` / `byteplus-plan` | `BYTEPLUS_API_KEY` | `byteplus-plan/ark-code-latest` |
| Cerebras | `cerebras` | `CEREBRAS_API_KEY` | `cerebras/zai-glm-4.7` |
| Cloudflare AI Gateway | `cloudflare-ai-gateway` | `CLOUDFLARE_AI_GATEWAY_API_KEY` | - |
| DeepInfra | `deepinfra` | `DEEPINFRA_API_KEY` | `deepinfra/deepseek-ai/DeepSeek-V4-Flash` |
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek/deepseek-v4-flash` |
| GitHub Copilot | `github-copilot` | `COPILOT_GITHUB_TOKEN` / `GH_TOKEN` / `GITHUB_TOKEN` | - |
| GMI Cloud | `gmi` | `GMI_API_KEY` | `gmi/google/gemini-3.1-flash-lite` |
| Groq | `groq` | `GROQ_API_KEY` | - |
| Hugging Face Inference | `huggingface` | `HUGGINGFACE_HUB_TOKEN` or `HF_TOKEN` | `huggingface/deepseek-ai/DeepSeek-R1` |
| Kilo Gateway | `kilocode` | `KILOCODE_API_KEY` | `kilocode/kilo/auto` |
| Kimi Coding | `kimi` | `KIMI_API_KEY` or `KIMICODE_API_KEY` | `kimi/kimi-for-coding` |
| MiniMax | `minimax` / `minimax-portal` | `MINIMAX_API_KEY` / `MINIMAX_OAUTH_TOKEN` | `minimax/MiniMax-M2.7` |
| Mistral | `mistral` | `MISTRAL_API_KEY` | `mistral/mistral-large-latest` |
| Moonshot | `moonshot` | `MOONSHOT_API_KEY` | `moonshot/kimi-k2.6` |
| NVIDIA | `nvidia` | `NVIDIA_API_KEY` | `nvidia/nvidia/nemotron-3-super-120b-a12b` |
| NovitaAI | `novita` | `NOVITA_API_KEY` | `novita/deepseek/deepseek-v3-0324` |
| [Ollama Cloud](/providers/ollama-cloud) | `ollama-cloud` | `OLLAMA_API_KEY` | `ollama-cloud/kimi-k2.6` |
| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` | `openrouter/auto` |
| Qianfan | `qianfan` | `QIANFAN_API_KEY` | `qianfan/deepseek-v3.2` |
| Qwen Cloud | `qwen` | `QWEN_API_KEY` / `MODELSTUDIO_API_KEY` / `DASHSCOPE_API_KEY` | `qwen/qwen3.5-plus` |
| [Qwen OAuth](/providers/qwen-oauth) | `qwen-oauth` | `QWEN_API_KEY` | `qwen-oauth/qwen3.5-plus` |
| StepFun | `stepfun` / `stepfun-plan` | `STEPFUN_API_KEY` | `stepfun/step-3.5-flash` |
| Together | `together` | `TOGETHER_API_KEY` | `together/meta-llama/Llama-3.3-70B-Instruct-Turbo` |
| Venice | `venice` | `VENICE_API_KEY` | - |
| Vercel AI Gateway | `vercel-ai-gateway` | `AI_GATEWAY_API_KEY` | `vercel-ai-gateway/anthropic/claude-opus-4.6` |
| Volcano Engine (Doubao) | `volcengine` / `volcengine-plan` | `VOLCANO_ENGINE_API_KEY` | `volcengine-plan/ark-code-latest` |
| xAI | `xai` | SuperGrok/X Premium OAuth or `XAI_API_KEY` | `xai/grok-4.3` |
| Xiaomi | `xiaomi` / `xiaomi-token-plan` | `XIAOMI_API_KEY` / `XIAOMI_TOKEN_PLAN_API_KEY` | `xiaomi/mimo-v2-flash` / `xiaomi-token-plan/mimo-v2.5-pro` |
#### Quirks worth knowing

View File

@@ -23,7 +23,7 @@ sidebarTitle: "Models CLI"
</Card>
</CardGroup>
Model refs choose a provider and model. They do not usually choose the low-level agent runtime. OpenAI agent refs are the main exception: `openai/gpt-5.5` runs through the Codex app-server runtime by default on the official OpenAI provider. Subscription Copilot refs (`github-copilot/*`) can additionally be opted into the bundled GitHub Copilot agent runtime — that path stays explicit (no `auto` fallback). Explicit runtime overrides belong on provider/model policy, not on the whole agent or session. In Codex runtime mode, the `openai/gpt-*` ref does not imply API-key billing; auth can come from a Codex account or `openai-codex` auth profile. See [Agent runtimes](/concepts/agent-runtimes) and [GitHub Copilot agent runtime](/plugins/copilot).
Model refs choose a provider and model. They do not usually choose the low-level agent runtime. OpenAI agent refs are the main exception: `openai/gpt-5.5` runs through the Codex app-server runtime by default on the official OpenAI provider. Subscription Copilot refs (`github-copilot/*`) can additionally be opted into the external GitHub Copilot agent runtime plugin — that path stays explicit (no `auto` fallback). Explicit runtime overrides belong on provider/model policy, not on the whole agent or session. In Codex runtime mode, the `openai/gpt-*` ref does not imply API-key billing; auth can come from a Codex account or `openai` OAuth profile. See [Agent runtimes](/concepts/agent-runtimes) and [GitHub Copilot agent runtime](/plugins/copilot).
## How model selection works
@@ -150,7 +150,7 @@ If you want to limit providers without manually listing every model, add
agents: {
defaults: {
models: {
"openai-codex/*": {},
"openai/*": {},
"vllm/*": {},
},
},

View File

@@ -45,7 +45,7 @@ To reduce that, OpenClaw treats `auth-profiles.json` as a **token sink**:
- the runtime reads credentials from **one place**
- we can keep multiple profiles and route them deterministically
- external CLI reuse is provider-specific: Codex CLI can bootstrap an empty
`openai-codex:default` profile, but once OpenClaw has a local OAuth profile,
`openai:default` profile, but once OpenClaw has a local OAuth profile,
the local refresh token is canonical. If that local refresh token is rejected,
OpenClaw can use a usable same-account Codex CLI token as a runtime-only
fallback; other integrations can remain externally managed and re-read their
@@ -131,7 +131,7 @@ Flow shape (PKCE):
5. exchange at `https://auth.openai.com/oauth/token`
6. extract `accountId` from the access token and store `{ access, refresh, expires, accountId }`
Wizard path is `openclaw onboard` → auth choice `openai-codex`.
Wizard path is `openclaw onboard` → auth choice `openai`.
## Refresh + expiry
@@ -147,7 +147,7 @@ At runtime:
- exception: some external CLI credentials stay externally managed; OpenClaw
re-reads those CLI auth stores instead of spending copied refresh tokens.
Codex CLI bootstrap is intentionally narrower: it seeds an empty
`openai-codex:default` profile, then OpenClaw-owned refreshes keep the local
`openai:default` profile, then OpenClaw-owned refreshes keep the local
profile canonical. If the local Codex refresh fails and Codex CLI has a
usable token for the same account, OpenClaw may use that token for the current
runtime request without writing it back to `auth-profiles.json`.

View File

@@ -266,6 +266,10 @@ The doctor checks Convex broker env, validates endpoint settings, and verifies a
Live transport lanes share one contract instead of each inventing their own scenario list shape. `qa-channel` is the broad synthetic product-behavior suite and is not part of the live transport coverage matrix.
Live transport runners should import the shared scenario ids, baseline
coverage helpers, and scenario-selection helper from
`openclaw/plugin-sdk/qa-live-transport-scenarios`.
| Lane | Canary | Mention gating | Bot-to-bot | Allowlist block | Top-level reply | Restart resume | Thread follow-up | Thread isolation | Reaction observation | Help command | Native command registration |
| -------- | ------ | -------------- | ---------- | --------------- | --------------- | -------------- | ---------------- | ---------------- | -------------------- | ------------ | --------------------------- |
| Matrix | x | x | x | x | x | x | x | x | x | | |

View File

@@ -181,12 +181,14 @@ prompt surface that matches their lifetime:
On the native Codex harness, OpenClaw avoids repeating stable workspace files
in every user turn. Codex loads `AGENTS.md` through its own project-doc
discovery. `SOUL.md`, `IDENTITY.md`, `TOOLS.md`, and `USER.md` are forwarded as
Codex developer instructions. `HEARTBEAT.md` content is not injected; heartbeat
turns get a collaboration-mode note pointing to the file when it exists and is
non-empty. `MEMORY.md` content from the configured agent workspace is not pasted
into every native Codex turn; when memory tools are available for that workspace,
Codex turns get a small workspace-memory note and should use `memory_search` or
`memory_get` when durable memory is relevant. If tools are disabled, memory
Codex developer instructions. The compact OpenClaw skills list is also forwarded
as turn-scoped collaboration developer instructions. `HEARTBEAT.md` content is
not injected; heartbeat turns get a collaboration-mode note pointing to the file
when it exists and is non-empty. `MEMORY.md` content from the configured agent
workspace is not pasted into every native Codex turn; when memory tools are
available for that workspace, Codex turns get a small workspace-memory note in
turn-scoped collaboration developer instructions and should use `memory_search`
or `memory_get` when durable memory is relevant. If tools are disabled, memory
search is unavailable, or the active workspace differs from the agent memory
workspace, `MEMORY.md` falls back to the normal bounded turn-context path. Active
`BOOTSTRAP.md` content keeps the normal turn-context role for now.
@@ -258,6 +260,11 @@ prompt instructs the model to use `read` to load the SKILL.md at the listed
location (workspace, managed, or bundled). If no skills are eligible, the
Skills section is omitted.
Native Codex turns receive this list as turn-scoped collaboration developer
instructions instead of per-turn user input, except lightweight cron turns that
preserve the exact scheduled prompt. Other harnesses keep the normal prompt
section.
The location can point at a nested skill, such as
`skills/personal/foo/SKILL.md`. Nesting is only organizational; the prompt still
uses the flat skill name from `SKILL.md` frontmatter.

View File

@@ -1235,7 +1235,6 @@
"plugins/memory-wiki",
"plugins/memory-lancedb",
"plugins/oc-path",
"plugins/skill-workshop",
"plugins/zalouser"
]
},
@@ -1333,6 +1332,7 @@
"group": "Agent coordination",
"pages": [
"tools/agent-send",
"tools/goal",
"tools/steer",
"tools/subagents",
"tools/acp-agents",
@@ -1404,6 +1404,7 @@
"providers/fal",
"providers/fireworks",
"providers/github-copilot",
"providers/gmi",
"providers/google",
"providers/gradium",
"providers/groq",
@@ -1416,8 +1417,10 @@
"providers/minimax",
"providers/mistral",
"providers/moonshot",
"providers/novita",
"providers/nvidia",
"providers/ollama",
"providers/ollama-cloud",
"providers/openai",
"providers/opencode",
"providers/opencode-go",
@@ -1426,6 +1429,7 @@
"providers/pixverse",
"providers/qianfan",
"providers/qwen",
"providers/qwen-oauth",
"providers/runway",
"providers/senseaudio",
"providers/sglang",

View File

@@ -199,8 +199,8 @@ Use `openclaw models auth login --provider <id> --profile-id <profileId>` for
providers that support named auth profiles during login.
```bash
openclaw models auth login --provider openai-codex --profile-id openai-codex:ritsuko
openclaw models auth login --provider openai-codex --profile-id openai-codex:lain
openclaw models auth login --provider openai --profile-id openai:ritsuko
openclaw models auth login --provider openai --profile-id openai:lain
```
This is the easiest way to keep multiple OAuth logins for the same provider

View File

@@ -450,7 +450,7 @@ Time format in system prompt. Default: `auto` (OS preference).
- `elevatedDefault`: default elevated-output level for agents. Values: `"off"`, `"on"`, `"ask"`, `"full"`. Default: `"on"`.
- `model.primary`: format `provider/model` (e.g. `openai/gpt-5.5` for OpenAI API-key or Codex OAuth access). If you omit the provider, OpenClaw tries an alias first, then a unique configured-provider match for that exact model id, and only then falls back to the configured default provider (deprecated compatibility behavior, so prefer explicit `provider/model`). If that provider no longer exposes the configured default model, OpenClaw falls back to the first configured provider/model instead of surfacing a stale removed-provider default.
- `models`: the configured model catalog and allowlist for `/model`. Each entry can include `alias` (shortcut) and `params` (provider-specific, for example `temperature`, `maxTokens`, `cacheRetention`, `context1m`, `responsesServerCompaction`, `responsesCompactThreshold`, OpenRouter `provider` routing, `chat_template_kwargs`, `extra_body`/`extraBody`).
- Use `provider/*` entries such as `"openai-codex/*": {}` or `"vllm/*": {}` to show all discovered models for selected providers without manually listing every model id.
- Use `provider/*` entries such as `"openai/*": {}` or `"vllm/*": {}` to show all discovered models for selected providers without manually listing every model id.
- Add `agentRuntime` to a `provider/*` entry when every dynamically discovered model for that provider should use the same runtime. Exact `provider/model` runtime policy still wins over the wildcard.
- Safe edits: use `openclaw config set agents.defaults.models '<json>' --strict-json --merge` to add entries. `config set` refuses replacements that would remove existing allowlist entries unless you pass `--replace`.
- Provider-scoped configure/onboarding flows merge selected provider models into this map and preserve unrelated providers already configured.
@@ -617,7 +617,7 @@ Periodic heartbeat runs.
- `every`: duration string (ms/s/m/h). Default: `30m` (API-key auth) or `1h` (OAuth auth). Set to `0m` to disable.
- `includeSystemPromptSection`: when false, omits the Heartbeat section from the system prompt and skips `HEARTBEAT.md` injection into bootstrap context. Default: `true`.
- `suppressToolErrorWarnings`: when true, suppresses tool error warning payloads during heartbeat runs.
- `timeoutSeconds`: maximum time in seconds allowed for a heartbeat agent turn before it is aborted. Leave unset to use `agents.defaults.timeoutSeconds`.
- `timeoutSeconds`: maximum time in seconds allowed for a heartbeat agent turn before it is aborted. Leave unset to use `agents.defaults.timeoutSeconds` when set, otherwise the heartbeat cadence capped at 600 seconds.
- `directPolicy`: direct/DM delivery policy. `allow` (default) permits direct-target delivery. `block` suppresses direct-target delivery and emits `reason=dm-blocked`.
- `lightContext`: when true, heartbeat runs use lightweight bootstrap context and keep only `HEARTBEAT.md` from workspace bootstrap files.
- `isolatedSession`: when true, each heartbeat runs in a fresh session with no prior conversation history. Same isolation pattern as cron `sessionTarget: "isolated"`. Reduces per-heartbeat token cost from ~100K to ~2-5K tokens.

View File

@@ -386,12 +386,13 @@ Controls inline attachment support for `sessions_spawn`.
<AccordionGroup>
<Accordion title="Attachment notes">
- Attachments are only supported for `runtime: "subagent"`. ACP runtime rejects them.
- Files are materialized into the child workspace at `.openclaw/attachments/<uuid>/` with a `.manifest.json`.
- Attachments require `enabled: true`.
- Subagent attachments are materialized into the child workspace at `.openclaw/attachments/<uuid>/` with a `.manifest.json`.
- ACP attachments are image-only and forwarded inline to the ACP runtime after the same file count, per-file byte, and total byte limits pass.
- Attachment content is automatically redacted from transcript persistence.
- Base64 inputs are validated with strict alphabet/padding checks and a pre-decode size guard.
- File permissions are `0700` for directories and `0600` for files.
- Cleanup follows the `cleanup` policy: `delete` always removes attachments; `keep` retains them only when `retainOnSessionKeep: true`.
- Subagent attachment file permissions are `0700` for directories and `0600` for files.
- Subagent cleanup follows the `cleanup` policy: `delete` always removes attachments; `keep` retains them only when `retainOnSessionKeep: true`.
</Accordion>
</AccordionGroup>

View File

@@ -82,12 +82,11 @@ Save to `~/.openclaw/openclaw.json` and you can DM the bot from that number.
"anthropic:default": { provider: "anthropic", mode: "api_key" },
"anthropic:work": { provider: "anthropic", mode: "api_key" },
"openai:default": { provider: "openai", mode: "api_key" },
"openai-codex:personal": { provider: "openai-codex", mode: "oauth" },
"openai:personal": { provider: "openai", mode: "oauth" },
},
order: {
anthropic: ["anthropic:default", "anthropic:work"],
openai: ["openai:default"],
"openai-codex": ["openai-codex:personal"],
openai: ["openai:personal", "openai:default"],
},
},

View File

@@ -109,6 +109,10 @@ target server during config edits.
headers: {
Authorization: "Bearer ${MCP_REMOTE_TOKEN}",
},
toolFilter: {
include: ["search_*"],
exclude: ["admin_*"],
},
// Optional Codex app-server projection controls.
codex: {
agents: ["main"],
@@ -125,6 +129,12 @@ target server during config edits.
Remote entries use `transport: "streamable-http"` or `transport: "sse"`;
`type: "http"` is a CLI-native alias that `openclaw mcp set` and
`openclaw doctor --fix` normalize into the canonical `transport` field.
- `mcp.servers.<name>.toolFilter`: optional per-server tool selection. `include`
limits the discovered MCP tools to matching names; `exclude` hides matching
names. Entries are exact MCP tool names or simple `*` globs. Servers with
resources or prompts also generate utility tool names (`resources_list`,
`resources_read`, `prompts_list`, `prompts_get`), and those names use the
same filter.
- `mcp.servers.<name>.codex`: optional Codex app-server projection controls.
This block is OpenClaw metadata for Codex app-server threads only; it does not
affect ACP sessions, generic Codex harness config, or other runtime adapters.
@@ -142,6 +152,11 @@ target server during config edits.
- Changes under `mcp.*` hot-apply by disposing cached session MCP runtimes.
The next tool discovery/use recreates them from the new config, so removed
`mcp.servers` entries are reaped immediately instead of waiting for idle TTL.
- Runtime discovery also honors MCP tool-list change notifications by dropping
the cached catalog for that session. Servers that advertise resources or
prompts get utility tools for listing/reading resources and listing/fetching
prompts. Repeated tool-call failures pause the affected server briefly before
another call is attempted.
See [MCP](/cli/mcp#openclaw-as-an-mcp-client-registry) and
[CLI backends](/gateway/cli-backends#bundle-mcp-overlays) for runtime behavior.
@@ -214,7 +229,8 @@ See [MCP](/cli/mcp#openclaw-as-an-mcp-client-registry) and
}
```
- Loaded from `~/.openclaw/extensions`, `<workspace>/.openclaw/extensions`, plus `plugins.load.paths`.
- Loaded from package or bundle directories under `~/.openclaw/extensions` and `<workspace>/.openclaw/extensions`, plus files or directories listed in `plugins.load.paths`.
- Put standalone plugin files in `plugins.load.paths`; auto-discovered extension roots ignore top-level `.js`, `.mjs`, and `.ts` files so helper scripts in those roots do not block startup.
- Discovery accepts native OpenClaw plugins plus compatible Codex bundles and Claude bundles, including manifestless Claude default-layout bundles.
- **Config changes require a gateway restart.**
- `allow`: optional allowlist (only listed plugins load). `deny` wins.
@@ -935,11 +951,11 @@ Notes:
profiles: {
"anthropic:default": { provider: "anthropic", mode: "api_key" },
"anthropic:work": { provider: "anthropic", mode: "api_key" },
"openai-codex:personal": { provider: "openai-codex", mode: "oauth" },
"openai:personal": { provider: "openai", mode: "oauth" },
},
order: {
anthropic: ["anthropic:default", "anthropic:work"],
"openai-codex": ["openai-codex:personal"],
openai: ["openai:personal"],
},
},
}
@@ -1249,8 +1265,8 @@ Current builds no longer include the TCP bridge. Nodes connect over the Gateway
```
- `sessionRetention`: how long to keep completed isolated cron run sessions before pruning from `sessions.json`. Also controls cleanup of archived deleted cron transcripts. Default: `24h`; set `false` to disable.
- `runLog.maxBytes`: max size per run log file (`cron/runs/<jobId>.jsonl`) before pruning. Default: `2_000_000` bytes.
- `runLog.keepLines`: newest lines retained when run-log pruning is triggered. Default: `2000`.
- `runLog.maxBytes`: accepted for compatibility with older file-backed cron run logs. Default: `2_000_000` bytes.
- `runLog.keepLines`: newest SQLite run-history rows retained per job. Default: `2000`.
- `webhookToken`: bearer token used for cron webhook POST delivery (`delivery.mode = "webhook"`), if omitted no auth header is sent.
- `webhook`: deprecated legacy fallback webhook URL (http/https) used only for stored jobs that still have `notify: true`.

View File

@@ -337,9 +337,9 @@ candidate contains redacted secret placeholders such as `***`.
</Accordion>
<Accordion title="Enable relay-backed push for official iOS builds">
Relay-backed push is configured in `openclaw.json`.
Relay-backed push uses the hosted OpenClaw relay by default: `https://ios-push-relay.openclaw.ai`.
Set this in gateway config:
To use a custom relay, set this in gateway config:
```json5
{
@@ -373,8 +373,8 @@ candidate contains redacted secret placeholders such as `***`.
End-to-end flow:
1. Install an official/TestFlight iOS build that was compiled with the same relay base URL.
2. Configure `gateway.push.apns.relay.baseUrl` on the gateway.
1. Install an official/TestFlight iOS build.
2. Optional: configure `gateway.push.apns.relay.baseUrl` on the gateway only when using a custom relay deployment.
3. Pair the iOS app to the gateway and let both node and operator sessions connect.
4. The iOS app fetches the gateway identity, registers with the relay using App Attest plus the app receipt, and then publishes the relay-backed `push.apns.register` payload to the paired gateway.
5. The gateway stores the relay handle and send grant, then uses them for `push.test`, wake nudges, and reconnect wakes.
@@ -387,6 +387,7 @@ candidate contains redacted secret placeholders such as `***`.
Compatibility note:
- `OPENCLAW_APNS_RELAY_BASE_URL` and `OPENCLAW_APNS_RELAY_TIMEOUT_MS` still work as temporary env overrides.
- Custom gateway relay URLs must match the relay base URL baked into the official/TestFlight iOS build.
- `OPENCLAW_APNS_RELAY_ALLOW_HTTP=true` remains a loopback-only development escape hatch; do not persist HTTP relay URLs in config.
See [iOS App](/platforms/ios#relay-backed-push-for-official-builds) for the end-to-end flow and [Authentication and trust flow](/platforms/ios#authentication-and-trust-flow) for the relay security model.
@@ -430,7 +431,7 @@ candidate contains redacted secret placeholders such as `***`.
```
- `sessionRetention`: prune completed isolated run sessions from `sessions.json` (default `24h`; set `false` to disable).
- `runLog`: prune `cron/runs/<jobId>.jsonl` by size and retained lines.
- `runLog`: prune retained cron run-history rows per job. `maxBytes` remains accepted for older file-backed run logs.
- See [Cron jobs](/automation/cron-jobs) for feature overview and CLI examples.
</Accordion>

View File

@@ -143,7 +143,7 @@ must be paired with `--lint`; regular doctor and repair runs reject them.
- Talk config migration from legacy flat `talk.*` fields into `talk.provider` + `talk.providers.<provider>`.
- Browser migration checks for legacy Chrome extension configs and Chrome MCP readiness.
- OpenCode provider override warnings (`models.providers.opencode` / `models.providers.opencode-go`).
- Codex OAuth shadowing warnings (`models.providers.openai-codex`).
- Legacy OpenAI Codex provider/profile migration (`openai-codex` → `openai`) and shadowing warnings for stale `models.providers.openai-codex`.
- OAuth TLS prerequisites check for OpenAI Codex OAuth profiles.
- Plugin/tool allowlist warnings when `plugins.allow` is restrictive but tool policy still asks for wildcard or plugin-owned tools.
- Legacy on-disk state migration (sessions/agent dir/WhatsApp auth).
@@ -171,7 +171,7 @@ must be paired with `--lint`; regular doctor and repair runs reject them.
- Channel status warnings (probed from the running gateway).
- Channel-specific permission checks live under `openclaw channels capabilities`; for example, Discord voice channel permissions are audited with `openclaw channels capabilities --channel discord --target channel:<channel-id>`.
- WhatsApp responsiveness checks for degraded Gateway event-loop health with local TUI clients still running; `--fix` stops only verified local TUI clients.
- Codex route repair for legacy `openai-codex/*` model refs in primary models, fallbacks, heartbeat/subagent/compaction overrides, hooks, channel model overrides, and session route pins; `--fix` rewrites them to `openai/*`, removes stale session/whole-agent runtime pins, and leaves canonical OpenAI agent refs on the default Codex harness.
- Codex route repair for legacy `openai-codex/*` model refs in primary models, fallbacks, image/video generation models, heartbeat/subagent/compaction overrides, hooks, channel model overrides, and session route pins; `--fix` rewrites them to `openai/*`, migrates `openai-codex:*` auth profiles/order to `openai:*`, removes stale session/whole-agent runtime pins, and leaves canonical OpenAI agent refs on the default Codex harness.
- Supervisor config audit (launchd/systemd/schtasks) with optional repair.
- Embedded proxy environment cleanup for gateway services that captured shell `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` values during install or update.
- Gateway runtime best-practice checks (Node vs Bun, version-manager paths).
@@ -327,10 +327,10 @@ That stages grounded durable candidates into the short-term dreaming store while
<Accordion title="2f. Codex route repair">
Doctor checks for legacy `openai-codex/*` model refs. Native Codex harness routing uses canonical `openai/*` model refs; OpenAI agent turns go through the Codex app-server harness instead of the OpenClaw OpenAI provider path.
In `--fix` / `--repair` mode, doctor rewrites affected default-agent and per-agent refs, including primary models, fallbacks, heartbeat/subagent/compaction overrides, hooks, channel model overrides, and stale persisted session route state:
In `--fix` / `--repair` mode, doctor rewrites affected default-agent and per-agent refs, including primary models, fallbacks, image/video generation models, heartbeat/subagent/compaction overrides, hooks, channel model overrides, and stale persisted session route state:
- `openai-codex/gpt-*` becomes `openai/gpt-*`.
- Codex intent moves to provider/model-scoped `agentRuntime.id: "codex"` entries for repaired agent model refs so `openai-codex:...` auth profiles can still be selected after the model ref becomes `openai/*`.
- Codex intent moves to provider/model-scoped `agentRuntime.id: "codex"` entries for repaired agent model refs.
- Stale whole-agent runtime config and persisted session runtime pins are removed because runtime selection is provider/model-scoped.
- Existing provider/model runtime policy is preserved unless the repaired legacy model ref needs Codex routing to keep the old auth path.
- Existing model fallback lists are preserved with their legacy entries rewritten; copied per-model settings move from the legacy key to the canonical `openai/*` key.
@@ -382,7 +382,7 @@ That stages grounded durable candidates into the short-term dreaming store while
</Accordion>
<Accordion title="3c. Session lock cleanup">
Doctor scans every agent session directory for stale write-lock files — files left behind when a session exited abnormally. For each lock file found it reports: the path, PID, whether the PID is still alive, lock age, and whether it is considered stale (dead PID, older than 30 minutes, or a live PID that can be proven to belong to a non-OpenClaw process). In `--fix` / `--repair` mode it removes stale lock files automatically; otherwise it prints a note and instructs you to rerun with `--fix`.
Doctor scans every agent session directory for stale write-lock files — files left behind when a session exited abnormally. For each lock file found it reports: the path, PID, whether the PID is still alive, lock age, and whether it is considered stale (dead PID, malformed owner metadata, older than 30 minutes, or a live PID that can be proven to belong to a non-OpenClaw process). In `--fix` / `--repair` mode it removes locks with dead, orphaned, recycled, malformed-old, or non-OpenClaw owners automatically. Old locks that are still owned by a live OpenClaw process are reported but left in place so doctor does not cut off an active transcript writer.
</Accordion>
<Accordion title="3d. Session transcript branch repair">
Doctor scans agent session JSONL files for the duplicated branch shape created by the 2026.4.24 prompt transcript rewrite bug: an abandoned user turn with OpenClaw internal runtime context plus an active sibling containing the same visible user prompt. In `--fix` / `--repair` mode, doctor backs up each affected file next to the original and rewrites the transcript to the active branch so gateway history and memory readers no longer see duplicate turns.

View File

@@ -63,6 +63,7 @@ Example config:
- Interval: `30m` (or `1h` when Anthropic OAuth/token auth is the detected auth mode, including Claude CLI reuse). Set `agents.defaults.heartbeat.every` or per-agent `agents.list[].heartbeat.every`; use `0m` to disable.
- Prompt body (configurable via `agents.defaults.heartbeat.prompt`): `Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.`
- Timeout: unset heartbeat turns use `agents.defaults.timeoutSeconds` when set. Otherwise, they use the heartbeat cadence capped at 600 seconds. Set `agents.defaults.heartbeat.timeoutSeconds` or per-agent `agents.list[].heartbeat.timeoutSeconds` for longer heartbeat work.
- The heartbeat prompt is sent **verbatim** as the user message. The system prompt includes a "Heartbeat" section only when heartbeats are enabled for the default agent, and the run is flagged internally.
- When heartbeats are disabled with `0m`, normal runs also omit `HEARTBEAT.md` from bootstrap context so the model does not see heartbeat-only instructions.
- Active hours (`heartbeat.activeHours`) are checked in the configured timezone. Outside the window, heartbeats are skipped until the next tick inside the window.
@@ -274,6 +275,10 @@ Use `accountId` to target a specific account on multi-account channels like Tele
<ParamField path="suppressToolErrorWarnings" type="boolean">
When true, suppresses tool error warning payloads during heartbeat runs.
</ParamField>
<ParamField path="timeoutSeconds" type="number" default="global timeout or min(every, 600)">
Maximum seconds allowed for a heartbeat agent turn before it is aborted. Leave unset to use `agents.defaults.timeoutSeconds` when set, otherwise the heartbeat cadence capped at 600 seconds.
</ParamField>
<ParamField path="activeHours" type="object">
Restricts heartbeat runs to a time window. Object with `start` (HH:MM, inclusive; use `00:00` for start-of-day), `end` (HH:MM exclusive; `24:00` allowed for end-of-day), and optional `timezone`.

View File

@@ -315,7 +315,7 @@ If the model loads cleanly but full agent turns misbehave, work top-down — con
openclaw infer model run --gateway --model <provider/model> --prompt "Reply with exactly: pong" --json
```
3. **Try lean mode.** If both probes pass but real agent turns fail with malformed tool calls or oversized prompts, enable `agents.defaults.experimental.localModelLean: true`. It drops the three heaviest default tools (`browser`, `cron`, `message`) from the visible model surface so the prompt shape is smaller and less brittle. When Code Mode or Tool Search is enabled, those tools can still sit behind the compact catalog controls. See [Experimental Features → Local model lean mode](/concepts/experimental-features#local-model-lean-mode) for the full explanation, when to use it, and how to confirm it is on.
3. **Try lean mode.** If both probes pass but real agent turns fail with malformed tool calls or oversized prompts, enable `agents.defaults.experimental.localModelLean: true`. It drops the three heaviest default tools (`browser`, `cron`, `message`) so the prompt shape is smaller and less brittle. See [Experimental Features → Local model lean mode](/concepts/experimental-features#local-model-lean-mode) for the full explanation, when to use it, and how to confirm it is on.
4. **Disable tools entirely as a last resort.** If lean mode is not enough, set `models.providers.<provider>.models[].compat.supportsTools: false` for that model entry. The agent will then operate without tool calls on that model.

View File

@@ -19,7 +19,7 @@ At startup, the Gateway logs the resolved default agent model together with the
mode defaults that affect new sessions, for example:
```text
agent model: openai-codex/gpt-5.5 (thinking=medium, fast=on)
agent model: openai/gpt-5.5 (thinking=medium, fast=on)
```
`thinking` comes from the default agent, model params, or global agent default;

View File

@@ -222,8 +222,9 @@ Set `stream: true` to receive Server-Sent Events (SSE):
- `frequency_penalty`: number; best-effort frequency penalty forwarded to the upstream provider via the agent stream-param channel. Validated range: -2.0 to 2.0. Returns `400 invalid_request_error` for out-of-range values.
- `presence_penalty`: number; best-effort presence penalty forwarded to the upstream provider via the agent stream-param channel. Validated range: -2.0 to 2.0. Returns `400 invalid_request_error` for out-of-range values.
- `seed`: number (integer); best-effort seed forwarded to the upstream provider via the agent stream-param channel. Returns `400 invalid_request_error` for non-integer values.
- `stop`: string or array of up to 4 strings; best-effort stop sequences forwarded to the upstream provider via the agent stream-param channel. Returns `400 invalid_request_error` for more than 4 sequences or non-string/empty entries.
When either token-cap field is set, the value is forwarded to the upstream provider via the agent stream-param channel. The actual wire field name sent to the upstream provider is chosen by the provider transport: `max_completion_tokens` for OpenAI-family endpoints, and `max_tokens` for providers that only accept the legacy name (such as Mistral and Chutes). Sampling fields (`temperature`, `top_p`, `frequency_penalty`, `presence_penalty`, `seed`) follow the same stream-param channel; the ChatGPT-based Codex Responses backend strips them server-side since it uses fixed sampling.
When either token-cap field is set, the value is forwarded to the upstream provider via the agent stream-param channel. The actual wire field name sent to the upstream provider is chosen by the provider transport: `max_completion_tokens` for OpenAI-family endpoints, and `max_tokens` for providers that only accept the legacy name (such as Mistral and Chutes). Sampling fields (`temperature`, `top_p`, `frequency_penalty`, `presence_penalty`, `seed`) follow the same stream-param channel; the ChatGPT-based Codex Responses backend strips them server-side since it uses fixed sampling. `stop` also rides the stream-param channel and maps to the transport's stop field (`stop` for Chat Completions backends, `stop_sequences` for Anthropic); the OpenAI Responses API has no stop parameter, so `stop` is not applied on Responses-backed models.
### Unsupported variants

View File

@@ -348,7 +348,8 @@ enumeration of `src/gateway/server-methods/*.ts`.
- `usage.status` returns provider usage windows/remaining quota summaries.
- `usage.cost` returns aggregated cost usage summaries for a date range.
Pass `agentId` for one agent, or `agentScope: "all"` to aggregate configured agents.
- `doctor.memory.status` returns vector-memory / cached embedding readiness for the active default agent workspace. Pass `{ "probe": true }` or `{ "deep": true }` only when the caller explicitly wants a live embedding provider ping.
- `doctor.memory.status` returns vector-memory / cached embedding readiness for the active default agent workspace. Pass `{ "probe": true }` or `{ "deep": true }` only when the caller explicitly wants a live embedding provider ping. Dreaming-aware clients may also pass `{ "agentId": "agent-id" }` to scope Dreaming store stats to a selected agent workspace; omitting `agentId` keeps the default-agent fallback and aggregates configured Dreaming workspaces.
- `doctor.memory.dreamDiary`, `doctor.memory.backfillDreamDiary`, `doctor.memory.resetDreamDiary`, `doctor.memory.resetGroundedShortTerm`, `doctor.memory.repairDreamingArtifacts`, and `doctor.memory.dedupeDreamDiary` accept optional `{ "agentId": "agent-id" }` params for selected-agent Dreaming views/actions. When `agentId` is omitted, they operate on the configured default agent workspace.
- `doctor.memory.remHarness` returns a bounded, read-only REM harness preview for remote control-plane clients. It can include workspace paths, memory snippets, rendered grounded markdown, and deep promotion candidates, so callers need `operator.read`.
- `sessions.usage` returns per-session usage summaries. Pass `agentId` for one
agent, or `agentScope: "all"` to list configured agents together.

View File

@@ -183,6 +183,13 @@ Define providers under `secrets.providers`:
passEnv: ["PATH", "VAULT_ADDR"],
jsonOnly: true,
},
"team-secrets": {
source: "exec",
pluginIntegration: {
pluginId: "acme-secrets",
integrationId: "secret-store",
},
},
},
defaults: {
env: "default",
@@ -219,6 +226,11 @@ Define providers under `secrets.providers`:
- Pair `allowSymlinkCommand` with `trustedDirs` for package-manager paths (for example `["/opt/homebrew"]`).
- Supports timeout, no-output timeout, output byte limits, env allowlist, and trusted dirs.
- Windows fail-closed note: if ACL verification is unavailable for the command path, resolution fails. For trusted paths only, set `allowInsecurePath: true` on that provider to bypass path security checks.
- Plugin-managed exec providers can use `pluginIntegration` instead of
copied `command`/`args`. OpenClaw resolves the current command details
from the installed plugin manifest during startup/reload. If the plugin is
disabled, removed, untrusted, or no longer declares the integration,
active SecretRefs using that provider fail closed.
Request payload (stdin):

View File

@@ -599,22 +599,24 @@ and troubleshooting see the main [FAQ](/help/faq).
native Codex app-server execution. `openai-codex/gpt-*` model refs are
legacy config repaired by `openclaw doctor --fix`. Direct OpenAI API-key
access remains available for non-agent OpenAI API surfaces and for agent
models through an ordered `openai-codex` API-key profile.
models through an ordered `openai` API-key profile.
See [Model providers](/concepts/model-providers) and [Onboarding (CLI)](/start/wizard).
</Accordion>
<Accordion title="Why does OpenClaw still mention openai-codex?">
`openai-codex` is the provider and auth-profile id for ChatGPT/Codex OAuth.
`openai` is the provider and auth-profile id for both OpenAI API keys and
ChatGPT/Codex OAuth. You may still see `openai-codex` in legacy config and
migration warnings.
Older configs also used it as a model prefix:
- `openai/gpt-5.5` = ChatGPT/Codex subscription auth with native Codex runtime for agent turns
- `openai-codex/gpt-5.5` = legacy model route repaired by `openclaw doctor --fix`
- `openai/gpt-5.5` plus an ordered `openai-codex` API-key profile = API-key auth for an OpenAI agent model
- `openai-codex:...` = auth profile id, not a model ref
- `openai/gpt-5.5` plus an ordered `openai` API-key profile = API-key auth for an OpenAI agent model
- `openai-codex:...` = legacy auth profile id migrated by `openclaw doctor --fix`
If you want the direct OpenAI Platform billing/limit path, set
`OPENAI_API_KEY`. If you want ChatGPT/Codex subscription auth, sign in with
`openclaw models auth login --provider openai-codex`. Keep the model ref as
`openclaw models auth login --provider openai`. Keep the model ref as
`openai/gpt-5.5`; `openai-codex/*` model refs are legacy config that
`openclaw doctor --fix` rewrites.

View File

@@ -160,9 +160,9 @@ troubleshooting, see the main [FAQ](/help/faq).
<Accordion title="Can I use GPT 5.5 for daily tasks and Codex 5.5 for coding?">
Yes. Treat model choice and runtime choice separately:
- **Native Codex coding agent:** set `agents.defaults.model.primary` to `openai/gpt-5.5`. Sign in with `openclaw models auth login --provider openai-codex` when you want ChatGPT/Codex subscription auth.
- **Native Codex coding agent:** set `agents.defaults.model.primary` to `openai/gpt-5.5`. Sign in with `openclaw models auth login --provider openai` when you want ChatGPT/Codex subscription auth.
- **Direct OpenAI API tasks outside the agent loop:** configure `OPENAI_API_KEY` for images, embeddings, speech, realtime, and other non-agent OpenAI API surfaces.
- **OpenAI agent API-key auth:** use `/model openai/gpt-5.5` with an ordered `openai-codex` API-key profile.
- **OpenAI agent API-key auth:** use `/model openai/gpt-5.5` with an ordered `openai` API-key profile.
- **Sub-agents:** route coding tasks to a Codex-focused agent with its own `openai/gpt-5.5` model.
See [Models](/concepts/models) and [Slash commands](/tools/slash-commands).

View File

@@ -76,7 +76,7 @@ Live tests are split into two layers so we can isolate failures:
- `OPENCLAW_LIVE_MODELS=modern` to run the modern allowlist (Opus/Sonnet 4.6+, GPT-5.2 + Codex, Gemini 3, DeepSeek V4, GLM 4.7, MiniMax M2.7, Grok 4.3)
- `OPENCLAW_LIVE_MODELS=small` to run the constrained small-model allowlist (Qwen 8B/9B local-compatible routes, OpenRouter Qwen/GLM, and Z.AI GLM)
- `OPENCLAW_LIVE_MODELS=all` is an alias for the modern allowlist
- or `OPENCLAW_LIVE_MODELS="openai/gpt-5.5,openai-codex/gpt-5.5,anthropic/claude-opus-4-6,..."` (comma allowlist)
- or `OPENCLAW_LIVE_MODELS="openai/gpt-5.5,anthropic/claude-opus-4-6,..."` (comma allowlist)
- Modern/all and small sweeps default to their curated caps; set `OPENCLAW_LIVE_MAX_MODELS=0` for an exhaustive selected-profile sweep or a positive number for a smaller cap.
- Exhaustive sweeps use `OPENCLAW_LIVE_TEST_TIMEOUT_MS` for the whole direct-model test timeout. Default: 60 minutes.
- Direct-model probes run with 20-way parallelism by default; set `OPENCLAW_LIVE_MODEL_CONCURRENCY` to override.
@@ -350,7 +350,7 @@ Narrow, explicit allowlists are fastest and least flaky:
- `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.5" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
- Tool calling across several providers:
- `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.5,openai-codex/gpt-5.5,anthropic/claude-opus-4-6,google/gemini-3-flash-preview,deepseek/deepseek-v4-flash,zai/glm-5.1,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
- `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.5,anthropic/claude-opus-4-6,google/gemini-3-flash-preview,deepseek/deepseek-v4-flash,zai/glm-5.1,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
- Google focus (Gemini API key + Antigravity):
- Gemini (API key): `OPENCLAW_LIVE_GATEWAY_MODELS="google/gemini-3-flash-preview" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
@@ -378,7 +378,7 @@ There is no fixed "CI model list" (live is opt-in), but these are the **recommen
This is the "common models" run we expect to keep working:
- OpenAI (non-Codex): `openai/gpt-5.5`
- OpenAI Codex OAuth: `openai-codex/gpt-5.5`
- OpenAI ChatGPT/Codex OAuth: `openai/gpt-5.5`
- Anthropic: `anthropic/claude-opus-4-6` (or `anthropic/claude-sonnet-4-6`)
- Google (Gemini API): `google/gemini-3.1-pro-preview` and `google/gemini-3-flash-preview` (avoid older Gemini 2.x models)
- Google (Antigravity): `google-antigravity/claude-opus-4-6-thinking` and `google-antigravity/gemini-3-flash`
@@ -387,7 +387,7 @@ This is the "common models" run we expect to keep working:
- MiniMax: `minimax/MiniMax-M2.7`
Run gateway smoke with tools + image:
`OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.5,openai-codex/gpt-5.5,anthropic/claude-opus-4-6,google/gemini-3.1-pro-preview,google/gemini-3-flash-preview,google-antigravity/claude-opus-4-6-thinking,google-antigravity/gemini-3-flash,deepseek/deepseek-v4-flash,zai/glm-5.1,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
`OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.5,anthropic/claude-opus-4-6,google/gemini-3.1-pro-preview,google/gemini-3-flash-preview,google-antigravity/claude-opus-4-6-thinking,google-antigravity/gemini-3-flash,deepseek/deepseek-v4-flash,zai/glm-5.1,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
### Baseline: tool calling (Read + optional Exec)
@@ -420,7 +420,7 @@ If you have keys enabled, we also support testing via:
More providers you can include in the live matrix (if you have creds/config):
- Built-in: `openai`, `openai-codex`, `anthropic`, `google`, `google-vertex`, `google-antigravity`, `google-gemini-cli`, `zai`, `openrouter`, `opencode`, `opencode-go`, `xai`, `groq`, `cerebras`, `mistral`, `github-copilot`
- Built-in: `openai`, `anthropic`, `google`, `google-vertex`, `google-antigravity`, `google-gemini-cli`, `zai`, `openrouter`, `opencode`, `opencode-go`, `xai`, `groq`, `cerebras`, `mistral`, `github-copilot`
- Via `models.providers` (custom endpoints): `minimax` (cloud/API), plus any OpenAI/Anthropic-compatible proxy (LM Studio, vLLM, LiteLLM, etc.)
<Tip>

View File

@@ -296,8 +296,8 @@ replacement. Gateway startup does not generate bundled-plugin dependency trees.
For full persistence details on VM deployments, see
[Docker VM Runtime - What persists where](/install/docker-vm-runtime#what-persists-where).
**Disk growth hotspots:** watch `media/`, session JSONL files,
`cron/runs/*.jsonl`, installed plugin package roots, and rolling file logs
**Disk growth hotspots:** watch `media/`, session JSONL files, the shared
SQLite state database, installed plugin package roots, and rolling file logs
under `/tmp/openclaw/`.
### Shell helpers (optional)

View File

@@ -277,11 +277,11 @@ For CLI entries, **set `capabilities` explicitly** to avoid surprising matches.
## Provider support matrix (OpenClaw integrations)
| Capability | Provider integration | Notes |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Image | OpenAI, OpenAI Codex OAuth, Codex app-server, OpenRouter, Anthropic, Google, MiniMax, Moonshot, Qwen, Z.AI, config providers | Vendor plugins register image support; `openai-codex/*` uses OAuth provider plumbing; `codex/*` uses a bounded Codex app-server turn; MiniMax and MiniMax OAuth both use `MiniMax-VL-01`; image-capable config providers auto-register. |
| Audio | OpenAI, Groq, xAI, Deepgram, OpenRouter, Google, SenseAudio, ElevenLabs, Mistral | Provider transcription (Whisper/Groq/xAI/Deepgram/OpenRouter STT/Gemini/SenseAudio/Scribe/Voxtral). |
| Video | Google, Qwen, Moonshot | Provider video understanding via vendor plugins; Qwen video understanding uses the Standard DashScope endpoints. |
| Capability | Provider integration | Notes |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Image | OpenAI, OpenAI Codex OAuth, Codex app-server, OpenRouter, Anthropic, Google, MiniMax, Moonshot, Qwen, Z.AI, config providers | Vendor plugins register image support; `openai/*` can use API-key or Codex OAuth routing; `codex/*` uses a bounded Codex app-server turn; MiniMax and MiniMax OAuth both use `MiniMax-VL-01`; image-capable config providers auto-register. |
| Audio | OpenAI, Groq, xAI, Deepgram, OpenRouter, Google, SenseAudio, ElevenLabs, Mistral | Provider transcription (Whisper/Groq/xAI/Deepgram/OpenRouter STT/Gemini/SenseAudio/Scribe/Voxtral). |
| Video | Google, Qwen, Moonshot | Provider video understanding via vendor plugins; Qwen video understanding uses the Standard DashScope endpoints. |
<Note>
**MiniMax note**

View File

@@ -7,7 +7,7 @@ read_when:
title: "iOS app"
---
Availability: internal preview. The iOS app is not publicly distributed yet.
Availability: iPhone app builds are distributed through Apple channels when enabled for a release. Local development builds can also run from source.
## What it does
@@ -75,7 +75,9 @@ openclaw gateway call node.list --params "{}"
Official distributed iOS builds use the external push relay instead of publishing the raw APNs
token to the gateway.
Gateway-side requirement:
By default, official/TestFlight builds and gateways use the hosted relay at `https://ios-push-relay.openclaw.ai`.
Custom relay deployments can override the gateway relay URL:
```json5
{
@@ -98,7 +100,7 @@ How the flow works:
- The iOS app fetches the paired gateway identity and includes it in relay registration, so the relay-backed registration is delegated to that specific gateway.
- The app forwards that relay-backed registration to the paired gateway with `push.apns.register`.
- The gateway uses that stored relay handle for `push.test`, background wakes, and wake nudges.
- The gateway relay base URL must match the relay URL baked into the official/TestFlight iOS build.
- Custom gateway relay URLs must match the relay URL baked into the official/TestFlight iOS build.
- If the app later connects to a different gateway or a build with a different relay base URL, it refreshes the relay registration instead of reusing the old binding.
What the gateway does **not** need for this path:
@@ -109,7 +111,7 @@ What the gateway does **not** need for this path:
Expected operator flow:
1. Install the official/TestFlight iOS build.
2. Set `gateway.push.apns.relay.baseUrl` on the gateway.
2. Optional: set `gateway.push.apns.relay.baseUrl` on the gateway only when using a custom relay deployment.
3. Pair the app to the gateway and let it finish connecting.
4. The app publishes `push.apns.register` automatically after it has an APNs token, the operator session is connected, and relay registration succeeds.
5. After that, `push.test`, reconnect wakes, and wake nudges can use the stored relay-backed registration.
@@ -128,6 +130,7 @@ compatible but does not count as a durable last-seen update.
Compatibility note:
- `OPENCLAW_APNS_RELAY_BASE_URL` still works as a temporary env override for the gateway.
- `OPENCLAW_PUSH_RELAY_BASE_URL` still works as a temporary env override for official/TestFlight iOS builds.
## Authentication and trust flow

View File

@@ -85,25 +85,25 @@ For an already-running app-server, use WebSocket transport:
Supported `appServer` fields:
| Field | Default | Meaning |
| --------------------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transport` | `"stdio"` | `"stdio"` spawns Codex; `"websocket"` connects to `url`. |
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `turnCompletionIdleTimeoutMs` | `60000` | Quiet window after Codex accepts a turn or after a turn-scoped app-server request while OpenClaw waits for `turn/completed`. |
| `postToolRawAssistantCompletionIdleTimeoutMs` | unset | Completion-idle guard used after a tool handoff when Codex emits raw assistant completion or progress but does not send `turn/completed`. Defaults to the assistant completion idle timeout when unset. Use this for trusted or heavy workloads where post-tool synthesis can legitimately stay quiet longer than the final assistant release budget. |
| `mode` | `"yolo"` unless local Codex requirements disallow YOLO | Preset for YOLO or guardian-reviewed execution. |
| `approvalPolicy` | `"never"` or an allowed guardian approval policy | Native Codex approval policy sent to thread start, resume, and turn. |
| `sandbox` | `"danger-full-access"` or an allowed guardian sandbox | Native Codex sandbox mode sent to thread start and resume. Active OpenClaw sandboxes narrow `danger-full-access` turns to Codex `workspace-write`; the turn network flag follows OpenClaw sandbox egress. |
| `approvalsReviewer` | `"user"` or an allowed guardian reviewer | Use `"auto_review"` to let Codex review native approval prompts when allowed. |
| `defaultWorkspaceDir` | current process directory | Workspace used by `/codex bind` when `--cwd` is omitted. |
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, and `null` clears the override. Legacy `"fast"` is accepted as `"priority"`. |
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with Codex app-server 0.132.0 or newer so native Codex execution can run inside the active OpenClaw sandbox. |
| Field | Default | Meaning |
| --------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `transport` | `"stdio"` | `"stdio"` spawns Codex; `"websocket"` connects to `url`. |
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `turnCompletionIdleTimeoutMs` | `60000` | Quiet window after Codex accepts a turn or after a turn-scoped app-server request while OpenClaw waits for `turn/completed`. |
| `postToolRawAssistantCompletionIdleTimeoutMs` | `300000` | Completion-idle and progress guard used after a tool handoff, native tool completion, or post-tool raw assistant progress while OpenClaw waits for `turn/completed`. Use this for trusted or heavy workloads where post-tool synthesis can legitimately stay quiet longer than the final assistant release budget. |
| `mode` | `"yolo"` unless local Codex requirements disallow YOLO | Preset for YOLO or guardian-reviewed execution. |
| `approvalPolicy` | `"never"` or an allowed guardian approval policy | Native Codex approval policy sent to thread start, resume, and turn. |
| `sandbox` | `"danger-full-access"` or an allowed guardian sandbox | Native Codex sandbox mode sent to thread start and resume. Active OpenClaw sandboxes narrow `danger-full-access` turns to Codex `workspace-write`; the turn network flag follows OpenClaw sandbox egress. |
| `approvalsReviewer` | `"user"` or an allowed guardian reviewer | Use `"auto_review"` to let Codex review native approval prompts when allowed. |
| `defaultWorkspaceDir` | current process directory | Workspace used by `/codex bind` when `--cwd` is omitted. |
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, and `null` clears the override. Legacy `"fast"` is accepted as `"priority"`. |
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with Codex app-server 0.132.0 or newer so native Codex execution can run inside the active OpenClaw sandbox. |
The plugin blocks older or unversioned app-server handshakes. Codex app-server
must report stable version `0.125.0` or newer.
@@ -329,18 +329,29 @@ OpenClaw session lane so follow-up chat messages are not queued behind a stale
native turn.
Most non-terminal notifications for the same turn disarm that short watchdog
because Codex has proven the turn is still alive. Raw `custom_tool_call_output`
completions keep the short post-tool watchdog armed because they are the
turn-scoped tool-result handoff. Completed `agentMessage` items and pre-tool raw
assistant `rawResponseItem/completed` items arm the assistant-output release: if
Codex then goes quiet without `turn/completed`, OpenClaw best-effort interrupts
the native turn and releases the session lane. Post-tool raw assistant progress
keeps waiting for `turn/completed` while a completion-idle guard stays armed; the
guard uses `appServer.postToolRawAssistantCompletionIdleTimeoutMs` when
configured and falls back to the assistant completion idle timeout otherwise.
Timeout diagnostics include the last app-server notification method and, for raw
assistant response items, the item type, role, id, and a bounded assistant text
preview.
because Codex has proven the turn is still alive. Tool handoffs use a longer
post-tool idle budget: after OpenClaw returns an `item/tool/call` response, after
native tool items such as `commandExecution` complete, after raw
`custom_tool_call_output` completions, and after post-tool raw assistant
progress. The guard uses `appServer.postToolRawAssistantCompletionIdleTimeoutMs`
when configured and defaults to five minutes otherwise. That same post-tool
budget also extends the progress watchdog for the silent synthesis window before
Codex emits the next current-turn event. Reasoning completions, commentary
`agentMessage` completions, and pre-tool raw reasoning or assistant progress can
be followed by an automatic final reply, so they use the post-progress reply
guard instead of releasing the session lane immediately. Only
final/non-commentary completed `agentMessage` items and pre-tool raw assistant
completions arm the assistant-output release: if Codex then goes quiet without
`turn/completed`, OpenClaw best-effort interrupts the native turn and releases
the session lane. Replay-safe stdio app-server failures, including
turn-completion idle timeouts without assistant, tool, active-item, or
side-effect evidence, are retried once on a fresh app-server attempt. Unsafe
timeouts still retire the stuck app-server client and release the OpenClaw
session lane. They also clear the stale native thread binding and surface a
recoverable timeout message for user or maintainer judgment instead of being
replayed automatically. Timeout diagnostics include the last app-server
notification method and, for raw assistant response items, the item type, role,
id, and a bounded assistant text preview.
## Model discovery
@@ -422,15 +433,17 @@ filenames for persona files, because Codex fallbacks only apply when
For OpenClaw workspace parity, the Codex harness resolves the other bootstrap
files. `SOUL.md`, `IDENTITY.md`, `TOOLS.md`, and `USER.md` are forwarded as
OpenClaw Codex developer instructions because they define the active agent,
available workspace guidance, and user profile. `HEARTBEAT.md` content is not
injected; heartbeat turns get a collaboration-mode pointer to read the file when
it exists and is non-empty. `MEMORY.md` content from the configured agent
workspace is not pasted into native Codex turn input when memory tools are
available for that workspace; when it exists, the harness adds a small
workspace-memory pointer and Codex should use `memory_search` or `memory_get`
when durable memory is relevant. If tools are disabled, memory search is
unavailable, or the active workspace differs from the agent memory workspace,
`MEMORY.md` uses the normal bounded turn-context path.
available workspace guidance, and user profile. The compact OpenClaw skills
list is forwarded as turn-scoped collaboration developer instructions.
`HEARTBEAT.md` content is not injected; heartbeat turns get a collaboration-mode
pointer to read the file when it exists and is non-empty. `MEMORY.md` content
from the configured agent workspace is not pasted into native Codex turn input
when memory tools are available for that workspace; when it exists, the harness
adds a small workspace-memory pointer to turn-scoped collaboration developer
instructions and Codex should use `memory_search` or `memory_get` when durable
memory is relevant. If tools are disabled, memory search is unavailable, or the
active workspace differs from the agent memory workspace, `MEMORY.md` uses the
normal bounded turn-context path.
`BOOTSTRAP.md` when present is forwarded as OpenClaw turn input reference
context.

View File

@@ -34,9 +34,10 @@ personality files and OpenClaw agent identity stay authoritative. Lightweight
OpenClaw runs still preserve their existing project-doc suppression. OpenClaw
developer instructions cover OpenClaw runtime concerns such as source-channel
delivery, OpenClaw dynamic tools, ACP delegation, adapter context, and the
active agent workspace profile files. OpenClaw skill catalogs plus `MEMORY.md`
and active `BOOTSTRAP.md` content are projected as turn input reference context
for native Codex.
active agent workspace profile files. OpenClaw skill catalogs and tool-routed
`MEMORY.md` pointers are projected as turn-scoped collaboration developer
instructions for native Codex. Active `BOOTSTRAP.md` content and full
`MEMORY.md` fallback injection still use turn input reference context.
## Thread bindings and model changes

View File

@@ -44,7 +44,7 @@ Discord, Slack, or another channel remains the communication surface.
- Codex app-server `0.125.0` or newer. The bundled plugin manages a compatible
Codex app-server binary by default, so local `codex` commands on `PATH` do not
affect normal harness startup.
- Codex auth available through `openclaw models auth login --provider openai-codex`,
- Codex auth available through `openclaw models auth login --provider openai`,
an app-server account in the agent's Codex home, or an explicit Codex API-key
auth profile.
@@ -61,7 +61,7 @@ canonical `openai/gpt-*` model ref.
Sign in with Codex OAuth:
```bash
openclaw models auth login --provider openai-codex
openclaw models auth login --provider openai
```
Enable the bundled `codex` plugin and select an OpenAI agent model:
@@ -112,7 +112,7 @@ harness options in OpenClaw config, and use the CLI only for Codex auth:
| Enable the harness | `plugins.entries.codex.enabled: true` | OpenClaw config |
| Keep an allowlisted plugin install | Include `codex` in `plugins.allow` | OpenClaw config |
| Route OpenAI agent turns through Codex | `agents.defaults.model` or `agents.list[].model` as `openai/gpt-*` | OpenClaw agent config |
| Sign in with Codex OAuth | `openclaw models auth login --provider openai-codex` | CLI auth profile |
| Sign in with ChatGPT/Codex OAuth | `openclaw models auth login --provider openai` | CLI auth profile |
| Add API-key backup for Codex runs | `openai:*` API-key profile listed after subscription auth in `auth.order.openai` | CLI auth profile + OpenClaw config |
| Fail closed when Codex is unavailable | Provider or model `agentRuntime.id: "codex"` | OpenClaw model/provider config |
| Use direct OpenAI API traffic | Provider or model `agentRuntime.id: "openclaw"` with normal OpenAI auth | OpenClaw model/provider config |
@@ -153,7 +153,7 @@ instead of silently switching compaction backends.
{
auth: {
order: {
openai: ["openai-codex:user@example.com", "openai:api-key-backup"],
openai: ["openai:user@example.com", "openai:api-key-backup"],
},
},
}
@@ -444,7 +444,8 @@ For upload mechanics and runtime-level diagnostics boundaries, see
Auth is selected in this order:
1. Ordered OpenAI auth profiles for the agent, preferably under
`auth.order.openai`. Existing `openai-codex:*` profile ids remain valid.
`auth.order.openai`. Run `openclaw doctor --fix` to migrate older
`openai-codex:*` profile ids and `auth.order.openai-codex`.
2. The app-server's existing account in that agent's Codex home.
3. For local stdio app-server launches only, `CODEX_API_KEY`, then
`OPENAI_API_KEY`, when no app-server account is present and OpenAI auth is
@@ -525,25 +526,25 @@ Supported top-level Codex plugin fields:
Supported `appServer` fields:
| Field | Default | Meaning |
| --------------------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transport` | `"stdio"` | `"stdio"` spawns Codex; `"websocket"` connects to `url`. |
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary; set it only for an explicit override. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. OpenClaw keeps per-agent `CODEX_HOME` and inherited `HOME` for local launches. |
| `codeModeOnly` | `false` | Opt into Codex's code-mode-only tool surface. OpenClaw dynamic tools remain registered with Codex so nested `tools.*` calls return through the app-server `item/tool/call` bridge. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `turnCompletionIdleTimeoutMs` | `60000` | Quiet window after Codex accepts a turn or after a turn-scoped app-server request while OpenClaw waits for `turn/completed`. Raise this for slow post-tool or status-only synthesis phases. |
| `postToolRawAssistantCompletionIdleTimeoutMs` | unset | Completion-idle guard used after a tool handoff when Codex emits raw assistant completion or progress but does not send `turn/completed`. Defaults to the assistant completion idle timeout when unset. Use this for trusted or heavy workloads where post-tool synthesis can legitimately stay quiet longer than the final assistant release budget. |
| `mode` | `"yolo"` unless local Codex requirements disallow YOLO | Preset for YOLO or guardian-reviewed execution. Local stdio requirements that omit `danger-full-access`, `never` approval, or the `user` reviewer make the implicit default guardian. |
| `approvalPolicy` | `"never"` or an allowed guardian approval policy | Native Codex approval policy sent to thread start/resume/turn. Guardian defaults prefer `"on-request"` when allowed. |
| `sandbox` | `"danger-full-access"` or an allowed guardian sandbox | Native Codex sandbox mode sent to thread start/resume. Guardian defaults prefer `"workspace-write"` when allowed, otherwise `"read-only"`. When an OpenClaw sandbox is active, `danger-full-access` turns use Codex `workspace-write` with network access derived from the OpenClaw sandbox egress setting. |
| `approvalsReviewer` | `"user"` or an allowed guardian reviewer | Use `"auto_review"` to let Codex review native approval prompts when allowed, otherwise `guardian_subagent` or `user`. `guardian_subagent` remains a legacy alias. |
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, `null` clears the override, and legacy `"fast"` is accepted as `"priority"`. |
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with Codex app-server 0.132.0 or newer so native Codex execution can run inside the active OpenClaw sandbox. |
| Field | Default | Meaning |
| --------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `transport` | `"stdio"` | `"stdio"` spawns Codex; `"websocket"` connects to `url`. |
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary; set it only for an explicit override. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. OpenClaw keeps per-agent `CODEX_HOME` and inherited `HOME` for local launches. |
| `codeModeOnly` | `false` | Opt into Codex's code-mode-only tool surface. OpenClaw dynamic tools remain registered with Codex so nested `tools.*` calls return through the app-server `item/tool/call` bridge. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `turnCompletionIdleTimeoutMs` | `60000` | Quiet window after Codex accepts a turn or after a turn-scoped app-server request while OpenClaw waits for `turn/completed`. |
| `postToolRawAssistantCompletionIdleTimeoutMs` | `300000` | Completion-idle and progress guard used after a tool handoff, native tool completion, or post-tool raw assistant progress while OpenClaw waits for `turn/completed`. Use this for trusted or heavy workloads where post-tool synthesis can legitimately stay quiet longer than the final assistant release budget. |
| `mode` | `"yolo"` unless local Codex requirements disallow YOLO | Preset for YOLO or guardian-reviewed execution. Local stdio requirements that omit `danger-full-access`, `never` approval, or the `user` reviewer make the implicit default guardian. |
| `approvalPolicy` | `"never"` or an allowed guardian approval policy | Native Codex approval policy sent to thread start/resume/turn. Guardian defaults prefer `"on-request"` when allowed. |
| `sandbox` | `"danger-full-access"` or an allowed guardian sandbox | Native Codex sandbox mode sent to thread start/resume. Guardian defaults prefer `"workspace-write"` when allowed, otherwise `"read-only"`. When an OpenClaw sandbox is active, `danger-full-access` turns use Codex `workspace-write` with network access derived from the OpenClaw sandbox egress setting. |
| `approvalsReviewer` | `"user"` or an allowed guardian reviewer | Use `"auto_review"` to let Codex review native approval prompts when allowed, otherwise `guardian_subagent` or `user`. `guardian_subagent` remains a legacy alias. |
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, `null` clears the override, and legacy `"fast"` is accepted as `"priority"`. |
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with Codex app-server 0.132.0 or newer so native Codex execution can run inside the active OpenClaw sandbox. |
OpenClaw-owned dynamic tool calls are bounded independently from
`appServer.requestTimeoutMs`: Codex `item/tool/call` requests use a 90 second
@@ -564,20 +565,30 @@ quiet for `appServer.turnCompletionIdleTimeoutMs`, OpenClaw best-effort
interrupts the Codex turn, records a diagnostic timeout, and releases the
OpenClaw session lane so follow-up chat messages are not queued behind a stale
native turn. Most non-terminal notifications for the same turn disarm that short
watchdog because Codex has proven the turn is still alive; raw
`custom_tool_call_output` completions keep the short post-tool watchdog armed
because they are the turn-scoped tool-result handoff. Global app-server
notifications, such as rate-limit updates, do not reset turn-idle progress.
Completed `agentMessage` items and pre-tool raw assistant
`rawResponseItem/completed` items arm the assistant-output release: if Codex then
goes quiet without `turn/completed`, OpenClaw best-effort interrupts the native
turn and releases the session lane. Post-tool raw assistant progress keeps
waiting for `turn/completed` while a completion-idle guard stays armed; the guard
uses `appServer.postToolRawAssistantCompletionIdleTimeoutMs` when configured and
falls back to the assistant completion idle timeout otherwise. Timeout
diagnostics include the last app-server notification method and, for raw
assistant response items, the item type, role, id, and a bounded assistant text
preview.
watchdog because Codex has proven the turn is still alive. Tool handoffs use a
longer post-tool idle budget: after OpenClaw returns an `item/tool/call`
response, after native tool items such as `commandExecution` complete, after raw
`custom_tool_call_output` completions, and after post-tool raw assistant
progress. The guard uses `appServer.postToolRawAssistantCompletionIdleTimeoutMs`
when configured and defaults to five minutes otherwise. That same post-tool
budget also extends the progress watchdog for the silent synthesis window before
Codex emits the next current-turn event. Global app-server notifications, such
as rate-limit updates, do not reset turn-idle progress. Reasoning completions,
commentary `agentMessage` completions, and pre-tool raw reasoning or assistant
progress can be followed by an automatic final reply, so they use the
post-progress reply guard instead of releasing the session lane immediately.
Only final/non-commentary completed `agentMessage` items and pre-tool raw
assistant completions arm the assistant-output release: if Codex then goes quiet
without `turn/completed`, OpenClaw best-effort interrupts the native turn and
releases the session lane. Replay-safe stdio app-server failures, including
turn-completion idle timeouts without assistant, tool, active-item, or
side-effect evidence, are retried once on a fresh app-server attempt. Unsafe
timeouts still retire the stuck app-server client and release the OpenClaw
session lane. They also clear the stale native thread binding and surface a
recoverable timeout message for user or maintainer judgment instead of being
replayed automatically. Timeout diagnostics include the last app-server
notification method and, for raw assistant response items, the item type, role,
id, and a bounded assistant text preview.
Environment overrides remain available for local testing:
@@ -715,7 +726,7 @@ Ask affected collaborators to run this read-only command on their OpenClaw host:
Useful excerpts usually include `openai/gpt-5.5` or `openai/gpt-5.4`,
`Runtime: OpenAI Codex`, `agentRuntime.id` or `harnessRuntime`,
`candidateProvider: "openai"`, and a `401`, `Incorrect API key`, or
`No API key` result. A corrected run should show the `openai-codex` OAuth
`No API key` result. A corrected run should show the OpenAI OAuth
path instead of a plain OpenAI API-key failure.
**Legacy `openai-codex/*` config remains:** run `openclaw doctor --fix`.

View File

@@ -1,13 +1,13 @@
---
summary: "Run OpenClaw embedded agent turns through the bundled GitHub Copilot SDK harness"
summary: "Run OpenClaw embedded agent turns through the external GitHub Copilot SDK harness"
title: "Copilot SDK harness"
read_when:
- You want to use the bundled GitHub Copilot SDK harness for an agent
- You want to use the GitHub Copilot SDK harness for an agent
- You need configuration examples for the `copilot` runtime
- You are wiring an agent to subscription Copilot (github / openclaw / copilot) and want it to run through the Copilot CLI
---
The bundled `copilot` extension lets OpenClaw run embedded subscription
The external `@openclaw/copilot` plugin lets OpenClaw run embedded subscription
Copilot agent turns through the GitHub Copilot CLI (`@github/copilot-sdk`)
instead of the built-in PI harness.
@@ -24,11 +24,11 @@ For the broader model/provider/runtime split, start with
## Requirements
- OpenClaw with the bundled `copilot` extension available.
- OpenClaw with the `@openclaw/copilot` plugin installed.
- If your config uses `plugins.allow`, include `copilot` (the manifest
id in `extensions/copilot/openclaw.plugin.json`). A restrictive
id declared by the plugin). A restrictive
allowlist that uses the npm-style `@openclaw/copilot` package name
will leave the bundled plugin blocked and the runtime will not load
will leave the plugin blocked and the runtime will not load
even with `agentRuntime.id: "copilot"`.
- A GitHub Copilot subscription that can drive the Copilot CLI (or a
`gitHubToken` env / auth-profile entry for headless / cron runs).
@@ -38,56 +38,38 @@ For the broader model/provider/runtime split, start with
or `~/.config/copilot` elsewhere) is used as the doctor probe fallback when
no explicit home is set.
`openclaw doctor` runs the bundled
`openclaw doctor` runs the plugin
[doctor contract](#doctor-and-probes) for the extension; failures there are
the canonical way to confirm the environment is ready before opting an agent
in.
## On-demand SDK install
## Plugin install
The Copilot agent runtime ships its small TypeScript code bundled inside
the openclaw tarball, but the underlying `@github/copilot-sdk` package
(and its platform-specific `@github/copilot-<platform>-<arch>` CLI
binary) is **not** installed by default — together they add ~260 MB to
your openclaw install footprint, and most openclaw users do not select
a Copilot model.
The Copilot runtime is an external plugin so the core `openclaw` package does
not carry the `@github/copilot-sdk` dependency or its platform-specific
`@github/copilot-<platform>-<arch>` CLI binary. Together they add roughly
260 MB, so install them only for agents that opt into this runtime:
The wizard offers to install the SDK the first time you select a
```bash
openclaw plugins install @openclaw/copilot
```
The wizard installs the plugin the first time you select a
`github-copilot/*` model **and** your config opts the model (or its
provider) into the Copilot agent runtime via
`agentRuntime: { id: "copilot" }` (see [Quickstart](#quickstart) below).
Without the opt-in, openclaw uses its built-in GitHub Copilot provider
and never prompts for the SDK install:
```
The Copilot agent runtime needs @github/copilot-sdk (~260 MB on first
install, downloads the @github/copilot CLI binary for your platform).
Install now? [Y/n]
```
If you accept, the SDK is installed into
`~/.openclaw/npm-runtime/copilot/` and detected on subsequent runs. The
install runs `npm ci` against a checked-in `package-lock.json` shipped
with openclaw at
`src/commands/copilot-sdk-install-manifest/package-lock.json`, so the
exact transitive graph reviewed for this release lands on disk on every
user machine.
If you decline, the runtime will fail at first invocation with an
actionable install message; re-run `openclaw setup` to retry the install
(or copy the pinned manifest into `~/.openclaw/npm-runtime/copilot/` and
run `npm ci` yourself if you need to install offline).
and never installs the runtime plugin.
The runtime resolves the SDK in this order:
1. `import("@github/copilot-sdk")` against the host openclaw install
(covers source/dev checkouts and any environment that pre-installs
the SDK alongside openclaw).
1. `import("@github/copilot-sdk")` from the installed `@openclaw/copilot`
package.
2. The well-known fallback dir `~/.openclaw/npm-runtime/copilot/` (the
wizard install target).
legacy on-demand install target).
A missing SDK surfaces a single error with code `COPILOT_SDK_MISSING`
and the manual install command above.
and the plugin reinstall command above.
## Quickstart

View File

@@ -141,7 +141,10 @@ observation-only.
**Subagents**
- `subagent_spawning` / `subagent_delivery_target` / `subagent_spawned` / `subagent_ended` - coordinate subagent routing and completion delivery
- `subagent_spawned` / `subagent_ended` - observe subagent launch and completion.
- `subagent_delivery_target` - compatibility hook for completion delivery when no core session binding can project a route.
- `subagent_spawning` - deprecated compatibility hook. Core now prepares `thread: true` subagent bindings through channel session-binding adapters before `subagent_spawned` fires.
- `subagent_spawned` includes `resolvedModel` and `resolvedProvider` when OpenClaw has resolved the child session's native model before launch.
**Lifecycle**
@@ -463,6 +466,10 @@ before the next major release:
- **`before_agent_start`** remains for compatibility. New plugins should use
`before_model_resolve` and `before_prompt_build` instead of the combined
phase.
- **`subagent_spawning`** remains for compatibility with older plugins, but
new plugins should not return thread routing from it. Core prepares
`thread: true` subagent bindings through channel session-binding adapters
before `subagent_spawned` fires.
- **`deactivate`** remains as a deprecated cleanup compatibility alias until
after 2026-08-16. New plugins should use `gateway_stop`.
- **`onResolution` in `before_tool_call`** now uses the typed

View File

@@ -169,6 +169,7 @@ or npm install metadata. Those belong in your plugin code and `package.json`.
| `modelIdNormalization` | No | `object` | Provider-owned model-id alias/prefix cleanup that must run before provider runtime loads. |
| `providerEndpoints` | No | `object[]` | Manifest-owned endpoint host/baseUrl metadata for provider routes that core must classify before provider runtime loads. |
| `providerRequest` | No | `object` | Cheap provider-family and request-compatibility metadata used by generic request policy before provider runtime loads. |
| `secretProviderIntegrations` | No | `Record<string, object>` | Declarative SecretRef exec provider presets that setup or install surfaces can offer without hardcoding provider-specific integrations in core. |
| `cliBackends` | No | `string[]` | CLI inference backend ids owned by this plugin. Used for startup auto-activation from explicit config refs. |
| `syntheticAuthRefs` | No | `string[]` | Provider or CLI backend refs whose plugin-owned synthetic auth hook should be probed during cold model discovery before runtime loads. |
| `nonSecretAuthMarkers` | No | `string[]` | Bundled-plugin-owned placeholder API key values that represent non-secret local, OAuth, or ambient credential state. |
@@ -635,7 +636,7 @@ read without importing the plugin runtime.
"realtimeTranscriptionProviders": ["openai"],
"realtimeVoiceProviders": ["openai"],
"memoryEmbeddingProviders": ["local"],
"mediaUnderstandingProviders": ["openai", "openai-codex"],
"mediaUnderstandingProviders": ["openai"],
"imageGenerationProviders": ["openai"],
"videoGenerationProviders": ["qwen"],
"webFetchProviders": ["firecrawl"],
@@ -1080,6 +1081,72 @@ Provider fields:
| `compatibilityFamily` | `"moonshot"` | Optional provider-family compatibility bucket for shared request helpers. |
| `openAICompletions` | `object` | OpenAI-compatible completions request flags, currently `supportsStreamingUsage`. |
## secretProviderIntegrations reference
Use `secretProviderIntegrations` when a plugin can publish a reusable SecretRef
exec provider preset. OpenClaw reads this metadata before plugin runtime loads,
stores plugin ownership in `secrets.providers.<alias>.pluginIntegration`, and
leaves actual secret resolution to the SecretRef runtime.
Presets are exposed only for bundled plugins and installed plugins discovered
from the managed plugin install roots, such as git and ClawHub installs.
```json
{
"secretProviderIntegrations": {
"secret-store": {
"providerAlias": "team-secrets",
"displayName": "Team secrets",
"source": "exec",
"command": "${node}",
"args": ["./bin/resolve-secrets.mjs"]
}
}
}
```
The map key is the integration id. If `providerAlias` is omitted, OpenClaw uses
the integration id as the SecretRef provider alias. Provider aliases must match
the normal SecretRef provider alias pattern, for example `team-secrets` or
`onepassword-work`.
When an operator selects the preset, OpenClaw writes a provider reference like:
```json
{
"secrets": {
"providers": {
"team-secrets": {
"source": "exec",
"pluginIntegration": {
"pluginId": "acme-secrets",
"integrationId": "secret-store"
}
}
}
}
}
```
At startup/reload, OpenClaw resolves that provider by loading current plugin
manifest metadata, checking that the owning plugin is installed and active, and
materializing the exec command from the manifest. Disabling or removing the
plugin revokes the provider for active SecretRefs. Operators who want standalone
exec configuration can still write manual `command`/`args` providers directly.
Only `source: "exec"` presets are currently supported. `command` must be
`${node}`, and `args[0]` must be a `./` plugin-root-relative resolver script.
OpenClaw materializes it at startup/reload to the current Node executable and
the absolute in-plugin script path. Node options such as `--require`, `--import`,
`--loader`, `--env-file`, `--eval`, and `--print` are not part of the manifest
preset contract. Operators who need non-Node commands can configure standalone
manual exec providers directly.
OpenClaw derives `trustedDirs` for manifest presets from the plugin root and,
for `${node}` presets, the current Node executable directory. Manifest-authored
`trustedDirs` are ignored. Other exec provider options such as `timeoutMs`,
`maxOutputBytes`, `jsonOnly`, `env`, `passEnv`, and `allowInsecurePath` pass
through to the normal SecretRef exec provider config.
## modelPricing reference
Use `modelPricing` when a provider needs control-plane pricing behavior before

View File

@@ -125,8 +125,8 @@ embeddings:
}
```
OpenAI Codex / ChatGPT OAuth (`openai-codex`) is not an OpenAI Platform
embeddings credential. For OpenAI embeddings, use an OpenAI API key auth profile,
OpenAI Codex / ChatGPT OAuth is not an OpenAI Platform embeddings credential.
For OpenAI embeddings, use an OpenAI API key auth profile,
`OPENAI_API_KEY`, or `models.providers.openai.apiKey`. OAuth-only users can use
another embedding-capable provider such as GitHub Copilot or Ollama.

View File

@@ -66,7 +66,6 @@ commands.
| [cloudflare-ai-gateway](/plugins/reference/cloudflare-ai-gateway) | Adds Cloudflare AI Gateway model provider support to OpenClaw. | `@openclaw/cloudflare-ai-gateway-provider`<br />included in OpenClaw | providers: cloudflare-ai-gateway |
| [codex-supervisor](/plugins/reference/codex-supervisor) | Supervise Codex app-server sessions from OpenClaw. | `@openclaw/codex-supervisor`<br />included in OpenClaw | contracts: tools |
| [comfy](/plugins/reference/comfy) | Adds ComfyUI model provider support to OpenClaw. | `@openclaw/comfy-provider`<br />included in OpenClaw | providers: comfy; contracts: imageGenerationProviders, musicGenerationProviders, videoGenerationProviders |
| [copilot](/plugins/reference/copilot) | Registers the GitHub Copilot agent runtime. | `@openclaw/copilot`<br />included in OpenClaw | plugin |
| [copilot-proxy](/plugins/reference/copilot-proxy) | Adds Copilot Proxy model provider support to OpenClaw. | `@openclaw/copilot-proxy`<br />included in OpenClaw | providers: copilot-proxy |
| [deepgram](/plugins/reference/deepgram) | Adds media understanding provider support. Adds realtime transcription provider support. | `@openclaw/deepgram-provider`<br />included in OpenClaw | contracts: mediaUnderstandingProviders, realtimeTranscriptionProviders |
| [deepinfra](/plugins/reference/deepinfra) | Adds DeepInfra model provider support to OpenClaw. | `@openclaw/deepinfra-provider`<br />included in OpenClaw | providers: deepinfra; contracts: imageGenerationProviders, mediaUnderstandingProviders, memoryEmbeddingProviders, speechProviders, videoGenerationProviders |
@@ -80,6 +79,7 @@ commands.
| [firecrawl](/plugins/reference/firecrawl) | Adds agent-callable tools. Adds web fetch provider support. Adds web search provider support. | `@openclaw/firecrawl-plugin`<br />included in OpenClaw | contracts: tools, webFetchProviders, webSearchProviders |
| [fireworks](/plugins/reference/fireworks) | Adds Fireworks model provider support to OpenClaw. | `@openclaw/fireworks-provider`<br />included in OpenClaw | providers: fireworks |
| [github-copilot](/plugins/reference/github-copilot) | Adds GitHub Copilot model provider support to OpenClaw. | `@openclaw/github-copilot-provider`<br />included in OpenClaw | providers: github-copilot; contracts: memoryEmbeddingProviders |
| [gmi](/plugins/reference/gmi) | Adds Gmi, Gmi Cloud, Gmicloud model provider support to OpenClaw. | `@openclaw/gmi-provider`<br />included in OpenClaw | providers: gmi, gmi-cloud, gmicloud |
| [google](/plugins/reference/google) | Adds Google, Google Gemini CLI, Google Vertex model provider support to OpenClaw. | `@openclaw/google-plugin`<br />included in OpenClaw | providers: google, google-gemini-cli, google-vertex; contracts: imageGenerationProviders, mediaUnderstandingProviders, memoryEmbeddingProviders, musicGenerationProviders, realtimeVoiceProviders, speechProviders, videoGenerationProviders, webSearchProviders |
| [gradium](/plugins/reference/gradium) | Adds text-to-speech provider support. | `@openclaw/gradium-speech`<br />included in OpenClaw | contracts: speechProviders |
| [groq](/plugins/reference/groq) | Adds Groq model provider support to OpenClaw. | `@openclaw/groq-provider`<br />included in OpenClaw | providers: groq; contracts: mediaUnderstandingProviders |
@@ -102,31 +102,30 @@ commands.
| [minimax](/plugins/reference/minimax) | Adds MiniMax, MiniMax Portal model provider support to OpenClaw. | `@openclaw/minimax-provider`<br />included in OpenClaw | providers: minimax, minimax-portal; contracts: imageGenerationProviders, mediaUnderstandingProviders, musicGenerationProviders, speechProviders, videoGenerationProviders, webSearchProviders |
| [mistral](/plugins/reference/mistral) | Adds Mistral model provider support to OpenClaw. | `@openclaw/mistral-provider`<br />included in OpenClaw | providers: mistral; contracts: mediaUnderstandingProviders, memoryEmbeddingProviders, realtimeTranscriptionProviders |
| [moonshot](/plugins/reference/moonshot) | Adds Moonshot model provider support to OpenClaw. | `@openclaw/moonshot-provider`<br />included in OpenClaw | providers: moonshot; contracts: mediaUnderstandingProviders, webSearchProviders |
| [novita](/plugins/reference/novita) | Adds Novita, Novita AI, Novitaai model provider support to OpenClaw. | `@openclaw/novita-provider`<br />included in OpenClaw | providers: novita, novita-ai, novitaai |
| [nvidia](/plugins/reference/nvidia) | Adds NVIDIA model provider support to OpenClaw. | `@openclaw/nvidia-provider`<br />included in OpenClaw | providers: nvidia |
| [oc-path](/plugins/reference/oc-path) | Adds the openclaw path CLI for oc:// workspace file addressing. | `@openclaw/oc-path`<br />included in OpenClaw | plugin |
| [ollama](/plugins/reference/ollama) | Adds Ollama model provider support to OpenClaw. | `@openclaw/ollama-provider`<br />included in OpenClaw | providers: ollama; contracts: memoryEmbeddingProviders, webSearchProviders |
| [ollama](/plugins/reference/ollama) | Adds Ollama, Ollama Cloud model provider support to OpenClaw. | `@openclaw/ollama-provider`<br />included in OpenClaw | providers: ollama, ollama-cloud; contracts: memoryEmbeddingProviders, webSearchProviders |
| [open-prose](/plugins/reference/open-prose) | OpenProse VM skill pack with a /prose slash command. | `@openclaw/open-prose`<br />included in OpenClaw | skills |
| [openai](/plugins/reference/openai) | Adds OpenAI, OpenAI Codex model provider support to OpenClaw. | `@openclaw/openai-provider`<br />included in OpenClaw | providers: openai, openai-codex; contracts: imageGenerationProviders, mediaUnderstandingProviders, memoryEmbeddingProviders, realtimeTranscriptionProviders, realtimeVoiceProviders, speechProviders, videoGenerationProviders |
| [openai](/plugins/reference/openai) | Adds OpenAI model provider support to OpenClaw, including ChatGPT/Codex OAuth. | `@openclaw/openai-provider`<br />included in OpenClaw | providers: openai; contracts: imageGenerationProviders, mediaUnderstandingProviders, memoryEmbeddingProviders, realtimeTranscriptionProviders, realtimeVoiceProviders, speechProviders, videoGenerationProviders |
| [opencode](/plugins/reference/opencode) | Adds OpenCode model provider support to OpenClaw. | `@openclaw/opencode-provider`<br />included in OpenClaw | providers: opencode; contracts: mediaUnderstandingProviders |
| [opencode-go](/plugins/reference/opencode-go) | Adds OpenCode Go model provider support to OpenClaw. | `@openclaw/opencode-go-provider`<br />included in OpenClaw | providers: opencode-go; contracts: mediaUnderstandingProviders |
| [openrouter](/plugins/reference/openrouter) | Adds OpenRouter model provider support to OpenClaw. | `@openclaw/openrouter-provider`<br />included in OpenClaw | providers: openrouter; contracts: imageGenerationProviders, mediaUnderstandingProviders, musicGenerationProviders, speechProviders, videoGenerationProviders |
| [perplexity](/plugins/reference/perplexity) | Adds web search provider support. | `@openclaw/perplexity-plugin`<br />included in OpenClaw | contracts: webSearchProviders |
| [policy](/plugins/reference/policy) | Adds policy-backed doctor checks for workspace conformance. | `@openclaw/policy`<br />included in OpenClaw | plugin |
| [qianfan](/plugins/reference/qianfan) | Adds Qianfan model provider support to OpenClaw. | `@openclaw/qianfan-provider`<br />included in OpenClaw | providers: qianfan |
| [qwen](/plugins/reference/qwen) | Adds Qwen, Qwen Cloud, Model Studio, DashScope model provider support to OpenClaw. | `@openclaw/qwen-provider`<br />included in OpenClaw | providers: qwen, qwencloud, modelstudio, dashscope; contracts: mediaUnderstandingProviders, videoGenerationProviders |
| [qwen](/plugins/reference/qwen) | Adds Qwen, Qwen Cloud, Model Studio, DashScope, Qwen Oauth, Qwen Portal, Qwen CLI model provider support to OpenClaw. | `@openclaw/qwen-provider`<br />included in OpenClaw | providers: qwen, qwencloud, modelstudio, dashscope, qwen-oauth, qwen-portal, qwen-cli; contracts: mediaUnderstandingProviders, videoGenerationProviders |
| [runway](/plugins/reference/runway) | Adds video generation provider support. | `@openclaw/runway-provider`<br />included in OpenClaw | contracts: videoGenerationProviders |
| [searxng](/plugins/reference/searxng) | Adds web search provider support. | `@openclaw/searxng-plugin`<br />included in OpenClaw | contracts: webSearchProviders |
| [senseaudio](/plugins/reference/senseaudio) | Adds media understanding provider support. | `@openclaw/senseaudio-provider`<br />included in OpenClaw | contracts: mediaUnderstandingProviders |
| [sglang](/plugins/reference/sglang) | Adds SGLang model provider support to OpenClaw. | `@openclaw/sglang-provider`<br />included in OpenClaw | providers: sglang |
| [signal](/plugins/reference/signal) | Adds the Signal channel surface for sending and receiving OpenClaw messages. | `@openclaw/signal`<br />included in OpenClaw | channels: signal |
| [skill-workshop](/plugins/reference/skill-workshop) | Captures repeatable workflows as workspace skills, with pending review, safe writes, and skill prompt refresh. | `@openclaw/skill-workshop`<br />included in OpenClaw | contracts: tools |
| [stepfun](/plugins/reference/stepfun) | Adds StepFun, StepFun Plan model provider support to OpenClaw. | `@openclaw/stepfun-provider`<br />included in OpenClaw | providers: stepfun, stepfun-plan |
| [synthetic](/plugins/reference/synthetic) | Adds Synthetic model provider support to OpenClaw. | `@openclaw/synthetic-provider`<br />included in OpenClaw | providers: synthetic |
| [tavily](/plugins/reference/tavily) | Adds agent-callable tools. Adds web search provider support. | `@openclaw/tavily-plugin`<br />included in OpenClaw | contracts: tools, webSearchProviders; skills |
| [telegram](/plugins/reference/telegram) | Adds the Telegram channel surface for sending and receiving OpenClaw messages. | `@openclaw/telegram`<br />included in OpenClaw | channels: telegram |
| [tencent](/plugins/reference/tencent) | Adds Tencent TokenHub model provider support to OpenClaw. | `@openclaw/tencent-provider`<br />included in OpenClaw | providers: tencent-tokenhub |
| [together](/plugins/reference/together) | Adds Together model provider support to OpenClaw. | `@openclaw/together-provider`<br />included in OpenClaw | providers: together; contracts: videoGenerationProviders |
| [tokenjuice](/plugins/reference/tokenjuice) | Compacts exec and bash tool results with tokenjuice reducers. | `@openclaw/tokenjuice`<br />included in OpenClaw | contracts: agentToolResultMiddleware |
| [tts-local-cli](/plugins/reference/tts-local-cli) | Adds text-to-speech provider support. | `@openclaw/tts-local-cli`<br />included in OpenClaw | contracts: speechProviders |
| [venice](/plugins/reference/venice) | Adds Venice model provider support to OpenClaw. | `@openclaw/venice-provider`<br />included in OpenClaw | providers: venice |
| [vercel-ai-gateway](/plugins/reference/vercel-ai-gateway) | Adds Vercel AI Gateway model provider support to OpenClaw. | `@openclaw/vercel-ai-gateway-provider`<br />included in OpenClaw | providers: vercel-ai-gateway |
@@ -136,9 +135,9 @@ commands.
| [vydra](/plugins/reference/vydra) | Adds Vydra model provider support to OpenClaw. | `@openclaw/vydra-provider`<br />included in OpenClaw | providers: vydra; contracts: imageGenerationProviders, speechProviders, videoGenerationProviders |
| [web-readability](/plugins/reference/web-readability) | Extract readable article content from local HTML web fetch responses. | `@openclaw/web-readability-plugin`<br />included in OpenClaw | contracts: webContentExtractors |
| [webhooks](/plugins/reference/webhooks) | Authenticated inbound webhooks that bind external automation to OpenClaw TaskFlows. | `@openclaw/webhooks`<br />included in OpenClaw | plugin |
| [workboard](/plugins/reference/workboard) | Dashboard workboard for agent-owned issues and sessions. | `@openclaw/workboard`<br />included in OpenClaw | plugin |
| [workboard](/plugins/reference/workboard) | Dashboard workboard for agent-owned issues and sessions. | `@openclaw/workboard`<br />included in OpenClaw | contracts: tools |
| [xai](/plugins/reference/xai) | Adds xAI model provider support to OpenClaw. | `@openclaw/xai-plugin`<br />included in OpenClaw | providers: xai; contracts: imageGenerationProviders, mediaUnderstandingProviders, realtimeTranscriptionProviders, speechProviders, tools, videoGenerationProviders, webSearchProviders |
| [xiaomi](/plugins/reference/xiaomi) | Adds Xiaomi model provider support to OpenClaw. | `@openclaw/xiaomi-provider`<br />included in OpenClaw | providers: xiaomi; contracts: speechProviders |
| [xiaomi](/plugins/reference/xiaomi) | Adds Xiaomi MiMo pay-as-you-go and Token Plan provider support to OpenClaw. | `@openclaw/xiaomi-provider`<br />included in OpenClaw | providers: xiaomi, xiaomi-token-plan; contracts: speechProviders |
| [zai](/plugins/reference/zai) | Adds Z.AI model provider support to OpenClaw. | `@openclaw/zai-provider`<br />included in OpenClaw | providers: zai; contracts: mediaUnderstandingProviders |
## Official external packages
@@ -151,6 +150,7 @@ commands.
| [anthropic-vertex](/plugins/reference/anthropic-vertex) | OpenClaw Anthropic Vertex provider plugin for Claude models on Google Vertex AI. | `@openclaw/anthropic-vertex-provider`<br />npm; ClawHub | providers: anthropic-vertex |
| [brave](/plugins/reference/brave) | OpenClaw Brave Search provider plugin for web search. | `@openclaw/brave-plugin`<br />npm; ClawHub | contracts: webSearchProviders |
| [codex](/plugins/reference/codex) | OpenClaw Codex app-server harness and model provider plugin with a Codex-managed GPT catalog. | `@openclaw/codex`<br />npm; ClawHub | providers: codex; contracts: mediaUnderstandingProviders, migrationProviders |
| [copilot](/plugins/reference/copilot) | Registers the GitHub Copilot agent runtime. | `@openclaw/copilot`<br />npm; ClawHub: `clawhub:@openclaw/copilot` | plugin |
| [diagnostics-otel](/plugins/reference/diagnostics-otel) | OpenClaw diagnostics OpenTelemetry exporter for metrics and traces. | `@openclaw/diagnostics-otel`<br />npm; ClawHub: `clawhub:@openclaw/diagnostics-otel` | plugin |
| [diagnostics-prometheus](/plugins/reference/diagnostics-prometheus) | OpenClaw diagnostics Prometheus exporter for runtime metrics. | `@openclaw/diagnostics-prometheus`<br />npm; ClawHub: `clawhub:@openclaw/diagnostics-prometheus` | plugin |
| [diffs](/plugins/reference/diffs) | OpenClaw read-only diff viewer plugin and file renderer for agents. | `@openclaw/diffs`<br />npm; ClawHub | contracts: tools; skills |
@@ -167,11 +167,12 @@ commands.
| [nextcloud-talk](/plugins/reference/nextcloud-talk) | OpenClaw Nextcloud Talk channel plugin for conversations. | `@openclaw/nextcloud-talk`<br />npm; ClawHub | channels: nextcloud-talk |
| [nostr](/plugins/reference/nostr) | OpenClaw Nostr channel plugin for NIP-04 encrypted direct messages. | `@openclaw/nostr`<br />npm; ClawHub | channels: nostr |
| [openshell](/plugins/reference/openshell) | OpenClaw sandbox backend for the NVIDIA OpenShell CLI with mirrored local workspaces and SSH command execution. | `@openclaw/openshell-sandbox`<br />npm; ClawHub | plugin |
| [pixverse](/plugins/reference/pixverse) | OpenClaw PixVerse video generation provider plugin. | `@openclaw/pixverse-provider`<br />npm; ClawHub | contracts: videoGenerationProviders |
| [pixverse](/plugins/reference/pixverse) | OpenClaw PixVerse video generation provider plugin. | `@openclaw/pixverse-provider`<br />npm; ClawHub: `clawhub:@openclaw/pixverse-provider` | contracts: videoGenerationProviders |
| [qqbot](/plugins/reference/qqbot) | OpenClaw QQ Bot channel plugin for group and direct-message workflows. | `@openclaw/qqbot`<br />npm; ClawHub | channels: qqbot; contracts: tools; skills |
| [slack](/plugins/reference/slack) | OpenClaw Slack channel plugin for channels, DMs, commands, and app events. | `@openclaw/slack`<br />npm; ClawHub | channels: slack |
| [synology-chat](/plugins/reference/synology-chat) | Synology Chat channel plugin for OpenClaw channels and direct messages. | `@openclaw/synology-chat`<br />npm; ClawHub | channels: synology-chat |
| [tlon](/plugins/reference/tlon) | OpenClaw Tlon/Urbit channel plugin for chat workflows. | `@openclaw/tlon`<br />npm; ClawHub | channels: tlon; skills |
| [tokenjuice](/plugins/reference/tokenjuice) | Compacts exec and bash tool results with tokenjuice reducers. | `@openclaw/tokenjuice`<br />npm; ClawHub: `clawhub:@openclaw/tokenjuice` | contracts: agentToolResultMiddleware |
| [twitch](/plugins/reference/twitch) | OpenClaw Twitch channel plugin for chat and moderation workflows. | `@openclaw/twitch`<br />npm; ClawHub | channels: twitch |
| [voice-call](/plugins/reference/voice-call) | OpenClaw voice-call plugin for Twilio, Telnyx, and Plivo phone calls. | `@openclaw/voice-call`<br />npm; ClawHub | contracts: tools |
| [whatsapp](/plugins/reference/whatsapp) | OpenClaw WhatsApp channel plugin for WhatsApp Web chats. | `@openclaw/whatsapp`<br />ClawHub: `clawhub:@openclaw/whatsapp`; npm | channels: whatsapp |

View File

@@ -38,7 +38,7 @@ pnpm plugins:inventory:gen
| [codex](/plugins/reference/codex) | OpenClaw Codex app-server harness and model provider plugin with a Codex-managed GPT catalog. | `@openclaw/codex`<br />npm; ClawHub | providers: codex; contracts: mediaUnderstandingProviders, migrationProviders |
| [codex-supervisor](/plugins/reference/codex-supervisor) | Supervise Codex app-server sessions from OpenClaw. | `@openclaw/codex-supervisor`<br />included in OpenClaw | contracts: tools |
| [comfy](/plugins/reference/comfy) | Adds ComfyUI model provider support to OpenClaw. | `@openclaw/comfy-provider`<br />included in OpenClaw | providers: comfy; contracts: imageGenerationProviders, musicGenerationProviders, videoGenerationProviders |
| [copilot](/plugins/reference/copilot) | Registers the GitHub Copilot agent runtime. | `@openclaw/copilot`<br />included in OpenClaw | plugin |
| [copilot](/plugins/reference/copilot) | Registers the GitHub Copilot agent runtime. | `@openclaw/copilot`<br />npm; ClawHub: `clawhub:@openclaw/copilot` | plugin |
| [copilot-proxy](/plugins/reference/copilot-proxy) | Adds Copilot Proxy model provider support to OpenClaw. | `@openclaw/copilot-proxy`<br />included in OpenClaw | providers: copilot-proxy |
| [deepgram](/plugins/reference/deepgram) | Adds media understanding provider support. Adds realtime transcription provider support. | `@openclaw/deepgram-provider`<br />included in OpenClaw | contracts: mediaUnderstandingProviders, realtimeTranscriptionProviders |
| [deepinfra](/plugins/reference/deepinfra) | Adds DeepInfra model provider support to OpenClaw. | `@openclaw/deepinfra-provider`<br />included in OpenClaw | providers: deepinfra; contracts: imageGenerationProviders, mediaUnderstandingProviders, memoryEmbeddingProviders, speechProviders, videoGenerationProviders |
@@ -58,6 +58,7 @@ pnpm plugins:inventory:gen
| [firecrawl](/plugins/reference/firecrawl) | Adds agent-callable tools. Adds web fetch provider support. Adds web search provider support. | `@openclaw/firecrawl-plugin`<br />included in OpenClaw | contracts: tools, webFetchProviders, webSearchProviders |
| [fireworks](/plugins/reference/fireworks) | Adds Fireworks model provider support to OpenClaw. | `@openclaw/fireworks-provider`<br />included in OpenClaw | providers: fireworks |
| [github-copilot](/plugins/reference/github-copilot) | Adds GitHub Copilot model provider support to OpenClaw. | `@openclaw/github-copilot-provider`<br />included in OpenClaw | providers: github-copilot; contracts: memoryEmbeddingProviders |
| [gmi](/plugins/reference/gmi) | Adds Gmi, Gmi Cloud, Gmicloud model provider support to OpenClaw. | `@openclaw/gmi-provider`<br />included in OpenClaw | providers: gmi, gmi-cloud, gmicloud |
| [google](/plugins/reference/google) | Adds Google, Google Gemini CLI, Google Vertex model provider support to OpenClaw. | `@openclaw/google-plugin`<br />included in OpenClaw | providers: google, google-gemini-cli, google-vertex; contracts: imageGenerationProviders, mediaUnderstandingProviders, memoryEmbeddingProviders, musicGenerationProviders, realtimeVoiceProviders, speechProviders, videoGenerationProviders, webSearchProviders |
| [google-meet](/plugins/reference/google-meet) | OpenClaw Google Meet participant plugin for joining calls through Chrome or Twilio transports. | `@openclaw/google-meet`<br />npm; ClawHub | contracts: tools |
| [googlechat](/plugins/reference/googlechat) | OpenClaw Google Chat channel plugin for spaces and direct messages. | `@openclaw/googlechat`<br />npm; ClawHub | channels: googlechat |
@@ -89,30 +90,30 @@ pnpm plugins:inventory:gen
| [msteams](/plugins/reference/msteams) | OpenClaw Microsoft Teams channel plugin for bot conversations. | `@openclaw/msteams`<br />npm; ClawHub | channels: msteams |
| [nextcloud-talk](/plugins/reference/nextcloud-talk) | OpenClaw Nextcloud Talk channel plugin for conversations. | `@openclaw/nextcloud-talk`<br />npm; ClawHub | channels: nextcloud-talk |
| [nostr](/plugins/reference/nostr) | OpenClaw Nostr channel plugin for NIP-04 encrypted direct messages. | `@openclaw/nostr`<br />npm; ClawHub | channels: nostr |
| [novita](/plugins/reference/novita) | Adds Novita, Novita AI, Novitaai model provider support to OpenClaw. | `@openclaw/novita-provider`<br />included in OpenClaw | providers: novita, novita-ai, novitaai |
| [nvidia](/plugins/reference/nvidia) | Adds NVIDIA model provider support to OpenClaw. | `@openclaw/nvidia-provider`<br />included in OpenClaw | providers: nvidia |
| [oc-path](/plugins/reference/oc-path) | Adds the openclaw path CLI for oc:// workspace file addressing. | `@openclaw/oc-path`<br />included in OpenClaw | plugin |
| [ollama](/plugins/reference/ollama) | Adds Ollama model provider support to OpenClaw. | `@openclaw/ollama-provider`<br />included in OpenClaw | providers: ollama; contracts: memoryEmbeddingProviders, webSearchProviders |
| [ollama](/plugins/reference/ollama) | Adds Ollama, Ollama Cloud model provider support to OpenClaw. | `@openclaw/ollama-provider`<br />included in OpenClaw | providers: ollama, ollama-cloud; contracts: memoryEmbeddingProviders, webSearchProviders |
| [open-prose](/plugins/reference/open-prose) | OpenProse VM skill pack with a /prose slash command. | `@openclaw/open-prose`<br />included in OpenClaw | skills |
| [openai](/plugins/reference/openai) | Adds OpenAI, OpenAI Codex model provider support to OpenClaw. | `@openclaw/openai-provider`<br />included in OpenClaw | providers: openai, openai-codex; contracts: imageGenerationProviders, mediaUnderstandingProviders, memoryEmbeddingProviders, realtimeTranscriptionProviders, realtimeVoiceProviders, speechProviders, videoGenerationProviders |
| [openai](/plugins/reference/openai) | Adds OpenAI model provider support to OpenClaw, including ChatGPT/Codex OAuth. | `@openclaw/openai-provider`<br />included in OpenClaw | providers: openai; contracts: imageGenerationProviders, mediaUnderstandingProviders, memoryEmbeddingProviders, realtimeTranscriptionProviders, realtimeVoiceProviders, speechProviders, videoGenerationProviders |
| [opencode](/plugins/reference/opencode) | Adds OpenCode model provider support to OpenClaw. | `@openclaw/opencode-provider`<br />included in OpenClaw | providers: opencode; contracts: mediaUnderstandingProviders |
| [opencode-go](/plugins/reference/opencode-go) | Adds OpenCode Go model provider support to OpenClaw. | `@openclaw/opencode-go-provider`<br />included in OpenClaw | providers: opencode-go; contracts: mediaUnderstandingProviders |
| [openrouter](/plugins/reference/openrouter) | Adds OpenRouter model provider support to OpenClaw. | `@openclaw/openrouter-provider`<br />included in OpenClaw | providers: openrouter; contracts: imageGenerationProviders, mediaUnderstandingProviders, musicGenerationProviders, speechProviders, videoGenerationProviders |
| [openshell](/plugins/reference/openshell) | OpenClaw sandbox backend for the NVIDIA OpenShell CLI with mirrored local workspaces and SSH command execution. | `@openclaw/openshell-sandbox`<br />npm; ClawHub | plugin |
| [perplexity](/plugins/reference/perplexity) | Adds web search provider support. | `@openclaw/perplexity-plugin`<br />included in OpenClaw | contracts: webSearchProviders |
| [pixverse](/plugins/reference/pixverse) | OpenClaw PixVerse video generation provider plugin. | `@openclaw/pixverse-provider`<br />npm; ClawHub | contracts: videoGenerationProviders |
| [pixverse](/plugins/reference/pixverse) | OpenClaw PixVerse video generation provider plugin. | `@openclaw/pixverse-provider`<br />npm; ClawHub: `clawhub:@openclaw/pixverse-provider` | contracts: videoGenerationProviders |
| [policy](/plugins/reference/policy) | Adds policy-backed doctor checks for workspace conformance. | `@openclaw/policy`<br />included in OpenClaw | plugin |
| [qa-channel](/plugins/reference/qa-channel) | Adds the QA Channel surface for sending and receiving OpenClaw messages. | `@openclaw/qa-channel`<br />source checkout only | channels: qa-channel |
| [qa-lab](/plugins/reference/qa-lab) | OpenClaw QA lab plugin with private debugger UI and scenario runner. | `@openclaw/qa-lab`<br />source checkout only | plugin |
| [qa-matrix](/plugins/reference/qa-matrix) | Matrix QA transport runner and substrate. | `@openclaw/qa-matrix`<br />source checkout only | plugin |
| [qianfan](/plugins/reference/qianfan) | Adds Qianfan model provider support to OpenClaw. | `@openclaw/qianfan-provider`<br />included in OpenClaw | providers: qianfan |
| [qqbot](/plugins/reference/qqbot) | OpenClaw QQ Bot channel plugin for group and direct-message workflows. | `@openclaw/qqbot`<br />npm; ClawHub | channels: qqbot; contracts: tools; skills |
| [qwen](/plugins/reference/qwen) | Adds Qwen, Qwen Cloud, Model Studio, DashScope model provider support to OpenClaw. | `@openclaw/qwen-provider`<br />included in OpenClaw | providers: qwen, qwencloud, modelstudio, dashscope; contracts: mediaUnderstandingProviders, videoGenerationProviders |
| [qwen](/plugins/reference/qwen) | Adds Qwen, Qwen Cloud, Model Studio, DashScope, Qwen Oauth, Qwen Portal, Qwen CLI model provider support to OpenClaw. | `@openclaw/qwen-provider`<br />included in OpenClaw | providers: qwen, qwencloud, modelstudio, dashscope, qwen-oauth, qwen-portal, qwen-cli; contracts: mediaUnderstandingProviders, videoGenerationProviders |
| [runway](/plugins/reference/runway) | Adds video generation provider support. | `@openclaw/runway-provider`<br />included in OpenClaw | contracts: videoGenerationProviders |
| [searxng](/plugins/reference/searxng) | Adds web search provider support. | `@openclaw/searxng-plugin`<br />included in OpenClaw | contracts: webSearchProviders |
| [senseaudio](/plugins/reference/senseaudio) | Adds media understanding provider support. | `@openclaw/senseaudio-provider`<br />included in OpenClaw | contracts: mediaUnderstandingProviders |
| [sglang](/plugins/reference/sglang) | Adds SGLang model provider support to OpenClaw. | `@openclaw/sglang-provider`<br />included in OpenClaw | providers: sglang |
| [signal](/plugins/reference/signal) | Adds the Signal channel surface for sending and receiving OpenClaw messages. | `@openclaw/signal`<br />included in OpenClaw | channels: signal |
| [skill-workshop](/plugins/reference/skill-workshop) | Captures repeatable workflows as workspace skills, with pending review, safe writes, and skill prompt refresh. | `@openclaw/skill-workshop`<br />included in OpenClaw | contracts: tools |
| [slack](/plugins/reference/slack) | OpenClaw Slack channel plugin for channels, DMs, commands, and app events. | `@openclaw/slack`<br />npm; ClawHub | channels: slack |
| [stepfun](/plugins/reference/stepfun) | Adds StepFun, StepFun Plan model provider support to OpenClaw. | `@openclaw/stepfun-provider`<br />included in OpenClaw | providers: stepfun, stepfun-plan |
| [synology-chat](/plugins/reference/synology-chat) | Synology Chat channel plugin for OpenClaw channels and direct messages. | `@openclaw/synology-chat`<br />npm; ClawHub | channels: synology-chat |
@@ -122,7 +123,7 @@ pnpm plugins:inventory:gen
| [tencent](/plugins/reference/tencent) | Adds Tencent TokenHub model provider support to OpenClaw. | `@openclaw/tencent-provider`<br />included in OpenClaw | providers: tencent-tokenhub |
| [tlon](/plugins/reference/tlon) | OpenClaw Tlon/Urbit channel plugin for chat workflows. | `@openclaw/tlon`<br />npm; ClawHub | channels: tlon; skills |
| [together](/plugins/reference/together) | Adds Together model provider support to OpenClaw. | `@openclaw/together-provider`<br />included in OpenClaw | providers: together; contracts: videoGenerationProviders |
| [tokenjuice](/plugins/reference/tokenjuice) | Compacts exec and bash tool results with tokenjuice reducers. | `@openclaw/tokenjuice`<br />included in OpenClaw | contracts: agentToolResultMiddleware |
| [tokenjuice](/plugins/reference/tokenjuice) | Compacts exec and bash tool results with tokenjuice reducers. | `@openclaw/tokenjuice`<br />npm; ClawHub: `clawhub:@openclaw/tokenjuice` | contracts: agentToolResultMiddleware |
| [tts-local-cli](/plugins/reference/tts-local-cli) | Adds text-to-speech provider support. | `@openclaw/tts-local-cli`<br />included in OpenClaw | contracts: speechProviders |
| [twitch](/plugins/reference/twitch) | OpenClaw Twitch channel plugin for chat and moderation workflows. | `@openclaw/twitch`<br />npm; ClawHub | channels: twitch |
| [venice](/plugins/reference/venice) | Adds Venice model provider support to OpenClaw. | `@openclaw/venice-provider`<br />included in OpenClaw | providers: venice |
@@ -135,9 +136,9 @@ pnpm plugins:inventory:gen
| [web-readability](/plugins/reference/web-readability) | Extract readable article content from local HTML web fetch responses. | `@openclaw/web-readability-plugin`<br />included in OpenClaw | contracts: webContentExtractors |
| [webhooks](/plugins/reference/webhooks) | Authenticated inbound webhooks that bind external automation to OpenClaw TaskFlows. | `@openclaw/webhooks`<br />included in OpenClaw | plugin |
| [whatsapp](/plugins/reference/whatsapp) | OpenClaw WhatsApp channel plugin for WhatsApp Web chats. | `@openclaw/whatsapp`<br />ClawHub: `clawhub:@openclaw/whatsapp`; npm | channels: whatsapp |
| [workboard](/plugins/reference/workboard) | Dashboard workboard for agent-owned issues and sessions. | `@openclaw/workboard`<br />included in OpenClaw | plugin |
| [workboard](/plugins/reference/workboard) | Dashboard workboard for agent-owned issues and sessions. | `@openclaw/workboard`<br />included in OpenClaw | contracts: tools |
| [xai](/plugins/reference/xai) | Adds xAI model provider support to OpenClaw. | `@openclaw/xai-plugin`<br />included in OpenClaw | providers: xai; contracts: imageGenerationProviders, mediaUnderstandingProviders, realtimeTranscriptionProviders, speechProviders, tools, videoGenerationProviders, webSearchProviders |
| [xiaomi](/plugins/reference/xiaomi) | Adds Xiaomi model provider support to OpenClaw. | `@openclaw/xiaomi-provider`<br />included in OpenClaw | providers: xiaomi; contracts: speechProviders |
| [xiaomi](/plugins/reference/xiaomi) | Adds Xiaomi MiMo pay-as-you-go and Token Plan provider support to OpenClaw. | `@openclaw/xiaomi-provider`<br />included in OpenClaw | providers: xiaomi, xiaomi-token-plan; contracts: speechProviders |
| [zai](/plugins/reference/zai) | Adds Z.AI model provider support to OpenClaw. | `@openclaw/zai-provider`<br />included in OpenClaw | providers: zai; contracts: mediaUnderstandingProviders |
| [zalo](/plugins/reference/zalo) | OpenClaw Zalo channel plugin for bot and webhook chats. | `@openclaw/zalo`<br />npm; ClawHub | channels: zalo |
| [zalouser](/plugins/reference/zalouser) | OpenClaw Zalo Personal Account plugin via native zca-js integration. | `@openclaw/zalouser`<br />npm; ClawHub | channels: zalouser; contracts: tools |

View File

@@ -17,3 +17,11 @@ Supervise Codex app-server sessions from OpenClaw.
## Surface
contracts: tools
<!-- openclaw-plugin-reference:manual-start -->
## Session Listing
`codex_sessions_list` defaults to loaded Codex sessions only. Set `include_stored` to include stored history; the plugin uses Codex app-server's state-DB-only listing path and caps stored results at 200 by default. Pass `max_stored_sessions` to lower or raise that cap, up to 1000.
<!-- openclaw-plugin-reference:manual-end -->

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