Compare commits

...

34 Commits

Author SHA1 Message Date
Vincent Koc
aa69b12d00 docs(changelog): refresh 2026.6.10 notes 2026-06-24 09:18:34 +08:00
Vincent Koc
3521a01489 chore(release): prepare 2026.6.10 stable 2026-06-23 18:34:00 +08:00
Vincent Koc
5ed8323901 test(e2e): refresh docker setup fixture 2026-06-23 11:55:51 +08:00
Vincent Koc
e42b914aa1 fix(ci): keep release branch CI shard bundles compatible 2026-06-23 10:44:54 +08:00
Vincent Koc
51459a4665 docs(changelog): include provider onboarding fix 2026-06-23 10:23:41 +08:00
snowzlmbot
8b5527b1f0 fix(onboard): refresh provider plugin registry after setup installs (#95792)
Merged via squash.

Prepared head SHA: c99d09f762
Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete

(cherry picked from commit 604d607311)
2026-06-23 10:21:04 +08:00
Vincent Koc
87b40c7160 test(release): align beta2 validation expectations 2026-06-22 16:11:19 +08:00
Vincent Koc
b8108e4794 test(telegram): add progress preview helper 2026-06-22 15:55:14 +08:00
Vincent Koc
dec86febb6 chore(release): refresh beta2 validation baselines 2026-06-22 15:44:39 +08:00
Vincent Koc
a2e555338a test(agents): cover fallback probe attempt position
(cherry picked from commit 2c3519c1d7)
2026-06-22 15:21:33 +08:00
Vincent Koc
8bb6472c4d fix(channels): preserve keyed progress state updates
(cherry picked from commit e114001cca)
2026-06-22 15:12:10 +08:00
Vincent Koc
e18d316734 test(agents): cover fallback attempt position
(cherry picked from commit 3ff59df960)
2026-06-22 15:12:10 +08:00
Vincent Koc
cfb07d0d3a fix(codex): satisfy app-server callback contract 2026-06-22 14:57:09 +08:00
Vincent Koc
8608fa2046 test: model command progress start events 2026-06-22 14:34:07 +08:00
Vincent Koc
3f67778c52 docs(changelog): align 2026.6.10 notes with 6.9 stable 2026-06-22 13:43:28 +08:00
Vincent Koc
cbef591210 chore(release): prepare 2026.6.10-beta.2 2026-06-22 13:37:36 +08:00
Jesse Merhi
de982a0224 fix: keep trusted policies with hook registry (#94545)
* fix: keep trusted policies with hook registry

* fix: compose trusted policies with live hooks

* fix: preserve trusted policy order

* test: update hook runner mock

* fix: keep hook policy registry internal
2026-06-22 10:47:52 +08:00
Vincent Koc
684e440137 fix: preserve fast auto delivery semantics 2026-06-22 09:34:41 +08:00
Vincent Koc
f4d93c855b fix: gate fallback fast reset notices 2026-06-22 09:27:31 +08:00
Vincent Koc
c4694f84ff fix: type fallback state for CLI runs 2026-06-22 09:19:34 +08:00
Vincent Koc
6c29f88913 fix: carry fast mode fallback state through runners 2026-06-22 09:19:07 +08:00
Vincent Koc
7f5423ca97 fix: complete fast mode fallback and status wiring 2026-06-22 09:09:48 +08:00
Vincent Koc
9509aa063c fix: preserve normalization and ACP fast mode contracts 2026-06-21 22:29:49 +08:00
Vincent Koc
20aec98554 fix: mark embedded auto fast mode explicitly 2026-06-21 22:18:39 +08:00
Vincent Koc
d1e190fbe8 fix: preserve fast mode across retries 2026-06-21 22:16:04 +08:00
Vincent Koc
2d42e52ac5 fix: preserve repeated channel progress events 2026-06-21 21:56:16 +08:00
Vincent Koc
075091d0ca fix: resolve fallback fast cutoff per model 2026-06-21 21:49:05 +08:00
Vincent Koc
cd32d9ff91 fix(codex): normalize cleared service tier in bindings 2026-06-21 21:43:41 +08:00
Vincent Koc
8845f2fd61 fix: clear Codex tier and render auto fast status 2026-06-21 21:42:02 +08:00
Vincent Koc
e4bf1e6774 test: align fast auto forward-port with current fixtures 2026-06-21 21:40:30 +08:00
Vincent Koc
f5ff56640e fix: remove stale fast auto event import 2026-06-21 21:37:48 +08:00
Vincent Koc
9540a69b24 feat: forward-port fast talks auto mode (#85104) 2026-06-21 21:35:44 +08:00
Tideclaw
d91c1607c4 fix: refresh plugin sdk surface budget 2026-06-21 15:20:37 +08:00
Vincent Koc
cf13590c1c chore(release): prepare 2026.6.10-beta.1 2026-06-21 13:21:20 +08:00
412 changed files with 5707 additions and 1248 deletions

View File

@@ -129,11 +129,28 @@ jobs:
trusted_config="$RUNNER_TEMP/pre-commit-base.yaml"
trusted_zizmor_config="$RUNNER_TEMP/zizmor-base.yml"
if ! git cat-file -e "${BASE_SHA}^{commit}" 2>/dev/null; then
timeout --signal=TERM --kill-after=10s 30s git fetch --no-tags --depth=1 origin \
"+${BASE_SHA}:refs/remotes/origin/security-base" ||
fetch_base_ref() {
local ref="$1"
local target="$2"
local fetch_status
for attempt in 1 2 3; do
timeout --signal=TERM --kill-after=10s 30s git fetch --no-tags --depth=1 origin \
"+refs/heads/${BASE_REF}:refs/remotes/origin/${BASE_REF}"
"+${ref}:${target}" && return 0
fetch_status="$?"
if [ "$fetch_status" != "124" ] && [ "$fetch_status" != "137" ]; then
return "$fetch_status"
fi
if [ "$attempt" = "3" ]; then
return "$fetch_status"
fi
echo "::warning::trusted base fetch for '$ref' timed out on attempt $attempt; retrying"
sleep 5
done
}
if ! git cat-file -e "${BASE_SHA}^{commit}" 2>/dev/null; then
fetch_base_ref "$BASE_SHA" "refs/remotes/origin/security-base" ||
fetch_base_ref "refs/heads/${BASE_REF}" "refs/remotes/origin/${BASE_REF}"
fi
if git cat-file -e "${BASE_SHA}:.pre-commit-config.yaml" 2>/dev/null; then

View File

@@ -2,38 +2,77 @@
Docs: https://docs.openclaw.ai
## 2026.6.10
### Highlights
- **Automatic fast mode for talks:** OpenClaw can enable fast mode for short conversational turns, then return to normal mode for longer runs with bounded fallback and delivery behavior. (#85104) Thanks @alexph-dev and @vincentkoc.
- **More reliable model routing:** Zai model synthesis, GLM overload failover, and native reasoning-level selection now follow the active model catalog more consistently. (#94461, #93241, #94067, #94136) Thanks @Pandah97, @chrysb, @0xghost42, @zhengli0922, @openperf, @civiltox, and @BorClaw.
- **Safer session and channel state:** channel switches reset stale origin fields, and cron delivery awareness stays attached to the target session. (#95328, #93580) Thanks @ZengWen-DT, @jalehman, @gorkem2020, and @scotthuang.
- **Trusted policies survive hook composition:** composed hook registries keep the trusted tool policies required by approval-sensitive flows. (#94545) Thanks @jesse-merhi.
### Changes
- **Agent and channel runtime:** fast-mode state now survives retries, fallback transitions, progress events, and embedded/CLI/ACP normalization; session and channel routing retain the current target and delivery context. (#85104, #93580, #95328) Thanks @alexph-dev, @vincentkoc, @scotthuang, @ZengWen-DT, @jalehman, and @gorkem2020.
- **Provider behavior:** model catalogs now supply the correct Zai base URL, overload classification, and native reasoning controls for live-discovered models. (#94461, #93241, #94067, #94136) Thanks @Pandah97, @chrysb, @0xghost42, @zhengli0922, @openperf, @civiltox, and @BorClaw.
### Fixes
- **Fast-mode and policy correctness:** fallback cutoffs and reset notices are bounded, repeated progress events remain visible, Codex service-tier state is normalized, and trusted policies are not lost when hook registries are composed. (#85104, #94545) Thanks @alexph-dev, @vincentkoc, and @jesse-merhi.
- **Model and delivery edge cases:** Zai and GLM failover paths use the right runtime metadata, while stale channel-origin state no longer leaks across session changes. (#94461, #93241, #95328) Thanks @Pandah97, @chrysb, @0xghost42, @zhengli0922, @ZengWen-DT, @jalehman, and @gorkem2020.
- **Provider plugin onboarding:** setup refreshes provider plugin registry metadata after installing setup-selected provider plugins, so auth continuation uses the newly installed provider instead of stale registry state. (#95792) Thanks @snowzlmbot.
### Complete contribution record
This audited record covers the complete v2026.6.9..HEAD history: 12 merged PRs. The generation manifest also supplies direct commits as editorial input; the grouped notes above prioritize user impact.
#### Pull requests
- **PR #86627** Keep core doctor health in contribution order. Thanks @giodl73-repo.
- **PR #93580** fix: preserve cron delivery awareness for target sessions. Thanks @scotthuang and @jalehman.
- **PR #95030** refactor: add SDK transcript identity target API. Thanks @jalehman.
- **PR #94838** refactor(copilot): complete harness lifecycle parity. Thanks @vincentkoc.
- **PR #95328** fix(sessions): reset stale per-channel origin fields on channel switch. Related #95325. Thanks @ZengWen-DT and @jalehman and @gorkem2020.
- **PR #94461** fix(zai): fall back to manifest baseUrl for synthesized GLM-5 models. Related #94269. Thanks @Pandah97 and @chrysb.
- **PR #93241** fix(agents): classify Zhipu GLM overload as overloaded for failover. Related #93211. Thanks @0xghost42 and @zhengli0922.
- **PR #94067** fix(channels): resolve native /think menu levels via runtime catalog for live-discovered models. Related #93835. Thanks @openperf and @civiltox.
- **PR #94136** fix(zai): expose GLM-5.2 reasoning levels [AI-assisted]. Thanks @BorClaw.
- **PR #85104** feat: fast talks auto mode. Related #85087. Thanks @alexph-dev.
- **PR #94545** fix: keep trusted policies with hook registry. Thanks @jesse-merhi.
- **PR #95792** fix(onboard): refresh provider plugin registry after setup installs. Related #95765. Thanks @snowzlmbot.
## 2026.6.9
### Highlights
- **Richer Telegram delivery:** Telegram now sends rich HTML, preserves rich markdown and sticker paths, renders progress drafts and command output more faithfully, normalizes HTML tables safely, and keeps mentions and spooled handlers on the right delivery path. (#93286, #93164, #93124, #93364, #93130, #93088, #93281, #94891, #94856) Thanks @obviyus, @vincentkoc, @goutamadwant, @kesslerio, @NianJiuZst, @SweetSophia, @Marvinthebored, @aaajiao, @zhangqueping, and @jairrab.
- **Richer Telegram delivery:** Telegram now sends rich HTML, preserves rich markdown and sticker paths, renders progress drafts and command output more faithfully, and keeps mentions and spooled handlers on the right delivery path. (#93286, #93164, #93124, #93364, #93130, #93088, #93281) Thanks @obviyus, @vincentkoc, @goutamadwant, @kesslerio, @NianJiuZst, @SweetSophia, @Marvinthebored, and @aaajiao.
- **More dependable agent recovery:** retries, terminal outcomes, usage after compaction, session history repair, and reply reconciliation now keep more interrupted or partial turns moving toward a visible final result. (#92191, #93073, #93228, #93084, #93469, #93291, #90943) Thanks @ai-hpc, @lml2468, @fuller-stack-dev, @Hollychou924, @leno23, @de1tydev, @425072024, @wuwahe3, @drvoss, @yetval, @sandieman2, and @vincentkoc.
- **A stronger Codex integration:** Codex gains automatic plugin approvals, GPT-5.3 Spark OAuth routing, remote-node `exec` as a dynamic tool, and more reliable app-server teardown and terminal outcomes. (#92625, #89133, #93654, #91767, #93287) Thanks @kevinslin, @VACInc, @vincentkoc, @JPKay-AI, and @aliahnaf2013-max.
- **Standalone official provider plugins:** external provider packages are now first-class npm releases, externally installed channel plugins load at Gateway startup, and StepFun is available from npm and ClawHub. (#93470) Thanks @sunlit-deng, @cxdnicole, and @vincentkoc.
- **Standalone official provider plugins:** external provider packages are now first-class npm releases, externally installed channel plugins load at Gateway startup, and StepFun is intentionally npm-only because its ClawHub package name is unavailable. (#93470) Thanks @sunlit-deng, @cxdnicole, and @vincentkoc.
- **More capable web and native clients:** the Control UI adds a session workspace rail and extension health, iOS adds Watch controls, and Android shows chat context. (#92856, #91952, #93387, #92837) Thanks @Solvely-Colin, @jalehman, @joshavant, and @Tosko4.
- **More useful search and skills:** Codex Hosted Search is available, key-free search providers remain deliberate opt-ins, and ClawHub skill installs retain verified source provenance. (#93446, #93616, #93283, #93506) Thanks @fuller-stack-dev, @davemorin, @momothemage, @nmccready-tars, and @vincentkoc.
### Changes
- Providers and auth: add Codex Hosted Search, improve Gemini CLI OAuth behind proxies, and keep external provider onboarding on current choices and package metadata. (#93446, #92815) Thanks @fuller-stack-dev, @yetval, @EvetteYoung, and @vincentkoc.
- Plugins and installs: externalized official providers publish as independent npm packages, Gateway discovers installed channel plugins at startup, and StepFun installs from npm or ClawHub. (#93470) Thanks @sunlit-deng, @cxdnicole, and @vincentkoc.
- Plugins and installs: externalized official providers publish as independent npm packages, Gateway discovers installed channel plugins at startup, and StepFun installs exclusively from npm. (#93470) Thanks @sunlit-deng, @cxdnicole, and @vincentkoc.
- Dashboard and mobile: add a session workspace rail, plugin health in status, compact cron lists, and iOS Watch controls. (#92856, #91952, #93395, #93387) Thanks @Solvely-Colin, @jalehman, @yu-xin-c, @centralpc, @joshavant, and @vincentkoc.
- Codex, observability, and skills: add automatic plugin approvals and SecretRefs, preserve ClawHub skill provenance, add OpenTelemetry log export, and expose remote-node execution to Codex when a node is connected. (#92625, #94324, #93283, #94561, #93654) Thanks @kevinslin, @kevinlin-openai, @momothemage, @nmccready-tars, @jesse-merhi, @vincentkoc, and @JPKay-AI.
- QA and release engineering: QA scenarios now use YAML, with broader profile evidence and release coverage for the plugin and channel matrix. Thanks @vincentkoc.
- Codex and skills: add automatic plugin approvals, preserve ClawHub skill provenance, and expose remote-node execution to Codex when a node is connected. (#92625, #93283, #93654) Thanks @kevinslin, @momothemage, @nmccready-tars, @vincentkoc, and @JPKay-AI.
- QA and release engineering: QA scenarios now use YAML, with broader profile evidence and release coverage for the plugin and channel matrix.
### Fixes
- Security and privacy: redact secrets from debug/config output, block internal HTTP session overrides, audit open-DM tool exposure, and retain plugin write ownership checks. (#93333, #88496, #93443, #92883, #93353) Thanks @Alix-007, @jason-allen-oneal, @coygeek, @RichardCao, @yu-xin-c, @cjg20ss, @eleqtrizit, and @vincentkoc.
- Agent and session runtime: retry thinking-only and empty post-tool turns, prevent duplicate hook execution, preserve pending subagent delivery, preserve fresh usage through compaction, and repair partial JSON/history artifacts. (#92191, #93073, #93009, #93084, #93469, #94349, #92383, #94257) Thanks @ai-hpc, @lml2468, @fuller-stack-dev, @zenglingbiao, @dertbv, @Hollychou924, @leno23, @de1tydev, @425072024, @wuwahe3, @drvoss, @vincentkoc, @sallyom, @oiGaDio, @Hidetsugu55, and @Nas01010101.
- Channels and replies: fix Telegram rich delivery, table rendering, action-error handling, and ingress recovery; preserve command progress detail across channel adapters; retain WhatsApp opening text after a media failure; keep Mattermost thread replies intact; and harden Discord action handling. (#93286, #93364, #93281, #93076, #93334, #93424, #93488, #94868, #94891, #94856, #94810, #93823) Thanks @obviyus, @NianJiuZst, @mcaxtr, @rushindrasinha, @amknight, @lzyyzznl, @darealgege, @vincentkoc, @zhangqueping, @jairrab, @ZOOWH, @parveshsaini, and @yetval.
- Agent and session runtime: retry thinking-only and empty post-tool turns, prevent duplicate hook execution, preserve fresh usage through compaction, and repair partial JSON/history artifacts. (#92191, #93073, #93009, #93084, #93469) Thanks @ai-hpc, @lml2468, @fuller-stack-dev, @zenglingbiao, @dertbv, @Hollychou924, @leno23, @de1tydev, @425072024, @wuwahe3, @drvoss, and @vincentkoc.
- Channels and replies: fix Telegram rich delivery and ingress recovery, preserve WhatsApp auth and media error reporting, keep Mattermost thread replies intact, and harden Discord action handling. (#93286, #93364, #93281, #93076, #93334, #93424, #93488) Thanks @obviyus, @NianJiuZst, @mcaxtr, @rushindrasinha, @amknight, @lzyyzznl, @darealgege, and @vincentkoc.
- Storage and migrations: avoid SQLite WAL on network filesystems, clean reindex artifacts, keep setup state out of workspace dot-directories, and import default-agent auth profiles into SQLite. (#93454, #92891, #93182, #93295, #93520, #93156) Thanks @vincentkoc, @ZengWen-DT, @Zeng-wen, @potterdigital, @Alix-007, @Pick-cat, @sallyom, @1qh, and @Tazio7.
- Provider and model behavior: fix Gemini CLI proxy OAuth, restore Codex Spark OAuth routing, correct Bedrock embedding model IDs, and preserve configured defaults in embedded runs. (#92815, #89133, #93452, #93428) Thanks @yetval, @EvetteYoung, @VACInc, @LiuwqGit, @aleck31, @zenglingbiao, @danielgerlag, and @vincentkoc.
- CLI, TUI, and apps: accept global flags after subcommands, keep terminal output and activity indicators visible, preserve CJK IME composition, and refresh stale UI state. (#93455, #93460, #93006, #93427, #93498, #93606) Thanks @ooiuuii, @Alix-007, @ZengWen-DT, @Zeng-wen, @AlethiaQuizForge, @Zhaoqj2016, @liuhao1024, @BrianClaw1955, @vincentkoc, and @NicoBoom13.
- Operations and updates: harden official plugin recovery, restart managed Gateways after failed update handoff, keep safe cron delivery defaults, avoid Node-specific npm prefixes, and keep package validation paths reliable. (#93325, #92111, #93650, #94453, #91685) Thanks @vincentkoc, @yetval, @ofan, @yaanfpv, @jincheng-xydt, @sallyom, @davectr, and @nxmxbbd.
- Operations and updates: harden official plugin recovery, restart managed Gateways after failed update handoff, avoid Node-specific npm prefixes, and keep package validation paths reliable. (#93325, #92111, #93650) Thanks @vincentkoc, @yetval, @ofan, and @yaanfpv.
### Complete contribution record
This audited record covers the complete v2026.6.8..HEAD history: 422 merged PRs. The generation manifest also supplies direct commits as editorial input; the grouped notes above prioritize user impact.
This audited record covers the complete v2026.6.8..HEAD~1 history: 375 merged PRs. The generation manifest also supplies direct commits as editorial input; the grouped notes above prioritize user impact.
#### Pull requests
@@ -175,7 +214,7 @@ This audited record covers the complete v2026.6.8..HEAD history: 422 merged PRs.
- **PR #90003** feat(policy): cover exec approvals artifact. Thanks @giodl73-repo.
- **PR #93448** fix(guards): allow auth profile sqlite reader. Thanks @amknight.
- **PR #93424** fix(mattermost): keep message tool replies in threads. Thanks @amknight and @vincentkoc.
- **PR #93418** fix(telegram): forward Bot API 10.1 rich_message content to agent. Related #93410. Thanks @xzh-icenter and @vincentkoc and @0pen7ech.
- **PR #93418** fix(telegram): forward Bot API 10.1 rich_message content to agent. Related #93410. Thanks @xzh-xydt and @vincentkoc and @0pen7ech.
- **PR #93175** test(qa): taxonomy profiles: includeAllCategories for release profile, update some coverage. Thanks @RomneyDa.
- **PR #93456** fix(agents): handle string assistant message content. Thanks @vincentkoc.
- **PR #93441** fix(outbound): ignore schema-padded poll metadata on send. Related #43015. Thanks @weichengdeng and @charzhou.
@@ -412,53 +451,6 @@ This audited record covers the complete v2026.6.8..HEAD history: 422 merged PRs.
- **PR #94658** test(sqlite): use shared temp directory helper. Thanks @vincentkoc.
- **PR #92135** fix(openai-embedding): preserve openai/ prefix for non-native base URLs. Related #92124. Thanks @xialonglee and @Kambrian.
- **PR #93737** refactor: add session maintenance transaction seam. Thanks @jalehman.
- **PR #93685** refactor(auto-reply): add lifecycle storage seams. Thanks @jalehman.
- **PR #94349** fix(agents): preserve pending subagent completion announces. Related #93323. Thanks @sallyom and @oiGaDio.
- **PR #93174** test: fold channel message flows into qa e2e. Thanks @RomneyDa.
- **PR #94093** Prevent Codex thread rotation from losing next-step context. Thanks @VACInc.
- **PR #53920** fix(scripts): avoid mutating tracked auth-monitor template during setup. Thanks @JackWuGlobal.
- **PR #94702** Standardize QA coverage IDs on dotted names. Thanks @RomneyDa.
- **PR #81825** fix(skills/1password): stop forcing tmux for desktop app auth (#52540). Thanks @koshaji and @tylerbittner.
- **PR #94725** fix(doctor): warn on volatile SQLite state. Thanks @vincentkoc.
- **PR #88551** fix(agents): skip auth gate for CLI-owned transport. Thanks @yu-xin-c.
- **PR #88581** feat(commands): add /name to rename the current session from chat. Thanks @BSG2000.
- **PR #94324** feat(codex): support app-server SecretRefs. Thanks @kevinlin-openai and @kevinslin.
- **PR #90882** fix: add self-knowledge docs rule to system prompt. Related #90713. Thanks @SutraHsing.
- **PR #94684** fix: #80507 show dry-run output for message send/poll. Thanks @lzyyzznl and @YB0y.
- **PR #93823** fix(whatsapp): keep opening text chunk when first media fails on multi-chunk reply. Thanks @yetval.
- **PR #89203** refactor: route SDK session compatibility through seam. Thanks @jalehman.
- **PR #94453** fix: default cron runMode to "due" instead of "force" (#94270). Thanks @jincheng-xydt and @sallyom and @davectr.
- **PR #94746** fix(note): prevent clack from re-breaking copy-sensitive tokens. Related #94730. Thanks @xzh-icenter and @berkgungor.
- **PR #89904** refactor: route sdk session compatibility through accessor. Thanks @jalehman.
- **PR #86719** fix(skills): retarget stale plugin skill symlinks. Related #85925. Thanks @stevenepalmer and @shakkernerd.
- **PR #94337** fix(tui): show 0 not ? for fresh-session context tokens in footer. Thanks @mushuiyu886.
- **PR #94539** fix(android): group settings by intent. Thanks @Tosko4.
- **PR #92383** fix(gateway): never return an empty chat.history transcript. Thanks @Hidetsugu55.
- **PR #92574** test(browser): cover action-input CLI request bodies. Related #83877. Thanks @yu-xin-c and @davinci282828.
- **PR #92873** test(diffs): add viewerState, toolbar toggle, shadow root, and hydrateProps tests (fixes #83915). Thanks @liuhao1024 and @davinci282828.
- **PR #94257** fix(sessions): preserve Media\* index alignment when reading user-turn fields. Thanks @Nas01010101.
- **PR #94756** fix(codex): bound turn/start text when context budget is non-positive. Related #94748. Thanks @Nas01010101.
- **PR #94729** fix(skills/trello): add curl to requires.bins to match body examples (fixes #94727). Thanks @liuhao1024 and @berkgungor.
- **PR #94790** feat(slack): log INFO receipt for inbound app_mention events. Related #94691. Thanks @ZengWen-DT and @BryceMurray.
- **PR #81696** fix: guard tool event callbacks (AI-assisted). Thanks @enjoylife1243.
- **PR #94809** chore: forward-port alpha release fixes.
- **PR #94612** fix(macos): open NSOpenPanel for embedded Control UI file inputs (#94468). Thanks @bbblending and @DINGDANGMAOUP.
- **PR #89806** fix(feishu): avoid axios interceptor internals. Related #83913. Thanks @sweetcornna and @davinci282828.
- **PR #91923** fix(ios): clean up notification settings state. Thanks @zats.
- **PR #91345** fix: suggest close CLI commands. Related #83999. Thanks @glenn-agent and @HannesOberreiter.
- **PR #94561** Add stdout diagnostics OTEL log exporter. Thanks @jesse-merhi.
- **PR #91013** fix(gateway): ignore stale abort markers for fresh chat events. Related #91012. Thanks @nxmxbbd.
- **PR #89279** fix(tasks): deliver ACP completions to bound Discord threads. Related #84022. Thanks @anyech and @h-mascot.
- **PR #91656** test(cron): expand parseAbsoluteTimeMs test coverage to 39 cases. Related #91654. Thanks @SpecialLeon.
- **PR #94810** fix(telegram): classify sendChatAction 401 by structured error_code, not bare substring match. Related #94787. Thanks @ZOOWH and @parveshsaini.
- **PR #94737** fix(reply): clarify provider internal error copy. Thanks @snowzlmbot.
- **PR #94868** fix(channels): preserve command progress detail. Thanks @vincentkoc.
- **PR #94891** fix(telegram): send progress previews as html text. Thanks @obviyus.
- **PR #94683** fix(outbound): keep direct-only targets out of group sessions. Related #92384. Thanks @scotthuang and @haiwei01.
- **PR #92477** fix: migrate watch app to single-target app (Xcode 27+ compat). Thanks @zats and @joshavant.
- **PR #94812** test(perf): compare saved CLI startup benchmarks. Thanks @FelixIsaac.
- **PR #94856** fix(telegram): normalize all HTML tables before entity-escaping in rich messages. Related #94317. Thanks @zhangqueping and @jairrab.
- **PR #91685** fix(cron): refuse keyless implicit isolated cron delivery inherited from shared agent-main bucket. Thanks @nxmxbbd.
## 2026.6.8

View File

@@ -2,5 +2,5 @@
# Source of truth: apps/android/version.json
# Generated by scripts/android-sync-versioning.ts.
OPENCLAW_ANDROID_VERSION_NAME=2026.6.9
OPENCLAW_ANDROID_VERSION_CODE=2026060901
OPENCLAW_ANDROID_VERSION_NAME=2026.6.10
OPENCLAW_ANDROID_VERSION_CODE=2026061001

View File

@@ -1,4 +1,4 @@
{
"version": "2026.6.9",
"versionCode": 2026060901
"version": "2026.6.10",
"versionCode": 2026061001
}

View File

@@ -1,5 +1,11 @@
# OpenClaw iOS Changelog
## 2026.6.10 - 2026-06-21
Maintenance update for the current OpenClaw beta release.
- Improved notification cleanup, Watch app compatibility, and native file input handling.
## 2026.6.9 - 2026-06-20
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.6.9
OPENCLAW_MARKETING_VERSION = 2026.6.9
OPENCLAW_IOS_VERSION = 2026.6.10
OPENCLAW_MARKETING_VERSION = 2026.6.10
OPENCLAW_BUILD_VERSION = 1
#include? "../build/Version.xcconfig"

View File

@@ -1,5 +1,3 @@
Maintenance update for the current OpenClaw release.
Maintenance update for the current OpenClaw beta release.
- Added Apple Watch controls for common agent actions.
- Improved Gateway setup, notification settings, and share-extension identity handling.
- Updated the Watch app integration for current Xcode compatibility.
- Improved notification cleanup, Watch app compatibility, and native file input handling.

View File

@@ -1,3 +1,3 @@
{
"version": "2026.6.9"
"version": "2026.6.10"
}

View File

@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2026.6.9</string>
<string>2026.6.10</string>
<key>CFBundleVersion</key>
<string>2026060900</string>
<string>2026061000</string>
<key>CFBundleIconFile</key>
<string>OpenClaw</string>
<key>CFBundleURLTypes</key>

View File

@@ -7273,7 +7273,9 @@ public struct ChatSendParams: Codable, Sendable {
public let sessionid: String?
public let message: String
public let thinking: String?
public let fastmode: Bool?
public let fastmodevalue: AnyCodable?
public var fastmode: Bool? { fastmodevalue?.value as? Bool }
public let fastautoonseconds: Int?
public let deliver: Bool?
public let originatingchannel: String?
public let originatingto: String?
@@ -7286,6 +7288,46 @@ public struct ChatSendParams: Codable, Sendable {
public let suppresscommandinterpretation: Bool?
public let idempotencykey: String
public init(
sessionkey: String,
agentid: String? = nil,
sessionid: String?,
message: String,
thinking: String?,
fastmodevalue: AnyCodable?,
fastautoonseconds: Int?,
deliver: Bool?,
originatingchannel: String?,
originatingto: String?,
originatingaccountid: String?,
originatingthreadid: String?,
attachments: [AnyCodable]?,
timeoutms: Int?,
systeminputprovenance: [String: AnyCodable]?,
systemprovenancereceipt: String?,
suppresscommandinterpretation: Bool?,
idempotencykey: String)
{
self.sessionkey = sessionkey
self.agentid = agentid
self.sessionid = sessionid
self.message = message
self.thinking = thinking
self.fastmodevalue = fastmodevalue
self.fastautoonseconds = fastautoonseconds
self.deliver = deliver
self.originatingchannel = originatingchannel
self.originatingto = originatingto
self.originatingaccountid = originatingaccountid
self.originatingthreadid = originatingthreadid
self.attachments = attachments
self.timeoutms = timeoutms
self.systeminputprovenance = systeminputprovenance
self.systemprovenancereceipt = systemprovenancereceipt
self.suppresscommandinterpretation = suppresscommandinterpretation
self.idempotencykey = idempotencykey
}
public init(
sessionkey: String,
agentid: String? = nil,
@@ -7305,23 +7347,25 @@ public struct ChatSendParams: Codable, Sendable {
suppresscommandinterpretation: Bool?,
idempotencykey: String)
{
self.sessionkey = sessionkey
self.agentid = agentid
self.sessionid = sessionid
self.message = message
self.thinking = thinking
self.fastmode = fastmode
self.deliver = deliver
self.originatingchannel = originatingchannel
self.originatingto = originatingto
self.originatingaccountid = originatingaccountid
self.originatingthreadid = originatingthreadid
self.attachments = attachments
self.timeoutms = timeoutms
self.systeminputprovenance = systeminputprovenance
self.systemprovenancereceipt = systemprovenancereceipt
self.suppresscommandinterpretation = suppresscommandinterpretation
self.idempotencykey = idempotencykey
self.init(
sessionkey: sessionkey,
agentid: agentid,
sessionid: sessionid,
message: message,
thinking: thinking,
fastmodevalue: fastmode.map { AnyCodable($0) },
fastautoonseconds: nil,
deliver: deliver,
originatingchannel: originatingchannel,
originatingto: originatingto,
originatingaccountid: originatingaccountid,
originatingthreadid: originatingthreadid,
attachments: attachments,
timeoutms: timeoutms,
systeminputprovenance: systeminputprovenance,
systemprovenancereceipt: systemprovenancereceipt,
suppresscommandinterpretation: suppresscommandinterpretation,
idempotencykey: idempotencykey)
}
private enum CodingKeys: String, CodingKey {
@@ -7330,7 +7374,8 @@ public struct ChatSendParams: Codable, Sendable {
case sessionid = "sessionId"
case message
case thinking
case fastmode = "fastMode"
case fastmodevalue = "fastMode"
case fastautoonseconds = "fastAutoOnSeconds"
case deliver
case originatingchannel = "originatingChannel"
case originatingto = "originatingTo"

View File

@@ -1,4 +1,4 @@
24f11880cec619997ff93d303c32431bf4fb2bfefb56c9f0ece35ff91b329a80 config-baseline.json
2923c1120c0369aeca6646cd67f7264590c6a1f4e5bc3157a04d7661324c6868 config-baseline.core.json
7ce9a1d8d4a69eab05d700241472db66f268f20c144692dc69d38ba22f06d741 config-baseline.json
5d355e16324e0e68d6e034e135e487947f67397a99a6ff91949c6aa07645e982 config-baseline.core.json
2d735389858305509528e74329b6f8c65d311e1471c3b4e91dc17aaab8e63a80 config-baseline.channel.json
d2e2114f1cd43dc894fe1a4836677b42a2a5af825537d6c4a932da832d58a590 config-baseline.plugin.json

View File

@@ -1,2 +1,2 @@
12393c35023a5bdddd276edc2b6669fa432454be9bee643138395e2106936945 plugin-sdk-api-baseline.json
62ffb6cd4a433281f571fdf552be9c3f953f6fa055937f822b18de7dd4e20d23 plugin-sdk-api-baseline.jsonl
4bbf1636d7e0b410fffa3d12a366371b2f66524f7c730fdc4de789d0f482aeb2 plugin-sdk-api-baseline.json
c5194a29911287897eee44c3579878bda552a6a7baa135bba9c719fa2ded9ab8 plugin-sdk-api-baseline.jsonl

View File

@@ -183,7 +183,7 @@ Model-selection precedence for isolated jobs is:
3. User-selected stored cron session model override
4. Agent/default model selection
Fast mode follows the resolved live selection too. If the selected model config has `params.fastMode`, isolated cron uses that by default. A stored session `fastMode` override still wins over config in either direction.
Fast mode follows the resolved live selection too. If the selected model config has `params.fastMode`, isolated cron uses that by default. A stored session `fastMode` override still wins over config in either direction. Auto mode uses the selected model's `params.fastAutoOnSeconds` cutoff when present, defaulting to 60 seconds.
If an isolated run hits a live model-switch handoff, cron retries with the switched provider/model and persists that live selection for the active run before retrying. When the switch also carries a new auth profile, cron persists that auth profile override for the active run too. Retries are bounded: after the initial attempt plus 2 switch retries, cron aborts instead of looping forever.

View File

@@ -197,7 +197,7 @@ Isolated cron resolves the active model in this order:
### Fast mode
Isolated cron fast mode follows the resolved live model selection. Model config `params.fastMode` applies by default, but a stored session `fastMode` override still wins over config.
Isolated cron fast mode follows the resolved live model selection. Model config `params.fastMode` applies by default, but a stored session `fastMode` override still wins over config. When the resolved mode is `auto`, the cutoff uses the selected model's `params.fastAutoOnSeconds` value, defaulting to 60 seconds.
### Live model switch retries

View File

@@ -1098,7 +1098,7 @@ for provider examples and precedence.
- `skills`: optional per-agent skill allowlist. If omitted, the agent inherits `agents.defaults.skills` when set; an explicit list replaces defaults instead of merging, and `[]` means no skills.
- `thinkingDefault`: optional per-agent default thinking level (`off | minimal | low | medium | high | xhigh | adaptive | max`). Overrides `agents.defaults.thinkingDefault` for this agent when no per-message or session override is set. The selected provider/model profile controls which values are valid; for Google Gemini, `adaptive` keeps provider-owned dynamic thinking (`thinkingLevel` omitted on Gemini 3/3.1, `thinkingBudget: -1` on Gemini 2.5).
- `reasoningDefault`: optional per-agent default reasoning visibility (`on | off | stream`). Overrides `agents.defaults.reasoningDefault` for this agent when no per-message or session reasoning override is set.
- `fastModeDefault`: optional per-agent default for fast mode (`true | false`). Applies when no per-message or session fast-mode override is set.
- `fastModeDefault`: optional per-agent default for fast mode (`"auto" | true | false`). Applies when no per-message or session fast-mode override is set.
- `models`: optional per-agent model catalog/runtime overrides keyed by full `provider/model` ids. Use `models["provider/model"].agentRuntime` for per-agent runtime exceptions.
- `runtime`: optional per-agent runtime descriptor. Use `type: "acp"` with `runtime.acp` defaults (`agent`, `backend`, `mode`, `cwd`) when the agent should default to ACP harness sessions.
- `identity.avatar`: workspace-relative path, `http(s)` URL, or `data:` URI.

View File

@@ -445,6 +445,7 @@ enumeration of `src/gateway/server-methods/*.ts`.
- `sessions.get` returns the full stored session row.
- Chat execution still uses `chat.history`, `chat.send`, `chat.abort`, and `chat.inject`. `chat.history` is display-normalized for UI clients: inline directive tags are stripped from visible text, plain-text tool-call XML payloads (including `<tool_call>...</tool_call>`, `<function_call>...</function_call>`, `<tool_calls>...</tool_calls>`, `<function_calls>...</function_calls>`, and truncated tool-call blocks) and leaked ASCII/full-width model control tokens are stripped, pure silent-token assistant rows such as exact `NO_REPLY` / `no_reply` are omitted, and oversized rows can be replaced with placeholders.
- `chat.message.get` is the additive bounded full-message reader for a single visible transcript entry. Clients pass `sessionKey`, optional `agentId` when the session selection is agent-scoped, plus a transcript `messageId` previously surfaced through `chat.history`, and the Gateway returns the same display-normalized projection without the lightweight history truncation cap when the stored entry is still available and not oversized.
- `chat.send` accepts one-turn `fastMode: "auto"` to use fast mode for model calls started before the auto cutoff, then start later retry, fallback, tool-result, or continuation calls without fast mode. The cutoff defaults to 60 seconds and can be configured per model with `agents.defaults.models["<provider>/<model>"].params.fastAutoOnSeconds`. A `chat.send` caller can pass one-turn `fastAutoOnSeconds` to override the cutoff for that request.
</Accordion>

View File

@@ -174,6 +174,7 @@ troubleshooting, see the main [FAQ](/help/faq).
- **Per session:** send `/fast on` while the session is using `openai/gpt-5.5`.
- **Per model default:** set `agents.defaults.models["openai/gpt-5.5"].params.fastMode` to `true`.
- **Automatic cutoff:** use `/fast auto` or `params.fastMode: "auto"` to start new model calls fast until the auto cutoff, then start later retry, fallback, tool-result, or continuation calls without fast mode. The cutoff defaults to 60 seconds; set `params.fastAutoOnSeconds` on the active model to change it.
Example:
@@ -184,7 +185,8 @@ troubleshooting, see the main [FAQ](/help/faq).
models: {
"openai/gpt-5.5": {
params: {
fastMode: true,
fastMode: "auto",
fastAutoOnSeconds: 30,
},
},
},
@@ -193,7 +195,7 @@ troubleshooting, see the main [FAQ](/help/faq).
}
```
For OpenAI, fast mode maps to `service_tier = "priority"` on supported native Responses requests. Session `/fast` overrides beat config defaults.
For OpenAI, fast mode maps to `service_tier = "priority"` on supported native Responses requests. Session `/fast` overrides beat config defaults. Codex app-server turns can only receive the tier at turn start, so `auto` applies on the next OpenClaw-started model turn rather than inside one already-running app-server turn.
See [Thinking and fast mode](/tools/thinking) and [OpenAI fast mode](/providers/openai#fast-mode).

View File

@@ -915,17 +915,17 @@ the Server-side compaction accordion below.
<Accordion title="Fast mode">
OpenClaw exposes a shared fast-mode toggle for `openai/*`:
- **Chat/UI:** `/fast status|on|off`
- **Chat/UI:** `/fast status|auto|on|off`
- **Config:** `agents.defaults.models["<provider>/<model>"].params.fastMode`
When enabled, OpenClaw maps fast mode to OpenAI priority processing (`service_tier = "priority"`). Existing `service_tier` values are preserved, and fast mode does not rewrite `reasoning` or `text.verbosity`.
When enabled, OpenClaw maps fast mode to OpenAI priority processing (`service_tier = "priority"`). Existing `service_tier` values are preserved, and fast mode does not rewrite `reasoning` or `text.verbosity`. `fastMode: "auto"` starts new model calls fast until the auto cutoff, then starts later retry, fallback, tool-result, or continuation calls without fast mode. The cutoff defaults to 60 seconds; set `params.fastAutoOnSeconds` on the active model to change it.
```json5
{
agents: {
defaults: {
models: {
"openai/gpt-5.5": { params: { fastMode: true } },
"openai/gpt-5.5": { params: { fastMode: "auto", fastAutoOnSeconds: 30 } },
},
},
},

View File

@@ -198,7 +198,7 @@ plugins.
| `/think <level\|default>` | Set the thinking level or clear the session override. Aliases: `/thinking`, `/t` |
| `/verbose on\|off\|full` | Toggle verbose output. Alias: `/v` |
| `/trace on\|off` | Toggle plugin trace output for the current session |
| `/fast [status\|on\|off\|default]` | Show, set, or clear fast mode |
| `/fast [status\|auto\|on\|off\|default]` | Show, set, or clear fast mode |
| `/reasoning [on\|off\|stream]` | Toggle reasoning visibility. Alias: `/reason` |
| `/elevated [on\|off\|ask\|full]` | Toggle elevated mode. Alias: `/elev` |
| `/exec host=<auto\|sandbox\|gateway\|node> security=<deny\|allowlist\|full> ask=<off\|on-miss\|always> node=<id>` | Show or set exec defaults |
@@ -211,7 +211,7 @@ plugins.
<Accordion title="verbose / trace / fast / reasoning safety">
- `/verbose` is for debugging — keep it **off** in normal use.
- `/trace` reveals only plugin-owned trace/debug lines; normal verbose chatter stays off.
- `/fast on|off` persists a session override; use the Sessions UI `inherit` option to clear it.
- `/fast auto|on|off` persists a session override; use the Sessions UI `inherit` option to clear it.
- `/fast` is provider-specific: OpenAI/Codex map it to `service_tier=priority`; direct Anthropic requests map it to `service_tier=auto` or `standard_only`.
- `/reasoning`, `/verbose`, and `/trace` are risky in group settings — they may reveal internal reasoning or plugin diagnostics. Keep them off in group chats.

View File

@@ -60,21 +60,22 @@ title: "Thinking levels"
## Fast mode (/fast)
- Levels: `on|off|default`.
- Directive-only message toggles a session fast-mode override and replies `Fast mode enabled.` / `Fast mode disabled.`. Use `/fast default` to clear the session override and inherit the configured default; aliases include `inherit`, `clear`, `reset`, and `unpin`.
- Levels: `auto|on|off|default`.
- Directive-only message toggles a session fast-mode override and replies `Fast mode set to auto.`, `Fast mode enabled.`, or `Fast mode disabled.`. Use `/fast default` to clear the session override and inherit the configured default; aliases include `inherit`, `clear`, `reset`, and `unpin`.
- Send `/fast` (or `/fast status`) with no mode to see the current effective fast-mode state.
- OpenClaw resolves fast mode in this order:
1. Inline/directive-only `/fast on|off` override (`/fast default` clears this layer)
1. Inline/directive-only `/fast auto|on|off` override (`/fast default` clears this layer)
2. Session override
3. Per-agent default (`agents.list[].fastModeDefault`)
4. Per-model config: `agents.defaults.models["<provider>/<model>"].params.fastMode`
5. Fallback: `off`
- `auto` keeps the session/config mode as auto but resolves each new model call independently. Calls that start before the auto cutoff have fast mode enabled; later retry, fallback, tool-result, or continuation calls start with fast mode disabled. The cutoff defaults to 60 seconds; set `agents.defaults.models["<provider>/<model>"].params.fastAutoOnSeconds` on the active model to change it.
- For `openai/*`, fast mode maps to OpenAI priority processing by sending `service_tier=priority` on supported Responses requests.
- For Codex-backed `openai/*` models, fast mode sends the same `service_tier=priority` flag on Codex Responses. OpenClaw keeps one shared `/fast` toggle across both auth paths.
- For Codex-backed `openai/*` / `openai-codex/*` models, fast mode sends the same `service_tier=priority` flag on Codex Responses. Native Codex app-server turns receive the tier only on `turn/start` or thread start/resume, so `auto` cannot retier one already-running app-server turn; it applies to the next model turn OpenClaw starts.
- For direct public `anthropic/*` requests, including OAuth-authenticated traffic sent to `api.anthropic.com`, fast mode maps to Anthropic service tiers: `/fast on` sets `service_tier=auto`, `/fast off` sets `service_tier=standard_only`.
- For `minimax/*` on the Anthropic-compatible path, `/fast on` (or `params.fastMode: true`) rewrites `MiniMax-M2.7` to `MiniMax-M2.7-highspeed`.
- Explicit Anthropic `serviceTier` / `service_tier` model params override the fast-mode default when both are set. OpenClaw still skips Anthropic service-tier injection for non-Anthropic proxy base URLs.
- `/status` shows `Fast` only when fast mode is enabled.
- `/status` shows `Fast` when fast mode is enabled and `Fast:auto` when the configured mode is auto.
## Verbose directives (/verbose or /v)

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/acpx",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/acpx",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"@agentclientprotocol/claude-agent-acp": "0.39.0",
"@zed-industries/codex-acp": "0.15.0",
@@ -701,6 +701,7 @@
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/@zed-industries/codex-acp/-/codex-acp-0.15.0.tgz",
"integrity": "sha512-eAv7sGBeiYrYkOulF729nrM51szS7WIhBtugRj5wWq6csRKZUhAZfoUZlF8xUWdHPtOIzd/eT6MNG6gMHu6z0w==",
"deprecated": "This package has been replaced by @agentclientprotocol/codex-acp. Please migrate to continue receiving updates.",
"license": "Apache-2.0",
"bin": {
"codex-acp": "bin/codex-acp.js"
@@ -721,6 +722,7 @@
"cpu": [
"arm64"
],
"deprecated": "This package has been replaced by @agentclientprotocol/codex-acp. Please migrate to continue receiving updates.",
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -737,6 +739,7 @@
"cpu": [
"x64"
],
"deprecated": "This package has been replaced by @agentclientprotocol/codex-acp. Please migrate to continue receiving updates.",
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -753,6 +756,7 @@
"cpu": [
"arm64"
],
"deprecated": "This package has been replaced by @agentclientprotocol/codex-acp. Please migrate to continue receiving updates.",
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -769,6 +773,7 @@
"cpu": [
"x64"
],
"deprecated": "This package has been replaced by @agentclientprotocol/codex-acp. Please migrate to continue receiving updates.",
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -785,6 +790,7 @@
"cpu": [
"arm64"
],
"deprecated": "This package has been replaced by @agentclientprotocol/codex-acp. Please migrate to continue receiving updates.",
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -801,6 +807,7 @@
"cpu": [
"x64"
],
"deprecated": "This package has been replaced by @agentclientprotocol/codex-acp. Please migrate to continue receiving updates.",
"license": "Apache-2.0",
"optional": true,
"os": [

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/acpx",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw ACP runtime backend with plugin-owned session and transport management.",
"repository": {
"type": "git",
@@ -26,10 +26,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"staticAssets": [
{
"source": "./src/runtime-internals/mcp-proxy.mjs",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/admin-http-rpc",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw admin HTTP RPC endpoint",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/alibaba-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw Alibaba Model Studio video provider plugin",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/amazon-bedrock-mantle-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/amazon-bedrock-mantle-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"@anthropic-ai/sdk": "0.100.1",
"@aws/bedrock-token-generator": "1.1.0"

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/amazon-bedrock-mantle-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Amazon Bedrock Mantle provider plugin for OpenAI-compatible model routing.",
"repository": {
"type": "git",
@@ -24,10 +24,10 @@
"minHostVersion": ">=2026.5.12-beta.1"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/amazon-bedrock-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/amazon-bedrock-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"@aws-sdk/client-bedrock": "3.1056.0",
"@aws-sdk/client-bedrock-runtime": "3.1056.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/amazon-bedrock-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Amazon Bedrock provider plugin with model discovery, embeddings, and guardrail support.",
"repository": {
"type": "git",
@@ -28,10 +28,10 @@
"minHostVersion": ">=2026.5.12-beta.1"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/anthropic-vertex-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/anthropic-vertex-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"@anthropic-ai/vertex-sdk": "0.16.1"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/anthropic-vertex-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Anthropic Vertex provider plugin for Claude models on Google Vertex AI.",
"repository": {
"type": "git",
@@ -23,10 +23,10 @@
"minHostVersion": ">=2026.5.12-beta.1"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/anthropic-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw Anthropic provider plugin",
"type": "module",

View File

@@ -8,6 +8,7 @@ import {
createAnthropicServiceTierWrapper,
createAnthropicThinkingPrefillWrapper,
resolveAnthropicBetas,
resolveAnthropicFastMode,
wrapAnthropicProviderStream,
} from "./stream-wrappers.js";
@@ -172,6 +173,10 @@ describe("anthropic stream wrappers", () => {
expect(captured.headers?.["anthropic-beta"]).toContain(OAUTH_BETA);
expect(captured.headers?.["anthropic-beta"]).not.toContain(CONTEXT_1M_BETA);
});
it("ignores unresolved auto fast mode at the provider boundary", () => {
expect(resolveAnthropicFastMode({ fastMode: "auto" })).toBeUndefined();
});
});
describe("createAnthropicThinkingPrefillWrapper", () => {
@@ -282,6 +287,19 @@ describe("Anthropic service_tier payload wrappers", () => {
expect(payload?.service_tier).toBe("standard_only");
});
it("fast mode resolves dynamic service_tier for each stream call", () => {
let enabled = true;
const first = runPayloadWrapper({ apiKey: "sk-ant-api03-test-key" }, (base) =>
createAnthropicFastModeWrapper(base, () => enabled),
);
enabled = false;
const second = runPayloadWrapper({ apiKey: "sk-ant-api03-test-key" }, (base) =>
createAnthropicFastModeWrapper(base, () => enabled),
);
expect(first?.service_tier).toBe("auto");
expect(second?.service_tier).toBe("standard_only");
});
it("explicit service tier injects service_tier=standard_only for regular API keys", () => {
const payload = serviceTierWrapperCases[1].run({
apiKey: "sk-ant-api03-test-key",

View File

@@ -44,6 +44,7 @@ const OPENCLAW_OAUTH_ANTHROPIC_BETAS = [
] as const;
type AnthropicServiceTier = "auto" | "standard_only";
type DynamicFastMode = boolean | (() => boolean | undefined);
function isAnthropic1MModel(modelId: string): boolean {
const normalized = normalizeLowercaseStringOrEmpty(modelId);
@@ -157,9 +158,20 @@ export function createAnthropicBetaHeadersWrapper(
/** Wrap a stream function with the Anthropic fast-mode service tier. */
export function createAnthropicFastModeWrapper(
baseStreamFn: StreamFn | undefined,
enabled: boolean,
enabled: DynamicFastMode,
): StreamFn {
return createAnthropicServiceTierWrapper(baseStreamFn, resolveAnthropicFastServiceTier(enabled));
const underlying = baseStreamFn ?? streamSimple;
return (model, context, options) => {
const resolved = typeof enabled === "function" ? enabled() : enabled;
if (resolved === undefined) {
return underlying(model, context, options);
}
return createAnthropicServiceTierWrapper(underlying, resolveAnthropicFastServiceTier(resolved))(
model,
context,
options,
);
};
}
/** Wrap a stream function with an explicit Anthropic service tier when allowed. */
@@ -204,9 +216,12 @@ export function createAnthropicThinkingPrefillWrapper(
export function resolveAnthropicFastMode(
extraParams: Record<string, unknown> | undefined,
): boolean | undefined {
return normalizeFastMode(
(extraParams?.fastMode ?? extraParams?.fast_mode) as string | boolean | null | undefined,
);
const raw = extraParams?.fastMode ?? extraParams?.fast_mode;
const fastMode =
typeof raw === "function"
? normalizeFastMode((raw as () => unknown)() as string | boolean | null | undefined)
: normalizeFastMode(raw as string | boolean | null | undefined);
return fastMode === "auto" ? undefined : fastMode;
}
/** Resolve Anthropic service tier from model extra params. */
@@ -232,7 +247,9 @@ export function wrapAnthropicProviderStream(
hasConfiguredAnthropicBeta(ctx.extraParams) ||
(ctx.extraParams?.context1m === true && isAnthropic1MModel(ctx.modelId));
const serviceTier = resolveAnthropicServiceTier(ctx.extraParams);
const fastMode = resolveAnthropicFastMode(ctx.extraParams);
const hasFastModeParam =
ctx.extraParams !== undefined &&
(Object.hasOwn(ctx.extraParams, "fastMode") || Object.hasOwn(ctx.extraParams, "fast_mode"));
return composeProviderStreamWrappers(
ctx.streamFn,
needsAnthropicBetaWrapper
@@ -241,8 +258,9 @@ export function wrapAnthropicProviderStream(
serviceTier
? (streamFn) => createAnthropicServiceTierWrapper(streamFn, serviceTier)
: undefined,
fastMode !== undefined
? (streamFn) => createAnthropicFastModeWrapper(streamFn, fastMode)
hasFastModeParam
? (streamFn) =>
createAnthropicFastModeWrapper(streamFn, () => resolveAnthropicFastMode(ctx.extraParams))
: undefined,
(streamFn) => createAnthropicThinkingPrefillWrapper(streamFn),
);

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/arcee-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/arcee-provider",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/arcee-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Arcee provider plugin.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/azure-speech",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw Azure Speech plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/bonjour",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Bonjour/mDNS gateway discovery",
"type": "module",
"dependencies": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/brave-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/brave-plugin",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/brave-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Brave Search provider plugin for web search.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"allowInvalidConfigRecovery": true
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9"
"openclawVersion": "2026.6.10"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/browser-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw browser tool plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/byteplus-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw BytePlus provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/canvas-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw Canvas plugin",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/cerebras-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/cerebras-provider",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/cerebras-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Cerebras provider plugin.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/chutes-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/chutes-provider",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/chutes-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Chutes.ai provider plugin.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/clickclack",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw ClickClack channel plugin",
"type": "module",
@@ -18,7 +18,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.9"
"openclaw": ">=2026.6.10"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/cloudflare-ai-gateway-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/cloudflare-ai-gateway-provider",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/cloudflare-ai-gateway-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Cloudflare AI Gateway provider plugin.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/codex-supervisor",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw Codex app-server fleet supervision plugin.",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/codex",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/codex",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"@openai/codex": "0.139.0",
"typebox": "1.1.39",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/codex",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Codex app-server harness and model provider plugin with a Codex-managed GPT catalog.",
"repository": {
"type": "git",
@@ -34,10 +34,10 @@
]
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9"
"openclawVersion": "2026.6.10"
},
"release": {
"publishToClawHub": true,

View File

@@ -189,7 +189,23 @@ export function isRawToolOutputCompletionNotification(
return false;
}
const item = isJsonObject(notification.params.item) ? notification.params.item : undefined;
return item ? readString(item, "type") === "custom_tool_call_output" : false;
switch (item ? readString(item, "type") : undefined) {
case "custom_tool_call_output":
case "function_call_output":
return true;
default:
return false;
}
}
export function isRawFunctionToolOutputCompletionNotification(
notification: CodexServerNotification,
): boolean {
if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) {
return false;
}
const item = isJsonObject(notification.params.item) ? notification.params.item : undefined;
return item ? readString(item, "type") === "function_call_output" : false;
}
/** Returns true for progress on Codex-native tool item types. */

View File

@@ -188,7 +188,7 @@ export type CodexAppServerRuntimeOptions = {
approvalPolicySource?: CodexAppServerApprovalPolicySource;
sandbox: CodexAppServerSandboxMode;
approvalsReviewer: CodexAppServerApprovalsReviewer;
serviceTier?: CodexServiceTier;
serviceTier?: CodexServiceTier | null;
networkProxy?: ResolvedCodexAppServerNetworkProxyConfig;
};

View File

@@ -65,6 +65,7 @@ export type CodexAppServerToolTelemetry = {
export type CodexAppServerEventProjectorOptions = {
nativePostToolUseRelayEnabled?: boolean;
onNativeToolResultRecorded?: () => void | Promise<void>;
trajectoryRecorder?: CodexTrajectoryRecorder | null;
};
@@ -632,7 +633,7 @@ export class CodexAppServerEventProjector {
}
this.recordToolMeta(item);
this.emitStandardItemEvent({ phase: "start", item });
this.emitNormalizedToolItemEvent({ phase: "start", item });
await this.emitNormalizedToolItemEvent({ phase: "start", item });
this.recordNativeToolTranscriptCall(item);
this.emitToolResultSummary(item);
this.emitAgentEvent({
@@ -696,7 +697,7 @@ export class CodexAppServerEventProjector {
}
this.recordToolMeta(item);
this.emitStandardItemEvent({ phase: "end", item });
this.emitNormalizedToolItemEvent({ phase: "result", item });
await this.emitNormalizedToolItemEvent({ phase: "result", item });
this.recordNativeToolTranscriptCall(item);
this.recordNativeToolTranscriptResult(item);
this.emitToolResultSummary(item);
@@ -816,7 +817,7 @@ export class CodexAppServerEventProjector {
this.emitPlanUpdate({ explanation: undefined, steps: splitPlanText(item.text) });
}
this.recordToolMeta(item);
this.emitSnapshotOnlyNativeToolProgress(item);
await this.emitSnapshotOnlyNativeToolProgress(item);
this.recordNativeToolTranscriptCall(item);
this.recordNativeToolTranscriptResult(item);
this.emitAfterToolCallObservation(item);
@@ -827,7 +828,7 @@ export class CodexAppServerEventProjector {
await this.maybeEndReasoning();
}
private emitSnapshotOnlyNativeToolProgress(item: CodexThreadItem): void {
private async emitSnapshotOnlyNativeToolProgress(item: CodexThreadItem): Promise<void> {
if (
!shouldSynthesizeToolProgressForItem(item) ||
!this.isCurrentTurnSnapshotItem(item) ||
@@ -839,11 +840,11 @@ export class CodexAppServerEventProjector {
const wasStarted = this.activeItemIds.has(item.id);
if (!wasStarted) {
this.emitStandardItemEvent({ phase: "start", item });
this.emitNormalizedToolItemEvent({ phase: "start", item });
await this.emitNormalizedToolItemEvent({ phase: "start", item });
}
this.activeItemIds.delete(item.id);
this.emitStandardItemEvent({ phase: "end", item });
this.emitNormalizedToolItemEvent({ phase: "result", item });
await this.emitNormalizedToolItemEvent({ phase: "result", item });
this.completedItemIds.add(item.id);
}
@@ -1116,10 +1117,10 @@ export class CodexAppServerEventProjector {
});
}
private emitNormalizedToolItemEvent(params: {
private async emitNormalizedToolItemEvent(params: {
phase: "start" | "result";
item: CodexThreadItem | undefined;
}): void {
}): Promise<void> {
const { item } = params;
if (!item || !shouldSynthesizeToolProgressForItem(item)) {
return;
@@ -1139,6 +1140,7 @@ export class CodexAppServerEventProjector {
if (!shouldEmitTranscriptToolProgress(name, args)) {
if (params.phase === "result") {
this.emitAfterToolCallObservation(item);
await this.options.onNativeToolResultRecorded?.();
}
return;
}
@@ -1162,6 +1164,7 @@ export class CodexAppServerEventProjector {
});
if (params.phase === "result") {
this.emitAfterToolCallObservation(item);
await this.options.onNativeToolResultRecorded?.();
}
}

View File

@@ -5617,6 +5617,50 @@ describe("runCodexAppServerAttempt", () => {
expect(resumeRequestParams?.approvalsReviewer).toBe("guardian_subagent");
});
it.each([
{ name: "fast on", fastMode: true, expectedServiceTier: "priority" },
{
name: "fast off",
fastMode: false,
configuredServiceTier: "priority",
expectedServiceTier: null,
},
{
name: "fast auto active",
fastMode: () => true,
expectedServiceTier: "priority",
},
] satisfies Array<{
name: string;
fastMode: EmbeddedRunAttemptParams["fastMode"];
configuredServiceTier?: "priority";
expectedServiceTier?: "priority" | null;
}>)(
"maps $name to app-server resume and turn service tier",
async ({ fastMode, configuredServiceTier, expectedServiceTier }) => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
await writeExistingBinding(sessionFile, workspaceDir, { model: "gpt-5.2" });
const { requests, waitForMethod, completeTurn } = createResumeHarness();
const params = createParams(sessionFile, workspaceDir);
params.fastMode = fastMode;
const options = configuredServiceTier
? { pluginConfig: { appServer: { serviceTier: configuredServiceTier } } }
: {};
const run = runCodexAppServerAttempt(params, options);
await waitForMethod("turn/start");
await completeTurn({ threadId: "thread-existing", turnId: "turn-1" });
await run;
for (const method of ["thread/resume", "turn/start"]) {
const request = requests.find((entry) => entry.method === method);
const requestParams = request?.params as Record<string, unknown> | undefined;
expect(requestParams?.serviceTier).toBe(expectedServiceTier);
}
},
);
it("reuses the bound auth profile for app-server startup when params omit it", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
@@ -5662,4 +5706,314 @@ describe("runCodexAppServerAttempt", () => {
expect(seenAgentDirs).toEqual([path.join(tempDir, "agent")]);
expect(requests.map((entry) => entry.method)).toContain("turn/start");
});
it("announces Codex app-server fast auto progress after the crossing tool result", async () => {
const now = vi.spyOn(Date, "now").mockReturnValue(1_000);
const onToolResult = vi.fn();
const onAgentEvent = vi.fn();
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const harness = createStartedThreadHarness();
const params = createParams(sessionFile, workspaceDir);
params.verboseLevel = "full";
params.fastModeAuto = true;
params.fastModeStartedAtMs = 1_000;
params.fastModeAutoOnSeconds = 30;
params.onToolResult = onToolResult;
params.onAgentEvent = onAgentEvent;
const run = runCodexAppServerAttempt(params);
await harness.waitForMethod("turn/start");
const notifyCommand = async (id: string, output: string, nowMs: number) => {
await harness.notify({
method: "item/started",
params: {
threadId: "thread-1",
turnId: "turn-1",
item: {
type: "commandExecution",
id,
command: `echo ${id}`,
cwd: workspaceDir,
status: "inProgress",
},
},
});
now.mockReturnValue(nowMs);
await harness.notify({
method: "item/completed",
params: {
threadId: "thread-1",
turnId: "turn-1",
item: {
type: "commandExecution",
id,
command: `echo ${id}`,
cwd: workspaceDir,
status: "completed",
aggregatedOutput: output,
exitCode: 0,
durationMs: 1,
},
},
});
};
await notifyCommand("tool-before", "before", 20_000);
await notifyCommand("tool-crossing", "crossing", 35_500);
await notifyCommand("tool-after", "after", 42_000);
await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
await run;
const payloads = onToolResult.mock.calls.map(([payload]) => payload) as Array<{
channelData?: Record<string, unknown>;
text?: string;
}>;
const texts = payloads.map((payload) => payload.text ?? "");
expect(texts.filter((text) => text.startsWith("💨Fast: auto-off"))).toEqual([
"💨Fast: auto-off(34s>=30s)",
]);
expect(texts.filter((text) => text === "💨Fast: auto-on")).toHaveLength(1);
const offIndex = texts.indexOf("💨Fast: auto-off(34s>=30s)");
const onIndex = texts.indexOf("💨Fast: auto-on");
expect(offIndex).toBeGreaterThan(0);
expect(onIndex).toBeGreaterThan(offIndex + 1);
expect(texts.slice(offIndex + 1, onIndex).some((text) => !text.startsWith("💨Fast:"))).toBe(
true,
);
expect(payloads[offIndex]?.channelData).toEqual({
openclawProgressKind: "fast-mode-auto",
});
expect(payloads[onIndex]?.channelData).toEqual({
openclawProgressKind: "fast-mode-auto",
});
const fastEvents = onAgentEvent.mock.calls
.map(([event]) => event)
.filter((event) => event.stream === "item" && event.data?.title === "Fast");
expect(fastEvents.map((event) => event.data?.summary)).toEqual([
"💨Fast: auto-off(34s>=30s)",
"💨Fast: auto-on",
]);
});
it("does not announce Codex fast auto progress for explicit fast mode", async () => {
const now = vi.spyOn(Date, "now").mockReturnValue(1_000);
const onToolResult = vi.fn();
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const harness = createStartedThreadHarness();
const params = createParams(sessionFile, workspaceDir);
params.fastModeAuto = false;
params.fastModeStartedAtMs = 1_000;
params.fastModeAutoOnSeconds = 30;
params.onToolResult = onToolResult;
const run = runCodexAppServerAttempt(params);
await harness.waitForMethod("turn/start");
now.mockReturnValue(35_500);
await harness.notify({
method: "rawResponseItem/completed",
params: {
threadId: "thread-1",
turnId: "turn-1",
item: {
type: "function_call_output",
id: "call-raw-output",
call_id: "call-raw-output",
output: "tool output",
},
},
});
await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
await run;
const texts = onToolResult.mock.calls.map(([payload]) => payload.text ?? "");
expect(texts.filter((text) => text.startsWith("💨Fast:"))).toEqual([]);
});
it("announces Codex app-server fast auto progress for snapshot-only tool results", async () => {
const now = vi.spyOn(Date, "now").mockReturnValue(1_000);
const onToolResult = vi.fn();
const onAgentEvent = vi.fn();
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const harness = createStartedThreadHarness();
const params = createParams(sessionFile, workspaceDir);
params.verboseLevel = "full";
params.fastModeAuto = true;
params.fastModeStartedAtMs = 1_000;
params.fastModeAutoOnSeconds = 30;
params.onToolResult = onToolResult;
params.onAgentEvent = onAgentEvent;
const run = runCodexAppServerAttempt(params);
await harness.waitForMethod("turn/start");
await new Promise<void>((resolve) => {
setImmediate(resolve);
});
now.mockReturnValue(35_500);
await harness.notify({
method: "turn/completed",
params: {
threadId: "thread-1",
turnId: "turn-1",
turn: {
id: "turn-1",
status: "completed",
items: [
{
type: "commandExecution",
id: "tool-crossing",
command: "echo crossing",
commandActions: [],
cwd: workspaceDir,
processId: null,
source: "agent",
status: "completed",
aggregatedOutput: "crossing",
exitCode: 0,
durationMs: 1,
},
],
},
},
});
await run;
const texts = onToolResult.mock.calls.map(([payload]) => payload.text ?? "");
expect(texts.filter((text) => text.startsWith("💨Fast: auto-off"))).toEqual([
"💨Fast: auto-off(34s>=30s)",
]);
expect(texts.filter((text) => text === "💨Fast: auto-on")).toHaveLength(1);
const fastEvents = onAgentEvent.mock.calls
.map(([event]) => event)
.filter((event) => event.stream === "item" && event.data?.title === "Fast");
expect(fastEvents.map((event) => event.data?.summary)).toEqual([
"💨Fast: auto-off(34s>=30s)",
"💨Fast: auto-on",
]);
});
it("announces Codex app-server fast auto progress for raw function call outputs", async () => {
const now = vi.spyOn(Date, "now").mockReturnValue(1_000);
const onToolResult = vi.fn();
const onAgentEvent = vi.fn();
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const harness = createStartedThreadHarness();
const params = createParams(sessionFile, workspaceDir);
params.verboseLevel = "full";
params.fastModeAuto = true;
params.fastModeStartedAtMs = 1_000;
params.fastModeAutoOnSeconds = 30;
params.onToolResult = onToolResult;
params.onAgentEvent = onAgentEvent;
const run = runCodexAppServerAttempt(params);
await harness.waitForMethod("turn/start");
await new Promise<void>((resolve) => {
setImmediate(resolve);
});
now.mockReturnValue(35_500);
await harness.notify({
method: "rawResponseItem/completed",
params: {
threadId: "thread-1",
turnId: "turn-1",
item: {
type: "function_call_output",
id: "call-raw-output",
call_id: "call-raw-output",
output: "tool output",
},
},
});
await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
await run;
const texts = onToolResult.mock.calls.map(([payload]) => payload.text ?? "");
expect(texts.filter((text) => text.startsWith("💨Fast: auto-off"))).toEqual([
"💨Fast: auto-off(34s>=30s)",
]);
expect(texts.filter((text) => text === "💨Fast: auto-on")).toHaveLength(1);
const fastEvents = onAgentEvent.mock.calls
.map(([event]) => event)
.filter((event) => event.stream === "item" && event.data?.title === "Fast");
expect(fastEvents.map((event) => event.data?.summary)).toEqual([
"💨Fast: auto-off(34s>=30s)",
"💨Fast: auto-on",
]);
});
it("does not duplicate Codex app-server fast auto progress already announced by the outer runner", async () => {
const now = vi.spyOn(Date, "now").mockReturnValue(1_000);
const onToolResult = vi.fn();
const onAgentEvent = vi.fn();
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const harness = createStartedThreadHarness();
const params = createParams(sessionFile, workspaceDir);
params.verboseLevel = "full";
params.fastModeAuto = true;
params.fastModeStartedAtMs = 1_000;
params.fastModeAutoOnSeconds = 30;
params.fastModeAutoProgressState = {
offAnnounced: true,
resetAnnounced: false,
};
params.onToolResult = onToolResult;
params.onAgentEvent = onAgentEvent;
const run = runCodexAppServerAttempt(params);
await harness.waitForMethod("turn/start");
await harness.notify({
method: "item/started",
params: {
threadId: "thread-1",
turnId: "turn-1",
item: {
type: "commandExecution",
id: "tool-1",
command: "echo tool-1",
cwd: workspaceDir,
status: "inProgress",
},
},
});
now.mockReturnValue(35_500);
await harness.notify({
method: "item/completed",
params: {
threadId: "thread-1",
turnId: "turn-1",
item: {
type: "commandExecution",
id: "tool-1",
command: "echo tool-1",
cwd: workspaceDir,
status: "completed",
aggregatedOutput: "tool output",
exitCode: 0,
durationMs: 1,
},
},
});
await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
await run;
const texts = onToolResult.mock.calls.map(([payload]) => payload.text ?? "");
expect(texts.filter((text) => text.startsWith("💨Fast: auto-off"))).toEqual([]);
expect(texts.filter((text) => text === "💨Fast: auto-on")).toHaveLength(1);
expect(params.fastModeAutoProgressState).toEqual({
offAnnounced: true,
resetAnnounced: true,
});
const fastEvents = onAgentEvent.mock.calls
.map(([event]) => event)
.filter((event) => event.stream === "item" && event.data?.title === "Fast");
expect(fastEvents.map((event) => event.data?.summary)).toEqual(["💨Fast: auto-on"]);
});
});

View File

@@ -12,6 +12,8 @@ import {
embeddedAgentLog,
emitAgentEvent as emitGlobalAgentEvent,
finalizeHarnessContextEngineTurn,
FAST_MODE_AUTO_PROGRESS_KIND,
formatFastModeAutoProgressText,
formatErrorMessage,
getAgentHarnessHookRunner,
getBeforeToolCallPolicyDiagnosticState,
@@ -27,9 +29,11 @@ import {
runAgentHarnessLlmInputHook,
runAgentHarnessLlmOutputHook,
runHarnessContextEngineMaintenance,
resolveFastModeForElapsed,
setActiveEmbeddedRun,
supportsModelTools,
runAgentCleanupStep,
type FastModeAutoProgressState,
type EmbeddedRunAttemptParams,
type EmbeddedRunAttemptResult,
type NativeHookRelayEvent,
@@ -85,6 +89,7 @@ import {
isCurrentThreadOptionalTurnRequestParams,
isCurrentThreadTurnRequestParams,
isNativeResponseStreamDeltaNotification,
isRawFunctionToolOutputCompletionNotification,
isTerminalTurnStatus,
readCodexNotificationItem,
readRawResponseToolCallId,
@@ -274,6 +279,22 @@ const CODEX_APP_SERVER_PROJECTED_CHARS_PER_TOKEN = 4;
const CODEX_APP_SERVER_ACTIVE_NATIVE_TURN_WAIT_TIMEOUT_MS = 30_000;
const ensuredCodexWorkspaceDirs = new Set<string>();
function withCodexAppServerFastModeServiceTier(
appServer: CodexAppServerRuntimeOptions,
params: EmbeddedRunAttemptParams,
): CodexAppServerRuntimeOptions {
const fastMode = typeof params.fastMode === "function" ? params.fastMode() : params.fastMode;
const serviceTier =
fastMode === undefined ? appServer.serviceTier : fastMode ? "priority" : undefined;
if (serviceTier === appServer.serviceTier) {
return appServer;
}
if (serviceTier) {
return { ...appServer, serviceTier };
}
return { ...appServer, serviceTier: null };
}
function estimateCodexAppServerProjectedTurnTokens(params: {
prompt: string;
developerInstructions?: string;
@@ -306,10 +327,10 @@ async function ensureCodexWorkspaceDirOnce(workspaceDir: string): Promise<void>
ensuredCodexWorkspaceDirs.add(normalized);
}
function emitCodexAppServerEvent(
async function emitCodexAppServerEvent(
params: EmbeddedRunAttemptParams,
event: Parameters<NonNullable<EmbeddedRunAttemptParams["onAgentEvent"]>>[0],
): void {
): Promise<void> {
try {
emitGlobalAgentEvent({
runId: params.runId,
@@ -321,10 +342,7 @@ function emitCodexAppServerEvent(
embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
}
try {
const maybePromise = params.onAgentEvent?.(event);
void Promise.resolve(maybePromise).catch((error: unknown) => {
embeddedAgentLog.debug("codex app-server agent event handler rejected", { error });
});
await params.onAgentEvent?.(event);
} catch (error) {
// Event consumers are observational; they must not abort or strand the
// canonical app-server turn lifecycle.
@@ -416,6 +434,14 @@ export async function runCodexAppServerAttempt(
);
const codexModelContentCapture = resolveDiagnosticModelContentCapturePolicy(params.config);
const codexModelCallId = `${params.runId}:codex-model:1`;
const fastModeAutoStartedAtMs =
typeof params.fastModeStartedAtMs === "number" && Number.isFinite(params.fastModeStartedAtMs)
? params.fastModeStartedAtMs
: undefined;
const fastModeAutoProgressState: FastModeAutoProgressState = params.fastModeAutoProgressState ?? {
offAnnounced: false,
resetAnnounced: false,
};
// Startup phase timings are profiler-gated because this function runs before
// every Codex turn; normal production should not do timing bookkeeping here.
const preDynamicStartupStages = createCodexDynamicToolBuildStageTracker({
@@ -764,7 +790,9 @@ export async function runCodexAppServerAttempt(
onYieldDetected: () => {
yieldDetected = true;
},
onCodexAppServerEvent: (event) => emitCodexAppServerEvent(params, event),
onCodexAppServerEvent: (event) => {
void emitCodexAppServerEvent(params, event);
},
onPersistentWebSearchPolicyResolved: (allowed) => {
persistentWebSearchAllowed = allowed;
},
@@ -791,7 +819,9 @@ export async function runCodexAppServerAttempt(
onYieldDetected: () => {
yieldDetected = true;
},
onCodexAppServerEvent: (event) => emitCodexAppServerEvent(params, event),
onCodexAppServerEvent: (event) => {
void emitCodexAppServerEvent(params, event);
},
});
const toolBridge = createCodexDynamicToolBridge({
tools,
@@ -1424,13 +1454,15 @@ export async function runCodexAppServerAttempt(
};
};
try {
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "codex_app_server.lifecycle",
data: { phase: "startup" },
});
const attemptAppServer = withCodexAppServerFastModeServiceTier(appServer, params);
pluginAppServer = attemptAppServer;
const startupResult = await startCodexAttemptThread({
attemptClientFactory,
appServer,
appServer: attemptAppServer,
pluginConfig,
computerUseConfig,
startupAuthProfileId,
@@ -1469,7 +1501,7 @@ export async function runCodexAppServerAttempt(
codexSandboxPolicy = startupResult.sandboxPolicy;
releaseSharedClientLease = startupResult.releaseSharedClientLease;
restartContextEngineCodexThread = startupResult.restartContextEngineCodexThread;
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "codex_app_server.lifecycle",
data: { phase: "thread_ready", threadId: thread.threadId },
});
@@ -1713,7 +1745,7 @@ export async function runCodexAppServerAttempt(
};
const emitLifecycleStart = () => {
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "lifecycle",
data: { phase: "start", startedAt: attemptStartedAt },
});
@@ -1724,7 +1756,7 @@ export async function runCodexAppServerAttempt(
if (!lifecycleStarted || lifecycleTerminalEmitted) {
return;
}
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "lifecycle",
data: {
startedAt: attemptStartedAt,
@@ -1760,6 +1792,75 @@ export async function runCodexAppServerAttempt(
emitExecutionPhaseOnce,
});
};
const emitFastModeAutoProgress = async (payload: {
enabled: boolean;
elapsedSeconds: number;
fastAutoOnSeconds?: number;
}): Promise<void> => {
const summary = formatFastModeAutoProgressText(payload);
await emitCodexAppServerEvent(params, {
stream: "item",
data: {
kind: "status",
title: "Fast",
phase: "update",
summary,
},
});
try {
await params.onToolResult?.({
text: summary,
channelData: { openclawProgressKind: FAST_MODE_AUTO_PROGRESS_KIND },
});
} catch (error) {
embeddedAgentLog.debug("codex app-server fast mode auto progress delivery failed", {
error,
});
}
};
const maybeAnnounceFastModeAutoOff = async (): Promise<void> => {
if (
params.fastModeAuto !== true ||
fastModeAutoStartedAtMs === undefined ||
fastModeAutoProgressState.offAnnounced
) {
return;
}
const next = resolveFastModeForElapsed({
mode: "auto",
startedAtMs: fastModeAutoStartedAtMs,
fastAutoOnSeconds: params.fastModeAutoOnSeconds,
});
if (next.enabled) {
return;
}
fastModeAutoProgressState.offAnnounced = true;
await emitFastModeAutoProgress(next);
};
const maybeEmitFastModeAutoReset = async (): Promise<void> => {
if (
params.fastModeAuto !== true ||
!fastModeAutoProgressState.offAnnounced ||
fastModeAutoProgressState.resetAnnounced
) {
return;
}
fastModeAutoProgressState.resetAnnounced = true;
await emitFastModeAutoProgress({
enabled: true,
elapsedSeconds: 0,
fastAutoOnSeconds: params.fastModeAutoOnSeconds,
});
};
const maybeEmitFastModeAutoResetBestEffort = async (): Promise<void> => {
try {
await maybeEmitFastModeAutoReset();
} catch (error) {
embeddedAgentLog.warn(
`codex app-server fast mode auto reset progress failed: ${formatErrorMessage(error)}`,
);
}
};
const isTerminalTurnNotificationForTurn = (
notification: CodexServerNotification,
@@ -1806,6 +1907,13 @@ export async function runCodexAppServerAttempt(
try {
await waitForCodexNotificationDispatchTurn();
await projector.handleNotification(notification);
if (
notificationState.isCurrentTurnNotification &&
activeTurnItemIds.size === 0 &&
isRawFunctionToolOutputCompletionNotification(notification)
) {
await maybeAnnounceFastModeAutoOff();
}
} catch (error) {
embeddedAgentLog.debug("codex app-server projector notification threw", {
method: notification.method,
@@ -2082,7 +2190,7 @@ export async function runCodexAppServerAttempt(
const toolArgs = sanitizeCodexToolArguments(call.arguments);
const shouldEmitDynamicToolProgress = shouldEmitTranscriptToolProgress(call.tool, toolArgs);
if (shouldEmitDynamicToolProgress) {
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "tool",
data: {
phase: "start",
@@ -2172,7 +2280,7 @@ export async function runCodexAppServerAttempt(
});
if (shouldEmitDynamicToolProgress) {
const progressResponse = toCodexDynamicToolProgressResponse(response, protocolResponse);
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "tool",
data: {
phase: "result",
@@ -2322,10 +2430,12 @@ export async function runCodexAppServerAttempt(
throw error;
};
const startCodexTurn = async (): Promise<CodexTurnStartResponse> => {
const turnAppServer = withCodexAppServerFastModeServiceTier(pluginAppServer, params);
pluginAppServer = turnAppServer;
const turnStartParams = buildTurnStartParams(params, {
threadId: thread.threadId,
cwd: codexExecutionCwd,
appServer: pluginAppServer,
appServer: turnAppServer,
promptText: codexTurnPromptText,
sandboxPolicy: codexSandboxPolicy,
environmentSelection: codexEnvironmentSelection,
@@ -2357,7 +2467,7 @@ export async function runCodexAppServerAttempt(
"codex app-server resumed thread has active native turn; waiting before turn/start",
{ threadId: thread.threadId, activeTurnIds: activeNativeTurnIds },
);
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "codex_app_server.lifecycle",
data: {
phase: "turn_start_waiting_for_native_turn",
@@ -2380,7 +2490,7 @@ export async function runCodexAppServerAttempt(
ctx: hookContext,
hookRunner,
});
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "codex_app_server.lifecycle",
data: { phase: "turn_starting", threadId: thread.threadId },
});
@@ -2397,7 +2507,7 @@ export async function runCodexAppServerAttempt(
);
const compactTurnCompleted = await waitForActiveNativeTurnCompletion();
if (compactTurnCompleted && !runAbortController.signal.aborted) {
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "codex_app_server.lifecycle",
data: { phase: "turn_start_retry_after_compact", threadId: thread.threadId },
});
@@ -2479,7 +2589,7 @@ export async function runCodexAppServerAttempt(
);
}
}
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "codex_app_server.lifecycle",
data: { phase: "thread_ready_retry", threadId: thread.threadId },
});
@@ -2509,7 +2619,7 @@ export async function runCodexAppServerAttempt(
error: turnStartErrorMessage,
});
}
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "codex_app_server.lifecycle",
data: { phase: "turn_start_failed", error: turnStartErrorMessage },
});
@@ -2632,6 +2742,7 @@ export async function runCodexAppServerAttempt(
nativeHookRelay?.allowedEvents.includes("post_tool_use") === true &&
nativeHookRelay.shouldRelayEvent("post_tool_use"),
trajectoryRecorder,
onNativeToolResultRecorded: maybeAnnounceFastModeAutoOff,
},
);
if (
@@ -2892,7 +3003,7 @@ export async function runCodexAppServerAttempt(
});
const terminalAssistantText = collectTerminalAssistantText(result);
if (terminalAssistantText && !finalAborted && !finalPromptError) {
emitCodexAppServerEvent(params, {
void emitCodexAppServerEvent(params, {
stream: "assistant",
data: { text: terminalAssistantText },
});
@@ -3024,6 +3135,9 @@ export async function runCodexAppServerAttempt(
systemPromptReport,
};
} finally {
if (params.isFinalFallbackAttempt !== false) {
await maybeEmitFastModeAutoResetBestEffort();
}
codexModelCallDiagnostics.emitError(
"codex app-server run completed without model-call terminal event",
);

View File

@@ -1113,7 +1113,9 @@ export function buildThreadStartParams(
approvalPolicy: options.appServer.approvalPolicy,
approvalsReviewer: options.appServer.approvalsReviewer,
...codexThreadSandboxOrPermissions(options.appServer),
...(options.appServer.serviceTier ? { serviceTier: options.appServer.serviceTier } : {}),
...(options.appServer.serviceTier !== undefined
? { serviceTier: options.appServer.serviceTier }
: {}),
personality: CODEX_NATIVE_PERSONALITY_NONE,
serviceName: "OpenClaw",
config: buildCodexRuntimeThreadConfigForRun(params, options.config, {
@@ -1193,7 +1195,9 @@ export function buildThreadResumeParams(
approvalPolicy: options.appServer.approvalPolicy,
approvalsReviewer: options.appServer.approvalsReviewer,
...codexThreadSandboxOrPermissions(options.appServer),
...(options.appServer.serviceTier ? { serviceTier: options.appServer.serviceTier } : {}),
...(options.appServer.serviceTier !== undefined
? { serviceTier: options.appServer.serviceTier }
: {}),
personality: CODEX_NATIVE_PERSONALITY_NONE,
config: buildCodexRuntimeThreadConfigForRun(params, options.config, {
nativeCodeModeEnabled: options.nativeCodeModeEnabled,
@@ -1428,7 +1432,9 @@ export function buildTurnStartParams(
}),
model: modelSelection.model,
personality: CODEX_NATIVE_PERSONALITY_NONE,
...(options.appServer.serviceTier ? { serviceTier: options.appServer.serviceTier } : {}),
...(options.appServer.serviceTier !== undefined
? { serviceTier: options.appServer.serviceTier }
: {}),
effort: resolveReasoningEffort(params.thinkLevel, modelSelection.model),
...(options.environmentSelection ? { environments: options.environmentSelection } : {}),
collaborationMode: buildTurnCollaborationMode(params, {

View File

@@ -511,7 +511,7 @@ async function writeThreadBindingFromResponse(
sandbox: resolved.execPolicy?.touched
? resolved.runtime.sandbox
: (params.sandbox ?? resolved.runtime.sandbox),
serviceTier: params.serviceTier ?? resolved.runtime.serviceTier,
serviceTier: params.serviceTier ?? resolved.runtime.serviceTier ?? undefined,
networkProxyProfileName: resolved.runtime.networkProxy?.profileName,
networkProxyConfigFingerprint: resolved.runtime.networkProxy?.configFingerprint,
},
@@ -689,7 +689,7 @@ async function runBoundTurn(params: {
}),
approvalPolicy: typeof approvalPolicy === "string" ? approvalPolicy : undefined,
sandbox,
serviceTier,
serviceTier: serviceTier ?? undefined,
networkProxyProfileName: modelScopedRuntime.networkProxy?.profileName,
networkProxyConfigFingerprint: modelScopedRuntime.networkProxy?.configFingerprint,
},

View File

@@ -192,7 +192,7 @@ export async function setCodexConversationModel(params: {
modelProvider: response.modelProvider ?? modelSelection.modelProvider,
approvalPolicy: binding.approvalPolicy,
sandbox: binding.sandbox,
serviceTier: binding.serviceTier ?? runtime.serviceTier,
serviceTier: binding.serviceTier ?? runtime.serviceTier ?? undefined,
},
lookup,
);

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/cohere-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/cohere-provider",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/cohere-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Cohere provider plugin.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": true
},
"release": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/comfy-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw ComfyUI provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/copilot-proxy",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw Copilot Proxy provider plugin",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/copilot",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/copilot",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"@github/copilot-sdk": "1.0.0-beta.9"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/copilot",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw GitHub Copilot agent runtime plugin (registers a `github-copilot` AgentHarness backed by @github/copilot-sdk over JSON-RPC to the GitHub Copilot CLI)",
"repository": {
"type": "git",
@@ -25,10 +25,10 @@
"minHostVersion": ">=2026.5.28"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/deepgram-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw Deepgram media-understanding provider",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/deepinfra-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/deepinfra-provider",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/deepinfra-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw DeepInfra provider plugin.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/deepseek-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/deepseek-provider",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/deepseek-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw DeepSeek provider plugin.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/diagnostics-otel",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/diagnostics-otel",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"@opentelemetry/api": "1.9.1",
"@opentelemetry/api-logs": "0.219.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diagnostics-otel",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw diagnostics OpenTelemetry exporter for metrics, traces, and logs.",
"repository": {
"type": "git",
@@ -34,10 +34,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9"
"openclawVersion": "2026.6.10"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/diagnostics-prometheus",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/diagnostics-prometheus",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diagnostics-prometheus",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw diagnostics Prometheus exporter for runtime metrics.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.4.25"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9"
"openclawVersion": "2026.6.10"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/diffs-language-pack",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/diffs-language-pack",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diffs-language-pack",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw diffs viewer syntax highlighting language pack",
"repository": {
"type": "git",
@@ -22,13 +22,13 @@
"minHostVersion": ">=2026.5.27"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"assetScripts": {
"build": "node ../../scripts/build-diffs-viewer-runtime.mjs full"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"staticAssets": [
{
"source": "./assets/viewer-runtime.js",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/diffs",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/diffs",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"@pierre/diffs": "1.2.4",
"@pierre/theme": "1.0.3",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/diffs",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw read-only diff viewer plugin and file renderer for agents.",
"repository": {
"type": "git",
@@ -29,13 +29,13 @@
"minHostVersion": ">=2026.4.30"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"assetScripts": {
"build": "node ../../scripts/build-diffs-viewer-runtime.mjs curated"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"staticAssets": [
{
"source": "./assets/viewer-runtime.js",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/discord",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/discord",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"@discordjs/voice": "0.19.2",
"discord-api-types": "0.38.48",
@@ -16,7 +16,7 @@
"ws": "8.21.0"
},
"peerDependencies": {
"openclaw": ">=2026.6.9"
"openclaw": ">=2026.6.10"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/discord",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Discord channel plugin for channels, DMs, commands, and app events.",
"repository": {
"type": "git",
@@ -20,7 +20,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.9"
"openclaw": ">=2026.6.10"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -67,10 +67,10 @@
"allowInvalidConfigRecovery": true
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9"
"openclawVersion": "2026.6.10"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/document-extract-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw local document extraction plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/duckduckgo-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw DuckDuckGo plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/elevenlabs-speech",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw ElevenLabs speech plugin",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/exa-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/exa-plugin",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/exa-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Exa plugin.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/fal-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw fal provider plugin",
"type": "module",

View File

@@ -1,19 +1,19 @@
{
"name": "@openclaw/feishu",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/feishu",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"@larksuiteoapi/node-sdk": "1.66.0",
"typebox": "1.1.39",
"zod": "4.4.3"
},
"peerDependencies": {
"openclaw": ">=2026.6.9"
"openclaw": ">=2026.6.10"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/feishu",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Feishu/Lark channel plugin for chats and workplace tools (community maintained by @m1heng).",
"repository": {
"type": "git",
@@ -17,7 +17,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.9"
"openclaw": ">=2026.6.10"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -51,10 +51,10 @@
"minHostVersion": ">=2026.5.29"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9"
"openclawVersion": "2026.6.10"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/file-transfer",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw file transfer plugin (file_fetch, dir_list, dir_fetch, file_write)",
"type": "module",
"dependencies": {

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/firecrawl-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/firecrawl-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"typebox": "1.1.39"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/firecrawl-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Firecrawl plugin.",
"repository": {
"type": "git",
@@ -24,10 +24,10 @@
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/fireworks-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw Fireworks provider plugin",
"type": "module",

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/github-copilot-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw GitHub Copilot provider plugin",
"type": "module",

View File

@@ -1,12 +1,12 @@
{
"name": "@openclaw/gmi-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/gmi-provider",
"version": "2026.6.9"
"version": "2026.6.10"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/gmi-provider",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw GMI Cloud provider plugin.",
"repository": {
"type": "git",
@@ -21,10 +21,10 @@
"minHostVersion": ">=2026.6.8"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9",
"openclawVersion": "2026.6.10",
"bundledDist": false
},
"release": {

View File

@@ -1,18 +1,18 @@
{
"name": "@openclaw/google-meet",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/google-meet",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"commander": "14.0.3",
"typebox": "1.1.39"
},
"peerDependencies": {
"openclaw": ">=2026.6.9"
"openclaw": ">=2026.6.10"
},
"peerDependenciesMeta": {
"openclaw": {

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/google-meet",
"version": "2026.6.9",
"version": "2026.6.10",
"description": "OpenClaw Google Meet participant plugin for joining calls through Chrome or Twilio transports.",
"repository": {
"type": "git",
@@ -16,7 +16,7 @@
"openclaw": "2026.5.28"
},
"peerDependencies": {
"openclaw": ">=2026.6.9"
"openclaw": ">=2026.6.10"
},
"peerDependenciesMeta": {
"openclaw": {
@@ -33,10 +33,10 @@
"minHostVersion": ">=2026.4.20"
},
"compat": {
"pluginApi": ">=2026.6.9"
"pluginApi": ">=2026.6.10"
},
"build": {
"openclawVersion": "2026.6.9"
"openclawVersion": "2026.6.10"
},
"release": {
"publishToClawHub": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/google-plugin",
"version": "2026.6.9",
"version": "2026.6.10",
"private": true,
"description": "OpenClaw Google plugin",
"type": "module",

View File

@@ -1,19 +1,19 @@
{
"name": "@openclaw/googlechat",
"version": "2026.6.9",
"version": "2026.6.10",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@openclaw/googlechat",
"version": "2026.6.9",
"version": "2026.6.10",
"dependencies": {
"gaxios": "7.1.4",
"google-auth-library": "10.6.2",
"zod": "4.4.3"
},
"peerDependencies": {
"openclaw": ">=2026.6.9"
"openclaw": ">=2026.6.10"
},
"peerDependenciesMeta": {
"openclaw": {

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