20774 Commits

Author SHA1 Message Date
zidongdesign
e5e73e3779
fix(tts): skip TTS synthesis for compaction notices
Compaction start/completion notices carry isCompactionNotice: true on
the ReplyPayload.  Guard maybeApplyTtsToPayload() with an early return
so these informational UI signals are never synthesised as speech,
regardless of TTS mode or auto-mode configuration.

Addresses review feedback from jalehman on PR #38805.
2026-03-20 19:52:28 -07:00
zidongdesign
d2ea0e3dc8
fix: preserve compaction count in streaming notices & route non-streaming notices through compaction metadata 2026-03-20 19:52:28 -07:00
zidongdesign
0b236892ac
fix(threading): honor replyToMode=off for compaction notices
Compaction notices carried replyToCurrent=true, which caused them to
pass through the allowExplicitReplyTagsWhenOff path in
createReplyToModeFilter("off") and retain replyToId.  In
replyToMode=off sessions this made the transient status messages
appear in-thread while normal assistant replies stayed off-thread,
contradicting the off-mode expectation.

Add an !isCompactionNotice guard to the explicit-tag fast-path so
compaction payloads always fall through to the strip branch and have
their replyToId removed — consistent with how every other payload is
treated in off mode.
2026-03-20 19:52:28 -07:00
zidongdesign
e2dc9b1682
fix(threading): keep compaction notices threaded after first assistant block
In replyToMode=first, the hasThreaded flag was set by the first assistant
chunk, causing the completion notice (emitted after flush) to hit the
`if (hasThreaded)` branch and have its replyToId stripped — making it
an unthreaded top-level message.

Fix: add an isCompactionNotice exemption inside the `hasThreaded` branch
so that compaction notices (both start and completion) always retain their
replyToId regardless of hasThreaded state, while non-notice payloads
continue to behave as before.

Addresses review comment https://github.com/openclaw/openclaw/pull/38805#discussion_r2901465625
2026-03-20 19:52:27 -07:00
zidongdesign
1e381c6c8c
fix: don't consume replyToMode=first slot for compaction notices
Compaction start/end notices are transient status messages that should
be threaded (appear in-context) but must not advance the hasThreaded
flag inside createReplyToModeFilter when mode=first.

Before this fix, the compaction start notice was the "first" threaded
message, so all real assistant reply chunks that followed had replyToId
stripped and were sent as unthreaded top-level messages.

Fix: skip advancing hasThreaded when payload.isCompactionNotice is true.
The notice still receives replyToId (so it appears in the thread), but
the filter's stateful "first" slot is preserved for the actual assistant
reply that follows.
2026-03-20 19:52:27 -07:00
zidongdesign
e7fd0a7b21
fix: wrap compaction start notice onBlockReply in try/catch to prevent unhandled rejection
onAgentEvent is fired fire-and-forget (void ctx.params.onAgentEvent?.(...)
in pi-embedded-subscribe.handlers.compaction.ts), so any rejection from the
awaited onBlockReply call would escape unobserved.

Wrap the delivery in a try/catch that swallows the error and logs a warning
via params.logger, consistent with other non-critical notice delivery paths.
2026-03-20 19:52:27 -07:00
zidongdesign
643eb31ea4
fix: exclude compaction notices from TTS transcript accumulation
Add isCompactionNotice flag to ReplyPayload and set it on both the
compaction start notice (agent-runner-execution.ts) and the completion
notice (agent-runner.ts). dispatch-from-config.ts skips accumulation
into accumulatedBlockText when the flag is set, so compaction status
lines (🧹 / ) are never synthesised into the fallback TTS audio for
block-streaming runs with tts.mode=final.
2026-03-20 19:52:27 -07:00
zidongdesign
88c9ad3026
fix: bypass pipeline for compaction start notice to preserve final reply
Previously the start notice was routed through blockReplyHandler which
enqueues into blockReplyPipeline, setting didStream() = true.  This
caused buildReplyPayloads to drop all final payloads (shouldDropFinalPayloads
path), discarding the real assistant reply on non-streaming model paths
where assistantTexts is populated from the final message (not block chunks).

Fix: send the start notice directly via opts.onBlockReply, bypassing the
pipeline entirely.  applyReplyToMode is still applied so replyToId threading
(replyToMode=all|first) is honoured.  This mirrors how the completion notice
in agent-runner.ts avoids the pipeline after flush()/stop().
2026-03-20 19:52:27 -07:00
zidongdesign
bcc2d2188e
fix: address P2 review comments on compaction notices
P2-1 (agent-runner.ts): Restrict direct completion notice to
block-streaming runs. The condition now checks blockStreamingEnabled
in addition to opts?.onBlockReply, preventing duplicate completion
notices in non-streaming sessions where verboseNotices already handles
the compaction-complete text.

P2-2 (agent-runner-execution.ts): Emit compaction start notice when
streaming is off. blockReplyHandler is a no-op for non-streaming runs,
so add a direct fallback path: when blockStreamingEnabled is false and
opts.onBlockReply is present, send the start notice directly with
applyReplyToMode threading applied.
2026-03-20 19:52:27 -07:00
zidongdesign
197ef0a1f5
fix: send compaction completion notice after pipeline stop to preserve didStream
Enqueueing the completion notice into blockReplyPipeline before flush
caused didStream() to return true even when no assistant content was
streamed. buildReplyPayloads drops all finalPayloads when didStream()
is true, so the real assistant reply could be silently discarded on
non-streaming model paths (e.g. pi-embedded-subscribe) that fill
assistantTexts without emitting block replies.

Fix: move the completion notice send to *after* pipeline flush+stop,
using a fire-and-forget Promise.race with blockReplyTimeoutMs. This
keeps the timeout guarantee (satisfying the previous P1) while not
touching didStream() at all.

Non-streaming fallback (verboseNotices) is unchanged.

Addresses P1 review comment on PR #38805.
2026-03-20 19:52:27 -07:00
zidongdesign
b9beb6869e
fix: route compaction completion notice through block reply pipeline
Previously the completion notice bypassed the block-reply pipeline by
calling opts.onBlockReply directly after the pipeline had already been
flushed and stopped. This meant timeout/abort handling and serial
delivery guarantees did not apply to the notice, risking stalls or
out-of-order delivery in streaming/routed runs.

Fix: enqueue the completion notice into blockReplyPipeline *before*
flush so it is delivered through the same path as every other block
reply. The non-streaming fallback (verboseNotices) is preserved for
runs where no pipeline exists.

Also removes the now-unnecessary direct opts.onBlockReply call and
cleans up the redundant suffix in the pre-flush path (count suffix is
still included in the verboseNotices fallback path where count is
available).

Addresses P1 review comment on PR #38805.
2026-03-20 19:52:27 -07:00
zidongdesign
8e216cbb4e
fix: thread compaction notices through reply-to mode handler
Compaction start and completion notices were sent via raw
opts.onBlockReply, bypassing createBlockReplyDeliveryHandler and the
applyReplyToMode pipeline. In channels configured with
replyToMode=all|first, this caused compaction notices to be delivered
as unthreaded top-level messages while all other replies stayed
threaded — inconsistent and noisy.

Fix agent-runner-execution.ts: extract createBlockReplyDeliveryHandler
result into blockReplyHandler and share it between onBlockReply and the
compaction start notice in onAgentEvent. Both now use the same handler.

Fix agent-runner.ts: inject currentMessageId + replyToCurrent into the
completion notice payload before passing through applyReplyToMode, so
threading directives are honoured consistently with normal replies.

Closes the P2 review comment on PR #38805 (agent-runner.ts:701).
2026-03-20 19:52:27 -07:00
zidongdesign
40b175a695
fix: send compaction completion notice via onBlockReply in streaming mode
In block-streaming mode, the reply pipeline bypasses buildReplyPayloads,
so notices only pushed to verboseNotices were never delivered to the user.
The start notice ("🧹 Compacting context...") was already sent via
opts.onBlockReply directly in agent-runner-execution.ts; mirror the same
path for the completion notice.

- If opts.onBlockReply is present (streaming mode): await onBlockReply
  with the completion text directly, so it reaches the user immediately.
- Otherwise (non-streaming): push to verboseNotices as before so it gets
  prepended to the final payload batch.

Also consolidate the verbose vs. non-verbose text selection into a single
completionText variable, removing the redundant pop/push pattern.
2026-03-20 19:52:26 -07:00
chenpitang
f422d3363d
feat: notify user when context compaction starts and completes
During auto-compaction the agent goes silent for several seconds while
the context is summarised.  Users on every channel (Discord, Feishu,
Telegram, webchat …) had no indication that something was happening —
leading to confusion and duplicate messages.

Changes:
- agent-runner-execution.ts: listen for compaction phase='start' event
  and immediately deliver a "🧹 Compacting context..." notice via the
  existing onBlockReply callback.  This fires for every channel because
  onBlockReply is the universal in-run delivery path.
- agent-runner.ts: make the completion notice unconditional (was
  previously guarded behind verboseEnabled).  Non-verbose users now see
  " Context compacted (count N)."; verbose users continue to see the
  legacy "🧹 Auto-compaction complete (count N)." wording.

Why onBlockReply for start?
onBlockReply is already wired to every channel adapter and fires during
the live run, so the notice arrives in-band with zero new plumbing.
Using verboseNotices (appended after the run) would be too late and
would miss the start signal entirely.

Fixes: users seeing silent pauses of 5-15 s with no feedback during
compaction on any channel.
2026-03-20 19:52:26 -07:00
Tyler Yust
5e417b44e1 Outbound: skip broadcast channel scan when channel is explicit 2026-03-20 18:21:01 -07:00
Tyler Yust
b71686ab44 Enhance web search provider config validation and compatibility handling
- Added a test to ensure no warnings for legacy Brave config when bundled web search allowlist compatibility is applied.
- Updated validation logic to incorporate compatibility configuration for bundled web search plugins.
- Refactored the ensureRegistry function to utilize the new compatibility handling.
2026-03-20 18:20:50 -07:00
Vincent Koc
c3be293dd5 fix(slack): unify slash conversation-runtime mock 2026-03-20 18:19:07 -07:00
Danh Doan
e78129a4d9
feat(context-engine): pass incoming prompt to assemble (#50848)
Merged via squash.

Prepared head SHA: 282dc9264d4157c78959c626bbe6f33ea364def5
Co-authored-by: danhdoan <12591333+danhdoan@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-03-20 17:03:21 -07:00
Sally O'Malley
6a6f1b5351
changelog (#51322)
Signed-off-by: sallyom <somalley@redhat.com>
2026-03-20 19:30:33 -04:00
Josh Lehman
751d5b7849
feat: add context engine transcript maintenance (#51191)
Merged via squash.

Prepared head SHA: b42a3c28b4395bd8a253c7728080f09100d02f42
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-03-20 16:28:27 -07:00
Peter Steinberger
6526074c85 test: trim singleton cold-start reloads 2026-03-20 23:14:28 +00:00
Peter Steinberger
0a842de354 test: widen low-profile singleton batching 2026-03-20 23:02:33 +00:00
Josh Lehman
2364e45fe4
test: align extension runtime mocks with plugin-sdk (#51289)
* test: align extension runtime mocks with plugin-sdk

Update stale extension tests to mock the plugin-sdk runtime barrels that production code now imports, and harden the Signal tool-result harness around system-event assertions so the channels lane matches current extension boundaries.

Regeneration-Prompt: |
  Verify the failing channels-lane tests against current origin/main in an isolated worktree before changing anything. If the failures reproduce on main, keep the fix test-only unless production behavior is clearly wrong. Recent extension refactors moved Telegram, WhatsApp, and Signal code onto plugin-sdk runtime barrels, so update stale tests that still mock old core module paths to intercept the seams production code now uses. For Signal reaction notifications, avoid brittle assertions that depend on shared queued system-event state when a direct harness spy on enqueue behavior is sufficient. Preserve scope: only touch the failing tests and their local harness, then rerun the reproduced targeted tests plus the full channels lane and repo check gate.

* test: fix extension test drift on main

* fix: lazy-load bundled web search plugin registry

* test: make matrix sweeper failure injection portable

* fix: split heavy matrix runtime-api seams

* fix: simplify bundled web search id lookup

* test: tolerate windows env key casing
2026-03-20 15:59:53 -07:00
Vincent Koc
e635cedb85 test(openai): cover bundle media surfaces 2026-03-20 15:53:12 -07:00
Vincent Koc
d54ebed7c8 test(openai): add plugin entry live coverage 2026-03-20 15:53:12 -07:00
Vincent Koc
d1d46c6cfb test(openai): broaden live model coverage 2026-03-20 15:53:12 -07:00
Vincent Koc
f1802a5bc7 test(openai): add live provider probe 2026-03-20 15:53:12 -07:00
Sally O'Malley
6e20c4baa0
feat: add anthropic-vertex provider for Claude via GCP Vertex AI (#43356)
Reuse pi-ai's Anthropic client injection seam for streaming, and add
the OpenClaw-side provider discovery, auth, model catalog, and tests
needed to expose anthropic-vertex cleanly.

Signed-off-by: sallyom <somalley@redhat.com>
2026-03-20 18:48:42 -04:00
Vincent Koc
42ca447189 test(openrouter): add live plugin coverage 2026-03-20 15:36:34 -07:00
Peter Steinberger
fac64c2392 test: widen unit timing snapshot coverage 2026-03-20 22:33:49 +00:00
Peter Steinberger
39a4fe576d test: normalize perf manifest paths 2026-03-20 22:06:46 +00:00
Josh Lehman
c3972982b5
fix: sanitize malformed replay tool calls (#50005)
Merged via squash.

Prepared head SHA: 64ad5563f7ae321b749d5a52bc0b477d666dc6be
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-03-20 15:03:30 -07:00
Peter Steinberger
cadbaa34c1 test: widen low-profile scheduler peeling 2026-03-20 21:30:44 +00:00
Peter Steinberger
994b42a5a5 test: parallelize safe audit case tables 2026-03-20 21:16:01 +00:00
Peter Steinberger
aed1f6d807 test: parallelize low-profile deferred lanes 2026-03-20 21:07:56 +00:00
Peter Steinberger
09cf6d80ec test: batch thread-only unit lanes 2026-03-20 20:51:38 +00:00
Josh Avant
7abfff756d
Exec: harden host env override handling across gateway and node (#51207)
* Exec: harden host env override enforcement and fail closed

* Node host: enforce env override diagnostics before shell filtering

* Env overrides: align Windows key handling and mac node rejection
2026-03-20 15:44:15 -05:00
Josh Avant
c7134e629c
LINE: harden Express webhook parsing to verified raw body (#51202)
* LINE: enforce signed-raw webhook parsing

* LINE: narrow scope and add buffer regression

* changelog

Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com>

---------

Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-03-20 15:32:55 -05:00
Vincent Koc
11d71ca352
pairing: keep setup codes bootstrap-token only (#51259) 2026-03-20 13:27:39 -07:00
Peter Steinberger
5a5e84ca1d test: drop duplicate web search helper 2026-03-20 20:25:24 +00:00
Peter Steinberger
fa71ad7c5d test: repair latest-main web search regressions 2026-03-20 20:17:11 +00:00
Josh Lehman
23fef04c4e
test: fix setup finalize web search mocks (#51253) 2026-03-20 13:07:22 -07:00
Peter Steinberger
1b18742e8e test: peel more slow unit files out of unit-fast 2026-03-20 20:04:52 +00:00
Teddy Tennant
a20ba74978
test: add SSRF guard coverage for URL credential bypass vectors (#50523)
* security: add SSRF guard tests for URL credential bypass vectors

* test(security): strengthen SSRF redirect guard coverage

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-03-20 12:45:06 -07:00
Gustavo Madeira Santana
3da66718f4
Web: derive search provider metadata from plugin contracts (#50935)
Merged via squash.

Prepared head SHA: e1c7d72833afff6ef33e8d32cdd395190742dc08
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-03-20 12:41:04 -07:00
Peter Steinberger
acf32287b4 test: trim more extension startup from unit tests 2026-03-20 19:28:32 +00:00
Jaaneek
916f496b51
Add Grok 4.20 reasoning and non-reasoning to xAI model catalog (#50772)
Merged via squash.

Prepared head SHA: 095e645ea58b2259b25c923aeaf11bbcb2990c8f
Co-authored-by: Jaaneek <25470423+Jaaneek@users.noreply.github.com>
Co-authored-by: huntharo <5617868+huntharo@users.noreply.github.com>
Reviewed-by: @huntharo
2026-03-20 15:28:30 -04:00
Peter Steinberger
f6b3245a7b fix: pass full sdk gate 2026-03-20 19:24:10 +00:00
Peter Steinberger
62ddc9d9e0 refactor: consolidate plugin sdk surface 2026-03-20 19:24:10 +00:00
Vincent Koc
46854a84a4 test(plugin-sdk): cover legacy root diagnostic listeners 2026-03-20 12:23:02 -07:00