* feat(config): give shared channel settings help text
* fix(ui): space the settings tiers and stop repeating help on list items
* feat(ui): link each channel detail to its docs page
* test(ui): mirror production channel hints in the mock dev server
* docs: note the shared channel help inheritance for plugin authors
* fix(config): let a channel suppress shared help with an empty string
* chore(config): regenerate bundled channel metadata for the new WhatsApp hints
* fix(ci): check bundled channel metadata locally
* chore(release): keep changelog release-owned
* chore(release): keep changelog release-owned
* fix(ui): keep shared channel help contract-neutral
* feat(agents): add per-run stats to embedded agent run meta
Adds codeModeEngaged, assistantTurns, bridgeCalls, and costUsd to
EmbeddedAgentRunMeta.agentMeta and mirrors them on the agent exec --json
envelope. Code-mode engagement is stamped from the tool-surface truth,
round trips accumulate across attempts beside usage, bridge counts come
from the run's tool-search catalog counters, and cost reuses the shared
model pricing helpers (cache tiers included, omitted without cost data).
* fix(agents): accumulate bridge call counts across run attempts
Attempt cleanup clears the per-attempt tool-search catalog, so retries and
fallbacks discarded earlier bridge counts. Fold each attempt's bridgeCalls
into the run accumulator beside assistantTurns and stamp the cumulative
totals into agentMeta, matching the documented per-run contract.
* refactor(channels): own account status in one closed state machine
* fix(gateway): stop storing derived reasons and configured in channel runtime
* fix(channels): separate linkage from configuration in whatsapp and zalo personal
* fix(cli): render channel state reasons apart from runtime failures
* refactor(channels): keep account-state projection internal to its owner
A user-home app-server keeps its native Codex account, and OpenClaw verified only
half of that contract. A subscription route was checked against the native
account, but a Platform (API-key) route was not: an operator signed in to Codex
with a ChatGPT subscription who selected an API-billed model silently spent their
plan. Both directions of the same billing boundary now share one account/read
check. An absent account is left alone, since a native home may serve a custom
model provider that reports no OpenAI account at all.
The home-scope rule behind #114397 was also expressed four times: two
prepared-auth call sites spread it in conditionally from raw plugin config, two
others read resolved start options, and the supervision connection applied its
own default inline. resolveCodexAppServerHomeScope now owns it, and homeScope is
a required argument of resolveCodexAppServerPreparedAuthHandoff, so a new call
site that forgets it fails to compile instead of failing every turn.
Docs dropped the stale user-home paragraph that still described the startup
failure #114397 removed and told operators to delete a working OpenAI profile.
* feat(plugins): deliver sessions.changed to plugin services
* docs: regenerate docs map
* refactor(clickclack): split reconcile scheduler and history formatting out of the discussion service
* style: format discussion service
* perf(logging): flush file transport asynchronously off the request path
* fix(ci): record flushLogger surface growth and drain before log reads
- +1 public export/callable budget with annotation: logger file-transport
flush for graceful shutdown drains; regenerate SDK API baseline
- three tests that read the log file right after logging now drain the
async file transport first (flushLogger) instead of racing the flusher
* test: drain async log transport before reading talk and request-trace logs
* test: drain async log transport in CLI logger file tests
* test: drop unused withTempDirSync import
* feat(plugins): mirror local coding sessions to a remote Beam receiver
* fix(plugins): satisfy static gates for the Beam mirror seam
* fix(plugins): import the config type from the narrow contracts subpath
* fix(plugins): require catalog consent and loopback-only plaintext for the Beam mirror
* fix(config): compaction.enabled is rejected as invalid config
Setting agents.defaults.compaction.enabled in openclaw.json made the
whole config fail to load with "agents.defaults.compaction: Invalid
input", so auto-compaction could not be turned off.
The runtime already reads the field (SettingsManager.getCompactionEnabled
returns settings.compaction?.enabled ?? true, and setCompactionEnabled
writes it), and the documented config example in
docs/reference/session-management-compaction.md already shows
"enabled: true". Only the zod schema was missing the key, and the
compaction object is .strict(), so the unknown key rejected the config.
Adds enabled to AgentDefaultsSchema and to AgentCompactionConfig.
Closes#110065
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(config): wire compaction enablement through runtime
Align the accepted compaction.enabled contract across runtime precedence, help, labels, docs, and generated schema baselines.
Co-authored-by: Zakaria Rahali <zakariarahali288@gmail.com>
* test(config): preserve omitted compaction setting
Document the reload lifecycle and lock in project-setting precedence when the OpenClaw config key is absent.
Co-authored-by: Zakaria Rahali <zakariarahali288@gmail.com>
* refactor(config): centralize compaction runtime override
* fix(config): preserve compaction safety guards
* fix(scripts): avoid ripgrep in merge fallback
* docs(config): refresh current main baseline
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* refactor(memory-core): remove orphaned shadow trials
* refactor(qqbot): migrate direct voice upload formats
Release note: QQBot configs using voiceDirectUploadFormats now migrate through openclaw doctor --fix to audioFormatPolicy.uploadDirectFormats at root and account scope. Existing nested uploadDirectFormats values win conflicts, and runtime reads only the nested policy.
* refactor(feishu): migrate tools base alias
Release note: Feishu configs using tools.base now migrate through openclaw doctor --fix to tools.bitable at root and account scope. Existing bitable values win conflicts, and runtime accepts only the canonical key.
* refactor(extensions): remove dead runtime state
* chore(config): refresh bundled channel metadata
* refactor(codex): keep realtime fallback type private
* test(ci): align QA compatibility scenario count
* feat(tools): per-model code-mode capability flags and auto master-switch tier
* feat(anthropic): flag claude-sonnet-4-6 as code-mode preferred
* revert(anthropic): drop claude-sonnet-4-6 from the code-mode preferred set
* test(anthropic): type the manifest compat field in the catalog contract test
* fix(anthropic): carry catalog compat onto hand-built forward-compat model rows
* refactor(slack): retire inline interactive directives
Release note: Slack configs using channels.slack.capabilities.interactiveReplies, including per-account settings, are removed by openclaw doctor --fix. Slack-only [[slack_buttons:...]] and [[slack_select:...]] markup is no longer parsed; emit typed presentation buttons and selects instead.
* docs: refresh Slack docs map
* test(ui): make channel settings renderable in the mock dev server
* fix(ui): hide advanced channel settings behind the shared advanced tier
* fix(ui): widen the tier renderer callback to lit's nothing
* fix(ui): keep the advanced collapse control on advanced-only channel forms
* docs: note the shared advanced tier on channel settings
* fix(gateway): reclaim startup migration leases whose owner process is gone
* fix(gateway): name a runnable command in crash-loop breaker suppression messages
* fix(gateway): scope the breaker recovery hint to the suppressed account
Reject recognizable POSIX and Windows shell source before QuickJS execution while preserving valid JavaScript, TypeScript, syntax errors, standard globals, and real hoisted bindings. Add real-worker regression coverage and adversarial cross-platform stress proof. Fixes#113069.
* feat(ui): let a link's slug settle a shared short-id prefix
Two sessions can share the first block of their uuid, which sent an otherwise
exact link to the disambiguation view even though the slug in that link already
said which session was meant. Capture the slug on short references and use it to
break the tie.
It can only narrow: a slug matching none or several of the tied sessions leaves
the chooser alone, and a reference that already resolves uniquely is untouched.
Generated links stay at their normal length instead of growing a full uuid.
* fix(ui): never settle a slug tie from an incomplete search
A truncated candidate set is an unfinished search, not a tie: an unexamined page
could hold the same short-id prefix under the same slug. Settling there would be
the guess the bounded search exists to avoid, so keep the chooser.
* fix(gateway): align configured local credentials
* test(gateway): align local credential coverage
* chore(gateway): leave release note to release process
Fix cross-client terminal history synchronization without letting stale snapshots erase in-flight responses. Bound orphaned stream assembly, preserve session and agent ownership, and cover real Gateway delivery, persistence races, reconnects, and stress bursts.
Closes#38829.
Credits prior issue investigation in #96252 and bounded-stream work in #109492.
Co-authored-by: Harjoth Khara <48686985+harjothkhara@users.noreply.github.com>
Co-authored-by: Wynne668 <290981215+ZengWen-DT@users.noreply.github.com>
The prompt-caching pricing reference in docs/reference/token-use.md linked to
docs.anthropic.com/docs/build-with-claude/prompt-caching. After Anthropic's
docs migration to platform.claude.com, that URL 301-redirects in an infinite
loop (browsers surface ERR_TOO_MANY_REDIRECTS).
Point it at the current canonical page, which returns HTTP 200 and still
documents the cache read/write pricing and 1h/5m TTL multipliers that the
surrounding paragraph references.