Commit Graph

64 Commits

Author SHA1 Message Date
Peter Steinberger
8181f51dbd perf(test): reuse temp root in slack prepare contract suite 2026-02-15 00:45:10 +00:00
Peter Steinberger
aae290eed3 refactor(test): dedupe slack inbound contract setup 2026-02-14 22:14:35 +00:00
Peter Steinberger
2f67564c93 refactor(test): dedupe slack inbound contract prep 2026-02-14 20:21:17 +00:00
Peter Steinberger
4b1cadaecb refactor(media): normalize inbound media type defaults (#16228) 2026-02-14 15:06:13 +01:00
Tanwa Arpornthip
c76288bdf1 fix(slack): download all files in multi-image messages (#15447)
* fix(slack): download all files in multi-image messages

resolveSlackMedia() previously returned after downloading the first
file, causing multi-image Slack messages to lose all but the first
attachment. This changes the function to collect all successfully
downloaded files into an array, matching the pattern already used by
Telegram, Line, Discord, and iMessage adapters.

The prepare handler now populates MediaPaths, MediaUrls, and
MediaTypes arrays so downstream media processing (vision, sandbox
staging, media notes) works correctly with multiple attachments.

Fixes #11892, #7536

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

* fix(slack): preserve MediaTypes index alignment with MediaPaths/MediaUrls

The filter(Boolean) on MediaTypes removed entries with undefined contentType,
shrinking the array and breaking index correlation with MediaPaths and MediaUrls.
Downstream code (media-note.ts, attachments.ts) requires these arrays to have
equal lengths for correct per-attachment MIME type lookup. Replace filter(Boolean)
with a nullish coalescing fallback to "application/octet-stream".

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

* fix(slack): align MediaType fallback and tests (#15447) (thanks @CommanderCrowCode)

* fix: unblock plugin-sdk account-id typing (#15447)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-14 14:16:02 +01:00
Masataka Shinohara
b93ad2cd48 fix(slack): populate thread session with existing thread history (#7610)
* feat(slack): populate thread session with existing thread history

When a new session is created for a Slack thread, fetch and inject
the full thread history as context. This preserves conversation
continuity so the bot knows what it previously said in the thread.

- Add resolveSlackThreadHistory() to fetch all thread messages
- Add ThreadHistoryBody to context payload
- Use thread history instead of just thread starter for new sessions

Fixes #4470

* chore: remove redundant comments

* fix: use threadContextNote in queue body

* fix(slack): address Greptile review feedback

- P0: Use thread session key (not base session key) for new-session check
  This ensures thread history is injected when the thread session is new,
  even if the base channel session already exists.

- P1: Fetch up to 200 messages and take the most recent N
  Slack API returns messages in chronological order (oldest first).
  Previously we took the first N, now we take the last N for relevant context.

- P1: Batch resolve user names with Promise.all
  Avoid N sequential API calls when resolving user names in thread history.

- P2: Include file-only messages in thread history
  Messages with attachments but no text are now included with a placeholder
  like '[attached: image.png, document.pdf]'.

- P2: Add documentation about intentional 200-message fetch limit
  Clarifies that we intentionally don't paginate; 200 covers most threads.

* style: add braces for curly lint rule

* feat(slack): add thread.initialHistoryLimit config option

Allow users to configure the maximum number of thread messages to fetch
when starting a new thread session. Defaults to 20. Set to 0 to disable
thread history fetching entirely.

This addresses the optional configuration request from #2608.

* chore: trigger CI

* fix(slack): ensure isNewSession=true on first thread turn

recordInboundSession() in prepare.ts creates the thread session entry
before session.ts reads the store, causing isNewSession to be false
on the very first user message in a thread. This prevented thread
context (history/starter) from being injected.

Add IsFirstThreadTurn flag to message context, set when
readSessionUpdatedAt() returns undefined for the thread session key.
session.ts uses this flag to force isNewSession=true.

* style: format prepare.ts for oxfmt

* fix: suppress InboundHistory/ThreadStarterBody when ThreadHistoryBody present (#13912)

When ThreadHistoryBody is fetched from the Slack API (conversations.replies),
it already contains pending messages and the thread starter. Passing both
InboundHistory and ThreadStarterBody alongside ThreadHistoryBody caused
duplicate content in the LLM context on new thread sessions.

Suppress InboundHistory and ThreadStarterBody when ThreadHistoryBody is
present, since it is a strict superset of both.

* remove verbose comment

* fix(slack): paginate thread history context fetch

* fix(slack): wire session file path options after main merge

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-13 05:51:04 +01:00
Peter Steinberger
a43136c85e fix: align slack thread footer metadata with reply semantics (#14625) (thanks @bennewton999) 2026-02-13 05:18:06 +01:00
Ben Newton
2b9d5e6e30 feat(slack): include thread metadata (thread_ts, parent_user_id) in agent context
Adds thread_ts and parent_user_id to the Slack message footer for thread
replies, giving agents awareness of thread context. Top-level messages
remain unchanged.

Includes tests verifying:
- Thread replies include thread_ts and parent_user_id in footer
- Top-level messages exclude thread metadata
2026-02-13 05:18:06 +01:00
0xRain
626a1d0699 fix(gateway): increase WebSocket max payload to 5 MB for image uploads (#14486)
* fix(gateway): increase WebSocket max payload to 5 MB for image uploads

The 512 KB limit was too small for base64-encoded images — a 400 KB
image becomes ~532 KB after encoding, exceeding the limit and closing
the connection with code 1006.

Bump MAX_PAYLOAD_BYTES to 5 MB and MAX_BUFFERED_BYTES to 8 MB to
support standard image uploads via webchat.

Closes #14400

* fix: align gateway WS limits with 5MB image uploads (#14486) (thanks @0xRaini)

* docs: fix changelog conflict for #14486

---------

Co-authored-by: 0xRaini <0xRaini@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-12 17:48:49 +01:00
J young Lee
2aa9570465 fix(slack): detect control commands when message starts with @mention (#14142)
Merged via /review-pr-v2 -> /prepare-pr-v2 -> /merge-pr-v2.

Prepared head SHA: cb0b4f6a3b
Co-authored-by: beefiker <55247450+beefiker@users.noreply.github.com>
Co-authored-by: gumadeiras <gumadeiras@gmail.com>
Reviewed-by: @gumadeiras
2026-02-11 11:41:48 -05:00
Peter Steinberger
53273b490b fix(auto-reply): prevent sender spoofing in group prompts 2026-02-10 00:44:38 -06:00
max
223eee0a20 refactor: unify peer kind to ChatType, rename dm to direct (#11881)
* fix: use .js extension for ESM imports of RoutePeerKind

The imports incorrectly used .ts extension which doesn't resolve
with moduleResolution: NodeNext. Changed to .js and added 'type'
import modifier.

* fix tsconfig

* refactor: unify peer kind to ChatType, rename dm to direct

- Replace RoutePeerKind with ChatType throughout codebase
- Change 'dm' literal values to 'direct' in routing/session keys
- Keep backward compat: normalizeChatType accepts 'dm' -> 'direct'
- Add ChatType export to plugin-sdk, deprecate RoutePeerKind
- Update session key parsing to accept both 'dm' and 'direct' markers
- Update all channel monitors and extensions to use ChatType

BREAKING CHANGE: Session keys now use 'direct' instead of 'dm'.
Existing 'dm' keys still work via backward compat layer.

* fix tests

* test: update session key expectations for dmdirect migration

- Fix test expectations to expect :direct: in generated output
- Add explicit backward compat test for normalizeChatType('dm')
- Keep input test data with :dm: keys to verify backward compat

* fix: accept legacy 'dm' in session key parsing for backward compat

getDmHistoryLimitFromSessionKey now accepts both :dm: and :direct:
to ensure old session keys continue to work correctly.

* test: add explicit backward compat tests for dmdirect migration

- session-key.test.ts: verify both :dm: and :direct: keys are valid
- getDmHistoryLimitFromSessionKey: verify both formats work

* feat: backward compat for resetByType.dm config key

* test: skip unix-path Nix tests on Windows
2026-02-09 09:20:52 +09:00
mudrii
5d82c82313 feat: per-channel responsePrefix override (#9001)
* feat: per-channel responsePrefix override

Add responsePrefix field to all channel config types and Zod schemas,
enabling per-channel and per-account outbound response prefix overrides.

Resolution cascade (most specific wins):
  L1: channels.<ch>.accounts.<id>.responsePrefix
  L2: channels.<ch>.responsePrefix
  L3: (reserved for channels.defaults)
  L4: messages.responsePrefix (existing global)

Semantics:
  - undefined -> inherit from parent level
  - empty string -> explicitly no prefix (stops cascade)
  - "auto" -> derive [identity.name] from routed agent

Changes:
  - Core logic: resolveResponsePrefix() in identity.ts accepts
    optional channel/accountId and walks the cascade
  - resolveEffectiveMessagesConfig() passes channel context through
  - Types: responsePrefix added to WhatsApp, Telegram, Discord, Slack,
    Signal, iMessage, Google Chat, MS Teams, Feishu, BlueBubbles configs
  - Zod schemas: responsePrefix added for config validation
  - All channel handlers wired: telegram, discord, slack, signal,
    imessage, line, heartbeat runner, route-reply, native commands
  - 23 new tests covering backward compat, channel/account levels,
    full cascade, auto keyword, empty string stops, unknown fallthrough

Fully backward compatible - no existing config is affected.
Fixes #8857

* fix: address CI lint + review feedback

- Replace Record<string, any> with proper typed helpers (no-explicit-any)
- Add curly braces to single-line if returns (eslint curly)
- Fix JSDoc: 'Per-channel' → 'channel/account' on shared config types
- Extract getChannelConfig() helper for type-safe dynamic key access

* fix: finish responsePrefix overrides (#9001) (thanks @mudrii)

* fix: normalize prefix wiring and types (#9001) (thanks @mudrii)

---------

Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com>
2026-02-04 16:16:34 -05:00
Peter Steinberger
35eb40a700 fix(security): separate untrusted channel metadata from system prompt (thanks @KonstantinMirin) 2026-02-03 23:02:45 -08:00
cpojer
935a0e5708 chore: Enable typescript/no-explicit-any rule. 2026-02-02 16:18:09 +09:00
cpojer
f06dd8df06 chore: Enable "experimentalSortImports" in Oxfmt and reformat all imorts. 2026-02-01 10:03:47 +09:00
cpojer
5ceff756e1 chore: Enable "curly" rule to avoid single-statement if confusion/errors. 2026-01-31 16:19:20 +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
Shadow
7e4e24445e Slack: clear ack reaction after streaming replies (#2044)
Co-authored-by: Shaurya Pratap Singh <fancyboi999@users.noreply.github.com>
2026-01-25 21:28:46 -06:00
Peter Steinberger
4b6cdd1d3c fix: normalize session keys and outbound mirroring 2026-01-24 11:57:11 +00:00
Peter Steinberger
d905ca0e02 fix: enforce explicit mention gating across channels 2026-01-24 11:09:33 +00:00
Peter Steinberger
bf4544784a fix: stabilize typing + summary merge 2026-01-23 23:34:30 +00:00
Peter Steinberger
aeb6b2ffad refactor: standardize channel logging 2026-01-23 23:34:30 +00:00
Peter Steinberger
1113f17d4c refactor: share reply prefix context 2026-01-23 23:34:30 +00:00
Peter Steinberger
8252ae2da1 refactor: unify typing callbacks 2026-01-23 23:33:32 +00:00
Peter Steinberger
d82ecaf9dc refactor: centralize inbound session updates 2026-01-23 23:33:32 +00:00
Peter Steinberger
521ea4ae5b refactor: unify pending history helpers 2026-01-23 23:33:32 +00:00
Peter Steinberger
cb8c8fee9a refactor: centralize ack reaction removal 2026-01-23 23:32:14 +00:00
Peter Steinberger
2e0a835e07 fix: unify inbound dispatch pipeline 2026-01-23 22:58:54 +00:00
Peter Steinberger
02bd6e4a24 refactor: centralize ack reaction gating 2026-01-23 22:24:31 +00:00
Travis Irby
578ac9f1a9 hydrate files from thread root message on replies
When replying to a Slack thread, files attached to the root message were
  not being fetched. The existing `resolveSlackThreadStarter()` fetched the
  root message text via `conversations.replies` but ignored the `files[]`
  array in the response.

  Changes:
  - Add `files` to `SlackThreadStarter` type and extract from API response
  - Download thread starter files when the reply message has no attachments
  - Add verbose log for thread starter file hydration

  Fixes issue where asking about a PDF in a thread reply would fail because
  the model never received the file content from the root message.
2026-01-23 05:10:36 +00:00
Peter Steinberger
45c1ccdfcf refactor: unify threading contexts 2026-01-21 20:35:12 +00:00
Peter Steinberger
88d76d4be5 refactor(channels): centralize match metadata 2026-01-21 18:21:19 +00:00
Peter Steinberger
65dd73b4c3 fix: clean up slack threading landings (#1360) (thanks @SocialNerd42069) 2026-01-21 06:29:36 +00:00
SocialNerd42069
0d6e78b718 fix(slack): respect verbose setting and preserve thread context for tool notifications
Fixes two bugs in Slack tool notification delivery:

1. Tool notifications ignored verbose=false - normalized verbose values so
   boolean false/'false' are properly treated as 'off'

2. Thread context lost - Slack outbound adapter now falls back to threadId
   when replyToId is missing, and MessageThreadId is set for thread replies

Closes #1333
2026-01-21 06:29:36 +00:00
Peter Steinberger
02ca148583 fix: preserve subagent thread routing (#1241)
Thanks @gnarco.

Co-authored-by: gnarco <gnarco@users.noreply.github.com>
2026-01-20 17:22:07 +00:00
Peter Steinberger
690bb192e6 style: format code 2026-01-18 19:36:46 +00:00
Peter Steinberger
744d1329cb feat: make inbound envelopes configurable
Co-authored-by: Shiva Prasad <shiv19@users.noreply.github.com>
2026-01-18 18:50:37 +00:00
Peter Steinberger
0d9172d761 fix: persist session origin metadata 2026-01-18 03:41:51 +00:00
Peter Steinberger
34590d2144 feat: persist session origin metadata across connectors 2026-01-18 02:42:10 +00:00
Peter Steinberger
f73dbdbaea refactor: unify channel config matching and gating
Co-authored-by: thewilloftheshadow <thewilloftheshadow@users.noreply.github.com>
2026-01-18 01:24:00 +00:00
Peter Steinberger
a5aa48beea feat: add dm allowlist match metadata logs
Co-authored-by: thewilloftheshadow <thewilloftheshadow@users.noreply.github.com>
2026-01-18 00:14:44 +00:00
Peter Steinberger
6b784a9771 style: oxfmt 2026-01-17 10:26:08 +00:00
Peter Steinberger
69ba2765de refactor(security): harden CommandAuthorized plumbing 2026-01-17 10:19:34 +00:00
Peter Steinberger
1f3a09b43b fix: persist deliveryContext on last-route updates
Co-authored-by: Adam Holt <mail@adamholt.co.nz>
2026-01-17 06:54:31 +00:00
Peter Steinberger
6a3ed5c850 fix(security): gate slash/control commands 2026-01-17 06:49:34 +00:00
Peter Steinberger
37a2eee837 refactor: drop legacy session store keys 2026-01-17 06:48:44 +00:00
Peter Steinberger
e59d8c5436 style: oxfmt format 2026-01-17 05:48:56 +00:00
Peter Steinberger
a624878973 fix(security): gate slash commands by sender 2026-01-17 05:25:42 +00:00