6 Commits

Author SHA1 Message Date
josh 4ac0455134 feat(chat): add message update and delete lifecycle callbacks (#788)
## summary

adds `onMessageUpdated` and `onMessageDeleted`, so a bot can react when
a message is edited or removed. Slack dispatches both today; other
adapters can opt in later

supersedes #549, which was verified there against real Slack webhooks.
reopened from a branch in this repo with the original commits preserved
and signed

```typescript
bot.onMessageUpdated(async (thread, message, previousMessage) => {
  await mirror.update(message.id, message.text);
});

bot.onMessageDeleted(async (event) => {
  await mirror.remove(event.messageId);
});
```

both are lifecycle events: they never route through `onNewMessage`,
`onNewMention`, or `onSubscribedMessage`, and the concurrency strategies
do not apply

### notes

- **the bot's own edits are filtered.** slack sends a `message_changed`
for every `chat.update`, and post-and-edit streaming calls it once per
delta, so without this a single streamed reply would call the handler
back repeatedly on its own message
- **`previousMessage` is forwarded on edits.** slack sends the pre-edit
message and it was being dropped. an edit handler usually needs the
before to know what changed, so it is the optional third argument
- **the two shapes differ deliberately.** an edit carries a full
replacement message, so it gets `(thread, message, previousMessage?)`. a
delete has no message, only the id of what was removed, so it gets an
event. use `chat.thread(event.threadId)` when a delete handler needs one
- **one thread id helper** now serves message, edit, and delete, so an
edit cannot resolve to a different thread than the message it edits

## test plan

core:

- an edit dispatches to `onMessageUpdated` and not to the normal message
handlers
- the handler receives the pre-edit message as its third argument
- the bot's own edits are skipped
- a delete dispatches with normalized event data
- both run inside the active conversation, so read tools built in these
handlers stay scoped

slack:

- `message_changed` dispatches as an update, `message_deleted` as a
delete
- `previous_message` is forwarded, and left undefined when slack omits
it
- hidden unfurl updates stay ignored, hidden real edits still dispatch
- message, edit, and delete resolve to one thread id in a flat DM and in
a threaded `agent_view` DM

verified against a real slack workspace over socket mode: editing and
deleting a DM both routed to the same thread id as the original message

---------

Co-authored-by: Miłosz Lenczewski <m.lenczewski@tidio.net>
2026-08-05 13:22:54 +01:00
Ben Sabic 6750d59e72 feat(github): add Vercel Connect support (#650)
Adds Vercel Connect support to the GitHub adapter:

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

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

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

## Companion

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

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

---------

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-03 01:38:51 +10:00
Ben Sabic 9921dcd1c4 docs(seo): improve npm metadata, README discoverability, and structured data (#587)
Improves Chat SDK discoverability across npm, READMEs, and the docs site
for search engines and AI coding agents.

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

---------

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

**Docs site**

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

**Adapter packages**

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

**Resources registry**

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

**Drive-by fixes**

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

**Tooling / CI**

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

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-05-29 11:41:23 +10:00
Ben Sabic 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>
2026-05-13 08:35:31 +10:00
Ben Sabic 79227ae991 docs: refresh adapter pages with hand-authored MDX (#474)
## Summary

Refreshes the adapter docs end-to-end so every adapter — official,
vendor-official, and community — now ships hand-authored MDX, lives
under a clean URL structure, and renders on a polished
sidebar/right-rail layout dedicated to `/adapters` (the shared `/docs`
chrome is untouched).

```mermaid
flowchart LR
  subgraph Before
    direction TB
    OB[official] --> CB[community<br/>incl. 5 vendor pages]
  end
  subgraph After
    direction TB
    OA[official] --> VA[vendor-official<br/>5 pages] --> CA[community]
  end
  Before -.-> After
```

### Content & routing

- **New `/adapters/vendor-official/<slug>` route** for vendor-maintained
adapters (Beeper Matrix, Photon iMessage, Liveblocks, Resend, Zernio).
Sidebar gets a third labelled group ("Vendor-Official Adapters") between
Official and Community, with a top divider matching the existing
Community treatment.
- **All 13 vendor-official + community adapters migrated** from runtime
README fetching to hand-authored MDX with rich `features:` matrices and
full body content (install, quick start, configuration, auth,
gateway/streaming, troubleshooting). README fetch stays as a fallback
for any future community adapter that hasn't been migrated yet, gated by
a new `mdxBody: true` frontmatter flag.
- **Messenger filter pages removed** (`/adapters/for/<messenger>` + the
"Browse by messenger" chip row on `/adapters`). Existing URLs
308-redirect to `/adapters`.
- **Permanent redirects** from
`/adapters/community/{matrix,imessage,resend,zernio,liveblocks}` to
their new `/adapters/vendor-official/...` paths.
- **Fixed** `/docs/adapters` and `/docs/state` so the bare pages are
accessible again — the previous catch-all redirect (`:slug*`) was
swallowing them. Switched to `:slug+` so subpath URLs still 308 while
the bare pages render.

### Visual polish

- **Adapter-only sidebar variant** (`AdaptersDocsLayout` +
`AdaptersSidebar`) with uppercase eyebrow separators, tighter rows, and
a thin themed scrollbar utility class. The shared `/docs` sidebar is
untouched.
- **Restyled `AdapterHero`**: drops the badges row + packageName, sits
the title inline with the logo, larger 17 px tagline, horizontal divider
beneath the block.
- **Restyled `PackageInstall`** as a tabbed dark single-line snippet
with a `$` prompt prefix and a copy button — replaces the previous
multi-line `CodeBlock` layout.
- **New "Deploy your chat app on Vercel" upsell card** (`<Upsell />`)
replaces the old `EditSource / ScrollTop / Feedback / CopyPage` footer
cluster on every adapter detail page.
- **Listing & messenger pages**: align the H1 to a tighter `text-4xl
sm:text-[44px]`, and the section headers to `text-base font-medium
tracking-tight` with a one-line muted lede.

### Tooling & tests

- Added `mdxBody: true` opt-in to the adapter frontmatter schema
(`source.config.ts`), and updated both detail-page handlers
(`community/[slug]` and the new `vendor-official/[slug]`) to render the
MDX body when present, falling back to README fetch otherwise.
- Refactored both detail-page handlers to flatten the body-render
branches into a `renderBody()` helper, removing the nested ternaries
that were tripping `lint/style/noNestedTernary`.
- New test file
[`packages/integration-tests/src/docs-adapters.test.ts`](https://github.com/vercel/chat/blob/docs/refresh-adapters/packages/integration-tests/src/docs-adapters.test.ts)
— **220 new assertions** covering:
- Adapter MDX frontmatter completeness, slug ↔ filename consistency, and
`type ∈ {platform, state}`.
- Vendor-official invariants: exactly the expected slugs,
`vendorOfficial: true`, `community: true`, `author`, `mdxBody: true`,
`<FeatureSupport />` rendered.
- Community invariants: `community: true` (never vendor-official),
`mdxBody: true`, `<FeatureSupport />`.
- Official invariants: never flagged, `packageName` always under
`@chat-adapter/*`.
- `adapters.json` ↔ MDX sync on `packageName` / `type` / `community` /
`vendorOfficial`.
- Extended `VALID_DOC_PACKAGES` so `docs-content.test.ts` accepts the
new vendor-official + community packages, plus `@chat-adapter/web`,
`@chat-adapter/web/react`, and `@chat-adapter/messenger`.

### Per-package AGENTS.md

- Added `AGENTS.md` to every official adapter and state adapter (14
packages), each tailored to that adapter's surface — overview, directory
layout, build/test commands, public exports, thread ID format, webhook
flow, authentication, format conversion, cards/streaming, platform
quirks, testing approach, coding conventions, and release rules.
- Added a one-line `CLAUDE.md` (`@AGENTS.md`) beside each so Claude Code
picks up the same instructions through its built-in resolver — same
convention as the root.

### Web adapter copy

- Cleaned up the Web adapter tagline (removed inline backticks) and
dropped the now-redundant "v1 scope" section from the body.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-05-12 16:01:19 +10:00