Commit Graph

1140 Commits

Author SHA1 Message Date
Ayaan Zaidi
21d3533460 fix(channels): ack mentions in groups that do not require them
The group-mentions ack gate returned false whenever a group did not require mentions, conflating group policy with whether this message mentioned the agent. Under the default scope, mentioning the agent in a group configured to answer everything produced no ack at all, so the user had no signal the turn was picked up until the reply arrived.

Behavior change on a default path: those groups now show the 👀 ack (and the lifecycle status reactions when messages.statusReactions.enabled is true) on mentions. Mention-required groups, group-all, unmentioned messages, and off/none are unchanged. The gate no longer reads requireMention, so the parameter is gone from the shared type and all channel call sites.

Proven live on Telegram across three configurations, including a no-mention control confirming group-mentions did not become group-all.
2026-07-30 17:58:46 +09:00
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
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
Peter Steinberger
d16e33e08e fix: restore trustworthy end-to-end QA and cross-channel delivery (#115404)
* fix(qa): repair verified end-to-end and channel regressions

* fix(gateway): make interrupted restart recovery lifecycle-safe

* test(heartbeat): target the canonical recovery session store

* fix(gateway): prioritize durable restart recovery before heartbeat

* fix(qa): preserve safe restart recovery and channel expiry

* fix(qa): fail closed and fence restart recovery

* test(agents): isolate restart recovery timing

* test(agents): prove actual restart retry timing

* fix(qa): report incompatible profile scenarios

* fix(scripts): resolve symlinked docker scheduler entrypoints

* fix(qa): require fresh native test evidence

* fix(heartbeat): fence active restart recovery delivery

* fix(gateway): consume untargeted restart acknowledgements

* fix(qa): satisfy exhaustive hosted validation gates

* fix(agents): fence stopped restart recovery dispatch

* style(agents): format restart recovery lifecycle regression

* test(gateway): isolate context prewarm sidecar lifecycle

* test(qa): make scenario process timeout cleanup deterministic

* fix(qa): stamp synthetic gateway configs with current version

* fix(openai): preserve vision capabilities in stale model catalogs

* test(qa): align profile channel rejection with current main

* fix(openai): forward supported moderation for image edits

* fix: restore latest-main CI and image edit documentation

* fix(qa): retain relocated code-mode evidence validation

* fix(openai): expose GPT-5.4 vision in static catalog

* fix(pricing): honor explicit model cost overrides

* test(pricing): keep isolated provider regressions deterministic

* fix(openai): inherit transport for discovered static models

* fix(gateway): honor agent-owned static image capabilities

* test(gateway): preserve prepared-snapshot attachment races

* test(gateway): isolate subagent persistence failure injection

* test(gateway): exercise concurrent voice replay admission

* fix(gateway): restore stale model image capabilities

* fix(agents): publish configured model vision capabilities

* fix(agents): isolate detached media transcript ownership

* test(agents): preserve generic transcript lock regression

* fix(gateway): require proven static model route identity

* fix(qa): accept bounded full-size generated image attachments

* fix(qa): require fresh script producer evidence

* test(qa): prove native E2E scenario execution
2026-07-29 12:45:27 -04:00
Peter Steinberger
5bfc65d7f4 refactor: remove 3,543 lines of redundant runtime and tests (#115961)
* refactor: remove 3,543 lines of redundant runtime and tests

* refactor: ratchet production environment variable budget
2026-07-29 11:43:41 -04:00
Peter Steinberger
986e5d1758 refactor(channels): share ingress retention defaults (#115824) 2026-07-29 06:24:30 -04:00
Peter Steinberger
bde6b166c0 refactor(channels): deduplicate ingress monitor shells (#115792)
* refactor(channels): deduplicate ingress monitor shells

* fix(channels): preserve ingress error overload types

* fix(channels): type ingress error overload implementation

* chore(plugin-sdk): ratchet ingress error surface
2026-07-29 05:33:00 -04:00
Peter Steinberger
c402688894 feat(media): probe duration and dimensions for playback metadata (#115728)
* feat(media): probe playback metadata

* fix(media): satisfy CI gates

* fix(media): satisfy lint rules
2026-07-29 04:52:17 -04:00
Peter Steinberger
382ea7b74e refactor: centralize channel streaming config hints (#115739)
* refactor: centralize channel streaming config hints

* fix: repair code mode static checks

* fix: restore QA evidence validator import
2026-07-29 04:42:23 -04:00
Peter Steinberger
302f262e6b refactor: deduplicate extension normalization primitives (#115650)
* refactor(plugins): reuse SDK normalization primitives

* fix(ci): repair code-mode matrix checks

* fix(ci): satisfy code-mode matrix gates

* fix(ci): use matrix evidence export

* fix(ci): validate matrix evidence artifact
2026-07-29 04:10:06 -04:00
Peter Steinberger
a24c1ceb3a fix(channels): release inbound debounce at admission (#115603)
Track full dispatch completion separately for error handling and shutdown drain while allowing same-session follow-ups to steer active runs. Fixes #113180.

Co-authored-by: Taksh <takshkothari09@gmail.com>
2026-07-29 01:38:15 -04:00
Peter Steinberger
dd5b9c8c04 fix(slack): prevent duplicate MPIM mention replies (#115528)
* fix(slack): make MPIM app mentions type-safe

Resolve typeless app mentions through explicit metadata, the scoped event cache, then conversations.info so modern C-prefixed MPIMs cannot be misclassified by event ordering. Add a real Slack QA scenario that requires one reply and cleans up its temporary MPIM.

Co-authored-by: moeealii <75953662+moeealii@users.noreply.github.com>

* fix(slack): type unresolved mention metadata

* fix(slack): satisfy MPIM type contracts

---------

Co-authored-by: moeealii <75953662+moeealii@users.noreply.github.com>
2026-07-29 00:23:06 -04:00
moeealii
e2a76333d8 fix(slack): resolve conversation type for app_mention in C-prefixed group DMs (#115468)
app_mention events carry no channel_type, and modern Slack group DMs
(mpims) use C-prefixed channel ids, so prefix inference classifies them
as channels. Mentions in group DMs then bypass the handler's im/mpim
dedupe guard and are processed down the channel path — misrouting
replies, and double-handling alongside message.mpim when dm.groupEnabled
is on.

Confirm against the event-carried type cache and, on a miss, the cached
conversations.info lookup before treating a channel_type-less mention as
a channel mention. Only an authoritative "mpim" answer changes behavior;
a C-prefixed id can never be an im.

Fixes #115463

Co-authored-by: moeealii <>
2026-07-28 23:23:49 -04:00
Peter Steinberger
c092ec437c refactor: remove duplicate runtime and plugin paths (#115483) 2026-07-28 22:06:04 -04:00
joshavant
a29214acd8 fix(slack): protect outbound hooks from previews 2026-07-28 14:41:50 -05:00
Peter Steinberger
2964be2581 fix: prevent Slack and Feishu ingress startup leaks (#115295)
* fix(channels): clean up failed ingress startup

* chore: leave release notes to release prep

* test(feishu): initialize monitor ingress state
2026-07-28 13:29:20 -04:00
shannon0430
b954b3ae4f fix(slack): avoid unsafe emphasis boundaries (#111575)
* fix(slack): avoid invalid italic boundaries

* fix(slack): handle standalone CJK italics

* fix(slack): handle unsafe emphasis boundaries

* fix(slack): avoid unsafe emphasis boundaries

Co-authored-by: shannon0430 <shannon0430@users.noreply.github.com>

---------

Co-authored-by: shannon0430 <shannon0430@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-28 13:28:28 -04:00
Peter Steinberger
0c36fabc61 fix(slack): deduplicate message and mention events in one flush (#115302)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-28 13:20:01 -04:00
MatthewSynthia
7df5834511 fix(slack): cap chat.update edit text at the 4000-char limit, not the 8000 send limit (#115027)
* fix(slack): cap chat.update edit text at the 4000-char limit, not the 8000 send limit

updateMessageSlack truncated the edit text to SLACK_TEXT_LIMIT (8000), but Slack chat.update
rejects text longer than 4000 characters with msg_too_long (documented in limits.ts). Every
other edit path (actions.ts, edit-text.ts, message-action-dispatch.ts, preview-finalize.ts)
uses SLACK_EDIT_TEXT_LIMIT (4000); updateMessageSlack was the lone outlier, so a long
question-delivery status edit failed instead of landing. Use the edit limit.

* fix(slack): enforce edit text byte limits

Co-authored-by: MatthewSynthia <matthewsynthia@users.noreply.github.com>

* fix(slack): preserve prepared edit text within limits

Co-authored-by: MatthewSynthia <matthewsynthia@users.noreply.github.com>

---------

Co-authored-by: MatthewSynthia <matthewsynthia@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-28 12:41:37 -04:00
Peter Steinberger
3fa4805563 fix(slack): preserve pasted inbound tables (#115163)
* fix(slack): preserve pasted inbound tables

Co-authored-by: yash <84263676+yxshee@users.noreply.github.com>

* fix(slack): keep inbound text selection private

Co-authored-by: yash <84263676+yxshee@users.noreply.github.com>

* fix(slack): exclude unfurl tables from inbound context

Co-authored-by: yash <84263676+yxshee@users.noreply.github.com>

* refactor(slack): clarify aggregate table size limit

Co-authored-by: yash <84263676+yxshee@users.noreply.github.com>

* docs(slack): clarify table fallback escaping

Co-authored-by: yash <84263676+yxshee@users.noreply.github.com>

---------

Co-authored-by: yash <84263676+yxshee@users.noreply.github.com>
2026-07-28 10:34:21 -04:00
sunlit-deng
74954fd931 fix(slack): bound response_url body inspection (#115093) 2026-07-28 08:35:33 -04:00
Peter Steinberger
4233301c7c fix(slack): keep previews with custom outbound identity (#115114)
* fix(slack): preserve previews with custom identity

Co-authored-by: goutamadwant <workwithgoutam@gmail.com>

* test(models): isolate configured visibility policy

---------

Co-authored-by: goutamadwant <workwithgoutam@gmail.com>
2026-07-28 06:33:59 -04:00
Harjoth Khara
07768aa5f6 fix(slack): abort health probes within their deadline (#107835)
Preserve the current dedicated Slack read-client architecture and stop probe retries or HTTP 429 delays from surviving the shared health deadline. Verify stalled sockets, dropped-request background retries, immediate rate-limit rejection, and trickling response bodies with real loopback transport. Fixes #106565.

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: zhangqueping <3436352+zhangqueping@users.noreply.github.com>
2026-07-28 05:34:03 -04:00
Peter Steinberger
50a97288dd fix(slack): stop cyclic directory pagination (#115056)
* fix(slack): stop cyclic cursor pagination

Co-authored-by: zw-xysk <zhao.wang1@xydigit.com>

* test(slack): initialize read client test runtime

* test(slack): isolate reconnect retry timers

---------

Co-authored-by: zw-xysk <zhao.wang1@xydigit.com>
2026-07-28 04:41:30 -04:00
Peter Steinberger
78d6c6c047 fix(slack): bound read-only Web API calls (#115018)
Co-authored-by: zw-xysk <zhao.wang1@xydigit.com>
2026-07-28 03:37:54 -04:00
wangmiao0668000666
9dbfeb7e61 fix(channels): keep healthy accounts' message actions when one credential SecretRef fails (#110329)
* fix(channels): isolate unavailable account discovery

Co-authored-by: wangmiao0668000666 <wang.miao86@xydigit.com>

* refactor(channels): remove stale discovery exports

* test(pr): provide ripgrep fixture command

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-28 01:50:51 -04:00
rabsef-bicrym
f229356689 fix(slack): preserve native tables during outbound delivery (#111955)
* fix(slack): preserve rendered presentations across cloning

* test(slack): cover serialized presentation provenance

* test(slack): prove restart fallback for rendered payloads

- Reload the Slack adapter to simulate a runtime restart.
- Verify stale rendered provenance falls back to text without blocks.

* fix(slack): fail closed on invalid rendered metadata

---------

Co-authored-by: Pavonis <pavonis@martian.engineering>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-27 23:39:20 -04:00
Peter Steinberger
a1e0c9ea09 refactor(packages): DM-policy contract suite, dead routes, package folds (#114776)
* test(channels): share DM policy contract suite

* refactor(memory): remove dead host CLI routes

* refactor(acp): use canonical normalization helpers

* refactor(web): fold provider runtime into core

* refactor(packages): remove dead runtime exports

* chore(knip): drop retired ACP entry roots
2026-07-27 20:20:13 -04:00
Peter Steinberger
6d9b2d4d66 refactor(outbound): consolidate fenced cross-channel delivery (#114689)
* refactor(outbound): consolidate fenced delivery ownership

* fix(outbound): break durable-delivery contract cycle

* fix(outbound): align delivery queue owner tests and exports
2026-07-27 16:50:58 -04:00
Peter Steinberger
0e37f143f5 refactor(slack)!: retire inline interactive directives for typed presentation (#114738)
* 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
2026-07-27 16:41:00 -04:00
Peter Steinberger
de3616526b fix(release): repair plugin prerelease contracts (#114597) 2026-07-27 09:57:43 -04:00
Peter Steinberger
cba38b74a3 improve(slack): consolidate transport regression coverage (#114329) 2026-07-27 01:24:49 -04:00
Peter Steinberger
7cce91cda9 refactor(channels): unify account and setup adapters (#114290) 2026-07-27 00:55:46 -04:00
joshavant
d8de71258a refactor(channels): route bundled command replies 2026-07-26 23:15:06 -05:00
Peter Steinberger
37182b9050 refactor(channels): declare thread addressing as a channel trait (#114245)
* refactor(channels): declare thread addressing as a channel trait

* fix(tasks): require declared thread capability for direct parent-review delivery

* docs(tasks): record the no-target-parsing tradeoff at the delivery gate
2026-07-26 23:05:13 -04:00
Jesse Merhi
d7627d6f4c refactor(prompt): use plain inbound context labels and drop system-tag sanitizer (#112000)
* refactor(prompt): plain inbound context labels with a provenance marker

Replaces trust-worded inbound context labels ("(untrusted metadata)",
"(untrusted, for context)") with plain labels plus a fixed provenance
marker suffix appended to every OpenClaw-injected context header.

Detection keys on the marker, not label text, so strippers stay correct
across UI, TUI, replay, /trace segmentation, memory recall, and the Swift
chat preprocessor. Drops sanitizeInboundSystemTags in favor of the marker
boundary plus trusted system-prompt narration.

Renames the untrusted-named plugin SDK context identifiers to
channel-provenance names, keeping deprecated aliases registered for
removal after 2026-09-08.

Adds `openclaw doctor --fix` migrations that rewrite legacy inbound
labels in stored SQLite transcripts and purge legacy envelope-
contaminated LanceDB recall rows.

* fix(ci): resolve gate failures for plain inbound context labels

- doctor sqlite readers: open read-only connections via openNodeSqliteDatabase
  so the Kysely connection-boundary guardrail holds; unexport the now-internal
  transcript snapshot type (Knip unused-export gate).
- compat registry: split the record table into registry-records.ts and
  plugin-sdk-subpath-records.ts. The new compat record pushed registry.ts past
  the 700-line oxlint cap; suppressions are disallowed, so follow the existing
  sibling record-module pattern. Public exports and PluginCompatCode literals
  unchanged.
- acp-runtime test: assert current finalization behavior (newline normalization
  only). The bracket de-fang and System: rewrite it expected were removed with
  sanitizeInboundSystemTags; forged system lines are neutralized at the
  system-event queue, the single chokepoint feeding the System:-per-line render.
- regenerate docs_map and the plugin SDK API baseline manifest.

* fix(prompt): harden inbound context label migration and drop in-band sanitizer

Review follow-ups on the plain-label + provenance-marker change:

- Remove src/security/system-tags.ts. Rewriting inbound text to neutralize
  look-alike `System:`/`[System]` markers corrupted legitimate user text and is
  not a real injection boundary; role separation plus external-content wrapping
  is. Explicit product decision, recorded at the system-event queue.
- Narrow the LanceDB legacy-row purge so it cannot delete benign memories. It
  now requires a complete known legacy sentinel line, a legacy label followed by
  a fenced JSON body, or the complete legacy external-content header. The prior
  predicates matched ordinary prose such as `Notes (untrusted metadata):`, and
  deletion is irreversible.
- Make explicit-empty canonical ChannelStructuredContext win over the deprecated
  alias via a present/absent result instead of collapsing `[]` to undefined.
- Keep `\r?` in the active-memory doctor rule. It is the only rule spanning the
  header's line break, migrated assistant rows skip newline normalization, and
  without it the marked-header replace wins and the body strips to empty. Added
  a CRLF regression test.
- Fix stale comments that described removed behavior, and cover the Swift
  prose-block strip path.

Claude-Session: https://claude.ai/code/session_01WNzsPddQmxy9Y7jKD4wAxH
2026-07-27 11:27:53 +10:00
Peter Steinberger
3f27d76ea7 fix(slack): resolve thread freshness owner (#114009) 2026-07-25 21:21:06 -07:00
Peter Steinberger
64daf8dd23 refactor(slack): split message dispatch (#113602) 2026-07-25 03:43:24 -07:00
Peter Steinberger
446816f751 test: table-drive followup scenarios, centralize sanitizer wiring, remove obsolete negatives (#113583)
* test(auto-reply): table-drive followup runner scenarios

* test(channels): centralize sanitizer wiring coverage

* test: remove obsolete negative coverage
2026-07-25 02:14:44 -07:00
Peter Steinberger
48ab15851b test: consolidate Slack and QMD matrices (#113574) 2026-07-25 01:53:49 -07:00
Vincent Koc
7f36147bda refactor(slack): reuse shared error coercion (#113581) 2026-07-25 16:41:46 +08:00
Peter Steinberger
a5d758e74b refactor(plugin-sdk): share channel DM policy setup (#113537) 2026-07-25 01:00:53 -07:00
Peter Steinberger
92a35b599a refactor: share channel probe runner (#113540) 2026-07-25 00:24:31 -07:00
Peter Steinberger
e87b3cea18 refactor(plugin-sdk): share doctor key-move builder (#113539) 2026-07-25 00:21:15 -07:00
Peter Steinberger
7d5fb6f242 test(release): align extension prerelease contracts (#113381) 2026-07-25 02:30:35 +08:00
Vincent Koc
e3636852ba refactor(normalization): reuse trimmed list helpers (#113295) 2026-07-24 17:43:22 +08:00
Peter Steinberger
73bba03e4c refactor: canonicalize session delivery state (#113225)
* refactor: canonicalize session delivery state

* test: canonicalize reply persistence fixtures

* test: canonicalize talk delivery fixtures

* test: canonicalize voice session routes

* test: canonicalize attachment delivery fixtures

* test: migrate gateway delivery fixtures

* fix: skip invalid session delivery rows

* test: align delivery SDK surface gates

* fix: preserve legacy delivery precedence

* test: canonicalize heartbeat delivery fixtures

* fix: preserve delivery route prompt identity

* test: canonicalize session delivery fixtures

* fix: preserve recoverable legacy delivery routes

* fix: canonicalize remaining session state

* fix: preserve canonical session classification

* style: format delivery state changes

* test: refresh plugin SDK delivery baseline

* test: avoid mutating session fixture input

* style: simplify delivery identity check

* style: simplify delivery origin spread

* fix: preserve fresh delivery route metadata

* test: assert canonical surface route switch

* fix: canonicalize doctor file-store imports

* fix: preserve transitional delivery migration state

* fix: satisfy canonical delivery CI gates

* ci: scope GitHub App token permissions

* test: infer canonical delivery projections

* test: canonicalize ACP requester delivery fixtures

* test: canonicalize harness rollback fixture

* style: apply pinned formatter
2026-07-24 01:01:19 -07:00
Peter Steinberger
aae10cade5 refactor(markdown): unify format profile declarations (#113254)
* refactor(markdown): unify format profile declarations

* test(markdown): avoid suppression inventory drift
2026-07-24 00:37:59 -07:00
joshavant
d8f1f098e5 fix(cron): honor explicit authority for senderless runs 2026-07-24 01:24:03 -05:00
Peter Steinberger
3b7b2a2a1f chore: update dependencies and migrate major contracts (#112963)
* build(deps): complete latest dependency migrations

* fix(deps): satisfy updated dependency types

* fix(deps): hold incompatible build tooling

* fix(deps): preserve portable tooling contracts

* build(deps): allow reviewed fresh transitive releases

* fix(deps): repair major upgrade validation

* build(deps): regenerate current dependency graph

* fix(logging): keep tslog adapter type private

* fix(agents): narrow grep subprocess handle

* fix(codex): prefer pinned managed binary

* fix(codex): fence managed native provenance

* build(deps): align codex ACP with managed harness

* fix(slack): use socket-mode Undici runtime

* fix(slack): detect cross-runtime responses

* fix(slack): bridge package-owned fetch types

* fix(deps): retain tslog v4 JSON contract

* build(plugin-sdk): refresh logging API manifest
2026-07-23 21:21:01 -07:00