Commit Graph

38 Commits

Author SHA1 Message Date
Ayaan Zaidi 73d4c07bd5 fix(delivery): record ambiguous final loss as durable notice debt (#121833)
A final reply whose platform send was accepted but whose response was lost
previously ended in silence. Custody that stays unknown after a claimed send
now records durable pendingDeliveryNotice debt; the next same-route turn
delivers one "could not confirm delivery" notice and acknowledges it into the
transcript. Restart recovery completes ambiguous sessions with the same debt
instead of a fire-and-forget notice; the debt survives reset and rollover, and
suppressed notice sends retain it instead of faking delivery. Permanent typed
no-send rejections settle as terminal suppression (no replay, no false
notice); retryable ones restore prepared custody for safe replay. Google Chat
media-only rejections use the typed no-send contract; Telegram native-command
replies join pending-final custody.

Fixes #80362

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-11 09:25:04 +00:00
sunlit-deng 6287c88c3b fix(googlechat): reject invalid UTF-8 in API JSON responses (#120239)
… regression

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-08 20:54:17 -05:00
Leon-SK668 d64f5b6a09 fix(googlechat): redact reflected credentials in API errors (#119965)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-06 18:21:13 -05:00
Peter Steinberger 554968fba6 fix(googlechat): recover durable lanes after oversized attachments (#118986) 2026-08-03 15:12:17 -07:00
Javier Ailbirt 7563e40e47 fix(googlechat): drop invalid thread resource names before send (#108324)
Reply routing can hand sendGoogleChatMessage a `thread` that is not a
valid `spaces/{space}/threads/{thread}` resource name — a bare id, a
`spaces/{space}/messages/{message}` name, or a thread from a different
(or wrongly-cased) space. The Chat API rejects the whole request with
`400 INVALID_ARGUMENT`, so the reply is never delivered even though the
agent already produced it (and did any side effects).

Guard the send so the `thread` field and the messageReplyOption fallback
are applied only when the thread is a well-formed name belonging to the
target space; otherwise post to the space as a new thread. Revives the
approach of #28153 (auto-closed as stale) and addresses the failure mode
behind #64313.
2026-08-01 11:59:08 -07:00
NIO 0316368518 fix(googlechat): cancel unread fetchOk bodies before release (#111290)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-29 07:34:19 -04:00
sunlit-deng 7ebd486ed1 fix(googlechat): media downloads can grow unbounded without a size cap (#98425)
* fix(googlechat): bound uncapped media downloads

* fix(googlechat): align media download cap
2026-07-27 23:29:00 -04:00
Josh Avant fbd330b7aa fix(channels): honor configured read target policies (#99905)
* fix(channels): enforce configured read targets

* test(channels): align policy checks with boundaries

* fix: bind channel reads to trusted turn context

* test: satisfy gateway lint

* fix: narrow message action channel imports

* fix(feishu): authorize message reads before provider access

* fix(slack): await reaction clear authorization

* fix(channels): align provider action contracts

* fix(matrix): read direct-room account data before sync

* fix(channels): reject unsupported attachment actions early

* fix: restore trusted operator conversation reads

* fix(matrix): authorize pin actions before provider reads

* fix: preserve trusted channel read workflows

* fix(discord): resolve current channel ids consistently

* fix(agents): preserve message action turn capability

* fix(plugins): enforce host-owned read provenance

* fix(channels): harden Teams and Discord read policy

* fix(channels): preserve exact-current action compatibility

* fix(imessage): authorize trusted current chat aliases

* fix(channels): preserve normalized current aliases

* fix(channels): preserve external current target aliases

* fix: reconcile channel policy with current main

* fix(discord): isolate DM read policy

* fix(channels): enforce provider read gates

* fix(gateway): await serialized message action identity tokens

* fix(ci): refresh channel protocol contracts
2026-07-10 22:29:37 -05:00
NIO 2d5dd6c035 fix(googlechat): bound control and media requests (#102227)
* fix(googlechat): add 30 s request timeout to withGoogleChatResponse

* fix(googlechat): satisfy ResolvedGoogleChatAccount in api.test.ts

* fix(googlechat): bound control and media requests

Co-authored-by: NIO <nocodet@mail.com>

---------

Co-authored-by: NIO <nocodet@mail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 14:49:14 +01:00
Peter Steinberger a2a68d154b fix(agent): preserve explicit recipient sessions (#101507)
* fix(agent): honor recipient session routing

Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: pingfanfan <pingfan.work@gmail.com>

* fix(agent): preserve canonical recipient routes

* fix(agent): require exact recipient routes

Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>

Co-authored-by: pingfanfan <pingfan.work@gmail.com>

* fix(agent): harden recipient route resolution

* fix(imessage): require canonical recipient handles

* fix(agent): refine provider recipient exactness

* fix(agent): bound direct alias session routing

* fix(signal): preserve direct alias route type

* fix(agent): honor binding-scoped recipient sessions

* fix(routing): honor configured main session aliases

* fix(clickclack): align account-owned session routes

* fix(twitch): preserve canonical recipient sessions

* fix(routing): isolate stable outbound identities

* chore: defer recipient session changelog

* fix(sms): use dedicated channel SDK facade

---------

Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: pingfanfan <pingfan.work@gmail.com>
2026-07-07 10:07:13 +01:00
wangmiao0668000666 4f3d81b918 fix(googlechat): replace unbounded response.json() with readProviderJsonResponse (#96772)
* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's #96042, #96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.

* fix(googlechat): add inline bounded-read regression tests

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

* fix(googlechat): remove unused variable flagged by oxlint

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

* fix(googlechat): bound api error body reads

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-06-27 08:11:10 +08:00
Franco Viotti 7305d9baca fix(googlechat): return sent thread metadata
Return Google Chat message and thread metadata from message sends, and cover the action/API result shape in tests.
2026-06-16 06:23:07 +08:00
Kevin Lin d7759c6a35 feat(googlechat): add native approval cards
## Summary

- Adds native Google Chat approval cards for exec and plugin approval requests that originate from Google Chat spaces or threads.
- Uses opaque server-side action tokens for Google Chat `cardsV2` button callbacks and updates delivered approval messages after resolution or expiry.
- Preserves the shipped Google Chat typing-message default while keeping approval cards on the channel-local native path.
- Suppresses duplicate manual `/approve ...` follow-up delivery inside `extensions/googlechat/` when the native card path owns the approval prompt.
- Documents Google Chat native approval behavior and the `typingIndicator: "message"` default.

## Linked context

Which issue does this close?

Closes #

Which issues, PRs, or discussions are related?

Related Spec 24.8: Google Chat native approval cards.

Was this requested by a maintainer or owner?

Requested by maintainer in the Codex task thread.

## Real behavior proof (required for external PRs)

- Behavior addressed: Google Chat exec and plugin approvals render as native cards and resolve through Google Chat button clicks. The latest change verifies an exec approval card is not accompanied by a duplicate manual `/approve` instruction bubble.
- Real environment tested: OpenClaw dev profile with a real Google Chat DM to the OpenClaw app, local gateway behind a temporary Cloudflare quick tunnel, and Arc/Computer Use against the signed-in Google Chat session.
- Exact steps or command run after this patch: Rebuilt the gateway runtime, started the dev-profile gateway with the Google Chat webhook routed through the tunnel, sent a fresh exec request from Google Chat, verified only the native approval card appeared, clicked `Allow Once` in Google Chat, and checked the command output reply plus marker file.
- Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output): Latest proof used nonce `GCHAT_NODOUBLE_LIVE_20260604070730`, approval id `949bc08c-9e57-47c0-b045-137603782292`, and proof directory `.mem/main/proofs/demo-89502-dev-gchat-exec-approval-no-double-send-channel-race/`. `raw/google-chat-gchat-nodouble-request-card-only-clean.png` shows the fresh user message followed by a single native `Exec Approval Required` card with `Allow Once`/`Deny` and no manual `/approve` follow-up bubble. `raw/google-chat-gchat-nodouble-resolved-clean.png` shows the card edited to `Exec Approval: Allowed once` and the final successful command reply. `raw/gchat-nodouble-live-filtered-log.txt` contains `googlechat approval resolved id=949bc08c-9e57-47c0-b045-137603782292 decision=allow-once`. `raw/marker-file-check.txt` records `/tmp/openclaw-gchat-no-double-GCHAT_NODOUBLE_LIVE_20260604070730` as created.
- Observed result after fix: The approval prompt posted as a native Google Chat card only. No duplicate manual approval-instruction bubble was sent. Clicking `Allow Once` resolved the approval through the gateway and OpenClaw replied with the successful exec output in the same Google Chat DM.
- What was not tested: A persistent production Google Chat app URL; live proof used a temporary Cloudflare tunnel for the local dev callback.
- Proof limitations or environment constraints: Video was not captured for the final resumed manual UI run; still screenshots, gateway/proxy logs, a marker-file artifact, and Showboat verification were captured.
- Before evidence (optional but encouraged): Before the final channel-local suppression path, Google Chat could show both the native approval card and a separate manual `/approve` instruction bubble.

## Tests and validation

Which commands did you run?

- `node scripts/build-all.mjs gatewayWatch`
- `node scripts/run-vitest.mjs extensions/googlechat/src/monitor-webhook.test.ts extensions/googlechat/src/monitor.test.ts extensions/googlechat/src/monitor.reply-delivery.test.ts extensions/googlechat/src/monitor-durable.test.ts extensions/googlechat/src/approval-card-actions.test.ts extensions/googlechat/src/approval-handler.runtime.test.ts extensions/googlechat/src/approval-native.test.ts extensions/googlechat/src/approval-card-click.test.ts extensions/googlechat/src/channel-config.test.ts extensions/googlechat/src/targets.test.ts`
- `git diff --check`
- `pnpm docs:list`
- `uvx showboat --workdir .mem/main/proofs/demo-89502-dev-gchat-exec-approval-no-double-send-channel-race verify .mem/main/proofs/demo-89502-dev-gchat-exec-approval-no-double-send-channel-race/raw/showboat-summary.md`
- Live dev-profile Google Chat proof described above.

What regression coverage was added or updated?

- Added Google Chat native approval capability, runtime delivery, card token, and card-click resolver tests.
- Added in-flight native card send suppression coverage so manual follow-up text is suppressed while native card delivery is pending.
- Added cleanup coverage so manual follow-ups are restored if native card send fails.
- Updated webhook ACK coverage for card-click events and default typing-indicator behavior coverage.

What failed before this fix, if known?

Google Chat could deliver the native approval card and still allow a model/message-tool manual `/approve` follow-up to appear as a second visible bubble.

If no test was added, why not?

Tests were added for the changed runtime and webhook behavior.

## Risk checklist

Did user-visible behavior change? (`Yes/No`)

Yes.

Did config, environment, or migration behavior change? (`Yes/No`)

No migration. The shipped Google Chat `typingIndicator: "message"` default is preserved.

Did security, auth, secrets, network, or tool execution behavior change? (`Yes/No`)

Yes.

What is the highest-risk area?

Approval authorization and callback token handling for native Google Chat card actions.

How is that risk mitigated?

Callbacks carry opaque action tokens only, token bindings check account, space, message, expiry, allowed decision, and in-flight state, and actor authorization reuses the existing Google Chat approver allowlist adapter based on stable `users/<id>` principals.

## Current review state

What is the next action?

Merge after current-head CI for `5923f2af46`.

What is still waiting on author, maintainer, CI, or external proof?

Current-head CI is green for `5923f2af46`; live dev-profile proof is complete.

Which bot or reviewer comments were addressed?

Addressed duplicate approval delivery by keeping the final suppression path inside `extensions/googlechat/`, preserving default typing-message behavior, and proving the current Google Chat surface sends only the native approval card.
2026-06-04 23:05:06 -07:00
Peter Steinberger 96e5812426 docs: document medium extension sources 2026-06-04 21:33:54 -04:00
Peter Steinberger 58e82d91ba fix(media): centralize content length parsing 2026-05-29 09:02:21 -04:00
Vincent Koc 60a6945a6e fix(googlechat): wrap malformed api json 2026-05-15 08:56:16 +08:00
Peter Steinberger 53d007bc87 refactor(media): centralize bounded remote downloads
Co-authored-by: samzong <samzong.lu@gmail.com>
2026-05-13 15:04:49 +01:00
Peter Steinberger 1f1ff0567a refactor(lint): reduce map spread patterns 2026-04-18 19:27:43 +01:00
Peter Steinberger af954a81d1 perf: optimize bundled extension tests 2026-04-17 16:05:09 +01:00
Peter Steinberger 325ff24bae refactor: dedupe probe error formatting 2026-04-07 02:03:34 +01:00
Vincent Koc 2b67a3f76e Plugins: internalize googlechat SDK imports 2026-03-17 21:11:17 -07:00
Peter Steinberger 6ecc184637 refactor: share googlechat api fetch handling 2026-03-13 21:40:53 +00:00
Gustavo Madeira Santana a1e21bc02d Plugins/googlechat: migrate to scoped plugin-sdk imports 2026-03-04 02:35:12 -05:00
Gustavo Madeira Santana 39a55844bc Extensions: migrate googlechat plugin-sdk imports 2026-03-04 01:20:49 -05:00
Sid 4691aab019 fix(cron): guard against year-rollback in croner nextRun (#30777)
* fix(cron): guard against year-rollback in croner nextRun

Croner can return a past-year timestamp for some timezone/date
combinations (e.g. Asia/Shanghai).  When nextRun returns a value at or
before nowMs, retry from the next whole second and, if still stale,
from midnight-tomorrow UTC before giving up.

Closes #30351

* googlechat: guard API calls with SSRF-safe fetch

* test: fix hoisted plugin context mock setup

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-01 22:22:59 -06:00
Peter Steinberger cdbed3c9b1 fix(googlechat): land #30965 thread reply option support (@novan)
Landed from contributor PR #30965 by @novan.

Co-authored-by: novan <novan@users.noreply.github.com>
2026-03-02 03:16:48 +00:00
Peter Steinberger b8b43175c5 style: align formatting with oxfmt 0.33 2026-02-18 01:34:35 +00:00
Peter Steinberger 31f9be126c style: run oxfmt and fix gate failures 2026-02-18 01:29:02 +00:00
cpojer d0cb8c19b2 chore: wtf. 2026-02-17 13:36:48 +09:00
Sebastian ed11e93cf2 chore(format) 2026-02-16 23:20:16 -05:00
cpojer 90ef2d6bdf chore: Update formatting. 2026-02-17 09:18:40 +09:00
cpojer f06dd8df06 chore: Enable "experimentalSortImports" in Oxfmt and reformat all imorts. 2026-02-01 10:03:47 +09:00
cpojer 230ca789e2 chore: Lint extensions folder. 2026-01-31 22:42:45 +09:00
Peter Steinberger 9a7160786a refactor: rename to openclaw 2026-01-30 03:16:21 +01:00
Peter Steinberger 6d16a658e5 refactor: rename clawdbot to moltbot with legacy compat 2026-01-27 12:21:02 +00:00
Peter Steinberger 5570e1a946 fix: polish Google Chat plugin (#1635) (thanks @iHildy)
Co-authored-by: Ian Hildebrand <ian@jedi.net>
2026-01-24 23:30:45 +00:00
iHildy c64184fcfa googlechat: implement typing indicator via message editing 2026-01-24 23:30:45 +00:00
iHildy b76cd6695d feat: add beta googlechat channel 2026-01-24 23:30:45 +00:00