Commit Graph

91 Commits

Author SHA1 Message Date
Sarah Fortune 00fc1bd123 fix(slack): scope enterprise channel and user policies by workspace (#122346)
* fix(slack): scope channel policies by workspace

* fix(slack): scope user policies by workspace

* fix(slack): preserve workspace policies at ingress

* test(slack): use canonical workspace ids

* chore(slack): remove stale allowlist import

* fix(slack): require workspace-scoped grid policies

* test(slack): scope enterprise policy fixtures

* style(slack): format workspace policy changes

* fix(slack): preserve workspace policy wildcards

* fix(slack): retain workspace system-event policies

* fix(slack): scope bot policy identities

* fix(slack): retain workspace in group policy

* fix(slack): preserve workspace DM allowlists

---------

Co-authored-by: Sarah Fortune <sarah.fortune@gmail.com>
2026-08-11 22:09:46 -07:00
Peter Steinberger a0ad38e71a feat(docs-ci): validate docs config examples against the schema (#121336)
* feat(docs-ci): validate config examples against schema

* docs: teach canonical agent roster configuration

* docs: nest inline environment variables under vars

* docs: update canonical media model keys

* docs: remove retired config keys from examples

* fix(docs-ci): keep audit internals private

* feat(docs-ci): validate plugin-owned config examples

* fix(docs-ci): validate indented config fences

* fix(ci): route manifest changes through docs audit

* chore(docs): refresh generated config baselines
2026-08-10 07:57:56 -07:00
Sarah Fortune a968d15f63 feat(slack): enable Enterprise Grid identity, DMs, routing, actions, approvals, and presence (#121373)
* refactor(slack): detect Enterprise Grid installs at runtime

* fix(slack): preserve enterprise bot identity

* style(slack): format enterprise identity test

* fix(slack): scope enterprise config by workspace

* fix(slack): preserve qualified binding casing

* feat(slack): enable enterprise presence polling

* fix(slack): normalize enterprise binding accounts

* fix(slack): require workspace-scoped Grid targets

* docs(slack): document Enterprise policy target forms

* fix(slack): preserve Grid pairing workspace scope

* refactor(slack): simplify scoped target formatting

* fix(slack): repair Enterprise Grid CI checks

* chore: refresh generated Slack metadata

* refactor(slack): simplify optional workspace scope

* test(slack): infer installation state handle types

* chore: resolve plugin SDK baseline conflict

* fix(ci): regenerate plugin SDK API baseline on Linux

* fix(slack): allow standalone workspace sends

---------

Co-authored-by: Sarah Fortune <sarah.fortune@gmail.com>
2026-08-10 07:10:06 +00:00
Peter Steinberger 914f73ac99 docs: replace retired config keys with canonical schema keys (#121330) 2026-08-09 20:30:43 -07:00
Sarah Fortune 66dee798b5 Revert "fix: enable Slack native approvals for Enterprise Grid installs (#120…" (#121219)
This reverts commit 96798953b2.
2026-08-09 19:49:35 +00:00
Sarah Fortune 96798953b2 fix: enable Slack native approvals for Enterprise Grid installs (#120874)
* fix(slack): scope Grid native approvals by team

* fix(slack): type action middleware context

* fix(slack): secure Grid native approvals

Co-authored-by: Sarah Fortune <sarah.fortune@gmail.com>

---------

Co-authored-by: Sarah Fortune <sarah.fortune@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-09 12:09:59 -07:00
Peter Steinberger 71a33f07a9 fix(imessage): make SSH-backed sends and actions reliable (#121038)
* fix(imessage): harden remote Mac transport

Route SSH-backed iMessage actions through JSON-RPC, preserve remote database paths, and stage outbound files on the Messages Mac with bounded cleanup. Keep local action semantics intact while failing closed on ambiguous wrappers and surfacing the remaining imsg v0.13.4 limits.

* fix(imessage): remove test-only exports
2026-08-09 04:48:38 -07:00
Peter Steinberger 96a75be170 fix(discord): default preview streaming to off (#120376)
Make Discord progress drafts and activity receipts explicit opt-ins while preserving configured streaming modes and legacy explicit progress migrations. Related: #87704.
2026-08-07 17:18:12 -07:00
Peter Steinberger bbde865b9c docs(gateway): fix invalid heartbeat visibility examples (#118827) 2026-08-03 11:17:14 -07:00
Vincent Koc 89aadef6ef feat(plugins): externalize iMessage channel (#117101) 2026-08-01 08:01:18 +08:00
zw-xysk 08305dbb94 docs(config-channels): repair Discord, Slack, and Google Chat configuration examples (#106188)
* docs(config-channels): replace legacy allow:true with enabled:true for Discord, Slack, and Google Chat config examples

* docs(config-channels): repair channel configuration examples

Make the complete Discord, Slack, and Google Chat setup examples valid and keep Slack channel routing on stable IDs.

Co-authored-by: 赵旺0668001248 <zhao.wang1@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-31 16:58:02 -07:00
Peter Steinberger eb0087dc7c fix(discord): connect mention-only bots without Message Content intent (#116962)
* fix(discord): support mention-only gateway intent

* chore: keep release changelog owner-only
2026-07-31 12:04:16 -07:00
clawSean a47c6b0ace docs(slack): clarify group DM bot membership (#101944)
* docs(slack): clarify group DM bot membership

* docs(slack): qualify MPDM API errors

* docs(slack): clarify MPDM invite requirements

Co-authored-by: clawSean <260045960+clawSean@users.noreply.github.com>

---------

Co-authored-by: clawSean <260045960+clawSean@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-28 14:27:09 -04:00
Peter Steinberger 938749180e refactor(nodes)!: retire arming leases for durable capability enablement (#114892)
* refactor(nodes): retire phone control leases

* fix(doctor): clean retired phone control state

* docs(nodes): document durable capability enablement

* docs(changelog): defer node enablement note

* fix(doctor): harden retired phone control cleanup

* fix(doctor): fail closed on unreadable lease state

* fix(doctor): validate retired lease journals

* fix(doctor): preserve deny-shadowed consent

* docs: refresh node authorization map

* fix(doctor): keep retirement helpers private
2026-07-27 23:51:30 -04:00
Peter Steinberger edecdbd05e refactor(config): config-surface reduction tranche 3 — product consolidations (review request) (#111527)
* refactor(config): consolidate media model lists

* refactor(config): unify memory configuration

* refactor(config): consolidate TTS ownership

* refactor(config): move typing policy to agents

* refactor(config): retire product-level config surfaces

* refactor(config): share scoped tool policy type

* chore(config): refresh generated baselines

* fix(config): honor agent typing overrides

* fix(config): migrate sibling config consumers

* refactor(infra): keep base64url decoder private

* fix(config): strip invalid legacy TTS values

* chore(config): refresh rebased baseline hash

* fix(doctor): route legacy messages.tts.realtime voice to talk during tts move

* refactor(config): polish final layout names

* refactor(config): freeze retired tuning defaults

* feat(config): add fast mode default symmetry

* refactor(config): key agent entries by id

* docs(config): update final layout reference

* test(config): cover final layout migrations

* chore(config): refresh final layout baselines

* fix(config): align final layout runtime readers

* fix(config): align remaining readers

* fix(config): stabilize final layout migrations

* fix(config): finalize config projection proof

* fix(config): address final layout review

* docs(release): preserve historical config names

* fix(config): complete keyed agent migration

* fix(config): close final migration gaps

* fix(config): finish full-branch review

* fix(config): complete runtime secret detection

* fix(config): close final review findings

* fix(config): finish canonical docs and heartbeat migration

* fix(config): integrate latest main after rebase

* refactor(env): isolate test-only controls

* refactor(env): isolate build and development controls

* refactor(env): collapse process identity indirection

* refactor(env): remove duplicate config and temp aliases

* docs(env): define the operator-facing allowlist

* ci(env): ratchet production variable count

* fix(env): remove stale provider helper import

* fix(env): make ratchet sorting explicit

* test(env): keep test seam in dead-code audit

* test(env): cover ratchet growth and boundary; document surface budgets

* docs(config): document tier-eval consolidations

* docs(config): clarify speech preference ownership

* test(memory): align retired tuning fixtures

* refactor(memory): freeze engine heuristics

* refactor(config): apply tier-eval tranche

* refactor(tts): move persona shaping to providers

* refactor(compaction): move prompt policy to providers

* test(config): align hookified prompt fixtures

* chore(deadcode): classify test-only exports

* chore(github): remove unused spawn helper

* chore(deadcode): classify queue diagnostics

* chore(deadcode): remove unused lane snapshot export

* chore(plugin-sdk): ratchet consolidated surface

* fix(config): integrate latest main after rebase
2026-07-21 20:28:43 -07:00
Peter Steinberger 783a5d21cf refactor(config): purge numeric tuning knobs behind built-in defaults (#111382) 2026-07-19 07:35:45 -07:00
Peter Steinberger fdf44edf4d docs: document channel ingress guarantees (#111069) 2026-07-18 17:26:41 -07:00
Omar Shahine bbad877aed fix: deliver Codex-generated images on message-tool routes (#110893)
* fix: deliver Codex-generated images on message-tool routes

* test(codex): cover native image delivery path

Document trusted harness artifact provenance and cover the runner-to-dispatch bridge.\n\nRelease note: Codex-generated images now reach message-tool-only routes while normal source suppression remains intact.\n\nCo-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 20:45:57 +01:00
Peter Steinberger 5bab0c2ea8 feat(slack): support running as a real Slack user (user identity) (#109837)
* feat(slack): add user-identity config surface (session token/cookie)

Introduce an account-level identity discriminator ("bot" default | "user") for
the Slack channel, plus sessionToken/sessionCookie secret fields for the
browser-session (user) path. Schema enforces structural coupling only
(identity="user" rejects appToken/signingSecret/relay/non-default mode);
credential presence is deferred to runtime like bot/app tokens. Account entries
inherit the top-level identity. Adds env fallback (SLACK_SESSION_TOKEN/COOKIE,
default account only), secret-contract registration, provenance *Source fields,
and UI hints. Config surface only; resolver/transport are later phases.

* refactor(slack): identity-aware operation-token resolver + dedup

Route Slack read/write token selection through a single identity-aware
resolveSlackOperationToken: identity="user" selects the browser-session token
for both operations (companion cookie attached later at client construction),
identity="bot" keeps the exact userToken/botToken + userTokenReadOnly behavior.
Delete the duplicated token-selection gate in action-runtime and route direct
sends/DM opens through the shared resolver with identity-neutral error wording.
Behavior-neutral for bot identity; net non-test LOC -2.

* refactor(slack): retarget user identity to xoxp + companion app

Replace the abandoned browser-session (xoxc/xoxd) approach for identity="user"
with the official path: authenticate as the human via the existing userToken
(xoxp) while a companion app (appToken/socket or signingSecret/http) carries
events. Remove sessionToken/sessionCookie config, env vars, secret-contract
entries, resolver fields, and their tests. Invert the schema coupling so
identity="user" permits the companion-app transport credentials, and drop the
now-vestigial user-identity structural guard entirely (identity is a permissive
discriminator; credential presence is a runtime concern). Resolver returns the
user token for user-identity reads and writes. Behavior-neutral for bot
identity.

* feat(slack): user-identity provider transport (xoxp + companion app)

Wire the identity="user" event transport. The companion Slack app runs Socket
Mode (appToken) or HTTP (signingSecret) while Bolt authenticates as the human
via the user token (no bot token). Startup auth.test runs on the user token and
its user_id becomes the self/mention target and self-send dedupe id (Bolt's
lazy per-event authorize populates context.botUserId=user_id, so the existing
self-event middleware drops the human's own messages). Identity-aware token
requirements and diagnostics; the bot-token identity warning is suppressed for
user identity. Behavior-neutral for identity="bot".

* feat(slack): user-identity setup, doctor, and docs

Add the setup wizard, doctor/status, and documentation for identity="user".
The wizard collects a user token plus the companion-app transport credential
(app token for socket, signing secret for http) and only persists identity when
"user" so bot setups keep byte-identical generated config; doctor validates the
user token via auth.test and warns on a missing transport credential; account
inspection reports user-token status. Message actions are gated on the active
identity's credential so user accounts expose actions. Docs add the exact
companion-app recipe (user scopes, on-behalf-of-user message events, socket/http
examples, the DM/group-DM-only-via-user-scope note, and self-send dedupe).
Behavior-neutral for identity="bot".

* test(slack): isolate user-identity provider tests to fix parallel flake

The new user-identity provider tests shared the globalThis-stored Slack test
client/handlers across files under parallel isolate:false, so their reaction
closures could reference a prior file's state and intermittently fail sibling
monitor tests (monitor.tool-result reactions). Track started monitors and
abort/await them all in afterEach (even on failed assertions), reset the shared
auth.test/mock state, and dispose the global Slack test runtime per file via a
new disposeSlackTestRuntime helper. Full Slack suite green across repeated
parallel runs.

* fix(slack): regenerate channel config metadata after rebase

* fix(slack): resolve setup consistent-return and doctor dead-export lint

* style: format install script test

* docs(slack): regenerate docs map for user-identity section

* test(slack): use renamed createSlackBoltApp token param in interop test

The rebase folded main's new wrapReceiver test into the renamed
createSlackBoltApp signature (botToken -> token); update the call site.
2026-07-17 23:23:21 +01:00
iloveleon19 382d570cbf feat(channels): add unified implicit mention policy (#108829)
* feat(mattermost): add thread.requireExplicitMention to opt out of thread auto-follow

Mattermost treats any reply in a thread the bot has participated in as an
implicit mention, so requireMention only gates the first message and the bot
then answers follow-ups addressed to other people for the participation TTL.
Slack exposes channels.slack.thread.requireExplicitMention for exactly this;
Mattermost had no equivalent and its strict schema rejected the key.

Add channels.mattermost.thread.requireExplicitMention (channel + per-account),
mirroring Slack. When set, thread participation no longer counts as a mention.
Default (unset/false) keeps today's auto-follow behavior unchanged.

Related: #108269

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(channels): add implicit mention policy foundation

* feat(channels): unify implicit mention policy

Co-authored-by: leon <dodoma0919@gmail.com>

* refactor(channels): keep implicit policy inside evaluator

* fix(channels): use exported implicit mention type

* chore(channels): satisfy extension lint

* fix(config): break implicit mention type cycle

* fix(plugin-sdk): account for implicit mention config export

* refactor(config): isolate implicit mention schema

* chore(plugin-sdk): align implicit mention surface budget

* fix(config): remove unused schema re-export

---------

Co-authored-by: leon <dodoma0919@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 17:16:01 -07:00
Peter Steinberger b624abfc69 fix(discord): stop channel presence greetings for unrelated guild members (#108448)
* fix(discord): scope presence wakes to channel viewers

* chore: remove release-owned changelog entry

* fix(discord): bound presence permission lookups

* test(discord): bind presence fetch mock

* fix(discord): keep presence lookup overflow retryable
2026-07-15 13:51:48 -07:00
Peter Steinberger a97bdfb687 feat(agents): narrow gateway tool to read-only config
Phase 3 of #107237. Removes config.apply/config.patch/restart from the
regular-agent gateway tool (mirroring Phase 2's update.run removal); only
config.get and config.schema.lookup reads remain. Persistent config changes
and restarts now go exclusively through the human-approved openclaw
delegation path — closing the last unmediated agent config-write surface.
gateway stays owner-only/control-plane gated (config reads expose secrets and
host topology). Legacy setups can re-enable writes via the existing per-agent
tool allowlist; no new config key. Net -2271 LOC.

Refs #107237
2026-07-15 01:56:31 -07:00
clawsweeper[bot] 3a208a5068 fix(discord): prevent presence wake floods after reconnects (#107969)
* feat(discord): throttle online-presence events after gateway reconnects

After a Discord gateway (re)connect the presence replay burst emitted one
system event per member, waking the agent each time. Add a per-account
emission gate: a post-reconnect suppression window (default 5 min), a
sliding-window burst limit (default 8/60s, logged once per episode), and
a configurable per-user greeting cooldown (default 8h). New guild
presenceEvents knobs: cooldownSeconds, reconnectSuppressSeconds,
burstLimit, burstWindowSeconds.

* fix(discord): preserve presence throttle retries

* fix(discord): preserve presence throttle retries

* fix(discord): scope presence throttle per guild

Co-authored-by: openclaw-clawsweeper[bot] <openclaw-clawsweeper[bot]@users.noreply.github.com>

* fix(discord): keep presence gate internals private

Co-authored-by: openclaw-clawsweeper[bot] <openclaw-clawsweeper[bot]@users.noreply.github.com>

---------

Co-authored-by: openclaw-clawsweeper[bot] <openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-14 22:02:53 -07:00
Peter Steinberger f59a0352b3 feat(discord): route online presence arrivals to agents (#107451)
* feat(discord): add online presence agent events

* fix(discord): harden presence event payloads

* fix(discord): satisfy presence lint contracts

* fix(heartbeat): run notification event wakes

* fix(discord): use wake heartbeat contract

* fix(discord): harden presence snapshot delivery

* chore: remove release-owned changelog entry

* fix(discord): remove unused presence type export

* fix(discord): keep presence config below loc limit

* fix(discord): reserve presence cooldown atomically
2026-07-14 07:22:11 -07:00
Peter Steinberger 4a05a087a1 refactor(config): retire flat streaming keys from the last six channel schemas via doctor migration (#105709)
* refactor(config): retire flat streaming keys from the last six channel schemas

signal, irc, nextcloud-talk, whatsapp, googlechat, and mattermost now accept
only the nested streaming.{chunkMode,block.enabled,block.coalesce} shape
(mattermost also drops scalar/boolean streaming); flat spellings migrate via
each channel's defineChannelAliasMigration doctor contract with root seeding
for their wholesale-replace account merges.

* feat(channels): warn once per key when the deprecated flat streaming fallback is used

Bundled schemas now reject the flat delivery keys, so the streaming.ts
fallback only serves external SDK plugin configs; emit a once-per-process
per-key subsystem warning and pin the removal plan to the next release train.

* chore(config): regenerate bundled channel config metadata for nested-only streaming

* docs: describe nested-only channel streaming config and the SDK flat-key deprecation window

* fix(whatsapp): seed migrated named-account streaming from the accounts.default layer

WhatsApp resolution layers accounts.default shared config between root and
named accounts, so doctor-materialized account streaming objects now inherit
default-account settings over root ones; mattermost schema test moves to the
nested-only shape with explicit rejection coverage; scope flat-key deprecation
notes to the pending Matrix/Feishu migrations.

* fix(whatsapp): resolve the default account case-insensitively when seeding migrated streaming

* chore(plugin-sdk): repin API baseline for nested-only channel streaming types
2026-07-12 15:27:28 -07:00
zw-xysk 0b30a3292f docs(slack): fix channel config examples — use 'enabled' instead of 'allow' to match strict schema (#103491)
* docs(slack): fix channel config examples — use 'enabled' instead of 'allow' to match strict schema

* docs(slack): align config reference channel toggle

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-12 08:38:03 +01:00
Peter Steinberger 508f6a2996 refactor(config): retire legacy flat streaming keys to doctor-owned migration (#104693)
* chore(config): regenerate bundled channel config metadata for retired flat streaming keys

* refactor(config): retire legacy flat streaming keys to doctor-owned migration

* fix(config): restore zod locale installer dropped in rebase and repin SDK surface
2026-07-11 18:15:03 -07:00
Peter Steinberger fa77fe10d5 chore: migrate active GPT-5.5 references to GPT-5.6 (#104452)
* chore(models): migrate active GPT-5.5 references

* test(workboard): expect GPT-5.6 Sol default

* chore: keep release notes in PR body

* test(models): align picker fixtures with Sol default

* test: update PDF default model expectation

* test(qa): migrate thinking smoke to Luna

* test(gateway): align mock catalog with Sol default

* ci: retrigger exact-head PR checks

* test(gateway): document default catalog invariant
2026-07-11 06:30:57 -07:00
Eva ae63a48e94 fix(auto-reply): recover stranded message-tool finals by default (#99536)
In messages.visibleReplies "message_tool" sessions, a successful agent turn that produced a substantive private final without calling message(action=send) previously left the user with silence and only an operator log. The gateway now enqueues one protected front-of-queue retry prompting the model to deliver the reply, and falls back to a sanitized visible diagnostic when the retry cannot be enqueued or also strands. Queue overflow protection is unified with the in-flight-aware drop policy (skip in-flight or protected items, reject when nothing is droppable), rejected overflow no longer refreshes the drain debounce, heartbeat turns are excluded from recovery, and recovery retries no longer share the client turn's queued-turn lifecycle.

Fixes #85714

Thanks to Eva (@100yenadmin) for the contribution.
2026-07-10 14:01:01 +05:30
kevinlin-openai 245b91b83d feat(slack): support Enterprise Grid org installs (#102372)
* feat(slack): support Enterprise Grid org installs

* docs: refresh generated docs map

* fix(slack): satisfy enterprise routing CI

* fix(slack): accept org auth without app id

* docs(plugin-sdk): document channel policy hooks

* fix(slack): reuse canonical sender for enterprise replies

* test(slack): fix enterprise sender lint

---------

Co-authored-by: Kevin Lin <kevin@dendron.so>
2026-07-08 23:53:19 -07:00
Peter Steinberger f7d7148cf0 docs: rewrite published docs grounded in current source (#100142)
Source-grounded rewrite of 529 published docs pages with per-unit information-loss verification: 1,713 factual corrections cited to src/**, generated surfaces regenerated, frontmatter titles preserved for i18n, release notes pages untouched. All docs gates green.

Closes #100141
2026-07-05 00:32:47 -04:00
Dizesales ff58d23e8f fix(telegram): resolve local Bot API container file paths against trustedLocalFileRoots [AI-assisted] (#91984)
* fix(telegram): resolve local Bot API container file paths against trustedLocalFileRoots

When the self-hosted telegram-bot-api server runs with --local inside a
container, getFile returns absolute file_path values rooted at the
container data dir (/var/lib/telegram-bot-api/...). The host process
mounts that volume at a different path, so the absolute path never
matches a trustedLocalFileRoots entry and inbound media fails to
materialize (messages reach the agent as bare <media:document>
placeholders without bytes).

Map container-absolute paths back to relative candidates and resolve
them under each trusted root, trying both with and without the
per-token directory segment the local server uses. Relative file_path
values are now also resolved against trusted roots before falling back
to the HTTP file endpoint, which keeps large-file (>20MB) local-mode
downloads working.

Path traversal protections: candidates are normalized, NUL bytes and
dot-segments are rejected, and reads stay behind the trusted-roots
file-access sandbox.

AI-assisted (Claude Code), validated with targeted vitest run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Co-Authored-By: Dizesales <269209351+Dizesales@users.noreply.github.com>

* fix(telegram): map local Bot API container media paths

Co-authored-by: Lucas Magalhaes <ellucasrj@gmail.com>

* chore(config): refresh channel metadata

---------

Co-authored-by: Lucas Magalhaes <ellucasrj@gmail.com>
Co-authored-by: Dizesales <269209351+Dizesales@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-04 17:07:51 -04:00
solodmd cf2efbe5d5 docs(gateway): fix Telegram streaming default in config-channels.md (#98453)
The config example in docs/gateway/config-channels.md incorrectly
listed streaming default as "off". The actual runtime default is
"partial", as confirmed by the Telegram plugin's default resolver.

docs/channels/telegram.md already correctly documents the default
as "partial".

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-01 02:33:24 -07:00
thomas.szbay 9bf681d663 feat(channels): add directUserId support for per-DM model override (#95120)
Add optional directUserId field to ChannelModelOverrideParams so the
shared channels.modelByChannel resolver can match DM-specific config
entries. Callers pass sessionEntry.origin?.nativeDirectUserId.

Closes #53638

Co-authored-by: Thomas Zhengtao <thomas.zhengtao@gmail.com>
2026-06-22 17:26:01 +00:00
Andy Ye 8549a203d4 Honor WhatsApp configured ACP bindings (#92513)
Merged via squash.

Prepared head SHA: 665080f482
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-06-13 18:09:22 -03:00
Omar Shahine bfccbc3fee fix(imessage): harden outbound send transport (#91783)
Merged via squash.

Prepared head SHA: 39ea25767b

Proof:
- Focused tests, docs/config generation, lint/type/doc checks passed before merge.
- ClawSweeper re-review marked proof and patch quality platinum after lobster live send proof.
- Maintainer accepted the `channels.imessage.sendTransport` config surface and compatibility-risk tradeoff.

Lobster proof id: openclaw-lobster-live-proof-c74895c2-b629-4bb0-abcb-e6521069b3d8

Reviewed-by: @omarshahine
2026-06-09 19:09:15 -07:00
Omar Shahine fc6400ede3 fix(imessage): always-on inbound recovery and dedupe (#91335)
* feat(imessage): always-on inbound recovery, deprecate catchup

Replaces the opt-in catchup subsystem with always-on inbound replay
protection that brings iMessage in line with the other channels, and
fixes #89237 (stale backlog dispatched as fresh after bridge recovery).

- New inbound-dedupe.ts: persistent claimable GUID dedupe (claim/commit/
  release) plus a stale-backlog age fence that suppresses live rows whose
  send date is materially older than arrival (logged, never silent).
- monitor-provider: claim at ingestion, carry the exact claimed key on the
  debouncer entry, commit on successful flush / release on dispatch failure
  (per-unit so a coalesced bucket cannot strand a sibling claim). Keeps the
  local startup since_rowid watermark so startup-window rows are not skipped.
- Deprecate catchup: delete catchup.ts + catchup-bridge.ts, remove the
  channels.imessage.catchup schema, cursor migration, and config-guard nag.
  Back-compat: strip the retired key before validation; new imessage doctor
  contract reports + removes it on doctor --fix.
- Docs updated for the new recovery model.

Net -947 prod LOC.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(imessage): recover downtime messages via since_rowid replay

Builds downtime recovery on the new inbound dedupe instead of restoring the
old catchup subsystem. On startup the monitor passes the last dispatched rowid
(a persisted per-account cursor) to imsg watch.subscribe as since_rowid, so imsg
replays the messages that landed while the gateway was down, then tails live.
The GUID dedupe drops anything already handled, so no cursor/retry bookkeeping
is needed.

- recovery-cursor.ts: minimal persisted per-account lastDispatchedRowid.
- monitor-provider: since_rowid = cursor (capped to the most recent
  IMESSAGE_RECOVERY_MAX_ROWS); split the age fence on the startup rowid boundary
  so replayed rows (<= boundary) use the wider recovery window and live rows
  (> boundary) keep the tight #89237 fence; advance the cursor on commit.
- Local only: remote SSH cliPath cannot read chat.db, so it tails from the
  current rowid (suppress-and-move-on) as before.

Restores missed-message recovery that the catchup removal dropped, with no
config and a fraction of the old LOC.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(imessage): make recovery cursor advance failure- and suppression-safe

Addresses two cursor-state regressions in the downtime-recovery path:

- Failed replay rows could be skipped forever: a released (failed) row keeps
  its dedupe claim for retry, but a later successful row in the same flush
  advanced the cursor past it, so the next startup's since_rowid skipped it.
  Hold a per-session floor at the lowest released rowid and never advance the
  cursor past it.
- Suppressed live backlog could be re-delivered after a restart: a live row
  suppressed under the tight live fence was not recorded, so after a restart it
  fell under the wider recovery window (its rowid now below the new boundary)
  and was delivered. Commit its dedupe key on suppression so the recovery
  replay treats it as already handled.

Both caught by Codex autoreview. Adds regression tests for the floor and the
suppression record.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(imessage): bound the GUID-less replay key length

Hash the composite fallback key's variable parts (conversation, sender,
created_at, text) so the key is length-bounded regardless of message text.
The persistent dedupe store already hashes keys internally, so this was not a
live overflow, but the bounded key removes the dependency on that and keeps the
fallback fail-open. Flagged by autoreview.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(imessage): recover downtime messages on remote cliPath setups too

The since_rowid replay runs over the imsg RPC client, so driving it from the
persisted recovery cursor (not the local chat.db boundary) makes downtime
recovery work for remote SSH cliPath gateways — the topology the old RPC-based
catchup served and that the rowid-boundary-only version regressed. Local setups
keep the wider, capped recovery window via the chat.db boundary; remote uses the
live age-fence window. Flagged by autoreview.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(imessage): seed recovery cursor from retired catchup cursor on upgrade

A one-time, self-cleaning migration: when the recovery cursor is empty on the
first startup after upgrade, seed it from the retired imessage.catchup-cursors
lastSeenRowid and consume the legacy entry. Without this a user who had catchup
enabled would not replay messages missed across the upgrade restart. Flagged by
autoreview.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(imessage): preserve catchup recovery on upgrade

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-06-08 16:54:10 +09:00
Andy Ye c317fd2bd7 docs(imessage): document SSH wrapper TCC send failure (#88758) 2026-05-31 23:00:08 -04:00
Ted Li 92b6af76d9 fix(reply): deliver plugin binding replies
Deliver plugin-owned bound-thread replies even when the source room is configured for `message_tool` visible replies. Normal agent final text still stays private unless the agent calls `message(action=send)`.

Document the distinction in the group/channel docs and root routing policy, and keep ambient room-event plus unauthorized text-slash suppression covered by regression tests.

Fixes #87721.
2026-05-31 11:17:45 +01:00
Peter Steinberger 75ea8b5094 docs: clarify message-tool-only visible replies 2026-05-31 10:35:20 +01:00
Peter Steinberger 0cfccdb0c7 fix(codex): keep WebChat delivery hints out of user requests
Land PR #87003 from @ragesaq with a maintainer fix for routed room events.

Co-authored-by: Forge <forge@psiclawops.dev>
2026-05-27 03:44:27 +01:00
Peter Steinberger f4b5e58231 fix: aggressively prune retired model catalogs 2026-05-23 17:29:50 +01:00
Kevin Lin 1008b8213b fix(slack): keep approvals in app conversation threads
* fix(slack): keep plugin approvals in app conversation threads

* fix(slack): preserve plugin approval routing

* fix(slack): keep suppression typing aligned

* fix(slack): suppress native dm approval fallback

* fix(slack): suppress stored native approval fallback
2026-05-21 21:51:34 -07:00
OpenClaw Contributor 4c6fe55d20 fix(discord): cap component ttl at one day 2026-05-21 21:54:30 +01:00
OpenClaw Contributor c17a48ccfd docs(discord): document component ttl config 2026-05-21 21:54:30 +01:00
Peter Steinberger e0b53cae41 docs: remove stale owner tool wording 2026-05-21 15:14:48 +01:00
Yuval Dinodia 324a95db8b docs(gateway): troubleshoot group @mention silent suppression (#77052)
Summary:
- Adds a symptom-keyed troubleshooting block to `docs/gateway/config-channels.md` for group/channel @mentions that log `queuedFinal=false, replies=0` and explains the `visibleReplies` remedies.
- Reproducibility: yes. for the docs gap and source behavior: current main lacks the exact symptom-keyed troubleshooting entry, and the resolver/tests show when message-tool mode suppresses automatic final delivery.

Automerge notes:
- PR branch already contained follow-up commit before automerge: docs(gateway): make group reply fix restart conditional
- PR branch already contained follow-up commit before automerge: docs(gateway): qualify direct-chat reply default in troubleshooting
- PR branch already contained follow-up commit before automerge: docs(gateway): align group reply troubleshooting with current automat…
- PR branch already contained follow-up commit before automerge: docs(gateway): scope group reply suppression cause to group config

Validation:
- ClawSweeper review passed for head e60ae89b20.
- Required merge gates passed before the squash merge.

Prepared head SHA: e60ae89b20
Review: https://github.com/openclaw/openclaw/pull/77052#issuecomment-4367898048

Co-authored-by: yetval <yetvald@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
2026-05-18 17:03:53 +00:00
Peter Steinberger c32878d1b7 fix(messages): keep Codex source replies tool-gated 2026-05-18 13:51:21 +01:00
Peter Steinberger 4b35003051 fix(messages): keep Codex direct replies automatic 2026-05-18 13:51:21 +01:00
Peter Steinberger 1e5450f23e fix(messages): keep group visible replies automatic by default (#83498)
* fix(messages): keep group visible replies automatic by default

* fix(messages): keep unauthorized slash turns quiet

* fix(messages): return boolean from slash guard

* test(messages): narrow visible reply fixtures

* test(messages): align completion delivery default
2026-05-18 09:48:58 +01:00