Route Discord thread follow-up messages to plugin-owned bindings by the raw thread id while retaining parent channel fallback matching. This fixes `/codex bind` follow-ups in Discord threads being claimed by the parent OpenClaw route instead of the bound Codex session.
Verification:
- `node scripts/run-vitest.mjs extensions/discord/src/channel.conversation.test.ts src/hooks/message-hook-mappers.test.ts extensions/discord/src/monitor/message-handler.process.test.ts -t "prefers bound session keys|passes Discord thread parent only|routes Discord thread plugin-owned bindings|passes thread parent ids|thread binding"`
- `node scripts/run-vitest.mjs src/auto-reply/reply/dispatch-from-config.test.ts -t "routes Discord thread plugin-owned bindings by raw thread id"`
- `pnpm build`
- `pnpm lint --threads=8`
- `CI=true FORCE_COLOR=0 pnpm lint --threads=8`
- `.agents/skills/autoreview/scripts/autoreview --mode local`
- GitHub: Real behavior proof, check-test-types, check-dependencies, check-prod-types, auto-reply dispatch shard, hooks shard, and extension package boundary passed on head 1e896d9835.
Known unrelated CI noise at merge: broad opengrep/test/lint CI failures are outside the touched Discord/session-binding surface and contradicted by focused local proof where applicable.
Co-authored-by: Hex <hex@openclaw.ai>
* fix(agents): route media task hints below the system-prompt cache boundary
Per-turn image/video/music generation task hints were injected into the
static prependSystemContext slot, landing above the cache boundary inside the
cacheable prefix. The hints are present only on user/manual turns and vary
with active media tasks, so the cacheable prefix shifted turn-to-turn and
defeated Anthropic/OpenAI prompt caching (#85203).
Split the per-turn media hints out of the prepend resolver into
resolveAttemptMediaTaskSystemPromptAddition and route them below the boundary
via the existing prependSystemPromptAddition helper, matching how subagent and
context-engine system-prompt additions are already routed. The static plugin
prependSystemContext / appendSystemContext hook fields are unchanged and
remain in the cacheable prefix. Applied at both consumers (embedded agent
runner and CLI runner).
* fix(agents): keep media task hints below the cache boundary for hook systemPrompt overrides
A before_prompt_build hook that returns a full systemPrompt override replaces
the base prompt with marker-free text. Per-turn media-generation task hints
were then front-prepended into that marker-free prompt, which providers cache
as a single block, so the cached prefix still shifted turn-to-turn on the
override path (#85203).
Wrap the base with ensureSystemPromptCacheBoundary at both media-routing sites
(embedded agent runner and CLI runner) so a marker-free override gets an
appended boundary and the hint routes into the uncached suffix. The helper is
idempotent, so marker-bearing prompts are unchanged. The shared
prependSystemPromptAddition wrapper and the static prependSystemContext /
appendSystemContext hook fields are untouched.
* fix(agents): keep marker-free idle prompts cacheable below the boundary
A marker-free hook systemPrompt override only had the cache boundary
ensured on turns with an active media task. On idle turns the later
appendModelIdentitySystemPrompt landed above the absent boundary, so the
idle cached system prefix diverged from active turns and prompt caching
broke across active/idle transitions. Ensure the boundary regardless of
media state in both the embedded and CLI runners, and extend the
regression to cover the model-identity append across active->idle.
* fix(agents): scope cache-boundary ensure to the model-identity append
Ensuring the boundary unconditionally on media-idle turns appended a
boundary marker to empty raw/gateway system prompts (turning "" into a
marker-only prompt) and to prompts with nothing below the boundary.
Instead ensure the boundary only when a model identity line is actually
appended to a non-empty prompt, in both the embedded and CLI runners.
This still keeps the identity below the boundary for marker-free hook
systemPrompt overrides (the #85203 idle-cache regression) while leaving
empty and identity-less prompts untouched.
* test: refresh stale type and lint expectations
* test: stabilize CI timeout checks
* test: satisfy channel entry lint
* fix(agents): skip cache boundary for blank prompts
* fix(channels): keep draft flush timer referenced
* test(agents): tolerate failed exec timeout setup
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Provider-scoped configured regex mention patterns for Discord, Matrix, Slack, Telegram, and WhatsApp.
Native platform mentions keep their existing behavior, and unsupported channels do not opt into the new regex policy path. The new policy supports per-channel allow/deny routing through mentionPatterns.mode with allowIn and denyIn so group auto-reply regexes can be limited without broad global blast radius.
Refs #70864.
Supersedes #87200.
Thanks @patrick-slimelab.
Remove isolate: true from the channel Vitest config and fix the leaking fake-timer/mock tests so the lane runs under the shared non-isolated runner. Verified with focused scoped-config/channel tests, the full channel Vitest config, git diff --check, and branch-mode autoreview.
Move Telegram plugin-local state from JSON sidecars into plugin-state SQLite. Keep legacy JSON handling in startup and doctor migration plans, with runtime state now reading and writing SQLite directly. Stabilize the channel Vitest lane by cleaning up typing timers and isolating that lane.
Extract shared normalization/coercion helpers into private @openclaw/normalization-core workspace package while preserving existing plugin SDK helper subpaths.\n\nAlso keeps direct normalization-core imports internal, wires UI/build/loader resolution, and replaces the slow PR network CodeQL lane with a fast added-line boundary scan while retaining full CodeQL for scheduled/manual runs.\n\nVerification: local moved tests, plugin SDK boundary tests, extension loader tests, agents-support shard, UI build/test, build artifacts, lint, workflow guards, autoreview, and GitHub CI passed on PR head 963d893715.
Adds opt-in Discord progress-draft commentary for assistant preambles while keeping commentary hidden by default and final delivery unchanged.
Keeps commentary config Discord-specific, strips directive tags/NO_REPLY, and clears stale commentary rows without stopping the active draft stream.
Thanks @bryanpearson.
Co-authored-by: bryanpearson <bryanmpearson@gmail.com>
Render Slack progress-mode updates as native task-card progress blocks, with bounded Slack chunk text and stable fallback behavior.
Also deep-merge Slack account streaming objects over top-level defaults while preserving legacy scalar account overrides, and keep the plugin SDK fetch runtime import path from evaluating guarded-fetch dispatcher code.
Verification:
- pnpm test extensions/slack/src/progress-blocks.test.ts extensions/slack/src/accounts.test.ts src/plugin-sdk/fetch-runtime.test.ts
- pnpm lint --threads=8
- git diff --check
- .agents/skills/autoreview/scripts/autoreview --mode local
- GitHub PR checks green on #87748 at 4803e98820
Refs #82258
Co-authored-by: Simon van Laak <32648751+simonvanlaak@users.noreply.github.com>
Suppress reasoning-prefixed silent replies before outbound delivery while preserving substantive replies that merely end with the silent token.\n\nFixes #66701.\n\nThanks @zuoanCo for the PR and @Cavadus for the report.\n\nProof: focused Vitest and pnpm check:changed passed on Testbox-through-Crabbox tbx_01ksmvfw0gk9xwh10ra1cyhzfw; CI passed for head a014eb0d91.