2062 Commits

Author SHA1 Message Date
Teconomix
ef3645a5ae
Merge fe8d0d5a9b8f7a8980947c36ab5e549ef78dc7da into 8a05c05596ca9ba0735dafd8e359885de4c2c969 2026-03-21 06:49:50 +01:00
Ayaan Zaidi
8a05c05596
fix: defer plugin runtime globals until use 2026-03-21 11:14:48 +05:30
scoootscooob
9fb78453e0
fix(discord): clarify startup readiness log (#51425)
Merged via squash.

Prepared head SHA: 390986dc4729975aadb25018b857063e79649f6c
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob
2026-03-20 22:00:09 -07:00
Cypherm
6b4c24c2e5
feat(telegram): support custom apiRoot for alternative API endpoints (#48842)
* feat(telegram): support custom apiRoot for alternative API endpoints

Add `apiRoot` config option to allow users to specify custom Telegram Bot
API endpoints (e.g., self-hosted Bot API servers). Threads the configured
base URL through all Telegram API call sites: bot creation, send, probe,
audit, media download, and api-fetch. Extends SSRF policy to dynamically
trust custom apiRoot hostname for media downloads.

Closes #28535

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

* fix(telegram): thread apiRoot through allowFrom lookups

* fix(telegram): honor lookup transport and local file paths

* refactor(telegram): unify username lookup plumbing

* fix(telegram): restore doctor lookup imports

* fix: document Telegram apiRoot support (#48842) (thanks @Cypherm)

---------

Co-authored-by: Cypherm <28184436+Cypherm@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-03-21 10:10:38 +05:30
Vincent Koc
c3be293dd5 fix(slack): unify slash conversation-runtime mock 2026-03-20 18:19:07 -07:00
Josh Lehman
2364e45fe4
test: align extension runtime mocks with plugin-sdk (#51289)
* test: align extension runtime mocks with plugin-sdk

Update stale extension tests to mock the plugin-sdk runtime barrels that production code now imports, and harden the Signal tool-result harness around system-event assertions so the channels lane matches current extension boundaries.

Regeneration-Prompt: |
  Verify the failing channels-lane tests against current origin/main in an isolated worktree before changing anything. If the failures reproduce on main, keep the fix test-only unless production behavior is clearly wrong. Recent extension refactors moved Telegram, WhatsApp, and Signal code onto plugin-sdk runtime barrels, so update stale tests that still mock old core module paths to intercept the seams production code now uses. For Signal reaction notifications, avoid brittle assertions that depend on shared queued system-event state when a direct harness spy on enqueue behavior is sufficient. Preserve scope: only touch the failing tests and their local harness, then rerun the reproduced targeted tests plus the full channels lane and repo check gate.

* test: fix extension test drift on main

* fix: lazy-load bundled web search plugin registry

* test: make matrix sweeper failure injection portable

* fix: split heavy matrix runtime-api seams

* fix: simplify bundled web search id lookup

* test: tolerate windows env key casing
2026-03-20 15:59:53 -07:00
Vincent Koc
e635cedb85 test(openai): cover bundle media surfaces 2026-03-20 15:53:12 -07:00
Vincent Koc
d54ebed7c8 test(openai): add plugin entry live coverage 2026-03-20 15:53:12 -07:00
Vincent Koc
d1d46c6cfb test(openai): broaden live model coverage 2026-03-20 15:53:12 -07:00
Vincent Koc
f1802a5bc7 test(openai): add live provider probe 2026-03-20 15:53:12 -07:00
Sally O'Malley
6e20c4baa0
feat: add anthropic-vertex provider for Claude via GCP Vertex AI (#43356)
Reuse pi-ai's Anthropic client injection seam for streaming, and add
the OpenClaw-side provider discovery, auth, model catalog, and tests
needed to expose anthropic-vertex cleanly.

Signed-off-by: sallyom <somalley@redhat.com>
2026-03-20 18:48:42 -04:00
Vincent Koc
42ca447189 test(openrouter): add live plugin coverage 2026-03-20 15:36:34 -07:00
Gustavo Madeira Santana
3da66718f4
Web: derive search provider metadata from plugin contracts (#50935)
Merged via squash.

Prepared head SHA: e1c7d72833afff6ef33e8d32cdd395190742dc08
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-03-20 12:41:04 -07:00
Jaaneek
916f496b51
Add Grok 4.20 reasoning and non-reasoning to xAI model catalog (#50772)
Merged via squash.

Prepared head SHA: 095e645ea58b2259b25c923aeaf11bbcb2990c8f
Co-authored-by: Jaaneek <25470423+Jaaneek@users.noreply.github.com>
Co-authored-by: huntharo <5617868+huntharo@users.noreply.github.com>
Reviewed-by: @huntharo
2026-03-20 15:28:30 -04:00
Peter Steinberger
f6b3245a7b fix: pass full sdk gate 2026-03-20 19:24:10 +00:00
Peter Steinberger
62ddc9d9e0 refactor: consolidate plugin sdk surface 2026-03-20 19:24:10 +00:00
Gustavo Madeira Santana
a05da76718
Matrix: dedupe replayed inbound events on restart (#50922)
Merged via squash.

Prepared head SHA: 10d9770aa61d864686e4ba20fbcffb8a8dd68903
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-03-20 12:13:24 -07:00
HCL
4e45a663e7 fix(telegram): prevent silent wrong-bot routing when accountId not in config
When a non-default accountId is specified but not found in the accounts
config, resolveTelegramToken() falls through to channel-level defaults
(botToken, tokenFile, env) — silently routing messages via the wrong
bot's token. This is a cross-bot message leak with no error or warning.

Root cause: extensions/telegram/src/token.ts:44-46, resolveAccountCfg()
returns undefined for unknown accountIds but code continues to fallbacks.
Introduced in e5bca0832f when Telegram moved to extensions/.

Fix: return { token: "", source: "none" } with a diagnostic log when
a non-default accountId is not found. Existing behavior for known
accounts (with or without per-account tokens) preserved.

Test: added "does not fall through when non-default accountId not in
config" — 1/1 new, 10/10 existing unaffected.

Closes #49383

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: HCL <chenglunhu@gmail.com>
2026-03-20 23:24:40 +05:30
Vincent Koc
23a119c6ea test(msteams): clear remaining rebase conflict hunk 2026-03-20 10:38:55 -07:00
Vincent Koc
5b7ae24e30 test(msteams): align adapter doubles with interfaces 2026-03-20 10:38:55 -07:00
Vincent Koc
a2e1991ed3 refactor(plugin-sdk): route bundled runtime barrels through public subpaths 2026-03-20 10:38:55 -07:00
Saurabh Mishra
4266e260e1
fix: emit message:sent hook on Telegram streaming preview finalization (#50917)
* fix: emit message:sent hook on Telegram streaming preview finalization

* fix: include messageId in preview-delivered hook callback

* fix: skip message:sent hook for preview-retained paths

* fix: correct JSDoc for onPreviewDelivered callback

* fix: pass visible preview text on regressive-skip path

* fix: remove dead fallbacks and add stopCreatesFirstPreview test

* Update extensions/telegram/src/lane-delivery-text-deliverer.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix: align telegram preview sent hooks (#50917) (thanks @bugkill3r)

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-03-20 22:42:04 +05:30
Peter Steinberger
18fa2992f9 fix: restore plugin sdk runtime barrels 2026-03-20 16:46:34 +00:00
Peter Steinberger
4c614c230d fix: restore local gate 2026-03-20 16:46:14 +00:00
teconomix
fe8d0d5a9b fix(mattermost): normalize both sides before divergence check (ID=2965488514)
[[reply_to_current]] sets payload.replyToId to the child-post id inside the thread,
not the thread root. The raw !== comparison triggered false divergence: child-post !=
thread-root, even though they both resolve to the same Mattermost thread.

Fix: compute baseReplyToId via resolveMattermostReplyRootId without the payload, then
compare finalReplyToId against baseReplyToId. Both paths normalize child-post ids to
the thread root before comparison, so [[reply_to_current]] and explicit child-post
targets no longer falsely trigger the divergent-target path.
2026-03-20 16:39:27 +00:00
Vincent Koc
aa78a0c00e refactor(plugin-sdk): formalize runtime contract barrels 2026-03-20 09:30:34 -07:00
Vincent Koc
9b6f286ac2 refactor(channels): share route format and binding helpers 2026-03-20 09:30:34 -07:00
Vincent Koc
faa9faa767 refactor(web-search): share provider clients and config helpers 2026-03-20 09:30:34 -07:00
Peter Steinberger
50ce9ac1c6 refactor: privatize bundled sdk facades 2026-03-20 15:56:14 +00:00
Peter Steinberger
f6948ce405 refactor: shrink sdk helper surfaces 2026-03-20 15:43:14 +00:00
sudie-codes
06845a1974
fix(msteams): resolve Graph API chat ID for DM file uploads (#49585)
Fixes #35822 — Bot Framework conversation.id format is incompatible with
Graph API /chats/{chatId}. Added resolveGraphChatId() to look up the
Graph-native chat ID via GET /me/chats, cached in the conversation store.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:08:26 -05:00
sudie-codes
7c3af3726f
msteams: extend MSTeamsAdapter and MSTeamsActivityHandler types; implement self() (#49929)
- Add updateActivity/deleteActivity to MSTeamsAdapter
- Add onReactionsAdded/onReactionsRemoved to MSTeamsActivityHandler
- Implement directory self() to return bot identity from appId credential
- Add tests for self() in channel.directory.test.ts
2026-03-20 10:08:23 -05:00
sudie-codes
897cda7d99
msteams: fix sender allowlist bypass when route allowlist is configured (GHSA-g7cr-9h7q-4qxq) (#49582)
When a route-level (teams/channel) allowlist was configured but the sender
allowlist (allowFrom/groupAllowFrom) was empty, resolveSenderScopedGroupPolicy
would downgrade the effective group policy from "allowlist" to "open", allowing
any Teams user to interact with the bot.

The fix: when channelGate.allowlistConfigured is true and effectiveGroupAllowFrom
is empty, preserve the configured groupPolicy ("allowlist") rather than letting
it be downgraded to "open". This ensures an empty sender allowlist with an active
route allowlist means deny-all rather than allow-all.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:08:19 -05:00
teconomix
5aa16edfbb fix(mattermost): detect reply target divergence correctly (ID=2965349638)
resolveMattermostReplyRootId always returns threadRootId when it is set, so
comparing finalReplyToId against effectiveReplyToId was always false when the
streaming preview was created in a thread. Explicit reply directives like
[[reply_to:...]] could therefore never trigger the divergent-target path.

Fix: compare payload.replyToId directly against effectiveReplyToId instead of
going through the resolver. The resolver is still used to compute finalReplyToId
for the actual delivery call.
2026-03-20 12:16:26 +00:00
teconomix
75b79f6f59 fix(mattermost): use patchInflight in flushPendingPatch and divergent-target wait
flushPendingPatch and the divergent-target branch were still using a 2-second
busy-wait on patchSending, which has the same race as the onSettled wait that was
already fixed: patchSending clears in the finally block before the network request
actually settles. Both paths now await patchInflight directly. (ID=2965256849)
2026-03-20 11:39:22 +00:00
teconomix
6bea6df33f fix(mattermost): keep text+media together; avoid split captioned posts (ID=2965096969)
Patching preview text then delivering media separately splits a captioned-file
reply into two posts: a text-only preview + captionless file attachment.

New logic in the isFinal branch:
- Text-only payload: patch in place as before (no change for common case)
- Media payload: skip the patch, reset state, deliver full payload via
  deliverMattermostReplyPayload (text+media together), then delete preview.
- Patch failure: same fallback as media payload — full delivery + delete.
2026-03-20 11:15:46 +00:00
teconomix
f49c6a402c fix(mattermost): deliver media attachments after successful final patch (ID=2965023940)
After a successful patchMattermostPost in the isFinal branch, the code returned
immediately without delivering any media attachments. deliverMattermostReplyPayload
is the only path that uploads/sends media, so caption+image/file/audio payloads
were silently dropping the attachment whenever streaming was active and the patch
succeeded.

Fix: after a successful patch, check whether the payload has mediaUrls/mediaUrl.
If so, call deliverMattermostReplyPayload with text=undefined to deliver only the
media through the normal attachment path.
2026-03-20 10:38:24 +00:00
teconomix
dff71545a6 fix(mattermost): track patchInflight in P4; use direct await in onSettled cleanup
Add patchInflight Promise tracking to P4 (feat/mattermost-block-streaming-rebased),
mirroring the existing P5 approach. The onSettled cleanup previously used a 3-second
busy-wait on patchSending, which would race on slow Mattermost links: if the first
preview POST takes longer than 3s the cleanup exits early, patchSending is forced false,
and when the POST later resolves it creates an orphan post that is never deleted.

Fix: track the interval tick's async function as patchInflight. onSettled awaits it
directly so the cleanup always captures the final streamMessageId, regardless of how
long the POST takes. (Codex ID=2964616785)
2026-03-20 10:21:19 +00:00
Vincent Koc
df536c3248 test(signal): harden tool-result infra-runtime mock 2026-03-20 01:33:16 -07:00
teconomix
374c92947a fix(mattermost): latch send failures; include patchInterval in onSettled cleanup
Two fixes:

1. Failure latch (Codex ID=2964357928): add previewSendFailed boolean that is set true
   in both the initial-send and patch-edit catch blocks (alongside stopPatchInterval).
   schedulePatch() checks it before re-arming the interval, so subsequent onPartialReply
   calls during a run with a permanent failure (missing permission, DM-creation error)
   no longer recreate the timer and retry indefinitely.

2. patchInterval in onSettled guard (Codex ID=2964357925): onSettled now triggers
   cleanup when patchInterval is non-null, even if streamMessageId and patchSending
   are still falsy. This covers the window between schedulePatch arming the interval
   and the first 200ms tick flipping patchSending — if the run ends in that window
   (same-target messaging-tool sends, empty/heartbeat replies), the interval is now
   stopped and the pending state is cleared.
2026-03-20 08:21:53 +00:00
Vincent Koc
f1e012e0fc fix(telegram): serialize thread binding persists 2026-03-20 00:30:11 -07:00
teconomix
0ecdda1433 fix(mattermost): wait for in-flight preview send in onSettled cleanup
When the first preview POST is still in flight (patchSending=true, streamMessageId=null),
the previous onSettled check was skipped entirely — the POST would resolve after cleanup
and leave an orphaned preview post with no interval to clear it.

Fix: trigger cleanup when either streamMessageId is set OR patchSending is true.
Stop the interval immediately, clear pending state, then wait up to 3s for patchSending
to clear before capturing the final streamMessageId and deleting the post.
2026-03-20 07:15:22 +00:00
Vincent Koc
a562fb5550 refactor(web-search): share scoped provider config plumbing 2026-03-19 23:52:53 -07:00
Vincent Koc
6c7526f8a0 fix(web-search): share unsupported filter handling 2026-03-19 23:41:02 -07:00
Vincent Koc
36a59d5c79 fix(discord): drop stale carbon deploy option 2026-03-19 23:30:48 -07:00
Shakker
f2849c2417 fix(feishu): stabilize lifecycle replay tests 2026-03-20 06:13:27 +00:00
Shakker
8d805a02fd fix(zalouser): decouple tests from zca-js runtime 2026-03-20 06:13:27 +00:00
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
Lakshya Agarwal
b36e456b09
feat: add Tavily as a bundled web search plugin with search and extract tools (#49200)
Merged via squash.

Prepared head SHA: ece9226e886004f1e0536dd5de3ddc2946fc118c
Co-authored-by: lakshyaag-tavily <266572148+lakshyaag-tavily@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-03-20 01:06:26 -04:00
ernestodeoliveira
80110c550f
fix(telegram): warn when setup leaves dmPolicy as pairing without allowFrom (#50710)
* fix(telegram): warn when setup leaves dmPolicy as pairing without allowFrom

* fix(telegram): scope setup warning to account config

* fix(telegram): quote setup allowFrom example

* fix: warn on insecure Telegram setup defaults (#50710) (thanks @ernestodeoliveira)

---------

Co-authored-by: Claude Code <claude-code@openclaw.ai>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-03-20 09:29:33 +05:30