mirror of
https://github.com/vercel/chat.git
synced 2026-09-14 18:32:29 +08:00
@chat-adapter/slack@4.31.0
221 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 - |
||
|
|
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> |
||
|
|
a8bf99ab19 |
fix(adapter-slack): don't rewrite @handles inside URL paths as mentions (#618)
## Problem `linkBareMentionNames` (in `markdown.ts`) rewrites any bare `@word` into a `<@word>` Slack mention. Its lookbehind `(?<![<\w])@(\w+)` excludes `<` and word characters, but **not `/`** — so an `@handle` inside a URL path gets rewritten, corrupting the link: ``` See https://hackmd.io/@jkyang/B1W69XA-fe → See https://hackmd.io/<@jkyang>/B1W69XA-fe ❌ (Slack renders a broken mention; link dead) ``` This affects common `@handle` URLs (HackMD `/@user`, Mastodon `/@user`, Medium `/@user`, …). It reproduces on `main` via `toSlackPayload` for both the plain `text` and the native `markdown_text` paths, because `finalize()` runs the regex over the whole string. (The `renderPostable({ markdown })` AST path is unaffected — bare URLs become link nodes there — which is likely why it's gone unnoticed.) This is the same class of bug as the email fix in #394, which tuned this same regex; URL paths are the sibling case it didn't cover. ## Fix Add `/` to the negative lookbehind so a handle preceded by a path separator is left intact: ```diff -const BARE_MENTION_PATTERN = /(?<![<\w])@(\w+)/g; +const BARE_MENTION_PATTERN = /(?<![<\w/])@(\w+)/g; ``` Whitespace-/punctuation-led mentions (`(cc @george)`), emails (`user@example.com`), and `<mailto:…>` links are unaffected. ## Tests Two cases added to the `mentions` suite (plain string + markdown). Verified against current `main`: - **Without the fix:** both new tests fail (e.g. `…/@user` → `…/<@user>`). - **With the fix:** full `markdown.test.ts` suite passes (28/28). Changeset included (`patch`). --------- 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> |
||
|
|
4662309fe3 |
feat(telegram): support native rich messages (#616)
## summary adds native rich message support for Telegram Bot API 10.1 explicit markdown and AST messages now use `sendRichMessage`, edits use rich message payloads, and private chat streams use `sendRichMessageDraft` before persisting the completed response preserves existing behavior for plain strings, raw messages, cards, media captions, and older or custom Bot API servers through automatic fallback adds typed inbound rich message parsing, rich message limits, regression coverage, and updated adapter documentation |
||
|
|
8336a3e818 |
feat(slack): expose webClientOptions to configure the underlying WebClient (#602)
## summary adds `webClientOptions` to `SlackAdapterConfig` so users can configure the underlying Slack `WebClient` instances the options apply to both the default client and per-token clients used for multi-workspace requests, including settings such as `retryConfig`, per-request `timeout`, custom headers, and `rejectRateLimitedCalls` `slackApiUrl` is intentionally excluded from `webClientOptions` because the existing `apiUrl` option remains the single configuration path for overriding the Slack Web API base URL custom headers are cloned for each client because the Slack SDK adds authorization to the provided headers object, preventing credentials from leaking between token-bound clients --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
9c936f8796 |
feat(telegram): support slash commands (#586)
## Summary Adds Telegram bot command support for Chat SDK slash command handlers. - Routes Telegram `/command` and `/command@botusername` messages to `bot.onSlashCommand` - Ignores commands addressed to another bot - Keeps non-command messages on the existing normal message path ## Test plan - `pnpm validate` - Tested locally against a real Telegram bot ## Checklist - [x] All commits are signed and verified - [x] `pnpm validate` passes - [x] Changeset added - [x] Documentation updated --------- 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. |
||
|
|
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> |
||
|
|
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 |
||
|
|
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 - |
||
|
|
b63c042ca1 |
fix(slack): resolve reaction user display names (#523)
## Summary Fixes Slack reaction events so `event.user.userName` and `event.user.fullName` are resolved from Slack user profile data instead of always being the raw Slack user ID. This reuses the Slack adapter's existing cached `lookupUser()` path and falls back to the user ID when lookup fails. Fixes #521 |
||
|
|
073ff920a1 |
fix(slack): return uploaded file ids from postMessage (#574)
## summary fixes #564 preserves Slack `files.uploadV2` confirmation IDs on `postMessage` results when a message includes uploaded files file-only Slack posts now keep the existing synthetic raw payload and add `uploadedFileIds`, while text/card posts with files augment the normal `chat.postMessage` raw response with the same IDs this lets callers confirm which files Slack accepted without replacing existing `raw` data |
||
|
|
999d268de1 |
fix(slack): pass token through native stream stop (#573)
## summary fixes #570 fixes Slack native streaming when the stream reaches `stop()` before a token-bearing append has flushed `SlackAdapter.stream()` now passes the resolved bot token on every `streamer.append()` and on `streamer.stop()`, matching Slack's auth requirements and avoiding `not_authed` responses from `chat.startStream` / `chat.stopStream` adds regression coverage for buffered markdown streams and repeated structured chunk appends |
||
|
|
ffc43fcf1f |
feat(whatsapp-adapter): Add typing indicator support (#320)
## Summary Adds typing indicator support for WhatsApp and also bumps the API version to the latest v25.0. > Good to know: There is a limitation with typing indicator API: it has a 25-second cooldown and rqeuires a recent incoming message. This means if you try to display the typing indicator before the cooldown period has passed, it won’t show up, but the message will still be marked with a red check mark. ## Test plan Verified end-to-end on a real WhatsApp Business profile --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
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) |
||
|
|
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> |
||
|
|
6ed4a43897 |
feat(slack): add low-level interaction helpers (#559)
## summary adds lower-level Slack helpers for custom runtimes that already own routing, state, sessions, or workflow execution this expands the existing Slack subpaths with typed inbound files, richer interaction payload fields, thread reply fetching, modal opening, and generic input request Block Kit helpers it keeps the helpers on the existing `@chat-adapter/slack` package and preserves the runtime-light import boundary for `webhook`, `api`, and `blocks` |
||
|
|
177735a60f |
fix(gchat): collapse redundant autolink formatting for email links (#553)
## Description Fix redundant autolink rendering for email addresses in the Google Chat adapter. Previously, autolinked email addresses were rendered as `<mailto:...|...>` even when the visible text already matched the email address. This resulted in unnecessary verbose output. This change collapses such cases to plain text for cleaner and more consistent rendering. While testing, it was observed that `tel:` links are not currently generated from plain phone number inputs in the existing parsing pipeline. However, support for `tel:` handling has still been added in the implementation for future compatibility as referenced in the issue. <img width="757" height="107" alt="image" src="https://github.com/user-attachments/assets/a8ccfd6c-6669-4535-b733-5f2c185d9e2f" /> Additionally, new test cases have been added to cover email autolinks, labeled mailto links, and general markdown link behavior. ## Type of Change - [x] Bug fix (non-breaking change which fixes an issue) ## Related Issues Fixes #516 ## Changes Made - Collapsed redundant `mailto:` autolinks when visible text matches the email address - Added support for `tel:` scheme handling for future compatibility - Updated link rendering logic in Google Chat adapter markdown converter - Added and updated unit tests for email and link conversion cases ## Testing - [x] All existing tests pass - [x] Added new tests for the changes - [x] Manually tested the changes ### Test Coverage - Email autolink collapsing verified - Custom labeled mailto links verified - HTTP link formatting verified - Edge cases for link conversion verified via unit tests ## Screenshots/Demos N/A ## Checklist - [x] My code follows the project's code style - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings or errors - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I have created a changeset (`pnpm changeset`) ## Changeset - [x] I have created a changeset for these changes ## Additional Notes During testing, `tel:` links were not observed in the current markdown parsing pipeline for plain phone numbers. However, support for `tel:` has been included to align with the issue description and for future-proofing the adapter behavior. --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
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 |
||
|
|
1294490755 |
refactor(slack): share provider helpers (#556)
## summary reuses the low-level Slack formatting helpers inside the high-level Slack adapter without changing adapter behavior this removes duplicated mrkdwn-to-markdown and markdown-bold conversion logic by sharing `slackMrkdwnToMarkdown`, `linkBareSlackMentions`, and `markdownBoldToSlackMrkdwn` across the format converter, card converter, and blocks subpath the low-level mention helper remains ID-based to match Slack docs, while the high-level adapter keeps its existing bare-name mention compatibility privately |
||
|
|
dbd8dc5b7c |
feat(slack): expose block kit helpers (#555)
## summary exposes a runtime-free `@chat-adapter/slack/blocks` subpath for converting Chat SDK-style card objects into Slack Block Kit blocks the new subpath includes typed card input shapes, fallback text helpers, Slack emoji placeholder conversion, and docs-backed Slack limits for headers, images, actions, select options, fields, and tables this keeps lower-level Slack rendering reusable without importing the full Slack adapter, `chat`, `@chat-adapter/shared`, or Slack SDK runtime packages |
||
|
|
aba6aa94fe |
feat(slack): add api primitives subpath (#548)
## summary adds `@chat-adapter/slack/api` for lightweight Slack Web API helpers the new subpath exposes fetch-based primitives for calling Slack Web API methods, posting and updating messages, sending response URL payloads, uploading files through Slack's external upload flow, and fetching private Slack file URLs with bearer auth it stays independent of the full Slack adapter runtime, Chat SDK runtime, Slack WebClient, Socket Mode, and shared adapter package, so lower-level runtimes can reuse Slack API correctness without adopting `createSlackAdapter` |
||
|
|
4c46c26c75 |
feat(slack): add format primitives subpath (#547)
## summary adds `@chat-adapter/slack/format` for lightweight Slack formatting helpers the new subpath exposes runtime-free primitives for Slack text objects, mrkdwn escaping, mentions, links, dates, and basic mrkdwn normalization without importing the full Slack adapter, Chat SDK runtime, Slack SDK, Socket Mode, or shared adapter package this keeps the normal `@chat-adapter/slack` adapter path unchanged while giving lower-level runtimes a small typed API for Slack formatting correctness |
||
|
|
b332a03d59 |
feat(slack): add webhook primitives subpath (#538)
## summary adds a lightweight `@chat-adapter/slack/webhook` subpath for lower-level Slack webhook handling without pulling in the full Slack adapter runtime this exposes primitives for verifying Slack requests, reading signed webhook bodies, parsing Events API callbacks, slash commands, and interactive payloads, and returning provider-native continuation data for message-like payloads this gives framework and infrastructure integrations a small Slack-owned surface they can use directly while keeping `chat`, Slack SDK clients, adapter state, dedupe, locks, and subscriptions out of the primitive path |
||
|
|
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 - |
||
|
|
9d7891b2f5 |
fix(release): prevent accidental major bumps (#520)
## summary fixes the release plan so peer-dependent packages only trigger major bumps when the next dependency version falls outside their supported range this keeps the current release on `4.29.0` instead of accidentally bumping the fixed `chat` and `@chat-adapter/*` group to `5.0.0` also changes `@chat-adapter/tests` to use a real `chat` peer range while keeping `workspace:*` for local development |
||
|
|
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 |
||
|
|
716e934aa2 |
feat(web-adapter): first class support for Vue and Svelte (#498)
## Summary <!-- What does this PR do? --> ## Test plan <!-- How did you verify the changes? --> ## Checklist - [ ] All commits are signed and verified - [ ] `pnpm validate` passes - [ ] Changeset added (or N/A — see [CONTRIBUTING.md](./CONTRIBUTING.md)) - [ ] Documentation updated (or N/A) --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
2f108bd4b3 |
feat: rename adapter.client to adapter.octokit / adapter.linearClient / adapter.webClient (#478)
## Summary
Rename the public native client getter on the GitHub, Linear, and Slack
adapters so it matches the underlying SDK class instead of the generic
`.client`. The previous `.client` getter is preserved as a `@deprecated`
alias on all three adapters, so existing code keeps working without
changes.
- `bot.getAdapter("github").client` is now
`bot.getAdapter("github").octokit` (returns `Octokit`)
- `bot.getAdapter("linear").client` is now
`bot.getAdapter("linear").linearClient` (returns `LinearClient` from
`@linear/sdk`)
- `bot.getAdapter("slack").client` is now
`bot.getAdapter("slack").webClient` (returns `WebClient` from
`@slack/web-api`)
Each new getter has TSDoc covering single- vs multi-tenant resolution
rules and when calling outside a webhook handler throws. Focused unit
tests assert that the new getter returns the underlying SDK instance,
that single-tenant calls return the same instance, that the deprecated
`.client` alias points at the new getter, that multi-tenant mode without
webhook context throws on both getters, and that inside a webhook
context the getter resolves to the per-tenant client.
Commits are split for review:
1. `feat(adapter-github): rename adapter.client to adapter.octokit`
2. `feat(adapter-linear): rename adapter.client to adapter.linearClient`
3. `docs: use .octokit / .linearClient in chat-sdk.dev examples`
4. `chore: changeset for adapter native client getter rename`
5. `fix: hoist regex literals in new client-getter tests to module
scope`
6. `feat(adapter-slack): rename adapter.client to adapter.webClient`
7. `docs: include slack .webClient in chat-sdk.dev examples`
8. `chore: include adapter-slack in native client getter rename
changeset`
9. `test(adapter-github,adapter-linear): cover with-context resolution
on the new client getters`
---------
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
|
||
|
|
b9b17cd37d |
fix(discord): handle interactions in gateway-only mode (#490)
## summary fixes #343 fix Discord gateway-only mode so `InteractionCreate` events are handled directly when no interactions endpoint is configured slash commands now defer the gateway interaction and route through the existing slash command handler path, and button interactions defer updates before routing through the existing action handler path also clarifies in the Discord README that Discord sends interactions through either the Gateway or an Interactions Endpoint URL, not both |
||
|
|
add27309fb | feat(telegram): support typed attachment uploads (#485) | ||
|
|
fdebde7988 |
Reapply "feat(slack): expose direct WebClient access via adapter.client" (#472) (#476)
This reverts commit
|
||
|
|
711babe06d |
fix(adapter-telegram): handle video_note (round video messages) in extractAttachments (#457)
* fix(adapter-telegram): handle video_note in extractAttachments Round video messages (video_note) were silently dropped because extractAttachments had no branch for them. Adds the video_note field to TelegramMessage and extracts it as a "video" attachment with width/height set to the clip's length. Fixes #456 * test(adapter-telegram): add video_note attachment extraction test |
||
|
|
06fb8e59ef |
chore: set up konsistent with basic initial config for package, adapter, and state adapter conventions (#466)
* set up konsistent with basic initial config * add konsistent to CI * fix konsistent.json formatting * fix(gchat): move GoogleChatAdapterConfig to ./types for konsistent * fix(slack): move SlackAdapterConfig to ./types and drop Partial wrapper from createSlackAdapter * fix(messenger): name createMessengerAdapter parameter MessengerAdapterConfig * fix(web): rename WebAdapterOptions to WebAdapterConfig and import Adapter type in index.ts * fix(whatsapp): align WhatsAppAdapterConfig and creator with konsistent + map kebab to PascalCase * fix(state-memory): add MemoryStateAdapterOptions type for konsistent * fix(state-ioredis): unify URL and client options under IoRedisStateAdapterOptions * fix(state-redis): unify URL and client options under RedisStateAdapterOptions * fix(state-pg): unify URL and client options under PostgresStateAdapterOptions * chore: changeset for konsistent convention alignment * chore: drop CHANGELOG.md from konsistent's required files list CHANGELOG.md is generated automatically by changesets on each release — it's never hand-authored and doesn't exist for a package until its first release lands. Requiring it as a convention check makes CI fail indefinitely for any newly added package, with no honest fix available (an empty placeholder is just noise that gets overwritten on first release). * docs: document konsistent and package shape conventions * fix(web): use WebAdapterConfig in WebAdapter field types after main merge The merge of main into konsistent brought in PR #475's `protected` field modifiers on top of the WebAdapterOptions → WebAdapterConfig rename, leaving two stale references to the (un-imported) old name. Switch them to WebAdapterConfig and update a stale JSDoc reference in als.ts to match. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> Co-authored-by: Ben Sabic <27636870+bensabic@users.noreply.github.com> |
||
|
|
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 |
||
|
|
3347bfbcda |
chore: remove .vercel.approvers files (#483)
Code ownership is already governed by .github/CODEOWNERS. Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
2ffed48bea |
feat: make adapter internals protected to enable subclassing (#475)
* chore: changed class function access to protected * chore: format * chore: added changeset * chore(changeset): drop unchanged shared package, expand description * refactor(adapters): keep internal state private, only protected for extension surface Narrow scope of #475: caches, polling/runtime state, and one-shot warning flags stay private. Methods and shared helpers (logger, formatConverter, chat, config) remain protected as the documented extension surface. Also fixes a typecheck failure where gchat's oauth2Client (now private) no longer requires a portable type for the emitted .d.ts. * test(adapters): add subclass extensibility tests Each adapter now has a compile-time test that subclasses can access the documented protected surface. If any of these members revert to private, the test file fails to type-check. * style: apply ultracite formatting to subclass tests * style(slack): mark static cache TTL constants as readonly These three protected static cache TTLs are configuration constants, not mutable state. Marking them readonly prevents subclasses (the new extension surface from this PR) from mutating values shared across every instance in-process. * test(adapters): document intent of subclass extensibility tests Mirrors the inline comment from the Telegram subclass test across the other nine adapter tests so future readers immediately understand these blocks are type-only sentinels — they fail at typecheck (not vitest) if a member reverts to private. * docs(adapters): document subclassing for adapter customization Adds a "Customizing an adapter via subclassing" section to the Adapters page that walks through extending an official adapter to override a protected hook (using the issue #433 Telegram processUpdate scenario as the canonical example) and clarifies that private members are intentionally off-limits. * refactor(linear): expose accessTokenExpiry to subclasses The surrounding refreshClientCredentialsToken and ensureValidToken methods are now protected, but accessTokenExpiry was kept private — meaning a subclass overriding either method couldn't read or update the expiry without calling super. Flipping it to protected lets subclasses fully reimplement the token-refresh flow. * chore(changeset): bump adapters from patch to minor This PR adds a new, additive capability — subclassing official adapters to override protected hooks. Per CONTRIBUTING.md, additive backward-compatible features warrant a minor bump rather than a patch. * docs(adapters): clarify subclassing surface stability Correct the parenthetical describing what stays `private` (credentials are now `protected`) and add a callout warning that the `protected` extension surface is intentionally broader than the public API but not yet fully stable, so subclass authors know to pin versions and prefer overriding the smallest hook. --------- 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>
|
||
|
|
c46fdb6b34 |
[slack] add support for external installation providers for bot token management (#467)
* [slack] add support for external installation providers for bot token management * changeset * fix(slack): correct stale 'Connex' comment to 'Vercel Connect' * docs(slack): expand changeset with provider details and Enterprise Grid notes * docs(slack): document installationProvider and Enterprise Grid lookup keys * test(slack): cover installationProvider for interactive payloads on both install types * fix(slack): route rehydrateAttachment through installationProvider --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
0f0c203165 |
fix(slack): prefer webhookVerifier over signingSecret (#468)
* fix(slack): prefer webhookVerifier over signingSecret and SLACK_SIGNING_SECRET
When `webhookVerifier` is configured, ignore both `config.signingSecret`
and the `SLACK_SIGNING_SECRET` env var. Previously a configured
`signingSecret` (or env var) would shadow the verifier the caller wired
up, which is the opposite of the intended override behavior.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs(slack): update README to match new webhookVerifier precedence
Mirror the JSDoc/changeset wording: webhookVerifier wins over both
signingSecret and SLACK_SIGNING_SECRET. The previous note still claimed
signingSecret won, contradicting the behavior fixed in
|
||
|
|
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> |