Commit Graph

182 Commits

Author SHA1 Message Date
github-actions[bot] b1940d2374 chore(release): version packages (#660)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @chat-adapter/github@4.33.0

### Minor Changes

- 6750d59: Add Vercel Connect support to the GitHub adapter. A new
`installationToken` config option (string or resolver) supplies
installation access tokens directly, skipping the GitHub App private-key
JWT exchange, and an optional `webhookVerifier` verifies inbound
webhooks (e.g. Connect trigger-forwarded requests via a Vercel OIDC
token) in place of the GitHub webhook secret. Pair with
`connectGitHubAdapter()` from `@vercel/connect/chat`.

`botUserId` now also auto-detects from the `GITHUB_BOT_USER_ID` env var,
and the adapter learns its bot user id from the first comment it posts.
In Connect mode (where the bot user id can't be auto-detected from an
installation token) set `botUserId` / `GITHUB_BOT_USER_ID` to enable
self-message detection and avoid the adapter replying to its own
comments.

Note: the `connectGitHubAdapter()` helper ships in `@vercel/connect` —
release this adapter together with (or after) the `@vercel/connect`
version that adds the `@vercel/connect/chat` subpath so the documented
helper resolves.

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/linear@4.33.0

### Minor Changes

- 4115c94: Add Vercel Connect support to the Linear adapter. The
`accessToken` config option now accepts a resolver (`() => string |
Promise<string>`) in addition to a string, so tokens can be sourced from
Vercel Connect at runtime, and a new optional `webhookVerifier` verifies
inbound webhooks (e.g. Connect trigger-forwarded requests via a Vercel
OIDC token) in place of the Linear webhook secret. Pair with
`connectLinearAdapter()` from `@vercel/connect/chat`. Connect-mode
outbound calls outside webhook handling are supported via
`withInstallation(organizationId, fn)`.

Note: the `connectLinearAdapter()` helper ships in `@vercel/connect` —
release this adapter together with (or after) the `@vercel/connect`
version that adds the `@vercel/connect/chat` subpath so the documented
helper resolves.

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/shared@4.33.0

### Minor Changes

- d4c52ca: add `replaceBareMentions`, a context-aware bare-`@mention`
resolver that skips code spans, URLs, schemeless hosts, and existing
angle-bracket tokens before handing each real `@name` to a
platform-specific replacer

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [076fe5d]
  - chat@4.33.0
## @chat-adapter/x@4.33.0

### Minor Changes

- ef2542c: add X (Twitter) adapter: reply to public mentions, send and
receive direct messages, post and edit from the bot account, and like
posts, using the X API v2 with OAuth 2.0 and managed token refresh

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## chat@4.33.0

### Minor Changes

- ef2542c: add X (Twitter) adapter: reply to public mentions, send and
receive direct messages, post and edit from the bot account, and like
posts, using the X API v2 with OAuth 2.0 and managed token refresh

### Patch Changes

- 3abdc69: docs(adapters): add Cloudflare Agents as a vendor-official
state adapter (`agents/chat-sdk`) to the catalog and docs listing. It is
hidden from the create-chat-sdk CLI (Worker/Durable Objects runtime),
and the interactive state picker now filters out CLI-incompatible state
adapters.
- 0b63791: Raise the default message dedupe TTL from 5 to 10 minutes so
it outlives the longest platform redelivery window. Slack's Events API
retries up to ~5 minutes after the original delivery — exactly at the
old TTL boundary, where a retried event could miss the expired dedupe
entry from its first processing and be handled twice. Configurable
behavior is unchanged (`dedupeTtlMs` still overrides).
- 0c761f1: docs(adapters): add Dial as a vendor-official adapter
(`@getdial/chat-sdk-adapter`) to the catalog, docs listing, and CLI
scaffold spec
- 24a04d5: docs(adapters): add Photon as a vendor-official adapter
(`@photon-ai/chat-adapter-imessage`) to the catalog, docs listing, and
CLI scaffold spec
- 076fe5d: preserve skipped mention routing for debounce and message
patterns
## create-chat-sdk@0.2.0

### Minor Changes

- ba375ce: Add Vercel Connect support to the scaffolder. Pass
`--connect` (or choose **Vercel Connect** at the new interactive
auth-mode prompt) to authenticate the Slack, GitHub, and Linear adapters
with a Vercel Connect connector instead of stored provider secrets. The
generated `src/lib/bot.ts` spreads the matching helper from
`@vercel/connect/chat` into the adapter factory, `@vercel/connect` is
added to dependencies, and `.env.example` lists each connector UID (for
example `SLACK_CONNECTOR`) plus the recommended `GITHUB_BOT_USER_ID` for
GitHub, in place of native secrets.
- ef2542c: add X (Twitter) adapter: reply to public mentions, send and
receive direct messages, post and edit from the bot account, and like
posts, using the X API v2 with OAuth 2.0 and managed token refresh

### Patch Changes

- 3abdc69: docs(adapters): add Cloudflare Agents as a vendor-official
state adapter (`agents/chat-sdk`) to the catalog and docs listing. It is
hidden from the create-chat-sdk CLI (Worker/Durable Objects runtime),
and the interactive state picker now filters out CLI-incompatible state
adapters.
- 0c761f1: docs(adapters): add Dial as a vendor-official adapter
(`@getdial/chat-sdk-adapter`) to the catalog, docs listing, and CLI
scaffold spec
- 24a04d5: docs(adapters): add Photon as a vendor-official adapter
(`@photon-ai/chat-adapter-imessage`) to the catalog, docs listing, and
CLI scaffold spec
## @chat-adapter/tests@4.33.0

### Minor Changes

- e7a396a: Add two shared behavioral test contracts for adapter authors:

- `threadIdContract` — verifies an adapter's thread-id codec round-trips
(`decode(encode(x))`), prefixes ids with the adapter name, matches any
pinned encoded strings, and (optionally) distinguishes DM from non-DM
threads.
- `selfMessageContract` — verifies an adapter dispatches inbound
messages from other users (to `processMessage` by default) but ignores
messages the bot authored itself, so it never replies to itself.
Requires the matchers to be registered via `setupFiles:
["@chat-adapter/tests/setup"]`.

- a7fb1bc: Add `connectWebhookContract`, a shared Vitest suite for
verifying an adapter's Vercel Connect webhook verification. Given a
small per-adapter descriptor (how to build the adapter in Connect mode
and craft an inbound webhook), it asserts the behavior every
Connect-capable adapter shares: a `webhookVerifier` replaces the native
signature/secret check and gates inbound requests — accept (`200`) on a
truthy result, reject (`401`) on a thrown error or falsy result — and is
invoked with the request and raw body. Connect-capable adapters can opt
in with ~10 lines.
## @chat-adapter/discord@4.33.0

### Patch Changes

- d4c52ca: use the shared `replaceBareMentions` scanner for `@mention`
conversion so email addresses, `@handles` inside URLs, and mentions
inside code spans are no longer mangled into Discord mentions, and
already-formatted `<@id>` tokens are not double-wrapped
- 6de4572: Implement `rehydrateAttachment` on the Discord adapter.
Serialization strips an attachment's `fetchData` closure (queue/debounce
strategies), and consumers rebuild it via `adapter.rehydrateAttachment`.
The Discord adapter did not implement the method, so downstream
consumers could not download inbound Discord attachments after
deserialization. The Discord CDN `url` survives serialization, so
`fetchData` is now rebuilt to fetch that url (preserving its signed
query params), matching how the other adapters implement the method.
- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/gchat@4.33.0

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/messenger@4.33.0

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/slack@4.33.0

### Patch Changes

- 0b63791: Process Slack Socket Mode retry envelopes instead of
discarding them. Slack redelivers an event (immediately, +1 min, +5 min)
when a prior delivery wasn't acknowledged — including events sent while
the app had no open socket, e.g. during a restart or a routine
connection refresh. The adapter previously acked and dropped every
envelope with `retry_num > 0`, so such events were permanently lost even
though Slack redelivered them. Retries are now routed like first
deliveries (logged at info with `retry_num`/`retry_reason`);
`Chat.processMessage`'s message-id dedupe drops true duplicates.
- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/teams@4.33.0

### Patch Changes

- d4c52ca: use the shared `replaceBareMentions` scanner for `@mention`
conversion so email addresses, `@handles` inside URLs, and mentions
inside code spans are no longer mangled into `<at>` mention tags
- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/telegram@4.33.0

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/twilio@4.33.0

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/web@4.33.0

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/whatsapp@4.33.0

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [d4c52ca]
- Updated dependencies [076fe5d]
  - chat@4.33.0
  - @chat-adapter/shared@4.33.0
## @chat-adapter/state-ioredis@4.33.0

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [076fe5d]
  - chat@4.33.0
## @chat-adapter/state-memory@4.33.0

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [076fe5d]
  - chat@4.33.0
## @chat-adapter/state-pg@4.33.0

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [076fe5d]
  - chat@4.33.0
## @chat-adapter/state-redis@4.33.0

### Patch Changes

- Updated dependencies [3abdc69]
- Updated dependencies [0b63791]
- Updated dependencies [0c761f1]
- Updated dependencies [ef2542c]
- Updated dependencies [24a04d5]
- Updated dependencies [076fe5d]
  - chat@4.33.0

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-07 23:22:51 +01:00
josh ef2542c5fd feat(x): add X (Twitter) adapter (#682)
## summary

new `@chat-adapter/x` adapter for X (Twitter), built on the X API v2 and
the X Activity API. write bot logic once and reply to mentions, hold DM
conversations, post from the account, and like posts, like the other
Chat SDK adapters

what it supports:
- reply to public mentions (`post.mention.create`) and top-level posts
via `channel.post`
- send and receive direct messages (`dm.received` / `dm.sent`)
- edit and delete owned posts, delete own DM events
- likes as the only reaction (`emoji.heart` or `"like"`)
- buffered streaming: accumulates an LLM stream and posts once instead
of post+edit churn on a public timeline
- OAuth 2.0 user context with managed token refresh (rotating refresh
token persisted in the state adapter, optional AES-256-GCM encryption)
- webhook CRC and `x-twitter-webhooks-signature` verification

key design decisions:
- DMs are threaded by the other participant's user id (`x:dm:{userId}`)
because X DM webhooks carry no conversation id, only participants
- OAuth 2.0 only at runtime: DM send and read are verified to work on
OAuth 2.0 user tokens, so no OAuth 1.0a in the adapter (subscription and
webhook setup is one-time and handled in the X developer console)
- parsers were written against real captured payloads: mentions use the
v2 shape (author hydrated in `includes.users`), DMs use the legacy
Account Activity shape (`direct_message_events`,
`message_create.message_data`, a `users` map, and no conversation id)

also includes the `chat/adapters` catalog entry, docs page, CLI scaffold
spec, and `sample-messages.md` with real captured payloads

<details><summary>usage</summary>

```typescript
import { Chat } from "chat";
import { createXAdapter } from "@chat-adapter/x";

const bot = new Chat({
  userName: "mybot",
  adapters: { x: createXAdapter() },
});

bot.onNewMention(async (thread, message) => {
  await thread.post(`hi @${message.author.userName}!`);
});

bot.onDirectMessage(async (thread) => {
  await thread.post("hello from X");
});
```
</details>

## test plan

- adapter unit tests pass against the real captured payload shapes, with
regression tests for author-from-`includes` (mentions) and the legacy
`direct_message_events` shape (DMs)
- real captured `post.mention.create` and `dm.received` payloads
verified end-to-end through `handleWebhook`: signature verification,
routing, author resolution, and participant threading, plus
bad-signature rejection returns 401
- every write and read path fired live against the X API through the
adapter: top-level post, reply to a mention, like and unlike, edit,
delete, DM send, DM read, DM delete
- OAuth 2.0 managed token refresh exercised live (access and refresh
token rotation)

---------

Signed-off-by: dancer <josh@afterima.ge>
2026-07-07 23:07:36 +01:00
OmriBenShoham 0c761f1bdd docs(adapters): add Dial as vendor-official adapter (#676)
Adds Dial as a vendor-official adapter — SMS, MMS, iMessage, and inbound
voice-call transcripts for Chat SDK.

- `vendor-official/dial.mdx` adapter page (following the Photon / Linq /
Sendblue format)
- catalog entry in `packages/chat/src/adapters/index.ts` with
`DIAL_API_KEY` / `DIAL_FROM_NUMBER_ID` / `DIAL_WEBHOOK_SECRET`
- `create-chat-sdk` scaffold spec entry
- registry entry in `adapters.json` + `dial` added to vendor-official
`meta.json`
- integration-test doc lists + changeset

Repo: https://github.com/GetDial-AI/chat-sdk-adapter · npm:
`@getdial/chat-sdk-adapter` · Dial docs:
https://docs.getdial.ai/integrations/agent-clients/vercel-chat-sdk

The adapter maps a phone conversation to a Chat SDK thread (identified
by the pair of phone numbers — Dial-owned and peer), an SMS/MMS/iMessage
to a message with optional media attachments, and a completed voice
call's transcript to a message on the caller's thread. Outbound sends
and transcript fetches go through the official `@getdial/sdk`; inbound
webhooks are HMAC-SHA256 verified against a per-subscription signing
secret with constant-time compare.

### Validation
- `pnpm --filter chat build` — clean
- `pnpm --filter chat typecheck` — clean
- `pnpm --filter create-chat-sdk typecheck` — clean
- `pnpm --filter @chat-adapter/integration-tests exec vitest run
src/docs-adapters.test.ts` — 361/361 passed
- `pnpm check` (ultracite) — clean
- `pnpm konsistent` — 34 files, no violations
2026-07-06 09:21:34 +10:00
Thomas Dietert 0b63791b66 fix(slack): process Socket Mode retry envelopes instead of dropping them (#667)
Fixes #666

## Summary

Both `slack_event` handlers (`startSocketMode` and
`runSocketModeListener`) ack and discard every envelope with `retry_num
> 0`. Slack retries an event (immediately, +1 min, +5 min) when a prior
delivery wasn't acked — including events that arrived while the app had
**no open socket** (restart, deploy, or Slack's routine connection
refreshes). For those, the retry is the only delivery the app ever sees,
so dropping it permanently loses the event (production incident details
in #666).

- **`@chat-adapter/slack`**: route retry envelopes through
`routeSocketEvent` like first deliveries (it acks per envelope type,
preserving the 3s ack window), and log them at info with `retry_num` /
`retry_reason` so redelivery is observable. Duplicate protection is
unchanged and sufficient: `Chat.processMessage` dedupes on `message.id`
(the Slack event `ts`, identical on a retry) via `state.setIfNotExists`.
- **`chat`**: raise the default `DEDUPE_TTL_MS` from 5 to 10 minutes.
Slack's final retry fires ~5 minutes after the original delivery —
exactly at the old TTL boundary, where the dedupe entry from the first
processing could expire just before the retry arrives and cause a
double-process. `dedupeTtlMs` config still overrides.

Behavior note for review: apps that relied on retries being invisible
will now see redelivered events flow through — deduped when already
handled, processed when not. That is the intended semantic:
at-least-once delivery from Slack, exactly-once handling via the SDK's
dedupe.

## Test plan

- Replaced the `"skips retries"` test with `"processes retries like
first deliveries (dedupe drops true duplicates)"` — asserts a
`retry_num: 1` envelope is acked and reaches `processMessage`.
- Updated the default-TTL test to 10 minutes; the custom-`dedupeTtlMs`
test is unchanged.
- `pnpm validate` passes end to end (knip, check, typecheck, test,
build); `pnpm --filter chat --filter @chat-adapter/slack test` = 1028 +
506 passing.


Signed-off-by: tdietert <thomasd@mercury.com>
2026-07-02 17:26:27 +01:00
Ben Sabic 3abdc69103 docs(adapters): add Cloudflare Agents as vendor-official state adapter (#669)
Adds Cloudflare Agents as a vendor-official **state** adapter —
`agents/chat-sdk`'s `createChatSdkState()`, a Chat SDK `StateAdapter`
that stores subscriptions, locks, queues, dedupe keys, thread/channel
state, transcripts, and history in Durable Object SQLite via
`ChatSdkStateAgent` sub-agents.

- `vendor-official/cloudflare-agents.mdx` state-adapter page (Agent
setup, wrangler DO migration, sharding, config, storage/cleanup)
- catalog entry in `packages/chat/src/adapters/index.ts` (`group:
vendor-official`, `type: state`)
- registry entry in `adapters.json` + `cloudflare-agents` in
vendor-official `meta.json`
- integration-test doc lists + changeset

Repo: https://github.com/cloudflare/agents · package `agents`
(`agents/chat-sdk`) ·
[docs](https://developers.cloudflare.com/agents/runtime/communication/chat-sdk/)

### Not wired into the create-chat-sdk CLI
This adapter runs inside a Cloudflare Worker with Durable Objects, not
the generated Next.js runtime, so it is intentionally kept out of the
scaffold:
- added to `CLI_INCOMPATIBLE_ADAPTERS` (rejected via `--adapter`, hidden
from the platform picker and e2e run, like `lark`/`matrix`)
- new `listCliStateAdapters()` filters the interactive **state** picker
and the `--help` adapter list (the state picker previously used raw
`listStateAdapters()` and would have offered it, then thrown on
selection)

### Tests
- `catalog/display.test.ts` — `listCliStateAdapters`: returns only state
adapters, includes `memory`/`redis`, and excludes `cloudflare-agents`
while asserting it *is* in the raw catalog
- `catalog/selection.test.ts` —
`resolveAdapterValue("cloudflare-agents")` throws "not supported"
- `cli/program.test.ts` — `buildAdapterList()` help text omits
`cloudflare-agents`
- existing `CLI_SCAFFOLD_SPEC covers every catalog adapter` +
docs-adapters/docs-content suites cover the catalog entry, registry
parity, and MDX imports

### Validation
- create-chat-sdk: **178 passed**, typecheck clean
- integration docs suites pass; Biome + knip clean

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-03 01:55:05 +10:00
Ben Sabic 24a04d5653 docs(adapters): add Photon as vendor-official adapter (#668)
Adds Photon as a vendor-official adapter — iMessage for Chat SDK.

- `vendor-official/photon.mdx` adapter page (following the Linq /
Sendblue / Kapso format)
- catalog entry in `packages/chat/src/adapters/index.ts` with
cloud/self-host credential modes
- `create-chat-sdk` scaffold spec entry
- registry entry in `adapters.json` + `photon` added to vendor-official
`meta.json`
- integration-test doc lists + changeset

Repo: https://github.com/photon-hq/vercel-chat-adapter-imessage · npm:
`@photon-ai/chat-adapter-imessage` · built on
[spectrum-ts](https://github.com/photon-hq/spectrum-ts)

The adapter runs in three modes — **Cloud** ([Spectrum
Cloud](https://app.photon.codes)), **self-hosted** (gRPC), and **local**
(on-device, macOS) — auto-detected from environment variables. Cloud
mode delivers inbound messages via HMAC-signed webhooks; DMs can be
replied to cold from a webhook delivery.

### Notes
- Catalog slug is `photon`; docs code examples use `imessage` as the
adapter key to match the upstream README.
- Feature flags encode the README's remote-only caveats (reactions /
editing / typing / modals as `partial`, mentions as DMs-only; no
history, thread info, or reaction removal).

### Validation
- `docs-adapters` integration tests — 1237 passed (catalog↔registry
parity, peerDeps↔PackageInstall alignment)
- `create-chat-sdk` e2e scaffold — 175 passed (scaffolds every catalog
adapter, incl. photon)
- `chat` + `create-chat-sdk` typecheck, Biome check, and konsistent —
clean

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-03 01:40:06 +10:00
Ben Sabic 6750d59e72 feat(github): add Vercel Connect support (#650)
Adds Vercel Connect support to the GitHub adapter:

- A new `installationToken` config option (string or resolver) supplies
installation access tokens directly, skipping the GitHub App private-key
JWT exchange.
- A new optional `webhookVerifier` verifies inbound webhooks (Connect
trigger-forwarded requests via a Vercel OIDC token) in place of the
GitHub webhook secret.

Pair with `connectGitHubAdapter()` from `@vercel/connect/chat`. Includes
a changeset (`@chat-adapter/github` minor).

Stacked on #647 (base `vercel-connect/base`).

## Companion

`@vercel/connect/chat` subpath: vercel/vercel#16826.

<img width="933" height="755" alt="CleanShot 2026-06-30 at 12 02 18"
src="https://github.com/user-attachments/assets/cc834560-0486-4f09-b8d5-8264be360544"
/>

---------

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-03 01:38:51 +10:00
josh 076fe5dc43 fix(chat): preserve skipped mention routing (#659)
## summary

fixes skipped mention routing for collapsed concurrency messages

queue and burst already passed skipped message context, but mention
routing could still swallow message pattern handlers when no
`onNewMention` handler was registered

this also makes debounce preserve skipped context so an earlier
debounced bot mention can still route to `onNewMention` when the latest
message does not mention the bot
2026-07-01 19:04:58 +10:00
github-actions[bot] 6f18930cf3 chore(release): version packages (#623)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @chat-adapter/discord@4.32.0

### Minor Changes

- 022a502: Add a Discord adapter interactionFlags callback for ephemeral
slash command responses.

### Patch Changes

- 0d4e3ee: fix: render bare URLs and autolinks as bare URLs instead of
`[url](url)` masked links, which Discord only renders inside embeds (in
normal messages they showed up as literal text)
- 490fa00: fix bare-mention conversion so it no longer mangles
surrounding text: email addresses and `word@word` handles are left
intact (the `@` must be at a word boundary), already-formatted mentions
like `<@123>` are no longer double-wrapped into `<<@123>>`, and a real
mention that follows a period (e.g. `docs.@everyone`) still converts
-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## chat@4.32.0

### Minor Changes

- 2e47351: Add `autoCompletePrevious` option to `Plan.addTask()`.
Defaults to `true` so sequential workflows keep auto-completing existing
in-progress tasks; pass `false` to keep multiple tasks in progress for
parallel execution.

### Patch Changes

-   eccc6b9: detect bot mentions in skipped queue and burst messages
- 438f551: Fix lightweight thread handles so streaming posts without an
incoming message context no longer crash.
- d034b8b: docs(adapters): add Linq as a vendor-official adapter
(`@linqapp/chat-sdk-adapter`) to the catalog, docs listing, and CLI
scaffold spec
- 06af3e1: docs(adapters): add Novu as a vendor-official adapter
(`@novu/chat-sdk-adapter`) to the catalog, docs listing, and CLI
scaffold spec
- efa9610: Sync bundled KB resources from Edge Config: add four new
guides (Vercel Connect, the Slack Vercel Connect bot, AI Gateway + AI
SDK, and the daily digest bot), refresh existing guide bodies, and
regenerate `resources/templates.json`. The `sync-resources` script now
fetches and validates all guides before writing (so a failed fetch
leaves the tree untouched), validates the source config shape, rejects
duplicate slugs, retries transient fetches, and mirrors `SKILL.md` to
all four committed copies.

## @chat-adapter/gchat@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## @chat-adapter/github@4.32.0

### Patch Changes

- fc7df9c: Remove raw GitHub webhook payload previews from adapter logs.

Debug and error logs now report only request-shape metadata, such as
body size, event type, content type, and signature presence, instead of
copying provider payload content into logs.

-   Updated dependencies [eccc6b9]

-   Updated dependencies [438f551]

-   Updated dependencies [d034b8b]

-   Updated dependencies [06af3e1]

-   Updated dependencies [2e47351]

-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## @chat-adapter/linear@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## @chat-adapter/messenger@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## @chat-adapter/shared@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0

## @chat-adapter/slack@4.32.0

### Patch Changes

- a8c4af7: prevent cached slack display names inside urls from being
resolved as user mentions before payload formatting
- 07c1112: Fix `@mention` rewriting so handles inside inline code spans
(`` `@vercel/postgres` ``) and fenced code blocks (```` ``` ````) are no
longer turned into `<@USER_ID>` Slack mentions. Agents printing npm
package names or shell snippets previously had those handles corrupted
into bot user IDs. Mention linking now skips whole code spans and code
blocks; handles outside code (including the same name mentioned
elsewhere in the message) still resolve normally.
-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## @chat-adapter/teams@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## @chat-adapter/telegram@4.32.0

### Patch Changes

- 937cac9: fix(telegram): stop `trimToMarkdownV2SafeBoundary` from
truncating valid messages at entity-marker characters (`_`, `*`, `~`)
inside link URLs. Per the MarkdownV2 spec, only `)` and `\` are special
inside the `(...)` part of an inline link, so URLs with raw underscores
in query parameters (e.g. `?a_b=1&c_d=2&e_f=3`) are now left intact
instead of being sliced mid-URL and degraded to plain text. Hard
truncation that cuts inside a link URL now trims back to before the
link's `[`.
- 4ee187a: Send Telegram typing actions immediately when private message
updates arrive.
-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## @chat-adapter/twilio@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## @chat-adapter/web@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## @chat-adapter/whatsapp@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0
    -   @chat-adapter/shared@4.32.0

## create-chat-sdk@0.1.1

### Patch Changes

- d034b8b: docs(adapters): add Linq as a vendor-official adapter
(`@linqapp/chat-sdk-adapter`) to the catalog, docs listing, and CLI
scaffold spec
- 06af3e1: docs(adapters): add Novu as a vendor-official adapter
(`@novu/chat-sdk-adapter`) to the catalog, docs listing, and CLI
scaffold spec

## @chat-adapter/state-ioredis@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0

## @chat-adapter/state-memory@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0

## @chat-adapter/state-pg@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0

## @chat-adapter/state-redis@4.32.0

### Patch Changes

-   Updated dependencies [eccc6b9]
-   Updated dependencies [438f551]
-   Updated dependencies [d034b8b]
-   Updated dependencies [06af3e1]
-   Updated dependencies [2e47351]
-   Updated dependencies [efa9610]
    -   chat@4.32.0

## @chat-adapter/tests@4.32.0

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-01 04:59:43 +01:00
Anudeep 2e4735118e fix: let Plan tasks run in parallel without implicit auto-completion (#632)
## Summary

Plan’s task list API always marked existing in-progress steps as
complete whenever a new step was added. That made sense for simple
sequential bots, but it blocked parallel work — even though the docs
already showed a parallel pattern and per-task updates by ID were added
earlier.

This PR adds an optional flag on task creation so callers can keep
multiple steps in progress at once, while leaving the old sequential
behavior as the default.


**Opt-out flag, default on**. We considered removing auto-completion
entirely. That would’ve been cleaner for parallel use but would’ve
broken existing sequential bots that rely on implicit “move to next
step” behavior. Defaulting to the current behavior keeps upgrades safe;
parallel callers pass the flag off.

**No broader API redesign**. Task completion stays explicit via status
updates and the existing “complete plan” flow. The change is scoped to
when a new task is appended.


closes #630
2026-07-01 04:26:48 +01:00
josh eccc6b91bf fix(chat): detect mentions in skipped queued messages (#656)
## summary

fixes #613

detects bot mentions across queued and burst skipped messages before
routing handlers

this makes `onNewMention` fire when an earlier skipped message mentions
the bot and the latest collapsed message does not, while preserving
`message.isMention` on the latest message

adds regression coverage for both `queue` and `burst`
2026-07-01 03:52:41 +01:00
Ben Sabic 99c598505f docs: refresh agent docs, README badges, and Chat SDK skill (#646)
- Replace npm version/download badges with Agent Stack and MIT badges on
the root README and all published package READMEs
- Streamline root `AGENTS.md`: fix title, add an accurate monorepo map,
trim duplicated CONTRIBUTING/Ultracite/env-var content, and link to
package-level `AGENTS.md` files
- Slim the Chat SDK agent skill (`skills/chat/SKILL.md` and published
copies) to defer to bundled docs, chat-sdk.dev, Vercel KB, and
`llms.txt` instead of inlining CLI flags, quick-start code, and API
tables
- Polish root README copy (install examples, adapter/build links, Vercel
Plugin URL, Vercel KB link, “Made by Vercel” badge)
- Minor `CONTRIBUTING.md` fixes: simplify DCO wording, correct
preview-branch proxy file references (`proxy.ts` vs middleware)

---------

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-27 14:06:13 +10:00
Akazawa Daisuke 438f5513b0 fix: avoid dummy message context for lightweight threads (#633)
## summary

fixes #631

removes dummy `Message` casts from lightweight thread, action, and
reaction paths when no incoming message context exists

this keeps the existing `currentMessage` guard meaningful and prevents
streaming through `chat.thread(threadId)`, `chat.openDM(...)`, action
threads, and reaction threads from reading fields from an empty object

when Slack lacks the thread or recipient context required by
`chat.startStream`, the adapter now returns `null` before consuming the
stream so Chat SDK can transparently use its post-and-edit fallback

native Slack streaming remains available for webhook-created threads and
DM threads with valid native stream context

---------

Co-authored-by: dancer <josh@afterima.ge>
2026-06-22 14:42:07 +01:00
Ben Sabic efa96108bd docs: sync KB resources and harden sync-resources script (#635)
Syncs the bundled Chat SDK KB resources from Edge Config and hardens the
`sync-resources` script that generates them.

- **New guides** (4): Vercel Connect, the Slack Vercel Connect bot, AI
Gateway + AI SDK, and the daily digest bot. Existing guide bodies
refreshed and `templates.json` regenerated.
- **Script hardening** (`scripts/sync-resources.ts`):
- Fetch + validate all guides into memory **before** wiping the
resources dir — a failed fetch now leaves the working tree untouched.
- Validate the `resources-edge-config.json` shape with a clear error
instead of a blind cast.
  - Reject duplicate guide slug collisions.
- Retry transient fetches (5xx / network) with exponential backoff; fail
fast on 4xx, bad content-type, and oversized bodies.
- Mirror `skills/chat/SKILL.md` to **all four** committed copies (docs
site `.well-known` + `AGENTS.md`, and the two `create-chat-sdk` scaffold
templates).
  - TSDoc on every function.
- **Tests**: new offline consistency test in
`packages/integration-tests` — every guide has a non-empty file with no
orphans, `templates.json` mirrors the config, no duplicate slugs, and
all four `SKILL.md` copies are byte-identical to the source.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-22 14:56:17 +10:00
George McCain d034b8b575 docs(adapters): add Linq as vendor-official adapter (#625)
Adds Linq as a vendor-official adapter — iMessage and SMS for Chat SDK.

- `vendor-official/linq.mdx` adapter page (following the Velt /
AgentPhone format)
- catalog entry in `adapters.json`
- `linq` added to the vendor-official `meta.json`

Repo: https://github.com/linq-team/linq-chat-sdk · npm:
`@linqapp/chat-sdk-adapter` (Apache-2.0)

The adapter is built and tested end-to-end against the live Linq API and
the Chat SDK runtime (real iMessage round-trip, webhooks, reactions,
media). Confirmed with Benji that a repo link works and Apache-2.0 is
fine. Happy to adjust the page to match any conventions I missed.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-20 11:47:57 +10:00
Dima Grossman 06af3e12fd docs(adapters): add Novu as vendor-official adapter (#622)
## Summary

Adds Novu as a vendor official adapter to Chat SDK allowing
multi-channel notification delivery and quick channel setup for
multi-tenant apps.

Official change log entry:
https://novu.co/changelog/novu-chat-sdk-adapter/
Official social post: https://x.com/novuhq/status/2067870170320679158 

## Test plan

Manually tested with our team to ensure compatability with the create
chat sdk and template apps, also created an example repo:
https://github.com/novuhq/novu-chat-sdk-example

## Checklist

- [x] All commits are signed and verified
- [x] `pnpm validate` passes
- [x] Changeset added (or N/A — see
[CONTRIBUTING.md](./CONTRIBUTING.md))
- [x] Documentation updated (or N/A)

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-19 22:11:33 +10:00
github-actions[bot] 2a553aa948 chore(release): version packages (#600)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @chat-adapter/slack@4.31.0

### Minor Changes

- 8336a3e: Add `webClientOptions` to `SlackAdapterConfig`, forwarded to
both the default and per-token `@slack/web-api` `WebClient` instances.
This exposes Web API settings such as `retryConfig`, per-request
`timeout`, and `rejectRateLimitedCalls`. Use the existing `apiUrl`
option to override the Slack Web API base URL.
- 171657a: Adding support for stable IDs to link button action handlers

### Patch Changes

- a8bf99a: Fix `@mention` rewriting so an `@handle` inside a URL is no
longer turned into a `<@handle>` Slack mention, which corrupted the
link. Mention linking now skips whole `http(s)://…` spans, so handles in
paths (`https://hackmd.io/@jkyang/abc`), query strings
(`?user=@george`), and fragments (`#@george`) are preserved; the
lookbehind also excludes a `/` immediately before `@` to cover
schemeless URLs (`mastodon.social/@user`). Whitespace- and
punctuation-led mentions (e.g. `(cc @george)`), emails, and `<mailto:…>`
links are unaffected.
-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## @chat-adapter/teams@4.31.0

### Minor Changes

-   8c71411: Add low-level Teams primitive subpaths for custom runtimes.

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## @chat-adapter/telegram@4.31.0

### Minor Changes

- 4662309: add native rich message formatting and streaming for Telegram
Bot API 10.1
- 9c936f8: Add support for routing Telegram bot commands to Chat SDK
slash command handlers

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## chat@4.31.0

### Minor Changes

- 778ae69: Add a zero-dependency `chat/adapters` catalog subpath for
official and vendor-official adapter metadata, environment specs, and
setup helpers.
- 171657a: Adding support for stable IDs to link button action handlers

## create-chat-sdk@0.1.0

### Minor Changes

- 8f3af76: Add the `create-chat-sdk` CLI for scaffolding webhook-only
Next.js Chat SDK bot projects. Supports interactive prompts,
non-interactive `--adapter` selection from the `chat/adapters` catalog,
coding-agent detection with an `--interactive` escape hatch, and
generated `src/lib/bot.ts`, `.env.example`, `next.config.ts`, and README
output per selected adapter.

## @chat-adapter/state-ioredis@4.31.0

### Minor Changes

- 8f3af76: Make `logger` optional in `createIoRedisState`, defaulting to
a console logger, matching `@chat-adapter/state-redis`.

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0

## @chat-adapter/discord@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## @chat-adapter/gchat@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## @chat-adapter/github@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## @chat-adapter/linear@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## @chat-adapter/messenger@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## @chat-adapter/shared@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0

## @chat-adapter/twilio@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## @chat-adapter/web@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## @chat-adapter/whatsapp@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0
    -   @chat-adapter/shared@4.31.0

## @chat-adapter/state-memory@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0

## @chat-adapter/state-pg@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0

## @chat-adapter/state-redis@4.31.0

### Patch Changes

-   Updated dependencies [778ae69]
-   Updated dependencies [171657a]
    -   chat@4.31.0

## @chat-adapter/tests@4.31.0

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-16 11:00:02 +01:00
Ben Sabic 8f3af76565 feat: add create-chat-sdk CLI (#603)
Adds `create-chat-sdk`, a CLI that scaffolds a Next.js Chat SDK bot
project:

```bash
npm create chat-sdk@latest my-bot

# non-interactive
npm create chat-sdk@latest -- my-bot --adapter slack redis -y
```

The user picks platform and state adapters interactively or via
`--adapter`, and the CLI generates a webhook-only project with
`src/lib/bot.ts`, `.env.example`, `next.config.ts`, `package.json`, and
a README, then optionally runs `git init` and installs dependencies.
There are no pages or client UI in the template.

Adapter choices come straight from the `chat/adapters` catalog, so the
CLI has no adapter registry of its own. When a coding agent such as
Cursor or Claude Code runs the CLI, it uses non-interactive defaults and
requires an explicit platform adapter. `--interactive` forces prompts.

## also in this pr

- `google-chat` is renamed to `gchat` everywhere, including docs pages,
the OG image, and adapter catalog. Old URLs redirect permanently,
including language-prefixed and `/og` paths
- a new docs page is available at `chat-sdk.dev/docs/create-chat-sdk`,
and the CLI is promoted on the homepage, package READMEs, and agent
skill
- `create-chat-sdk` releases independently with a minor changeset for
its initial `0.1.0` release

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: dancer <josh@afterima.ge>
2026-06-16 08:48:38 +01:00
Ben Sabic 778ae69abc add zero-dependency chat/adapters for adapters catalog (#599)
Adapter Catalog:
- Adds a zero-dependency `chat/adapters` subpath for official and
vendor-official adapter metadata.
- Includes typed catalog entries, env specs, peer dependency metadata,
and helper APIs for setup and onboarding flows.
- Wires the subpath into the `chat` package export map and build config.

Code Coverage:
- Adds unit coverage for catalog integrity, registry sync, helper
behavior, official env declarations, and peer dependency derivation.
- Extends docs integration coverage for `chat/adapters` imports and
vendor-official package install metadata.

Documentation:
- Documents the new catalog on the adapter overview page.
- Splits platform-specific adapter guidance into a new
`/docs/platform-adapters` page.
- Renames `/docs/state` to `/docs/state-adapters` and adds a redirect
for the old slug.

Agent Guidance:
- Updates repo-local and public agent guidance so agents know when and
how to use `chat/adapters`.
- Adds focused `AGENTS.md` guidance inside `packages/chat/src/adapters`
for future catalog maintenance.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-09 10:43:00 +10:00
Vishal Yathish 171657a019 [chat] adding stable id to link button action handlers (#598)
Enabling overriding the `link:<url>` action ID for `LinkButton` events.
2026-06-08 08:36:24 -07:00
Ben Sabic 9921dcd1c4 docs(seo): improve npm metadata, README discoverability, and structured data (#587)
Improves Chat SDK discoverability across npm, READMEs, and the docs site
for search engines and AI coding agents.

- **npm metadata**: point every published package `homepage` at
chat-sdk.dev deep links; expand `chat` keywords/description; fix
`repository.directory` (`packages/chat-sdk` → `packages/chat`); align
state adapter keywords
- **READMEs**: add npm callouts, Documentation/Guides links, and AI
Coding Agents sections (skill install, optional Vercel Plugin,
`llms.txt` / `llms-full.txt`) across all published packages and the repo
root
- **docs JSON-LD**: `HowTo` / `TechArticle` on getting-started,
streaming, and cards; `CollectionPage` + official-only `ItemList` on
`/adapters` (with split human vs JSON-LD descriptions)
- **UTMs**: add `chat-sdk_site` / `chat-sdk_repo` tracking params to
Resources links in selected MDX pages and adapter READMEs (discord,
github, slack, liveblocks, getting-started, ai index)
- **contract tests**: integration-tests guardrails for npm metadata and
README discoverability so future package additions don't drift

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-05 14:00:18 +10:00
josh f40c4d4840 docs(chat): clarify isMe semantics for adapter authors (#582)
## summary

clarifies that `author.isMe` means the message was sent by the current
bot runtime and should be filtered from handler dispatch

documents that adapters backed by user-owned accounts should not map
platform fields like `fromMe` directly to `isMe`

recommends tracking message ids returned by `postMessage` so webhook
echoes can be identified without filtering legitimate user-authored
messages
2026-06-03 13:40:58 -07:00
github-actions[bot] a5b118f1dc chore(release): version packages (#546)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @chat-adapter/slack@4.30.0

### Minor Changes

-   4c46c26: add lightweight Slack formatting primitives subpath
- dbd8dc5: expose runtime-free Block Kit helpers for Slack card
conversion
-   aba6aa9: add lightweight Slack API primitives subpath
-   b332a03: add lightweight Slack webhook primitives subpath
- 6ed4a43: add low-level Slack helpers for files, thread replies, views,
interactions, and input blocks

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)

- 073ff92: surface Slack file upload confirmation ids in postMessage
results

-   b63c042: fix(slack): resolve reaction user display names

Slack reaction events now resolve the reacting user's display name and
real name
through the existing cached user lookup path. If lookup fails, the
adapter falls
    back to the Slack user ID.

-   1294490: reuse low-level Slack formatting helpers in the adapter

- 999d268: pass the Slack bot token through native stream append and
stop calls

-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## @chat-adapter/telegram@4.30.0

### Minor Changes

- 5461ea9: Add native Telegram private chat draft streaming with
fallback streaming elsewhere.

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## @chat-adapter/twilio@4.30.0

### Minor Changes

- 25ebc3b: add Twilio SMS, MMS, and voice helpers with webhook,
messaging, and formatting primitives

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## @chat-adapter/whatsapp@4.30.0

### Minor Changes

- ffc43fc: Add WhatsApp typing indicator support by sending Meta's
read-plus-typing payload when a recent inbound message is available.
Update the default API version to v25.0.

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## chat@4.30.0

### Minor Changes

- 5461ea9: Add native Telegram private chat draft streaming with
fallback streaming elsewhere.

## @chat-adapter/discord@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## @chat-adapter/gchat@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
- 177735a: - Fix redundant mailto link rendering in Google Chat adapter
- Google Chat adapter was emitting redundant `<mailto:...|...>` tokens
when rendering autolinked email addresses. This change collapses
`mailto:` URLs when the visible text equals the email address, ensuring
cleaner output consistent with plain text rendering in Google Chat.
-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## @chat-adapter/github@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## @chat-adapter/linear@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## @chat-adapter/messenger@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## @chat-adapter/shared@4.30.0

### Patch Changes

-   Updated dependencies [5461ea9]
    -   chat@4.30.0

## @chat-adapter/teams@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## @chat-adapter/web@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0
    -   @chat-adapter/shared@4.30.0

## @chat-adapter/state-ioredis@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0

## @chat-adapter/state-memory@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0

## @chat-adapter/state-pg@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0

## @chat-adapter/state-redis@4.30.0

### Patch Changes

- 9b8d8c4: expand npm `keywords` for adapter and state packages to
improve discoverability (adds `chat-sdk`, `chatbot`, `ai-agent`,
`ai-sdk`, `vercel`, plus platform-specific terms)
-   Updated dependencies [5461ea9]
    -   chat@4.30.0

## @chat-adapter/tests@4.30.0

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-01 18:18:35 -07:00
Ben Sabic 9b8d8c4518 Discoverability lift: link KB guides, broaden npm keywords, mirror to AGENTS.md (#560)
Broad SEO/AEO pass across the docs site, adapter READMEs and AGENTS.md
files, and npm package metadata so Chat SDK content shows up better in
search engines, in LLM-driven package recommendations, and in
IDE/coding-agent context.

**Docs site**

- Adds a `## Resources` section to the Getting Started and AI overview
pages and to the Slack, Discord, GitHub, Liveblocks, and Sendblue
adapter pages, each linking to applicable guides/templates with
descriptions sourced from `resources-edge-config.json` and a cross-link
back to the central `/resources` hub.

**Adapter packages**

- Mirrors the same Resources sections into the Slack, Discord, and
GitHub READMEs (so they surface on npm) and into their AGENTS.md files
(so coding agents see them alongside the API notes).
- Expands `keywords` on every published adapter and state package — adds
`chat-sdk`, `chatbot`, `ai-agent`, `ai-sdk`, `vercel`, plus
platform-specific terms like `slack-bot`, `block-kit`, `slash-commands`,
`github-app`, `whatsapp-business`, `state-adapter`.

**Resources registry**

- Registers four new entries in `resources-edge-config.json`
(Human-in-the-Loop guide, Liveblocks AI agent guide, Slack + Vercel Blob
guide, Durable iMessage Agent template) and runs `pnpm sync-resources`
so the bundled `chat` package guides, `templates.json`, and
`skills/chat/SKILL.md` all pick them up.
- Fixes the synced Slack AI agent guide to import `toAiMessages` from
`chat/ai` instead of the deprecated `chat` re-export path (the upstream
KB source has also been updated, so future syncs will preserve this).

**Drive-by fixes**

- Resend adapter doc quick start: corrects `MemoryStateAdapter` class
import to the `createMemoryState()` factory (matching every other
adapter doc).
- Zalo adapter doc: drops the "community adapter" callout that
duplicated frontmatter.

**Tooling / CI**

- Adds `tsx` as a root devDependency so `pnpm sync-resources` works out
of the box (it previously relied on `npx tsx`, which hung when not
pre-cached).
- Loosens the CI changeset gate to also skip `packages/chat/resources/`
(generated data), matching the existing `*.md` carve-out.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-05-29 11:41:23 +10:00
luren 5461ea982b feat(telegram): add native DM draft streaming with segmented stream results (#340)
## Summary

Add native Telegram DM streaming via `sendMessageDraft` while preserving
Chat SDK's existing post+edit fallback for non-DM threads.

This PR:
- adds native private-chat draft streaming to the Telegram adapter
- splits long streamed markdown into Telegram-safe persisted segments
- retries without `parse_mode` when Telegram rejects markdown entity
parsing
- exposes segmented native stream results in the chat core
- updates docs and feature matrices to reflect Telegram DM draft
streaming

---------

Co-authored-by: dancer <josh@afterima.ge>
2026-05-28 15:17:10 -07:00
github-actions[bot] 6581d31507 chore(release): version packages (#469)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @chat-adapter/discord@4.29.0

### Minor Changes

- 2ffed48: Adapter internals are now `protected` rather than `private`,
so consumers can subclass an adapter to override or extend its behavior
(e.g. handling additional Telegram update types by overriding
`processUpdate`).

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines
- b9b17cd: handle slash commands and button interactions in Discord
gateway-only mode
-   Updated dependencies [ac8a207]
-   Updated dependencies [e60bc8c]
-   Updated dependencies [add2730]
-   Updated dependencies [b75eedb]
    -   chat@4.29.0
    -   @chat-adapter/shared@4.29.0

## @chat-adapter/gchat@4.29.0

### Minor Changes

- 2ffed48: Adapter internals are now `protected` rather than `private`,
so consumers can subclass an adapter to override or extend its behavior
(e.g. handling additional Telegram update types by overriding
`processUpdate`).

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines

- 06fb8e5: Align package shapes with the new `konsistent` conventions.
All changes are
backwards-compatible — previous type names are kept as deprecated
aliases.

- `@chat-adapter/gchat`, `@chat-adapter/slack`: moved `*AdapterConfig`
(and
related sub-types) into a `./types` module; the public re-exports from
        `index.ts` are unchanged.
- `@chat-adapter/slack`: `createSlackAdapter` now accepts
`SlackAdapterConfig`
directly instead of `Partial<SlackAdapterConfig>`. Every field on the
config
        was already optional, so no call sites need to change.
- `@chat-adapter/messenger`: `MessengerAdapterConfig` fields are now
optional
(the factory still falls back to `FACEBOOK_*` env vars), and `logger` /
`userName` live on `MessengerAdapterConfig` directly. The factory
signature
is now `createMessengerAdapter(config?: MessengerAdapterConfig)`.
- `@chat-adapter/web`: renamed `WebAdapterOptions` to
`WebAdapterConfig`; the
        old name is exported as a deprecated alias.
- `@chat-adapter/whatsapp`: every field on `WhatsAppAdapterConfig` is
optional
(the factory still falls back to `WHATSAPP_*` env vars).
`createWhatsAppAdapter`
is now typed `(config?: WhatsAppAdapterConfig) => WhatsAppAdapter`.
- `@chat-adapter/state-memory`: added an empty
`MemoryStateAdapterOptions`
type so the package matches every other state adapter;
`createMemoryState`
        now accepts an optional argument of that type.
    -   `@chat-adapter/state-ioredis`, `@chat-adapter/state-redis`,
`@chat-adapter/state-pg`: the URL- and client-based option shapes were
split
        into named interfaces (`*StateAdapterUrlOptions` /
`*StateAdapterClientOptions`) and unified under `*StateAdapterOptions`.
The
factories now take the union type directly. Old names —
`RedisStateClientOptions`,
        `CreateRedisStateOptions`, `PostgresStateClientOptions`,
`CreatePostgresStateOptions`, `IoRedisStateClientOptions` — are kept as
        deprecated aliases.

-   Updated dependencies [ac8a207]

-   Updated dependencies [e60bc8c]

-   Updated dependencies [add2730]

-   Updated dependencies [b75eedb]
    -   chat@4.29.0
    -   @chat-adapter/shared@4.29.0

## @chat-adapter/github@4.29.0

### Minor Changes

- 2f108bd: Rename the typed native client getter on the Slack, GitHub,
and Linear adapters to match the underlying SDK class.

- `bot.getAdapter("slack").client` is now
`bot.getAdapter("slack").webClient` (returns `WebClient` from
`@slack/web-api`).
- `bot.getAdapter("github").client` is now
`bot.getAdapter("github").octokit` (returns `Octokit`).
- `bot.getAdapter("linear").client` is now
`bot.getAdapter("linear").linearClient` (returns `LinearClient`).

The previous `.client` getter is kept as a deprecated alias on all three
adapters, so existing code continues to work without changes.

- 2ffed48: Adapter internals are now `protected` rather than `private`,
so consumers can subclass an adapter to override or extend its behavior
(e.g. handling additional Telegram update types by overriding
`processUpdate`).

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines
-   Updated dependencies [ac8a207]
-   Updated dependencies [e60bc8c]
-   Updated dependencies [add2730]
-   Updated dependencies [b75eedb]
    -   chat@4.29.0
    -   @chat-adapter/shared@4.29.0

## @chat-adapter/linear@4.29.0

### Minor Changes

- 2f108bd: Rename the typed native client getter on the Slack, GitHub,
and Linear adapters to match the underlying SDK class.

- `bot.getAdapter("slack").client` is now
`bot.getAdapter("slack").webClient` (returns `WebClient` from
`@slack/web-api`).
- `bot.getAdapter("github").client` is now
`bot.getAdapter("github").octokit` (returns `Octokit`).
- `bot.getAdapter("linear").client` is now
`bot.getAdapter("linear").linearClient` (returns `LinearClient`).

The previous `.client` getter is kept as a deprecated alias on all three
adapters, so existing code continues to work without changes.

- 2ffed48: Adapter internals are now `protected` rather than `private`,
so consumers can subclass an adapter to override or extend its behavior
(e.g. handling additional Telegram update types by overriding
`processUpdate`).

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines
-   Updated dependencies [ac8a207]
-   Updated dependencies [e60bc8c]
-   Updated dependencies [add2730]
-   Updated dependencies [b75eedb]
    -   chat@4.29.0
    -   @chat-adapter/shared@4.29.0

## @chat-adapter/messenger@4.29.0

### Minor Changes

- 2ffed48: Adapter internals are now `protected` rather than `private`,
so consumers can subclass an adapter to override or extend its behavior
(e.g. handling additional Telegram update types by overriding
`processUpdate`).

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines

- 06fb8e5: Align package shapes with the new `konsistent` conventions.
All changes are
backwards-compatible — previous type names are kept as deprecated
aliases.

- `@chat-adapter/gchat`, `@chat-adapter/slack`: moved `*AdapterConfig`
(and
related sub-types) into a `./types` module; the public re-exports from
        `index.ts` are unchanged.
- `@chat-adapter/slack`: `createSlackAdapter` now accepts
`SlackAdapterConfig`
directly instead of `Partial<SlackAdapterConfig>`. Every field on the
config
        was already optional, so no call sites need to change.
- `@chat-adapter/messenger`: `MessengerAdapterConfig` fields are now
optional
(the factory still falls back to `FACEBOOK_*` env vars), and `logger` /
`userName` live on `MessengerAdapterConfig` directly. The factory
signature
is now `createMessengerAdapter(config?: MessengerAdapterConfig)`.
- `@chat-adapter/web`: renamed `WebAdapterOptions` to
`WebAdapterConfig`; the
        old name is exported as a deprecated alias.
- `@chat-adapter/whatsapp`: every field on `WhatsAppAdapterConfig` is
optional
(the factory still falls back to `WHATSAPP_*` env vars).
`createWhatsAppAdapter`
is now typed `(config?: WhatsAppAdapterConfig) => WhatsAppAdapter`.
- `@chat-adapter/state-memory`: added an empty
`MemoryStateAdapterOptions`
type so the package matches every other state adapter;
`createMemoryState`
        now accepts an optional argument of that type.
    -   `@chat-adapter/state-ioredis`, `@chat-adapter/state-redis`,
`@chat-adapter/state-pg`: the URL- and client-based option shapes were
split
        into named interfaces (`*StateAdapterUrlOptions` /
`*StateAdapterClientOptions`) and unified under `*StateAdapterOptions`.
The
factories now take the union type directly. Old names —
`RedisStateClientOptions`,
        `CreateRedisStateOptions`, `PostgresStateClientOptions`,
`CreatePostgresStateOptions`, `IoRedisStateClientOptions` — are kept as
        deprecated aliases.

-   Updated dependencies [ac8a207]

-   Updated dependencies [e60bc8c]

-   Updated dependencies [add2730]

-   Updated dependencies [b75eedb]
    -   chat@4.29.0
    -   @chat-adapter/shared@4.29.0

## @chat-adapter/shared@4.29.0

### Minor Changes

-   add2730: support typed Telegram attachment uploads

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines
-   Updated dependencies [ac8a207]
-   Updated dependencies [e60bc8c]
-   Updated dependencies [b75eedb]
    -   chat@4.29.0

## @chat-adapter/slack@4.29.0

### Minor Changes

- 2f108bd: Rename the typed native client getter on the Slack, GitHub,
and Linear adapters to match the underlying SDK class.

- `bot.getAdapter("slack").client` is now
`bot.getAdapter("slack").webClient` (returns `WebClient` from
`@slack/web-api`).
- `bot.getAdapter("github").client` is now
`bot.getAdapter("github").octokit` (returns `Octokit`).
- `bot.getAdapter("linear").client` is now
`bot.getAdapter("linear").linearClient` (returns `LinearClient`).

The previous `.client` getter is kept as a deprecated alias on all three
adapters, so existing code continues to work without changes.

- c46fdb6: Add support for external `installationProvider` and
Enterprise Grid org-wide installs.

- New optional `installationProvider` config: `{
getInstallation(installationId, isEnterpriseInstall) =>
Promise<SlackInstallation | null> }`. When set, the adapter resolves bot
tokens for incoming events, slash commands, and interactive payloads
through the provider instead of the internal `StateAdapter` — useful for
hosted token-management systems (e.g. Vercel Connect). The provider is
read-only; OAuth callback writes (`setInstallation`,
`handleOAuthCallback`) and the `getInstallation`/`deleteInstallation`
public methods continue to use internal state, so callers using a
provider should manage their own writes.
- Enterprise Grid org-wide installs (`is_enterprise_install: true`) are
now keyed on `enterprise_id` instead of `team_id` across event_callback,
slash command, and interactive payload paths. Multi-workspace
deployments using the internal `StateAdapter` for org-wide installs must
repopulate installations under the `enterprise_id` key — previously,
org-wide events would fall through to a `team_id` lookup that did not
match what the OAuth flow had stored.

- fdebde7: feat(slack): expose direct `WebClient` access via
`adapter.client`

`bot.getAdapter("slack").client` now returns a typed `WebClient` from
`@slack/web-api`, matching the existing pattern on the Linear and GitHub
adapters. The returned client is bound to the bot token for the current
    request context (multi-workspace) or the configured default token
(single-workspace). Use it for any Web API call not covered by the SDK's
    high-level methods, e.g. `adapter.client.pins.add(...)` or
    `adapter.client.usergroups.list(...)`.

    Resolution order:

    1.  The token from the current `requestContext` — set during webhook
        handling, or by `adapter.withBotToken(token, fn)`.
    2.  The default `botToken`, when configured as a static string or a
        synchronous resolver function.

Throws `AuthenticationError` outside of any context in multi-workspace
mode, or when `botToken` is configured as an async resolver function.
    For async tokens, await the token first and bind it explicitly with
    `adapter.withBotToken(token, () => adapter.client...)`.

    Also fixes `createSlackAdapter()` silently dropping the `apiUrl`
    config field.

- 2ffed48: Adapter internals are now `protected` rather than `private`,
so consumers can subclass an adapter to override or extend its behavior
(e.g. handling additional Telegram update types by overriding
`processUpdate`).

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines

- 06fb8e5: Align package shapes with the new `konsistent` conventions.
All changes are
backwards-compatible — previous type names are kept as deprecated
aliases.

- `@chat-adapter/gchat`, `@chat-adapter/slack`: moved `*AdapterConfig`
(and
related sub-types) into a `./types` module; the public re-exports from
        `index.ts` are unchanged.
- `@chat-adapter/slack`: `createSlackAdapter` now accepts
`SlackAdapterConfig`
directly instead of `Partial<SlackAdapterConfig>`. Every field on the
config
        was already optional, so no call sites need to change.
- `@chat-adapter/messenger`: `MessengerAdapterConfig` fields are now
optional
(the factory still falls back to `FACEBOOK_*` env vars), and `logger` /
`userName` live on `MessengerAdapterConfig` directly. The factory
signature
is now `createMessengerAdapter(config?: MessengerAdapterConfig)`.
- `@chat-adapter/web`: renamed `WebAdapterOptions` to
`WebAdapterConfig`; the
        old name is exported as a deprecated alias.
- `@chat-adapter/whatsapp`: every field on `WhatsAppAdapterConfig` is
optional
(the factory still falls back to `WHATSAPP_*` env vars).
`createWhatsAppAdapter`
is now typed `(config?: WhatsAppAdapterConfig) => WhatsAppAdapter`.
- `@chat-adapter/state-memory`: added an empty
`MemoryStateAdapterOptions`
type so the package matches every other state adapter;
`createMemoryState`
        now accepts an optional argument of that type.
    -   `@chat-adapter/state-ioredis`, `@chat-adapter/state-redis`,
`@chat-adapter/state-pg`: the URL- and client-based option shapes were
split
        into named interfaces (`*StateAdapterUrlOptions` /
`*StateAdapterClientOptions`) and unified under `*StateAdapterOptions`.
The
factories now take the union type directly. Old names —
`RedisStateClientOptions`,
        `CreateRedisStateOptions`, `PostgresStateClientOptions`,
`CreatePostgresStateOptions`, `IoRedisStateClientOptions` — are kept as
        deprecated aliases.

- 0f0c203: fix(slack): prefer `webhookVerifier` over `signingSecret` and
`SLACK_SIGNING_SECRET`

When a `webhookVerifier` is configured, it now takes precedence over
both the
`signingSecret` config field and the `SLACK_SIGNING_SECRET` env var.
Previously,
    a configured `signingSecret` (or env var) would shadow the verifier.

-   Updated dependencies [ac8a207]

-   Updated dependencies [e60bc8c]

-   Updated dependencies [add2730]

-   Updated dependencies [b75eedb]
    -   chat@4.29.0
    -   @chat-adapter/shared@4.29.0

## @chat-adapter/teams@4.29.0

### Minor Changes

- 2ffed48: Adapter internals are now `protected` rather than `private`,
so consumers can subclass an adapter to override or extend its behavior
(e.g. handling additional Telegram update types by overriding
`processUpdate`).

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines
-   Updated dependencies [ac8a207]
-   Updated dependencies [e60bc8c]
-   Updated dependencies [add2730]
-   Updated dependencies [b75eedb]
    -   chat@4.29.0
    -   @chat-adapter/shared@4.29.0

## @chat-adapter/telegram@4.29.0

### Minor Changes

-   add2730: support typed Telegram attachment uploads
- 2ffed48: Adapter internals are now `protected` rather than `private`,
so consumers can subclass an adapter to override or extend its behavior
(e.g. handling additional Telegram update types by overriding
`processUpdate`).

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines
- 711babe: Handle `video_note` (round video messages) in
`extractAttachments`. Previously these messages were silently dropped;
now they are returned as `video` attachments with `width`/`height` set
to the clip's `length`.
-   Updated dependencies [ac8a207]
-   Updated dependencies [e60bc8c]
-   Updated dependencies [add2730]
-   Updated dependencies [b75eedb]
    -   chat@4.29.0
    -   @chat-adapter/shared@4.29.0

## @chat-adapter/web@4.29.0

### Minor Changes

- 2ffed48: Adapter internals are now `protected` rather than `private`,
so consumers can subclass an adapter to override or extend its behavior
(e.g. handling additional Telegram update types by overriding
`processUpdate`).
- 716e934: Add first-class Vue and Svelte support via new subpath
exports `@chat-adapter/web/vue` and `@chat-adapter/web/svelte`. Each
exports a `useChat()` factory preconfigured with `DefaultChatTransport`,
returning a framework-reactive `Chat` instance from `@ai-sdk/vue` /
`@ai-sdk/svelte` respectively. Note: unlike the React subpath which
wraps `@ai-sdk/react`'s `useChat` hook and returns destructurable
helpers, the Vue and Svelte wrappers return a `Chat` class instance —
access `chat.messages`, `chat.sendMessage()`, `chat.status`, and
`chat.stop()` directly on the object.

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines

- 06fb8e5: Align package shapes with the new `konsistent` conventions.
All changes are
backwards-compatible — previous type names are kept as deprecated
aliases.

- `@chat-adapter/gchat`, `@chat-adapter/slack`: moved `*AdapterConfig`
(and
related sub-types) into a `./types` module; the public re-exports from
        `index.ts` are unchanged.
- `@chat-adapter/slack`: `createSlackAdapter` now accepts
`SlackAdapterConfig`
directly instead of `Partial<SlackAdapterConfig>`. Every field on the
config
        was already optional, so no call sites need to change.
- `@chat-adapter/messenger`: `MessengerAdapterConfig` fields are now
optional
(the factory still falls back to `FACEBOOK_*` env vars), and `logger` /
`userName` live on `MessengerAdapterConfig` directly. The factory
signature
is now `createMessengerAdapter(config?: MessengerAdapterConfig)`.
- `@chat-adapter/web`: renamed `WebAdapterOptions` to
`WebAdapterConfig`; the
        old name is exported as a deprecated alias.
- `@chat-adapter/whatsapp`: every field on `WhatsAppAdapterConfig` is
optional
(the factory still falls back to `WHATSAPP_*` env vars).
`createWhatsAppAdapter`
is now typed `(config?: WhatsAppAdapterConfig) => WhatsAppAdapter`.
- `@chat-adapter/state-memory`: added an empty
`MemoryStateAdapterOptions`
type so the package matches every other state adapter;
`createMemoryState`
        now accepts an optional argument of that type.
    -   `@chat-adapter/state-ioredis`, `@chat-adapter/state-redis`,
`@chat-adapter/state-pg`: the URL- and client-based option shapes were
split
        into named interfaces (`*StateAdapterUrlOptions` /
`*StateAdapterClientOptions`) and unified under `*StateAdapterOptions`.
The
factories now take the union type directly. Old names —
`RedisStateClientOptions`,
        `CreateRedisStateOptions`, `PostgresStateClientOptions`,
`CreatePostgresStateOptions`, `IoRedisStateClientOptions` — are kept as
        deprecated aliases.

-   Updated dependencies [ac8a207]

-   Updated dependencies [e60bc8c]

-   Updated dependencies [add2730]

-   Updated dependencies [b75eedb]
    -   chat@4.29.0
    -   @chat-adapter/shared@4.29.0

## @chat-adapter/whatsapp@4.29.0

### Minor Changes

- 2ffed48: Adapter internals are now `protected` rather than `private`,
so consumers can subclass an adapter to override or extend its behavior
(e.g. handling additional Telegram update types by overriding
`processUpdate`).

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines

- 06fb8e5: Align package shapes with the new `konsistent` conventions.
All changes are
backwards-compatible — previous type names are kept as deprecated
aliases.

- `@chat-adapter/gchat`, `@chat-adapter/slack`: moved `*AdapterConfig`
(and
related sub-types) into a `./types` module; the public re-exports from
        `index.ts` are unchanged.
- `@chat-adapter/slack`: `createSlackAdapter` now accepts
`SlackAdapterConfig`
directly instead of `Partial<SlackAdapterConfig>`. Every field on the
config
        was already optional, so no call sites need to change.
- `@chat-adapter/messenger`: `MessengerAdapterConfig` fields are now
optional
(the factory still falls back to `FACEBOOK_*` env vars), and `logger` /
`userName` live on `MessengerAdapterConfig` directly. The factory
signature
is now `createMessengerAdapter(config?: MessengerAdapterConfig)`.
- `@chat-adapter/web`: renamed `WebAdapterOptions` to
`WebAdapterConfig`; the
        old name is exported as a deprecated alias.
- `@chat-adapter/whatsapp`: every field on `WhatsAppAdapterConfig` is
optional
(the factory still falls back to `WHATSAPP_*` env vars).
`createWhatsAppAdapter`
is now typed `(config?: WhatsAppAdapterConfig) => WhatsAppAdapter`.
- `@chat-adapter/state-memory`: added an empty
`MemoryStateAdapterOptions`
type so the package matches every other state adapter;
`createMemoryState`
        now accepts an optional argument of that type.
    -   `@chat-adapter/state-ioredis`, `@chat-adapter/state-redis`,
`@chat-adapter/state-pg`: the URL- and client-based option shapes were
split
        into named interfaces (`*StateAdapterUrlOptions` /
`*StateAdapterClientOptions`) and unified under `*StateAdapterOptions`.
The
factories now take the union type directly. Old names —
`RedisStateClientOptions`,
        `CreateRedisStateOptions`, `PostgresStateClientOptions`,
`CreatePostgresStateOptions`, `IoRedisStateClientOptions` — are kept as
        deprecated aliases.

-   Updated dependencies [ac8a207]

-   Updated dependencies [e60bc8c]

-   Updated dependencies [add2730]

-   Updated dependencies [b75eedb]
    -   chat@4.29.0
    -   @chat-adapter/shared@4.29.0

## chat@4.29.0

### Minor Changes

- ac8a207: Add `chat/ai` subpath as the home for AI utilities, including
`createChatTools` for the Vercel AI SDK and `toAiMessages` for
converting chat history into AI SDK prompts.

`createChatTools` exposes Chat SDK operations as ready-to-use AI SDK
tools so an agent can read messages, post replies, send DMs, react,
edit, delete, and manage thread subscriptions across every adapter the
supplied `Chat` instance has registered. Write operations require user
approval by default and can be toggled globally or per-tool via
`requireApproval`. Three presets (`reader`, `messenger`, `moderator`)
scope the toolset, and tools can also be cherry-picked from the same
subpath.

`toAiMessages` (and the `AiMessage` / `AiMessagePart` /
`ToAiMessagesOptions` types) now ship from `chat/ai` alongside the tools
— keeping the optional `ai` and `zod` peer dependencies out of bundles
that don't use them. The previous `chat` re-exports continue to work,
but are marked `@deprecated` so editors surface a hint pointing at
`chat/ai`; existing code keeps compiling, and migrating is a single
import-path change.

-   b75eedb: add burst concurrency strategy

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines

## @chat-adapter/state-ioredis@4.29.0

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines

- 06fb8e5: Align package shapes with the new `konsistent` conventions.
All changes are
backwards-compatible — previous type names are kept as deprecated
aliases.

- `@chat-adapter/gchat`, `@chat-adapter/slack`: moved `*AdapterConfig`
(and
related sub-types) into a `./types` module; the public re-exports from
        `index.ts` are unchanged.
- `@chat-adapter/slack`: `createSlackAdapter` now accepts
`SlackAdapterConfig`
directly instead of `Partial<SlackAdapterConfig>`. Every field on the
config
        was already optional, so no call sites need to change.
- `@chat-adapter/messenger`: `MessengerAdapterConfig` fields are now
optional
(the factory still falls back to `FACEBOOK_*` env vars), and `logger` /
`userName` live on `MessengerAdapterConfig` directly. The factory
signature
is now `createMessengerAdapter(config?: MessengerAdapterConfig)`.
- `@chat-adapter/web`: renamed `WebAdapterOptions` to
`WebAdapterConfig`; the
        old name is exported as a deprecated alias.
- `@chat-adapter/whatsapp`: every field on `WhatsAppAdapterConfig` is
optional
(the factory still falls back to `WHATSAPP_*` env vars).
`createWhatsAppAdapter`
is now typed `(config?: WhatsAppAdapterConfig) => WhatsAppAdapter`.
- `@chat-adapter/state-memory`: added an empty
`MemoryStateAdapterOptions`
type so the package matches every other state adapter;
`createMemoryState`
        now accepts an optional argument of that type.
    -   `@chat-adapter/state-ioredis`, `@chat-adapter/state-redis`,
`@chat-adapter/state-pg`: the URL- and client-based option shapes were
split
        into named interfaces (`*StateAdapterUrlOptions` /
`*StateAdapterClientOptions`) and unified under `*StateAdapterOptions`.
The
factories now take the union type directly. Old names —
`RedisStateClientOptions`,
        `CreateRedisStateOptions`, `PostgresStateClientOptions`,
`CreatePostgresStateOptions`, `IoRedisStateClientOptions` — are kept as
        deprecated aliases.

-   Updated dependencies [ac8a207]

-   Updated dependencies [e60bc8c]

-   Updated dependencies [b75eedb]
    -   chat@4.29.0

## @chat-adapter/state-memory@4.29.0

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines

- 06fb8e5: Align package shapes with the new `konsistent` conventions.
All changes are
backwards-compatible — previous type names are kept as deprecated
aliases.

- `@chat-adapter/gchat`, `@chat-adapter/slack`: moved `*AdapterConfig`
(and
related sub-types) into a `./types` module; the public re-exports from
        `index.ts` are unchanged.
- `@chat-adapter/slack`: `createSlackAdapter` now accepts
`SlackAdapterConfig`
directly instead of `Partial<SlackAdapterConfig>`. Every field on the
config
        was already optional, so no call sites need to change.
- `@chat-adapter/messenger`: `MessengerAdapterConfig` fields are now
optional
(the factory still falls back to `FACEBOOK_*` env vars), and `logger` /
`userName` live on `MessengerAdapterConfig` directly. The factory
signature
is now `createMessengerAdapter(config?: MessengerAdapterConfig)`.
- `@chat-adapter/web`: renamed `WebAdapterOptions` to
`WebAdapterConfig`; the
        old name is exported as a deprecated alias.
- `@chat-adapter/whatsapp`: every field on `WhatsAppAdapterConfig` is
optional
(the factory still falls back to `WHATSAPP_*` env vars).
`createWhatsAppAdapter`
is now typed `(config?: WhatsAppAdapterConfig) => WhatsAppAdapter`.
- `@chat-adapter/state-memory`: added an empty
`MemoryStateAdapterOptions`
type so the package matches every other state adapter;
`createMemoryState`
        now accepts an optional argument of that type.
    -   `@chat-adapter/state-ioredis`, `@chat-adapter/state-redis`,
`@chat-adapter/state-pg`: the URL- and client-based option shapes were
split
        into named interfaces (`*StateAdapterUrlOptions` /
`*StateAdapterClientOptions`) and unified under `*StateAdapterOptions`.
The
factories now take the union type directly. Old names —
`RedisStateClientOptions`,
        `CreateRedisStateOptions`, `PostgresStateClientOptions`,
`CreatePostgresStateOptions`, `IoRedisStateClientOptions` — are kept as
        deprecated aliases.

-   Updated dependencies [ac8a207]

-   Updated dependencies [e60bc8c]

-   Updated dependencies [b75eedb]
    -   chat@4.29.0

## @chat-adapter/state-pg@4.29.0

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines

- 06fb8e5: Align package shapes with the new `konsistent` conventions.
All changes are
backwards-compatible — previous type names are kept as deprecated
aliases.

- `@chat-adapter/gchat`, `@chat-adapter/slack`: moved `*AdapterConfig`
(and
related sub-types) into a `./types` module; the public re-exports from
        `index.ts` are unchanged.
- `@chat-adapter/slack`: `createSlackAdapter` now accepts
`SlackAdapterConfig`
directly instead of `Partial<SlackAdapterConfig>`. Every field on the
config
        was already optional, so no call sites need to change.
- `@chat-adapter/messenger`: `MessengerAdapterConfig` fields are now
optional
(the factory still falls back to `FACEBOOK_*` env vars), and `logger` /
`userName` live on `MessengerAdapterConfig` directly. The factory
signature
is now `createMessengerAdapter(config?: MessengerAdapterConfig)`.
- `@chat-adapter/web`: renamed `WebAdapterOptions` to
`WebAdapterConfig`; the
        old name is exported as a deprecated alias.
- `@chat-adapter/whatsapp`: every field on `WhatsAppAdapterConfig` is
optional
(the factory still falls back to `WHATSAPP_*` env vars).
`createWhatsAppAdapter`
is now typed `(config?: WhatsAppAdapterConfig) => WhatsAppAdapter`.
- `@chat-adapter/state-memory`: added an empty
`MemoryStateAdapterOptions`
type so the package matches every other state adapter;
`createMemoryState`
        now accepts an optional argument of that type.
    -   `@chat-adapter/state-ioredis`, `@chat-adapter/state-redis`,
`@chat-adapter/state-pg`: the URL- and client-based option shapes were
split
        into named interfaces (`*StateAdapterUrlOptions` /
`*StateAdapterClientOptions`) and unified under `*StateAdapterOptions`.
The
factories now take the union type directly. Old names —
`RedisStateClientOptions`,
        `CreateRedisStateOptions`, `PostgresStateClientOptions`,
`CreatePostgresStateOptions`, `IoRedisStateClientOptions` — are kept as
        deprecated aliases.

-   Updated dependencies [ac8a207]

-   Updated dependencies [e60bc8c]

-   Updated dependencies [b75eedb]
    -   chat@4.29.0

## @chat-adapter/state-redis@4.29.0

### Patch Changes

-   e60bc8c: chore: set supported Node versions in engines

- 06fb8e5: Align package shapes with the new `konsistent` conventions.
All changes are
backwards-compatible — previous type names are kept as deprecated
aliases.

- `@chat-adapter/gchat`, `@chat-adapter/slack`: moved `*AdapterConfig`
(and
related sub-types) into a `./types` module; the public re-exports from
        `index.ts` are unchanged.
- `@chat-adapter/slack`: `createSlackAdapter` now accepts
`SlackAdapterConfig`
directly instead of `Partial<SlackAdapterConfig>`. Every field on the
config
        was already optional, so no call sites need to change.
- `@chat-adapter/messenger`: `MessengerAdapterConfig` fields are now
optional
(the factory still falls back to `FACEBOOK_*` env vars), and `logger` /
`userName` live on `MessengerAdapterConfig` directly. The factory
signature
is now `createMessengerAdapter(config?: MessengerAdapterConfig)`.
- `@chat-adapter/web`: renamed `WebAdapterOptions` to
`WebAdapterConfig`; the
        old name is exported as a deprecated alias.
- `@chat-adapter/whatsapp`: every field on `WhatsAppAdapterConfig` is
optional
(the factory still falls back to `WHATSAPP_*` env vars).
`createWhatsAppAdapter`
is now typed `(config?: WhatsAppAdapterConfig) => WhatsAppAdapter`.
- `@chat-adapter/state-memory`: added an empty
`MemoryStateAdapterOptions`
type so the package matches every other state adapter;
`createMemoryState`
        now accepts an optional argument of that type.
    -   `@chat-adapter/state-ioredis`, `@chat-adapter/state-redis`,
`@chat-adapter/state-pg`: the URL- and client-based option shapes were
split
        into named interfaces (`*StateAdapterUrlOptions` /
`*StateAdapterClientOptions`) and unified under `*StateAdapterOptions`.
The
factories now take the union type directly. Old names —
`RedisStateClientOptions`,
        `CreateRedisStateOptions`, `PostgresStateClientOptions`,
`CreatePostgresStateOptions`, `IoRedisStateClientOptions` — are kept as
        deprecated aliases.

-   Updated dependencies [ac8a207]

-   Updated dependencies [e60bc8c]

-   Updated dependencies [b75eedb]
    -   chat@4.29.0

## @chat-adapter/tests@4.29.0

### Patch Changes

- 0adf3ad: Add `@chat-adapter/tests` — Vitest factories, matchers, and
setup utilities for Chat SDK adapter and bot authors.

- **Factories**: `createMockAdapter`, `createMockChatInstance`,
`createMockState` (with working in-memory
subscriptions/locks/KV/queues), `createTestMessage`,
`mockLogger`/`createMockLogger`.
- **Matchers**: `toHavePosted(threadId, textPattern?)`,
`toHaveDispatched(handler)`, `toBeSubscribedTo(threadId)`.
- **Setup file**: `@chat-adapter/tests/setup` registers all matchers via
`expect.extend` — drop into `vitest.config.ts` `setupFiles`.

`chat` and `vitest` are peer dependencies. Adapter-specific helpers
(e.g. signed Slack webhook builders) belong in each adapter's own
`/testing` subpath, not in this kit.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-18 07:16:55 -07:00
Ben Sabic ac8a20779c feat(chat): add chat/ai subpath for AI SDK utilities (#492)
## Summary

Introduces a dedicated `chat/ai` subpath as the home for every Vercel AI
SDK helper that ships with Chat SDK. Importing from this subpath keeps
the optional `ai` and `zod` peer dependencies out of bundles that don't
use them.

### What's new

- **`createChatTools`** — exposes Chat SDK operations as ready-to-use AI
SDK tools so an agent can read, post, react, edit, delete, and manage
thread subscriptions across every adapter the supplied `Chat` instance
has registered.
- Write operations require user approval by default (`requireApproval:
true`); toggle globally or per-tool.
- Three presets — `reader`, `messenger`, `moderator` — scope the
toolset.
- Individual tools can also be cherry-picked (`import { postMessage,
addReaction } from "chat/ai"`).
- **`toAiMessages`** (and the `Ai*` / `ToAiMessagesOptions` types) now
live alongside the tools at `chat/ai`. The previous `chat` re-exports
continue to work, but are flagged `@deprecated` with an editor hint
pointing to the new home — migration is a one-line import change.
- **Docs** — new `/docs/ai` section between Usage and Adapters in the
sidebar:
  - `/docs/ai` — Overview
  - `/docs/ai/ai-sdk-tools` — `createChatTools` guide
  - `/docs/ai/to-ai-messages` — `toAiMessages` reference
  - `/docs/ai/types` — Reference for every type exported from `chat/ai`
- **Example app** — `examples/nextjs-chat` now demos the new surface via
a "Run Agent Demo" button on the welcome card and a free-form `/agent
<prompt>` slash command (streaming, with a placeholder so users get
immediate feedback in channel contexts where Slack's typing-status API
is a no-op).

### Future plans

`createChatTools` currently exposes the cross-adapter Chat SDK surface
only. A natural follow-up is to also support **platform-specific tools**
— e.g. expose Slack-only `pin`/`unpin`, Discord-only thread archiving,
GitHub-only issue commenting, etc., so users can further extend what
their agent can do without dropping back to raw adapter calls. The shape
would likely be additional opt-in factories under `chat/ai` (or
per-adapter subpaths like `@chat-adapter/slack/ai`) that return tools
layered on top of the platform-specific adapter clients, while keeping
the cross-platform `createChatTools` API as the lowest common
denominator.

### Coverage

- `createChatTools` orchestrator: 100% statements / 94.7% branches.
- Every tool factory's `execute()` is exercised end-to-end (29 tests in
`index.test.ts`).
- `toAiMessages` keeps its existing 35-test suite covering role mapping,
attachment handling, links, transforms, and unsupported-attachment
fallbacks.
- Tools folder overall: 99.0% statements / 86.1% branches / 97.4%
functions / 98.9% lines.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: dancer <josh@afterima.ge>
2026-05-14 20:13:42 -07:00
josh b75eedbb5f feat(chat): add queue-debounce concurrency strategy (#495)
## summary

adds an opt-in `burst` concurrency strategy for #414

when a thread is idle, the first message waits for `debounceMs`,
messages that arrive during that window are queued, and the handler runs
once with the latest message plus earlier burst messages in
`context.skipped`

after the handler finishes, messages that arrived while it was running
are drained like `queue`, so the latest queued message is processed with
earlier queued messages in `context.skipped`

keeps existing `drop`, `queue`, `debounce`, and `concurrent` behavior
unchanged

updates docs to cover `burst`, explain when to choose it over
`debounce`, and document the related `MessageContext` behavior
2026-05-14 19:18:40 -07:00
josh 67c1794a54 docs(chat): clarify direct message routing precedence (#491)
## summary

clarifies that registered `onDirectMessage` handlers take precedence for
incoming DM messages before subscribed-message, mention, and pattern
routing

updates the direct messages, event handling, thread subscription, and
API docs so they match the current runtime behavior

adds `onDirectMessage` to the Chat API docs

fixes #432
2026-05-12 15:14:57 +10:00
Felix Arntz e60bc8c408 chore: add .nvmrc file, formally specify Node version range support, and cover more versions in CI (#465)
* add .nvmrc file

* follow up

* make support of Node >= 20 explicit

* update default Node version for contributing to the repo to 24

* run build-and-test CI job for both Node 20 and 24

* add changeset for package.json change
2026-05-11 19:28:34 +10:00
github-actions[bot] 5edcbbf7ef chore(release): version packages (#464)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-08 04:09:48 -07:00
github-actions[bot] b3fc64d34e chore(release): version packages (#442)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-08 04:01:03 -07:00
josh 0cc3d06fd4 docs: fix stale API examples, adapter matrix, and broken links (#463)
* 1

* 2

* cs

* 3
2026-05-08 03:58:08 -07:00
josh c1cd9b5da1 feat(chat): add callbackUrl to buttons and modals (#454)
* 1

* wfw

* 4224

* dfe

* wip

* f

* 22

* tsts

* more

* ch

* dc

* t

* tm

* docs

* ex

* k

* cs

* lock

* test(chat): expand callbackUrl coverage

* docs: document callbackUrl handling for adapter authors

* docs: expand changeset for callbackUrl feature

* docs(skill): mention callbackUrl on Button and Modal

* feat(example): add modal callbackUrl workflow demo

* test(integration): add replay tests for callbackUrl flows

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-05-08 17:26:18 +10:00
Vishal Yathish 68025ca965 [messenger] add messenger (meta) platform adapter to chat sdk (#461)
* [messenger] add messenger (meta) platform adapter to chat sdk

- Webhook handling with HMAC-SHA256 signature verification
- Generic and Button template support for cards
- Postback, reaction, delivery/read confirmation handling
- Message caching for fetchMessages (Messenger has no history API)
- Replay tests and ~98% code coverage

Co-authored-by: Dimitar K. Nikolov <mitkodkn@users.noreply.github.com>
Co-authored-by: Ben Sabic <27636870+bensabic@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix: The `@chat-adapter/messenger` package version is `4.15.0` while all other packages in the Changesets fixed version group are at `4.27.0`, breaking the fixed versioning contract.

This commit fixes the issue reported at packages/adapter-messenger/package.json:3

**Bug explanation:**

The repository uses Changesets with a `"fixed"` configuration: `[["chat", "@chat-adapter/*"]]`. This means all packages matching these patterns must always share the same version number. Every package in the group (`chat`, `@chat-adapter/discord`, `@chat-adapter/gchat`, `@chat-adapter/github`, `@chat-adapter/linear`, `@chat-adapter/shared`, `@chat-adapter/slack`, `@chat-adapter/teams`, `@chat-adapter/telegram`, `@chat-adapter/web`, `@chat-adapter/whatsapp`, and the state packages) is at version `4.27.0`, except `@chat-adapter/messenger` which is at `4.15.0`.

This is likely because the messenger adapter was newly added to the monorepo (copied from a template or created fresh) and its version was never aligned with the rest of the fixed group. This mismatch will cause problems with the Changesets release workflow — when Changesets tries to bump versions for the fixed group, it may produce inconsistent or errored releases because one package is 12 minor versions behind the others.

**Fix explanation:**

Changed `"version": "4.15.0"` to `"version": "4.27.0"` in `packages/adapter-messenger/package.json` to align it with all other packages in the fixed version group.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: visyat <vishal.yathish@gmail.com>

* Fix: Messenger adapter env var guard only checks `FACEBOOK_APP_SECRET` but `createMessengerAdapter` requires all three env vars, causing a `ValidationError` crash at Next.js build time when only `FACEBOOK_APP_SECRET` is set.

This commit fixes the issue reported at examples/nextjs-chat/src/lib/adapters.ts:154

**Bug Analysis:**

The build failure is confirmed in the Vercel build log with:
```
Error [ValidationError]: pageAccessToken is required. Set FACEBOOK_PAGE_ACCESS_TOKEN or provide it in config.
```

The root cause is in `examples/nextjs-chat/src/lib/adapters.ts` at line ~154. The messenger adapter guard only checks for `FACEBOOK_APP_SECRET`:
```typescript
if (process.env.FACEBOOK_APP_SECRET) {
```

However, `createMessengerAdapter` (in `packages/adapter-messenger/src/index.ts`) validates and throws `ValidationError` for each of three required env vars: `FACEBOOK_APP_SECRET`, `FACEBOOK_PAGE_ACCESS_TOKEN`, and `FACEBOOK_VERIFY_TOKEN`. When only `FACEBOOK_APP_SECRET` is set in the Vercel project environment, the guard passes, `createMessengerAdapter` is called, and it throws a `ValidationError` for the missing `FACEBOOK_PAGE_ACCESS_TOKEN`. Since this code runs at module evaluation time during the Next.js build's "Collecting page data" phase, the uncaught error crashes the entire build.

This is inconsistent with other adapters in the same file. For example, the WhatsApp adapter checks both `WHATSAPP_ACCESS_TOKEN` and `WHATSAPP_PHONE_NUMBER_ID`, and the gchat/github/linear/whatsapp adapters all wrap creation in try-catch blocks.

**Fix:**

1. Updated the env var guard to check all three required environment variables (`FACEBOOK_APP_SECRET`, `FACEBOOK_PAGE_ACCESS_TOKEN`, and `FACEBOOK_VERIFY_TOKEN`) before attempting to create the adapter.
2. Wrapped the `createMessengerAdapter` call in a try-catch block (matching the pattern used by gchat, github, linear, and whatsapp adapters) so that any unexpected validation errors are caught and logged as warnings instead of crashing the build.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: visyat <vishal.yathish@gmail.com>

---------

Co-authored-by: Dimitar K. Nikolov <mitkodkn@users.noreply.github.com>
Co-authored-by: Ben Sabic <27636870+bensabic@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
2026-05-08 17:25:54 +10:00
josh eb5f94a8ee feat(chat): add message.subject and adapter client access (#459)
* 1

* w

* 3f

* x

* ln

* gh

* sl

* t1

* u

* t2

* t3

* t4

* t5

* d

* d2

* cs

* fx

* cl

* docs: clean up subject + .client docs and restructure nav

- subject.mdx: simplify prose, drop redundant platform lists, link to MessageSubject API and getAdapter
- api/message.mdx: add MessageSubject TypeTable
- api/chat.mdx: expand getAdapter with Direct client access content
- adapters.mdx: add Parent subject and Native client rows to feature matrix
- usage.mdx: mention .client under Accessing adapters
- adapter-github/-linear READMEs: add Direct API client section
- meta.json: split Features into Messaging + Interactivity, move error-handling to Usage
- title case across messaging-cluster page titles

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-05-08 10:51:53 +10:00
Ben Sabic 3490a8c84c feat: add @chat-adapter/web — browser chat UI for chat-sdk bots (#444)
* feat(chat): expose awaitable Promise from processMessage

Return the inner task as Promise<void> instead of void so streaming
adapters can await full handler completion and surface user-handler
rejections at the wire level. waitUntil semantics for existing webhook
adapters are unchanged — the SDK still tracks the work with errors
swallowed (and logged) so platforms don't retry on handler bugs.

Required by @chat-adapter/web, whose response body is the user
handler's stream.

* feat(adapter-web): add @chat-adapter/web package

A new platform adapter that lets a chat-sdk bot serve a browser chat
UI alongside Slack/Teams/Discord/etc. without writing any client-side
glue. Speaks the AI SDK UI message stream protocol, so @ai-sdk/react's
useChat and the ai-elements component library work out of the box.

- `@chat-adapter/web` — server: createWebAdapter({ userName, getUser })
- `@chat-adapter/web/react` — client: useChat() preconfigured with
  DefaultChatTransport against /api/chat (override via `api`)

Defaults that matter for v1:
- `isDM: true` — every web message routes through onDirectMessage
- `persistMessageHistory: true` — chat-sdk caches each turn in the
  configured state adapter so handlers can read prior context via
  thread.messages / channel.messages (no platform history API exists)
- channelId === threadId — web has no separate channel concept; this
  prevents cross-conversation bleed when a single user has multiple
  useChat sessions
- Native `adapter.stream` implementation pumps text-deltas straight
  onto the SSE response — no post+edit fallback

Out of scope for v1: cards/JSX rendering, reactions, modals, file
uploads, edit/delete, multi-tab proactive push.

* feat(example-nextjs-chat): wire up web adapter and add /chat page

- Register the web adapter in lib/adapters.ts with a demo getUser
  (single shared identity — replace with NextAuth/Clerk/cookie auth
  in production)
- Expose POST /api/chat backed by bot.webhooks.web (using next/after
  for waitUntil)
- Add a minimal /chat page using @chat-adapter/web/react's useChat —
  same bot.onDirectMessage handler that powers Slack now powers the
  browser too

Bumps `ai` to ^6.0.174 to align with @ai-sdk/react@^3 (avoids dual
provider-utils versions in the workspace).

* docs: list @chat-adapter/web in registry

- Add an entry to adapters.json so the package shows up on /adapters
- Add a globe SVG to lib/logos.tsx and wire it into the icon map
- Mention the new adapter in docs/adapters.mdx

* feat(adapter-web): tighten request handling and message construction

- Reject user ids containing ':' with HTTP 400 — the character would
  corrupt the thread-id round-trip through decodeThreadId
- Skip emitting text-start/text-end in postMessage when the resolved
  text is empty so useChat doesn't render blank assistant bubbles
- Derive the parseMessage author from raw.role so rehydrated assistant
  messages report the bot identity instead of "unknown"
- Drop the duplicate handler-error log; chat.processMessage already
  logs at ERROR level
- Document the actual persistMessageHistory default (true) and the
  state-cache rationale; promote the fetchMessages no-op rationale
  into its JSDoc

* test(adapter-web): add direct coverage for stream()

- Aborting request.signal mid-stream short-circuits the iterator and
  still writes text-end via the finally block
- Non-text StreamChunks (task_update, plan_update) are dropped without
  emitting any delta
- The SentMessage returned from thread.post matches the id used in
  text-start / text-end events

* docs(adapter-web): expand README into the full adapter docs page

The docs site renders each adapter's README, so flesh out
@chat-adapter/web to match the depth of @chat-adapter/slack:
authentication boundary, threading semantics, streaming,
persistence, React hook reference, configuration table,
feature matrix, and troubleshooting.

* docs(adapter-web): drop unsupported provider import from streaming example

* fix(adapter-web): validate conversationId for reserved colon character

* fix(example): show error state in web chat demo

* fix(example): add thinking indicator to web chat demo

* feat(example): redesign web chat demo with tailwind

* chore: remove redundant changeset

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: dancer <josh@afterima.ge>
2026-05-05 15:55:40 -07:00
Ben Sabic 46d183bdab feat(chat): add Transcripts API + rename per-thread cache to threadHistory (#448)
* feat(chat): add Transcripts API and rename per-thread cache to threadHistory

Introduce `bot.transcripts` for cross-platform per-user message persistence.
When `ChatConfig.transcripts` and `ChatConfig.identity` are configured, every
inbound message has its `userKey` resolved during dispatch and the API exposes
`append` / `list` / `count` / `delete` keyed by that user. Backed by the
existing `StateAdapter.appendToList` primitive — every built-in state adapter
supports it with no contract changes.

Rename the existing per-thread history cache from `messageHistory` to
`threadHistory` (with backwards compat for `ChatConfig.messageHistory` and
`Adapter.persistMessageHistory`) so the two persistence layers don't share a
"messages" name. The state-adapter storage key prefix is unchanged so existing
data isn't orphaned.

`delete()` writes a tombstone via `appendToList(key, _, { maxLength: 1 })`
rather than `state.delete(key)`, because `state.delete` only addresses the
k/v namespace on every non-memory state adapter — `list()` and `count()`
filter the tombstone out so the API contract is preserved.

* docs(chat): cover Transcripts API and Conversation history

Add a Features-style "Conversation history" guide (`/docs/conversation-history`)
walking through identity resolution, the LLM-context append/list pattern,
filtering, and per-user deletion for DSR flows.

Add an API reference page at `/docs/api/transcripts` with `<TypeTable>` blocks
for `ChatConfig.transcripts`, `ChatConfig.identity`, every method on
`bot.transcripts`, and the `TranscriptEntry` shape.

Wire both into the corresponding `meta.json` files.

* example(nextjs-chat): wire Transcripts API into the AI mode handler

Replace the brittle `threadState.history` shim with `bot.transcripts.list({ ..., threadId, limit })` as the fallback context source for platforms without
`fetchMessages` (Telegram, WhatsApp). Drop the `history` field from
`ThreadState` accordingly.

Add a hardcoded `TEST_USER_KEY = "test-user"` so the API can be exercised
without juggling real user identities, plus "Show Transcripts" and
"Clear Transcripts" buttons in the welcome card so the store can be
inspected and reset from chat.

* fix(chat): tighten Transcripts API public surface and wiring

Polish on top of the Transcripts API + threadHistory rename, addressing
review concerns before merge.

Public surface (`types.ts`, `index.ts`):
- Expose `transcripts` on the `ChatInstance` interface so callers typed
  against the public interface can reach `bot.transcripts`.
- Promote the `count` argument to a named `CountQuery` interface,
  matching `DeleteTarget` / `ListQuery`. Exported from `index.ts`.
- Document on `TranscriptsApi.list()` that pagination is intentionally
  out-of-scope — the store keeps at most `maxPerUser` entries per user.
- Reconcile the `TranscriptEntry.id` JSDoc with the implementation:
  UUID assigned at append time, returned in append order, not
  lexicographically sortable; use `timestamp` for cross-store ordering.

Wiring (`chat.ts`):
- Include `threadId` in the identity-resolver failure log context so
  operators can correlate failures with the source thread.

Stale-reference sweep:
- Replace lingering "Messages API" / `chat.messages` /
  `messages.storeFormatted` strings in shipped JSDoc with the new
  `transcripts` names (these ride into `.d.ts` and are user-visible).
- Fix the dead `[Messages API](./messages.ts)` link in the existing
  thread-history-rename changeset.

* test(chat): cover dual-read precedence, resolver edges, concurrent ops

Fill gaps in the Transcripts API + threadHistory rename test suite:

`chat.test.ts` (persistThreadHistory block):
- top-level `config.messageHistory` (deprecated alias) flows through
  to the per-thread cache when `threadHistory` is unset
- `threadHistory` takes precedence over `messageHistory` when both are
  set — pinned by asserting `appendToList` receives the new config's
  `maxLength` / `ttlMs`
- both `persistThreadHistory` and `persistMessageHistory` set on the
  adapter still triggers persistence

`transcripts-wiring.test.ts`:
- sync resolver returning a plain string populates `message.userKey`
- resolver returning `""` is treated as no userKey (truthy check at
  the dispatch hook would silently flip if a future change moved to
  `!== undefined`)

`transcripts.test.ts`:
- concurrent append/delete/append interleave preserves invariants:
  `count()` and `list()` agree (no tombstone leak), no pre-delete
  entry survives, and the post-delete result is bounded by the two
  concurrent appends

* docs(chat): use named types in Transcripts API reference

- `formatted` rows in the AppendInput / TranscriptEntry TypeTables
  now render `FormattedContent | undefined` (the alias actually
  exported from `chat`), instead of `Root | undefined` which would
  force readers to pull the type from `mdast` directly.
- `count` signature uses the new `CountQuery` named type, with a
  one-liner describing its single field.

* example(nextjs-chat): fix stale comment on transcripts demo handler

The action handler was relabelled to `transcripts` when it was wired
to `bot.transcripts.list`, but the leading comment still read
"Demonstrate fetchMessages and allMessages" from the previous
iteration. Update it to describe the transcripts demo.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-05-05 15:25:37 -07:00
github-actions[bot] f55378a3d8 chore(release): version packages (#378)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-30 13:41:37 -07:00
mdnanocom 8a0c7b308d [chat] fix Slack streaming team ID for interactive payloads (#330)
* [chat] fix Slack streaming team ID for interactive payloads

* chore: downgrade changeset to patch

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-04-29 08:17:05 -07:00
Ben Sabic a520797922 feat: add chat.getUser() for cross-platform user lookups (#391)
* feat: add chat.getUser() for cross-platform user lookups

Add UserInfo type and optional getUser() method to the Adapter interface.
Implement on Slack (extends existing lookupUser with email/avatar),
Discord, Google Chat, GitHub, Linear, and Telegram adapters.

Add "Who Am I" button to the example app demonstrating the feature.
Update docs with getUser API reference and usage examples.

* fix(chat): improve getUser across slack and gchat adapters

- slack: return null from lookupUser on failure instead of fallback
  object, removing the isBot === undefined sentinel in getUser
- slack: use image_192 instead of image_72 for better avatar quality
- gchat: cache avatarUrl from webhook sender payload
- gchat: return avatarUrl in getUser response
- gchat: fix tests to use current cache format with isBot field
- docs: document null return, fix example to use message.author

* chore: fix lint

* docs(chat): include Microsoft Teams in getUser supported adapters list

* feat(adapter-teams): add getUser() support (#404)

* feat(adapter-teams): add getUser() via Microsoft Graph API

- Cache aadObjectId from activity.from during webhook handling
- Implement getUser() using Graph GET /users/{user-id} endpoint
- Requires User.Read.All application permission
- Returns null gracefully when user hasn't interacted or Graph call fails

* docs: add getUser() section to Teams adapter README

* chore: apply ultracite formatting to adapter-teams getUser

* fix(chat): cover all 7 adapters in getUser inference and document per-platform constraints

---------

Co-authored-by: dancer <josh@afterima.ge>
2026-04-29 07:58:33 -07:00
josh 70281dc58f feat(chat): add initialOption and option_groups to ExternalSelect (#410)
* feat(chat): add initialOption and option_groups to ExternalSelect

* docs(modals): document ExternalSelect initialOption and option_groups, truncate group label to 75 chars
2026-04-28 09:32:15 +10:00
Ben Sabic b0ab804f18 - Bundle guide markdown and a templates manifest with the chat package at resources/guides/*.md and resources/templates.json so AI agents can discover Chat SDK resources offline (#423)
- Add scripts/sync-resources.ts (run via pnpm sync-resources) that reads apps/docs/resources-edge-config.json, fetches each guide's .md version over https with a timeout and size cap, writes templates.json, and regenerates the Available resources block in skills/chat/SKILL.md
- Migrate the Slack Next.js, Discord Nuxt, and Hono code-review guides from on-site MDX to Vercel KB and register them in the resources edge-config JSON alongside the existing external guides
- Remove /docs/guides MDX content, sidebar entries, top-level Guides nav entry, getting-started cards, and the dead /guides/ branch in the sitemap route now that all guides live externally and are surfaced on /resources
- Replace the homepage Guides/Templates section and the standalone Adapters pill section with a single two-column Resources + Adapters section (icons, headings, descriptions, outline buttons, divider), and drop the URL footer from ResourceCard on the Resources page
- Update skills/chat/SKILL.md to point at resources/guides and resources/templates.json and list the available guides and templates between marker comments that sync-resources rewrites
- Add tsx to knip's ignoreBinaries so npx tsx in the new script does not fail lint

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: dancer <josh@afterima.ge>
2026-04-27 10:20:44 +10:00
Ben Sabic d630e6c8a7 fix(chat): honor concurrency.maxConcurrent in the concurrent strategy (#419)
Closes #417.

- handleConcurrent now acquires a per-thread semaphore slot when
  maxConcurrent is finite; fast path preserved for the default Infinity.
- Constructor throws on maxConcurrent < 1 (would deadlock) and warns
  when maxConcurrent is paired with a non-concurrent strategy (was
  previously ignored silently).

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-04-24 11:59:42 -07:00
Franz Rebaza a179b29141 Implement external_select block kit for Slack (#397)
* feat(slack): external_select's block kit implementation

- block_suggestion handler for slack webgook
- new <ExternalSelect/> to chat modal jsx
- new .onOptionsLoad()

* feat: add tests for new external_selec implementation

* feat(docs): Slack externa_select docs

* chore: changeset

* chore: remove docs from changeset

---------

Co-authored-by: dancer <josh@afterima.ge>
2026-04-21 05:49:51 -07:00
Sergei Patrikeev b9a1961aa5 fix(telegram): MarkdownV2 rendering + telegram-chat reference example (#407)
* fix(telegram): switch parse_mode from legacy Markdown to MarkdownV2

The Telegram adapter hardcoded `parse_mode: "Markdown"` (legacy) but
rendered messages via the SDK's generic `stringifyMarkdown()`, which
emits standard markdown. Two incompatible dialects glued together:

- Standard markdown uses `**bold**`, Telegram legacy uses `*bold*`
- Legacy Markdown has no escape rules — any message with `.`, `!`,
  `(`, `)`, `-`, `_` in unexpected positions was rejected with
  `can't parse entities`, which is virtually every LLM-generated
  response
- Legacy Markdown is deprecated by Telegram and lacks support for
  underline, strikethrough, spoiler, and blockquote

This commit:

- Switches TELEGRAM_MARKDOWN_PARSE_MODE to "MarkdownV2"
- Replaces fromAst() with a proper AST → MarkdownV2 renderer:
  - Single `*bold*`, `_italic_`, `~strike~` markers
  - Context-aware escaping: 20-char matrix for normal text, only
    `` ` `` and `\` inside code blocks, only `)` and `\` inside link
    URLs
  - Headings rendered as bold (MarkdownV2 has no heading syntax)
  - Ordered/unordered lists with escaped dashes and periods
  - Blockquotes with per-line `>` prefix
  - Tables pre-empted and rendered as ASCII code blocks
  - Explicit handlers for reference-style links, images, HTML, and
    definitions so nothing is silently dropped
- Routes card fallback text through `fromMarkdown` (not raw escape)
  with `boldFormat: "**"` — @chat-adapter/shared's cardToFallbackText
  defaults `boldFormat` to "*" (Slack mrkdwn), which would render as
  italic on Telegram. Explicit "**" keeps the card title rendered as
  real MarkdownV2 bold.
- Fixes resolveParseMode so every message routed through the format
  converter (`{markdown}`, `{ast}`, cards, JSX) gets
  `parse_mode: "MarkdownV2"`. Previously only `{markdown}` and cards
  were covered, so `{ast}` messages shipped without parse_mode and
  rendered asterisks literally.
- Documents inbound vs outbound dialects on applyTelegramEntities /
  escapeMarkdownInEntity (inbound entities → standard markdown)
  versus the new outbound MarkdownV2 renderer, so future
  contributors don't confuse the two.

Tests: full 20-char MarkdownV2 escape matrix, context-escape tests
for code blocks and link URLs, nested-formatting tests, edge cases
(empty, whitespace-only, raw HTML), and an end-to-end LLM-output
corpus test that asserts MarkdownV2 validity (no unescaped special
chars outside entities or code blocks). Regression guards added in
index.test.ts for the AST / plain-string / raw parse_mode paths and
for card-title MarkdownV2 bold rendering.

Fixes #226

* feat(examples): add telegram-chat reference bot

Polling-mode Telegram bot that exercises the adapter end-to-end:
MarkdownV2 rendering, interactive cards with inline keyboards,
reactions, file uploads, and streaming edits. Runs with a single
`pnpm --filter example-telegram-chat start`; no webhook, no public
URL, no external API keys.

Menu structure — three categorized sub-menus reached from any DM text:

- Text & Markdown: plain, inline emphasis, code block, links, list+table,
  20-char torture string, LLM-style corpus, streaming editMessage loop
- Cards & Actions: interactive approval card (edits in-place on press),
  callback_data size probe demonstrating the 64-byte limit, LinkButton
- Media & Reactions: on-demand reaction one-shot (briefly subscribes),
  generated 1×1 PNG upload, generated minimal PDF upload

Zero new runtime deps. PNG/PDF are hand-rolled in memory
(lib/png.ts, lib/pdf.ts) rather than pulled from a binary-processing
library. Failure handling is consistent: every demo runner is
try/catch-wrapped and posts an inline ❌ line with the error message.

Excluded from npm release via .changeset/config.json.

* fix(telegram): produce valid MarkdownV2 when truncating long messages

The MarkdownV2 migration widened a latent truncation bug into a reliable
400. The previous truncator sliced at 4096/1024 chars and appended
literal "..." — but in MarkdownV2 `.` is a reserved character, the slice
can leave an orphan trailing `\`, and it can cut through a paired
entity (`*bold*`, `` `code` ``) leaving it unclosed.

Unify the two truncate methods into one `truncateForTelegram(text,
limit, parseMode)` that appends `\.\.\.` for MarkdownV2 and walks back
past unbalanced entity delimiters or orphan backslashes. Plain text
keeps literal `...`. Adds 8 length-limit tests.

Related cleanup:
- Move MarkdownV2 string utilities and Bot API limits to markdown.ts.
- Type renderMarkdownV2 exhaustively on mdast's `Nodes` union with a
  `never` assertion so new node kinds fail the build. Replaces the
  hand-rolled `AstNode` interface. Adds explicit cases for table /
  tableRow / tableCell (throw — preprocessed by fromAst),
  footnoteDefinition, footnoteReference, yaml.
- Introduce `TelegramParseMode = "MarkdownV2" | "plain"` replacing
  `string | undefined`. `toBotApiParseMode` handles the wire mapping.
- Re-export `Nodes` from the chat package; re-export
  `TelegramReactionType` from the adapter entry.

* feat(examples): add length-limit demos to telegram-chat reference bot

Three new menu entries exercise the MarkdownV2 truncation path that the
prior commit fixed:

- Long (5000 plain) — basic truncation, verifies escaped `\.\.\.` ellipsis
- Long (bold crosses 4096) — entity-balancing heuristic for unclosed `*`
- Long (code crosses 4096) — entity-balancing heuristic for unclosed `` ` ``

Each button posts a message whose rendered length exceeds Telegram's
4096-char limit and would have produced `can't parse entities` 400s
against the previous truncator. Serves as an interactive smoke test
alongside the unit tests in packages/adapter-telegram.

* test(telegram): add unit tests for truncation helpers and MarkdownV2 boundary trimming

* docs(telegram): update README to reflect MarkdownV2 parse mode

* chore: unexport trimToMarkdownV2SafeBoundary to fix knip

---------

Co-authored-by: dancer <josh@afterima.ge>
2026-04-21 05:27:47 -07:00
Hayden Bleasel 7e90d9c8fa Add Slack Socket Mode support (#162)
* Add slack/socket mode dependency

* Update config types and SlackAdapter class

* Add socket mode methods, extract interactive dispatch

* Update createSlackAdapter factory function

* Write tests for socket mode

* Create slack-socket-mode.md

* Run fix

* Fix polynomial regex issues

* Fix: Floating promises in `routeSocketEvent` for slash commands and interactive payloads can cause unhandled promise rejections that crash the Node.js process.


This commit fixes the issue reported at packages/adapter-slack/src/index.ts:1152

**Bug Analysis:**

In `routeSocketEvent` (line 1150), which is a synchronous `void` method, two async operations produce floating promises:

1.  `this.handleSlashCommand(params)` (line 1165) - `handleSlashCommand` is `async` and always returns a `Promise<Response>`. It calls `await this.lookupUser(userId)` which internally calls `await this.chat.getState().get()` (before the try/catch around the API call), and `this.chat.processSlashCommand()`. Any of these could throw.
    
2.  `this.dispatchInteractivePayload(payload)` (line 1172) - Returns `Response | Promise<Response>`. When the payload type is `view_submission`, it delegates to `async handleViewSubmission()`, which calls `await this.chat.processModalSubmit()` and accesses `payload.view.state.values` (which could throw on malformed payloads).
    

Since `routeSocketEvent` is synchronous (`void` return type) and called from a sync context within the socket mode event handler (after `await ack()` has already completed), these returned promises are fire-and-forget. If any reject, it triggers an unhandled promise rejection, which in Node.js 15+ terminates the process by default.

In contrast, in the webhook code path (`handleWebhook`), these same methods are always `return`-ed from async functions, so their promises are properly chained to the caller.

**Fix:**

Added `.catch()` handlers to both floating promises:

1.  For `handleSlashCommand`: Added `.catch()` that logs the error via `this.logger.error`.
2.  For `dispatchInteractivePayload`: Since it returns `Response | Promise<Response>` (only a Promise for `view_submission`), used `instanceof Promise` to conditionally attach a `.catch()` handler only when the result is a Promise.

This approach was chosen over making `routeSocketEvent` async because: (a) it doesn't change the method signature, (b) the caller doesn't need to await it (the ack has already been sent), and (c) errors are logged rather than silently swallowed.


Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: haydenbleasel <hello@haydenbleasel.com>

* Add socket mode forwarding support to Slack adapter

- Export SlackForwardedSocketEvent type
- Add x-slack-socket-token check at top of handleWebhook() for forwarded events
- Update routeSocketEvent() to accept WebhookOptions and use waitUntil
- Add startSocketModeListener(), runSocketModeListener(), forwardSocketEvent()

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

* Add tests for socket mode forwarding

- Forwarded event accepted/rejected based on appToken
- Bypasses signature verification for forwarded events
- Options passthrough to handlers
- startSocketModeListener returns 200/500 appropriately

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

* Add socket mode cron route and vercel config

- New /api/slack/socket-mode route using createPersistentListener
- Mirrors Discord gateway pattern (CRON_SECRET auth, Redis coordination)
- Cron runs every 9 min, listener duration 10 min

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

* Fix signingSecret defaulting to empty string in socket mode

Make signingSecret optional (string | undefined) instead of falling
back to "". verifySignature now returns false when no secret is
configured, preventing HMAC with an empty key from silently passing.

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

* Wrap event_callback in try-catch in routeSocketEvent

Sync errors from processEventPayload were silently dropped in
socket mode. Wrap with try-catch for parity with slash_commands
and interactive cases.

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

* Use dedicated socketForwardingSecret for forwarding auth

Stop using the Slack app-level token (xapp-...) as the bearer token
for HTTP forwarding. Adds socketForwardingSecret config option
(auto-detected from SLACK_SOCKET_FORWARDING_SECRET) with fallback
to appToken for backwards compatibility.

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

* Replace double cast with type guard for socket event body

Validate body.event exists and construct a properly typed
SlackWebhookPayload instead of using `as unknown as`.

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

* Internalize SlackForwardedSocketEvent type

Remove export — only used internally by the forwarding mechanism.

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

* Fix formatting in socketForwardingSecret check

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

* Add socket mode documentation to Slack adapter README

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

* fix(slack): use SDK envelope type for socket mode event routing

* fix(slack): pass interactive response through ack in socket mode

* feat(chat): add clear modal response action to close entire view stack

* chore: update changeset for clear modal action

---------

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: dancer <josh@afterima.ge>
2026-04-20 08:09:26 -07:00
josh 9093292ef4 feat(chat): add streaming options to thread.post() (#388)
* feat(chat): add streaming options to thread.post()

* test(chat): add comprehensive tests for PostStreamOptions

* feat(chat): add StreamMessage PostableObject for streaming with options

* refactor(chat): remove PostStreamOptions second param, keep only StreamMessage PostableObject

* refactor(chat): rename StreamMessage to StreamingPlan, fix post() return type

Rename per Malte's feedback - StreamingPlan better describes what the
options control (task grouping, stop blocks for streamed plans).

Fix type safety issue where post<T extends PostableObject>() returned
SentMessage at runtime instead of T. Now awaits handleStream() for
side effects and returns the original StreamingPlan instance.

* test(chat): cover updateIntervalMs-only and fallback paths for StreamingPlan

Remove a duplicated test block, drop a duplicate JSDoc line on Thread.post,
and add tests for posting a StreamingPlan with only updateIntervalMs and
for routing StreamingPlan through the fallback post+edit path when the
adapter has no native streaming.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-04-17 02:40:13 +10:00
Ben Sabic 37dbb4ac8b feat(chat): add thread.getParticipants() (#386)
* feat(chat): add thread.getParticipants() method

Returns unique human participants in a thread by scanning message
history. Excludes the bot itself. Useful for subscribing only to
1:1 conversations and unsubscribing when others join.

* fix: filter all bots in getParticipants(), not just self

Third-party bots (e.g. Jira, GitHub) were included as participants
because only isMe was checked. Now filters on isBot as well.

* docs: add getParticipants() to Thread API reference and guides

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-04-15 10:51:20 +10:00
Nate McGrady bca47924b7 feat: enhance task update structure with optional details field (#385)
- Added a `details` field to the `task_update` type for providing additional context in task updates.
- Updated relevant documentation and test cases to reflect the new field, improving clarity on task progress reporting.
2026-04-15 09:47:34 +10:00