mirror of
https://github.com/vercel/chat.git
synced 2026-09-14 18:32:29 +08:00
chat@4.32.0
126 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
4cc87dd888 | [gchat] [bug] render markdown links with Google Chat custom link syntax (#356) | ||
|
|
097c9b4630 |
[chat] adding plan/update plan blocks for threads (#115)
* [chat] adding plan/update plan blocks for threads * refactor plan impl into its own file * thread.post() instead of thread.postPlan() * fixes * lint fixes * refactor postable objects * knip * Refactor PostableObject into dedicated module and add fallback support (#191) * feat: refactor adapter-slack and types based on Malte's comments Move PostableObject to dedicated file, update type exports, add fallback posts, and make PostableObject generic. Slack-Thread: https://vercel.slack.com/archives/C0977L169MW/p1772755978706959?thread_ts=1772755978.706959&cid=C0977L169MW Co-authored-by: Vishal Yathish <135551666+visyat@users.noreply.github.com> * fix: fallback path for PostableObject and clean up exports - Plan mutations (addTask, updateTask, complete) now work in fallback mode by using editMessage with fallback text instead of no-oping - Revert Slack adapter to throw on unsupported kinds (caller handles fallback, so adapter-level fallback strings are unnecessary) - Remove redundant re-exports of isPostableObject/PostableObject from plan.ts — export from canonical postable-object.ts only - Stop exporting POSTABLE_OBJECT symbol (internal implementation detail) - Fix nested ternary lint error in getFallbackText - Add tests for fallback post/edit path Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: v0 <v0[bot]@users.noreply.github.com> Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * Fall back to plain text instead of throwing for unsupported postable object kinds Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(chat): deduplicate PostableObject handling, improve type safety and test coverage --------- Co-authored-by: v0 <v0[bot]@users.noreply.github.com> Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
a0f508eee6 |
Migrate from BotFramework to TeamsSDK (#302)
* Migrate Teams adapter from botbuilder to @microsoft/teams.apps
Replace botbuilder/botframework-connector with @microsoft/teams.apps (TeamsSDK v2.0.6).
Breaking changes:
- Remove certificate auth (TeamsAuthCertificate) — use token or managedIdentityClientId instead
- Env vars changed: TEAMS_APP_ID → CLIENT_ID, TEAMS_APP_PASSWORD → CLIENT_SECRET, TEAMS_APP_TENANT_ID → TENANT_ID
- Reactions now work (addReaction/removeReaction) instead of throwing NotImplementedError
- Graph API calls use @microsoft/teams.graph-endpoints typed endpoints
Key changes:
- BridgeHttpAdapter captures TeamsSDK route handler for serverless dispatch
- Event handlers registered via app.on() (message, messageReaction, card.action, conversationUpdate, installationUpdate)
- Outbound calls use app.send() and app.api.conversations.activities()
- Stream support via post+edit (native HttpStream when SDK exports it)
- Graph API uses typed endpoints from @microsoft/teams.graph-endpoints
- isMention detection via activity entities instead of bot name matching
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Align TeamsAdapterConfig with AppOptions from TeamsSDK
- Replace custom config fields with Pick<AppOptions, ...>
clientId (was appId), clientSecret (was appPassword), tenantId (was appTenantId)
- Remove TeamsAuthFederated, appType — use managedIdentityClientId directly
- Constructor passes config through to App (App handles env var resolution)
- Use this.app.id instead of this.config.appId for bot identity checks
- 3 replay-fetch-messages tests have known failures (type shape mismatch)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Remove api() getter, add handler type safety
- Remove useless private api() getter, use this.app.api directly
- Type handlers with specific activity types:
handleMessageActivity(ctx: IActivityContext<IMessageActivity>)
handleAdaptiveCardAction(ctx: IActivityContext<IAdaptiveCardActionInvokeActivity>)
handleReactionFromContext(ctx: IActivityContext<IMessageReactionActivity>)
- Remove unnecessary casts now that ctx.activity is properly typed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Revert bot.tsx example changes from migration branch
Keep Azure OpenAI and DM handler changes as local-only, not part of the migration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Revert example package.json from migration branch
Keep only adapters.ts config changes, revert package.json dep changes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Remove unrelated skill files from migration branch
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix
* Update README for TeamsSDK migration
- New env vars: CLIENT_ID, CLIENT_SECRET, TENANT_ID
- New config: clientId, clientSecret, tenantId, token, managedIdentityClientId
- Remove certificate auth docs (dropped)
- Reactions now supported (add/remove)
- Typing indicator now supported
- Graph API uses @microsoft/teams.graph-endpoints
- Note streaming and modals status
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Revert "Update README for TeamsSDK migration"
This reverts commit
|
||
|
|
27b34e153b |
fix(chat): use adapter to parse channel id (#286)
* fix(chat): use adapter to parse channel id * test: fix cases use adapter to parse channel id * chore: update changeset |
||
|
|
8337173704 |
Programmatically ensure that SKILL.md is always up-to-date and compiles (#272)
* Update the SKILL.md and add a test that checks its consistency * Refactor docs test * Typed and knip |
||
|
|
af8c9580ac |
Revert "Revert "Test TS compilation of all docs (#264)" (#265)" (#266)
This reverts commit
|
||
|
|
d90f50c1a3 |
Revert "Test TS compilation of all docs (#264)" (#265)
This reverts commit
|
||
|
|
449850f8b8 |
Test TS compilation of all docs (#264)
* Test TS compilation of all docs * Lint |
||
|
|
6646702128 |
Security fixes (#262)
* Bump Next * Fix code scanning issues |
||
|
|
97be8a9ac9 |
feat(slack): resolve bare channel mentions to display names (#229)
* feat(slack): resolve bare channel mentions to display names Mirror the existing lookupUser() pattern to resolve bare <#C123> channel mentions into <#C123|channelName> via conversations.info API with caching. Channels with existing labels (<#C123|general>) are left unchanged. Also fix 22 pre-existing test timeouts in sandboxed environments by adding botUserId to skip real auth.test calls, and mocking users.info where parseSlackMessage/handleSlashCommand calls lookupUser. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Replay test * changeset --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
deeb9cec3a | Improve tests | ||
|
|
60f5d8e19f |
feat: add WhatsApp Business Cloud API adapter (#102)
* feat: add WhatsApp Business Cloud API adapter
Add @chat-adapter/whatsapp with support for sending/receiving messages,
reactions, interactive reply buttons, typing indicators, and webhook
verification via the Meta Graph API. Includes full test suite,
documentation updates, and workspace/turbo configuration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add media download, attachments, and location support to WhatsApp adapter
- Add downloadMedia() public method for fetching images, documents,
audio, video, and stickers via the Graph API (two-step: URL then binary)
- Populate message attachments with lazy fetchData() for all media types
- Add location support with Google Maps URL and structured text
- Add audio, video, sticker, and location fields to WhatsAppInboundMessage
- Set isMention: true on all messages (WhatsApp DMs are always direct)
- Update parseMessage to include attachments and isMention
- Add 10 new tests covering all media types, locations, and isMention
- Update docs feature matrix to reflect media receive support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review feedback for WhatsApp adapter
- Validate Graph API response before accessing messages[0].id in
sendTextMessage and sendInteractiveMessage
- Escape backticks and backslashes in escapeWhatsApp()
- Apply escapeWhatsApp() to renderText() content in all style branches
- Use webhook phoneNumberId in buildMessage() instead of this.phoneNumberId
- Encode proper threadId in parseMessage() instead of empty string
- Strict decodeThreadId() validation (exactly 2 segments after prefix)
- Add tests for extra segments in decodeThreadId and threadId in parseMessage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Migrate improvements from #179
Bring over several enhancements from chitru's WhatsApp adapter PR (#179):
- Voice message support (separate from audio)
- Legacy button response handling (template quick replies)
- Callback data encoding/decoding for interactive reply round-trips
- Message truncation at WhatsApp's 4096 char limit
- Example app integration (adapters, webhook route, package.json)
- GET webhook forwarding for WhatsApp verification challenges
- Package README and changeset
- Tests for all new functionality (68 total)
Co-Authored-By: Chitru Shrestha <chitra.shrestha@akuru.com.au>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): add error handling for inbound message processing
Wrap handleInboundMessage calls in try/catch to log errors if
synchronous processing fails (e.g., thread ID encoding). The async
processing already has its own error handling in Chat.processMessage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): prevent markdown regex from matching across newlines
Use [^\n*] and [^\n~] in fromWhatsAppFormat regex to prevent bold/strike
spans from merging across line boundaries. Adds a regression test.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): use WhatsAppInteractiveMessage type instead of object
Replace the untyped `object` parameter in sendInteractiveMessage with
the proper WhatsAppInteractiveMessage type for full type safety.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): hoist emoji mapping to module-level constant
Move the emoji name-to-unicode mapping out of resolveEmoji() so it is
not re-allocated on every call.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): remove duplicate JSDoc comment in types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(example): add startTyping to WhatsApp recording methods
The adapter supports typing indicators but the method was missing from
the recording proxy list.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): fix formatting and add package to readme test allowlist
Fix line-length formatting in markdown.ts regex and add
@chat-adapter/whatsapp to the valid packages list in readme tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): use defaultEmojiResolver instead of custom emoji map
Replace the hand-rolled EMOJI_MAP with the shared defaultEmojiResolver
from the chat SDK. WhatsApp uses unicode emoji like GChat, so toGChat()
provides the correct mapping with broader coverage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): make Graph API version configurable
Add apiVersion option to WhatsAppAdapterConfig (defaults to v21.0)
so users can upgrade without waiting for a package release.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): validate lat/lng before constructing Google Maps URL
Coerce and validate latitude/longitude with Number.isFinite() to
prevent unexpected URL construction from malformed webhook payloads.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): throw on editMessage instead of silently sending new message
Callers expecting an edit would get duplicate messages with the silent
fallback. Throwing makes the unsupported operation explicit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): document regex asymmetry between toWhatsApp and fromWhatsApp
Explain why toWhatsAppFormat doesn't need newline guards like
fromWhatsAppFormat does — the standard markdown parser output
never produces spans crossing line boundaries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): document callback data passthrough behavior
Add comments explaining that non-prefixed and malformed callback data
is intentionally passed through for legacy/external button IDs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): add editMessage and deleteMessage to recording methods
Include all adapter methods in the recording list for complete
debugging traces, even for unsupported operations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): preserve escaped formatting chars in toWhatsAppFormat
Escaped asterisks and tildes in standard markdown (e.g. \* and \~) are
now preserved through the conversion pipeline so WhatsApp renders them
as literal characters instead of misinterpreting them as formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): split long messages instead of truncating
Replace silent truncation at 4096 chars with message splitting that
breaks on paragraph (\n\n) then line (\n) boundaries, sending multiple
messages so no content is lost. Adds 8 tests for the splitting logic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(whatsapp): align editMessage/deleteMessage behavior and docs
- Fix README: editMessage/deleteMessage both throw, not fallback/no-op
- Fix editMessage JSDoc to reflect it throws
- Make deleteMessage throw instead of silently warning (consistent with editMessage)
- Bump @types/node to ^25.3.2 to match monorepo
- Add sample-messages.md with webhook payload examples
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs(whatsapp): add adapter documentation page
Add whatsapp.mdx covering installation, usage, Meta app setup,
webhook config, interactive messages, media attachments, 24-hour
messaging window, configuration, features, and troubleshooting.
Also add WhatsApp to the adapters navigation in meta.json.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add whatsapp adapter debug logging and try/catch
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(whatsapp): convert emoji placeholders in outgoing messages
WhatsApp adapter was sending raw {{emoji:wave}} placeholders instead of
Unicode emoji. Apply convertEmojiPlaceholders on all outgoing paths:
text messages, card fallback text, and interactive message fields.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix button rendering and streaming (needs to buffer)
* fix(example): handle editMessage failure on WhatsApp
WhatsApp Cloud API doesn't support message editing. Catch the error
in the demo "processing" animation and send a follow-up instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(chat): add onDirectMessage handler, stop treating DMs as mentions
DMs now route to dedicated onDirectMessage handlers instead of being
forced through onNewMention. If no DM handlers registered, DMs fall
through to onNewMention for backward compat. Adapters no longer set
isMention=true for DMs — the Chat SDK handles routing via adapter.isDM().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(chat): always route DMs to onDirectMessage regardless of subscription
Previously, onDirectMessage only fired for unsubscribed DM threads.
Subscribed DMs were routed to onSubscribedMessage, which was confusing
on non-threaded platforms (WhatsApp, Telegram) where all DMs share one
threadId — after the first message, onDirectMessage never fired again.
Now, DMs always route to onDirectMessage first, and onSubscribedMessage
only handles non-DM subscribed threads. Backward compat is preserved:
if no onDirectMessage handlers are registered, DMs fall through as
mentions.
The example bot is simplified accordingly — onDirectMessage now fetches
conversation history via fetchMessages each time instead of relying on
subscribe() and stored state.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(chat): pass channel as third argument to DirectMessageHandler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(example): reply to channel instead of thread in DM handler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(example): use thread instead of channel for DM operations
Channel ID is only two parts (whatsapp:{phoneNumberId}) which isn't a
valid conversation target on WhatsApp. The thread ID includes the user
phone and is required for startTyping/post/fetchMessages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Revert "fix(example): use thread instead of channel for DM operations"
This reverts commit
|