Commit Graph

986 Commits

Author SHA1 Message Date
Peter Steinberger
d395a8e6ec docs(pairing): correct setup-code expiry payload (#103943) 2026-07-10 21:58:28 +01:00
xingzhou
8d5f7e27b2 fix(sms): replayed Twilio webhooks process again after high inbound traffic (#101107)
* fix(sms): replayed Twilio webhooks process again after high inbound traffic

* fix(sms): harden Twilio replay saturation

* test(sms): expose response header spy

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 17:58:53 +01:00
Yuval Dinodia
b7ab62c2cf fix(mattermost): preserve text-block boundaries in draft preview (#87322) (#87449)
* fix(mattermost): preserve text-block boundaries in draft preview (#87322)

* fix(mattermost): preserve block preview boundaries

* fix(mattermost): reset progress at tool boundaries

* docs(plugin-sdk): refresh API baseline

* fix(mattermost): group parallel tool previews

* fix(mattermost): stage tool previews before awaits

* fix(mattermost): satisfy tool boundary return contract

* fix(mattermost): serialize preview block generations

Co-authored-by: Yuval Dinodia <yetvald@gmail.com>

* fix(mattermost): preserve complete block previews

* test(agents): align streaming assertions

* test(telegram): align reply pipeline mock

* fix(plugin-sdk): keep reply prefix options compatible

* test(mattermost): exercise threaded final participation

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 14:32:11 +01:00
Peter Steinberger
b07ebe3ff3 feat: correlate managed agent requests (#103476) 2026-07-10 08:42:55 +01:00
Peter Steinberger
fa3eb673cd feat(slack): accept spoken mentions in audio clips (#103416)
* feat(slack): support spoken audio mentions

* chore: keep release notes in PR body
2026-07-09 22:33:26 -07:00
iloveleon19
70a7e6e658 feat(mattermost): add opt-in DM threading by chat type (#98111)
* feat(mattermost): add opt-in DM threading via dmReplyToMode

Resolves #93203.

Mattermost direct messages are hardcoded non-threaded: resolveMattermostReplyToMode
returns "off" for direct chats before consulting config, and the reply-root /
effective-reply resolvers short-circuit for direct chats. So every DM accretes into
one ever-growing session with unbounded per-session token usage, with no way to
isolate each DM topic the way groups/channels (and Slack) can.

Add channels.mattermost.dmReplyToMode (same enum as replyToMode), default "off" so
existing flat-DM deployments are unchanged. When set to "first"/"all", a DM @mention
starts an independent, thread-scoped session:

- resolveMattermostReplyToMode: direct chats return config.dmReplyToMode ?? "off".
- resolveMattermostEffectiveReplyToId: direct early-return gated on replyToMode "off"
  (the value already reflects dmReplyToMode for direct chats).
- resolveMattermostReplyRootId: direct early-return gated on the absence of a thread
  root (a DM carries one only when DM threading is enabled).
- New DM threads start fresh (no parent-session inheritance) so each topic is isolated;
  a threaded DM keeps its own history key while a flat DM root keeps none.

Default-off preserves the documented flat-DM contract, so this changes no existing
behavior. Adds unit coverage and documents the opt-in. The only open question is the
knob shape (dmReplyToMode enum vs a boolean dmThreading) — happy to adjust.

Refs #65729.

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

* fix(mattermost): register dmReplyToMode in config schema

dmReplyToMode was wired into the account config type and reply
resolution but never added to MattermostConfigSchema, so setting it in
openclaw.json failed config validation ("must not have additional
properties: dmReplyToMode") and the gateway refused to start — the knob
could not actually be enabled. Register it in the schema, regenerate the
bundled channel config metadata and doc baseline, and add a
config-schema test.

* fix(mattermost): thread direct reply transport when dmReplyToMode is on

resolveReplyTransport nulled the direct reply root/thread id
unconditionally, so routed replies and message-tool follow-ups in an
opted-in DM thread were still sent flat even when the effective
replyToMode was first/all. Keep direct transport flat only when the mode
is off (the historical contract) and preserve the thread root otherwise,
matching the monitor-level DM threading gates. Adds channel.test.ts
coverage for resolveReplyTransport.

* fix(mattermost): use per-chat reply mode overrides

* fix(mattermost): bound direct thread history

* chore(config): refresh docs baseline

---------

Co-authored-by: leon <leon@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 06:19:03 +01:00
Peter Steinberger
add2c586c2 feat(slack): support native chart presentations (#102635) 2026-07-10 04:05:23 +01:00
Ayaan Zaidi
e6a9a5d182 docs(web): document Docker host-networking requirement for the Telegram Mini App 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
b2ee68780c docs(web): document Telegram dashboard entry 2026-07-10 07:53:37 +05:30
colton-octaria
dc8c0aaaf2 fix(msteams): recover inbound channel and group-chat files safely (#90738)
* fix(msteams): read file attachments on Teams channel messages

Three bugs blocked reading files attached to channel messages:
- Graph /teams/{id} used channelData.team.id (the 19:..@thread.tacv2 thread id)
  instead of team.aadGroupId (the AAD group GUID) -> 400.
- The Graph fetch was gated on an <attachment id> HTML marker that channel
  @mention activities don't carry -> fetch skipped.
- A thread reply was fetched at /messages/{replyId} (404) then fell back to the
  bare thread root, returning the root's file for every reply. Replies live at
  /messages/{root}/replies/{replyId}.

Fixes #89594

* fix(msteams): gate Graph media fallback on text/html stub; run trigger tests in channel context

* fix(msteams): canonicalize Graph attachment recovery

Build one canonical Graph message URL per Teams activity, recover marker-free channel and group-chat file shares, and retain bounded current-main attachment handling.

Co-authored-by: Colton Williams <colton@coltons-apps.tech>

* fix(msteams): canonicalize Graph media recovery

Recover channel and group-chat files through one fail-closed Graph identity path, bound inbound enrichment, and remove invalid app-only Graph fallbacks.

Co-authored-by: Colton Williams <colton@coltons-apps.tech>
Co-authored-by: Joshua Packwood <joshua.packwood@gmail.com>

---------

Co-authored-by: Colton Williams <colton@coltons-apps.tech>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Joshua Packwood <joshua.packwood@gmail.com>
2026-07-10 02:34:12 +01:00
Peter Steinberger
e6a8feb9c2 refactor(pairing): move device pairing store to shared SQLite state DB (#103160)
* refactor(pairing): move device pairing store to shared SQLite state DB

Device pairing, pending requests, and bootstrap tokens now live in the
device_pairing_* / device_bootstrap_tokens tables of state/openclaw.sqlite
instead of devices/{paired,pending,bootstrap}.json. Gateways import legacy
paired records once at startup (before the node-surface fold) and archive
the JSON files with a .migrated suffix; transient pending/bootstrap rows
are dropped. The unshipped node_pairing_* tables are removed from the
schema and dropped from existing DBs. Doctor now flags un-imported legacy
store files instead of corrupt-JSON reads.

* refactor(pairing): drop stale awaits now that store persistence is synchronous

* refactor(pairing): extract leaf record types to break store/domain module cycle
2026-07-10 01:46:56 +01:00
Peter Steinberger
e7a6ed8eb6 chore(pairing): retire vestigial node token plumbing and flatten cleanup claims (#103140) 2026-07-09 23:48:01 +01:00
Peter Steinberger
8985598302 fix(gateway): stop paired-device duplication and redesign the Nodes page (#102810)
* fix(gateway): prune superseded silent device pairings on auto-approve

* feat(ui): unified nodes & devices inventory with dedupe and cleanup

* docs: nodes page inventory + silent pairing supersede cleanup

* refactor(gateway): run silent-pairing prune after approval broadcast

* fix(ui): surface node list errors on the nodes inventory card

* fix(gateway): restrict pairing auto-prune to same-host silent approvals

* fix(gateway): report live device connections and guard pairing prune races

* docs(ui): document bulk-cleanup name-collision tradeoff

* fix(gateway): avoid map-spread when marking live device connections

* docs: regenerate docs map
2026-07-09 15:40:30 +01:00
Alix-007
64e80888d4 fix(qqbot): bound speech transcription requests (#102028)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 13:25:29 +01:00
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
e2a4973edf docs(slack): explain voice input and audio clips (#102410)
* docs(slack): document voice input support

* docs: refresh generated map

---------

Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-08 21:28:49 -07:00
Omar Shahine
91a0ebbce6 Improve iMessage imsg setup and skill ownership (#101407)
Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
2026-07-07 14:13:37 -07:00
Vincent Koc
f0564943a7 docs(openai): refresh realtime 2.1 examples 2026-07-06 23:22:33 -07:00
Jesse Merhi
4112e3a0f3 Add native Signal reply quotes (#95718)
* feat(signal): quote native replies

* Fix Signal native reply edge cases

* fix(signal): tighten native reply quotes

* fix(signal): harden native reply quotes

* fix(signal): preserve approval reaction state

* fix(signal): target native replies to edited messages

* fix(signal): preserve plugin approval reaction kind

* fix(signal): keep edit event reply ids distinct
2026-07-07 13:49:13 +10:00
Peter Steinberger
037ad2bdfb feat(telegram): offer BotFather web app flow in setup help and docs (#100540) 2026-07-06 07:48:55 +01:00
Peter Steinberger
a6e19fe014 fix(slack): avoid repeated thread root media (#100516)
* fix(slack): avoid repeated thread root media

* test(slack): cover reset thread media seeding
2026-07-06 02:17:44 +01:00
scoootscooob
7e7fc0075e [codex] Honor all ack scope for room events (#87433)
* fix(discord): honor all ack scope for room events

* fix(channels): align all ack scope for room events

* fix(channels): centralize ambient ack scope

* test(telegram): restore room-event ack fixture

* test(discord): satisfy promise executor lint

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 01:28:41 +01:00
Peter Steinberger
4da855a1ff fix(slack): prefer native status by default (#100462)
Co-authored-by: Peter Steinberger <steipete@openai.com>
2026-07-05 23:10:08 +01:00
ragesaq
a08ca5fc5d feat(clickclack): stamp model/thinking attribution onto agent posts
Wires replyOptions.onModelSelected so the resolved provider/model and
thinking level for each turn (including after fallback) are sent as
author_model / author_thinking fields on activity rows and the final
reply. Servers without these columns ignore the unknown JSON fields, so
the wire shape is backward compatible; servers that persist them get
per-message attribution.
2026-07-05 09:32:37 -07:00
ragesaq
339cc4f12a fix(clickclack): address review — docs, lint lanes, activity coalescing
- docs: document agentActivity option, the non-inherited agent_activity:write
  scope, default-off and best-effort degradation behavior
- activity: type the enqueue catch parameter as unknown (lint lane)
- activity: treat toolCallId as opaque; normalize only itemId lane prefixes
- activity: skip identical/stale-shorter commentary snapshots so no
  redundant PATCHes queue
- http-client: fail fast when createActivityMessage has no channel or
  conversation target; narrow mocked request bodies before JSON.parse
2026-07-05 09:32:37 -07:00
Peter Steinberger
862de9f1a1 fix(pairing): advertise reachable Tailnet routes (#100317)
* fix(pairing): advertise reachable tailnet routes

* fix(pairing): satisfy native and SDK checks

* fix(ios): cancel stale pairing route probes

* test(pairing): document LAN-only Serve fallback

* fix(ios): preserve pairing result initializer
2026-07-05 07:43:43 -07:00
Vishal Jain
4c42815348 fix(whatsapp): bound reconnect catch-up replies (#80642)
* fix(whatsapp): bound reconnect catch-up replies

Co-authored-by: Vishal Jain <jainvishal2212@gmail.com>

* docs(changelog): defer reconnect entry to aggregate

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-05 06:34:57 -07:00
Peter Steinberger
c00d79a1d1 fix(imessage): false group drop-all startup warning when groupAllowFrom is set without groups (#100046)
* fix(imessage): only warn about empty group allowlist when messages actually drop

With groupPolicy="allowlist", a non-empty effective groupAllowFrom admits
group messages even when channels.imessage.groups is empty (senderFilterBypass
in src/config/group-policy.ts), so the startup warning "Every inbound group
message will be dropped" fired as a false positive for that configuration.

The warning now mirrors the runtime gate's effective sender allowlist (same
allowFrom fallback + legacy chat-target merge) and fires only when both the
groups registry and the effective group sender allowlist are empty - the only
startup-provable drop-all config. The message now names groupAllowFrom as the
fix, since adding groups entries alone leaves the sender gate blocking.

Docs: describe the two group gates' warnings separately with per-warning
remedies instead of implying both fire for the same config.

* docs(imessage): format migration guide

* fix(imessage): warn on empty group sender allowlist

* docs: move iMessage fix to unreleased
2026-07-05 04:21:22 -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
truiem-bot
420b3cdd29 feat(slack): support per-channel replyToMode (#82253)
* feat(slack): support per-channel replyToMode

* fix(slack): align per-channel threading contexts

* fix(slack): preserve queued channel reply mode

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-04 23:41:24 -04:00
Jeff Sutherland
1945a8e5de Warn on shared Slack Socket Mode connections (#79938)
* Warn on shared Slack Socket Mode connections

* fix(slack): harden shared socket diagnostics

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-04 22:41:18 -04:00
Hana Chang
4ec7842be0 feat(slack): add ignoreOtherMentions channel config (#53467)
* feat(slack): add ignoreOtherMentions channel config

Mirrors the existing Discord `ignoreOtherMentions` option for Slack
channels. When set on a channel entry, drop channel/group/MPIM messages
that mention another user or subteam but not this bot — the inverse of
`requireMention`. Useful in busy channels where the bot would otherwise
reply to side conversations.

Implementation lives in `prepareSlackMessage` right after the
`allowBots: "mentions"` bot-drop gate and before the `shouldRequireMention`
non-mention drop, so it integrates with the new `messageIngress` ingress
pipeline. The gate is conditional on `canDetectMention` (botUserId
resolvable via `auth.test` or explicit mention regexes configured) to
avoid false drops when we have no reliable way to tell bot vs non-bot
mentions apart.

Slack implicit mentions (thread participation) are intentionally NOT
respected here — they fire for every message in a bot-participated
thread, so honoring them would defeat the feature in any active thread.
The gate matches on `wasMentioned` (explicit) and `hasAnyMention`, with
the existing `shouldBypassMention` override (e.g. authorized commands)
also respected.

Includes config types, zod schema, channel-config resolution,
prepare-message implementation, full test coverage in
`prepare.test.ts`, regenerated channel + docs baselines, and Slack
docs entry.

* refactor(slack): harden other-mention filtering

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-04 20:08:14 -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
Barbara Kudiess
129e0a8cf0 feat: pair mobile devices from the Control UI (#94672)
* feat(gateway): add device.pair.setupCode RPC for connect QR

The OpenClaw mobile/companion app scans a pairing setup code to connect to the gateway, but that code + QR could only be produced by the openclaw qr CLI (ASCII to stdout). Non-terminal clients driving onboarding had no way to display the connect QR.

Add a device.pair.setupCode gateway method that reuses resolvePairingSetupFromConfig + encodePairingSetupCode + renderQrPngDataUrl to return { setupCode, qrDataUrl?, gatewayUrl, auth, urlSource }. The embedded setup code mints a short-lived bootstrap token that hands off broad operator scopes (read/write/approvals/talk.secrets), so the method requires operator.admin (matching the wizard methods a companion already uses) and is not advertised. auth is a label only; the gateway credential is never returned, and an oversized QR is omitted so the response always satisfies the result schema.

Refs #94661.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(ui): pair mobile devices from Control UI

* docs: refresh generated docs map

* docs: clarify mobile QR auto-connect

* docs: clarify mobile QR auto-connect

* docs: clarify mobile QR auto-connect

---------

Co-authored-by: Barbara Kudiess <76582160+bkudiess@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-04 12:41:14 -04:00
Peter Steinberger
82610d3b15 feat(whatsapp): add requester-bound MeowCaller calls (#99635)
* feat(whatsapp): add requester-bound MeowCaller calls

* fix(whatsapp): align MeowCaller CLI contract

* test(whatsapp): narrow MeowCaller audio path

* fix(whatsapp): budget MeowCaller setup phases

* feat(whatsapp): gate experimental calls

* fix(whatsapp): use managed call temp storage

* fix(whatsapp): preserve channel entry boundary
2026-07-04 02:19:28 -07:00
Jesse Merhi
8c915f0685 feat(signal): add target aliases (#95738)
* feat(signal): add target aliases

* fix(signal): canonicalize alias delivery targets

* fix(signal): harden alias target resolution

* test(signal): cover formatted media aliases

* test(signal): align approval alias proof with request shape

* Reuse Signal alias map for directory listing
2026-07-03 23:40:10 +10:00
Jesse Merhi
8abc633cf8 Add Signal status reaction lifecycle (#98791) 2026-07-03 21:42:39 +10:00
Jesse Merhi
64318d7624 Rework Android gateway onboarding setup (#98752)
* feat(android): rework gateway onboarding setup

* fix(android): restore protocol mismatch onboarding guidance

* fix(android): sync onboarding native i18n

* fix(android): preserve LAN manual setup prefill

* fix(android): refine onboarding node approval step

* fix(android): polish onboarding recovery actions

* test(android): cover onboarding protocol mismatch copy

* fix(android): separate onboarding node approval

* fix(android): guard onboarding node approval transitions

* fix(android): keep onboarding approval states reachable

* fix(android): wait for node access before onboarding continue

* fix(android): refresh node approval after operator handoff

* fix(android): refresh onboarding approval states

* fix(android): require approval after onboarding permission changes

* fix(android): keep onboarding approval gates active

* fix(android): preserve permission reapproval state

* fix(android): skip node approval on legacy gateways

* fix(android): wait for node approval refresh

* fix(android): preserve camera setting on upgrade

* fix(android): avoid stuck approval check spinner

* fix(android): request talk secrets on operator connects

* fix(android): avoid missed node approval completion

* fix(android): keep nearby LAN setup local

* fix(android): complete onboarding after node approval

* fix(android): reconcile onboarding with gateway auth plans

* chore(android): refresh native i18n inventory after rebase

* Fix Android onboarding review edge cases

* Fix native i18n onboarding sentinels
2026-07-03 21:20:12 +10:00
Suhruth Vuppala
4440226d52 test(discord): clarify and guardrail gateway proxy selection (#99126)
* feat(discord): add HTTP_PROXY/HTTPS_PROXY env fallback for gateway WebSocket

Discord Gateway WebSocket connections now honor HTTP_PROXY/HTTPS_PROXY
environment variables as fallback before direct connection, matching the
existing pattern from Discord REST API and WhatsApp.

This enables Discord channel deployment in Kubernetes/OpenShift environments
with network policy egress restrictions, removing the need for broad :443
egress as a workaround.

- Add createEnvProxyDiscordGatewayAgent() helper (mirrors rest-fetch.ts pattern)
- Try env proxy before direct HttpsAgent in createDiscordGatewayPlugin()
- Explicit channels.discord.proxy still overrides env proxy
- Add formatErrorMessage and resolveEnvHttpProxyAgentOptions imports

Fixes #98266

* test(discord): keep gateway proxy explicit

Signed-off-by: sallyom <somalley@redhat.com>

* fix(discord): allow explicit remote proxy URLs

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: sallyom <somalley@redhat.com>
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-07-02 20:27:19 -05:00
Ayaan Zaidi
dad7768da8 docs(telegram): document group history removal 2026-07-02 09:22:59 -07:00
Mark
5db7c3797d Fix Telegram plugin callback routing (#97174)
* fix telegram plugin callback routing

* Add Telegram callback proof coverage

* Fix proof script lint

* Fix Telegram proof CI regressions

* test: fix telegram callback proof CI regressions

* fix: retire registry-owned callbacks

* fix: retire registry-owned callbacks

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-01 19:49:54 +01:00
wm0018
8a519a9abe docs(matrix): document missing streaming.progress mode, progress sub-fields, and mentionPatterns config (#98318)
* docs(matrix): document missing streaming.progress mode, progress sub-fields, and mentionPatterns config

* docs: clarify Matrix progress labels

---------

Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
2026-07-01 02:49:23 -07:00
Omar Shahine
c92c33d108 feat(imessage): native poll support — create, read, vote (#98421)
* feat(imessage): add native poll action

Wire the imsg CLI 'poll send' bridge command into the iMessage channel
message-tool action surface, mirroring the existing Discord poll action.
Adds the 'poll' action (gate: polls), a sendPoll runtime, selector-gated
capability advertisement (pollPayloadMessage), config type + zod schema,
regenerated channel metadata, docs, and tests.

* feat(imessage): read inbound polls, vote, and suppress vote echo

Builds on the native poll send action:

- Inbound polls now render to the agent as a readable line (question +
  numbered options + tallies) instead of the raw 0xFFFD balloon placeholder,
  so a received poll no longer reads as an empty message.
- New `poll-vote` action casts a vote via `imsg poll vote`, resolving a
  1-based option index / text / UUID to the poll's option identifier.
- message_tool_only echo guard: the model tends to narrate its choice in a
  text reply right after voting ("Blue."), which is redundant since the vote
  shows on the poll. A new `poll_vote_echo` suppression reason (alongside
  inbound_metadata_echo / internal_runtime_context_echo) drops a send/reply
  that exactly restates the just-cast vote, using the option label imsg
  returns. Extra content passes through untouched.

* fix(imessage): gate poll-vote on imsg poll.vote rpc capability

Released imsg carries the pollPayloadMessage selector (poll create) but
predates the poll.vote CLI/RPC. Gating both poll and poll-vote on that
selector alone would advertise a vote action the released CLI rejects.
Gate poll-vote additionally on the advertised poll.vote rpc method so this
plugin can ship ahead of the imsg release.

* fix(imessage): enforce poll.vote capability at execution, not just discovery

Codex review flagged the discovery gate as bypassable: a caller that already
knows action=poll-vote skips describeMessageTool and reaches handleAction
directly. Add the same imessageRpcSupportsMethod(status, 'poll.vote') check in
the poll-vote execution path (after assertPrivateApiEnabled), so a direct
dispatch on released imsg fails closed with a clear message instead of an
opaque CLI rejection. Adds a negative handleAction test.

* fix(imessage): harden native poll support

* fix(message): validate targets before channel discovery

* fix(message): validate targets before channel discovery

---------

Co-authored-by: Omar Shahine <lobster@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-01 10:48:32 +01:00
Marcus Castro
fa3c9de459 test(qa-lab): harden whatsapp qa scenarios (#95622)
* fix(whatsapp): preserve group participant identity in QA driver

* fix(whatsapp): infer same-chat action targets

* test(qa-lab): record whatsapp scenario posture

* test(qa-lab): harden whatsapp live scenario coverage

* docs(qa): describe whatsapp qa lane coverage
2026-07-01 00:01:09 -03:00
wm0018
ff1e7e1305 docs(telegram): correct errorPolicy values and defaults 2026-06-29 01:20:44 -07:00
wm0018
293f0369d0 docs(feishu): remove nonexistent disabled dmPolicy option 2026-06-29 01:05:03 -07:00
slammajamma28
68ad8dacc0 fix(docs): Fix formatting on permissions for Discord bot (#97584)
* Fix required formatting text permissions for Discord bot

* remove whitespace
2026-06-28 18:30:36 -07:00
黄伟浩
f4201578e5 fix(matrix): warn on accumulated token storage roots (#97353) 2026-06-28 12:34:52 -07:00
Naseem Muhammad
9ff8510f52 fix path to Discord Developer Mode in setup guide (#97336) 2026-06-28 11:03:25 -07:00
Omar Shahine
f2af052cee perf(imessage): show typing sooner for slow replies (#95621)
Merged via squash.

Prepared head SHA: 65e9ad10fd
Co-authored-by: omarshahine <10343873+omarshahine@users.noreply.github.com>
Co-authored-by: omarshahine <10343873+omarshahine@users.noreply.github.com>
Reviewed-by: @omarshahine
2026-06-24 15:31:48 -07:00