Commit Graph

70571 Commits

Author SHA1 Message Date
Peter Steinberger
075030c19e fix(channels): preserve single-account setup labels (#111134)
Fixes #111130
2026-07-18 19:32:31 -07:00
Wynne668
5bb969f7de fix(tlon): preserve shutdown when body cancellation fails (#111106)
* fix(tlon): observe shutdown body cancellation failures

* test(tlon): streamline shutdown cleanup proof

* test(tlon): narrow shutdown fixtures

---------

Co-authored-by: ZengWen-DT <290981215+ZengWen-DT@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 19:32:04 -07:00
Yuval Dinodia
18b79d99ab fix(gateway): bound busy channel health by real run age (#103793)
* fix(gateway): bound busy channel health by real run age

The channel health policy treats a channel as healthy-busy even while
disconnected, bounded only by a 25 minute stale ceiling measured from
lastRunActivityAt. The run-state heartbeat refreshes lastRunActivityAt
every 60 seconds for as long as any run is active, so a run that hangs
forever (for example a send blocking on a dead socket after the
transport already reported connected:false) keeps that timestamp fresh
and the stuck ceiling is never reached. The account is then reported
healthy forever by the health monitor, readiness probe, and health CLI,
and no restart ever fires.

createRunStateMachine now tracks each in-flight run's start time keyed by
an opaque run handle and publishes the oldest still-active run's start as
activeRunStartedAt. The health policy busy override keys its ceiling off
the real run age, so a run stuck longer than the threshold reports stuck
and the monitor can restart it. Because the reported start is the oldest
active run and advances to the next-oldest as runs complete, a channel
churning through many short overlapping runs (activeRuns above 1 across
concurrent queue keys) stays healthy; only a genuinely hung run breaches
the ceiling. Short and active runs stay healthy and the existing
lastRunActivityAt fallback is preserved for snapshots without a start
time.

* fix(channels): retain run-state callback compatibility

Keep the released zero-argument onRunEnd callback source-compatible while allowing internal queue callers to pass a run handle for exact concurrent-run accounting. The compatibility path closes the oldest active run, preserving existing lifecycle behavior for consumers that do not use handles.

* fix(channels): keep anonymous runs out of age tracking

The zero-argument lifecycle callbacks cannot identify which concurrent run completed, so they must not update the identity-sensitive run start used by channel health. Keep their busy count separately and reserve exact start tracking for the shared queue's handle-aware lifecycle path.

* fix(channels): keep tracked runs internal

Keep the public run-state lifecycle callbacks unchanged. The channel queue now owns opaque run identity and augments its status updates with the oldest active queue run, so implementation details do not expand the SDK surface.

* fix(channels): type queue run start status

Keep activeRunStartedAt in the internal status patch type so the queue can publish its private tracked-run age through the existing status sink.

* fix(channels): wrap isActive to satisfy unbound-method lint

* fix(gateway): gate busy run-age ceiling on disconnected transport
2026-07-18 20:26:17 -06:00
Jason (Json)
7d62a277ff fix(ui): teardown MCP Apps before unmount (#111124)
* fix(ui): teardown MCP Apps before unmount

* fix(ui): keep MCP teardown helpers internal
2026-07-18 20:25:46 -06:00
Peter Steinberger
68771ebdfe feat(cron): script payloads behind the trigger gate (#111112)
Run script payloads through the shared headless code-mode executor with payload-grade budgets and success-only trigger.state persistence.

Reuse cron delivery, wake, pacing, and dangerous trigger-gate contracts for notify, wake, and nextCheck results.
2026-07-18 19:24:12 -07:00
Yuval Dinodia
80746b06b9 fix(sessions): commit reduced session index before deleting evicted transcripts (#108378)
* fix(sessions): commit reduced session index before deleting evicted transcripts

The file-backed session store disk-budget sweep evicted an old session by
removing its in-memory entry and immediately, permanently deleting its
transcript artifact, and only afterwards did the caller serialize and
atomically replace sessions.json. A crash, power loss, or store-write failure
in that window left durable metadata in sessions.json pointing at transcripts
that were already gone, an irreversible loss of evicted session history during
the low-disk maintenance when failures are most likely.

enforceSessionDiskBudget now plans the evicted entries' owned artifact
deletions during the sweep (accounting their freed bytes so the stop condition
is unchanged) and defers the physical unlink until after an injected
commitEvictedIndex callback atomically persists the reduced index. saveSessionStore
supplies that callback. A crash after the commit leaves only reclaimable orphan
files; a crash before it retains the transcript.

* fix(sessions): retain evicted artifacts without commit boundary

* fix(sessions): fsync reduced index before eviction
2026-07-18 20:22:45 -06:00
Yuval Dinodia
6ff963eb46 fix(transcripts): imported text can inject terminal escapes through transcripts show (#110060)
* fix(transcripts): imported text can inject terminal escapes through transcripts show

Imported transcript text, speaker labels, and session titles were rendered
into summary.md unsanitized, and openclaw transcripts show writes that file
directly to stdout, so a transcript could clear the terminal or spoof
colored status text. Sanitize external strings with the terminal-core
sanitizer when the summary is built, so summary.json, summary.md, and the
CLI output stay free of control bytes while transcript.jsonl keeps the raw
capture.

* fix(transcripts): protect terminal output boundaries

* fix(transcripts): keep canonical session identity separate from terminal presentation

* fix(transcripts): escape C1 control characters in transcripts json output
2026-07-18 20:20:13 -06:00
sunlit-deng
4dbeb84c25 fix(tlon): account checks leave streaming responses open (#111081)
* fix(tlon): release account probe response bodies

* test(tlon): assert probe cleanup ordering

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 19:18:30 -07:00
xingzhou
69aeba9d86 fix(discord): sustained gateway bursts stop growing memory (#110954)
* fix(discord): sustained gateway bursts stop growing memory

* fix(discord): contain gateway queue overflow

* fix(discord): drop oldest saturated gateway sends

Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>

* fix(discord): surface gateway overflow warnings

Co-authored-by: 张贵萍0668001030 <zhang.guiping@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 19:14:16 -07:00
Wynne668
ead8f691ea fix(matrix): preserve redirects when body cancellation fails (#111105)
* fix(matrix): observe redirect body cancellation failures

* test(matrix): verify rejection listener cleanup

---------

Co-authored-by: ZengWen-DT <290981215+ZengWen-DT@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 19:06:46 -07:00
tiffanychum
feb6da25f5 fix(googlechat): keep accounts.default streaming when doctor migrates named accounts (#106018)
* fix(googlechat): keep accounts.default streaming when doctor migrates named accounts

* fix(googlechat): canonicalize migrated streaming

Replace the layered doctor migration with canonical root/default/account materialization and prove runtime resolution matches the stored config.\n\nCo-authored-by: tiffanychum <71036662+tiffanychum@users.noreply.github.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 19:05:57 -07:00
Peter Steinberger
ced95b3fce refactor(discord): split message process runtime (#111119) 2026-07-18 19:04:30 -07:00
Jason (Json)
047232bd16 fix(telegram): fall back for web apps outside DMs (#111116) 2026-07-18 19:52:19 -06:00
Peter Steinberger
0a8c485395 fix(browser): make copilot runtime bundle deterministic (#111109) 2026-07-18 18:49:38 -07:00
wahaha1223
ecc56749e1 fix(anthropic): guard invalid timestamps in history imports (#110536)
* fix(anthropic): guard invalid timestamps in history imports

* fix(anthropic): reject pre-epoch history timestamps

* fix(anthropic): preserve valid transcript dates

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 18:45:10 -07:00
Peter Steinberger
7e1aca92b4 fix(acp): exit help and EOF cleanly (#111091) 2026-07-18 18:41:09 -07:00
Marcus Castro
f2137f41b8 fix(whatsapp): serialize source runtime loading (#111094) 2026-07-18 22:40:19 -03:00
Peter Steinberger
b51e3d02c7 docs(meetings): mention Discord voice channels 2026-07-19 02:35:21 +01:00
Eden
2e16660f18 fix(line): retry inbound media through the ingress drain on transient download failure (#110921)
* fix(line): retry inbound media through the ingress drain on transient download failure

* fix(line): retry all transient inbound media failures

Co-authored-by: 許元豪 <146086744+edenfunf@users.noreply.github.com>

* style(line): format media retry test

* test(line): use scanner-safe quote token

* fix(line): narrow durable media retries

* fix(line): preserve status after body cleanup

* chore(changelog): avoid concurrent entry conflict

* style(line): format retry helper signature

* test(line): assert rejected media chunk

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 18:26:33 -07:00
Peter Steinberger
53a79a3af1 refactor(agents): unify Responses tool-call id resolver (#111103) 2026-07-18 18:23:41 -07:00
Peter Steinberger
f8f68d1645 fix(android): move device identity key into encrypted storage (#110939)
* fix(android): move device identity key into encrypted storage

Migrates the plaintext openclaw/identity/device.json Ed25519 signing key
into EncryptedSharedPreferences with a verified one-time import (synchronous
write, readback check, then plaintext delete) and no fallback reader.
Persistence failures now fail closed instead of silently continuing.
Documents why the cleartext NSC base-config must stay: NSC domain rules
cannot express user-selected RFC1918 gateway endpoints and OkHttp enforces
the policy, so GatewayHostSecurity remains the cleartext gate.

* fix(android): suppress UseKtx on synchronous identity commit

KTX edit(commit = true) discards commit's Boolean; the identity migration
fails closed on that result.
2026-07-18 18:23:27 -07:00
Ted Li
50e81ce493 fix(diagnostics-otel): classify model calls as client spans (#104211)
Model-call spans wrap outbound provider inference requests, so classify them as CLIENT independently of the optional GenAI naming convention. Generic tool spans remain unchanged because their shared events can represent local work.

Release note: operators filtering dashboards or alerts on span kind will see model-call spans move from INTERNAL to CLIENT.

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 18:21:45 -07:00
mushuiyu886
c3adaa3195 fix(nostr): report relay connections only after they succeed (#110878)
* fix(nostr): report relay connections only after they succeed

* test(nostr): exercise relay callback during subscription

* test(nostr): reuse resolved account fixture

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 18:18:39 -07:00
Peter Steinberger
09dd616782 docs(meetings): add platform comparison guide 2026-07-19 02:17:43 +01:00
Peter Steinberger
968f9ad0f3 test(codex): split event projector suites (#111097) 2026-07-18 18:17:25 -07:00
Peter Steinberger
756a491a51 fix(speech): strip markdown before TTS and route code-heavy replies sensibly (#110948)
The talk.speak synthesis path passed raw agent text to providers, so talk
mode could read fenced code, links, and tables aloud. Speech normalization
now happens once at the shared synthesis boundary (speech-mode stripMarkdown:
label-only links, decorative bullet/glyph cleanup, punctuation collapsing).
Code-heavy replies (>=50% fenced content, CommonMark-aware scanner incl.
blockquote/list containers and unclosed fences) get routed by surface:
talk.speak speaks a short on-screen fallback line, channel auto-TTS skips
the voice note since the visible text already carries the content, and
explicit conversions (tts.convert, tagged hidden TTS, chat Listen) always
speak stripped best-effort content.
2026-07-18 18:16:43 -07:00
Peter Steinberger
b96d5cf554 fix(qa): resume channel cursor after gateway restart (#111096) 2026-07-18 18:16:14 -07:00
Peter Steinberger
03c3c4b978 fix(browser): keep copilot runtime bundle in sync (#111089) 2026-07-18 18:15:21 -07:00
Yuval Dinodia
c17a81b470 fix(plugins): roll back cleared runtime registrations when an activating reload aborts (#103812)
* fix(plugins): roll back cleared runtime registrations when an activating reload aborts

loadOpenClawPlugins clears the process-global agent-harness, plugin-command,
compaction, detached-task, interactive-handler, embedding, memory-embedding,
and memory stores up front on an activating load and only re-registers them at
the end via activatePluginRegistry. The body has a finally with no catch, so a
throw during discovery or manifest load (a corrupted or half-written plugin
manifest mid-upgrade) leaves the previously active registry marked active while
its runtime stores are gone process-wide; the gateway reload driver only logs
and swallows the error.

Snapshot the process-global stores before the clear with the existing
snapshotPluginProcessGlobalState helper and restore them on any throw before
activation. clearActivatedPluginRuntimeState moves next to the snapshot and
restore helpers it pairs with in plugin-registration-transaction.ts, which
already owns atomic plugin registration state and imports from every module the
clear touches; loader.ts re-exports it so existing callers are unchanged.

* fix(plugins): make reload rollback activation-safe

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 18:11:16 -07:00
Peter Steinberger
d96a87e8e9 docs: document session automation contracts (#111095) 2026-07-18 18:10:14 -07:00
Christian De Santis
276785ae6d fix: distinct Responses tool-call ids for repeated native Kimi calls (#110956)
* fix: distinct Responses tool-call ids for repeated native Kimi calls

The gateway tool (and any tool reused at the same call index) collapsed to
the same call_* id in OpenAI Responses replay because the id normalizer
hashed only the callId half of paired functions.<tool>:<index>|fc_tmp_*
ids, dropping the unique suffix. That broke replay with
invalid_replay_transcript: dangling_tool_call once a session called the
same tool at the same index more than once. Hash the full pairing instead.

* fix: resolve no-shadow lint error in openai.test.ts helper params

* test(agents): cover repeated Responses tool calls

* test(agents): type-check Responses id assertions

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 18:05:20 -07:00
Peter Steinberger
62c5a8b888 fix(gateway): make scope errors machine-readable across clients (#111013)
* fix(gateway): consume structured scope errors

* docs(gateway): clarify tools error boundary

* refactor(gateway): unify node admin policy
2026-07-18 17:53:45 -07:00
Peter Steinberger
593ac4ae0c feat(apps): rewind and fork a session from native chat bubbles (#110886)
* feat(apps): rewind and fork a session from native chat bubbles

* docs(apps): note lease-parity contract on message fork dispatch

* fix(apps): native i18n inventory sync and doc-comment style for bubble actions

* fix(apps): translate native bubble action strings across locales

* fix(apps): refresh generated iOS localization catalog after rebase
2026-07-18 17:52:03 -07:00
Peter Steinberger
47afe8f88f refactor(discord): split message process tests (#111066)
* refactor(discord): split message process tests

* test(discord): register split suite lifecycle

* test(discord): keep process harness internals private
2026-07-18 17:49:19 -07:00
qingminlong
fc30a6c67d fix(oc-path): reject oversized multibyte JSONC input (#104140)
* fix(oc-path): enforce JSONC byte limit for multibyte input

* fix(oc-path): surface JSONC size diagnostics in CLI

* fix(oc-path): classify oversized JSONC as parse error

* test(oc-path): cover JSONC byte cap boundaries

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 17:47:15 -07:00
Peter Steinberger
aad27e2629 test(worktrees): honor host umask in mode assertions (#111075) 2026-07-18 17:44:39 -07:00
Peter Steinberger
6c2973dee4 feat(ui): automatic session attention states in the sidebar (#111035)
* feat(ui): automatic session attention states in the sidebar (question, approval, failed run)

* test(ui): split attention presentation and read-marker cases under line budgets

* fix(ui): restore precise chat-pane test-support signatures
2026-07-18 17:43:59 -07:00
Yuval Dinodia
0a588fa795 fix(acp): /acp sessions exposes every gateway session to non-owner senders (#110745)
* fix(acp): scope /acp sessions listing for non-owner senders

/acp sessions listed every ACP session on the gateway for any sender
allowlisted via commands.allowFrom, exposing other senders' session
labels, agent ids, runtime state, and thread bindings. The handler now
returns only the current bound or requester session for non-owner
senders, while owner identity and operator.admin clients keep the full
gateway-wide listing, matching the documented contract.

Fixes #103055

* test(acp): cover empty and missing-session cases for /acp sessions scoping

* fix(acp): avoid non-owner session scans

* docs(acp): remove duplicated session scope text

* test(acp): cover internal session visibility

* fix(acp): require current ACP metadata

* test(acp): reject sessions target tokens

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 18:38:48 -06:00
Peter Steinberger
c745e7d66c fix(gateway): reject unsafe explicit approval IDs (#111055)
* fix(gateway): validate explicit approval ids

* fix(gateway): reject trailing approval controls

* test(gateway): cover embedded approval controls

* fix(gateway): reject empty explicit approval ids

* test(gateway): align approval projections with safe ids

* style(gateway): format approval id validation

* fix(gateway): reject approval url dot segments
2026-07-18 17:38:21 -07:00
Peter Steinberger
20677baf76 feat(android): copy or save rendered widgets as images from the chat transcript (#111030)
* feat(android): copy or save rendered widgets as images from the chat transcript

* chore(i18n): sync native app i18n inventory for widget export strings

* chore(i18n): regenerate native locale artifacts for widget export strings
2026-07-18 17:31:30 -07:00
Peter Steinberger
ec740e79a4 fix(agents): honor Anthropic retry-after cooldowns (#111072) 2026-07-18 17:28:04 -07:00
mushuiyu886
7abcd6c691 fix(skills): distinguish duplicate ClawHub search results by publisher (#110903)
* fix(skills): distinguish duplicate search results by publisher

* test(skills): cover owner-qualified search output

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 17:27:25 -07:00
Peter Steinberger
fdf44edf4d docs: document channel ingress guarantees (#111069) 2026-07-18 17:26:41 -07:00
Peter Steinberger
dcffb3f66f fix(ui): restore Control UI E2E coverage (#111036)
* fix(ui): restore control ui e2e coverage

* test(ui): align e2e coverage with thread labels

* test(ui): wait for fake talk channel readiness

* chore: keep release note in PR body
2026-07-18 17:26:26 -07:00
Peter Steinberger
e3ae52b792 feat(ui): microphone picker on the composer talk button (#111043)
* feat(ui): add composer microphone picker

* fix(ui): single check indicator in mic picker, matching house radio-menu pattern

* fix(ui): keep System default focusable during mic discovery; update composer contract test for picker caret
2026-07-18 17:25:55 -07:00
shaoohh
e669e97194 fix(acp): persist confirmed output from cancelled turns (#110300)
* fix(acp): persist cancelled partial replies

* fix(acp): persist delivered output for cancelled turns

Normalize terminal status at the ACP manager boundary and settle routed/direct delivery outcomes before persisting cancelled bound turns.

Co-authored-by: shaoohh <150606856+shaoohh@users.noreply.github.com>

* fix(acp): require confirmed cancelled-turn delivery

Persist cancelled-turn output only when the core dispatcher reports successful delivery. Keep canonical ACP history independent of outbound-only hook rewrites and prove backend cancellation with the real dispatcher.

Co-authored-by: shaoohh <150606856+shaoohh@users.noreply.github.com>

* test(acp): satisfy cancellation proof lint

Keep the pending-delivery race assertion behavior while avoiding a return value from the Promise executor.

Co-authored-by: shaoohh <150606856+shaoohh@users.noreply.github.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 17:24:42 -07:00
Peter Steinberger
45f6543c9a feat(macos): Quick Chat power features — voice dictation, paste-to-app, model/reasoning control (#110994)
* feat(macos): add Quick Chat power features

* docs(macos): document Quick Chat power features

* chore(i18n): refresh native locale artifacts for Quick Chat power features

* fix(macos): update DEBUG test helper sendProvider to the reasoning-threaded arity
2026-07-18 17:21:03 -07:00
Kris Wu
e5b2ca3c6b feat(config): add compaction.thinkingLevel to override thinking level during compaction (#98074)
* feat(config): add compaction.thinkingLevel to override thinking during compaction

* fix: make compaction.thinkingLevel override inherited session thinking

* fix: warn on compaction.thinkingLevel ignored by Codex native runtime

* feat(config): add compaction thinking override

Co-authored-by: wu.duozhen@xydigit.com <wu.duozhen@xydigit.com>

* test(agents): remove duplicate compaction harness

Co-authored-by: wu.duozhen@xydigit.com <wu.duozhen@xydigit.com>

* test(plugin-sdk): account for thinking level export

Co-authored-by: wu.duozhen@xydigit.com <wu.duozhen@xydigit.com>

* chore: keep release note in PR metadata

* chore: reconcile plugin SDK surface budgets

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 17:18:28 -07:00
mushuiyu886
9fe92cf5ce fix(nostr): profile imports no longer crash on invalid fields (#110684)
* fix(nostr): profile imports no longer crash on invalid fields

* test(nostr): define invalid profile import policy

* test(nostr): cover invalid imported URL types

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 17:18:23 -07:00
Peter Steinberger
b4187ced90 feat: add live-validated Zoom meeting guest plugin (#111048)
* feat(zoom-meetings): add browser guest transport

* fix(zoom-meetings): type reusable refresh result

* test(meeting-bot): bind reusable refresh callback

* chore(zoom-meetings): use existing plugin label

* chore(zoom-meetings): defer changelog to release

* test(zoom-meetings): cover node setup through public host
2026-07-18 17:17:26 -07:00