mirror of
https://github.com/vercel/chat.git
synced 2026-09-14 18:32:29 +08:00
chat@4.35.0
138 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b4a93bdbc5 |
build(deps-dev): bump @hono/node-server from 2.0.2 to 2.0.10 (#733)
Bumps [@hono/node-server](https://github.com/honojs/node-server) from 2.0.2 to 2.0.10. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/honojs/node-server/releases">@hono/node-server's releases</a>.</em></p> <blockquote> <h2>v2.0.10</h2> <h2>Security fixes</h2> <p>This release includes a fix for the following security issue:</p> <h3>Unauthenticated memory-leak DoS via aborted WebSocket handshake</h3> <p>Affects: <code>upgradeWebSocket</code>. A WebSocket upgrade request with a missing or malformed <code>Sec-WebSocket-Key</code> header leaked the request's <code>IncomingMessage</code> and left a promise pending, even though no connection was established. Since the route is reachable pre-handshake without authentication, an attacker could flood it to gradually exhaust memory. <a href="https://github.com/honojs/node-server/security/advisories/GHSA-9mqv-5hh9-4cgg">GHSA-9mqv-5hh9-4cgg</a></p> <hr /> <p>Users of <code>upgradeWebSocket</code> are encouraged to upgrade to this version.</p> <h2>v2.0.9</h2> <h2>What's Changed</h2> <ul> <li>fix(websocket): polyfill missing ErrorEvent global by <a href="https://github.com/otnc"><code>@otnc</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/371">honojs/node-server#371</a></li> <li>fix(serve-static): correct Range header parsing edge cases by <a href="https://github.com/otnc"><code>@otnc</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/372">honojs/node-server#372</a></li> <li>fix: recover complete request bodies after client disconnect by <a href="https://github.com/usualoma"><code>@usualoma</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/375">honojs/node-server#375</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/otnc"><code>@otnc</code></a> made their first contribution in <a href="https://redirect.github.com/honojs/node-server/pull/371">honojs/node-server#371</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/honojs/node-server/compare/v2.0.8...v2.0.9">https://github.com/honojs/node-server/compare/v2.0.8...v2.0.9</a></p> <h2>v2.0.8</h2> <h2>What's Changed</h2> <ul> <li>ci(release): add <code>--no-git-checks</code> option for <code>pnpm stage publish</code> by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/369">honojs/node-server#369</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/honojs/node-server/compare/v2.0.7...v2.0.8">https://github.com/honojs/node-server/compare/v2.0.7...v2.0.8</a></p> <h2>v2.0.7</h2> <h2>What's Changed</h2> <ul> <li>chore: migrate to pnpm by <a href="https://github.com/BlankParticle"><code>@BlankParticle</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/367">honojs/node-server#367</a></li> <li>fix(serve-static): serve precompressed files for application/octet-stream by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/366">honojs/node-server#366</a></li> <li>chore: bump <code>supertest</code> by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/368">honojs/node-server#368</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/honojs/node-server/compare/v2.0.6...v2.0.7">https://github.com/honojs/node-server/compare/v2.0.6...v2.0.7</a></p> <h2>v2.0.6</h2> <h2>What's Changed</h2> <ul> <li>ci: publish to npm from CI with OIDC trusted publishing and bump <code>np</code> by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/361">honojs/node-server#361</a></li> <li>ci: use npm Staged publishing by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/364">honojs/node-server#364</a></li> <li>fix: preserve status and statusText when cloning a Response with liveheaders by <a href="https://github.com/usualoma"><code>@usualoma</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/363">honojs/node-server#363</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/honojs/node-server/compare/v2.0.5...v2.0.6">https://github.com/honojs/node-server/compare/v2.0.5...v2.0.6</a></p> <h2>v2.0.5</h2> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/honojs/node-server/commit/7c1457ed5536c02fdd2f001129fae67bcbca54a1"><code>7c1457e</code></a> 2.0.10</li> <li><a href="https://github.com/honojs/node-server/commit/3a21938c418340e980cb7ffa88e78369f78392d1"><code>3a21938</code></a> Merge commit from fork</li> <li><a href="https://github.com/honojs/node-server/commit/98420217e53a17a238ef1aa1a6bef0b2b70136c5"><code>9842021</code></a> 2.0.9</li> <li><a href="https://github.com/honojs/node-server/commit/51f3bf56f56d9691ec0f7e1562a96f0b485a7dd9"><code>51f3bf5</code></a> fix: recover complete request bodies after client disconnect (<a href="https://redirect.github.com/honojs/node-server/issues/375">#375</a>)</li> <li><a href="https://github.com/honojs/node-server/commit/fdb87badbe313cfbfe6bb2355e9893dc0698d2bd"><code>fdb87ba</code></a> fix(serve-static): correct Range header parsing edge cases (<a href="https://redirect.github.com/honojs/node-server/issues/372">#372</a>)</li> <li><a href="https://github.com/honojs/node-server/commit/912e3fd80c4311756f724bd566de1433c8d772d9"><code>912e3fd</code></a> fix(websocket): polyfill missing ErrorEvent global (<a href="https://redirect.github.com/honojs/node-server/issues/371">#371</a>)</li> <li><a href="https://github.com/honojs/node-server/commit/114c15efb38dabaf81af774ddb764409e3d156d8"><code>114c15e</code></a> 2.0.8</li> <li><a href="https://github.com/honojs/node-server/commit/5db2d5df662cd69ff5c4cc23b8ecb3a6f63e4e38"><code>5db2d5d</code></a> ci(release): add <code>--no-git-checks</code> option for <code>pnpm stage publish</code> (<a href="https://redirect.github.com/honojs/node-server/issues/369">#369</a>)</li> <li><a href="https://github.com/honojs/node-server/commit/a528a77ed2c28dc12775c849abc6b6df6d4cb44c"><code>a528a77</code></a> 2.0.7</li> <li><a href="https://github.com/honojs/node-server/commit/b2d610c1e37a96639fbb2eae662e858800aa8906"><code>b2d610c</code></a> chore: bump <code>supertest</code> (<a href="https://redirect.github.com/honojs/node-server/issues/368">#368</a>)</li> <li>Additional commits viewable in <a href="https://github.com/honojs/node-server/compare/v2.0.2...v2.0.10">compare view</a></li> </ul> </details> <details> <summary>Maintainer changes</summary> <p>This version was pushed to npm by <a href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new releaser for <code>@hono/node-server</code> since your current version.</p> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/vercel/chat/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
4cb7e5d58e |
feat(chat): durable human-in-the-loop approvals via chat/workflow (#728)
Adds a `chat/workflow` subpath export with `requestApproval()`. This is the DX from #284, rebuilt on Workflow SDK so the approval survives deploys, restarts, and arbitrarily long waits. No in-memory promises, no approvals registry, no restart-recovery machinery: the workflow suspends on a webhook and resumes when a button is clicked. `requestApproval()` posts a card with Approve/Deny buttons whose `callbackUrl` targets a `createWebhook()` URL, suspends the workflow until a decision (or optional durable-sleep timeout), validates approvers, finalizes the card in place with the outcome (removing the buttons, leaving an audit trail), and returns the decision. ```typescript import { requestApproval } from "chat/workflow"; import type { Thread } from "chat"; export async function deployApproval(opts: { thread: Thread; version: string }) { "use workflow"; const { approved, user, timedOut } = await requestApproval(opts.thread, { title: `Deploy ${opts.version}?`, fields: { Version: opts.version }, timeout: "24h", approvers: ["U_ALICE", "U_BOB"], }); if (approved) { await deploy(opts.version); } } ``` Starting it from a handler is one line. `Thread` instances serialize across the workflow boundary automatically via the existing `@workflow/serde` hooks on `ThreadImpl` (requires `chat.registerSingleton()`): ```typescript import { start } from "workflow/api"; bot.onNewMention(async (thread, message) => { await start(deployApproval, [{ thread, version: parseVersion(message.text) }]); }); ``` **Details** - `workflow` is a new **optional** peer dependency (same pattern as `ai`); the subpath is the only code that imports it - Unauthorized clicks (when `approvers` is set) and unrecognizable payloads post a notice / are ignored, and the workflow keeps waiting - On timeout the card is finalized as timed out and the result has `timedOut: true` - Card builders (`buildApprovalCard`, `buildResolvedCard`) are exported for custom flows - Verified the published `dist` preserves the `"use step"` directives and down-levels `using` correctly, so the app-side Workflow SDK compiler handles the library code - Docs page under Interactivity; changeset (`chat` minor); 8 unit tests mocking the `workflow` primitives **Deliberate deviation from #284:** no `thread.requestApproval()` method. The function must suspend at workflow level, so hanging it off `ThreadImpl` would make `workflow` a hard dependency of core (or require prototype patching). The standalone `requestApproval(thread, options)` keeps the dependency optional. --------- Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com> Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
4717a38407 |
feat(slack): support data table and data visualization blocks (#696)
Adds support for Slack's [data table](https://docs.slack.dev/reference/block-kit/blocks/data-table-block) and [data visualization](https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block) Block Kit blocks. - **`chat`**: new cross-platform `ChartElement` + `Chart()` builder (JSX supported) mirroring Slack's model — pie `segments`, or bar/area/line `series` against shared `categories`. `Table()` gains optional `caption` and `pageSize`. Charts degrade to a text table on other platforms via the shared card fallback (`chartElementToFallbackText`). - **`@chat-adapter/slack`**: card tables now render as paginated, sortable `data_table` blocks by default (header-only tables keep the plain `table` block; oversized tables still fall back to ASCII). Charts render as `data_visualization` blocks; charts violating Slack constraints — including the undocumented **max 2 charts per message** — fall back to a text rendering instead of an API rejection. Same treatment in the `@chat-adapter/slack/blocks` subpath. - **`postMessage`** now surfaces Slack's per-block validation messages on `invalid_blocks` errors (this is how the 2-chart limit was found). - Example app gets a **Show Charts** button and table pagination on **Show Table**; docs, feature matrices, and changeset updated. Verified live against Slack: data table pagination/sorting and both chart types render natively. <table> <tr> <th>Data Table</th> <th>Data Charts</th> </tr> <tr> <td><img width="979" height="896" alt="CleanShot 2026-07-12 at 23 28 32" src="https://github.com/user-attachments/assets/3307bd90-9322-452f-86fb-07d46446822d" /></td> <td><img width="955" height="879" alt="CleanShot 2026-07-12 at 23 29 02" src="https://github.com/user-attachments/assets/ddb31a1b-e3fd-457c-a2e6-bde4934afebe" /></td> </tr> </table> --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
1721fa01e7 |
feat(slack): add Slack Agent messaging experience (agent_view) support (#684)
## Summary
Add support for Slack's Agent messaging experience (`agent_view`), the
2026 replacement for `assistant_view`.
## Core (`chat`)
- New `onAppContextChanged` event carrying the active-view context as a
normalized `AppContextEntity[]` (`channel` / `canvas` / `list` /
`message` / `unknown`) describing what the user is currently viewing.
- `AppHomeOpenedEvent` now carries:
- the same folded active-view context as optional `entities`
- the opened `tab` (`"home"` / `"messages"`), so handlers can
distinguish a Home-tab open from the DM-open signal under `agent_view`
## Slack adapter (`@chat-adapter/slack`)
- **`agentView` config flag.** Under `agent_view`:
- `app_home_opened` is the DM-open signal and fires regardless of tab
(branch on `event.tab` if you also publish a Home view)
- DM messages are threaded per Slack's new model — each user message is
a thread root (`thread_ts ?? ts`)
- conversation-scoped threads returned by `openDM()` keep working: when
that thread is subscribed, incoming top-level DM messages route to it,
so `onSubscribedMessage` and per-thread state behave the same as in
legacy mode
- **`app_context_changed` routing** with normalized entities. Malformed
payloads degrade gracefully: a missing `context` yields `entities: []`,
and entities with a null/malformed `value` normalize to `kind:
"unknown"` — never a webhook 500.
- **`getAppContext(message)`** helper to read the folded active-view
context off a DM message.
- **`setSuggestedPrompts`** accepts an optional thread reference
(`agent_view` lets prompts sit at the top of the agent conversation).
- **Env auth fallback now keys off auth fields**: `SLACK_BOT_TOKEN` /
`SLACK_CLIENT_ID` / `SLACK_CLIENT_SECRET` fallback is disabled only when
an auth-related field (`botToken`, `clientId`, `clientSecret`,
`installationProvider`) is passed explicitly, rather than by the
presence of any config object. This lets non-auth options compose with
env auth — e.g. `createSlackAdapter({ agentView: true })` picks up env
credentials — and matches the semantics documented in the adapter's
AGENTS.md. *(Behavior change for callers passing non-auth-only configs
while relying on env vars being ignored.)*
- Bumped `@slack/web-api` to `^7.18.0` (adds the optional `thread_ts`
typing for `setSuggestedPrompts`).
## Docs
- New "Agent messaging experience" section on the Slack adapter page
(config, manifest snippet, threading model, openDM bridge).
- "Handling active-view context" section in handling-events, plus
`tab`/`entities` rows on the app-home event table.
- Callout: under `agent_view`, bot replies are threaded per user
message, so `conversations.history` only returns the user's side of a DM
— build AI conversation history from transcripts instead of channel
history.
## Example app (`examples/nextjs-chat`)
- Plain `SLACK_BOT_TOKEN` adapter branch (previously Slack was only
wired via Vercel Connect).
- DM AI history built from transcripts instead of channel history (see
docs callout above); assistant turns persisted.
- The `dm me` trigger regex now matches mention text, which carries the
`@bot` prefix on Slack.
## Test plan
- `pnpm validate` and `pnpm konsistent` pass.
- Unit tests cover the new events, entity normalization (including
malformed payloads), `agent_view` DM threading, the openDM subscription
bridge, `tab` passthrough, `setSuggestedPrompts` thread handling, and
env-fallback behavior; an integration replay test exercises the full
webhook flow.
- Verified manually against a live `agent_view` workspace:
`onAppContextChanged` entities, folded context on `app_home_opened` and
DM messages, `tab` values for both tabs, per-message DM threading, the
openDM subscription bridge, and signed malformed-payload replays (all
return 200).
- Legacy regression pass with `agentView` off: conversation-scoped DM
threading, Home-tab-only `app_home_opened`, mention flow unchanged.
### Slack references
- Agent messaging experience:
https://docs.slack.dev/changelog/2026/06/30/agent-messages-tab/
- Active-view context:
https://docs.slack.dev/changelog/2026/07/02/app-context/
## Checklist
- [x] All commits are signed and verified
- [x] All commits are signed off for the DCO (`git commit -s`)
- [x] `pnpm validate` passes
- [x] Changeset added
- [x] Documentation updated
---------
Signed-off-by: Damian Borowy <301205838+damianborowy-nexos@users.noreply.github.com>
Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
|
||
|
|
1dff4515e2 |
refactor(docs): migrate chat-sdk.dev to @vercel/geistdocs (#686)
## Summary Migrates `apps/docs` from locally-copied geistdocs runtime code to the published [`@vercel/geistdocs`](https://www.npmjs.com/package/@vercel/geistdocs) package (1.8.2), following the official [migration guide](https://preview.geistdocs.com/docs/migration). Net **−8,400 lines**. ### Package-backed now - Docs page + layouts: `createDocsPage`, `GeistdocsDocsLayout`, `GeistdocsHomeLayout` (JSON-LD + sr-only markdown hints preserved via `renderTop`) - Navbar (OSS product switcher via `navbarOssProducts`), footer, provider, search dialog, page actions (edit source, feedback, copy page, Ask AI, open-in-chat, scroll top) - `/api/search` → `createSearchRoute`, `/api/chat` → `createChatRoute` (AI SDK v6; AI Gateway default, optional `GEISTDOCS_CHAT_PROXY_URL`) - `llms.mdx` → `createDocsMarkdownRoute`, `sitemap.md` → `createSitemapMarkdownRoute` (now includes an **Adapters** section) - **New**: `/agents.md` via `createAgentsRoute`, backed by a new `agent` readiness config - `proxy.ts` → `createProxy` with explicit `markdownRoutes` for `/docs` → `llms.mdx` and `/adapters` → `adapters.mdx` (adds AI-agent UA rewrites) - CSS: `@vercel/geistdocs/styles.css` + slim local overrides (shadcn tokens for remaining `components/ui`, body tint, prose inline code, `#nd-*` tweaks); code blocks now use the geist Shiki theme - Icons/logos from `@vercel/geistdocs/assets/*`; feedback via the package action (same geistdocs.com endpoint + `siteId`) ### Kept local by design - Curated `/llms.txt` index + `/llms-full.txt` corpus — the published `AGENTS.md`/SKILL.md artifacts and integration tests reference this exact contract - The adapters section (README fetching, OG images, JSON-LD, feature matrices, `adapters.mdx` markdown route) — now rendered inside the package docs layout - RSS and OG image routes (app-owned per the migration guide) - Skipped `/.well-known/mcp.json`: no MCP servers configured, and the proxy matcher must keep excluding `.well-known` for the served agent-skills files ### Cleanup - Deleted local copies: `components/geistdocs/*` chrome, `components/ai-elements/*`, chat hooks/persistence, feedback server actions, unused shadcn primitives, geistcn logo/icon fallbacks covered by package assets - Removed 13 now-unused deps (`ai@5`, `@ai-sdk/react@2`, `dexie`, `jotai`, `cmdk`, `vaul`, `mermaid`, `nanoid`, `react-player`, `use-stick-to-bottom`, `@orama/tokenizers`, `dexie-react-hooks`, `next-themes`) - Updated `docs-llms.test.ts` proxy assertions to the `createProxy` markdown-route shape ### Behavior changes to be aware of - Code blocks use the geist Shiki theme instead of GitHub light/dark - Ask AI history is no longer persisted in IndexedDB (package owns the panel) - Adapters sidebar uses the standard geistdocs tree rendering instead of the bespoke grouped sidebar - Per-page markdown output appends the standard geistdocs footer links (`/sitemap.md`, `/llms.txt`, `/agents.md`) ## Test plan - `pnpm validate` green (knip + check + typecheck + test + build) - Smoke-tested against `next build && next start`: `/`, `/docs`, `/adapters`, `/agents.md`, `/llms.txt`, `/llms-full.txt`, `/sitemap.md`, page-level `.md` URLs for both docs and adapters, `Accept: text/markdown` negotiation, search API, JSON-LD, sr-only markdown hints, edit-source URLs (`apps/docs/content/docs/{path}`), OSS navbar, page actions - Verified compiled CSS chunks contain the home grid, Shiki palette, and geist utilities (note: stale turbopack dev caches from before this change can serve incomplete CSS — `rm -rf apps/docs/.next` fixes it) ## Checklist - [x] All commits are signed and verified - [x] All commits are signed off for the DCO (`git commit -s`) - [x] `pnpm validate` passes - [x] Changeset added (or N/A — docs app + tests only, no package behavior change) - [x] Documentation updated (or N/A) --------- Signed-off-by: molebox <rich@vercel.com> |
||
|
|
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>
|
||
|
|
eb466e526f |
docs: add chat-adapter-zaileys community adapter (#677)
## Summary Adds **chat-adapter-zaileys** to the community adapters catalog — a WhatsApp adapter powered by [Zaileys](https://github.com/zeative/zaileys), a batteries-included TypeScript wrapper around the unofficial WhatsApp Web API. - npm: https://www.npmjs.com/package/chat-adapter-zaileys - Repo: https://github.com/zeative/chat-adapter-zaileys - Docs: https://zeative.github.io/chat-adapter-zaileys/ ## What it adds vs the existing Baileys community adapter - Real `thread.fetchMessages` history backed by a pluggable message store (memory/SQLite/Postgres/Redis/Convex), with cursor pagination and `rehydrateAttachment` for queue/debounce strategies - Cards render as **native WhatsApp buttons** with `chat.onAction` round-trips - Poll votes decrypted natively — no `messageSecret` bookkeeping, works across restarts - `scheduleMessage` support (persisted scheduler) - Opt-in slash-command routing to `chat.onSlashCommand` - QR/pairing auth, reconnection, and session persistence handled by the underlying client ## Files changed (per `.agents/skills/add-adapter`) - `apps/docs/content/adapters/community/zaileys.mdx` — docs page with feature matrix - `apps/docs/content/adapters/community/meta.json` — slug added to Platforms - `apps/docs/adapters.json` — registry entry - `packages/integration-tests/src/documentation-test-utils.ts` — `chat-adapter-zaileys` + `zaileys` in `VALID_DOC_PACKAGES` ## Validation - `pnpm --filter chat build` ✓ - `pnpm --filter @chat-adapter/integration-tests test` → 914/914 ✓ - `pnpm --filter chat typecheck` ✓ - `pnpm check` + `pnpm konsistent` ✓ Signed-off-by: zeative <zaadevofc@gmail.com> |
||
|
|
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 |
||
|
|
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> |
||
|
|
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> |
||
|
|
4115c9431e |
feat(linear): add Vercel Connect support (#649)
Adds Vercel Connect support to the Linear adapter: - `accessToken` now accepts a `() => string | Promise<string>` resolver in addition to a string, so tokens can be sourced from Vercel Connect at runtime. - A new optional `webhookVerifier` verifies inbound webhooks (Connect trigger-forwarded requests via a Vercel OIDC token) in place of the Linear webhook secret. - Connect-mode outbound calls outside webhook handling are supported via `withInstallation(organizationId, fn)`. Pair with `connectLinearAdapter()` from `@vercel/connect/chat`. Includes a changeset (`@chat-adapter/linear` minor). Stacked on #647 (base `vercel-connect/base`). ## Companion `@vercel/connect/chat` subpath: vercel/vercel#16826. <img width="929" height="664" alt="CleanShot 2026-06-30 at 12 35 30" src="https://github.com/user-attachments/assets/c5861cb9-d66b-42c6-b838-5b4983f48646" /> --------- Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com> Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
ab0e1806c8 |
feat(chat): Vercel Connect (#647)
Adds a Vercel Connect guide to the docs under **Usage** (`chat-sdk.dev/docs/vercel-connect`), covering connector setup, trigger forwarding, the per-platform `connect*Adapter` helpers from `@vercel/connect/chat`, custom OIDC webhook verification and its trust boundary, and limitations. Also adds a "Vercel Connect Guide" card to the docs homepage. This is the base of a stack; the adapter, tests, and CLI PRs below build on it. Docs-only, so no changeset. ## Stack - #647 — feat(chat): Vercel Connect (this PR, base → `main`) - #648 — docs(slack): document Vercel Connect support - #649 — feat(linear): add Vercel Connect support - #650 — feat(github): add Vercel Connect support - #654 — feat(tests): add Vercel Connect webhook contract helper - #655 — feat(create-chat-sdk): add Vercel Connect mode All of the above are stacked on this branch (`vercel-connect/base`). ## Companion The helpers this documents ship in the `@vercel/connect/chat` subpath: vercel/vercel#16826. --------- Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com> Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
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> |
||
|
|
ef3f0f63bd |
docs: add Weixin community adapter (#638)
Adds the [`chat-adapter-weixin`](https://github.com/wong2/weixin-chat-adapter) community adapter (Weixin / WeChat iLink bot) to the docs. ### What's included - `apps/docs/content/adapters/community/weixin.mdx` — hand-authored adapter page following the existing community-adapter structure (install, quick start, long-polling note, QR login, env vars, config `TypeTable`, thread-ID format, capabilities/limitations, and `<FeatureSupport />`). - `apps/docs/adapters.json` — registry entry (`community: true`, author, pinned README commit). - `apps/docs/content/adapters/community/meta.json` — sidebar link under **Platforms**. ### Notes The adapter talks to Weixin's iLink bot HTTP JSON APIs directly. It uses long polling for inbound messages (no webhook) and requires a Chat SDK `StateAdapter` for cursor / context-token / dedupe / history. It's 1:1 only, so messages route through `onDirectMessage`. ### Verification `docs-adapters` (322) and `docs-llms` (129) integration tests pass. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
64b66864b1 |
chore(changesets): ignore all example-* packages and enforce the convention (#626)
Replace the explicit per-example entries in the changesets `ignore` list with an `example-*` name glob (matched by micromatch). All example apps are private and never published, so listing them individually only adds version and changelog churn to release PRs, and each new example required editing this CODEOWNERS-gated file. Add an integration test that resolves the changesets config against the workspace and asserts every examples/* package is in the resolved ignore list and follows the `example-*` naming convention, so an off-convention example app fails CI instead of silently leaking into releases. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
8c7141174a |
feat(teams): add low-level primitives (#593)
Add Teams subpath exports for custom runtimes, including Bot Connector API helpers, Graph reads, parse-only webhooks, format helpers, Adaptive Cards, and Task Module primitives. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
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> |
||
|
|
b14114a714 |
test(slack): expand emulator coverage for emulate.dev 0.6.0 APIs (#591)
Upgrade @emulators/* to 0.6.0 and add integration tests for DMs, reactions, fetch history, modals, scheduled messages, file uploads, member joins, and bookmarks against the in-process Slack emulator. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
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> |
||
|
|
7ecb9730e3 |
chore(docs): add missing Twilio logo and add official platform adapter OG images (#589)
Adds official platform adapter branding across the docs site, npm
READMEs, and social previews.
- **Homepage**: add Twilio to the supported-platforms logo grid
- **OG images**: add custom artwork for all 11 official platform
adapters under content/adapters/official/og/; serve static-first from
the existing /adapters/official/{slug}/og route with dynamic fallback
for state adapters
- **READMEs**: add linked hero banners to every official platform
adapter package README, using the live OG URL as the single image source
- **Tests**: integration-test guardrails for OG image coverage, README
banner discoverability, and knip-clean helpers
- **Changeset**: empty changeset for CI
<img width="2400" height="1256" alt="Chat SDK - Slack"
src="https://github.com/user-attachments/assets/4d186a1c-5651-44b8-8698-091ee23b44da"
/>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
|
||
|
|
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> |
||
|
|
c290464634 |
docs(adapters): promote Sendblue to vendor-official adapter (#584)
Moves the Sendblue adapter from community to vendor-official in the docs site now that Sendblue maintains `chat-adapter-sendblue`. - package: `chat-adapter-sendblue` - repo: https://github.com/sendblue-api/chat-adapter-sendblue - docs: https://docs.sendblue.com/guides/chat-sdk-adapter/ Updates the adapter registry and hand-authored detail page (iMessage, SMS, RCS, `sb-signing-secret` webhook verification, official Sendblue guide links). Reorders vendor-official adapters so Liveblocks, Resend, Sendblue, and Zernio appear first. Adds a permanent redirect from `/adapters/community/sendblue`. Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
2fb8ad29cf |
docs(adapters): add Kapso WhatsApp adapter (#577)
## Summary Adds [Kapso WhatsApp](https://docs.kapso.ai/) as a vendor-official adapter in `adapters.json`. Kapso is a WhatsApp adapter for Chat SDK that receives signed Kapso webhooks, replies through Chat SDK threads, and supports WhatsApp-native messaging features: - **Text messages** — send and receive WhatsApp messages via Kapso - **Buttons/cards** — Chat SDK card buttons render as WhatsApp reply buttons - **Media** — send and receive images, video, audio, documents, and stickers - **Reactions** — add/remove reactions and handle inbound reaction events - **History** — fetch Kapso-backed message, contact, and conversation metadata - **Webhook verification** — validates Kapso `X-Webhook-Signature` deliveries | Feature | Support | | --- | --- | | Send/receive text | Yes | | Reply buttons | Yes, up to 3 | | CTA URL buttons | Yes | | Media attachments | Yes | | Reactions | Yes | | Message history | Yes | - **Docs**: [docs.kapso.ai](https://docs.kapso.ai/) - **npm**: [`@kapso/chat-adapter`](https://www.npmjs.com/package/@kapso/chat-adapter) - **GitHub**: [`gokapso/chat-sdk-adapter`](https://github.com/gokapso/chat-sdk-adapter) - **Blog**: https://kapso.ai/blog/chat-sdk-adapter |
||
|
|
9b99ee2d2d |
fix(docs): allow Velt adapter examples (#575)
## summary fixes the release-blocking docs validation failures from the Velt vendor-official adapter page this updates the docs integration-test allowlists so `velt` is an expected vendor-official adapter slug and `@veltdev/chat-sdk-adapter` is accepted in docs code examples no changeset needed because this only updates test expectations for existing docs content |
||
|
|
5a72259fbc |
feat(docs): improve LLM/search discoverability of docs (#566)
SEO/AEO improvements for the docs site: - Append `| Chat SDK` to every page's `<title>` and `og:title` (home stays `Chat SDK`). - Expose a plain-markdown version of every docs and adapter page via an `sr-only` AI/LLM hint link and a `text/markdown` alternate; adapter pages get a new `/adapters/<group>/<slug>.md` endpoint. - Turn `llms.txt` into a sitemap-style index linking to each page's markdown, and move the full-text concatenation to `llms-full.txt`. A `<link rel="llms-txt">` is added to every page. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
293356525d |
feat: docs: add Lark / Feishu adapter (#517)
## Summary Adds [`@larksuite/vercel-chat-adapter`](https://www.npmjs.com/package/@larksuite/vercel-chat-adapter), the Lark / Feishu adapter for Chat SDK, as a **vendor-official community adapter**. - **Package**: `@larksuite/vercel-chat-adapter` — published on npm under the official `larksuite` scope - **Built on**: [`@larksuiteoapi/node-sdk`](https://www.npmjs.com/package/@larksuiteoapi/node-sdk)'s `LarkChannel`, the official Lark Node SDK - **Docs source**: external README referenced by `adapters.json` lives in [`larksuite/node-sdk`](https://github.com/larksuite/node-sdk/tree/cbc4adf13cbcb93b389db01faf428e3b3cef053c/docs/vercel-chat-adapter) (the official Lark vendor-owned GitHub org, pinned at commit `cbc4adf1`); the in-tree MDX in this PR is the rendered detail page (`mdxBody: true`) - **Capabilities**: native cardkit typewriter streaming, interactive cards, reactions, edit / delete, message history (via SDK `normalize()`), DM detection, mention handling, and scan-to-create app onboarding through `registerLarkApp` ## Changes | File | Change | |---|---| | `apps/docs/adapters.json` | Add Lark / Feishu entry (`community: true`, `vendorOfficial: true`) | | `apps/docs/content/adapters/vendor-official/lark.mdx` | New hand-authored MDX detail page (frontmatter with full features matrix, install / quick start / configuration / transport / streaming / ID encoding / history / safety / limitations / FeatureSupport) | | `apps/docs/content/adapters/vendor-official/meta.json` | Append `"lark"` to the sidebar `pages` array | | `packages/integration-tests/src/docs-adapters.test.ts` | Append `"lark"` to the hardcoded vendor-official slug list asserted by `Vendor-Official adapter MDX › contains exactly the expected adapters` | No icon registered in `adapters.json` / `iconMap` / `adapterLogos` — matches the existing pattern for vendor-official adapters (Beeper, Resend, Liveblocks, Zernio, Photon). ## Vendor Official tier Per `docs/contributing/building.mdx` (Qualifications for vendor official tier): - ✅ **Commitment for continued maintenance** — owned by the Lark / Feishu team - ✅ **GitHub hosting in official vendor-owned org** — adapter README lives in [`larksuite/node-sdk`](https://github.com/larksuite/node-sdk), the official Lark org - ✅ **Documentation in primary vendor docs** — will be cross-linked from the official Lark Open Platform developer documentation - ✅ **Announcement** — will be announced through Lark developer changelog / channels ## A note on source visibility The adapter source is not currently open-sourced due to internal release-process requirements. What is public: - The npm package itself (consumable by any user) - The README, hosted in `larksuite/node-sdk` (official Lark org) - The underlying [`@larksuiteoapi/node-sdk`](https://github.com/larksuite/node-sdk) on which it is built — this *is* fully open-source ## Test plan - [x] `pnpm --filter docs build` — docs app builds cleanly; `/en/adapters/vendor-official/lark` and `/en/adapters/vendor-official/lark/og` routes are generated - [x] `pnpm typecheck` — passes (33 tasks) - [x] `pnpm check` (Ultracite / Biome) — 438 files, no fixes - [x] `pnpm --filter @chat-adapter/integration-tests test docs-adapters` — 232 tests pass (frontmatter, vendor-official roster, adapters.json ↔ MDX sync) - [x] Manual: `/adapters` lists the Lark / Feishu card in the **Vendor Official** section; `/adapters/vendor-official/lark` renders the MDX detail page with the FeatureSupport matrix |
||
|
|
bd38498b60 |
docs(adapters): add AgentPhone as vendor-official adapter (#562)
## Summary Adds [AgentPhone](https://agentphone.to) as a vendor-official adapter in `adapters.json`. AgentPhone is the first Chat SDK adapter with unified support for **SMS, MMS, iMessage, and voice calls** in a single package: - **SMS/MMS** — send and receive via `agent.message` webhooks - **iMessage** — full support including tapback reactions (love, like, laugh, etc.) and expressive send styles - **Voice** — inbound/outbound call transcripts and summaries via `agent.call_ended` webhooks - **HMAC-SHA256** webhook verification with replay protection | | SMS | MMS | iMessage | Voice | |---|---|---|---|---| | Send messages | ✓ | ✓ | ✓ | — | | Receive messages | ✓ | ✓ | ✓ | — | | Media attachments | — | ✓ | ✓ | — | | Reactions | — | — | ✓ | — | | Call transcripts | — | — | — | ✓ | - **npm**: [`@agentphone/chat-sdk-adapter`](https://www.npmjs.com/package/@agentphone/chat-sdk-adapter) - **GitHub**: [`AgentPhone-AI/chat-sdk-adapter`](https://github.com/AgentPhone-AI/chat-sdk-adapter) - **Docs**: [docs.agentphone.ai](https://docs.agentphone.ai) |
||
|
|
25ebc3b925 |
feat(twilio): add sms, mms, and voice helpers (#558)
## summary adds a first-class Twilio adapter for SMS and MMS bots, plus low-level voice helpers for custom Twilio voice routes this includes webhook parsing and signature verification, outbound Messages API helpers, phone-number and Messaging Service sending, inbound MMS attachments with authenticated `fetchData`, plain text card fallback rendering, markdown conversion, and runtime-light `api`, `webhook`, `voice`, and `format` subpaths the adapter intentionally avoids the `twilio` npm runtime dependency so apps can use the low-level helpers without pulling in the full SDK |
||
|
|
0488a6613c |
docs(slack): document low-level api subpaths (#557)
## summary documents the low-level Slack subpaths for custom runtimes that own routing, state, sessions, or workflow execution covers `@chat-adapter/slack/webhook`, `@chat-adapter/slack/format`, `@chat-adapter/slack/api`, and `@chat-adapter/slack/blocks`, including when to use them instead of the full `createSlackAdapter` runtime also links the new guide from the Slack adapter page |
||
|
|
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>
|
||
|
|
cd7b6af1c8 |
test(integration-tests): add Emulate.dev-backed tests for the GitHub adapter (#479)
## Summary Add an Emulate.dev-backed integration-test suite for the GitHub adapter, mirroring the structure of the Slack work in #477. Tests drive the adapter against an in-process [`@emulators/github`](https://emulate.dev/docs/github) server and assert on its stateful store (comments, reviews) rather than `mock.calls`, catching wire-format and contract issues that pure Octokit mocks miss. - New private devDeps in `packages/integration-tests`: `@emulators/github`, `@emulators/core`, `@hono/node-server`, plus a workspace dep on `@chat-adapter/github`. (`@emulators/core` and `@hono/node-server` are also declared by #477; this PR is independent of merge order.) - New harness `packages/integration-tests/src/github-emulator-utils.ts` boots the emulator on an ephemeral `127.0.0.1` port, seeds a deterministic user / repo / issue / PR / starter review comment, and exposes a near-passthrough HTTP forwarder. **No re-signing needed** here. `@emulators/core`'s `WebhookDispatcher` already signs deliveries with `X-Hub-Signature-256: sha256=<hex>` exactly as the GitHub adapter expects. The harness also adds a small URL rewriter for Octokit's `pulls.createReplyForReviewComment` shortcut endpoint, translating it into the canonical review-comment POST that the emulator implements. - Four new test files (12 tests), wired to the adapter via its existing `apiUrl` + `webhookSecret` config **zero source changes** to `packages/adapter-github`: - `emulator-github-auth.test.ts` (2) `GET /user` populates `botUserId` during `initialize()`. - `emulator-github-comments.test.ts` (4) `thread.post` / `edit` / `delete` on issue and PR-conversation threads. - `emulator-github-reviews.test.ts` (3) review-comment replies routed through `pulls.createReplyForReviewComment` with the right \`in_reply_to_id\`, plus edit / delete. - `emulator-github-events.test.ts` (3) full inbound `issue_comment` / `pull_request_review_comment` round-trip, including bot self-message filtering. ```mermaid flowchart LR subgraph Test["Vitest test process"] SDK[GitHubAdapter + Chat] Forwarder["HTTP forwarder<br/>passthrough"] Emu["@emulators/github<br/>(in-process Hono)"] end SDK -->|"issues.createComment / pulls.* / GET /user<br/>(apiUrl override)"| Emu Emu -->|"X-Hub-Signature-256 + x-github-event"| Forwarder Forwarder -->|"chat.webhooks.github(request)"| SDK ``` ### Out of scope (deliberate) - **Reactions** `@emulators/github` does not implement the `/reactions` endpoints used by the adapter. Reaction logic is still covered by the existing mock-based tests in `packages/adapter-github/src/index.test.ts`. - **GitHub App auth** (JWT \u2192 installation token via `POST /app/installations/:id/access_tokens`) the adapter and emulator both support it, but PAT-mode was the agreed scope here. - **Multi-tenant install flows** via `installation` webhook events. - Branches/refs, releases, search, actions, checks not used by the adapter. ## Test plan - [x] `pnpm --filter @chat-adapter/integration-tests test` 407 tests pass across 34 files (including the 12 new emulator-github tests, ~480 ms total). - [x] `pnpm check` and `pnpm knip` clean. - [x] CI safety verified: ephemeral ports (`port: 0`), loopback-only binds (`127.0.0.1`), deterministic teardown via `httpServer.close()`, no env vars, no external network egress. ## Checklist - [x] All commits are signed and verified - [x] \`pnpm validate\` passes - [x] Changeset added (or N/A see [CONTRIBUTING.md](./CONTRIBUTING.md)) N/A: \`@chat-adapter/integration-tests\` is \`private: true\` and the change is test-only. - [x] Documentation updated (or N/A) \`packages/integration-tests/README.md\` describes the new emulator-github test category. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
79227ae991 |
docs: refresh adapter pages with hand-authored MDX (#474)
## Summary
Refreshes the adapter docs end-to-end so every adapter — official,
vendor-official, and community — now ships hand-authored MDX, lives
under a clean URL structure, and renders on a polished
sidebar/right-rail layout dedicated to `/adapters` (the shared `/docs`
chrome is untouched).
```mermaid
flowchart LR
subgraph Before
direction TB
OB[official] --> CB[community<br/>incl. 5 vendor pages]
end
subgraph After
direction TB
OA[official] --> VA[vendor-official<br/>5 pages] --> CA[community]
end
Before -.-> After
```
### Content & routing
- **New `/adapters/vendor-official/<slug>` route** for vendor-maintained
adapters (Beeper Matrix, Photon iMessage, Liveblocks, Resend, Zernio).
Sidebar gets a third labelled group ("Vendor-Official Adapters") between
Official and Community, with a top divider matching the existing
Community treatment.
- **All 13 vendor-official + community adapters migrated** from runtime
README fetching to hand-authored MDX with rich `features:` matrices and
full body content (install, quick start, configuration, auth,
gateway/streaming, troubleshooting). README fetch stays as a fallback
for any future community adapter that hasn't been migrated yet, gated by
a new `mdxBody: true` frontmatter flag.
- **Messenger filter pages removed** (`/adapters/for/<messenger>` + the
"Browse by messenger" chip row on `/adapters`). Existing URLs
308-redirect to `/adapters`.
- **Permanent redirects** from
`/adapters/community/{matrix,imessage,resend,zernio,liveblocks}` to
their new `/adapters/vendor-official/...` paths.
- **Fixed** `/docs/adapters` and `/docs/state` so the bare pages are
accessible again — the previous catch-all redirect (`:slug*`) was
swallowing them. Switched to `:slug+` so subpath URLs still 308 while
the bare pages render.
### Visual polish
- **Adapter-only sidebar variant** (`AdaptersDocsLayout` +
`AdaptersSidebar`) with uppercase eyebrow separators, tighter rows, and
a thin themed scrollbar utility class. The shared `/docs` sidebar is
untouched.
- **Restyled `AdapterHero`**: drops the badges row + packageName, sits
the title inline with the logo, larger 17 px tagline, horizontal divider
beneath the block.
- **Restyled `PackageInstall`** as a tabbed dark single-line snippet
with a `$` prompt prefix and a copy button — replaces the previous
multi-line `CodeBlock` layout.
- **New "Deploy your chat app on Vercel" upsell card** (`<Upsell />`)
replaces the old `EditSource / ScrollTop / Feedback / CopyPage` footer
cluster on every adapter detail page.
- **Listing & messenger pages**: align the H1 to a tighter `text-4xl
sm:text-[44px]`, and the section headers to `text-base font-medium
tracking-tight` with a one-line muted lede.
### Tooling & tests
- Added `mdxBody: true` opt-in to the adapter frontmatter schema
(`source.config.ts`), and updated both detail-page handlers
(`community/[slug]` and the new `vendor-official/[slug]`) to render the
MDX body when present, falling back to README fetch otherwise.
- Refactored both detail-page handlers to flatten the body-render
branches into a `renderBody()` helper, removing the nested ternaries
that were tripping `lint/style/noNestedTernary`.
- New test file
[`packages/integration-tests/src/docs-adapters.test.ts`](https://github.com/vercel/chat/blob/docs/refresh-adapters/packages/integration-tests/src/docs-adapters.test.ts)
— **220 new assertions** covering:
- Adapter MDX frontmatter completeness, slug ↔ filename consistency, and
`type ∈ {platform, state}`.
- Vendor-official invariants: exactly the expected slugs,
`vendorOfficial: true`, `community: true`, `author`, `mdxBody: true`,
`<FeatureSupport />` rendered.
- Community invariants: `community: true` (never vendor-official),
`mdxBody: true`, `<FeatureSupport />`.
- Official invariants: never flagged, `packageName` always under
`@chat-adapter/*`.
- `adapters.json` ↔ MDX sync on `packageName` / `type` / `community` /
`vendorOfficial`.
- Extended `VALID_DOC_PACKAGES` so `docs-content.test.ts` accepts the
new vendor-official + community packages, plus `@chat-adapter/web`,
`@chat-adapter/web/react`, and `@chat-adapter/messenger`.
### Per-package AGENTS.md
- Added `AGENTS.md` to every official adapter and state adapter (14
packages), each tailored to that adapter's surface — overview, directory
layout, build/test commands, public exports, thread ID format, webhook
flow, authentication, format conversion, cards/streaming, platform
quirks, testing approach, coding conventions, and release rules.
- Added a one-line `CLAUDE.md` (`@AGENTS.md`) beside each so Claude Code
picks up the same instructions through its built-in resolver — same
convention as the root.
### Web adapter copy
- Cleaned up the Web adapter tagline (removed inline backticks) and
dropped the now-redundant "v1 scope" section from the body.
---------
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
|
||
|
|
fdebde7988 |
Reapply "feat(slack): expose direct WebClient access via adapter.client" (#472) (#476)
This reverts commit
|
||
|
|
14b1434998 |
test(integration-tests): add Emulate.dev-backed tests for the Slack adapter (#477)
* chore(integration-tests): add Emulate.dev Slack emulator devDeps
Add @emulators/slack, @emulators/core, and @hono/node-server as
devDependencies of the private integration-tests package. These power
the upcoming in-process Slack emulator harness used to drive the Slack
adapter against a stateful, Slack-shaped HTTP server instead of mocks.
* test(integration-tests): add Slack emulator test harness
Introduce slack-emulator-utils.ts, a test-only helper that boots the
@emulators/slack Hono app on an ephemeral 127.0.0.1 port via
@hono/node-server and pre-seeds a deterministic team / channel / bot /
human user / OAuth app. The Slack adapter is wired to it via its
existing apiUrl config; no source changes required.
Also exposes startSlackWebhookForwarder, a tiny in-process Node http
forwarder that re-signs the emulator's outbound event_callback
deliveries with x-slack-signature / x-slack-request-timestamp before
handing them to chat.webhooks.slack(...). The emulator's core
WebhookDispatcher only emits GitHub-style X-Hub-Signature-256 headers,
so this bridge is what makes inbound flows exercise the SDK's real
HMAC verification path.
The handle returns direct access to the emulator's Store and
WebhookDispatcher so tests can assert on persisted state instead of
mock call records.
* test(integration-tests): cover Slack auth, postMessage, and reactions via emulator
Add three test files that drive the SlackAdapter's outbound WebClient
calls through the in-process emulator and assert on its stateful store
rather than on mock call records:
- emulator-slack-auth.test.ts (3 tests): auth.test populates botUserId
during initialize(); explicit botUserId is respected; multi-workspace
mode skips the call entirely.
- emulator-slack-post-message.test.ts (5 tests): plain text and threaded
thread.post round-trip into the messages collection and are visible
via conversations.replies; editMessage updates via chat.update;
deleteMessage removes via chat.delete; markdown posts succeed.
- emulator-slack-reactions.test.ts (3 tests): addReaction /
removeReaction round-trip via reactions.add / reactions.remove and
show up via reactions.get; multi-user reactions accumulate correctly.
These exercise the full HTTP path against a Slack-shaped server,
catching wire-format and contract issues that pure mocks miss.
* test(integration-tests): cover Slack inbound events and OAuth v2 install via emulator
Add two test files that drive end-to-end flows previously only
verifiable against real Slack:
- emulator-slack-events.test.ts (4 tests): a human posts to the
emulator, which dispatches an event_callback to the local forwarder,
which signs the body and hands it to chat.webhooks.slack(...). The
SDK's onNewMention and onNewMessage handlers run with a live Thread
and the bot's reply lands back in the emulator. Bot self-messages
are correctly filtered. This is the only Slack adapter test in the
repo that covers the full inbound-then-outbound round-trip without
hand-crafted webhook payloads.
- emulator-slack-oauth.test.ts (4 tests): handleOAuthCallback
exchanges a real authorization code via oauth.v2.access against the
emulator's authorize/callback flow; the resulting installation is
persisted in the state adapter; invalid codes and mismatched
client_secrets are rejected; the freshly issued bot token works for
subsequent chat.postMessage calls via withBotToken.
* docs(integration-tests): document emulator-* test category
Add an "Emulator tests" entry to the package README so newcomers can
distinguish the new emulator-backed suite from the existing unit and
replay tests, and find the harness in slack-emulator-utils.ts.
* fix(integration-tests): keep full token scopes after emulator.reset()
`applyTokenSeed` (used during `reset()`) was granting only
["chat:write", "channels:read"] to seeded tokens, while the initial
`createCoreServer({ tokens })` call granted the full bot/human scope
sets. After the first `reset()` the bot token silently lost
`channels:history`, `users:read`, `reactions:read`, and
`reactions:write`, which would surface as flaky behaviour for any test
that relied on those scopes after a reset.
Unify both call sites on a single `buildTokenSeedEntries` helper so
fresh-boot and post-reset state always grant the same scopes. Add a
regression test in emulator-slack-auth.test.ts that triggers a manual
`emulator.reset()` and re-asserts that the bot token still resolves
via auth.test.
* refactor(integration-tests): reorganize Slack emulator tests under emulator/slack/
Address review feedback (visyat) by moving the flat
`emulator-slack-*.test.ts` files into a per-adapter directory:
packages/integration-tests/src/emulator/slack/
utils.ts
auth.test.ts
events.test.ts
oauth.test.ts
post-message.test.ts
reactions.test.ts
This scales cleanly as more adapter emulator suites land (e.g.
`emulator/github/`), instead of cluttering the top-level src tree with
adapter-prefixed file names.
Also hoist the duplicated `silentLogger` definition from each test
file into the shared `utils.ts`, removing five identical copies.
No behavior changes. All 20 emulator tests still pass.
* test(integration-tests): cover Slack multi-workspace token resolution via emulator
Add `emulator/slack/multi-workspace.test.ts` exercising the path that
was previously only covered by replay/mock-based tests: the adapter
runs without a hardcoded `botToken`, multiple workspaces are persisted
in the state adapter via `adapter.setInstallation(teamId, ...)`, and
inbound `event_callback`s for either team are routed to the correct
per-tenant bot token end-to-end against the shared emulator.
To make this work, the helper grew two small additions:
- `addEmulatorWorkspace(emulator, seed)` — register an additional
team + bot + channel + token on an already-booted emulator, so two
tenants live side-by-side without needing two emulator instances.
- The inbound forwarder's `augmentEventEnvelope` now accepts an
optional `resolveTeamId(envelope)` callback, defaulting to a constant
teamId for the existing single-workspace tests. The multi-workspace
test passes a resolver that looks up the dispatched event's channel
in the emulator store and returns the owning team's id, so the SDK's
per-team token resolver sees the right `team_id` on the envelope.
Three new tests: team-A routing, team-B routing, and `getInstallation`
returning null for unknown team ids. Follow-up from review feedback on
PR #477.
---------
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
|
||
|
|
2279f1db70 |
Revert "feat(slack): expose direct WebClient access via adapter.client" (#472)
* Revert "feat(slack): expose direct WebClient access via adapter.client (#471)"
This reverts commit
|
||
|
|
8366b8b0fb |
feat(slack): expose direct WebClient access via adapter.client (#471)
* feat(slack): expose direct WebClient access via adapter.client
Mirror the Linear and GitHub adapter pattern by exposing the underlying
@slack/web-api WebClient as `adapter.client` for any Web API call not
covered by the SDK's high-level methods.
Resolution order:
1. Token from the current request context (multi-workspace webhooks,
`withBotToken()`).
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. For both,
bind the token explicitly with `adapter.withBotToken(token, () => ...)`.
Internally, the existing private `client` field is renamed to `_client`
so the public getter can return per-token cached `WebClient` instances.
All internal API calls continue to route through `_client.foo(await
this.withToken(...))` unchanged. Also fixes `createSlackAdapter()`
silently dropping the `apiUrl` config field, surfaced by the new
apiUrl-propagation test.
* docs(slack): document direct WebClient access
Add Slack to the "Direct client access" section of the chat-sdk.dev
docs (api/chat.mdx, usage.mdx) alongside Linear and GitHub. Update the
multi-tenant Callout to spell out both Slack constraints — request
context required in multi-workspace mode, and `withBotToken()` required
when `botToken` is an async resolver.
Add a parallel "Direct WebClient access" section to the Slack adapter
README with a usage example, the token resolution order, and the
async-resolver workaround.
* feat(example): add Channel Info button using slack.client
Demonstrate the new direct WebClient access pattern in the nextjs-chat
demo with a "Channel Info (Slack)" button. The handler resolves the
Slack adapter from the action event, reaches into
`adapter.client.conversations.info` (channels:read scope, already in
the example manifest), and renders the result as a Card with channel
name, member count, topic, purpose, and the standard flags. Falls back
to a friendly message on non-Slack platforms.
* feat(example): add Pin Message button using slack.client.pins.add
Pin the welcome card itself via `adapter.client.pins.add({ channel,
timestamp: event.messageId })` to demonstrate calling a Slack Web API
endpoint not wrapped by the SDK. Adds the required `pins:write` scope
to the example Slack manifest.
* chore(example): render channel info as a table and include num_members
Replace the Fields/Section layout in the Channel Info card with a
two-column Table for a tidier presentation, and pass
`include_num_members: true` so the Members row is actually populated
(Slack's `conversations.info` omits it by default).
* test(slack): expand coverage for adapter.client
Adds three tests:
- Cache differentiation: distinct tokens produce distinct WebClient
instances so per-workspace credentials never bleed across calls.
- apiUrl env var resolution: SLACK_API_URL is honored by the WebClient
the new getter returns (covers GovSlack-style deployments).
- End-to-end multi-workspace token routing: a real block_actions
webhook drives `processAction`, and the handler-side
`event.adapter.client.token` matches the installation's bot token —
proving the request-context-bound client works inside webhook
dispatch.
---------
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
|
||
|
|
0adf3adef6 |
feat(tests): add @chat-adapter/tests test kit (#470)
* feat(tests): add @chat-adapter/tests test kit
New package providing Vitest factories, custom matchers, and a setup file for
people building Chat SDK adapters and bots.
Factories: createMockAdapter, createMockChatInstance, createMockState (with
working in-memory subscriptions/locks/KV/queues), createTestMessage,
mockLogger / createMockLogger.
Matchers: toHavePosted(threadId, textPattern?), toHaveDispatched(handler),
toBeSubscribedTo(threadId). Auto-register via the
'@chat-adapter/tests/setup' subpath in vitest 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.
* test(integration-tests): allow @chat-adapter/tests imports in README check
* docs: add Testing page covering @chat-adapter/tests
New content/docs/testing.mdx walks bot authors and custom-adapter authors
through the kit's factories, custom matchers, and setup file. Added under
the Usage section in the sidebar, after error-handling.
Cross-link from contributing/testing.mdx clarifying that the hand-rolled
patterns there are for repo contributors building first-party adapters,
while consumers of Chat SDK should use @chat-adapter/tests.
* test(integration-tests): allow @chat-adapter/tests imports in docs check
* fix(tests): match real Adapter.postMessage signature in toHavePosted
Adapter.postMessage is (threadId: string, message: AdapterPostableMessage)
— previously the matcher read args[0] as { id: string } and args[1] as
{ text: string }, neither of which match the actual SDK shape. The matcher's
own tests fed the same wrong shape into the mock so they passed locally
while the matcher silently failed against any real bot or adapter.
Now compares args[0] as a string threadId, and extracts a comparable string
from AdapterPostableMessage's union — strings directly, PostableMarkdown
.markdown, PostableRaw.raw, and PostableCard.fallbackText. PostableAst and
fallback-less cards aren't text-matchable; documented in the JSDoc.
Tests updated to call postMessage with the real signature and to cover
each comparable AdapterPostableMessage shape.
* test(tests): add smoke tests driving matchers against a real Chat
Construct a real `Chat` with a `createMockAdapter` + `createMockState` and
exercise `Chat.thread().post()` and `.subscribe()` end-to-end. The matchers
(toHavePosted, toBeSubscribedTo) then assert against the actual call shape
the SDK uses, so a future signature drift breaks here instead of silently
agreeing with whatever wrong shape lives in the unit tests.
This is the regression guard for the postMessage-shape bug fixed in the
prior commit: each new matcher in subsequent PRs should be paired with a
smoke case here.
* feat(tests): round out adapter mutation matchers
Adds toHaveEdited, toHaveDeleted, toHaveReactedWith, toHaveStartedTyping,
and toHavePostedToChannel — covering the common Adapter mutation surface
that bot authors assert on. Each matcher's signature was checked against
packages/chat/src/types.ts, and each is paired with a smoke case that
drives a real Chat through the corresponding Thread/Channel API so
signature drift breaks the smoke test instead of silently agreeing with
the unit tests.
Emoji matching accepts both plain strings and EmojiValue ({ name }).
Text matching reuses the same extraction rules as toHavePosted —
strings, PostableMarkdown.markdown, PostableRaw.raw, and
PostableCard.fallbackText. Documented in matcher JSDoc, README, and
the Testing docs page.
---------
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
3546b3fddb |
feat(slack): use native markdown_text for outgoing messages (#440)
* feat(slack): use native markdown_text field for outgoing messages
Slack now natively renders markdown via the `markdown_text` parameter on
chat.postMessage / postEphemeral / update / scheduleMessage and via
response_url payloads. The adapter passes markdown through directly instead
of converting to mrkdwn.
- Tables, headings, code fences, blockquotes, and nested lists render
natively in Slack instead of falling back to ASCII / mrkdwn.
- `string` and `{ raw }` messages still go to `text` (preserves literal `*`).
- `{ markdown }` and `{ ast }` messages go to `markdown_text` (12k char limit).
- `renderWithTableBlocks`, `toBlocksWithTable`, `mdastTableToSlackBlock`,
and the AST→mrkdwn renderer (`fromAst` / `nodeToMrkdwn`) are removed.
- `SlackMarkdownConverter` alias is removed; use `SlackFormatConverter`.
- `renderFormatted(ast)` now returns standard markdown (was mrkdwn).
- Incoming `message` events still arrive as mrkdwn and are parsed unchanged.
Net -473 lines across markdown.ts and the five sender call sites.
* fix(slack): use mrkdwn fallback for response_url edits
|
||
|
|
9824d3335e |
Adapter hardening pass (#441)
* Adapter hardening pass * chore: remove redundant changeset --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
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> |
||
|
|
ed46bae52e |
feat(adapter-teams): native streaming for DMs via emit (#416)
* feat(adapter-teams): use native Teams SDK streaming for DMs Use ctx.stream.emit() from the Teams SDK for DM streaming instead of manual post+edit. This sends proper typing activities with streamType channelData, giving the native streaming UI in Teams. - Capture IStreamer from activity context in handleMessageActivity - Block handler with deferred promise so stream stays alive during processing - streamViaEmit() for DMs: uses stream.emit() with incremental text deltas - Group chats: accumulate full response and post as single message (no flicker) - Handle StreamCancelledError and stream.canceled for graceful cancellation Co-Authored-By: Claude <noreply@anthropic.com> * fix(tests): update Teams streaming assertions for accumulate-and-post Group chats now accumulate streamed chunks and post as a single message instead of post+edit, so assertions should check sentActivities not updatedActivities. * style: format replay-streaming test * chore: add changeset for teams native streaming --------- |
||
|
|
2531e9cff5 |
feat(slack): dynamic botToken resolver and custom webhookVerifier (#421)
* feat(slack): dynamic botToken resolver and custom webhookVerifier Allow `botToken` to be a function returning `string | Promise<string>` so apps can rotate or lazily fetch tokens; the resolver is invoked per API call. Add `webhookVerifier: (request) => string | Promise<string>` as an alternative to `signingSecret` for custom request verification — returns the verified body text or throws to produce a 401. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * change verifier signature to make it compatible with function * make scheduleMessage cancel() rotation-safe and honor verifier body - scheduleMessage cancel(): re-resolve token in single-workspace mode so rotation works. Slack rotated tokens have a 12h TTL and scheduled messages can outlive their schedule-time token, leaving cancel() with stale auth. Multi-workspace still snapshots ctx.token since cancel() runs outside the AsyncLocalStorage frame. - webhookVerifier: when it returns a string, use it as the verified body for downstream parsing. JSDoc previously implied this contract; the code only checked truthiness. - webhookVerifier JSDoc: explicit SECURITY note that timestamp/replay protection is the implementer's responsibility when bypassing signingSecret. - Tests: cover Attachment.fetchData snapshot semantics — multi-workspace uses the ctx token captured at attachment creation; single-workspace re-resolves the default provider per fetch (rotation-safe). * docs(slack): document botToken resolver and webhookVerifier in README * opt out of SLACK_SIGNING_SECRET env fallback when webhookVerifier is set A webhookVerifier passed in config was being silently shadowed by SLACK_SIGNING_SECRET in the env (read by both createSlackAdapter and the SlackAdapter constructor). An explicit verifier now opts out of that fallback in both code paths. Added a regression test that stubs the env var via vi.stubEnv. * register handleReactionEvent's outer promise via waitUntil handleReactionEvent does async work (conversations.replies, users.info) before delegating to chat.processReaction, which is the only point that registers a waitUntil task. The outer prep work was untracked, so callers that drained waitUntil tasks could complete before the reaction handler finished — flaky in CI under tight microtask scheduling. Track the outer promise too so the full handler is awaited. * fix(integration-tests): drain waitUntil cascade in test tracker --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
e8c4b1a6c4 |
docs: update adapter docs (#412)
* docs: update adapter docs * docs: update adapter docs * docs: update adapter docs --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
0f8b2b150b |
[slack] [bug] preserve self mentions in multi-workspace installs (#355)
* [slack] preserve self mentions in multi-workspace installs * add changeset for slack multi-workspace self-mention fix --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |