Commit Graph

75 Commits

Author SHA1 Message Date
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
bai 8fe175f7fe Implement state adapter based on Postgres (#154)
* Initial work on postgres state store

* Run fix

* Replace pre-written CHANGELOG with proper changeset

The CHANGELOG was manually written with a version entry. This repo uses
Changesets to manage versioning, so add a proper changeset file instead.

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

* Add missing @vitest/coverage-v8 dev dependency

The vitest config specifies coverage provider "v8" but the package
was missing from devDependencies.

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

* Drop drizzle-orm, use raw postgres queries

The adapter only needs 3 simple tables with basic CRUD. drizzle-orm is
a full ORM that adds significant dependency weight for no real benefit
here. The ensureSchema() method was already using raw queries. This
halves the dependency surface to just the postgres driver.

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

* Add comprehensive unit tests for postgres state adapter

Test factory function edge cases (missing URL, env var fallbacks,
custom keyPrefix) and ensureConnected guard for all state operations.

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

* Document expired row cleanup limitation for postgres adapter

Unlike Redis, Postgres doesn't auto-delete expired rows. Document the
opportunistic cleanup behavior and provide SQL for periodic cleanup.

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

* Remove stale drizzle keyword from package.json

drizzle-orm was removed in a prior commit but the keyword remained.

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

* Fix expiresAt parsing in acquireLock

The postgres library returns timestamptz columns as JavaScript Date
objects, not strings. Wrapping in new Date() was unnecessary overhead.

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

* Document lock atomicity difference vs Redis adapters

The Postgres ON CONFLICT approach relies on row-level locking rather
than a single atomic SET NX PX like Redis. Note this for users who
need high-contention distributed locking.

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

* Use crypto.randomUUID() for lock token generation

Math.random() is not cryptographically secure and has a higher
collision risk in distributed environments. crypto.randomUUID() is
available in Node 16+ and provides better uniqueness guarantees.

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

* Delete CHANGELOG.md

* Add comprehensive unit tests for postgres state adapter

Mock the postgres module and SQL client to achieve 100% coverage
across statements, branches, functions, and lines. Tests cover
factory function, connection lifecycle, subscriptions, locking,
cache operations, and the owned-client disconnect path.

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

* Add setIfNotExists method and merge with main

Implement the setIfNotExists method added to the StateAdapter
interface since this branch diverged. Uses INSERT ... ON CONFLICT
DO NOTHING with RETURNING to atomically check-and-set.

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

* Add postgres to state docs navigation and memory adapter callout

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

* Migrate postgres state adapter from postgres to pg (node-postgres)

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

* Rename state-postgres to state-pg and align version to 4.17.0

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

---------

Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:05:32 -08:00
John Pham 130e780418 fix openModal crash when action has no thread context (#174)
* fix openModal crash when action has no thread context

Home tab actions (e.g. Change Team) have no thread → openModal closure
crashed accessing thread.channel on null. Guard thread access in the
openModal closure and pass undefined to storeModalContext.

Add test for empty threadId action → openModal works with null thread.

* add changeset

* make ActionEvent.thread nullable, remove unsafe cast

- Change `ActionEvent.thread` type from `Thread` to `Thread | null`
- Remove `null as unknown as Thread` unsafe cast in handleActionEvent
- Update test files to use null guards and optional chaining

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

---------

Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-04 11:15:33 -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
Hayden Bleasel da7e05d521 Fix Discord reaction events missing thread context (#158)
* Initial fix

* Add tests

* Create cute-nights-send.md

* Misc improvements
2026-03-02 13:44:00 -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
Hayden Bleasel f774c4e7b1 Run formatter 2026-02-27 10:03:36 -08:00
Hayden Bleasel b0ff46b62b Create telegram-utils.test.ts 2026-02-27 10:02:14 -08:00
Hayden Bleasel 8a9a6d2374 Upgrade vitest 2026-02-27 09:58:28 -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
Vishal Yathish 2623a50815 [bugfix] multiple files uploaded to slack as different messages (#116) 2026-02-25 16:58:40 -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
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
John Pham f371c0d951 feat(slack): add assistant_thread_started event support (#54)
* feat(slack): full Slack Assistants API support

- Route assistant_thread_started + assistant_thread_context_changed
- Add onAssistantThreadStarted + onAssistantContextChanged handlers
- Add setSuggestedPrompts, setAssistantStatus, setAssistantTitle methods
- Extend stream() for Block Kit on stop (stopBlocks)
- Bump @slack/web-api to ^7.11.0 for chatStream
- 14 integration tests

* fix: pass waitUntil to assistant thread started handlers
2026-02-19 16:18:05 -08:00
John Pham 283edba8ab feat(slack): enable DM support (#39)
* feat(slack): enable DM support with per-thread IDs and implicit mentions

DMs now use per-message threadTs (same as channels) instead of collapsing
all DM messages into one thread. Each top-level DM starts a new conversation;
thread replies continue the same conversation.

DM messages automatically set isMention=true so bots process them without
requiring @mention — natural for 1:1 conversations.

* fix: use empty threadTs for top-level DMs, thread_ts for replies

Top-level DM messages use empty threadTs to match openDM() subscriptions.
DM thread replies use thread_ts for per-conversation isolation.
Fixes integration test replay-dm.test.ts.

* style: fix biome formatting

* test: add e2e replay tests for direct DM implicit mention

* style: fix extra blank line lint error

* test: use real recorded DM fixtures for e2e tests
2026-02-18 11:30:22 -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 43172e7b89 formatting fix 2026-02-09 18:05:44 -08:00
Nicolás Montone 06b152abff add multi-workspace e2e 2026-02-09 15:29:53 -08:00
Nicolás Montone 935600514e Add multi-workspace support to slack adapter 2026-02-09 13:02:38 -08:00
Fernando Rojo acf570ac40 Merge pull request #30 from vercel-labs/f/linear
feat: add Linear adapter
2026-02-06 12:42:56 -05:00
Vishal Yathish efaa9162d3 [bugfix] slack API does not send team ID in event payload when files attached on thread start (#28)
* [slack] slack API does not send team ID in event payload when files attached on mention

* changeset
2026-02-05 17:10:29 -08:00
Fernando Rojo 154dda0965 linear 2026-02-05 19:52:12 -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
Fernando Rojo ce0ea536ba readme fixes 2026-01-21 12:52:44 -05:00
Fernando Rojo 62014514fe fix: tests in readme 2026-01-21 12:44:40 -05:00
Fernando Rojo 8073eae795 fix: lint 2026-01-21 12:23:59 -05:00
Malte Ubl 7403d64618 readme 2026-01-05 12:50:44 -08:00
Malte Ubl b1a8d47356 README tests 2026-01-04 18:55:01 -08:00
Malte Ubl 2286214024 README updates and replay test for role mention 2026-01-04 18:40:28 -08:00
Malte Ubl e64f13bb73 discord-ws15 2026-01-04 17:32:30 -08:00
Malte Ubl 21012ea23c Forwarding discord via http 2026-01-04 16:29:47 -08:00
Malte Ubl c9abd473ab verify9 2026-01-04 13:39:37 -08:00
Malte Ubl 8fabb998f9 verify6 2026-01-04 13:25:26 -08:00
Malte Ubl 815548c39a verify 2026-01-04 13:00:11 -08:00
Malte Ubl 50f06527e7 Add discord adapter (#7)
* Implement a discord adapter

* Integration tests
2026-01-04 12:44:34 -08:00
Malte Ubl 7e8826f9c2 Required-logger 2026-01-04 09:12:45 -08:00
Malte Ubl 4ef6e98b65 Test refactor 2026-01-03 13:48:05 -08:00
Malte Ubl 56d7c58f91 Teams original message 2026-01-03 13:33:59 -08:00
Malte Ubl 45c4f8b14d Fix teams again7 2026-01-03 13:17:06 -08:00
Malte Ubl 0c13ed5320 Fix teams again6 2026-01-03 13:04:24 -08:00
Malte Ubl 143af459f4 Fix teams again5 2026-01-03 12:20:34 -08:00
Malte Ubl 63cc5c85f1 Replay tests for fetchMessages and allMessages 2026-01-03 10:42:49 -08:00
Malte Ubl 09bb779f70 Make only one recording entry per sha 2026-01-03 08:32:24 -08:00