Commit Graph

41063 Commits

Author SHA1 Message Date
Ayaan Zaidi
c63241d3ce fix(channels): resolve tool progress against the caller's stream mode
resolveChannelStreamingPreviewToolProgress guessed a mode when streaming.mode
was unset, so it could never be right for every channel: guessing "partial"
dropped Discord and Telegram's explicit progress.toolProgress opt-out, and my
earlier switch to "progress" broke it the other way for Slack, Mattermost, and
Teams, whose real default is partial. With both keys configured and disagreeing,
the wrong one won.

The helper has no channel identity, so it stops guessing and takes the mode the
caller already resolved. All nine call sites pass theirs. Omitting it keeps the
previous configured-mode reading, so untouched callers behave exactly as before.

Reported by ClawSweeper on #116143.
2026-07-30 13:36:21 +09:00
Ayaan Zaidi
c6633aead5 refactor(channels): render the progress label as a block, not a line
The label was smuggled into the rolling line array as a `{draftLabel}`
sentinel so it would participate in the maxLines window, then special-cased
in three places plus an index lookup to pull it back out for its own block.

A label is not a line; it is a block that yields its slot once real work
fills the window. Saying that directly removes the sentinel, every
`isLabelLine` check, and the double map over the line list, while keeping the
documented scroll-away behavior and the plan/tool budget split.

Adds the missing boundary test for a checklist that consumes the whole line
budget: `slice(-0)` returns every element, so that case needs the explicit
empty-window branch rather than falling out of the arithmetic.
2026-07-30 13:36:21 +09:00
Ayaan Zaidi
06aa81a73f fix(channels): show tool lines under the progress status headline
A status headline replaced the rolling tool lines instead of sitting above
them, so a default Discord draft showed one preamble sentence for an entire
tool-heavy turn. Operators reached for `/verbose` to see any activity, which
delivers durable per-tool-call messages and floods the channel.

- Render the headline above the lines; both stay visible in one message.
- Shorten the start gate from 5s to 1.5s. The gate only creates the draft
  when the timer fires and finalize cancels it, so quick answers still post
  no draft while a 3s tool turn stops being silent.
- Drop Discord's label-gated tool-progress default so
  resolveChannelStreamingPreviewToolProgress is the single owner. An explicit
  `toolProgress: false` still silences the lines.
- Resolve that toggle against a "progress" mode guess when `streaming.mode`
  is unset, so the progress-draft channels stop ignoring an explicit
  `progress.toolProgress` opt-out.

Telegram now defaults to `streaming.mode: "progress"` like Discord; set
`"partial"` to keep streamed answer text. Its renderer draws work lines from
the compositor's structured lines, so `rendersRollingLinesNatively` keeps
them out of the composed text rather than printing every line twice.
2026-07-30 13:36:21 +09:00
harish ganeshmurthy
5496cff965 feat(cron): include run time in failure alerts (#80246)
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: haishmg <4529977+haishmg@users.noreply.github.com>
2026-07-30 12:25:10 +08:00
Vincent Koc
b2136fa234 fix(test): serialize transcript mirror dirty-state setup (#116207) 2026-07-30 12:12:55 +08:00
Eden
9c6e06b557 fix(auto-reply): deliver ingress-retried messages after their queued run is dropped (#115891)
* fix(auto-reply): deliver ingress-retried messages after their queued run is dropped

* fix(auto-reply): key queued dedupe release by adoption lifecycle

Overflow-summary compaction clones a queued run onto a new object, so a
release keyed by the run object missed runs completed via their clone and
the ingress retry stayed suppressed on the summarize drop policy. The
adoption lifecycle reference survives cloning and already keys admission
state, so it is the identity the release must use.

* fix(auto-reply): guard queued dedupe ownership

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 11:19:01 +08:00
wangmiao0668000666
b942db4d56 fix(agents): throw CompactionError when summarization fails (#115500)
* fix(agents): throw CompactionError when summarization fails

Transform compaction summarization from silent infinite failure loops
into clear, actionable errors.

Previously, when all summarization attempts failed, summarizeWithFallbackResult
returned a generic fallback string blaming "size limits". This caused:
- Misleading error messages (auth/network errors reported as "size limits")
- Callers unable to distinguish real summaries from failures
- Silent infinite retry loops where token counts climbed indefinitely

Now, CompactionError is thrown with the original error details preserved.
Callers immediately know compaction failed and can take appropriate action
(switch model, notify user, etc.).

Fixes #115413

Co-Authored-By: nebulacoder-v8.0 <noreply@zte.com.cn>

* fixup: export CompactionError from agent-core index, remove dead code

* fixup: address ClawSweeper review - keep CompactionError internal, track last error, add failure-proof test

* fixup: type corrections in failure-proof test

* fixup: type annotate failure-proof messages as UserMessage[]

* fixup: avoid possibly-undefined array access in failure-proof test

* test(agents): prove compaction provider failure cancellation

---------

Co-authored-by: nebulacoder-v8.0 <noreply@zte.com.cn>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 10:28:01 +08:00
Vincent Koc
3016666e5c fix(test): isolate ACP startup output stream (#116076) 2026-07-30 10:27:19 +08:00
Yuval Dinodia
cee6203f44 fix(agents): deny all tools when scheduled authority names a removed account (#115932)
* fix(agents): deny all tools when scheduled authority names a removed account

resolveGroupToolPolicy returned { allow: [] } as its fail-closed sentinel
when a scheduled run named a channel account that is no longer configured.
The runtime matcher treats an empty allowlist as "allow everything not
denied", so revoking the creator account widened the scheduled tool surface
to the full set including exec and apply_patch instead of denying it.

The sentinel now carries an explicit wildcard deny, which the matcher and
the plugin-harness native-tool clamp both honor.

* test(agents): cover scheduled-run tool denial after owner account removal

Adds capability-profile level coverage that a scheduled run whose named
owner account was removed resolves to a deny-all group policy, exercising
the scheduled-authority handoff from resolveConversationCapabilityProfile
through resolveRequesterToolPolicies into resolveGroupToolPolicy.

* fix(gateway): enforce scheduled account authority for loopback tools

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 10:24:53 +08:00
Riive
82af1bf7d4 fix(cron): stop replaying old schedule slots after a cron job is edited (#115779)
* fix(cron): bound restart catch-up to the active schedule

Editing a recurring job's schedule made the gateway fire it immediately on
the next restart. Startup catch-up compares the new schedule's previous slot
against lastRunAtMs, which still belongs to the retired schedule, so a slot
that never existed under the old schedule counted as missed.

Record when scheduling inputs take effect and replay a missed slot only when
it is newer than that. Jobs whose schedule never changed carry no stamp and
keep replaying every computed slot, so catch-up is unchanged for them.

The missed-slot predicate was duplicated in the runnable check and the
backoff-deferral pass; both now share one helper so the bound cannot drift.

Fixes #91944

* fix(cron): protect schedule activation ownership

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 10:07:13 +08:00
Vincent Koc
d5e3c68632 fix(daemon): block conflicting systemd gateway owners (#116162) 2026-07-30 09:53:38 +08:00
Vincent Koc
51f9f061f0 docs(config): clarify user timezone contract (#116160) 2026-07-30 09:49:18 +08:00
Vincent Koc
12e5eb6a23 fix(ui): clarify model setup flows (#116086) 2026-07-30 09:47:57 +08:00
joshavant
21db50efc7 refactor(whatsapp): keep inbound boundary transport-private 2026-07-29 20:34:55 -05:00
Vincent Koc
f970e5093b refactor(channels): add portable inbound boundary 2026-07-29 20:34:55 -05:00
Vincent Koc
f4969c33d9 fix(sessions): migrate legacy transcripts during SQLite import (#116077) 2026-07-30 09:28:47 +08:00
xin zhuang
2e1bf01f51 fix(config): allow explicit main agent bindings when agents.list is non-empty (#89419)
* fix(config): preserve explicit main route bindings

* fix(config): preserve configured main-like agent bindings

* test(routing): cover implicit main roster precedence

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 09:15:44 +08:00
Vincent Koc
3f918d4b3c fix(hooks): honor user timezone in session memory (#116136) 2026-07-30 09:04:52 +08:00
Yuval Dinodia
8ce1e18d2f fix(agents): apply_patch rewrites bytes on hunk context lines (#116128)
* fix(agents): apply_patch rewrites bytes on hunk context lines

A fuzzy apply_patch update replaced the entire matched span with the
model-authored patch text, so trailing whitespace, typographic punctuation,
and tab indentation on lines the hunk marked as context were overwritten
while the tool reported plain success.

The parser now records which emitted lines came in as context and which old
line each one came from, and the update applier keeps the file's own bytes
for those lines. Added and removed lines are still written from the patch.

* test(agents): cover apply_patch context preservation

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 09:04:04 +08:00
Wynne668
77ec4c5420 fix(config): reject invalid heartbeat activeHours without cadence (#102319)
* fix(config): validate heartbeat activeHours without cadence

* fix(config): repair invalid heartbeat active hours

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 08:54:36 +08:00
Ayaan Zaidi
06a5b974ad fix(proxy): keep the capture header predicate module-private
Only the shared redaction helper needs to be public; the name predicate is
an implementation detail and an unused export trips the dependency check.
2026-07-30 09:48:33 +09:00
Ayaan Zaidi
879894a5bd fix(proxy): redact sensitive headers in standalone debug proxy captures
The standalone debug proxy wrote raw request and response headers into
capture rows while the patched-fetch runtime redacted at the parallel
call sites, so a capture taken through the proxy could persist
Authorization, Cookie, and API-key values to disk.

Move the runtime's redaction policy into a leaf module both writers
import instead of adding a second copy, so the two capture paths cannot
drift. The shared helper also flattens node's array-valued headers,
which the standalone proxy passes in directly, and keeps value-level
registered-secret redaction for header names that are not themselves
sensitive.

Reported by SebTardif in #90009; supersedes #82951, which redacted only
by header name and predates the proxy-server rewrite.
2026-07-30 09:48:33 +09:00
Josh Boys
edbb1fca86 fix(doctor): fail closed on unknown channel schema (#116025)
doctor --fix copies allowFrom into groupAllowFrom for any channel
whose capabilities allow the fallback, guarded by a check against
the compile-time generated channel schema metadata. That metadata
only covers core-compiled channels; extension-installed channels
like agentmail have no entry there. The guard treated a missing
schema as "no restriction" and wrote groupAllowFrom anyway, which
agentmail's own runtime schema then rejected, aborting the whole
doctor --fix batch (including unrelated pending migrations).

Fail closed instead: without schema info, don't write the field.

Fixes #116024
2026-07-30 08:43:07 +08:00
Vincent Koc
e473598c2c fix(ui): make model setup actionable before selection (#116079) 2026-07-30 08:34:43 +08:00
Vincent Koc
156d2e623e refactor(channels): own account config mutations (#115970) 2026-07-30 08:20:41 +08:00
Jason (Json)
9991f49ebb fix(discord): keep activity receipts in adopted threads (#116119)
* fix(discord): keep active thread replies together

* fix(discord): preserve adopted thread progress receipts

* test(discord): prove adopted thread reply matching

* fix(discord): preserve receipt on draft finalization failure
2026-07-29 18:08:18 -06:00
metaforismo
3cda5ad32f perf(gateway): cache lazy server methods import (#116060)
* perf(gateway): cache lazy server methods import

* refactor(gateway): use shared lazy runtime loader
2026-07-29 17:07:29 -07:00
Peter Steinberger
a19132e7eb fix(codex): prevent approval promotion from blocking unattended runs (#116117)
* fix(codex): honor hook approval ownership

* fix(codex): keep permission grants human-gated
2026-07-29 17:00:16 -07:00
Ayaan Zaidi
d8074d7ca2 fix(daemon): require system-scope ownership before removing the user unit
Doctor's dueling-scope repair removed the user-scope gateway unit on file
presence alone. A system unit file that is merely staged, disabled, failed, or
uncheckable would then cost the operator their only working gateway, and the
default confirm value is true so non-interactive repair amplifies it.

Gate the removal on isSystemUnitActiveOrEnabled: the system unit must be the
live or boot-configured supervisor. Otherwise doctor explains the ambiguity and
prints both fix directions instead of deleting anything. An erroring probe
fails closed for the same reason.

Applies the ClawSweeper rank-up move on #91221.
2026-07-30 08:52:05 +09:00
北京刻熵科技有限责任公司
dcfd6a535d fix(daemon): only treat same-canonical-name user+system units as dueling
Address review: a marker-owned system unit with a *different* name (e.g. an
intentional rescue-bot gateway on the same host) must not be classified as a
duplicate of the canonical user unit, or doctor could remove a legitimate user
gateway. Dueling now requires user.unitName === system.unitName; the direct
canonical system path still matches the real #79375 case. Adds a regression
test for "user canonical + custom marker-owned system" -> kind:"user".
2026-07-30 08:52:05 +09:00
北京刻熵科技有限责任公司
9308557f72 fix(daemon): detect and resolve dueling user+system systemd gateway units
After upgrading on Linux, a user-scope unit
(~/.config/systemd/user/openclaw-gateway.service) and a system-scope unit
(/etc/systemd/system/openclaw-gateway.service) can both exist and both try to
manage the gateway. They bind the same port and each instance's stale-process
detection SIGTERMs the other, producing an endless restart cascade (#79375).

The detector `findInstalledSystemdGatewayScope` checked the user path first and
returned early, so it could never surface that both scopes coexist.

This adds, in three layers:

1. Detection: `findSystemdGatewayInstallation` — a discriminated union
   (none/user/system/dueling) that reports every installed scope without
   early-returning. `findInstalledSystemdGatewayScope` is refactored to delegate
   to it while preserving the exact user-first preference its four lifecycle
   callers rely on (no behavior change for stop/restart/is-enabled/runtime).
   Adds `uninstallUserSystemdGatewayUnit` (removes only the $HOME user unit, no
   root needed) and the pure `formatDuelingScopesWarning` helper.

2. Doctor: `maybeResolveDuelingSystemdGatewayScopes` detects the dueling state
   and, after the existing confirm/policy gate, removes the redundant user-scope
   unit while keeping the root-installed system unit authoritative. Declining or
   an externally-managed policy falls back to the existing cleanup hints.

3. Startup guard: in service mode, when a stale-kill actually happened, log a
   targeted remediation pointing at `openclaw doctor --fix` instead of letting
   the loop look like routine stale cleanup. Diagnostic only — the kill decision
   is unchanged.
2026-07-30 08:52:05 +09:00
SunnyShu0925
b96ada0680 test: add stalled provider response body timeout coverage 2026-07-30 08:48:52 +09:00
SunnyShu0925
45b34a6dca fix(infra): bound stalled provider JSON/text/error-body reads with default chunk timeout 2026-07-30 08:48:52 +09:00
Vincent Koc
342826b904 test(gateway): cover hook account replay scope (#116121) 2026-07-30 07:23:51 +08:00
Vincent Koc
1f56e2da21 fix(messages): validate configured envelope timezone (#116103)
* fix(messages): validate configured envelope timezone

* fix(messages): preserve UTC envelope rendering

* fix(messages): preserve local fallback mode
2026-07-30 07:18:13 +08:00
Vincent Koc
9e041cd386 fix(hooks): preserve multi-account agent delivery (#116095)
* fix(hooks): preserve account routing for agent delivery

Refs #43866

Co-authored-by: Paul Desmond Parker <paul.parker@dcconnect.cn>

* test(gateway): prove hook account delivery handoff

---------

Co-authored-by: Paul Desmond Parker <paul.parker@dcconnect.cn>
2026-07-30 07:10:21 +08:00
Peter Steinberger
23e151a016 fix(config): reject reserved __proto__ MCP server name (#116112) 2026-07-29 16:09:26 -07:00
Sergio Cadavid
42e21ad13b fix(plugins): keep run context available after registration (#107028) 2026-07-30 07:07:33 +08:00
Vincent Koc
8530edb057 fix(plugins): deliver subagent completion to current requester (#116091)
* fix(plugins): deliver subagent completion to requester

Co-authored-by: ambitioncn <36698505+ambitioncn@users.noreply.github.com>

* test(qa): register current-requester plugin fixture

* fix(plugins): scope requester authority per hook

---------

Co-authored-by: ambitioncn <36698505+ambitioncn@users.noreply.github.com>
2026-07-30 07:06:17 +08:00
Vincent Koc
fc95d7190c fix(hooks): route mapped wake events to configured sessions (#116109)
Fixes #64556
2026-07-30 06:56:19 +08:00
Ayaan Zaidi
daaaef95f0 fix(gateway): cap channels stuck in pending restart
The health monitor lets a pending-restart continuation skip the cooldown so a
timed-out recovery stop can finish on the next pass. That continuation was
never recorded, so an account stuck in restartPending with reconnectAttempts 0
restarted on every check forever, bypassing maxRestartsPerHour entirely: stop
and start thrash the channel manager with log spam and no give-up state.

Only the first continuation per pending episode is now free. Later passes
rejoin cooldown and the hourly budget, and the free pass re-arms only after
the account genuinely leaves restartPending (running again or the pending flag
dropped) so a transient reconnectAttempts bump cannot mint new free restarts.
2026-07-30 07:53:14 +09:00
Peter Steinberger
695391b3ce fix(gateway): evict idle agent terminal sessions under pool pressure (#116101)
* fix(gateway): evict idle agent terminal sessions under pool pressure

* fix(gateway): claim eviction victims and kill only after replacement spawn

* fix(gateway): revalidate eviction victims after the replacement spawn

* fix(gateway): count in-flight reservations when committing eviction

* fix(gateway): reselect eviction victim at commit time

* fix(gateway): release eviction claims on cancelled opens
2026-07-29 15:31:44 -07:00
Vincent Koc
925fdb023e refactor(ui): remove retired time format bootstrap (#116097) 2026-07-29 22:23:27 +00:00
Vincent Koc
43945b836a fix(hooks): retain manual reset memory admission (#116094)
Refs #113396
2026-07-30 06:22:31 +08:00
Vincent Koc
54e273e695 fix(agents): keep date reasoning current in long-running sessions (#116090)
* fix(agents): ground date reasoning below cache boundary

Co-authored-by: Deepak Jain <406777+deepujain@users.noreply.github.com>

* docs: refresh temporal context map

* chore: leave release notes to release curation

* test(agents): keep compaction date mock complete

---------

Co-authored-by: Deepak Jain <406777+deepujain@users.noreply.github.com>
2026-07-29 22:12:47 +00:00
Yuval Dinodia
51241c4e00 fix(agents): edit tool rewrites line endings on lines it did not touch (#116011)
* fix(agents): edit tool rewrites line endings on lines it did not touch

The edit tool detected one line ending from the file's first newline,
normalized the whole file to LF for matching, then re-applied that single
ending to every line on write. A one-line edit therefore rewrote the
terminator of every untouched line, and deleted lone carriage returns
that were data rather than line breaks. The diff and unified patch
returned to the model are computed on the normalized text, so the damage
never surfaces in the tool result or the TUI preview.

Rebuild the written text from the original terminators instead. A bare
carriage return is tracked as its own terminator, so lines the edits did
not touch keep their exact bytes and a rewritten line is written back
with the terminator bytes it had. Newly written lines take the
terminator of the original line they replaced. Matching still runs in LF
space, so LF oldText against a CRLF file matches as before.

* fix(agents): preserve CR fallback for leading edit insertions

* fix(agents): align replacement line-ending boundaries

* fix(agents): preserve edit line-ending provenance

* refactor(agents): isolate edit replacement reconstruction

* test(agents): cover edits through production line endings

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 05:49:56 +08:00
Ayaan Zaidi
c661061d4a fix(agents): keep streamed pre-tool assistant text in claude-cli final output
The claude-cli terminal result envelope carries only the final message text.
On the default draft-preview path (no block streaming, no commentary
classification) the preview streamed every text block, then final delivery
edited it down to just the post-tool closer, silently erasing pre-tool
answer text (#106760).

Both the incremental parser and the transcript reparse now keep the
streamed accumulation when it is connected to the result through tool
splits: boundaries join with a paragraph break, non-tool message
boundaries restart preservation candidacy (superseded drafts still defer
to the envelope), interim results commit their segment without breaking
cumulative delta snapshots, and transcript reparses continue past interim
results like the incremental parser.
2026-07-30 06:48:01 +09:00
Adam Kalsey
e85e1dba3f fix(plugins): keep next-turn injections callable after register (#111131)
Co-authored-by: guptaishaan <guptaishaan@users.noreply.github.com>
2026-07-30 05:47:00 +08:00
Peter Steinberger
8fefe62ba4 fix(agents): settle aborted runs through after-turn so agent_end fires (#116087) 2026-07-29 17:44:51 -04:00
Vincent Koc
215e49b1a2 fix(hooks): report eventless hooks as not ready (#116083)
Fixes #72370

Release note: hooks check now reports selected hooks without declared events as not ready instead of ready.
2026-07-30 05:29:25 +08:00