mirror of
https://github.com/vercel/chat.git
synced 2026-09-14 18:32:29 +08:00
chat@4.31.0
166 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2a553aa948 |
chore(release): version packages (#600)
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @chat-adapter/slack@4.31.0 ### Minor Changes - |
||
|
|
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> |
||
|
|
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> |
||
|
|
171657a019 |
[chat] adding stable id to link button action handlers (#598)
Enabling overriding the `link:<url>` action ID for `LinkButton` events. |
||
|
|
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> |
||
|
|
f40c4d4840 |
docs(chat): clarify isMe semantics for adapter authors (#582)
## summary clarifies that `author.isMe` means the message was sent by the current bot runtime and should be filtered from handler dispatch documents that adapters backed by user-owned accounts should not map platform fields like `fromMe` directly to `isMe` recommends tracking message ids returned by `postMessage` so webhook echoes can be identified without filtering legitimate user-authored messages |
||
|
|
a5b118f1dc |
chore(release): version packages (#546)
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @chat-adapter/slack@4.30.0 ### Minor Changes - |
||
|
|
9b8d8c4518 |
Discoverability lift: link KB guides, broaden npm keywords, mirror to AGENTS.md (#560)
Broad SEO/AEO pass across the docs site, adapter READMEs and AGENTS.md files, and npm package metadata so Chat SDK content shows up better in search engines, in LLM-driven package recommendations, and in IDE/coding-agent context. **Docs site** - Adds a `## Resources` section to the Getting Started and AI overview pages and to the Slack, Discord, GitHub, Liveblocks, and Sendblue adapter pages, each linking to applicable guides/templates with descriptions sourced from `resources-edge-config.json` and a cross-link back to the central `/resources` hub. **Adapter packages** - Mirrors the same Resources sections into the Slack, Discord, and GitHub READMEs (so they surface on npm) and into their AGENTS.md files (so coding agents see them alongside the API notes). - Expands `keywords` on every published adapter and state package — adds `chat-sdk`, `chatbot`, `ai-agent`, `ai-sdk`, `vercel`, plus platform-specific terms like `slack-bot`, `block-kit`, `slash-commands`, `github-app`, `whatsapp-business`, `state-adapter`. **Resources registry** - Registers four new entries in `resources-edge-config.json` (Human-in-the-Loop guide, Liveblocks AI agent guide, Slack + Vercel Blob guide, Durable iMessage Agent template) and runs `pnpm sync-resources` so the bundled `chat` package guides, `templates.json`, and `skills/chat/SKILL.md` all pick them up. - Fixes the synced Slack AI agent guide to import `toAiMessages` from `chat/ai` instead of the deprecated `chat` re-export path (the upstream KB source has also been updated, so future syncs will preserve this). **Drive-by fixes** - Resend adapter doc quick start: corrects `MemoryStateAdapter` class import to the `createMemoryState()` factory (matching every other adapter doc). - Zalo adapter doc: drops the "community adapter" callout that duplicated frontmatter. **Tooling / CI** - Adds `tsx` as a root devDependency so `pnpm sync-resources` works out of the box (it previously relied on `npx tsx`, which hung when not pre-cached). - Loosens the CI changeset gate to also skip `packages/chat/resources/` (generated data), matching the existing `*.md` carve-out. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
5461ea982b |
feat(telegram): add native DM draft streaming with segmented stream results (#340)
## Summary Add native Telegram DM streaming via `sendMessageDraft` while preserving Chat SDK's existing post+edit fallback for non-DM threads. This PR: - adds native private-chat draft streaming to the Telegram adapter - splits long streamed markdown into Telegram-safe persisted segments - retries without `parse_mode` when Telegram rejects markdown entity parsing - exposes segmented native stream results in the chat core - updates docs and feature matrices to reflect Telegram DM draft streaming --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
6581d31507 |
chore(release): version packages (#469)
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @chat-adapter/discord@4.29.0 ### Minor Changes - |
||
|
|
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>
|
||
|
|
b75eedbb5f |
feat(chat): add queue-debounce concurrency strategy (#495)
## summary adds an opt-in `burst` concurrency strategy for #414 when a thread is idle, the first message waits for `debounceMs`, messages that arrive during that window are queued, and the handler runs once with the latest message plus earlier burst messages in `context.skipped` after the handler finishes, messages that arrived while it was running are drained like `queue`, so the latest queued message is processed with earlier queued messages in `context.skipped` keeps existing `drop`, `queue`, `debounce`, and `concurrent` behavior unchanged updates docs to cover `burst`, explain when to choose it over `debounce`, and document the related `MessageContext` behavior |
||
|
|
67c1794a54 |
docs(chat): clarify direct message routing precedence (#491)
## summary clarifies that registered `onDirectMessage` handlers take precedence for incoming DM messages before subscribed-message, mention, and pattern routing updates the direct messages, event handling, thread subscription, and API docs so they match the current runtime behavior adds `onDirectMessage` to the Chat API docs fixes #432 |
||
|
|
e60bc8c408 |
chore: add .nvmrc file, formally specify Node version range support, and cover more versions in CI (#465)
* add .nvmrc file * follow up * make support of Node >= 20 explicit * update default Node version for contributing to the repo to 24 * run build-and-test CI job for both Node 20 and 24 * add changeset for package.json change |
||
|
|
5edcbbf7ef |
chore(release): version packages (#464)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
b3fc64d34e |
chore(release): version packages (#442)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
0cc3d06fd4 |
docs: fix stale API examples, adapter matrix, and broken links (#463)
* 1 * 2 * cs * 3 |
||
|
|
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> |
||
|
|
eb5f94a8ee |
feat(chat): add message.subject and adapter client access (#459)
* 1 * w * 3f * x * ln * gh * sl * t1 * u * t2 * t3 * t4 * t5 * d * d2 * cs * fx * cl * docs: clean up subject + .client docs and restructure nav - subject.mdx: simplify prose, drop redundant platform lists, link to MessageSubject API and getAdapter - api/message.mdx: add MessageSubject TypeTable - api/chat.mdx: expand getAdapter with Direct client access content - adapters.mdx: add Parent subject and Native client rows to feature matrix - usage.mdx: mention .client under Accessing adapters - adapter-github/-linear READMEs: add Direct API client section - meta.json: split Features into Messaging + Interactivity, move error-handling to Usage - title case across messaging-cluster page titles --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
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>
|
||
|
|
46d183bdab |
feat(chat): add Transcripts API + rename per-thread cache to threadHistory (#448)
* feat(chat): add Transcripts API and rename per-thread cache to threadHistory
Introduce `bot.transcripts` for cross-platform per-user message persistence.
When `ChatConfig.transcripts` and `ChatConfig.identity` are configured, every
inbound message has its `userKey` resolved during dispatch and the API exposes
`append` / `list` / `count` / `delete` keyed by that user. Backed by the
existing `StateAdapter.appendToList` primitive — every built-in state adapter
supports it with no contract changes.
Rename the existing per-thread history cache from `messageHistory` to
`threadHistory` (with backwards compat for `ChatConfig.messageHistory` and
`Adapter.persistMessageHistory`) so the two persistence layers don't share a
"messages" name. The state-adapter storage key prefix is unchanged so existing
data isn't orphaned.
`delete()` writes a tombstone via `appendToList(key, _, { maxLength: 1 })`
rather than `state.delete(key)`, because `state.delete` only addresses the
k/v namespace on every non-memory state adapter — `list()` and `count()`
filter the tombstone out so the API contract is preserved.
* docs(chat): cover Transcripts API and Conversation history
Add a Features-style "Conversation history" guide (`/docs/conversation-history`)
walking through identity resolution, the LLM-context append/list pattern,
filtering, and per-user deletion for DSR flows.
Add an API reference page at `/docs/api/transcripts` with `<TypeTable>` blocks
for `ChatConfig.transcripts`, `ChatConfig.identity`, every method on
`bot.transcripts`, and the `TranscriptEntry` shape.
Wire both into the corresponding `meta.json` files.
* example(nextjs-chat): wire Transcripts API into the AI mode handler
Replace the brittle `threadState.history` shim with `bot.transcripts.list({ ..., threadId, limit })` as the fallback context source for platforms without
`fetchMessages` (Telegram, WhatsApp). Drop the `history` field from
`ThreadState` accordingly.
Add a hardcoded `TEST_USER_KEY = "test-user"` so the API can be exercised
without juggling real user identities, plus "Show Transcripts" and
"Clear Transcripts" buttons in the welcome card so the store can be
inspected and reset from chat.
* fix(chat): tighten Transcripts API public surface and wiring
Polish on top of the Transcripts API + threadHistory rename, addressing
review concerns before merge.
Public surface (`types.ts`, `index.ts`):
- Expose `transcripts` on the `ChatInstance` interface so callers typed
against the public interface can reach `bot.transcripts`.
- Promote the `count` argument to a named `CountQuery` interface,
matching `DeleteTarget` / `ListQuery`. Exported from `index.ts`.
- Document on `TranscriptsApi.list()` that pagination is intentionally
out-of-scope — the store keeps at most `maxPerUser` entries per user.
- Reconcile the `TranscriptEntry.id` JSDoc with the implementation:
UUID assigned at append time, returned in append order, not
lexicographically sortable; use `timestamp` for cross-store ordering.
Wiring (`chat.ts`):
- Include `threadId` in the identity-resolver failure log context so
operators can correlate failures with the source thread.
Stale-reference sweep:
- Replace lingering "Messages API" / `chat.messages` /
`messages.storeFormatted` strings in shipped JSDoc with the new
`transcripts` names (these ride into `.d.ts` and are user-visible).
- Fix the dead `[Messages API](./messages.ts)` link in the existing
thread-history-rename changeset.
* test(chat): cover dual-read precedence, resolver edges, concurrent ops
Fill gaps in the Transcripts API + threadHistory rename test suite:
`chat.test.ts` (persistThreadHistory block):
- top-level `config.messageHistory` (deprecated alias) flows through
to the per-thread cache when `threadHistory` is unset
- `threadHistory` takes precedence over `messageHistory` when both are
set — pinned by asserting `appendToList` receives the new config's
`maxLength` / `ttlMs`
- both `persistThreadHistory` and `persistMessageHistory` set on the
adapter still triggers persistence
`transcripts-wiring.test.ts`:
- sync resolver returning a plain string populates `message.userKey`
- resolver returning `""` is treated as no userKey (truthy check at
the dispatch hook would silently flip if a future change moved to
`!== undefined`)
`transcripts.test.ts`:
- concurrent append/delete/append interleave preserves invariants:
`count()` and `list()` agree (no tombstone leak), no pre-delete
entry survives, and the post-delete result is bounded by the two
concurrent appends
* docs(chat): use named types in Transcripts API reference
- `formatted` rows in the AppendInput / TranscriptEntry TypeTables
now render `FormattedContent | undefined` (the alias actually
exported from `chat`), instead of `Root | undefined` which would
force readers to pull the type from `mdast` directly.
- `count` signature uses the new `CountQuery` named type, with a
one-liner describing its single field.
* example(nextjs-chat): fix stale comment on transcripts demo handler
The action handler was relabelled to `transcripts` when it was wired
to `bot.transcripts.list`, but the leading comment still read
"Demonstrate fetchMessages and allMessages" from the previous
iteration. Update it to describe the transcripts demo.
---------
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
|
||
|
|
f55378a3d8 |
chore(release): version packages (#378)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
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> |
||
|
|
a520797922 |
feat: add chat.getUser() for cross-platform user lookups (#391)
* feat: add chat.getUser() for cross-platform user lookups Add UserInfo type and optional getUser() method to the Adapter interface. Implement on Slack (extends existing lookupUser with email/avatar), Discord, Google Chat, GitHub, Linear, and Telegram adapters. Add "Who Am I" button to the example app demonstrating the feature. Update docs with getUser API reference and usage examples. * fix(chat): improve getUser across slack and gchat adapters - slack: return null from lookupUser on failure instead of fallback object, removing the isBot === undefined sentinel in getUser - slack: use image_192 instead of image_72 for better avatar quality - gchat: cache avatarUrl from webhook sender payload - gchat: return avatarUrl in getUser response - gchat: fix tests to use current cache format with isBot field - docs: document null return, fix example to use message.author * chore: fix lint * docs(chat): include Microsoft Teams in getUser supported adapters list * feat(adapter-teams): add getUser() support (#404) * feat(adapter-teams): add getUser() via Microsoft Graph API - Cache aadObjectId from activity.from during webhook handling - Implement getUser() using Graph GET /users/{user-id} endpoint - Requires User.Read.All application permission - Returns null gracefully when user hasn't interacted or Graph call fails * docs: add getUser() section to Teams adapter README * chore: apply ultracite formatting to adapter-teams getUser * fix(chat): cover all 7 adapters in getUser inference and document per-platform constraints --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
70281dc58f |
feat(chat): add initialOption and option_groups to ExternalSelect (#410)
* feat(chat): add initialOption and option_groups to ExternalSelect * docs(modals): document ExternalSelect initialOption and option_groups, truncate group label to 75 chars |
||
|
|
b0ab804f18 |
- Bundle guide markdown and a templates manifest with the chat package at resources/guides/*.md and resources/templates.json so AI agents can discover Chat SDK resources offline (#423)
- Add scripts/sync-resources.ts (run via pnpm sync-resources) that reads apps/docs/resources-edge-config.json, fetches each guide's .md version over https with a timeout and size cap, writes templates.json, and regenerates the Available resources block in skills/chat/SKILL.md - Migrate the Slack Next.js, Discord Nuxt, and Hono code-review guides from on-site MDX to Vercel KB and register them in the resources edge-config JSON alongside the existing external guides - Remove /docs/guides MDX content, sidebar entries, top-level Guides nav entry, getting-started cards, and the dead /guides/ branch in the sitemap route now that all guides live externally and are surfaced on /resources - Replace the homepage Guides/Templates section and the standalone Adapters pill section with a single two-column Resources + Adapters section (icons, headings, descriptions, outline buttons, divider), and drop the URL footer from ResourceCard on the Resources page - Update skills/chat/SKILL.md to point at resources/guides and resources/templates.json and list the available guides and templates between marker comments that sync-resources rewrites - Add tsx to knip's ignoreBinaries so npx tsx in the new script does not fail lint Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
d630e6c8a7 |
fix(chat): honor concurrency.maxConcurrent in the concurrent strategy (#419)
Closes #417. - handleConcurrent now acquires a per-thread semaphore slot when maxConcurrent is finite; fast path preserved for the default Infinity. - Constructor throws on maxConcurrent < 1 (would deadlock) and warns when maxConcurrent is paired with a non-concurrent strategy (was previously ignored silently). Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
a179b29141 |
Implement external_select block kit for Slack (#397)
* feat(slack): external_select's block kit implementation - block_suggestion handler for slack webgook - new <ExternalSelect/> to chat modal jsx - new .onOptionsLoad() * feat: add tests for new external_selec implementation * feat(docs): Slack externa_select docs * chore: changeset * chore: remove docs from changeset --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
b9a1961aa5 |
fix(telegram): MarkdownV2 rendering + telegram-chat reference example (#407)
* fix(telegram): switch parse_mode from legacy Markdown to MarkdownV2
The Telegram adapter hardcoded `parse_mode: "Markdown"` (legacy) but
rendered messages via the SDK's generic `stringifyMarkdown()`, which
emits standard markdown. Two incompatible dialects glued together:
- Standard markdown uses `**bold**`, Telegram legacy uses `*bold*`
- Legacy Markdown has no escape rules — any message with `.`, `!`,
`(`, `)`, `-`, `_` in unexpected positions was rejected with
`can't parse entities`, which is virtually every LLM-generated
response
- Legacy Markdown is deprecated by Telegram and lacks support for
underline, strikethrough, spoiler, and blockquote
This commit:
- Switches TELEGRAM_MARKDOWN_PARSE_MODE to "MarkdownV2"
- Replaces fromAst() with a proper AST → MarkdownV2 renderer:
- Single `*bold*`, `_italic_`, `~strike~` markers
- Context-aware escaping: 20-char matrix for normal text, only
`` ` `` and `\` inside code blocks, only `)` and `\` inside link
URLs
- Headings rendered as bold (MarkdownV2 has no heading syntax)
- Ordered/unordered lists with escaped dashes and periods
- Blockquotes with per-line `>` prefix
- Tables pre-empted and rendered as ASCII code blocks
- Explicit handlers for reference-style links, images, HTML, and
definitions so nothing is silently dropped
- Routes card fallback text through `fromMarkdown` (not raw escape)
with `boldFormat: "**"` — @chat-adapter/shared's cardToFallbackText
defaults `boldFormat` to "*" (Slack mrkdwn), which would render as
italic on Telegram. Explicit "**" keeps the card title rendered as
real MarkdownV2 bold.
- Fixes resolveParseMode so every message routed through the format
converter (`{markdown}`, `{ast}`, cards, JSX) gets
`parse_mode: "MarkdownV2"`. Previously only `{markdown}` and cards
were covered, so `{ast}` messages shipped without parse_mode and
rendered asterisks literally.
- Documents inbound vs outbound dialects on applyTelegramEntities /
escapeMarkdownInEntity (inbound entities → standard markdown)
versus the new outbound MarkdownV2 renderer, so future
contributors don't confuse the two.
Tests: full 20-char MarkdownV2 escape matrix, context-escape tests
for code blocks and link URLs, nested-formatting tests, edge cases
(empty, whitespace-only, raw HTML), and an end-to-end LLM-output
corpus test that asserts MarkdownV2 validity (no unescaped special
chars outside entities or code blocks). Regression guards added in
index.test.ts for the AST / plain-string / raw parse_mode paths and
for card-title MarkdownV2 bold rendering.
Fixes #226
* feat(examples): add telegram-chat reference bot
Polling-mode Telegram bot that exercises the adapter end-to-end:
MarkdownV2 rendering, interactive cards with inline keyboards,
reactions, file uploads, and streaming edits. Runs with a single
`pnpm --filter example-telegram-chat start`; no webhook, no public
URL, no external API keys.
Menu structure — three categorized sub-menus reached from any DM text:
- Text & Markdown: plain, inline emphasis, code block, links, list+table,
20-char torture string, LLM-style corpus, streaming editMessage loop
- Cards & Actions: interactive approval card (edits in-place on press),
callback_data size probe demonstrating the 64-byte limit, LinkButton
- Media & Reactions: on-demand reaction one-shot (briefly subscribes),
generated 1×1 PNG upload, generated minimal PDF upload
Zero new runtime deps. PNG/PDF are hand-rolled in memory
(lib/png.ts, lib/pdf.ts) rather than pulled from a binary-processing
library. Failure handling is consistent: every demo runner is
try/catch-wrapped and posts an inline ❌ line with the error message.
Excluded from npm release via .changeset/config.json.
* fix(telegram): produce valid MarkdownV2 when truncating long messages
The MarkdownV2 migration widened a latent truncation bug into a reliable
400. The previous truncator sliced at 4096/1024 chars and appended
literal "..." — but in MarkdownV2 `.` is a reserved character, the slice
can leave an orphan trailing `\`, and it can cut through a paired
entity (`*bold*`, `` `code` ``) leaving it unclosed.
Unify the two truncate methods into one `truncateForTelegram(text,
limit, parseMode)` that appends `\.\.\.` for MarkdownV2 and walks back
past unbalanced entity delimiters or orphan backslashes. Plain text
keeps literal `...`. Adds 8 length-limit tests.
Related cleanup:
- Move MarkdownV2 string utilities and Bot API limits to markdown.ts.
- Type renderMarkdownV2 exhaustively on mdast's `Nodes` union with a
`never` assertion so new node kinds fail the build. Replaces the
hand-rolled `AstNode` interface. Adds explicit cases for table /
tableRow / tableCell (throw — preprocessed by fromAst),
footnoteDefinition, footnoteReference, yaml.
- Introduce `TelegramParseMode = "MarkdownV2" | "plain"` replacing
`string | undefined`. `toBotApiParseMode` handles the wire mapping.
- Re-export `Nodes` from the chat package; re-export
`TelegramReactionType` from the adapter entry.
* feat(examples): add length-limit demos to telegram-chat reference bot
Three new menu entries exercise the MarkdownV2 truncation path that the
prior commit fixed:
- Long (5000 plain) — basic truncation, verifies escaped `\.\.\.` ellipsis
- Long (bold crosses 4096) — entity-balancing heuristic for unclosed `*`
- Long (code crosses 4096) — entity-balancing heuristic for unclosed `` ` ``
Each button posts a message whose rendered length exceeds Telegram's
4096-char limit and would have produced `can't parse entities` 400s
against the previous truncator. Serves as an interactive smoke test
alongside the unit tests in packages/adapter-telegram.
* test(telegram): add unit tests for truncation helpers and MarkdownV2 boundary trimming
* docs(telegram): update README to reflect MarkdownV2 parse mode
* chore: unexport trimToMarkdownV2SafeBoundary to fix knip
---------
Co-authored-by: dancer <josh@afterima.ge>
|
||
|
|
7e90d9c8fa |
Add Slack Socket Mode support (#162)
* Add slack/socket mode dependency
* Update config types and SlackAdapter class
* Add socket mode methods, extract interactive dispatch
* Update createSlackAdapter factory function
* Write tests for socket mode
* Create slack-socket-mode.md
* Run fix
* Fix polynomial regex issues
* Fix: Floating promises in `routeSocketEvent` for slash commands and interactive payloads can cause unhandled promise rejections that crash the Node.js process.
This commit fixes the issue reported at packages/adapter-slack/src/index.ts:1152
**Bug Analysis:**
In `routeSocketEvent` (line 1150), which is a synchronous `void` method, two async operations produce floating promises:
1. `this.handleSlashCommand(params)` (line 1165) - `handleSlashCommand` is `async` and always returns a `Promise<Response>`. It calls `await this.lookupUser(userId)` which internally calls `await this.chat.getState().get()` (before the try/catch around the API call), and `this.chat.processSlashCommand()`. Any of these could throw.
2. `this.dispatchInteractivePayload(payload)` (line 1172) - Returns `Response | Promise<Response>`. When the payload type is `view_submission`, it delegates to `async handleViewSubmission()`, which calls `await this.chat.processModalSubmit()` and accesses `payload.view.state.values` (which could throw on malformed payloads).
Since `routeSocketEvent` is synchronous (`void` return type) and called from a sync context within the socket mode event handler (after `await ack()` has already completed), these returned promises are fire-and-forget. If any reject, it triggers an unhandled promise rejection, which in Node.js 15+ terminates the process by default.
In contrast, in the webhook code path (`handleWebhook`), these same methods are always `return`-ed from async functions, so their promises are properly chained to the caller.
**Fix:**
Added `.catch()` handlers to both floating promises:
1. For `handleSlashCommand`: Added `.catch()` that logs the error via `this.logger.error`.
2. For `dispatchInteractivePayload`: Since it returns `Response | Promise<Response>` (only a Promise for `view_submission`), used `instanceof Promise` to conditionally attach a `.catch()` handler only when the result is a Promise.
This approach was chosen over making `routeSocketEvent` async because: (a) it doesn't change the method signature, (b) the caller doesn't need to await it (the ack has already been sent), and (c) errors are logged rather than silently swallowed.
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: haydenbleasel <hello@haydenbleasel.com>
* Add socket mode forwarding support to Slack adapter
- Export SlackForwardedSocketEvent type
- Add x-slack-socket-token check at top of handleWebhook() for forwarded events
- Update routeSocketEvent() to accept WebhookOptions and use waitUntil
- Add startSocketModeListener(), runSocketModeListener(), forwardSocketEvent()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add tests for socket mode forwarding
- Forwarded event accepted/rejected based on appToken
- Bypasses signature verification for forwarded events
- Options passthrough to handlers
- startSocketModeListener returns 200/500 appropriately
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add socket mode cron route and vercel config
- New /api/slack/socket-mode route using createPersistentListener
- Mirrors Discord gateway pattern (CRON_SECRET auth, Redis coordination)
- Cron runs every 9 min, listener duration 10 min
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix signingSecret defaulting to empty string in socket mode
Make signingSecret optional (string | undefined) instead of falling
back to "". verifySignature now returns false when no secret is
configured, preventing HMAC with an empty key from silently passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Wrap event_callback in try-catch in routeSocketEvent
Sync errors from processEventPayload were silently dropped in
socket mode. Wrap with try-catch for parity with slash_commands
and interactive cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Use dedicated socketForwardingSecret for forwarding auth
Stop using the Slack app-level token (xapp-...) as the bearer token
for HTTP forwarding. Adds socketForwardingSecret config option
(auto-detected from SLACK_SOCKET_FORWARDING_SECRET) with fallback
to appToken for backwards compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Replace double cast with type guard for socket event body
Validate body.event exists and construct a properly typed
SlackWebhookPayload instead of using `as unknown as`.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Internalize SlackForwardedSocketEvent type
Remove export — only used internally by the forwarding mechanism.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix formatting in socketForwardingSecret check
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add socket mode documentation to Slack adapter README
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(slack): use SDK envelope type for socket mode event routing
* fix(slack): pass interactive response through ack in socket mode
* feat(chat): add clear modal response action to close entire view stack
* chore: update changeset for clear modal action
---------
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: dancer <josh@afterima.ge>
|
||
|
|
9093292ef4 |
feat(chat): add streaming options to thread.post() (#388)
* feat(chat): add streaming options to thread.post() * test(chat): add comprehensive tests for PostStreamOptions * feat(chat): add StreamMessage PostableObject for streaming with options * refactor(chat): remove PostStreamOptions second param, keep only StreamMessage PostableObject * refactor(chat): rename StreamMessage to StreamingPlan, fix post() return type Rename per Malte's feedback - StreamingPlan better describes what the options control (task grouping, stop blocks for streamed plans). Fix type safety issue where post<T extends PostableObject>() returned SentMessage at runtime instead of T. Now awaits handleStream() for side effects and returns the original StreamingPlan instance. * test(chat): cover updateIntervalMs-only and fallback paths for StreamingPlan Remove a duplicated test block, drop a duplicate JSDoc line on Thread.post, and add tests for posting a StreamingPlan with only updateIntervalMs and for routing StreamingPlan through the fallback post+edit path when the adapter has no native streaming. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
37dbb4ac8b |
feat(chat): add thread.getParticipants() (#386)
* feat(chat): add thread.getParticipants() method Returns unique human participants in a thread by scanning message history. Excludes the bot itself. Useful for subscribing only to 1:1 conversations and unsubscribing when others join. * fix: filter all bots in getParticipants(), not just self Third-party bots (e.g. Jira, GitHub) were included as participants because only isMe was checked. Now filters on isBot as well. * docs: add getParticipants() to Thread API reference and guides --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
bca47924b7 |
feat: enhance task update structure with optional details field (#385)
- Added a `details` field to the `task_update` type for providing additional context in task updates. - Updated relevant documentation and test cases to reflect the new field, improving clarity on task progress reporting. |
||
|
|
608d5f00b0 |
feat(chat): add chat.thread() for creating thread handles (#380)
* feat(chat): add chat.thread() method for creating thread handles Allows constructing a Thread handle from a thread ID outside of webhook contexts, enabling proactive messaging to existing threads. Closes #148 * docs: add chat.thread() to API reference --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
1e7c55150e | feat: restore attachment fetchData after queue/debounce serialization (#338) | ||
|
|
a8f2aab256 |
[chat] enable updating task blocks by ID, rather than only most recent (#375)
* [chat] enable updating task blocks by ID, rather than only most recent * add changeset for updateTask by ID * test(chat): add tests for updateTask by ID --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
7f5bea3fe1 |
Version Packages (#368)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
ddb084b3a6 |
fix(chat): guard fallback streaming against empty content (#357)
* fix(chat): guard fallback streaming against empty content * test(chat): add tests for empty content guards in fallback streaming * chore: add changeset |
||
|
|
2235c160ca |
fix(chat): export standalone reviver for workflow-safe deserialization (#257)
* fix(chat): export standalone reviver for workflow-safe deserialization Importing the Chat instance into Vercel Workflow files pulls in adapter packages that depend on Node.js modules, which aren't available in the workflow sandbox. This adds a standalone `reviver` function exported from `chat` that deserializes Thread/Channel/Message objects without needing a Chat instance or its adapter dependencies. Also updates the durable chat sessions guide to use the standalone reviver and dynamic bot imports inside step functions. Closes #243 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(chat): preserve adapterName on deserialized toJSON and add standalone reviver docs * fix: sort imports in index.ts --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: dancer <josh@afterima.ge> Co-authored-by: Ben Sabic <27636870+bensabic@users.noreply.github.com> Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
63515f2286 |
Version Packages (#351)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
2700ce85b3 |
feat(chat): Enable disabling code-fencing for streamed tables per-adapter (#349)
* feat(chat): Enable disabling code-fencing for streamed tables per-adapter As Slack now natively supports markdown tables, the code-fencing for tables is not required and in fact stops them from being rendered natively. This PR adds an option to configure code-fencing tables per adapter. By default true, false only for Slack. * Update StreamingMarkdownRendererOptions comments Removed comment about default behavior for wrapTablesForAppend option. |
||
|
|
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> |
||
|
|
a8dc522c4c |
Version Packages (#310)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
4f5d20029f |
Add modal support for Teams (#325)
* feat(teams): add dialog (task module) support
Teams dialogs require modal content to be returned inline in the HTTP
response when a task/fetch invoke fires. This adds:
- `actionType: "modal"` on buttons to emit msteams task/fetch hint
- `onOpenModal` hook on WebhookOptions for inline modal interception
- dialog.open/dialog.submit handlers in Teams adapter with Promise.race
- Modal-to-AdaptiveCard converter (modals.ts)
- Bridge adapter sends empty body (not "{}") for dialog close responses
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(teams): use @microsoft/teams.cards builders for Adaptive Cards
Replace hand-rolled plain JSON objects and local type definitions with
typed builder classes from @microsoft/teams.cards. This gives compile-time
type safety and eliminates the local AdaptiveCard/AdaptiveCardElement/
AdaptiveCardAction interfaces.
Also fix ephemeral modal button missing actionType="modal", which
prevented the dialog from opening on Teams.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(teams): preserve contextId in modal update/push responses
Pass the original contextId through to re-rendered modals so subsequent
submissions can still retrieve the stored thread/message/channel context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: address review feedback across dialog support
- Clean up timeout timer in handleDialogOpen to prevent resource leak
- Also race on actionPromise so errors surface instead of silently timing out
- Extract buildContinueResponse helper to deduplicate update/push cases
- Use typed TextInputOptions/ChoiceSetInputOptions instead of Record<string, unknown>
- Make processSlashCommand options parameter explicit (WebhookOptions | undefined)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(chat): await storeModalContext before opening modal
The state write was fire-and-forget, so a fast dialog.submit could
arrive before the context was persisted, causing retrieveModalContext
to return empty. Also adds changeset for the new public API surface.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(chat): add missing disabled prop to ButtonProps JSX interface
The ButtonElement and ButtonOptions already supported disabled, but the
JSX ButtonProps interface was missing it, causing <Button disabled> to
silently drop the prop.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback for dialog support
- Add unit tests for modals.ts (16 tests) and modal button actionType in cards.test.ts
- Make dialog open timeout configurable via dialogOpenTimeoutMs in TeamsAdapterConfig
- Fix ModalSubmitHandler type to accept Promise<void> returns, remove @ts-expect-error from example
- Delete stored modal context after retrieval to prevent state adapter leaks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: lint fixes and add X-User-Agent header to Teams adapter
- Fix import ordering, formatting, and non-null assertions in modals.test.ts
- Sort interface members in TeamsAdapterConfig
- Add X-User-Agent: Vercel.ChatSDK header to Teams SDK App client
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
8d8927411d |
fix: disable source maps in published packages (#337)
* fix: disable source maps in published packages * chore: add changeset |
||
|
|
d3f04ec92b |
docs: add missing JSDoc and adapter-shared README (#339)
* docs(chat): add JSDoc to onModalSubmit and onModalClose * docs(shared): add README for adapter-shared package |
||
|
|
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 |
||
|
|
91820173f4 | Version Packages (#300) | ||
|
|
4166e09dad | Add channelVisibility support to Thread, Channel, and Slack adapter (#51) |