218 Commits

Author SHA1 Message Date
teconomix
e2c4d8bd45 fix(mattermost): clean up streaming preview when no final payload arrives; stop retrying failed initial sends
Two fixes:

1. onSettled orphan cleanup (Codex ID=2963834802): add cleanup in the streaming
   dispatcher's onSettled callback for cases where the reply pipeline produces no
   final payload — e.g. messaging-tool sends suppressed by agent-runner-payloads.ts,
   or empty/heartbeat responses. Without this, onPartialReply could create a preview
   post that is never finalized or deleted. The cleanup mirrors the existing logic in
   #43041 (P5).

2. Initial-send retry storm (Codex ID=2963834806): call stopPatchInterval() in the
   sendMessageMattermost catch block, mirroring the existing fix for patchMattermostPost
   failures. Without this, a failed initial post attempt (missing post permission, DM
   creation failure, etc.) causes the 200ms interval to retry indefinitely for the rest
   of the response, flooding the API and gateway logs.
2026-03-20 06:03:16 +00:00
teconomix
38f3e76f97 fix(mattermost): wait for in-flight preview send before divergent delivery; stop retrying failed patches
Two fixes:

1. Divergent-target flush (Codex ID=2962544342): when replyTargetDiverged is true
   the flush is skipped to avoid creating a preview in the wrong thread, but the
   patch interval was not stopped and any in-flight first sendMessageMattermost
   was not awaited. If that send resolved after the divergent delivery returned,
   it created a stray preview post with no cleanup path. Fix: always stop the
   interval and wait for patchSending to settle (up to 2s) even on the divergent
   path, so streamMessageId is populated if the send resolves during this window
   and the orphan cleanup below can capture and delete it.

2. Patch-failure retry storm (Codex ID=2962544347): after a patchMattermostPost
   failure in the schedulePatch interval, streamMessageId remained set and every
   subsequent 200ms tick retried the same failing request, spamming the API until
   final delivery. Fix: call stopPatchInterval() in the catch block so retries
   stop immediately. The preview stays frozen at its last successful text; deliver()
   will patch or replace it when the final reply arrives.
2026-03-20 03:53:16 +00:00
teconomix
59db1c2b67 fix(mattermost): deliver media-only final before deleting streamed preview
When the final payload has no text (media-only), the in-place text patch branch
is skipped, but the streamed preview post was previously left in the channel
alongside the attachment. The orphanedStreamId capture now always holds the
stream post ID (not only on divergent-target paths), and a new branch delivers
the media payload first and deletes the stale preview only after delivery
succeeds. If delivery fails, the preview stays visible as a fallback.
2026-03-19 20:17:51 +00:00
teconomix
e1e572b9ca fix(mattermost): compute replyTargetDiverged before flush; deliver-before-delete for divergent thread; fix disableBlockStreaming undefined
Three fixes from latest Codex review:

1. Compute replyTargetDiverged before flushPendingPatch: previously the flush
   always ran first, potentially creating a preview post under effectiveReplyToId
   even when the final payload would land in a different thread. Now flush is
   skipped when the target diverges, avoiding a transient post in the wrong thread.

2. Divergent-thread cleanup order: when replyTargetDiverged, deliver the correct
   message first and delete the orphaned preview only afterward. This matches the
   same pattern as the fallback path — if delivery fails, the user keeps the
   partial preview rather than losing all visible output.

3. disableBlockStreaming: changed fallback from false to undefined so accounts
   without an explicit blockStreaming setting preserve the agent blockStreamingDefault
   instead of having block streaming forced on.
2026-03-18 14:43:22 +00:00
teconomix
276e5d735b fix(mattermost): deduplicate truncated patch edits; delete orphan only after fallback succeeds
Two fixes from latest Codex review:

1. Truncation dedup: compare lastSentText against the truncated text (not the full
   rawText) in both schedulePatch and flushPendingPatch. Previously, once a reply
   grew past textLimit the guard compared the growing rawText against the stored
   rawText, so the post would be patched every 200 ms with the same truncated body
   — running into avoidable Mattermost rate limiting on long responses.

2. Orphan cleanup order: in the final-edit fallback path, deliver the replacement
   message first and only delete the orphaned stream post afterward. If the fallback
   send also fails, the user keeps the partial preview instead of losing all visible
   output.
2026-03-18 13:31:11 +00:00
teconomix
7ed3db579f fix(mattermost): make streaming opt-in; apply textLimit to patches; handle reply target divergence
Three fixes addressing Codex review feedback:

1. Streaming opt-in: change streamingEnabled from (blockStreaming !== false) to
   (blockStreaming === true) so accounts without an explicit blockStreaming setting
   preserve their agent blockStreamingDefault instead of having edit-in-place
   streaming silently enabled.

2. Text limit: apply textLimit truncation in schedulePatch and flushPendingPatch
   before sending/patching. Intermediate preview posts only need the first chunk;
   final delivery goes through deliverMattermostReplyPayload which applies full
   chunking. This prevents oversize patch loops when responses exceed the limit.

3. Reply target divergence: when the final payload carries an explicit replyToId
   that resolves to a different root than the streaming post was created under
   (e.g. a [[reply_to_current]] directive), skip the in-place patch and fall
   through to normal delivery so the reply lands in the correct thread. Any
   orphaned stream post is deleted before the correct reply is sent.
2026-03-18 13:31:11 +00:00
teconomix
33678bb973 fix(mattermost): set lastSentText after network success; wait for in-flight tick in flush
Race condition: lastSentText was set synchronously before the async send/patch
completed, so a failed request was treated as delivered and subsequent ticks
skipped retrying. flushPendingPatch also didn't wait for in-flight interval ticks,
causing it to exit early (text === lastSentText guard) when a tick had just fired
but hadn't resolved yet, leaving streamMessageId null and forcing final delivery
to send a new post instead of patching the streamed one.

Fixes:
- schedulePatch interval: set lastSentText only after successful send/patch
- flushPendingPatch: wait up to 2s for in-flight patchSending before proceeding
- flushPendingPatch: set lastSentText after network success, not before
2026-03-18 13:31:10 +00:00
teconomix
ee6d984950 fix(mattermost): use client.request in patchMattermostPost and deleteMattermostPost
Both functions called the global fetch directly, bypassing the fetchImpl
stored in the client closure. This silently ignored any custom fetch
implementation passed to createMattermostClient (test mocks, proxy-aware
fetchers, SSRF guards).

Switch both to client.request<void>() which uses fetchImpl, auto-injects
the Authorization header, handles Content-Type for JSON bodies, and
propagates errors consistently with every other client function.

uploadMattermostFile retains its direct fetch call (multipart/form-data
conflicts with request's automatic Content-Type injection).

Addresses Greptile review: 'New functions bypass client.request,
ignoring custom fetchImpl'.
2026-03-18 13:31:10 +00:00
teconomix
ec10de7361 fix(mattermost): inherit agent block-streaming default in button/model-picker paths
When account.blockStreaming is unset, pass undefined instead of false for
disableBlockStreaming so downstream get-reply-directives inherits the
agent-level default rather than forcing block streaming on.

Affected paths: button-click interactions (handleInteractiveMenuInteraction)
and model picker confirmations (handleModelPickerInteraction).

slash-http.ts already used undefined correctly; this brings monitor.ts
into alignment.

Addresses Codex P2 review: 'Preserve inherited block-streaming default
for model picker replies' and 'Preserve default block-streaming behavior
for button replies'.
2026-03-18 13:31:10 +00:00
teconomix
9f29865224 feat(mattermost): block streaming edit-in-place (v3.12 rebase)
Rebased onto v3.12 main. Upstream extracted deliver logic to reply-delivery.ts,
so streaming now wraps deliverMattermostReplyPayload() instead of replacing
the inline deliver body.

Changes:
- client.ts: add patchMattermostPost() + deleteMattermostPost() API helpers
- monitor.ts: inject streaming state (schedulePatch, flushPendingPatch, setInterval)
  before main inbound createReplyDispatcherWithTyping only (3 dispatch paths exist,
  only main handler gets streaming via unique humanDelay+typingCallbacks anchor)
- monitor.ts: upgrade deliver signature to (payload, info) for isFinal detection
- monitor.ts: wrap deliverMattermostReplyPayload() with isFinal streaming logic
  (final+streaming: patch in-place or fallback; non-streaming: delegate to helper)
- monitor.ts: add onPartialReply + disableBlockStreaming override in replyOptions

pnpm check: no new errors introduced (pre-existing errors on main unrelated to this PR)

Fixes: https://github.com/openclaw/openclaw/issues/XXXX
PR: https://github.com/openclaw/openclaw/pull/33506
2026-03-18 13:31:10 +00:00
Vincent Koc
b333eb137b Tests: align plugin test imports with local barrels 2026-03-17 23:23:58 -07:00
Peter Steinberger
05603e4e6c refactor: deduplicate channel config adapters 2026-03-18 04:51:29 +00:00
Peter Steinberger
b86bc9de95
refactor: split remaining monitor runtime helpers 2026-03-17 21:27:21 -07:00
Gustavo Madeira Santana
d6c13d9dc0
Mattermost: move outbound session routing behind plugin boundary 2026-03-18 04:09:48 +00:00
Peter Steinberger
a2518a16ac
refactor: split monitor runtime helpers 2026-03-17 20:52:42 -07:00
Peter Steinberger
005b25e9d4
refactor: split remaining monitor runtime helpers 2026-03-17 20:36:03 -07:00
Peter Steinberger
9350cb19dd refactor: deduplicate plugin setup and channel config helpers 2026-03-18 03:28:05 +00:00
Gustavo Madeira Santana
682f4d1ca3
Plugin SDK: require unified message discovery 2026-03-18 03:02:16 +00:00
Gustavo Madeira Santana
bb803a42ac
Mattermost: normalize plugin imports 2026-03-18 02:18:06 +00:00
Gustavo Madeira Santana
fb0d04c834
Tests: migrate channel action discovery to describeMessageTool 2026-03-18 02:17:47 +00:00
Gustavo Madeira Santana
1c6676cd57
Plugins: remove first-party legacy message discovery shims 2026-03-18 02:17:40 +00:00
Gustavo Madeira Santana
4c36436fb4
Plugin SDK: add legacy message discovery helper 2026-03-18 02:08:07 +00:00
Vincent Koc
d3fc6c0cc7 Plugins: internalize mattermost and tlon SDK imports 2026-03-17 19:05:51 -07:00
Gustavo Madeira Santana
28ab5061bf
Mattermost: consolidate message tool discovery 2026-03-18 00:07:01 +00:00
Gustavo Madeira Santana
d95dc50e0a
Mattermost: own message tool button schema 2026-03-17 23:48:44 +00:00
Jonathan Jing
2145eb5908
feat(mattermost): add retry logic and timeout handling for DM channel creation (#42398)
Merged via squash.

Prepared head SHA: 3db47be907decd78116603c6ab4a48ff91eb2c25
Co-authored-by: JonathanJing <17068507+JonathanJing@users.noreply.github.com>
Co-authored-by: mukhtharcm <56378562+mukhtharcm@users.noreply.github.com>
Reviewed-by: @mukhtharcm
2026-03-17 22:16:56 +05:30
Peter Steinberger
4b125762f6
refactor: clean extension api boundaries 2026-03-17 09:38:21 -07:00
Peter Steinberger
f9588da3e0
refactor: split plugin testing seam from bundled extension helpers 2026-03-17 01:05:09 -07:00
Peter Steinberger
f6868b7e42
refactor: dedupe channel entrypoints and test bridges 2026-03-16 23:52:23 -07:00
Peter Steinberger
f2bd76cd1a
refactor: finalize plugin sdk legacy boundary cleanup 2026-03-16 22:51:46 -07:00
Peter Steinberger
9ebe38b6e3
refactor: untangle remaining plugin sdk boundaries 2026-03-16 21:16:32 -07:00
Peter Steinberger
78869f1517 refactor(mattermost): reuse patched setup adapter 2026-03-17 04:09:49 +00:00
Vincent Koc
f5ef936615 Tests: replace local channel contracts 2026-03-15 23:46:45 -07:00
Vincent Koc
13090da3ac Tests: add Mattermost channel contract suite 2026-03-15 23:32:13 -07:00
Peter Steinberger
f6f0045e0f
test: move setup surface coverage 2026-03-15 22:01:04 -07:00
Peter Steinberger
5c120cb36c
refactor: make setup the primary wizard surface 2026-03-15 22:01:04 -07:00
Vincent Koc
92bea9704e Channels: add message action capabilities 2026-03-15 21:55:45 -07:00
Peter Steinberger
98dcbd3e7e
build: add setup entrypoints for migrated channel plugins 2026-03-15 20:44:26 -07:00
Peter Steinberger
8ab01c5c93
refactor(core): land plugin auth and startup cleanup 2026-03-15 20:12:37 -07:00
Peter Steinberger
3f12e90f3e
fix(ci): repair security and route test fixtures 2026-03-15 19:54:00 -07:00
Vincent Koc
6513749ef6 Mattermost: split setup adapter helpers 2026-03-15 19:26:13 -07:00
Peter Steinberger
60bf58ddbc
refactor: trim onboarding sdk exports 2026-03-15 19:14:36 -07:00
Peter Steinberger
59bcac472e fix: gate setup-only plugin side effects 2026-03-16 01:05:42 +00:00
Peter Steinberger
1f37203f88
refactor: move signal imessage mattermost to setup wizard 2026-03-15 17:06:42 -07:00
Vincent Koc
5e78c8bc95
Webhooks: tighten pre-auth body handling (#46802)
* Webhooks: tighten pre-auth body handling

* Webhooks: clean up request body guards
2026-03-15 09:45:18 -07:00
Vincent Koc
a47722de7e
Integrations: tighten inbound callback and allowlist checks (#46787)
* Integrations: harden inbound callback and allowlist handling

* Integrations: address review follow-ups

* Update CHANGELOG.md

* Mattermost: avoid command-gating open button callbacks
2026-03-15 09:24:24 -07:00
Teconomix
0c926a2c5e
fix(mattermost): carry thread context to non-inbound reply paths (#44283)
Merged via squash.

Prepared head SHA: 2846a6cfa959019d3ed811ccafae6b757db3bdf3
Co-authored-by: teconomix <6959299+teconomix@users.noreply.github.com>
Co-authored-by: mukhtharcm <56378562+mukhtharcm@users.noreply.github.com>
Reviewed-by: @mukhtharcm
2026-03-14 12:23:23 +05:30
Peter Steinberger
49a2ff7d01
build: sync plugins for 2026.3.14 2026-03-14 06:05:39 +00:00
Peter Steinberger
97dc493e2a refactor: share extension channel status summaries 2026-03-14 02:40:27 +00:00
Peter Steinberger
e885f1999f refactor: reduce extension channel setup duplication 2026-03-14 02:40:27 +00:00