Commit Graph

121 Commits

Author SHA1 Message Date
Hayden Bleasel 6646702128 Security fixes (#262)
* Bump Next

* Fix code scanning issues
2026-03-17 11:23:47 -07:00
Malte Ubl e20637158d feat: add LinkPreview to Message for URL and embedded message support (#217)
* feat: add LinkPreview to Message for URL and embedded message support

Add `links: LinkPreview[]` to `Message` so handlers can access URLs
shared in messages. Each LinkPreview contains the URL and optional
unfurl metadata (title, description, siteName, imageUrl).

On Slack, links are extracted from rich_text block elements (falling
back to <url> patterns in text). Links pointing to other Slack messages
(*.slack.com/archives/{channel}/p{ts}) include a `fetchMessage()`
callback that retrieves and parses the linked message.

`toAiMessages()` now appends link metadata to message content
automatically, labeling embedded message links distinctly so AI models
understand the context.

- Add LinkPreview interface to core types
- Add links field to Message, MessageData, SerializedMessage
- Extract links in Slack adapter (blocks + text fallback)
- Provide fetchMessage for Slack message URLs
- Set links: [] in all other adapters
- Include link metadata in toAiMessages() output
- Document LinkPreview in message API docs
- Document toAiMessages() in streaming and handling-events docs
- Add toAiMessages to API overview

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

* fix: remove redundant links: [] from adapters for backwards compatibility

The Message constructor already defaults links to [] when not provided,
so adapters that don't support link extraction don't need to pass it
explicitly. This makes the change backwards-compatible for third-party
adapters — they get an empty links array without any code changes.

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

* fix: avoid polynomial regex in Slack link extraction

Replace `[^>|]+` pattern (which backtracks on `|`) with `[^>]+`
and a programmatic indexOf split. This prevents ReDoS on untrusted
message text.

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

* feat: add attachment support and mention tests to toAiMessages

toAiMessages now includes image and text-file attachments as multipart
content compatible with AI SDK's UserContent type:

- Images → ImagePart (via fetchData base64 or URL fallback)
- Text files (text/*, application/json, etc.) → FilePart
- Video/audio → warns via onUnsupportedAttachment callback
- Other file types → silently skipped

The function is now async to support fetchData() calls for inlining
attachment data as base64 data URIs. When fetchData fails, falls back
to the attachment URL.

Also adds mention rendering tests verifying that @mentions appear as
@name (not Slack's <@U123> syntax) in toAiMessages output, both in
plain messages and with links/includeNames enabled.

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

* fix: make AiMessage types structurally compatible with AI SDK

Use a discriminated union (AiUserMessage | AiAssistantMessage) so
AiMessage[] is directly assignable to ModelMessage[] without casts.
Match DataContent type (string | Uint8Array | ArrayBuffer | Buffer)
for image/file parts to ensure structural compatibility.

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

* fix(example): pass image attachments to AI via toAiMessages

The onNewMention handler was passing message.text directly to the AI
agent, dropping any image attachments. Now uses toAiMessages([message])
which includes images via fetchData as base64 inline data, enabling
the AI to actually see uploaded images.

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

* fix: pass image data as Buffer, not data URI

The AI SDK expects DataContent (Buffer/Uint8Array/base64 string) for
image and file parts, not data URIs. Passing `data:image/png;base64,...`
caused "Could not process image" errors from the API. Now passes the
raw Buffer from fetchData() directly, with mediaType set separately.

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

* fix: require fetchData for attachments, no URL fallback

Slack's url_private requires Bearer token auth that AI providers can't
provide. Remove URL fallback — attachments are only included when
fetchData() succeeds (which handles auth internally). Log errors
instead of silently falling through.

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

* debug: add temporary logging to toAiMessages image handling

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

* fix: use data URIs for image/file attachments in toAiMessages

The AI SDK's convertToLanguageModelV2DataContent parses data: URIs
to extract both the base64 content and media type. Raw base64 strings
lose the media type (returns mediaType: void 0), and raw Buffers may
not serialize correctly across network boundaries. Data URIs are the
most reliable format.

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

* debug: log fetched image size to diagnose API rejection

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

* debug: log prompt structure to diagnose image rejection

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

* fix: use FilePart instead of ImagePart for image attachments

The AI SDK's ImagePart with data URI strings doesn't work correctly
through the AI Gateway. Use FilePart (type: "file") with data URI
in the data field instead — this matches the working pattern used by
other projects and handles image data correctly across all providers.

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

* debug: comprehensive logging at every decision point in toAiMessages

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

* debug: log data prefix to verify content format

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

* debug: log token capture and detect HTML responses from Slack file fetch

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

* fix: improve Slack file fetch error message and remove debug logging

When Slack returns an HTML login page instead of file data (typically
due to missing "files:read" OAuth scope), the error message now
explicitly tells the user what scope to add. Also removes all
temporary debug logging from toAiMessages and createAttachment.

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

* Add transform support

* changeset

* address-feedback

* lint

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-12 07:23:09 -07:00
Matthew Lewis d565c61e9d add github username (#216) 2026-03-11 10:41:24 -04:00
Achraf Ghellach 60f5d8e19f feat: add WhatsApp Business Cloud API adapter (#102)
* feat: add WhatsApp Business Cloud API adapter

Add @chat-adapter/whatsapp with support for sending/receiving messages,
reactions, interactive reply buttons, typing indicators, and webhook
verification via the Meta Graph API. Includes full test suite,
documentation updates, and workspace/turbo configuration.

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

* feat: add media download, attachments, and location support to WhatsApp adapter

- Add downloadMedia() public method for fetching images, documents,
  audio, video, and stickers via the Graph API (two-step: URL then binary)
- Populate message attachments with lazy fetchData() for all media types
- Add location support with Google Maps URL and structured text
- Add audio, video, sticker, and location fields to WhatsAppInboundMessage
- Set isMention: true on all messages (WhatsApp DMs are always direct)
- Update parseMessage to include attachments and isMention
- Add 10 new tests covering all media types, locations, and isMention
- Update docs feature matrix to reflect media receive support

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

* fix: address PR review feedback for WhatsApp adapter

- Validate Graph API response before accessing messages[0].id in
  sendTextMessage and sendInteractiveMessage
- Escape backticks and backslashes in escapeWhatsApp()
- Apply escapeWhatsApp() to renderText() content in all style branches
- Use webhook phoneNumberId in buildMessage() instead of this.phoneNumberId
- Encode proper threadId in parseMessage() instead of empty string
- Strict decodeThreadId() validation (exactly 2 segments after prefix)
- Add tests for extra segments in decodeThreadId and threadId in parseMessage

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

* Migrate improvements from #179

Bring over several enhancements from chitru's WhatsApp adapter PR (#179):

- Voice message support (separate from audio)
- Legacy button response handling (template quick replies)
- Callback data encoding/decoding for interactive reply round-trips
- Message truncation at WhatsApp's 4096 char limit
- Example app integration (adapters, webhook route, package.json)
- GET webhook forwarding for WhatsApp verification challenges
- Package README and changeset
- Tests for all new functionality (68 total)

Co-Authored-By: Chitru Shrestha <chitra.shrestha@akuru.com.au>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(whatsapp): add error handling for inbound message processing

Wrap handleInboundMessage calls in try/catch to log errors if
synchronous processing fails (e.g., thread ID encoding). The async
processing already has its own error handling in Chat.processMessage.

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

* fix(whatsapp): prevent markdown regex from matching across newlines

Use [^\n*] and [^\n~] in fromWhatsAppFormat regex to prevent bold/strike
spans from merging across line boundaries. Adds a regression test.

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

* fix(whatsapp): use WhatsAppInteractiveMessage type instead of object

Replace the untyped `object` parameter in sendInteractiveMessage with
the proper WhatsAppInteractiveMessage type for full type safety.

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

* fix(whatsapp): hoist emoji mapping to module-level constant

Move the emoji name-to-unicode mapping out of resolveEmoji() so it is
not re-allocated on every call.

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

* fix(whatsapp): remove duplicate JSDoc comment in types

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

* fix(example): add startTyping to WhatsApp recording methods

The adapter supports typing indicators but the method was missing from
the recording proxy list.

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

* fix(whatsapp): fix formatting and add package to readme test allowlist

Fix line-length formatting in markdown.ts regex and add
@chat-adapter/whatsapp to the valid packages list in readme tests.

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

* fix(whatsapp): use defaultEmojiResolver instead of custom emoji map

Replace the hand-rolled EMOJI_MAP with the shared defaultEmojiResolver
from the chat SDK. WhatsApp uses unicode emoji like GChat, so toGChat()
provides the correct mapping with broader coverage.

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

* fix(whatsapp): make Graph API version configurable

Add apiVersion option to WhatsAppAdapterConfig (defaults to v21.0)
so users can upgrade without waiting for a package release.

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

* fix(whatsapp): validate lat/lng before constructing Google Maps URL

Coerce and validate latitude/longitude with Number.isFinite() to
prevent unexpected URL construction from malformed webhook payloads.

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

* fix(whatsapp): throw on editMessage instead of silently sending new message

Callers expecting an edit would get duplicate messages with the silent
fallback. Throwing makes the unsupported operation explicit.

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

* fix(whatsapp): document regex asymmetry between toWhatsApp and fromWhatsApp

Explain why toWhatsAppFormat doesn't need newline guards like
fromWhatsAppFormat does — the standard markdown parser output
never produces spans crossing line boundaries.

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

* fix(whatsapp): document callback data passthrough behavior

Add comments explaining that non-prefixed and malformed callback data
is intentionally passed through for legacy/external button IDs.

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

* fix(whatsapp): add editMessage and deleteMessage to recording methods

Include all adapter methods in the recording list for complete
debugging traces, even for unsupported operations.

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

* fix(whatsapp): preserve escaped formatting chars in toWhatsAppFormat

Escaped asterisks and tildes in standard markdown (e.g. \* and \~) are
now preserved through the conversion pipeline so WhatsApp renders them
as literal characters instead of misinterpreting them as formatting.

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

* fix(whatsapp): split long messages instead of truncating

Replace silent truncation at 4096 chars with message splitting that
breaks on paragraph (\n\n) then line (\n) boundaries, sending multiple
messages so no content is lost. Adds 8 tests for the splitting logic.

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

* fix(whatsapp): align editMessage/deleteMessage behavior and docs

- Fix README: editMessage/deleteMessage both throw, not fallback/no-op
- Fix editMessage JSDoc to reflect it throws
- Make deleteMessage throw instead of silently warning (consistent with editMessage)
- Bump @types/node to ^25.3.2 to match monorepo
- Add sample-messages.md with webhook payload examples

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

* docs(whatsapp): add adapter documentation page

Add whatsapp.mdx covering installation, usage, Meta app setup,
webhook config, interactive messages, media attachments, 24-hour
messaging window, configuration, features, and troubleshooting.
Also add WhatsApp to the adapters navigation in meta.json.

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

* fix: add whatsapp adapter debug logging and try/catch

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

* fix(whatsapp): convert emoji placeholders in outgoing messages

WhatsApp adapter was sending raw {{emoji:wave}} placeholders instead of
Unicode emoji. Apply convertEmojiPlaceholders on all outgoing paths:
text messages, card fallback text, and interactive message fields.

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

* Fix button rendering and streaming (needs to buffer)

* fix(example): handle editMessage failure on WhatsApp

WhatsApp Cloud API doesn't support message editing. Catch the error
in the demo "processing" animation and send a follow-up instead.

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

* feat(chat): add onDirectMessage handler, stop treating DMs as mentions

DMs now route to dedicated onDirectMessage handlers instead of being
forced through onNewMention. If no DM handlers registered, DMs fall
through to onNewMention for backward compat. Adapters no longer set
isMention=true for DMs — the Chat SDK handles routing via adapter.isDM().

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

* feat(chat): always route DMs to onDirectMessage regardless of subscription

Previously, onDirectMessage only fired for unsubscribed DM threads.
Subscribed DMs were routed to onSubscribedMessage, which was confusing
on non-threaded platforms (WhatsApp, Telegram) where all DMs share one
threadId — after the first message, onDirectMessage never fired again.

Now, DMs always route to onDirectMessage first, and onSubscribedMessage
only handles non-DM subscribed threads. Backward compat is preserved:
if no onDirectMessage handlers are registered, DMs fall through as
mentions.

The example bot is simplified accordingly — onDirectMessage now fetches
conversation history via fetchMessages each time instead of relying on
subscribe() and stored state.

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

* feat(chat): pass channel as third argument to DirectMessageHandler

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

* fix(example): reply to channel instead of thread in DM handler

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

* fix(example): use thread instead of channel for DM operations

Channel ID is only two parts (whatsapp:{phoneNumberId}) which isn't a
valid conversation target on WhatsApp. The thread ID includes the user
phone and is required for startTyping/post/fetchMessages.

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

* Revert "fix(example): use thread instead of channel for DM operations"

This reverts commit f4801d7015.

* fix(adapters): return valid thread IDs from channelIdFromThreadId

WhatsApp's channelIdFromThreadId was stripping the user WA ID, producing
an invalid ID that caused ValidationError on channel operations like
startTyping(). Since every WhatsApp conversation is a 1:1 DM, channel
and thread are identical.

Telegram's channelIdFromThreadId was returning a raw chatId without the
telegram: prefix, which is not a valid thread ID for adapter operations.

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

* fix(chat): normalize fullStream in Channel.post() to extract text deltas

Channel.post() was coercing AI SDK fullStream objects to strings via +=,
producing "[object Object]" output. Now uses fromFullStream() to extract
text-delta events, matching how Thread.post() already handles streams.

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

* fix(example): use thread.allMessages for DM history instead of adapter directly

The DM handler was calling channel.adapter.fetchMessages() which always
returns empty on WhatsApp (no native history API). Now uses
thread.allMessages which falls back to the persisted message history
cache, giving the AI conversation context.

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

* feat(chat): add message history support to Channel for DM platforms

Channel now falls back to the persisted message history cache when the
adapter lacks native message fetch (e.g. WhatsApp, Telegram). Incoming
messages are persisted under both thread and channel IDs. Outgoing
messages from channel.post() are also persisted.

The example DM handler now uses channel.messages instead of calling the
adapter directly.

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

* fix(whatsapp): improve markdown rendering and remove broken typing indicator

- Convert headings to bold text, thematic breaks to text separators,
  and tables to code blocks (WhatsApp doesn't support these)
- Convert standard italic (*text*) to WhatsApp italic (_text_) since
  WhatsApp uses *text* for bold
- Make startTyping a no-op (Cloud API doesn't support typing indicators)
- Update channelIdFromThreadId test for channel===thread change

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

* fix(example): reverse channel.messages to chronological order for AI

channel.messages yields newest first but AI expects chronological order.

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

* fix(chat): auto-sort messages chronologically in toAiMessages

toAiMessages now sorts by dateSent (oldest first) so callers don't need
to worry about iteration order from channel.messages or thread.messages.

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

* fix(chat): pass accumulated stream text as markdown in Channel.post()

Stream text was posted as a plain string, bypassing the adapter's format
converter. Now wraps it as { markdown: accumulated } so headings, bold,
italic etc. are properly converted for each platform.

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

* fix(whatsapp): use stringifier options for emphasis and bullets

Use emphasis: '_' and bullet: '-' options in stringifyMarkdown so the
only * in output is **strong**, avoiding conflicts between list bullets
and italic markers. Simplifies toWhatsAppFormat to only convert
**bold** -> *bold* and ~~strike~~ -> ~strike~.

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

* fix(whatsapp): flatten bold inside headings to avoid triple asterisks

When AI outputs headings with bold text like `## **Choose React if:**`,
the heading-to-bold conversion created nested strong nodes producing
`***text***`. Now flattens strong children in headings so they merge
into a single bold span.

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

* test(whatsapp): add full toBe assertion for complex markdown conversion

Also use ━━━ for thematic breaks instead of --- to avoid remark escaping.

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

* test: add WhatsApp replay tests from production recordings

Adds WhatsApp DM replay test infrastructure:
- Fixture from real webhook recordings (dm/whatsapp.json)
- WhatsApp test utilities with HMAC-signed request factory and
  Graph API fetch mock (whatsapp-utils.ts)
- 6 replay tests covering DM handling, thread/channel IDs, message
  sending, status update filtering, sequential messages, and
  message history persistence

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

* fix(whatsapp): fix type narrowing in replay test after merge

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

* Update WhatsApp logo

* Update adapters.json

* Update logos.tsx

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Chitru Shrestha <chitra.shrestha@akuru.com.au>
Co-authored-by: Malte Ubl <malte.ubl@gmail.com>
2026-03-10 15:16:10 -07:00
Malte Ubl 350717aa6b Switch back to sonnet. Otherwise streaming is too fast. Remove the immediate response on AI responses. 2026-03-07 12:42:26 -08:00
Malte Ubl a3cfc1aee3 Support native tables in slack (#194)
* Support native tables in slack

Brand new per https://docs.slack.dev/reference/block-kit/blocks/table-block/
Only one per message.

* Record streams

* Error handling

* Debugging

* fix-delta

* fix-delta2

* fix-delta3

* fix-delta4

* fix-delta5

* show-table

* show-table2

* replay-test

* changeset

* lint-types
2026-03-07 12:31:18 -08:00
Hayden Bleasel ebbe108b76 Fix code scanning issues 2026-03-06 17:15:03 -08:00
Hayden Bleasel 5cfd9be5fa Fix JSX issues (#161)
* Fix JSX issues

* fix: add null guards for event.thread in onAction handlers

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-05 16:13:33 -08:00
Malte Ubl ff954f938b Correctly handle AI SDK stream concatenation (#170)
* Correctly handle AI SDK stream concatenation

* changset

* docs

---------

Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
2026-03-04 11:02:02 -08:00
Nicolás Montone f0c7050349 add member_joined_channel event support to Slack adapter (#167)
* Add member_joined_channel event support to Slack adapter

* changset

* Apply suggestion from @NicolasMontone

* fix
2026-03-03 16:24:40 -08:00
Malte Ubl 02e7ef605c Implement markdown and AST rendering for tables across adapters (#160)
* Implement markdown and AST rendering for tables across adapters

* Render the default instead

* Fix bot app

* lint

* streaming-rendering

* fix-streaming

* fix-streaming-agent

* fix-streaming-again2

* fix-streaming-again3

* prefix tests

* no final edit

* changeset

* feedback

* lint

* Copilot feedback
2026-03-03 09:43:18 -08:00
Peter Clement f01b92fec4 Ensure handling of Discord slash commands (#152)
* Correctly handle discord slash commands

* chore: remove unintended bot.tsx formatting churn

* tidy up

* Expand subcommand path into event.command

* Fix race condition

* Run fix

* Fix duplicate slash-context check

* Fix integration test mock

* Run fix

* Update docs

---------

Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
2026-03-02 13:21:25 -08:00
dependabot[bot] 3574a5b47e Bump next from 16.0.10 to 16.1.5 (#146)
Bumps [next](https://github.com/vercel/next.js) from 16.0.10 to 16.1.5.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v16.0.10...v16.1.5)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.1.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 20:28:30 -08:00
Nicolás Pujia 740abd93b9 fix: use createMemoryState if no REDIS_URL (#142) 2026-02-28 18:59:30 -08:00
Hayden Bleasel f1a620dfbe Update proxy.ts 2026-02-27 10:08:05 -08:00
Hayden Bleasel 730fa67283 Rename middleware to proxy 2026-02-27 09:29:46 -08:00
Hayden Bleasel b66b5ed849 Remove files 2026-02-27 09:29:09 -08:00
Hayden Bleasel ac1c55ceeb Resolves #78 2026-02-27 09:24:16 -08:00
dependabot[bot] a22b14136c Bump @types/node from 22.19.3 to 25.3.0 (#79)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.3 to 25.3.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.3.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-27 09:01:01 -08:00
Tobias Lins 0c688a0111 Add support for telegram bot (#90)
* Add support for telegram bot

* Add support for action buttons in telegram

* Use markdown parse mode

* Add more tests

* Fix linting issues

* Fixes

* Fixes

* Don't reverse order messages for AI and always answer for telegram

* Add telegram integration test

* Update telegram.json
2026-02-26 14:10:41 -08:00
Nicolás Montone 5b3090a7a6 add CardLink Element (#109) 2026-02-25 08:05:30 -08:00
Vishal Yathish 90dc3251a5 [slack] add support for typing indicators with custom loading states (#87)
* [slack] add support for typing indicators with custom loading states

* adjust docs

* add changeset

* adjust

* remove

* minor bugfix

* add to example
2026-02-24 12:12:47 -08:00
Malte Ubl 9affdf3a55 Make the logger optional and infer most adapter config (#88)
* Make the logger optional and infer most adapter config

* Fix init
2026-02-23 17:48:41 -08:00
Hayden Bleasel 3070a0388c Model updates 2026-02-21 11:24:34 -08:00
Hayden Bleasel e970a6939b Upgrade Biome configuration to use Ultracite preset (#81)
* Upgrade Biome to Ultracite

* Remove package commands

* Update biome.jsonc

* Update biome.jsonc

* Initial fixes

* Update biome.jsonc

* Remaining fixes

* Update pnpm-lock.yaml

* Fix commands

* Update knip.json

* Merge Claude files

* Fix skipped test

* Misc fixes
2026-02-20 22:01:10 -08:00
Hayden Bleasel 1348532068 Open Source Beta Prep (#73)
* Update docs - Slack Assistants API, App Home tab, Stream stop blocks

* Update README.md

* Update package readmes, fix readme integration test

* Add npm badges to all package READMEs

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

* Add test coverage to all packages

* Create CODE_OF_CONDUCT.md

* Create pull_request_template.md

* Create issue templates

* Create config.yml

* Add unit tests for errors, singleton, logger, message, modals, gchat utils, and teams markdown

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

* Add a vitest:workspace command

* Misc URL fixes

* Update CONTRIBUTING.md

* Misc fixes, upgrade workflow/serde

* Replace PII in integration test data

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 13:25:09 -08:00
Vishal Yathish 8c50252d00 [chat] add support for slash commands (#50)
* [chat] add support for slash commands

* add comprehensive tests

* add documentation

* adding changeset
2026-02-18 08:32:44 -08:00
Malte Ubl 446df01e75 [RFC] Add Channel abstraction as first-class citizen alongside Thread (#46)
* [chat] add Channel abstraction as first-class citizen alongside Thread

Introduces a Channel concept — the container that holds threads — enabling
channel-level operations, thread-to-channel navigation, and natural support
for threadless platforms (iMessage, WhatsApp, SMS).

Design:

- Postable base interface: shared by both Thread and Channel, providing id,
  adapter, isDM, state/setState, messages (newest-first async iterator),
  post, postEphemeral, startTyping, mentionUser. Enables polymorphic code
  that works with either entity.

- Channel interface (extends Postable): adds name, threads() async iterator,
  and fetchInfo(). ChannelImpl provides the concrete implementation with
  backward message pagination, thread listing, posting, state management
  (channel-state: key prefix), and workflow serialization (chat:Channel).

- Thread updates: Thread now extends Postable and gains a `channel` getter
  (lazy-created, cached ChannelImpl) and a `messages` getter (newest-first
  backward iterator) alongside the existing `allMessages` (oldest-first).

- Channel ID format: derived from thread IDs by dropping the thread part.
  Default: first two colon-separated parts (slack:C123, gchat:spaces/ABC).
  Adapters override via optional channelIdFromThreadId() method.

- Adapter interface additions (all optional): channelIdFromThreadId,
  fetchChannelMessages, listThreads, fetchChannelInfo, postChannelMessage.

- Chat class: chat.channel(channelId) method creates a Channel by ID,
  auto-inferring adapter from the prefix. Reviver handles chat:Channel.

- Slack adapter: implements all five channel methods using
  conversations.history (vs conversations.replies for threads),
  conversations.info, and chat.postMessage without thread_ts.

- Mock adapter: updated with all channel methods for testing.

- 32 new tests covering ChannelImpl, thread.channel, deriveChannelId,
  and the backward messages iterator.

Usage:

  // Navigate from thread to channel
  const channel = thread.channel;

  // Get a channel directly
  const channel = chat.channel("slack:C123ABC");

  // Iterate messages newest first
  for await (const msg of channel.messages) { ... }

  // List threads in a channel
  for await (const t of channel.threads()) { ... }

  // Post to channel top-level
  await channel.post("Hello channel!");

TODO:
- Add replay tests for channel operations against recorded webhook data
- Implement channel methods in non-Slack adapters (GChat, Teams, Discord,
  GitHub, Linear) — currently they fall back to the default/no-op behavior

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

* channel-post-sample

* Better metadata

* Fix bug

* Fixes

* Other adapters

* Fix-gchat

* Fix-discord

* Fix-discord-threads

* Discord replay

* Teams tests and fix pre-existing failures

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-16 17:09:51 -08:00
Vishal Yathish 417374b844 [chat] add inline select components (#45)
* [chat] add inline select components

* changeset

* adding radio buttons

* adding unit tests

* add documentation for the new components

* add replay tests
2026-02-15 17:18:53 -08:00
Vishal Yathish f7cdd29641 [modals] enable modals from ephemeral messages (#42)
* [modals] enable modals from ephemeral messages

* add replay tests

* edit in place
2026-02-14 21:40:58 -08:00
Nicolás Montone c7d51cb8f4 add support for privatemetadata in slack adapter (#40)
* add private metadata in chat adapter

* add test on jsx runtime

* changeset
2026-02-14 17:17:03 -08:00
Nicolás Montone 5ed3ed9126 add example 2026-02-09 14:03:50 -08:00
Fernando Rojo e8ec9cd901 oauth 2026-02-05 20:06:55 -05:00
Fernando Rojo 0392ad6701 linear threads 2026-02-05 19:58:09 -05:00
Fernando Rojo 154dda0965 linear 2026-02-05 19:52:12 -05:00
Fernando Rojo 284dc2830f log 2026-01-31 22:59:23 -05:00
Fernando Rojo d4db2ff47e fix: rendering 2026-01-31 22:06:48 -05:00
Fernando Rojo 0b4899c8fc emoji support 2026-01-31 21:33:28 -05:00
Fernando Rojo 5b0f3f5a94 fixes 2026-01-31 21:24:21 -05:00
Fernando Rojo 1fb8fd2a50 github 2026-01-31 19:02:43 -05:00
Vishal Yathish 160f1f7d59 [chat] fetch event relatedMessage separately (#25)
* [chat] fetch event message separately

* add replay tests

* remove logs

* add changeset

* pass context between modal frames

* remove dividers

* remove unused export
2026-01-23 21:44:53 -08:00
Vishal Yathish 5eec3f6cdc restore 2026-01-22 15:32:15 -08:00
Vishal Yathish 660a84ee09 cleanup 2026-01-22 15:30:44 -08:00
Vishal Yathish e84cbf4187 [chat] add relatedThread and relatedMessage props to modal events 2026-01-22 13:19:09 -08:00
Fernando Rojo 70bca43f51 lint 2026-01-21 15:00:17 -05:00
Fernando Rojo b03cbd7130 add <LinkButton> 2026-01-21 14:54:48 -05:00
Fernando Rojo 8073eae795 fix: lint 2026-01-21 12:23:59 -05:00
Fernando Rojo 4f2ff75070 ephemeral readme 2026-01-21 11:14:39 -05:00
Vishal Yathish a488dbf118 [chat] add support for modals and form inputs + add to slack adapter 2026-01-20 10:20:08 -08:00
Malte Ubl e9a540a574 Remove bad Fluid behavior 2026-01-06 08:57:22 -08:00