Commit Graph

248 Commits

Author SHA1 Message Date
Shkumbin Hasani 2338a66544 feat(whatsapp): add sendTemplate for pre-approved template messages (#588)
Closes #585

## Summary

Adds `sendTemplate()` to the WhatsApp adapter for sending pre-approved
[Message
Templates](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-message-templates)
— the only message type the Cloud API accepts outside the 24-hour
customer service window, and therefore required for business-initiated
conversations (notifications, reminders, re-engagement).

The inbound half already existed (`handleButtonResponse` dispatches
template quick-reply taps to `onAction` handlers); this completes the
outbound side. Notably, the package's `AGENTS.md` already documented
`sendTemplate` and `WhatsAppTemplateMessage` as part of the public
surface — this PR implements exactly that documented API.

## Changes

- **`sendTemplate(threadId, template)`** on `WhatsAppAdapter` — posts a
`type: "template"` payload through the existing `graphApiRequest` path
and returns a `RawMessage`, mirroring
`sendInteractiveMessage`/`sendSingleTextMessage`
- **Types**: `WhatsAppTemplateMessage`, `WhatsAppTemplateComponent`,
`WhatsAppTemplateParameter`, `WhatsAppTemplateButtonParameter` in
`types.ts`, modeled on the Cloud API template object (header/body/button
components; text, currency, date_time, and media parameters),
re-exported from the package entry point
- Templates are kept out of the `PostableMessage`/mdast pipeline —
they're sent by name + variable components, not free-form markdown, and
the adapter intentionally does not auto-substitute templates for
outbound text posts (per AGENTS.md)
- `openDM()` JSDoc now links to `sendTemplate` for the
business-initiated path

## Docs

- New "Template messages" section in the adapter README and
`apps/docs/content/adapters/official/whatsapp.mdx` with a usage example
- Added "Template messages" row to the README feature table
- Corrected the feature-matrix frontmatter labels: `cardFormat`
"WhatsApp templates" → "Interactive messages" and `fields` "Template
variables" → "Formatted text" — cards render as Cloud API interactive
messages (as the page body already states), and the old labels would now
wrongly imply cards go through the new template API

## Usage

```typescript
const threadId = await adapter.openDM("15551234567");

await adapter.sendTemplate(threadId, {
  name: "appointment_reminder",
  language: "en",
  components: [
    {
      type: "body",
      parameters: [{ type: "text", text: "Tomorrow at 2pm" }],
    },
  ],
});
```

## Testing

- 5 new tests in `index.test.ts` following the existing `fetch`-spy
pattern: payload shape (name/language/`to`), component pass-through
(body + URL button), empty-components omission, missing-message-ID
error, and invalid thread ID rejection
- `pnpm validate` (knip, check, typecheck, test, build) passes — 117/117
adapter tests green

Includes a `minor` changeset for `@chat-adapter/whatsapp`.

---------

Signed-off-by: dancer <josh@afterima.ge>
Co-authored-by: dancer <josh@afterima.ge>
2026-07-13 21:50:06 +10:00
Ben Sabic 0f743c9b33 feat(slack): support native Slack agents (#698)
Builds on the Agent messaging experience support from #684 with a
declarative config layer for building Slack agents, plus hardening for
native streaming.

Everything is configured on `createSlackAdapter()` — no per-event wiring
required.

## Slack adapter (`@chat-adapter/slack`)

### `suggestedPrompts`

Static payload or per-thread resolver, applied automatically when an
assistant/agent thread opens:

- `assistant_thread_started` (legacy `assistant_view`), with the
thread's `thread_ts`
- Messages-tab `app_home_opened` (with `agentView` enabled), without
`thread_ts` so prompts pin atop the agent conversation

The resolver receives the thread context (`channelId`, `userId`, legacy
`threadTs`/`teamId`/`enterpriseId`, and normalized active-view
`entities` under `agentView`); returning `null`/`undefined` skips the
thread. Prompts beyond Slack's 4-prompt limit are dropped with a
warning. Resolver/API failures are logged, never a webhook 500. Applied
via `waitUntil` inside the request scope so multi-workspace token
context propagates.

### `loadingMessages`

Default rotating status strings for the assistant thinking indicator,
used by `startTyping` and `setAssistantStatus` when no explicit
status/messages are passed.

### `nativeStreaming` + automatic post-and-edit fallback

- New `nativeStreaming` config (default `true`). Set `false` on Slack
flavours without the `chat.startStream` family (e.g., GovSlack) to
always stream via post-and-edit.
- If the workspace rejects the **first** native streaming call,
`stream()` falls back to throttled post-and-edit mid-stream instead of
failing the reply; already-consumed text is preserved (it lives in the
renderer). Permanent platform errors (`unknown_method`,
`method_deprecated`, `feature_not_enabled`) latch native streaming off
for subsequent streams on the adapter instance; transient errors don't
latch.
- Structured chunks (`task_update`/`plan_update`) are skipped in
fallback mode; failures after native content has rendered still
propagate (mixing surfaces would duplicate output).
- Also updates the stale streaming description in the package AGENTS.md
(the adapter now streams via
`chat.startStream`/`appendStream`/`stopStream`, not `chat.update`).

### `feedbackButtons`

Appends Slack's native thumbs up/down (a `context_actions` block with a
`feedback_buttons` element) to every streamed reply on
`chat.stopStream`, after any `StreamingPlan` `endWith` blocks. Pass
`true` for defaults or an options object (`actionId`, labels, values).
Clicks dispatch through the regular `block_actions` flow to
`bot.onAction` with a positive/negative value — no new plumbing. Exports
`buildFeedbackButtonsBlock(options?)` for attaching the same block to
non-streamed messages.

New exported types: `SlackFeedbackButtonsOptions`,
`SlackSuggestedPrompt`, `SlackSuggestedPrompts`,
`SlackSuggestedPromptsContext`, `SlackSuggestedPromptsOptions`.

## Docs

- Configuration table rows for `agentView`, `suggestedPrompts`,
`loadingMessages`, `nativeStreaming`, `feedbackButtons`.
- New "Native streaming" and "Feedback buttons" sections plus
declarative suggested-prompts examples.
- All agent content grouped under a new **Advanced → Agents** subsection
(Agent messaging experience → Assistants API → Native streaming →
Feedback buttons). Heading titles unchanged, so existing anchors keep
resolving.
- TypeTable descriptions rewritten as plain text (they don't render
markdown).

## Example app (`examples/nextjs-chat`)

- `SLACK_AGENT_OPTIONS` shared across both Slack adapter branches:
active-view-aware `suggestedPrompts` resolver, `loadingMessages`,
`feedbackButtons` with an `ai_feedback` acknowledgment handler.
- Env toggles: `SLACK_AGENT_VIEW` (agent_view mode) and
`SLACK_NATIVE_STREAMING` (compare native vs post-and-edit).
- Commented `agent_view` blocks in `slack-manifest.yml` (feature block,
`assistant:write` scope, agent events) with a note that the switch is
irreversible.
- AI flows call `startTyping()` without an explicit status so configured
loading messages rotate.

## Test plan

- `pnpm validate` and `pnpm konsistent` pass.
- 26 new unit tests: suggested prompts
(static/resolver/agent_view/truncation/error paths), loading message
defaults, native streaming fallback (opt-out, mid-stream fallback,
permanent-error latching, transient non-latching, propagation after
native render, structured-chunk skipping), feedback buttons (block
shape, custom options, ordering after `endWith`, webhook round-trip of a
click).
- Each adapter commit was built and verified independently (typecheck +
full suite green at every step) for bisectability.
- Verified manually against a live `agent_view` workspace: prompts
pinned on thread open, loading messages rotating in the thinking
indicator, native token-by-token streaming in DMs and channel threads,
post-and-edit fallback via the opt-out flag, and feedback clicks
dispatching to `onAction`.

## Notes

- One changeset covers the three adapter features (`minor` for
`@chat-adapter/slack`).
- Known follow-up (not in this PR): under `agentView`, a subscribed
conversation-scoped DM thread (the #684 openDM bridge) routes DM
messages to a thread without `thread_ts`, which silently pins DMs to
post-and-edit. Worth deciding whether the bridge should keep per-message
threading for replies or log loudly when it redirects.

## Screenshots

| Suggested Prompts | Feedback Buttons |
| --- | --- |
| <img width="647" height="347" alt="CleanShot 2026-07-13 at 13 26 27"
src="https://github.com/user-attachments/assets/4c89932b-ed19-4b4a-83ae-d3d022d0c120"
/> | <img width="825" height="276" alt="CleanShot 2026-07-13 at 13 28
23"
src="https://github.com/user-attachments/assets/6bdf6979-5209-4bed-b0bc-dfbee7165455"
/> |

---------

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-13 12:27:25 +01:00
Dima Grossman 8bd8a57518 feat(whatsapp): send outbound files and attachments via Cloud API (#537)
Implement media upload, MIME mapping, caption fallbacks, and card+file
sequencing.

## Summary

The WhatsApp adapter previously ignored `files` and `attachments` on
outbound `post()` calls (only text and interactive cards were sent).
This PR implements full outbound media support via the [WhatsApp Cloud
API](https://developers.facebook.com/docs/whatsapp/cloud-api/reference/media):

1. **Binary upload** — `POST /{phoneNumberId}/media` → `media_id` →
typed media message
2. **Link passthrough** — HTTPS `Attachment.url` sent directly (no
upload)
3. **Multi-file** — one WhatsApp message per file/attachment, sent
sequentially
4. **Captions** — markdown or card fallback text on the first media
message when supported
5. **Card + files** — media first, then interactive buttons (when
applicable)

**Packages:** `@chat-adapter/whatsapp` (minor)

---

## Supported inputs

| Input | Description |
|-------|-------------|
| `files: FileUpload[]` | Binary buffers/blobs with `filename` and
optional `mimeType`. Always uploaded via `/media`. |
| `attachments: Attachment[]` | Typed media (`image` \| `file` \|
`video` \| `audio`). Binary via `data` / `fetchData`, or HTTPS URL-only
via `url`. |

Both can be combined on `{ markdown }`, `{ raw }`, `{ ast }`, or `{ card
}` postables. `files` are processed first, then `attachments`.

### Examples

```typescript
// PDF with caption
await thread.post({
  markdown: "Here's the report",
  files: [{ data: pdfBuffer, filename: "report.pdf", mimeType: "application/pdf" }],
});

// Multiple files (N sequential messages)
await thread.post({
  markdown: "Two files attached",
  files: [
    { data: buf1, filename: "a.pdf", mimeType: "application/pdf" },
    { data: buf2, filename: "b.png", mimeType: "image/png" },
  ],
});

// Card with buttons + image file
await thread.post({
  card: approvalCard,
  files: [{ data: proofBuffer, filename: "proof.png", mimeType: "image/png" }],
});

// Files only (no text)
await thread.post({
  markdown: "",
  files: [{ data: buffer, filename: "data.xlsx" }],
});
```

---

## Behavior reference

### Message flow (with media)

```
postMessage()
  ├─ files or attachments present?
  │    YES → postMessageWithMedia()
  │         ├─ Resolve text (card fallback OR markdown/raw/ast)
  │         ├─ Caption strategy (see below)
  │         ├─ For each file/attachment: upload (if binary) → sendMediaMessage()
  │         └─ Card present?
  │              ├─ interactive buttons → sendInteractiveMessage()
  │              └─ text-only card fallback → sendTextMessage() (if caption didn't already send text)
  │
  └─ NO → existing text / card-only path (unchanged)
```

### Multi-file

WhatsApp allows **one media object per API message**. Multiple `files`
or `attachments` in a single `post()` produce **N sequential messages**.
The returned `RawMessage` is the **last** one sent (same convention as
long-text chunking).

| File index | Caption |
|------------|---------|
| First | Markdown / card fallback text (when caption rules allow) |
| 2…N | No caption |

### Caption placement

| Condition | Behavior |
|-----------|----------|
| Text ≤ 1024 chars, first media is not `audio`, media supports captions
| Text sent as **caption** on first media message |
| Text > 1024 chars | **Separate text message first**, then media with
no captions |
| First media is `audio` | **Separate text message first** (audio does
not support captions), then audio |
| No text (`markdown: ""`, files only) | Media only, no caption |

### MIME type → WhatsApp message type

| MIME | WhatsApp `type` |
|------|-----------------|
| `image/jpeg`, `image/png` | `image` |
| Other `image/*` (e.g. GIF, WebP, SVG) | `document` |
| `video/mp4`, `video/3gpp` | `video` |
| `audio/*` | `audio` |
| Everything else (PDF, XLSX, etc.) | `document` |

For `Attachment` without `mimeType`, the adapter uses `attachment.type`
(`image` → image, `file` → document, etc.), then applies MIME rules when
`mimeType` is set.

### Size limits (pre-flight)

Throws `ValidationError` when binary size is known (before upload):

| Type | Limit |
|------|-------|
| `image` | 5 MB |
| `audio` | 16 MB |
| `video` | 16 MB |
| `document` | 100 MB |

URL-only attachments skip size validation unless `attachment.size` is
provided.

### Card + files

When both a **card** and **files/attachments** are present:

1. **Media message(s)** first — caption uses `cardToFallbackText(card)`
on the first media item
2. **Card message** second:
   - Valid reply buttons (1–3) → interactive button message
- Otherwise → text fallback message (skipped if text was already sent as
a leading message)

### Card image vs `files` (important)

| How image is provided | Result |
|-----------------------|--------|
| `<Image>` child or `card.imageUrl` only (no `files`) | **No real image
media.** Card becomes interactive text or text fallback; image URL may
appear as plain text in fallback. |
| `files` / `attachments` + card with buttons | **Real image message** +
separate interactive button message |

To send a photo with buttons, pass the image via `files` or
`attachments`, not only as a card image child.

### Link passthrough

- `Attachment` with **only** `url` (no `data` / `fetchData`) → `{ link:
url }` in the media payload
- URL **must** be `https://`
- No `/media` upload call

### Binary resolution

| Source | Path |
|--------|------|
| `FileUpload.data` | `toBuffer()` → `uploadMedia()` → `{ id }` |
| `Attachment.data` / `fetchData` | Same |
| `Attachment.url` only | `{ link }` passthrough |

---

## Out of scope (follow-ups)

- Stickers (WebP encoding requirements)
- Voice notes (`voice` vs `audio` distinction)
- Media ID caching across posts (30-day expiry)
- Interactive message **image headers** (card-embedded images without
`files`)
- Replay integration test mock extensions for `/media`
- Edit/replace flows that include files

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-13 21:03:07 +10:00
Ben Sabic e6d4fbe8d8 fix(docs): include adapter pages in the search index (#697)
## Summary

Site search on chat-sdk.dev never returned adapter pages — e.g.
searching `imessage` found nothing even though several
`content/adapters/vendor-official/` pages (Sendblue, Linq, Photon, Dial)
mention iMessage prominently.

The cause: the search route only passed the `content/docs` collection
(`geistdocsSource`) to `createSearchRoute`, so the separate
`content/adapters` collection (`adaptersSource`) was never indexed by
Orama.

This adds `adaptersSource` to the route's sources. The adapters loader
already shares the same `i18n` config, and `createSearchRoute` supports
plain fumadocs loaders, so no other changes are needed.

## Testing

Ran the docs dev server and queried `/api/search` directly:

- `?query=imessage` → 46 results across 6 adapter pages (sendblue, linq,
photon, dial, agentphone, blooio), with content-level matches and
highlights
- `?query=sendblue` → returns the Sendblue page
- `?query=webhook` → core `/docs` pages still returned alongside
adapters (existing search unaffected)
- No duplicate result IDs (no per-locale double indexing)

`pnpm check` and `tsc --noEmit` in `apps/docs` are clean. Docs-only
change — no changeset.

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-13 18:58:40 +10:00
josh 4bca64f058 feat(x): support image uploads on posts and DMs (#700)
## summary

the X adapter previously rejected every attachment (`File uploads are
not supported by the X adapter yet`). this adds image upload support:
images passed as `files` or `attachments` are uploaded through X's v2
chunked media endpoints and attached to the resulting post or DM

- uploads via X's current path-based flow: `POST
/2/media/upload/initialize` (JSON) then `/{id}/append` (multipart) then
`/{id}/finalize`, reusing the adapter's managed OAuth token
- attaches `media_ids` on `POST /2/tweets` for posts, and `attachments`
for DMs
- supports png, jpeg, and webp, up to 4 per post, with or without text
- requires the `media.write` OAuth 2.0 scope on the user token

### before / after

- before: posting a message with `files`/`attachments` throws a
`ValidationError`
- after: images upload and attach, and a post can be media-only or media
plus text

<details>
<summary>usage</summary>

```typescript
await thread.post({
  markdown: "France lead the title race",
  files: [{ data: pngBuffer, filename: "odds.png", mimeType: "image/png" }],
});
```

</details>

## test plan

- added unit tests covering the initialize JSON body, the multipart
append path, finalize, `media_ids` on the tweet, DM `attachments`,
media-only posts, MIME inference from filename, the over-limit
rejection, and unsupported-type rejection
- verified live against the X API end to end: uploaded an image and
posted then deleted it through the adapter (the initial command-param
implementation 400'd against the live API, which is what surfaced the
path-based endpoints as required)
- `pnpm --filter @chat-adapter/x build`, tests, `pnpm exec biome check`,
and `pnpm konsistent` all pass

---------

Signed-off-by: dancer <josh@afterima.ge>
2026-07-13 18:57:29 +10:00
ishaksebsib 8d7ccdb11b feat(telegram): support multiple file and attachment uploads (#605)
## Summary

Adds Telegram media group support for posting multiple files and
compatible typed attachments. Multiple `files` are sent as document
media groups, while `attachments` preserve image, video, audio, or file
media types and use Telegram’s native `sendMediaGroup`.

---------

Signed-off-by: dancer <josh@afterima.ge>
Co-authored-by: dancer <josh@afterima.ge>
2026-07-13 08:59:49 +01:00
Dean Mauro 0fdb902980 feat(discord): Components support (#678)
## Summary

#### What

Adds opt-in support for Discord
[Components](https://docs.discord.com/developers/components/reference).

#### Why

Discord Components allows developers more control over the layout of bot
messages by treating text, images, files, and buttons as flexible
components. Instead of the rigid text-above-embeds layout, elements can
be arranged in any order or column.

An extreme example of what's possible with Components:

<img width="728" height="1117" alt="image"
src="https://github.com/user-attachments/assets/fde6ab9c-f635-45fb-b64f-9ddf4c26580f"
/>

#### How

Embeds remain the default behavior. The Discord adapter now supports a
`componentsV2` flag to
When enabled, card messages render with Discord Components v2
containers, sections, text displays, media galleries, separators,
buttons, and string selects, and include the `IS_COMPONENTS_V2` message
flag.

## Test plan

Create a Chat with the Discord adapter. Set `contentFormat:
DiscordContentFormat.ComponentsV2` and create a post that uses sections,
markdown, buttons, etc. Note that
1. All elements should render correctly.
2. Individual sections can contain their own actions.
3. Markdown formatting gets rendered correctly.

```
import { Actions, Button, Card, CardText, Image, LinkButton, Section } from "chat";
import { createDiscordAdapter } from "@chat-adapter/discord";

const discord = createDiscordAdapter({
  contentFormat: DiscordContentFormat.ComponentsV2,
});

await thread.post(
  <Card title="Deployment ready" subtitle="Production build completed">
    <Section>
      <CardText>
        **Version 2.4.0** is ready to promote.

        Review the release notes, then choose an action below.
      </CardText>
      <Image url="https://example.com/deploy-preview.png" alt="Preview" />
    </Section>

    <Actions>
      <Button id="promote" style="primary">
        Promote
      </Button>
      <Button id="rollback" style="danger">
        Roll back
      </Button>
      <LinkButton url="https://example.com/deployments/123">
        View deployment
      </LinkButton>
    </Actions>
  </Card>
);
```

---------

Signed-off-by: dancer <josh@afterima.ge>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: dancer <josh@afterima.ge>
2026-07-13 08:48:48 +01:00
Max 6c2a3918d5 feat(discord): rename thread channels (#693)
## Summary

Add `DiscordAdapter#setThreadTitle()` to rename native Discord thread
channels and document the required **Manage Threads** permission.

Signed-off-by: onmax <maximogarciamtnez@gmail.com>
Signed-off-by: dancer <josh@afterima.ge>
Co-authored-by: dancer <josh@afterima.ge>
2026-07-13 08:17:21 +01:00
Faraz Patankar 5341f909a4 feat(discord): ignore @everyone/@here pings unless respondToGlobalMentions is set (#701)
## Summary

Fixes #699.

In gateway mode, the bot responded to `@everyone`/`@here` announcements.
The legacy gateway listener used discord.js
`message.mentions.has(botId)`, which counts global pings as a mention of
the bot by default.

Global pings are now ignored on both gateway paths by default, and a new
`respondToGlobalMentions` config option (default `false`, per the
issue's suggestion) lets users opt back in:

- **Legacy gateway mode**: mention detection passes `{ ignoreEveryone:
true }` to `mentions.has()`; `@everyone`/`@here` only count via
`message.mentions.everyone` when the option is enabled. Direct mentions,
`mentionRoleIds` role mentions, and replies to the bot are unaffected.
- **Forwarded gateway mode**: added the `mention_everyone` field to
`DiscordGatewayMessageData` and wired it into the same gate (this path
previously ignored global pings silently, with no way to opt in).

## Changes

- `respondToGlobalMentions?: boolean` on `DiscordAdapterConfig` (default
`false`)
- Mention detection updated in both `setupLegacyGatewayHandlers` and
`handleForwardedMessage`
- 5 new tests covering both transports: global pings ignored by default,
honored when opted in, and direct mentions still detected while global
pings are ignored
- Docs: config tables in
`apps/docs/content/adapters/official/discord.mdx` and the adapter README
- Changeset (minor, `@chat-adapter/discord`)

## Testing

- `pnpm validate` passes (knip + check + typecheck + test + build)
- All 249 `@chat-adapter/discord` tests pass, including the 5 new ones

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: Faraz Patankar <farazpatankar@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 08:12:43 +01:00
Ben Sabic 4717a38407 feat(slack): support data table and data visualization blocks (#696)
Adds support for Slack's [data
table](https://docs.slack.dev/reference/block-kit/blocks/data-table-block)
and [data
visualization](https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block)
Block Kit blocks.

- **`chat`**: new cross-platform `ChartElement` + `Chart()` builder (JSX
supported) mirroring Slack's model — pie `segments`, or bar/area/line
`series` against shared `categories`. `Table()` gains optional `caption`
and `pageSize`. Charts degrade to a text table on other platforms via
the shared card fallback (`chartElementToFallbackText`).
- **`@chat-adapter/slack`**: card tables now render as paginated,
sortable `data_table` blocks by default (header-only tables keep the
plain `table` block; oversized tables still fall back to ASCII). Charts
render as `data_visualization` blocks; charts violating Slack
constraints — including the undocumented **max 2 charts per message** —
fall back to a text rendering instead of an API rejection. Same
treatment in the `@chat-adapter/slack/blocks` subpath.
- **`postMessage`** now surfaces Slack's per-block validation messages
on `invalid_blocks` errors (this is how the 2-chart limit was found).
- Example app gets a **Show Charts** button and table pagination on
**Show Table**; docs, feature matrices, and changeset updated.

Verified live against Slack: data table pagination/sorting and both
chart types render natively.

<table>
  <tr>
    <th>Data Table</th>
    <th>Data Charts</th>
  </tr>
  <tr>
<td><img width="979" height="896" alt="CleanShot 2026-07-12 at 23 28 32"
src="https://github.com/user-attachments/assets/3307bd90-9322-452f-86fb-07d46446822d"
/></td>
<td><img width="955" height="879" alt="CleanShot 2026-07-12 at 23 29 02"
src="https://github.com/user-attachments/assets/ddb31a1b-e3fd-457c-a2e6-bde4934afebe"
/></td>
  </tr>
</table>

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-13 07:57:40 +01:00
damianborowy-nexos 1721fa01e7 feat(slack): add Slack Agent messaging experience (agent_view) support (#684)
## Summary

Add support for Slack's Agent messaging experience (`agent_view`), the
2026 replacement for `assistant_view`.

## Core (`chat`)

- New `onAppContextChanged` event carrying the active-view context as a
normalized `AppContextEntity[]` (`channel` / `canvas` / `list` /
`message` / `unknown`) describing what the user is currently viewing.
- `AppHomeOpenedEvent` now carries:
  - the same folded active-view context as optional `entities`
- the opened `tab` (`"home"` / `"messages"`), so handlers can
distinguish a Home-tab open from the DM-open signal under `agent_view`

## Slack adapter (`@chat-adapter/slack`)

- **`agentView` config flag.** Under `agent_view`:
- `app_home_opened` is the DM-open signal and fires regardless of tab
(branch on `event.tab` if you also publish a Home view)
- DM messages are threaded per Slack's new model — each user message is
a thread root (`thread_ts ?? ts`)
- conversation-scoped threads returned by `openDM()` keep working: when
that thread is subscribed, incoming top-level DM messages route to it,
so `onSubscribedMessage` and per-thread state behave the same as in
legacy mode
- **`app_context_changed` routing** with normalized entities. Malformed
payloads degrade gracefully: a missing `context` yields `entities: []`,
and entities with a null/malformed `value` normalize to `kind:
"unknown"` — never a webhook 500.
- **`getAppContext(message)`** helper to read the folded active-view
context off a DM message.
- **`setSuggestedPrompts`** accepts an optional thread reference
(`agent_view` lets prompts sit at the top of the agent conversation).
- **Env auth fallback now keys off auth fields**: `SLACK_BOT_TOKEN` /
`SLACK_CLIENT_ID` / `SLACK_CLIENT_SECRET` fallback is disabled only when
an auth-related field (`botToken`, `clientId`, `clientSecret`,
`installationProvider`) is passed explicitly, rather than by the
presence of any config object. This lets non-auth options compose with
env auth — e.g. `createSlackAdapter({ agentView: true })` picks up env
credentials — and matches the semantics documented in the adapter's
AGENTS.md. *(Behavior change for callers passing non-auth-only configs
while relying on env vars being ignored.)*
- Bumped `@slack/web-api` to `^7.18.0` (adds the optional `thread_ts`
typing for `setSuggestedPrompts`).

## Docs

- New "Agent messaging experience" section on the Slack adapter page
(config, manifest snippet, threading model, openDM bridge).
- "Handling active-view context" section in handling-events, plus
`tab`/`entities` rows on the app-home event table.
- Callout: under `agent_view`, bot replies are threaded per user
message, so `conversations.history` only returns the user's side of a DM
— build AI conversation history from transcripts instead of channel
history.

## Example app (`examples/nextjs-chat`)

- Plain `SLACK_BOT_TOKEN` adapter branch (previously Slack was only
wired via Vercel Connect).
- DM AI history built from transcripts instead of channel history (see
docs callout above); assistant turns persisted.
- The `dm me` trigger regex now matches mention text, which carries the
`@bot` prefix on Slack.

## Test plan

- `pnpm validate` and `pnpm konsistent` pass.
- Unit tests cover the new events, entity normalization (including
malformed payloads), `agent_view` DM threading, the openDM subscription
bridge, `tab` passthrough, `setSuggestedPrompts` thread handling, and
env-fallback behavior; an integration replay test exercises the full
webhook flow.
- Verified manually against a live `agent_view` workspace:
`onAppContextChanged` entities, folded context on `app_home_opened` and
DM messages, `tab` values for both tabs, per-message DM threading, the
openDM subscription bridge, and signed malformed-payload replays (all
return 200).
- Legacy regression pass with `agentView` off: conversation-scoped DM
threading, Home-tab-only `app_home_opened`, mention flow unchanged.

### Slack references

- Agent messaging experience:
https://docs.slack.dev/changelog/2026/06/30/agent-messages-tab/
- Active-view context:
https://docs.slack.dev/changelog/2026/07/02/app-context/

## Checklist

- [x] All commits are signed and verified
- [x] All commits are signed off for the DCO (`git commit -s`)
- [x] `pnpm validate` passes
- [x] Changeset added
- [x] Documentation updated

---------

Signed-off-by: Damian Borowy <301205838+damianborowy-nexos@users.noreply.github.com>
Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-12 19:35:28 +10:00
Rich Haines 1dff4515e2 refactor(docs): migrate chat-sdk.dev to @vercel/geistdocs (#686)
## Summary

Migrates `apps/docs` from locally-copied geistdocs runtime code to the
published
[`@vercel/geistdocs`](https://www.npmjs.com/package/@vercel/geistdocs)
package (1.8.2), following the official [migration
guide](https://preview.geistdocs.com/docs/migration). Net **−8,400
lines**.

### Package-backed now

- Docs page + layouts: `createDocsPage`, `GeistdocsDocsLayout`,
`GeistdocsHomeLayout` (JSON-LD + sr-only markdown hints preserved via
`renderTop`)
- Navbar (OSS product switcher via `navbarOssProducts`), footer,
provider, search dialog, page actions (edit source, feedback, copy page,
Ask AI, open-in-chat, scroll top)
- `/api/search` → `createSearchRoute`, `/api/chat` → `createChatRoute`
(AI SDK v6; AI Gateway default, optional `GEISTDOCS_CHAT_PROXY_URL`)
- `llms.mdx` → `createDocsMarkdownRoute`, `sitemap.md` →
`createSitemapMarkdownRoute` (now includes an **Adapters** section)
- **New**: `/agents.md` via `createAgentsRoute`, backed by a new `agent`
readiness config
- `proxy.ts` → `createProxy` with explicit `markdownRoutes` for `/docs`
→ `llms.mdx` and `/adapters` → `adapters.mdx` (adds AI-agent UA
rewrites)
- CSS: `@vercel/geistdocs/styles.css` + slim local overrides (shadcn
tokens for remaining `components/ui`, body tint, prose inline code,
`#nd-*` tweaks); code blocks now use the geist Shiki theme
- Icons/logos from `@vercel/geistdocs/assets/*`; feedback via the
package action (same geistdocs.com endpoint + `siteId`)

### Kept local by design

- Curated `/llms.txt` index + `/llms-full.txt` corpus — the published
`AGENTS.md`/SKILL.md artifacts and integration tests reference this
exact contract
- The adapters section (README fetching, OG images, JSON-LD, feature
matrices, `adapters.mdx` markdown route) — now rendered inside the
package docs layout
- RSS and OG image routes (app-owned per the migration guide)
- Skipped `/.well-known/mcp.json`: no MCP servers configured, and the
proxy matcher must keep excluding `.well-known` for the served
agent-skills files

### Cleanup

- Deleted local copies: `components/geistdocs/*` chrome,
`components/ai-elements/*`, chat hooks/persistence, feedback server
actions, unused shadcn primitives, geistcn logo/icon fallbacks covered
by package assets
- Removed 13 now-unused deps (`ai@5`, `@ai-sdk/react@2`, `dexie`,
`jotai`, `cmdk`, `vaul`, `mermaid`, `nanoid`, `react-player`,
`use-stick-to-bottom`, `@orama/tokenizers`, `dexie-react-hooks`,
`next-themes`)
- Updated `docs-llms.test.ts` proxy assertions to the `createProxy`
markdown-route shape

### Behavior changes to be aware of

- Code blocks use the geist Shiki theme instead of GitHub light/dark
- Ask AI history is no longer persisted in IndexedDB (package owns the
panel)
- Adapters sidebar uses the standard geistdocs tree rendering instead of
the bespoke grouped sidebar
- Per-page markdown output appends the standard geistdocs footer links
(`/sitemap.md`, `/llms.txt`, `/agents.md`)

## Test plan

- `pnpm validate` green (knip + check + typecheck + test + build)
- Smoke-tested against `next build && next start`: `/`, `/docs`,
`/adapters`, `/agents.md`, `/llms.txt`, `/llms-full.txt`, `/sitemap.md`,
page-level `.md` URLs for both docs and adapters, `Accept:
text/markdown` negotiation, search API, JSON-LD, sr-only markdown hints,
edit-source URLs (`apps/docs/content/docs/{path}`), OSS navbar, page
actions
- Verified compiled CSS chunks contain the home grid, Shiki palette, and
geist utilities (note: stale turbopack dev caches from before this
change can serve incomplete CSS — `rm -rf apps/docs/.next` fixes it)

## Checklist

- [x] All commits are signed and verified
- [x] All commits are signed off for the DCO (`git commit -s`)
- [x] `pnpm validate` passes
- [x] Changeset added (or N/A — docs app + tests only, no package
behavior change)
- [x] Documentation updated (or N/A)

---------

Signed-off-by: molebox <rich@vercel.com>
2026-07-09 15:29:47 +02:00
josh b3123815fa docs: use xai/grok-4.5 across docs, guides, and examples (#687)
## summary

- swap chat model strings to `xai/grok-4.5` across the docs site, the
shipped guides, and the example bots, so the docs lead with the latest
model
- apps/docs: ai overview, ai-sdk-tools, and streaming pages, the two
landing-page code samples, and the live chat demo route
(`app/api/chat/route.ts`, previously `openai/gpt-4.1-mini`)
- packages/chat/resources/guides: the seven guides that use a chat model
(slack connect, slack + ai sdk, liveblocks, vercel blob, github code
review, daily digest, ai gateway)
- examples: nextjs-chat and nuxt-chat bots
- deliberately left non-chat model strings as they were, since grok-4.5
cannot fill those roles: the `openai/text-embedding-3-small` embedding
model and the `openai/gpt-4o-mini` reranker
- in the ai gateway guide, grok-4.5 is now the primary model but the
fallback list stays cross-provider (`anthropic/claude-opus-4.8`,
`google/gemini-3.1-pro-preview`) so the failover example still
demonstrates real cross-provider fallback
- also fixed a pre-existing prose/code mismatch in that guide, the
fallback prose said `claude-opus-4.7` while the code listed `4.8`, now
aligned to `4.8`

---------

Signed-off-by: dancer <josh@afterima.ge>
2026-07-09 13:35:36 +10:00
Ben Sabic 8ae68f749d feat(docs): add X logo to homepage and balance mobile logo wrap (#683)
## What

- Add the new **X** adapter logo to the homepage supported-platforms
grid, placed after Messenger.
- Cap the grid width on mobile (`max-w-64`, reset with `sm:max-w-none`)
so the logos wrap **4 / 4 / 3** instead of orphaning a single logo
(Telegram) on its own line.

## Why

We now ship an `@chat-adapter/x` adapter, so X belongs in the homepage
lineup. With 11 logos, the previous flex-wrap fit 5 per row on phones,
producing a lonely 5 / 5 / 1 break. Constraining the container forces
even, centered rows down to 320px-wide screens.

## Notes

- The `x` logo SVG and the `/adapters/official/x` page already exist
(added in a prior change from `main`); this only wires X into the
homepage grid.
- Docs-only change — no changeset required.

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-08 11:50:40 +10:00
josh ef2542c5fd feat(x): add X (Twitter) adapter (#682)
## summary

new `@chat-adapter/x` adapter for X (Twitter), built on the X API v2 and
the X Activity API. write bot logic once and reply to mentions, hold DM
conversations, post from the account, and like posts, like the other
Chat SDK adapters

what it supports:
- reply to public mentions (`post.mention.create`) and top-level posts
via `channel.post`
- send and receive direct messages (`dm.received` / `dm.sent`)
- edit and delete owned posts, delete own DM events
- likes as the only reaction (`emoji.heart` or `"like"`)
- buffered streaming: accumulates an LLM stream and posts once instead
of post+edit churn on a public timeline
- OAuth 2.0 user context with managed token refresh (rotating refresh
token persisted in the state adapter, optional AES-256-GCM encryption)
- webhook CRC and `x-twitter-webhooks-signature` verification

key design decisions:
- DMs are threaded by the other participant's user id (`x:dm:{userId}`)
because X DM webhooks carry no conversation id, only participants
- OAuth 2.0 only at runtime: DM send and read are verified to work on
OAuth 2.0 user tokens, so no OAuth 1.0a in the adapter (subscription and
webhook setup is one-time and handled in the X developer console)
- parsers were written against real captured payloads: mentions use the
v2 shape (author hydrated in `includes.users`), DMs use the legacy
Account Activity shape (`direct_message_events`,
`message_create.message_data`, a `users` map, and no conversation id)

also includes the `chat/adapters` catalog entry, docs page, CLI scaffold
spec, and `sample-messages.md` with real captured payloads

<details><summary>usage</summary>

```typescript
import { Chat } from "chat";
import { createXAdapter } from "@chat-adapter/x";

const bot = new Chat({
  userName: "mybot",
  adapters: { x: createXAdapter() },
});

bot.onNewMention(async (thread, message) => {
  await thread.post(`hi @${message.author.userName}!`);
});

bot.onDirectMessage(async (thread) => {
  await thread.post("hello from X");
});
```
</details>

## test plan

- adapter unit tests pass against the real captured payload shapes, with
regression tests for author-from-`includes` (mentions) and the legacy
`direct_message_events` shape (DMs)
- real captured `post.mention.create` and `dm.received` payloads
verified end-to-end through `handleWebhook`: signature verification,
routing, author resolution, and participant threading, plus
bad-signature rejection returns 401
- every write and read path fired live against the X API through the
adapter: top-level post, reply to a mention, like and unlike, edit,
delete, DM send, DM read, DM delete
- OAuth 2.0 managed token refresh exercised live (access and refresh
token rotation)

---------

Signed-off-by: dancer <josh@afterima.ge>
2026-07-07 23:07:36 +01:00
zaadevofc eb466e526f docs: add chat-adapter-zaileys community adapter (#677)
## Summary

Adds **chat-adapter-zaileys** to the community adapters catalog — a
WhatsApp adapter powered by
[Zaileys](https://github.com/zeative/zaileys), a batteries-included
TypeScript wrapper around the unofficial WhatsApp Web API.

- npm: https://www.npmjs.com/package/chat-adapter-zaileys
- Repo: https://github.com/zeative/chat-adapter-zaileys
- Docs: https://zeative.github.io/chat-adapter-zaileys/

## What it adds vs the existing Baileys community adapter

- Real `thread.fetchMessages` history backed by a pluggable message
store (memory/SQLite/Postgres/Redis/Convex), with cursor pagination and
`rehydrateAttachment` for queue/debounce strategies
- Cards render as **native WhatsApp buttons** with `chat.onAction`
round-trips
- Poll votes decrypted natively — no `messageSecret` bookkeeping, works
across restarts
- `scheduleMessage` support (persisted scheduler)
- Opt-in slash-command routing to `chat.onSlashCommand`
- QR/pairing auth, reconnection, and session persistence handled by the
underlying client

## Files changed (per `.agents/skills/add-adapter`)

- `apps/docs/content/adapters/community/zaileys.mdx` — docs page with
feature matrix
- `apps/docs/content/adapters/community/meta.json` — slug added to
Platforms
- `apps/docs/adapters.json` — registry entry
- `packages/integration-tests/src/documentation-test-utils.ts` —
`chat-adapter-zaileys` + `zaileys` in `VALID_DOC_PACKAGES`

## Validation

- `pnpm --filter chat build` ✓
- `pnpm --filter @chat-adapter/integration-tests test` → 914/914 ✓
- `pnpm --filter chat typecheck` ✓
- `pnpm check` + `pnpm konsistent` ✓

Signed-off-by: zeative <zaadevofc@gmail.com>
2026-07-06 09:27:43 +10:00
OmriBenShoham 0c761f1bdd docs(adapters): add Dial as vendor-official adapter (#676)
Adds Dial as a vendor-official adapter — SMS, MMS, iMessage, and inbound
voice-call transcripts for Chat SDK.

- `vendor-official/dial.mdx` adapter page (following the Photon / Linq /
Sendblue format)
- catalog entry in `packages/chat/src/adapters/index.ts` with
`DIAL_API_KEY` / `DIAL_FROM_NUMBER_ID` / `DIAL_WEBHOOK_SECRET`
- `create-chat-sdk` scaffold spec entry
- registry entry in `adapters.json` + `dial` added to vendor-official
`meta.json`
- integration-test doc lists + changeset

Repo: https://github.com/GetDial-AI/chat-sdk-adapter · npm:
`@getdial/chat-sdk-adapter` · Dial docs:
https://docs.getdial.ai/integrations/agent-clients/vercel-chat-sdk

The adapter maps a phone conversation to a Chat SDK thread (identified
by the pair of phone numbers — Dial-owned and peer), an SMS/MMS/iMessage
to a message with optional media attachments, and a completed voice
call's transcript to a message on the caller's thread. Outbound sends
and transcript fetches go through the official `@getdial/sdk`; inbound
webhooks are HMAC-SHA256 verified against a per-subscription signing
secret with constant-time compare.

### Validation
- `pnpm --filter chat build` — clean
- `pnpm --filter chat typecheck` — clean
- `pnpm --filter create-chat-sdk typecheck` — clean
- `pnpm --filter @chat-adapter/integration-tests exec vitest run
src/docs-adapters.test.ts` — 361/361 passed
- `pnpm check` (ultracite) — clean
- `pnpm konsistent` — 34 files, no violations
2026-07-06 09:21:34 +10:00
Thomas Dietert 0b63791b66 fix(slack): process Socket Mode retry envelopes instead of dropping them (#667)
Fixes #666

## Summary

Both `slack_event` handlers (`startSocketMode` and
`runSocketModeListener`) ack and discard every envelope with `retry_num
> 0`. Slack retries an event (immediately, +1 min, +5 min) when a prior
delivery wasn't acked — including events that arrived while the app had
**no open socket** (restart, deploy, or Slack's routine connection
refreshes). For those, the retry is the only delivery the app ever sees,
so dropping it permanently loses the event (production incident details
in #666).

- **`@chat-adapter/slack`**: route retry envelopes through
`routeSocketEvent` like first deliveries (it acks per envelope type,
preserving the 3s ack window), and log them at info with `retry_num` /
`retry_reason` so redelivery is observable. Duplicate protection is
unchanged and sufficient: `Chat.processMessage` dedupes on `message.id`
(the Slack event `ts`, identical on a retry) via `state.setIfNotExists`.
- **`chat`**: raise the default `DEDUPE_TTL_MS` from 5 to 10 minutes.
Slack's final retry fires ~5 minutes after the original delivery —
exactly at the old TTL boundary, where the dedupe entry from the first
processing could expire just before the retry arrives and cause a
double-process. `dedupeTtlMs` config still overrides.

Behavior note for review: apps that relied on retries being invisible
will now see redelivered events flow through — deduped when already
handled, processed when not. That is the intended semantic:
at-least-once delivery from Slack, exactly-once handling via the SDK's
dedupe.

## Test plan

- Replaced the `"skips retries"` test with `"processes retries like
first deliveries (dedupe drops true duplicates)"` — asserts a
`retry_num: 1` envelope is acked and reaches `processMessage`.
- Updated the default-TTL test to 10 minutes; the custom-`dedupeTtlMs`
test is unchanged.
- `pnpm validate` passes end to end (knip, check, typecheck, test,
build); `pnpm --filter chat --filter @chat-adapter/slack test` = 1028 +
506 passing.


Signed-off-by: tdietert <thomasd@mercury.com>
2026-07-02 17:26:27 +01:00
Ben Sabic 3abdc69103 docs(adapters): add Cloudflare Agents as vendor-official state adapter (#669)
Adds Cloudflare Agents as a vendor-official **state** adapter —
`agents/chat-sdk`'s `createChatSdkState()`, a Chat SDK `StateAdapter`
that stores subscriptions, locks, queues, dedupe keys, thread/channel
state, transcripts, and history in Durable Object SQLite via
`ChatSdkStateAgent` sub-agents.

- `vendor-official/cloudflare-agents.mdx` state-adapter page (Agent
setup, wrangler DO migration, sharding, config, storage/cleanup)
- catalog entry in `packages/chat/src/adapters/index.ts` (`group:
vendor-official`, `type: state`)
- registry entry in `adapters.json` + `cloudflare-agents` in
vendor-official `meta.json`
- integration-test doc lists + changeset

Repo: https://github.com/cloudflare/agents · package `agents`
(`agents/chat-sdk`) ·
[docs](https://developers.cloudflare.com/agents/runtime/communication/chat-sdk/)

### Not wired into the create-chat-sdk CLI
This adapter runs inside a Cloudflare Worker with Durable Objects, not
the generated Next.js runtime, so it is intentionally kept out of the
scaffold:
- added to `CLI_INCOMPATIBLE_ADAPTERS` (rejected via `--adapter`, hidden
from the platform picker and e2e run, like `lark`/`matrix`)
- new `listCliStateAdapters()` filters the interactive **state** picker
and the `--help` adapter list (the state picker previously used raw
`listStateAdapters()` and would have offered it, then thrown on
selection)

### Tests
- `catalog/display.test.ts` — `listCliStateAdapters`: returns only state
adapters, includes `memory`/`redis`, and excludes `cloudflare-agents`
while asserting it *is* in the raw catalog
- `catalog/selection.test.ts` —
`resolveAdapterValue("cloudflare-agents")` throws "not supported"
- `cli/program.test.ts` — `buildAdapterList()` help text omits
`cloudflare-agents`
- existing `CLI_SCAFFOLD_SPEC covers every catalog adapter` +
docs-adapters/docs-content suites cover the catalog entry, registry
parity, and MDX imports

### Validation
- create-chat-sdk: **178 passed**, typecheck clean
- integration docs suites pass; Biome + knip clean

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-03 01:55:05 +10:00
Ben Sabic 24a04d5653 docs(adapters): add Photon as vendor-official adapter (#668)
Adds Photon as a vendor-official adapter — iMessage for Chat SDK.

- `vendor-official/photon.mdx` adapter page (following the Linq /
Sendblue / Kapso format)
- catalog entry in `packages/chat/src/adapters/index.ts` with
cloud/self-host credential modes
- `create-chat-sdk` scaffold spec entry
- registry entry in `adapters.json` + `photon` added to vendor-official
`meta.json`
- integration-test doc lists + changeset

Repo: https://github.com/photon-hq/vercel-chat-adapter-imessage · npm:
`@photon-ai/chat-adapter-imessage` · built on
[spectrum-ts](https://github.com/photon-hq/spectrum-ts)

The adapter runs in three modes — **Cloud** ([Spectrum
Cloud](https://app.photon.codes)), **self-hosted** (gRPC), and **local**
(on-device, macOS) — auto-detected from environment variables. Cloud
mode delivers inbound messages via HMAC-signed webhooks; DMs can be
replied to cold from a webhook delivery.

### Notes
- Catalog slug is `photon`; docs code examples use `imessage` as the
adapter key to match the upstream README.
- Feature flags encode the README's remote-only caveats (reactions /
editing / typing / modals as `partial`, mentions as DMs-only; no
history, thread info, or reaction removal).

### Validation
- `docs-adapters` integration tests — 1237 passed (catalog↔registry
parity, peerDeps↔PackageInstall alignment)
- `create-chat-sdk` e2e scaffold — 175 passed (scaffolds every catalog
adapter, incl. photon)
- `chat` + `create-chat-sdk` typecheck, Biome check, and konsistent —
clean

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-03 01:40:06 +10:00
Ben Sabic ba375ce16c feat(create-chat-sdk): add Vercel Connect mode (#655)
Adds an opt-in Vercel Connect authentication mode to the scaffolder for
the Slack, GitHub, and Linear adapters, via a `--connect` flag and a new
interactive auth-mode prompt (shown only when a Connect-capable adapter
is selected).

When enabled, the generated project:

- spreads the matching helper from `@vercel/connect/chat` into the
adapter factory in `src/lib/bot.ts` (non-Connect adapters keep their
native factory calls)
- adds `@vercel/connect` to dependencies
- lists each connector UID (for example `SLACK_CONNECTOR`) plus the
recommended `GITHUB_BOT_USER_ID`, in place of native provider secrets,
in `.env.example`
- documents `vercel link` / `vercel env pull` and the deployed-URL
webhook caveat in the README and post-install next steps

Connect policy lives in the existing `scaffold-spec.ts` (per-adapter
`connect` field), so `chat/adapters` stays the single source of adapter
metadata.

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

## Companion

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

---------

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-03 01:39:40 +10: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 4115c9431e feat(linear): add Vercel Connect support (#649)
Adds Vercel Connect support to the Linear adapter:

- `accessToken` now accepts a `() => string | Promise<string>` resolver
in addition to a string, so tokens can be sourced from Vercel Connect at
runtime.
- A new optional `webhookVerifier` verifies inbound webhooks (Connect
trigger-forwarded requests via a Vercel OIDC token) in place of the
Linear webhook secret.
- Connect-mode outbound calls outside webhook handling are supported via
`withInstallation(organizationId, fn)`.

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

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

## Companion

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

<img width="929" height="664" alt="CleanShot 2026-06-30 at 12 35 30"
src="https://github.com/user-attachments/assets/c5861cb9-d66b-42c6-b838-5b4983f48646"
/>

---------

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-03 01:23:21 +10:00
Ben Sabic ba687cb13c docs(slack): document Vercel Connect support (#648)
Documents authenticating the Slack adapter with Vercel Connect via
`connectSlackAdapter()` from `@vercel/connect/chat`. The Slack adapter
already supports a `botToken` resolver and a `webhookVerifier`, so this
is a documentation-only change (no changeset).

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

## Companion

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

<img width="824" height="527" alt="CleanShot 2026-06-30 at 12 03 26"
src="https://github.com/user-attachments/assets/cbced069-8913-4848-9cf1-df0e5f614353"
/>

---------

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-03 01:01:51 +10:00
Ben Sabic ab0e1806c8 feat(chat): Vercel Connect (#647)
Adds a Vercel Connect guide to the docs under **Usage**
(`chat-sdk.dev/docs/vercel-connect`), covering connector setup, trigger
forwarding, the per-platform `connect*Adapter` helpers from
`@vercel/connect/chat`, custom OIDC webhook verification and its trust
boundary, and limitations. Also adds a "Vercel Connect Guide" card to
the docs homepage.

This is the base of a stack; the adapter, tests, and CLI PRs below build
on it. Docs-only, so no changeset.

## Stack

- #647 — feat(chat): Vercel Connect (this PR, base → `main`)
- #648 — docs(slack): document Vercel Connect support
- #649 — feat(linear): add Vercel Connect support
- #650 — feat(github): add Vercel Connect support
- #654 — feat(tests): add Vercel Connect webhook contract helper
- #655 — feat(create-chat-sdk): add Vercel Connect mode

All of the above are stacked on this branch (`vercel-connect/base`).

## Companion

The helpers this documents ship in the `@vercel/connect/chat` subpath:
vercel/vercel#16826.

---------

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-03 01:01:16 +10:00
Ben Sabic beae9bffdb chore(docs): update eve link (#664)
eve homepage is now live, change the link from the docs to the homepage
now, reflecting how the other OSS sites behave

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-07-01 16:39:02 +01:00
dependabot[bot] df825b3a56 build(deps-dev): bump postcss from 8.5.15 to 8.5.16 (#658)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.15 to
8.5.16.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/postcss/postcss/releases">postcss's
releases</a>.</em></p>
<blockquote>
<h2>8.5.16</h2>
<ul>
<li>Fixed <code>Input#origin()</code> position (by <a
href="https://github.com/mizdra"><code>@​mizdra</code></a>).</li>
<li>Fixed <code>raws</code> after rehydrating a JSON AST (by <a
href="https://github.com/sarathfrancis90"><code>@​sarathfrancis90</code></a>).</li>
<li>Fixed putting parent-less node in <code>nodes</code> of new node (by
<a
href="https://github.com/MahinAnowar"><code>@​MahinAnowar</code></a>).</li>
<li>Fixed computing <code>offset</code> in <code>positionBy()</code> (by
<a
href="https://github.com/greymoth-jp"><code>@​greymoth-jp</code></a>).</li>
<li>Fixed <code>rangeBy()</code> on <code>index: 0</code> (by <a
href="https://github.com/sarathfrancis90"><code>@​sarathfrancis90</code></a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/postcss/postcss/blob/main/CHANGELOG.md">postcss's
changelog</a>.</em></p>
<blockquote>
<h2>8.5.16</h2>
<ul>
<li>Fixed <code>Input#origin()</code> position (by <a
href="https://github.com/mizdra"><code>@​mizdra</code></a>).</li>
<li>Fixed <code>raws</code> after rehydrating a JSON AST (by <a
href="https://github.com/sarathfrancis90"><code>@​sarathfrancis90</code></a>).</li>
<li>Fixed putting parent-less node in <code>nodes</code> of new node (by
<a
href="https://github.com/MahinAnowar"><code>@​MahinAnowar</code></a>).</li>
<li>Fixed computing <code>offset</code> in <code>positionBy()</code> (by
<a
href="https://github.com/greymoth-jp"><code>@​greymoth-jp</code></a>).</li>
<li>Fixed <code>rangeBy()</code> on <code>index: 0</code> (by <a
href="https://github.com/sarathfrancis90"><code>@​sarathfrancis90</code></a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/postcss/postcss/commit/92ccc93ff15bd193491d67fad9763e62d489dfad"><code>92ccc93</code></a>
Release 8.5.16 version</li>
<li><a
href="https://github.com/postcss/postcss/commit/818bdd6043359af773ccc3ca8663053d61a707c8"><code>818bdd6</code></a>
Update formatting</li>
<li><a
href="https://github.com/postcss/postcss/commit/46e451068ee6160b837865b715cf6972f28fabd5"><code>46e4510</code></a>
Fix <code>Input#origin()</code> returning incorrect position (<a
href="https://redirect.github.com/postcss/postcss/issues/2036">#2036</a>)</li>
<li><a
href="https://github.com/postcss/postcss/commit/34942ce76c0b0c9ee65b1421017ac71855e722c4"><code>34942ce</code></a>
Fix tests</li>
<li><a
href="https://github.com/postcss/postcss/commit/d4feed645314ee421edf80ee9ebe453cc75c997f"><code>d4feed6</code></a>
Don't clone root-less child nodes in container constructor (<a
href="https://redirect.github.com/postcss/postcss/issues/2097">#2097</a>)</li>
<li><a
href="https://github.com/postcss/postcss/commit/da323fc8d327a38199a21987dcbf7e27e3bc34f3"><code>da323fc</code></a>
Revert version update to fix old Node.js on CI</li>
<li><a
href="https://github.com/postcss/postcss/commit/886336919497516df8f140d0fb327bd125e35053"><code>8863369</code></a>
Update dependencies</li>
<li><a
href="https://github.com/postcss/postcss/commit/3828982213fec6bc13d0791b1adf40393be0935e"><code>3828982</code></a>
Preserve node raws when rehydrating a JSON AST (<a
href="https://redirect.github.com/postcss/postcss/issues/2100">#2100</a>)</li>
<li><a
href="https://github.com/postcss/postcss/commit/d1e80b830386b08dcd5b962fd466d1c51f28e82d"><code>d1e80b8</code></a>
Fix Node#rangeBy() ignoring index 0 (<a
href="https://redirect.github.com/postcss/postcss/issues/2091">#2091</a>)</li>
<li><a
href="https://github.com/postcss/postcss/commit/b91e4a63907325d98b75d11fda546bdd91acc608"><code>b91e4a6</code></a>
Fix Node.js 26 tests</li>
<li>Additional commits viewable in <a
href="https://github.com/postcss/postcss/compare/8.5.15...8.5.16">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for postcss since your current version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=postcss&package-manager=npm_and_yarn&previous-version=8.5.15&new-version=8.5.16)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/vercel/chat/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-01 13:22:22 +01:00
Anudeep 2e4735118e fix: let Plan tasks run in parallel without implicit auto-completion (#632)
## Summary

Plan’s task list API always marked existing in-progress steps as
complete whenever a new step was added. That made sense for simple
sequential bots, but it blocked parallel work — even though the docs
already showed a parallel pattern and per-task updates by ID were added
earlier.

This PR adds an optional flag on task creation so callers can keep
multiple steps in progress at once, while leaving the old sequential
behavior as the default.


**Opt-out flag, default on**. We considered removing auto-completion
entirely. That would’ve been cleaner for parallel use but would’ve
broken existing sequential bots that rely on implicit “move to next
step” behavior. Defaulting to the current behavior keeps upgrades safe;
parallel callers pass the flag off.

**No broader API redesign**. Task completion stays explicit via status
updates and the existing “complete plan” flow. The change is scoped to
when a new task is appended.


closes #630
2026-07-01 04:26:48 +01:00
Dean Mauro 022a502726 feat(discord): add ephemeral slash command responses (#514)
## summary

resolves #515

adds Discord slash-command interaction response flags so selected
commands can defer as ephemeral

Discord locks ephemerality on the initial
`DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE` response, so the adapter now
exposes `interactionFlags` on `createDiscordAdapter` for that initial
acknowledgement

```ts
import {
  createDiscordAdapter,
  DiscordInteractionResponseFlag,
} from "@chat-adapter/discord";

const discord = createDiscordAdapter({
  interactionFlags: ({ command }) => {
    if (command === "/admin") {
      return DiscordInteractionResponseFlag.Ephemeral;
    }
  },
});
```

handlers still use the normal `event.channel.post(...)` flow, and
`event.channel.postEphemeral(...)` keeps the normal Chat SDK fallback
behavior outside Discord's slash-command interaction response path


Co-authored-by: dancer <josh@afterima.ge>
2026-07-01 04:16:52 +01:00
Ben Sabic 99c598505f docs: refresh agent docs, README badges, and Chat SDK skill (#646)
- Replace npm version/download badges with Agent Stack and MIT badges on
the root README and all published package READMEs
- Streamline root `AGENTS.md`: fix title, add an accurate monorepo map,
trim duplicated CONTRIBUTING/Ultracite/env-var content, and link to
package-level `AGENTS.md` files
- Slim the Chat SDK agent skill (`skills/chat/SKILL.md` and published
copies) to defer to bundled docs, chat-sdk.dev, Vercel KB, and
`llms.txt` instead of inlining CLI flags, quick-start code, and API
tables
- Polish root README copy (install examples, adapter/build links, Vercel
Plugin URL, Vercel KB link, “Made by Vercel” badge)
- Minor `CONTRIBUTING.md` fixes: simplify DCO wording, correct
preview-branch proxy file references (`proxy.ts` vs middleware)

---------

Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-27 14:06:13 +10:00
Pau Guirao dd3fa75ac4 docs(zernio): document 0.4.0 — interactive lists, WhatsApp rich messages, openDM (#643)
Updates the Zernio (vendor-official) adapter page to reflect
`@zernio/chat-sdk-adapter@0.4.0`.

## What changed
- **Feature support**: `selectMenus` → partial (card
`Select`/`RadioSelect` now map to a WhatsApp interactive **list**).
- **Platform matrix**: added Lists, Location/Contacts, Templates/Flows
rows (WhatsApp); corrected WhatsApp typing to ✓.
- **New sections**:
- *WhatsApp rich messages* — `sendInteractive`
(button/list/cta_url/flow/location-request/voice-call), `sendLocation`,
`sendContacts`, `sendTemplate`, `reply` via the exported
`ZernioApiClient`.
- *Inbound interactive replies* — reading button/list/flow responses, ad
referral, and quoted context off `message.raw.metadata`.
- *Opening conversations* — `openDM` and `openConversation` (cold-start
by phone).
- **API client**: added `createConversation`.

Scope follows the same split as other adapters: cross-platform concepts
live in the adapter; WhatsApp-only sends go through the alongside
client.
2026-06-26 18:37:06 +10:00
wong2 ba30885093 docs: remove QQ Bot community adapter entry (#642)
Removes the QQ Bot community adapter entry from
`apps/docs/adapters.json`.

The entry only provided a navigation listing without a corresponding
content page, so https://chat-sdk.dev/adapters/community/qq-bot resolved
to a 404.
2026-06-24 19:47:27 +10:00
christopherkindl 7d02ea32de [docs] use actual eve logo in OSS nav dropdown (#641)
- Swap the text-based eve placeholder in the OSS products dropdown for
the actual eve wordmark, hard-copied as an SVG from
`@vercel/geistcn-assets` and themed via `currentColor`.
- Put AI Elements last, drop Streamdown to address G feedback

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 14:03:09 -07:00
wong2 ef3f0f63bd docs: add Weixin community adapter (#638)
Adds the
[`chat-adapter-weixin`](https://github.com/wong2/weixin-chat-adapter)
community adapter (Weixin / WeChat iLink bot) to the docs.

### What's included
- `apps/docs/content/adapters/community/weixin.mdx` — hand-authored
adapter page following the existing community-adapter structure
(install, quick start, long-polling note, QR login, env vars, config
`TypeTable`, thread-ID format, capabilities/limitations, and
`<FeatureSupport />`).
- `apps/docs/adapters.json` — registry entry (`community: true`, author,
pinned README commit).
- `apps/docs/content/adapters/community/meta.json` — sidebar link under
**Platforms**.

### Notes
The adapter talks to Weixin's iLink bot HTTP JSON APIs directly. It uses
long polling for inbound messages (no webhook) and requires a Chat SDK
`StateAdapter` for cursor / context-token / dedupe / history. It's 1:1
only, so messages route through `onDirectMessage`.

### Verification
`docs-adapters` (322) and `docs-llms` (129) integration tests pass.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-23 20:33:43 +10:00
Ben Sabic 63ac3e5988 docs: homepage nits (#628)
- Break hero title cleanly on desktop only so "for" doesn't strand on
mobile
- Keep OSS stat labels (e.g. "Weekly downloads") on one line
- Shrink feature box headings on mobile, full size from sm
- Span the third feature box full-width on mobile
- Enable horizontal scroll for long code lines in the code showcase
- Match "more adapters" link color to the "Supports" label

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-22 14:56:35 +10:00
Ben Sabic efa96108bd docs: sync KB resources and harden sync-resources script (#635)
Syncs the bundled Chat SDK KB resources from Edge Config and hardens the
`sync-resources` script that generates them.

- **New guides** (4): Vercel Connect, the Slack Vercel Connect bot, AI
Gateway + AI SDK, and the daily digest bot. Existing guide bodies
refreshed and `templates.json` regenerated.
- **Script hardening** (`scripts/sync-resources.ts`):
- Fetch + validate all guides into memory **before** wiping the
resources dir — a failed fetch now leaves the working tree untouched.
- Validate the `resources-edge-config.json` shape with a clear error
instead of a blind cast.
  - Reject duplicate guide slug collisions.
- Retry transient fetches (5xx / network) with exponential backoff; fail
fast on 4xx, bad content-type, and oversized bodies.
- Mirror `skills/chat/SKILL.md` to **all four** committed copies (docs
site `.well-known` + `AGENTS.md`, and the two `create-chat-sdk` scaffold
templates).
  - TSDoc on every function.
- **Tests**: new offline consistency test in
`packages/integration-tests` — every guide has a non-empty file with no
orphans, `templates.json` mirrors the config, no duplicate slugs, and
all four `SKILL.md` copies are byte-identical to the source.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-22 14:56:17 +10:00
George McCain d034b8b575 docs(adapters): add Linq as vendor-official adapter (#625)
Adds Linq as a vendor-official adapter — iMessage and SMS for Chat SDK.

- `vendor-official/linq.mdx` adapter page (following the Velt /
AgentPhone format)
- catalog entry in `adapters.json`
- `linq` added to the vendor-official `meta.json`

Repo: https://github.com/linq-team/linq-chat-sdk · npm:
`@linqapp/chat-sdk-adapter` (Apache-2.0)

The adapter is built and tested end-to-end against the live Linq API and
the Chat SDK runtime (real iMessage round-trip, webhooks, reactions,
media). Confirmed with Benji that a repo link works and Apache-2.0 is
fine. Happy to adjust the page to match any conventions I missed.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-20 11:47:57 +10:00
Ben Sabic a528a9f655 feat(docs): add eve to product switcher (#624)
Add an eve entry (text wordmark + Beta badge, linking to eve.dev/docs)
to the top of the OSS product switcher in the docs navbar.

<img width="352" height="328" alt="CleanShot 2026-06-20 at 01 09 35"
src="https://github.com/user-attachments/assets/cd2f03b0-8b40-477b-a8a2-ac4a9911f44d"
/>

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-20 08:57:07 +10:00
Dima Grossman 06af3e12fd docs(adapters): add Novu as vendor-official adapter (#622)
## Summary

Adds Novu as a vendor official adapter to Chat SDK allowing
multi-channel notification delivery and quick channel setup for
multi-tenant apps.

Official change log entry:
https://novu.co/changelog/novu-chat-sdk-adapter/
Official social post: https://x.com/novuhq/status/2067870170320679158 

## Test plan

Manually tested with our team to ensure compatability with the create
chat sdk and template apps, also created an example repo:
https://github.com/novuhq/novu-chat-sdk-example

## Checklist

- [x] All commits are signed and verified
- [x] `pnpm validate` passes
- [x] Changeset added (or N/A — see
[CONTRIBUTING.md](./CONTRIBUTING.md))
- [x] Documentation updated (or N/A)

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-19 22:11:33 +10:00
Yoen Zhang d3cd9719c0 docs(adapters): sharpen Velt description + add live demo link (#578)
Follow-up to #572 (now merged). Improvements to the Velt vendor-official
entry:

- **Sharpen the description + tagline** to reflect what's distinctive:
comments are *anchored* to the exact element, across documents,
rich-text editors, canvases, PDFs, and video — with per-comment document
context and a streaming AI reply.
- **Add a Live demo link** to the Examples section: the [tiptap comments
demo](https://sample-apps-tiptap-comments-demo.vercel.app) where you
@-mention **Velt Bot** and get a streaming AI reply (runs the
`nextjs-velt-ai-bot` sample app).
- **Re-pin the `readme` SHA** to current `main` so the linked package
README reflects the latest content (now includes example + live-demo
links).

Touches only `apps/docs/adapters.json` and
`apps/docs/content/adapters/vendor-official/velt.mdx`
2026-06-18 12:29:56 +10:00
josh a1110dd6d0 fix(docs): restore Open Graph images (#620)
## summary

restores Open Graph and Twitter preview images across the homepage,
adapters, and resources pages

adds the canonical metadata base so social image URLs resolve against
chat-sdk.dev instead of localhost
2026-06-17 23:12:16 +01:00
OSS Polar Bear 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>
2026-06-16 18:54:07 +10:00
Ben Sabic c2a26e7104 feat(docs): refresh homepage styling (#615)
Stacked on top of #603 (`create-chat-sdk`).

Refreshes the chat-sdk.dev homepage styling:

- Adds Geist typography utilities (`text-heading-*`, `text-copy-*`) and
applies them to the hero, section headings, and copy.
- Adds a grid-based layout (`home-grid.css`) with consistent guide lines
for the stats, supported-platforms, code, and integrations sections.
- Adds a tabbed code showcase for the Chat SDK Core section, with window
chrome, a Geist syntax theme, and
`bot.ts`/handlers/cards/streaming/tools/state/multi-platform snippets.
- Scopes inline-code styling and sets the dark-mode
`--ds-background-100`/`--ds-background-200` tokens so `background-100`
is the elevated surface.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-16 18:04:30 +10:00
Ben Sabic 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>
2026-06-16 08:48:38 +01:00
josh 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
2026-06-15 19:44:32 +01:00
aqt 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>
2026-06-14 23:46:22 +01:00
Ben Sabic 5a59ae2aa3 fix(docs): allow product switcher logo to navigate home (#614)
Adds a safeguard in `NavigationMenuTrigger` to skip `preventDefault`
when the click is on a nested link, so the logo navigates home without
interfering with the chevron dropdown, matching the AI SDK website
interaction model.

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-06-15 08:45:11 +10:00
ishaksebsib 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>
2026-06-09 22:36:36 +10:00
Ben Sabic 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>
2026-06-09 10:43:00 +10:00
Vishal Yathish 171657a019 [chat] adding stable id to link button action handlers (#598)
Enabling overriding the `link:<url>` action ID for `LinkButton` events.
2026-06-08 08:36:24 -07:00