mirror of
https://github.com/vercel/chat.git
synced 2026-09-14 18:32:29 +08:00
@chat-adapter/gchat@4.37.0
847 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3468cdfe0b |
chore(release): version packages (#767)
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @chat-adapter/gchat@4.37.0 ### Minor Changes -@chat-adapter/shared@4.37.0 @chat-adapter/teams@4.37.0 @chat-adapter/x@4.37.0 @chat-adapter/tests@4.37.0 @chat-adapter/twilio@4.37.0 @chat-adapter/messenger@4.37.0 @chat-adapter/linear@4.37.0 create-chat-sdk@0.3.0 @chat-adapter/state-pg@4.37.0 @chat-adapter/telegram@4.37.0 @chat-adapter/state-memory@4.37.0 @chat-adapter/whatsapp@4.37.0 @chat-adapter/state-redis@4.37.0 @chat-adapter/slack@4.37.0 @chat-adapter/instagram@4.37.0 @chat-adapter/web@4.37.0 @chat-adapter/github@4.37.0 @chat-adapter/state-ioredis@4.37.0 chat@4.37.0 @chat-adapter/gchat@4.37.0 @chat-adapter/discord@4.37.0 |
||
|
|
c3b5a08e7e |
fix(gchat): bind Pub/Sub push verification to a configured identity (#797)
## summary Pub/Sub push verification checked the token's `aud` and nothing else. [Google's guidance](https://docs.cloud.google.com/pubsub/docs/authenticate-push-subscriptions) is explicit that signature and audience verification are not sufficient on their own, and that the `email` and `email_verified` claims must be checked alongside them adds `pubsubServiceAccountEmail` (env `GOOGLE_CHAT_PUBSUB_SERVICE_ACCOUNT_EMAIL`), the identity in the subscription's push auth settings. a push is accepted only when `email_verified` is true and `email` matches exactly. when the option is unset, pushes are rejected rather than trusted on their audience alone direct webhooks are untouched, and the project-number path already bound to an exact issuer ### how it happened `verifyBearerToken` took the claim validator as an optional parameter, so a call site could simply omit it, and the Pub/Sub one did while the direct-webhook one did not. that is now required: ```diff - validatePayload?: (payload: { + validatePayload: (payload: { ``` both call sites pass one and the type system enforces it, so the omission cannot recur ## test plan - a token from a different service account is rejected - a token is rejected when no identity is configured - a token is rejected when `email_verified` is not true - a token with no `email` claim is rejected - a matching identity with a verified email is accepted - direct-webhook and project-number verification are unchanged docs cover the new option in the README and adapter page, including the push-subscription authentication step that produces the token |
||
|
|
2a2b2c5500 |
feat(instagram): add native DM adapter (#770)
Adds a first-party Instagram Direct Messages adapter backed by Meta's
Instagram API with Instagram Login.
- Verifies webhook challenges and HMAC signatures, then normalizes DMs,
story replies, media, quick replies, postbacks, and reactions.
- Sends plain text, cards, quick replies, typing indicators, URL
attachments, and uploaded media through `graph.instagram.com`.
- Maps authentication, rate-limit, and 24-hour messaging-window failures
to typed adapter errors.
- Registers Instagram in the adapter catalog, CLI scaffold, official
docs, replay suite, and Next.js example.
## Usage
```ts
import { createInstagramAdapter } from "@chat-adapter/instagram";
import { Chat } from "chat";
const bot = new Chat({
userName: "mystore",
adapters: { instagram: createInstagramAdapter() },
});
```
## Webhook
```ts
export async function POST(request: Request) {
return bot.webhooks.instagram(request);
}
```
## Verification
- `pnpm --filter @chat-adapter/instagram test`
- `pnpm --filter @chat-adapter/instagram typecheck`
- `pnpm --filter example-nextjs-chat typecheck`
- `pnpm --filter example-nextjs-chat build`
- `pnpm check`
- `pnpm konsistent`
## Live Testing
<table>
<tr>
<td><img width="1440" height="2109" alt="1000000502"
src="https://github.com/user-attachments/assets/9fdb8c3b-4e41-4c81-9426-08756a5e4201"
/></td>
<td><img width="1440" height="1995" alt="1000000503"
src="https://github.com/user-attachments/assets/8a572493-c57a-4412-9049-5737aaa9dfd0"
/></td>
</tr>
</table>
Closes #729 / Co-Authored by @ivandujaut
---------
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
|
||
|
|
6abf4807db |
feat(whatsapp): Add native LinkButton support for WhatsApp CTA URL messages (#781)
Adds native `LinkButton` support to the WhatsApp adapter by mapping Chat SDK `LinkButton` actions to WhatsApp Cloud API CTA URL interactive messages. Previously, WhatsApp cards containing only `LinkButton` actions were rendered as plain text with the URL exposed. WhatsApp supports native CTA URL buttons through `interactive.type: "cta_url"`, so this change enables the adapter to use that native capability. Closes #780 ## Changes Made - Added support for converting a single `LinkButton` action into a WhatsApp CTA URL interactive message. - Added the `cta_url` interactive message shape to the WhatsApp adapter types. - Preserved existing reply button behavior and fallback handling for unsupported card configurations. - Added test coverage for: - Single `LinkButton` → native CTA URL message conversion. - Existing reply button behavior remaining unchanged. - Multiple `LinkButton` fallback behavior. ### Test Coverage Added tests covering the new CTA URL conversion path and verified the generated WhatsApp payload contains: - `interactive.type: "cta_url"` - `action.name: "cta_url"` - `action.parameters.display_text` - `action.parameters.url` ## Screenshots/Demos <img width="864" height="338" alt="image" src="https://github.com/user-attachments/assets/cc58a76b-5a96-406a-9f79-ca7a2725836b" /> ## Additional Notes WhatsApp CTA URL messages only support a single URL button per interactive message. The implementation intentionally only promotes cards with exactly one `LinkButton` into a CTA URL message and keeps existing fallback behavior for unsupported combinations. --------- Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
e8cc4bc930 |
docs: add inbound cross-links to orphaned pages (#789)
These docs pages had no inbound links from other pages, so they're only reachable via the sidebar. Adds minimal cross-links from related pages. --------- Signed-off-by: molebox <rich@vercel.com> |
||
|
|
1426e2b05e |
Update CODEOWNERS to require @vercel/chat-sdk approval (#791)
Update CODEOWNERS to require @vercel/chat-sdk approval, except for MD changes |
||
|
|
cd4a655844 |
fix(docs): remove hardcoded bg-background from CodePreview pre element (#790)
## Problem On the GetStarted cards in the home page, the `<pre>` inside `CodePreview` had `bg-background` hardcoded. When hovering a card (`hover:bg-muted/40`), the code block retained its own opaque background, so the hover tint only showed through around the text — the dark/muted fill appeared clipped to the text container rather than filling the whole rotated card. ## Fix Removed `bg-background` from the `<pre>` element so it inherits the parent card's background. The default state is unchanged since the card itself already has `bg-background`. --------- Co-authored-by: v0 <it+v0agent@vercel.com> Co-authored-by: Matias Gonzalez <29680544+matiasngf@users.noreply.github.com> |
||
|
|
0ec6a7361b |
feat(notion): add Notion comments adapter (#689)
Adds `@chat-adapter/notion`, an official adapter that lets a Chat SDK
bot take part in **Notion comment discussions** (page-level and
block/discussion threads) with the same handler code used for Slack,
Linear, GitHub, etc. Inbound events arrive via Notion webhooks
(`comment.created`) with HMAC signature verification; outbound actions
use the Comments REST API. Because Notion lets a connection edit its own
comments, the adapter supports **Post+Edit streaming**.
### Highlights
- **Webhooks** — `comment.created` verified with `X-Notion-Signature`
HMAC over the raw body (timing-safe), plus the one-time
`verification_token` handshake. Returns a fast 200 with idempotent,
state-backed dedupe.
- **Post+Edit streaming** — posts the first chunk, then `PATCH`es the
comment as tokens arrive, throttled to Notion's ~3 req/s limit (global
token bucket, `Retry-After` aware). Long bodies are split into
sequential comments to stay under the 2000-char rich-text cap.
- **Mentions** — three modes: `mention` (default; plain-text `@userName`
/ `@botUserId`), `all-comments`, and `keyword`.
- **`message.subject`** — resolves the parent page via the Pages API
(title, url, archived status, author).
- **File uploads** — up to 3 native attachments via the File Uploads API
(binary `single_part`; public URLs via `external_url` with bounded
polling); overflow and failures fall back to markdown links.
- **History** — `fetchMessages` over list-comments (open comments only),
direction-aware.
- Cards render as markdown fallback; reactions / typing / DMs are typed
no-ops or errors. Registered in the `chat/adapters` catalog and the
`create-chat-sdk` scaffold; pinned to `Notion-Version: 2026-03-11`.
### Usage
```ts
// lib/bot.ts
import { Chat } from "chat";
import { createNotionAdapter } from "@chat-adapter/notion";
import { createRedisState } from "@chat-adapter/state-redis";
export const bot = new Chat({
userName: "notion-bot",
adapters: { notion: createNotionAdapter() }, // reads NOTION_TOKEN + NOTION_VERIFICATION_TOKEN
state: createRedisState(),
});
bot.onNewMention(async (thread, message) => {
const subject = await message.subject; // parent page metadata (title, url, …)
await thread.post(`Thanks for the mention on **${subject?.title ?? "this page"}**!`);
});
```
```ts
// app/api/webhooks/notion/route.ts
import { bot } from "@/lib/bot";
export const POST = (request: Request): Promise<Response> => bot.webhooks.notion(request);
```
### Configuration
Auto-detects `NOTION_TOKEN` and `NOTION_VERIFICATION_TOKEN`, plus
optional `NOTION_BOT_USERNAME`, `NOTION_MENTION_MODE`,
`NOTION_KEYWORDS`, and `NOTION_VERSION`; everything is overridable via
`createNotionAdapter({ … })`. The docs page covers the full connection +
webhook setup (capabilities, content access, and the webhook-URL-lock
warning).
Changeset bumps `@chat-adapter/notion`, `chat`, and `create-chat-sdk`
(minor). Layered as four commits: `feat` (adapter +
catalog/scaffold/emoji), `docs`, `test`, `chore(example)`.
---------
Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
Co-authored-by: dancer <josh@afterima.ge>
|
||
|
|
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> |
||
|
|
7a1922357c |
fix(gchat): bind add-on webhook verification to a configured identity (#787)
## summary
endpoint-URL webhook verification accepted any `email` claim matching
the generic Workspace Add-on shape:
```ts
/^service-\d+@gcp-sa-gsuiteaddons\.iam\.gserviceaccount\.com$/
```
the `\d+` is a GCP project number, and service agents are
`service-{PROJECT_NUMBER}@gcp-sa-{SERVICE}...` for the project that owns
them. so that shape identifies "some Workspace Add-on", not *this* app's
add-on, and it was the only thing standing between a public endpoint URL
and a verified request. the method's own doc comment already stated the
correct invariant, that the token is only trustworthy if it was issued
to Google Chat itself
adds `workspaceAddOnServiceAccountEmail` (env
`GOOGLE_CHAT_WORKSPACE_ADDON_SERVICE_ACCOUNT_EMAIL`) and compares add-on
identities exactly. when it is unset, add-on-shaped tokens are rejected
rather than trusted by shape, with a log naming the option to set
`chat@system.gserviceaccount.com` is untouched, so standalone Chat apps
behave exactly as before. the project-number and Pub/Sub paths were
already bound to exact identities and are unchanged
### behavior
| token `email` | before | after |
| --- | --- | --- |
| `chat@system.gserviceaccount.com` | accept | accept |
| add-on shape, matches configured identity | accept | accept |
| add-on shape, different project | accept | **reject** |
| add-on shape, option unset | accept | **reject** |
<details>
<summary>why not reject at construction</summary>
refusing to initialize when the option is absent would be the
stricter-looking choice, but the adapter cannot tell Workspace Add-on
mode from config alone, it only sees `endpointUrl`. throwing there would
break every ordinary endpoint-URL Chat app. rejecting add-on-shaped
tokens at verification is the precise equivalent without the collateral
</details>
## test plan
- an add-on token matching the configured identity is accepted
- an add-on token from a different project is rejected, the case the
generic shape allowed
- an add-on token is rejected when no identity is configured
- `chat@system.gserviceaccount.com` is still accepted with no add-on
config
- suffixed and prefixed lookalike domains, an uppercase variant, and
trailing whitespace are all rejected
- a matching identity with `email_verified: false` is rejected
the two rejection cases above returned 200 before this change and 401
after
|
||
|
|
258a7312ba |
docs: add vendor-official guide and refresh adapter docs (#784)
Adds a vendor-official contributing guide covering qualifications, listing terms, and the PR checklist for platform vendors. Contributing and adapter overview pages point to that guide for listing details instead of repeating them. Moves Slack and Teams low-level API docs onto their adapter pages, with permanent redirects from `/docs/slack-primitives` and `/docs/teams-primitives`. Trims stale hand-maintained comparison tables from the docs intro and platform adapters overview. Those pages now link to `/adapters` and the generated official feature matrix. Adds contributing CTAs for building an adapter and listing a vendor-official one. Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
0334e97b62 |
chore(docs): upgrade geistdocs to 1.19.4 (#783)
Bumps `@vercel/geistdocs` in the docs app from 1.19.2 to 1.19.4 (to fix safari logo bug) |
||
|
|
4cc3445c6f |
fix(teams,slack): follow-up hardening for html and url parsing (#779)
Follow-up and hardening for two inbound parsers. - **Teams** — HTML-to-text conversion now strips tags until the output is stable, so nested or malformed markup can't leave a partial tag behind. A shared `stripHtmlTags` helper backs both the format converter and the Graph message converter (was three inline single-pass regexes). - **Slack** — the link-unfurl fallback bounds the length of bracketed URLs parsed from message text, avoiding a quadratic scan on adversarial input. Valid links are unaffected. Two changesets (`@chat-adapter/teams`, `@chat-adapter/slack`); no public-type change. Independent of #774/#775. |
||
|
|
fe4ed11ea9 |
docs: add XChat branding and clarify X vs XChat adapters (#777)
- Add a dedicated XChat speech-bubble logo for the docs hero and `/adapters` card - Point XChat docs and `adapters.json` at the new `xchat` icon instead of reusing `x` - Update the XChat OG image - Add reciprocal “X Adapter vs XChat Adapter” / “XChat Adapter vs X Adapter” sections on both docs pages - Rename remaining “X Chat” references to “XChat” in the adapter package README and comments Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
6f0d2f020a |
fix(slack): resolve outgoing mentions on the native streaming path (#755)
Fixes #754, reported by @alvarosevilla95. Slack's native streaming path appended renderer deltas as raw `markdown_text`, skipping the outgoing @name mention resolution that the post-and-edit fallback gets via postMessage/editMessage, so cached names rendered as plain text in the default mode. The fix runs committed `StreamingMarkdownRenderer` text through the existing `resolveOutgoingMentions` incrementally (line by line, tracking code-fence state) before each `streamer.append` delta is computed. Chunk safety falls out of the renderer's own semantics: incomplete lines are only committed inside fences (where mentions stay literal, matching the full-text resolver) or at inline-marker cuts, which cannot split a bare `@name`, so a mention spanning source chunks still reaches the resolver whole. The fallback path is untouched. Patch changeset included; both commits are DCO signed off. Six regression tests cover unique resolution, chunk-spanning mentions, mid-stream line commits, ambiguity, participant disambiguation, and code-fence literalness; 5 of the 6 fail without the fix (the sixth passes either way by design, since the broken path also leaves ambiguous mentions plain). Package suite: 626 passed (baseline 620, zero new failures); biome and typecheck clean. --------- Signed-off-by: Mohith Gajjela <109003762+Mohith26@users.noreply.github.com> |
||
|
|
85e3d22ba1 |
fix(chat): follow-up hardening and docs for agent read-tool scoping (#774)
Follow-up hardening and updated docs for the agent read-tool scoping in `createChatTools`. ## What changed - Wrap the remaining dispatch paths (modal submit/close, assistant-thread, assistant-context, app-home, app-context, member-joined) in `runInConversation` so read tools built inside those handlers inherit the active conversation. - Log a warning when a read runs with no resolvable scope, instead of failing open silently. - Keep scoping channel-level by default; add opt-in `strictScope: true` to confine a thread scope to that thread alone (rejects sibling threads on per-thread-ACL platforms like Discord and GitHub). - Update the AI SDK tools docs to cover the channel-level default, what `scope` does and does not do, and the `strictScope` opt-in. --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
16879fdc7a |
fix(whatsapp): model forwarded and product-inquiry context variants in WhatsAppInboundMessage (#723)
## Problem
`WhatsAppInboundMessage.context` is typed as:
```ts
/** Context for quoted replies */
context?: {
from: string;
id: string;
};
```
But Meta's Cloud API webhook sends **mutually exclusive context shapes**
depending on message origin ([text messages webhook
reference](https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/reference/messages/text)):
- **Quoted replies** (and interactions with a business message): `from`
+ `id`
- **Forwarded messages**: only `forwarded` ("only included if forwarded
5 times or less") or `frequently_forwarded` ("only included if forwarded
more than 5 times") — **no `id`, no `from`**
- **Catalog product inquiries**: `from` + `id` + `referred_product`
Because the type declares `id` required whenever `context` is present,
downstream code like `message.raw.message.context?.id.trim()`
type-checks cleanly and then throws a `TypeError` at runtime the first
time a user forwards a message to the bot — `context` exists, `id`
doesn't. We hit exactly this in production code building reply-to
handling on top of the adapter.
## Change
- All `context` fields are optional, and the forwarded/product-inquiry
fields (`forwarded`, `frequently_forwarded`, `referred_product`) are
added, with doc comments noting which variant each field belongs to.
- Changeset included (`@chat-adapter/whatsapp`: patch).
The adapter itself never reads `context` at runtime, so this is a
type-only change. Consumers who currently dereference `context.id`
unguarded will get a compile error after upgrading — intentionally,
since that code is a latent runtime crash on forwarded messages.
---------
Signed-off-by: Ricardo Rivero <ricardo@enzadon.com>
Co-authored-by: dancer <josh@afterima.ge>
|
||
|
|
a235e644f7 |
build(deps): bump actions/checkout from 7.0.0 to 7.0.1 (#769)
Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/actions/checkout/releases">actions/checkout's releases</a>.</em></p> <blockquote> <h2>v7.0.1</h2> <h2>What's Changed</h2> <ul> <li>skip running unsafe pr check if input is default by <a href="https://github.com/aiqiaoy"><code>@aiqiaoy</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2518">actions/checkout#2518</a></li> <li>trim only ascii whitespace for branch by <a href="https://github.com/aiqiaoy"><code>@aiqiaoy</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2521">actions/checkout#2521</a></li> <li>escape values passed to --unset by <a href="https://github.com/aiqiaoy"><code>@aiqiaoy</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2530">actions/checkout#2530</a></li> <li>Various dependency updates</li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/checkout/compare/v7...v7.0.1">https://github.com/actions/checkout/compare/v7...v7.0.1</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's changelog</a>.</em></p> <blockquote> <h1>Changelog</h1> <h2>v7.0.1</h2> <ul> <li>Skip running unsafe pr check if input is default by <a href="https://github.com/aiqiaoy"><code>@aiqiaoy</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2518">actions/checkout#2518</a></li> <li>Trim only ascii whitespace for branch by <a href="https://github.com/aiqiaoy"><code>@aiqiaoy</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2521">actions/checkout#2521</a></li> <li>Escape values passed to --unset by <a href="https://github.com/aiqiaoy"><code>@aiqiaoy</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2530">actions/checkout#2530</a></li> <li>Various dependency updates</li> </ul> <h2>v7.0.0</h2> <ul> <li>Block checking out fork PR for pull_request_target and workflow_run by <a href="https://github.com/aiqiaoy"><code>@aiqiaoy</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li> <li>Various dependency updates</li> </ul> <h2>v6.0.3</h2> <ul> <li>Fix checkout init for SHA-256 repositories by <a href="https://github.com/yaananth"><code>@yaananth</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li> <li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a href="https://github.com/yaananth"><code>@yaananth</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li> </ul> <h2>v6.0.2</h2> <ul> <li>Fix tag handling: preserve annotations and explicit fetch-tags by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li> </ul> <h2>v6.0.1</h2> <ul> <li>Add worktree support for persist-credentials includeIf by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li> </ul> <h2>v6.0.0</h2> <ul> <li>Persist creds to a separate file by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li> <li>Update README to include Node.js 24 support details and requirements by <a href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li> </ul> <h2>v5.0.1</h2> <ul> <li>Port v6 cleanup to v5 by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li> </ul> <h2>v5.0.0</h2> <ul> <li>Update actions checkout to use node 24 by <a href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li> </ul> <h2>v4.3.1</h2> <ul> <li>Port v6 cleanup to v4 by <a href="https://github.com/ericsciple"><code>@ericsciple</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li> </ul> <h2>v4.3.0</h2> <ul> <li>docs: update README.md by <a href="https://github.com/motss"><code>@motss</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li> <li>Add internal repos for checking out multiple repositories by <a href="https://github.com/mouismail"><code>@mouismail</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li> <li>Documentation update - add recommended permissions to Readme by <a href="https://github.com/benwells"><code>@benwells</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li> <li>Adjust positioning of user email note and permissions heading by <a href="https://github.com/joshmgross"><code>@joshmgross</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li> <li>Update README.md by <a href="https://github.com/nebuk89"><code>@nebuk89</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li> <li>Update CODEOWNERS for actions by <a href="https://github.com/TingluoHuang"><code>@TingluoHuang</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li> <li>Update package dependencies by <a href="https://github.com/salmanmkc"><code>@salmanmkc</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li> </ul> <h2>v4.2.2</h2> <ul> <li><code>url-helper.ts</code> now leverages well-known environment variables by <a href="https://github.com/jww3"><code>@jww3</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li> <li>Expand unit test coverage for <code>isGhes</code> by <a href="https://github.com/jww3"><code>@jww3</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li> </ul> <h2>v4.2.1</h2> <ul> <li>Check out other refs/* by commit if provided, fall back to ref by <a href="https://github.com/orhantoy"><code>@orhantoy</code></a> in <a href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/actions/checkout/commit/3d3c42e5aac5ba805825da76410c181273ba90b1"><code>3d3c42e</code></a> prep v7.0.1 release (<a href="https://redirect.github.com/actions/checkout/issues/2531">#2531</a>)</li> <li><a href="https://github.com/actions/checkout/commit/28802689a136bfcdb721715abd713740beecbe07"><code>2880268</code></a> escape values passed to --unset (<a href="https://redirect.github.com/actions/checkout/issues/2530">#2530</a>)</li> <li><a href="https://github.com/actions/checkout/commit/12cd2235efa0937479335606d7c3ac9f6c0973b1"><code>12cd223</code></a> trim only ascii whitespace for branch (<a href="https://redirect.github.com/actions/checkout/issues/2521">#2521</a>)</li> <li><a href="https://github.com/actions/checkout/commit/62661c4e71a304b2823ed026347b8d34c3eac541"><code>62661c4</code></a> skip running unsafe pr check if input is default (<a href="https://redirect.github.com/actions/checkout/issues/2518">#2518</a>)</li> <li><a href="https://github.com/actions/checkout/commit/e8d4307400f9427dba7cb98e488d6ab85f1cec5f"><code>e8d4307</code></a> Bump the minor-actions-dependencies group with 2 updates (<a href="https://redirect.github.com/actions/checkout/issues/2499">#2499</a>)</li> <li><a href="https://github.com/actions/checkout/commit/631c942040754b6e095e929c1677c07e10ed4f87"><code>631c942</code></a> eslint 9 (<a href="https://redirect.github.com/actions/checkout/issues/2474">#2474</a>)</li> <li><a href="https://github.com/actions/checkout/commit/4f1f4aec02e41874fa0262ea8ff5172d7978ad1e"><code>4f1f4ae</code></a> Bump actions/upload-artifact from 4 to 7 (<a href="https://redirect.github.com/actions/checkout/issues/2476">#2476</a>)</li> <li><a href="https://github.com/actions/checkout/commit/ba097532fb203f7e88c9c3c0b899b49469908a92"><code>ba09753</code></a> Bump actions/checkout from 6 to 7 (<a href="https://redirect.github.com/actions/checkout/issues/2488">#2488</a>)</li> <li><a href="https://github.com/actions/checkout/commit/b9e0990d219a03df7633c93f6f005a8fecbcab22"><code>b9e0990</code></a> Bump docker/login-action from 3.3.0 to 4.2.0 (<a href="https://redirect.github.com/actions/checkout/issues/2479">#2479</a>)</li> <li><a href="https://github.com/actions/checkout/commit/e8cb398be4a550817e382abf69e4c12c76fce1f2"><code>e8cb398</code></a> Bump docker/build-push-action from 6.5.0 to 7.2.0 (<a href="https://redirect.github.com/actions/checkout/issues/2478">#2478</a>)</li> <li>Additional commits viewable in <a href="https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1">compare view</a></li> </ul> </details> <br /> [](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) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
e542485196 |
build(deps): bump actions/setup-node from 6.4.0 to 7.0.0 (#768)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.4.0 to 7.0.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/actions/setup-node/releases">actions/setup-node's releases</a>.</em></p> <blockquote> <h2>v7.0.0</h2> <h2>What's Changed</h2> <h3>Enhancements:</h3> <ul> <li>Add cache-primary-key and cache-matched-key as outputs by <a href="https://github.com/gowridurgad"><code>@gowridurgad</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/1577">actions/setup-node#1577</a></li> <li>Migrate to ESM and upgrade dependencies by <a href="https://github.com/gowridurgad"><code>@gowridurgad</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/1574">actions/setup-node#1574</a></li> </ul> <h3>Bug fixes:</h3> <ul> <li>Remove dummy NODE_AUTH_TOKEN export by <a href="https://github.com/gowridurgad"><code>@gowridurgad</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/1558">actions/setup-node#1558</a></li> <li>Only use <code>mirrorToken</code> in <code>getManifest</code> if it's provided by <a href="https://github.com/deiga"><code>@deiga</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/1548">actions/setup-node#1548</a></li> </ul> <h3>Documentation updates:</h3> <ul> <li>Add documentation for publishing to npm with Trusted Publisher (OIDC) by <a href="https://github.com/chiranjib-swain"><code>@chiranjib-swain</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/1536">actions/setup-node#1536</a></li> <li>docs: Update restore-only cache documentation by <a href="https://github.com/priya-kinthali"><code>@priya-kinthali</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/1550">actions/setup-node#1550</a></li> <li>docs: Update caching recommendations to mitigate cache poisoning risks by <a href="https://github.com/chiranjib-swain"><code>@chiranjib-swain</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/1567">actions/setup-node#1567</a></li> </ul> <h3>Dependency update:</h3> <ul> <li>Upgrade <code>@actions/cache</code> to 5.1.0, log cache write denied by <a href="https://github.com/jasongin"><code>@jasongin</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/1569">actions/setup-node#1569</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/chiranjib-swain"><code>@chiranjib-swain</code></a> made their first contribution in <a href="https://redirect.github.com/actions/setup-node/pull/1536">actions/setup-node#1536</a></li> <li><a href="https://github.com/deiga"><code>@deiga</code></a> made their first contribution in <a href="https://redirect.github.com/actions/setup-node/pull/1548">actions/setup-node#1548</a></li> <li><a href="https://github.com/jasongin"><code>@jasongin</code></a> made their first contribution in <a href="https://redirect.github.com/actions/setup-node/pull/1569">actions/setup-node#1569</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/setup-node/compare/v6...v7.0.0">https://github.com/actions/setup-node/compare/v6...v7.0.0</a></p> <h2>v6.5.0</h2> <h2>What's Changed</h2> <ul> <li>Update <code>@actions/cache</code> to 5.1.0 and add security overrides for undici and fast-xml-parser by <a href="https://github.com/HarithaVattikuti"><code>@HarithaVattikuti</code></a> in <a href="https://redirect.github.com/actions/setup-node/pull/1579">actions/setup-node#1579</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/actions/setup-node/compare/v6.4.0...v6.5.0">https://github.com/actions/setup-node/compare/v6.4.0...v6.5.0</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/actions/setup-node/commit/820762786026740c76f36085b0efc47a31fe5020"><code>8207627</code></a> Migrate to ESM and upgrade dependencies (<a href="https://redirect.github.com/actions/setup-node/issues/1574">#1574</a>)</li> <li><a href="https://github.com/actions/setup-node/commit/04be95cf3511ea51ebf9f224ddfb99cc7ab87cd4"><code>04be95c</code></a> Add cache-primary-key and cache-matched-key as outputs (<a href="https://redirect.github.com/actions/setup-node/issues/1577">#1577</a>)</li> <li><a href="https://github.com/actions/setup-node/commit/7c2c68d20d402ed6a201ada70a81341941093140"><code>7c2c68d</code></a> docs: Update caching recommendations to mitigate cache poisoning risks (<a href="https://redirect.github.com/actions/setup-node/issues/1567">#1567</a>)</li> <li><a href="https://github.com/actions/setup-node/commit/6a61c0375d66246de94630495909f12cf8dac84d"><code>6a61c03</code></a> Merge pull request <a href="https://redirect.github.com/actions/setup-node/issues/1569">#1569</a> from jasongin/update-actions-cache-5.1.0</li> <li><a href="https://github.com/actions/setup-node/commit/30eb73b41ded577900c1ebf968ef95cdf8f7434f"><code>30eb73b</code></a> Resolve high-severity audit issues</li> <li><a href="https://github.com/actions/setup-node/commit/4e1a87a501d0302f99e30e2748568adcb388d09f"><code>4e1a87a</code></a> Update dist</li> <li><a href="https://github.com/actions/setup-node/commit/360237f0c01778d0c17291f75c56d6feae4f7574"><code>360237f</code></a> Strict equality</li> <li><a href="https://github.com/actions/setup-node/commit/4f8aac5beb2f0854bc79651567a18c67eb0b9de3"><code>4f8aac5</code></a> Bump <code>@actions/cache</code> to 5.1.0, log cache write denied</li> <li><a href="https://github.com/actions/setup-node/commit/f4a67bbeca970f103397d3d2b9462cf787cd2980"><code>f4a67bb</code></a> Only use <code>mirrorToken</code> in <code>getManifest</code> if it's provided (<a href="https://redirect.github.com/actions/setup-node/issues/1548">#1548</a>)</li> <li><a href="https://github.com/actions/setup-node/commit/0355742c943ddb13ca8a6b700f824231caa91e75"><code>0355742</code></a> Remove dummy NODE_AUTH_TOKEN export (<a href="https://redirect.github.com/actions/setup-node/issues/1558">#1558</a>)</li> <li>Additional commits viewable in <a href="https://github.com/actions/setup-node/compare/48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e...820762786026740c76f36085b0efc47a31fe5020">compare view</a></li> </ul> </details> <br /> [](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) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
b674923849 |
fix(x): harden CRC challenge token validation (#775)
Follow-up hardening for the X webhook CRC challenge. The CRC challenge endpoint returned an HMAC over any caller-supplied `crc_token`, using the same construction and secret as POST webhook signature verification. That let a caller have an arbitrary body signed via the public GET challenge and replay the response as `x-twitter-webhooks-signature` on a forged POST. `crc_token` is now restricted to X's opaque token shape before signing. A webhook event body is JSON and can never match, so a CRC response can no longer double as a POST event signature. Both base64 and base64url alphabets are accepted so a legitimate token is never rejected. `verifySignature` is unchanged. Regression tests: a webhook-shaped `crc_token` is rejected with 400 and no `response_token`; a signature the challenge can produce (for a valid token) verifies only against a body equal to that token, which is not event JSON, so no handler is dispatched. 216 adapter-x tests pass. --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
0642ce335f |
docs: document WhatsApp typing indicator support (#772)
This PR updates the WhatsApp adapter documentation to reflect the existing typing indicator support through `thread.startTyping()`. The feature was already implemented in the adapter but was missing from the documentation and feature matrix, making it difficult for users to discover. Fixes #771 |
||
|
|
c311827945 |
fix(slack): preserve channel id and normalize frequently hallucinated link format (#756)
This change fixes two conversion issues in `slackMrkdwnToMarkdown`, which runs on every incoming Slack message. **1. Preserve channel IDs in labeled channel tokens** Previously the channel ID was dropped during conversion, so agents reading `message.text` had no ID to pass to channel tools. Labeled tokens now keep both the readable name and the ID: ``` <#C042BLND6R6|general> → #general (C042BLND6R6) <#C042BLND6R6> → #C042BLND6R6 (unchanged) ``` Bare channel mentions are still enriched with the channel name via `conversations.info`, so incoming messages end up with both the name and the ID either way. **2. Normalize the commonly hallucinated link order** AI models frequently emit Slack links with the label and URL swapped. These are now normalized before Markdown conversion: ``` <docs|https://example.com> → [docs](https://example.com) ``` Valid links whose display label is itself a URL (common with Slack's truncated link displays) are detected and left in the correct order: ``` <https://a.com|https://b.com> → [https://b.com](https://a.com) ``` --------- Signed-off-by: Sergey Bekrin <sergey@bekrin.me> Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com> Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
629e655578 |
fix(telegram): combine incoming media groups (#760)
- buffer incoming Telegram updates that share a `media_group_id` and dispatch them once the album settles - coordinate through the configured `StateAdapter` so separate serverless instances still produce one message - preserve the shared caption and order attachments by Telegram message ID --------- Signed-off-by: onmax <maximogarciamtnez@gmail.com> |
||
|
|
470b6af94b |
chore(release): version packages (#748)
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @chat-adapter/slack@4.36.0 ### Minor Changes -@chat-adapter/messenger@4.36.0 @chat-adapter/gchat@4.36.0 @chat-adapter/github@4.36.0 chat@4.36.0 @chat-adapter/web@4.36.0 @chat-adapter/discord@4.36.0 @chat-adapter/state-redis@4.36.0 @chat-adapter/whatsapp@4.36.0 @chat-adapter/teams@4.36.0 @chat-adapter/state-memory@4.36.0 @chat-adapter/telegram@4.36.0 @chat-adapter/slack@4.36.0 @chat-adapter/state-ioredis@4.36.0 @chat-adapter/shared@4.36.0 create-chat-sdk@0.2.1 @chat-adapter/tests@4.36.0 @chat-adapter/linear@4.36.0 @chat-adapter/state-pg@4.36.0 @chat-adapter/twilio@4.36.0 @chat-adapter/x@4.36.0 |
||
|
|
d453f75a0e |
ci: skip the changeset check on the release pr (#765)
## summary the release pr consumes every changeset and bumps the versions, which is the exact state `changeset status` reports as an error, so the check always fails there |
||
|
|
7714d766e6 |
fix: remove duplicate lockfile entries (#766)
## summary `pnpm-lock.yaml` on main has duplicated `nanoid@3.3.16` and `postcss@8.5.25` keys after #740 and #744 merged back to back, so `pnpm install --frozen-lockfile` fails and every ci job on main is red ``` ERR_PNPM_BROKEN_LOCKFILE duplicated mapping key (10069:3) ``` the duplicate blocks are byte identical, so this deletes the extras and changes no versions. regenerating the lockfile was not an option: `.npmrc` sets `min-release-age=2`, which re-resolves to older packages and would have reverted both bumps |
||
|
|
7cda0e008e |
build(deps-dev): bump postcss from 8.5.16 to 8.5.18 (#744)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.16 to 8.5.18. <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.18</h2> <ul> <li>Restricted loading previous source maps file to the <code>opts.from</code> folder for security reasons (use <code>unsafeMap: true</code> to disable the check).</li> </ul> <h2>8.5.17</h2> <ul> <li>Fixed <code>Maximum call stack size exceeded</code> error.</li> <li>Fixed Prototype hijacking for <code>postcss.fromJSON()</code>.</li> <li>Fixed <code>Input#origin()</code> for unmapped end position (by <a href="https://github.com/chatman-media"><code>@chatman-media</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.18</h2> <ul> <li>Restricted loading previous source maps file to the <code>opts.from</code> folder for security reasons (use <code>unsafeMap: true</code> to disable the check).</li> </ul> <h2>8.5.17</h2> <ul> <li>Fixed <code>Maximum call stack size exceeded</code> error.</li> <li>Fixed Prototype hijacking for <code>postcss.fromJSON()</code>.</li> <li>Fixed <code>Input#origin()</code> for unmapped end position (by <a href="https://github.com/chatman-media"><code>@chatman-media</code></a>).</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/postcss/postcss/commit/4c0d194c136fd374495d0993c890d794cab65b81"><code>4c0d194</code></a> Release 8.5.18 version</li> <li><a href="https://github.com/postcss/postcss/commit/92b4e7891ec7b811821d01acc8aa0f010caf41e2"><code>92b4e78</code></a> Update dependencies</li> <li><a href="https://github.com/postcss/postcss/commit/95663d3eb7ba26f4854dd19d3b4f4425760cf56c"><code>95663d3</code></a> Limit where source map can be loaded for security reasons</li> <li><a href="https://github.com/postcss/postcss/commit/74e25ae9f4efaa56a41a449064a655d7da78072c"><code>74e25ae</code></a> Release 8.5.17 version</li> <li><a href="https://github.com/postcss/postcss/commit/d1518afd5a88f42728b30b87f8917210f363f9f1"><code>d1518af</code></a> Fix Maximum call stack size exceeded error</li> <li><a href="https://github.com/postcss/postcss/commit/2421312ffea96ba77b35ce24a1b2d9c2e22b5e83"><code>2421312</code></a> Fix linter</li> <li><a href="https://github.com/postcss/postcss/commit/a50352c583df991710f92ccac25b36304695161a"><code>a50352c</code></a> Fix CI</li> <li><a href="https://github.com/postcss/postcss/commit/33948f0969bb858acdd52c9692e3a785a3ed0a73"><code>33948f0</code></a> Prevent prototype hijacking in fromJSON</li> <li><a href="https://github.com/postcss/postcss/commit/2131909351161cd2c5fc2be58b14919a873ea824"><code>2131909</code></a> Update dependencies</li> <li><a href="https://github.com/postcss/postcss/commit/93440abcca92793b31c5d1fdf5f2da7b58b27599"><code>93440ab</code></a> Fix non-closed <code>\<div align="center"></code> in README (<a href="https://redirect.github.com/postcss/postcss/issues/2110">#2110</a>)</li> <li>Additional commits viewable in <a href="https://github.com/postcss/postcss/compare/8.5.16...8.5.18">compare view</a></li> </ul> </details> <br /> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
379842f2b2 |
build(deps): bump next from 16.2.6 to 16.2.11 (#740)
Bumps [next](https://github.com/vercel/next.js) from 16.2.6 to 16.2.11. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/vercel/next.js/releases">next's releases</a>.</em></p> <blockquote> <h2>v16.2.11</h2> <p>This release contains security fixes for the following advisories:</p> <p>High:</p> <ul> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-m99w-x7hq-7vfj">Denial of Service in App Router using Server Actions</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-6gpp-xcg3-4w24">Middleware / Proxy bypass in App Router applications using Turbopack and single locale</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-p9j2-gv94-2wf4">Server-Side Request Forgery in rewrites via attacker-controlled destination hostname</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-89xv-2m56-2m9x">Server-Side Request Forgery in Server Actions on custom servers</a></li> </ul> <p>Moderate:</p> <ul> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-68g3-v927-f742">Cache confusion of response bodies for requests with bodies</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-4633-3j49-mh5q">Cache confusion of response bodies for requests with bodies containing invalid UTF-8 byte sequences</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-q8wf-6r8g-63ch">Denial of Service in the Image Optimization API using SVGs</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-955p-x3mx-jcvp">Unauthenticated disclosure of internal Server Function endpoints</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-4c39-4ccg-62r3">Unbounded Server Action payload in Edge runtime</a></li> </ul> <h2>v16.2.10</h2> <p>Contains no changes except publishing <code>@next/swc-wasm-web</code> which was accidentally not published since 16.2.4.</p> <h2>v16.2.9</h2> <p>Empty release to ensure <code>next@latest</code> points at a stable release. Next.js only allows publishing with Trusted Publishing enabled. In order to fix NPM dist-tags, we have to release a new version. Updating dist-tags is not possible with Trusted Publishing.</p> <h2>v16.2.8</h2> <p>Release with no changes in an attempt to fix <code>next@latest</code> pointing at a prerelease version.</p> <h2>v16.2.7</h2> <blockquote> <p>[!NOTE] This release is backporting bug fixes. It does <strong>not</strong> include all pending features/changes on canary.</p> </blockquote> <h3>Core Changes</h3> <ul> <li>Backport documentation fixes for v16.2 (<a href="https://redirect.github.com/vercel/next.js/issues/93804">#93804</a>)</li> <li>[backport] Patch <code>playwright-core</code> to resolve <code>_finishedPromise</code> on <code>requestFailed</code> (<a href="https://redirect.github.com/vercel/next.js/issues/93920">#93920</a>)</li> <li>[backport] Fix dev mode hydration failure when page is served from HTTP cache (<a href="https://redirect.github.com/vercel/next.js/issues/93492">#93492</a>)</li> <li>[backport] Fix catch-all <code>router.query</code> corruption with <code>basePath</code> + <code>rewrites</code> (<a href="https://redirect.github.com/vercel/next.js/issues/93917">#93917</a>)</li> <li>[backport] Encode non-ASCII characters in cache tags at construction (<a href="https://redirect.github.com/vercel/next.js/issues/93918">#93918</a>)</li> <li>[backport] Fix server action forwarding loop with middleware rewrites (<a href="https://redirect.github.com/vercel/next.js/issues/93919">#93919</a>)</li> <li>[backport] Turbopack: switch from base40 to base38 hash encoding (<a href="https://redirect.github.com/vercel/next.js/issues/93932">#93932</a>)</li> <li>[ci] Disable hanging node 24 typescript tests on 16.2 backport branch (<a href="https://redirect.github.com/vercel/next.js/issues/94164">#94164</a>)</li> <li>[backport] Fix "type: module" in project dir when using standalone or adapters (<a href="https://redirect.github.com/vercel/next.js/issues/94050">#94050</a>)</li> <li>[backport] Propagate adapter preferred regions (<a href="https://redirect.github.com/vercel/next.js/issues/94200">#94200</a>)</li> <li>[16.2.x] Don't drop <code>FormData</code> entries (<a href="https://redirect.github.com/vercel/next.js/issues/94240">#94240</a>)</li> <li>[backport] feat(turbopack): add LocalPathOrProjectPath PostCSS config resolution (<a href="https://redirect.github.com/vercel/next.js/issues/94284">#94284</a>)</li> </ul> <h3>Credits</h3> <p>Huge thanks to <a href="https://github.com/eps1lon"><code>@eps1lon</code></a>, <a href="https://github.com/icyJoseph"><code>@icyJoseph</code></a>, <a href="https://github.com/unstubbable"><code>@unstubbable</code></a>, <a href="https://github.com/mischnic"><code>@mischnic</code></a>, <a href="https://github.com/bgw"><code>@bgw</code></a>, <a href="https://github.com/timneutkens"><code>@timneutkens</code></a>, and <a href="https://github.com/lukesandberg"><code>@lukesandberg</code></a> for helping!</p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/vercel/next.js/commit/9beca0821cf4606ae33466ed6f4fc75f2887a4da"><code>9beca08</code></a> v16.2.11</li> <li><a href="https://github.com/vercel/next.js/commit/3c48c7af78f2c01691065cb303da1b107a2c8617"><code>3c48c7a</code></a> [16.x] Fix Turbopack middleware matcher with i18n single locale</li> <li><a href="https://github.com/vercel/next.js/commit/ac1eff3f7a7285176396ecc69c3b160a3d6ad1a2"><code>ac1eff3</code></a> [16.x] Improve performance of checking valid MPA form submissions</li> <li><a href="https://github.com/vercel/next.js/commit/9a4651e754f70b12e397694ffc41f44c3ba8cc17"><code>9a4651e</code></a> [16.x] Enforce <code>serverActions.bodySizeLimit</code> for Server Actions in Edge runtime</li> <li><a href="https://github.com/vercel/next.js/commit/b51206321854193208c0805ba42acc49287f942b"><code>b512063</code></a> [16.x] Set correct origin for internal redirects in custom server</li> <li><a href="https://github.com/vercel/next.js/commit/d3033266c6dff23f7be71e19341fe3a8c6e2c599"><code>d303326</code></a> [16.x] Ensure exotic rewrite param values are properly encoded</li> <li><a href="https://github.com/vercel/next.js/commit/73b94872bc343d09494b50394d8c08eb9fc8e56a"><code>73b9487</code></a> [16.x] fix(fetch-cache): key fetch(Request, init) by the effective request</li> <li><a href="https://github.com/vercel/next.js/commit/bf9d17fb30501829f6fd7c0ee8e44e2794565742"><code>bf9d17f</code></a> [16.x] fix(incremental-cache): byte-exact fetch cache key for binary bodies</li> <li><a href="https://github.com/vercel/next.js/commit/fe28768f533582ea8f6ee7d7a7498715927d45f5"><code>fe28768</code></a> [16.x] fix(next/image): improve performance of detectContentType()</li> <li><a href="https://github.com/vercel/next.js/commit/d8afb8d550ac4ac5c106ea1410c3af43eaf1d469"><code>d8afb8d</code></a> [16.x] Performance improvements when decoding React Server function payloads</li> <li>Additional commits viewable in <a href="https://github.com/vercel/next.js/compare/v16.2.6...v16.2.11">compare view</a></li> </ul> </details> <br /> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
0e62da79a4 |
chore(docs): use Geist heading tokens on adapter pages (#764)
Follow-up to #762 — this commit was left out when that PR merged (Docs-only styling change) Signed-off-by: christopherkindl <53372002+christopherkindl@users.noreply.github.com> |
||
|
|
3ae34b3ed1 |
feat(docs): migrate the homepage to geistdocs 1.19 and the Geist design system (#762)
Third repo in the design sync, after `vercel/geistdocs#216`/`#218` and `vercel/flags#457`. Upgrades the docs site to `@vercel/geistdocs@1.19.2` and brings the homepage onto the Geist design system. `apps/docs` is `private: true`, so no changeset. ## Dependency `1.19.2` peers on `next: ^16.2.11` and the app pinned `16.2.6`, so **next moves to `16.2.12`** alongside it — without that pnpm reports an unmet peer. Installed via `pnpm add --save-exact` per AGENTS.md. All 20 geistdocs subpaths this app imports still exist in 1.19.2; no API breakage. The footer needed no work: 1.16 already shipped the prop-less Vercel-directory `<Footer />`. ## Layout — `home-grid.css` is gone Deleted `app/styles/home-grid.css` (368 lines) and its `global.css` import, and rebuilt each section on `grid-cols-12` / `col-span-*`: | section | before (CSS) | after | |---|---|---| | OSS stats | 2×2 → 4×1 @768 | `col-span-6 min-[768px]:col-span-3` | | Features | 2-up + full-width 3rd → 3×1 @961 | `col-span-12 sm:col-span-6 lg:col-span-4` | | Code | stacked → sidebar 1/3 + code 2/3 @961 | `lg:col-span-8` / `lg:col-span-4`, pinned with `col-start` + `row-start` | | Integrations | 1×5 → tall left + 2×2 @961 | `lg:col-span-4 lg:row-span-2` + four `lg:col-span-4` | The code section needs explicit `col-start`/`row-start` because the sidebar follows the code in the DOM but sits left of it from `lg`. Other layout changes: - **Single gutter at the page root** (`mx-auto w-full max-w-[1448px] px-4 sm:px-6`); removed the per-section horizontal padding that duplicated it, so every section's content lands on the navbar/footer content edge. - **Content widened 1114px → 1400px**, the navbar's content span (1448 − 2×24). - **Bottom gap above the footer trimmed ~320px → ~176px** — layout `pb-32` → `pb-16` and page `pb-24 sm:pb-36` → `pb-12 sm:pb-16`. Three paddings were stacking. The 768px stats breakpoint is preserved with `min-[768px]:` — there's no Tailwind equivalent here (`md`=601, `lg`=961) and four KPI columns at 601px would be ~140px each. ## Design — ported from vercel.com/ai-sdk Read off the flagged source in `front/apps/vercel-marketing/.../ai-sdk`, not the live site. - **Code showcase tabs** → the `SlidingTabs` primitive: pill labels with an animated indicator, full keyboard nav (arrows/Home/End, roving tabindex), and an invisible-bold label so the tab doesn't shift width when it bolds. Four tabs per group with dot pagination for the rest, tabs above the code block. Copied into `components/ui/sliding-tabs.tsx` with `cn` rewired and the `no-scrollbar` utility inlined (geistdocs doesn't define it). - **"Scale with confidence"** → heading and paragraph on one bottom-aligned row (cols 1–4 / 8–12), then four bordered cards `col-span-12 md:col-span-6 lg:col-span-3`. Type mapped from their primitives: `SectionHeading size="48"` → `text-heading-40 lg:text-heading-48`, `SectionParagraph size="18"` → `text-copy-16 lg:text-copy-18`. - **Feature row** → icon + muted eyebrow over a prominent statement. Note this **inverts the previous emphasis**: the heading is now the small muted label and the description the larger line, matching the reference. Icons come from geistdocs' own set so they match Geist's line weight: `IconLinked`, `IconWorkflow`, `IconAcronymTs`. - **Get-started install snippet** → the shared `CommandPrompt`, with its buttons on one row from `lg`. - Remaining headings converted to `text-heading-*`. - Navbar logo drops `height={22}` to take `LogoChatSdk`'s new 18px default (renders 106.9×22 → 87.4×18). ## Two fixes worth calling out **`lib/utils.ts` — `cn` was silently dropping typography.** Geist's `text-copy-*`/`text-heading-*` share the `text-` prefix with colour utilities, so stock `tailwind-merge` classifies them as colours and drops the size whenever both appear in one `cn()` call. geistdocs ships a `cn` that registers them as `font-size` for exactly this reason but doesn't export it, so the config is replicated here. This was a latent bug across the app, not just the new code. **`Analytics`/`SpeedInsights` moved out of the `"use client"` provider** into the server layout. Both emit `<script>`, and scripts rendered inside a client tree never execute — so analytics wasn't firing on client navigations. React 19.2.7 (pulled in by this bump) now warns about it; the bug predates it. ## Verification - `pnpm --filter docs build` passes (270 pages), `tsc --noEmit` clean, `biome check` clean. - Rendered output spot-checked for the tab strip, dot pagination, card classes, and feature icons. **`pnpm validate` could not be run** — it needs Node ≥20.19 and this machine is on v20.11.1 (`pnpm check` dies on `styleText` from `node:util`). Biome, tsc and build were run directly instead, but the knip and test legs are unrun and should be confirmed in CI. Signed-off-by: christopherkindl <53372002+christopherkindl@users.noreply.github.com> |
||
|
|
caa63253c5 |
feat(x): add XChat encrypted messaging support (#745)
## summary new `@chat-adapter/xchat` adapter for XChat, X's encrypted messaging. write bot logic once and hold encrypted 1:1 and group conversations like the other Chat SDK adapters — all crypto handled inside the adapter via `@xdevplatform/chat-xdk` (wasm), all REST via the typed `@xdevplatform/xdk` client. ## background: chat-xdk [`@xdevplatform/chat-xdk`](https://www.npmjs.com/package/@xdevplatform/chat-xdk) is the official XChat cryptography SDK — a Rust core compiled to WebAssembly that implements the XChat encryption protocol. it handles per-conversation symmetric keys and key exchange, message encryption/decryption, event signing and signature verification, and encrypted media (secretstream). the bot's private keys live in a PIN-protected [Juicebox](https://juicebox.xyz) store (secret-shared across independent realms), so no key material sits in env vars or on disk — the adapter unlocks with a PIN at startup. this adapter is the glue: chat-xdk produces and consumes the encrypted envelopes, the typed `@xdevplatform/xdk` client moves them over the X API, and everything is normalized to the Chat SDK's `Thread`/`Message` model. what it supports: - encrypted send/receive in DMs and groups (webhook push + polling), signature verification on by default - mention detection from structured mention entities, swipe-replies to the bot, and a plain-text `@handle` fallback; group replies go out as quoted replies with TTL propagated - `openDM(userId)`: starts (or reuses) an encrypted 1:1 — cached/history-recovered conversation key, else a full key exchange so the bot can message first - media both ways: inbound attachments with lazy download+decrypt, outbound encrypted (secretstream) via the 3-step upload flow - edit and delete of the bot's own messages: edits are encrypted events targeting the original's sequence id; deletes are locally signed delete-for-all actions recipients verify - reactions in and out, typing keep-alive while handlers run, configurable group welcome message - read receipts sent per delivered inbound message (`sendReadReceipts`, default on) - cards by degradation: text + tappable entities, link buttons as `label: url` lines, primary link as a URL preview attachment with optional encrypted banner key design decisions: - mdast stays the canonical format; markdown passes through as raw text (XChat clients render plain text — no markdown), with URLs and @mentions made tappable via entity spans and tables degraded to ASCII code blocks - thread ids are `xchat:{conversationId}` (groups `g…`, 1:1s the sorted participant pair) - the first edit of a fresh message is age-gated (`editSafetyDelayMs`, default 5000ms): receiving clients park an edit whose original hasn't arrived, leaving the message permanently invisible — the gate prevents that race - undecryptable or unverified events are dropped, never delivered as empty messages - no core changes: the adapter implements the standard `Adapter` interface only also includes the `chat/adapters` catalog entry, docs page (with OG image), `adapters.json` registry entry, and `create-chat-sdk` scaffold spec, modeled on the `x` adapter's registration. <details><summary>usage</summary> ```bash XCHAT_BOT_TOKEN=... # OAuth2 user access token (identity resolved from GET /2/users/me) XCHAT_PIN=... # Juicebox PIN that unlocks the bot's keys X_CONSUMER_SECRET=... # optional: verifies webhook signatures ``` ```typescript import { Chat } from "chat"; import { createXchatAdapter } from "@chat-adapter/xchat"; import { createMemoryState } from "@chat-adapter/state-memory"; const bot = new Chat({ userName: "mybot", adapters: { xchat: createXchatAdapter() }, // credentials from env state: createMemoryState(), }); // DMs always bot.onDirectMessage(async (thread, message) => { await thread.post(`You said: ${message.text}`); }); // group chats when the bot is @mentioned bot.onNewMention(async (thread, message) => { await thread.post("You rang?"); }); // wire the webhook (e.g. a Next.js route) export async function POST(request: Request) { return bot.webhooks.xchat(request); } ``` </details> testing: 109 unit tests, including real-wasm-crypto round trips against vendored fixture vectors (decrypt + signature verification, webhook delivery, read receipts, edit age-gating, signed deletes). verified live against production XChat: DMs, group mentions, media, reactions, edits, deletes, openDM, cards. note on the lockfile: `@xdevplatform/xdk@0.6.6` was published <48h ago, so it was resolved with a one-shot `--config.minimumReleaseAge=0` override; the locked integrity hash was verified against the npm registry. the repo policy file is untouched. --------- Co-authored-by: dancer <josh@afterima.ge> |
||
|
|
53bf73db22 |
fix(telegram): preserve media identity and MIME metadata (#752)
## Summary Preserve Telegram's stable `file_unique_id` alongside the current downloadable `file_id` in normalized attachment metadata. Telegram photo attachments now report `image/jpeg`, including rich-message photos. This keeps adapter normalization in `@chat-adapter/telegram`; deduplication remains consumer-owned. After upgrading to the release containing this patch, Calories can remove `patches/@chat-adapter__telegram@4.35.0.patch` while retaining its perceptual-hash fallback for recompressed images. Signed-off-by: onmax <maximogarciamtnez@gmail.com> |
||
|
|
3c37cfbc15 |
fix(teams): authenticate protected inline attachments (#749)
## Summary Authenticates connector-hosted Teams inline attachments through the configured Bot Framework client, so `message.attachments[].fetchData()` can retrieve protected content. Teams file download cards use their direct `content.downloadUrl` anonymously, and serialized attachments reconstruct the same routing during rehydration. Bot credentials are limited to non-redirecting HTTPS requests whose origin exactly matches the Activity connector origin. Cross-origin URLs, HTTP URLs, and file-card download URLs never enter the authenticated client path. File-card MIME inference covers common image and text formats plus PDF, XLS, and XLSX attachments. The implementation follows [Microsoft's inline-image access-token sample](https://learn.microsoft.com/en-us/samples/officedev/microsoft-teams-samples/officedev-microsoft-teams-samples-bot-file-upload-nodejs/) and [Teams file-card contract](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/bots-filesv4). Signed-off-by: onmax <maximogarciamtnez@gmail.com> |
||
|
|
b547f45842 |
fix(chat): stop treating email addresses as bot mentions (#761)
## summary a message containing an email address like `jane@acme.com` was treated as a mention of a bot named `acme`, so the bot engaged on every pasted colleague email `detectMention` now requires the `@` not to follow a word character: ```ts `(?<!\\w)@${escapeRegex(botUserName)}(?![\\w-])` ``` - applies to both the username and the user id pattern - an email local part always ends in a word character, so `jane@acme.com`, `foo.bar@acme.com`, `foo-bar@acme.com` and url userinfo are all excluded - real mentions are unaffected: start of a message, after a space, after punctuation like `(` or `:`, and after an ellipsis fixes #759 |
||
|
|
a8867a0abb |
docs(adapters): add QQ Bot and WeCom community adapters (#753)
Adds two community platform adapters to the docs and `adapters.json` registry: - `@agentor/chat-qq` — QQ Bot. WebSocket or webhook (Ed25519) modes; QQ DM, group, and text-channel scenes; rich media. - `@agentor/chat-wecom` — WeCom (企业微信). Group webhook bots, smart bots (callback or WebSocket), and apps; WeCom Template Cards (5 types) and AES-256-CBC callback encryption. Follows the community-adapter flow: docs MDX pages, `meta.json`, `adapters.json` entries, and `VALID_DOC_PACKAGES`. Community-only adapters intentionally omit a `chat/adapters` catalog entry, a `create-chat-sdk` scaffold-spec, and a changeset. Signed-off-by: Demo Macro <abc@imst.xyz> |
||
|
|
0153a39f7b |
feat(modals): add DateInput and NumberInput modal children (#757)
`ModalChild` is `TextInput | Select | ExternalSelect | RadioSelect | Text | Fields` — there is no date or number primitive. A bot collecting a renewal date or a quantity has to render a text input with a `YYYY-MM-DD` hint and validate the string on submit, on every platform, even though neither platform is the constraint: - Slack Block Kit has a native [`datepicker`](https://docs.slack.dev/reference/block-kit/block-elements/date-picker-element) and [`number_input`](https://docs.slack.dev/reference/block-kit/block-elements/number-input-element). - Adaptive Cards has `Input.Date` and `Input.Number`, both already exported by `@microsoft/teams.cards`. One addition to the union lifts both surfaces. `ModalSubmitEvent.values` stays `Record<string, string>`, so this is additive for existing handlers. ## Changes - `DateInput` / `NumberInput` element types, builders, and options in `packages/chat/src/modals.ts`, added to `ModalChild` + `VALID_MODAL_CHILD_TYPES`. - JSX/React support: props, component overloads, `modalComponentMap`, and `fromReactModalElement` branches. - Slack renderer: `datepicker` (`initial_date`, `placeholder`) and `number_input` (`is_decimal_allowed`, `initial_value`, `min_value`, `max_value` — Slack takes these as strings). - Teams renderer: `Input.Date` / `Input.Number`, in both `modals.ts` (`@microsoft/teams.cards`) and the dependency-free `modals-primitives`. - Docs: `docs/modals.mdx` component tables and `docs/api/modals.mdx` reference + `ModalChild` table. - Changeset (`chat`, `@chat-adapter/slack`, `@chat-adapter/teams`: minor). ### Two runtime decode gaps this had to close - Slack reports a datepicker as `selected_date`, not `value`, so view-submission flattening now reads `value ?? selected_date ?? selected_option?.value`. `number_input` already arrives as `value`. - Teams' `Input.Number` submits a JSON **number**, which the previous `typeof val === "string"` filter dropped silently. Numbers are now stringified in both `parseDialogSubmitValues` and `parseTeamsDialogSubmitValues`. This applies to any numeric value a Teams dialog submits, not only `Input.Number` — a key that used to be absent from `event.values` is now present as a string. Called out in the changeset; one existing test updated. Non-scalar values are still dropped. ### Deliberate asymmetries - `DateInput` has no `min`/`max` — Slack's `datepicker` has no bounds, and a prop that silently does nothing on one platform is worse than its absence. - `NumberInput.decimal` maps to Slack's required `is_decimal_allowed`. Adaptive Cards has no decimal switch, so Teams accepts decimals either way; this is called out in the docs. - A `DateInput` `initialValue` that is not a real `YYYY-MM-DD` date is dropped with a warning instead of forwarded. Slack rejects a malformed `initial_date` by failing the entire `views.open` with `invalid_arguments` — the modal never opens, and the error surfaces as a JSON pointer rather than anything actionable. Adaptive Cards just renders the field empty, so forwarding verbatim would make the same modal work on Teams and die on Slack. The drop matches how `filterModalChildren` handles unsupported children. Validation round-trips through `Date` because it rolls impossible dates over (`2026-02-31` → Mar 3) instead of rejecting them. Signed-off-by: CamdenA21 <camden@sandstone.com> |
||
|
|
c5d86b103e |
feat(chat): scope agent read tools to the active conversation (#751)
built-in agent read tools now stay inside the conversation they are handling, so a thread or channel id the model supplies that resolves elsewhere is rejected before the adapter is called - `Chat` tracks the conversation being handled across message, action, slash command and reaction dispatch, using `AsyncLocalStorage` - read tools (`fetchMessages`, `fetchChannelMessages`, `fetchThread`, `listThreads`, `getThreadParticipants`, `getChannelInfo`) inherit that conversation, so existing handlers get this with no code change - scoping is per channel, so an agent can still follow other threads in its own conversation - pass `scope` to set it explicitly, or `scope: false` for workspace-wide reads this brings read tools in line with the least-privilege defaults write tools already have, where `needsApproval` is on unless you opt out **not breaking:** `scope` is optional and every existing call site keeps working. agents that run outside a handler, such as a queued job or a resumed workflow step, have no conversation to inherit and should pass `scope` ## test plan - read tools reject out-of-conversation ids and still serve in-conversation ones, per tool - the conversation is inherited correctly through message, action, slash command and reaction dispatch - concurrent conversations stay isolated, so one agent cannot inherit another's scope - an explicit `scope` overrides the handled conversation, and `scope: false` restores workspace-wide reads - ids resolve through `adapter.channelIdFromThreadId`, verified against the slack, teams, google chat, discord, telegram and whatsapp id shapes - `pnpm validate` clean: workspace tests, typecheck, lint, knip and build all pass |
||
|
|
257a32d01c |
fix(teams): classify group chats by conversation type (#746)
Fixes `a:`-prefixed Teams group chats being treated as DMs, so they use non-DM routing and buffered responses. [Microsoft defines conversation IDs as opaque strings and `conversationType` as the channel-provided conversation discriminator](https://github.com/Microsoft/botframework-sdk/blob/main/specs/botframework-activity/botframework-activity.md#conversation-account). The adapter therefore stores a classification override only when `conversationType` disagrees with the legacy ID-prefix heuristic. Existing subscription and history keys remain stable when the heuristic was already correct. Explicit group chats also bypass stale DM Graph context, and Graph-listed child threads retain the override. --------- Signed-off-by: onmax <maximogarciamtnez@gmail.com> |
||
|
|
f6b64318d9 |
chore(docs): upgrade geistdocs to 1.16.0 (#747)
Upgrades the docs to `@vercel/geistdocs@1.16.0`. - Bump `@vercel/geistdocs` 1.15.5 → 1.16.0 - Drop the removed `config` prop from `<Footer />` (1.16.0 replaces the footer with the Vercel product directory and no longer accepts props) - Load Geist Sans from the `geist` npm package so the new `ss11` stylistic set (alternate "I") renders — Google Fonts strips it |
||
|
|
e3c136b6dc |
chore(release): version packages (#710)
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @chat-adapter/discord@4.35.0 ### Minor Changes -@chat-adapter/messenger@4.35.0 @chat-adapter/whatsapp@4.35.0 @chat-adapter/discord@4.35.0 @chat-adapter/state-redis@4.35.0 @chat-adapter/slack@4.35.0 @chat-adapter/web@4.35.0 @chat-adapter/state-pg@4.35.0 @chat-adapter/x@4.35.0 @chat-adapter/gchat@4.35.0 @chat-adapter/twilio@4.35.0 @chat-adapter/state-memory@4.35.0 @chat-adapter/tests@4.35.0 @chat-adapter/shared@4.35.0 @chat-adapter/teams@4.35.0 @chat-adapter/github@4.35.0 chat@4.35.0 @chat-adapter/linear@4.35.0 @chat-adapter/telegram@4.35.0 @chat-adapter/state-ioredis@4.35.0 |
||
|
|
54eea71501 |
feat(telegram): add user allowlist (#742)
## Summary Add an opt-in `allowedUserIds` Telegram adapter option, with `TELEGRAM_ALLOWED_USER_IDS` as a comma-separated environment fallback. Updates from other or unidentified users are ignored before dispatch. This follows the adapter-level targeting pattern from [the Discord channel response allowlist](https://github.com/vercel/chat/pull/715), while enforcing an ingress allowlist instead of expanding mention routing. ## Test plan - `pnpm --filter @chat-adapter/telegram test` - `pnpm --filter @chat-adapter/telegram typecheck` - `pnpm check` - `pnpm konsistent` - `TURBO_CONCURRENCY=2 pnpm validate` ## 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 — see [CONTRIBUTING.md](./CONTRIBUTING.md)) - [x] Documentation updated (or N/A) Signed-off-by: onmax <maximogarciamtnez@gmail.com> |
||
|
|
1d0295f996 |
chore(docs): upgrade geistdocs to 1.15.5 (#743)
- Upgrade `@vercel/geistdocs` to 1.15.5 - New navbar flyout menu style + nav items in flyout menu are rendered server-side to be in the html for crawlers (as requested by Malte) - Homepage section titles use Geist sans heading tokens (new vercel.com style) | **New flyout menu** | **Improved docs mobile layout** | | ------------- | ------------- | | <video src="https://github.com/user-attachments/assets/7baf37d9-7a87-4853-91fb-6c3febf974cb" /> | <img width="499" height="747" alt="image" src="https://github.com/user-attachments/assets/b48a955e-0e15-4e03-ada2-fbc52c2fdcb7" /> | **Preview:** https://chat-git-chore-geistdocs-1155.vercel.sh/ |
||
|
|
160140e32b |
feat(teams): add targeted ephemeral messages (#737)
## Summary Microsoft Teams supports targeted messages that are visible only to a selected conversation member, but the Teams adapter did not expose that native behavior through the SDK's ephemeral-message API. This PR wires `postEphemeral` for Teams to send native targeted messages while preserving normal `postMessage` behavior by default. The adapter now creates explicit targeted outbound activities with `MessageActivity.withRecipient(recipient, true)` for text and adaptive-card messages, returns `usedFallback: false`, and keeps the feature gated behind `thread.postEphemeral()` / `channel.postEphemeral()`. It also bumps the Teams SDK packages to `^2.0.13`, adds targeted coverage, updates public docs/matrices, and includes a changeset. Live verification found that Teams targeted messages require the app to be installed in the shared conversation. Group chats and channels both worked after using the Teams install picker with `Open -> select placement -> Go`; personal bot chat targeted sends returned a Teams `BadArgument` response. ## Test plan Previously validated with: - `corepack pnpm --filter @chat-adapter/teams exec vitest run src/index.test.ts --coverage.enabled=false` - `corepack pnpm --filter @chat-adapter/teams exec tsc --noEmit` - `corepack pnpm --filter example-nextjs-chat exec tsc --noEmit` - `corepack pnpm --filter chat exec vitest run src/emoji.test.ts --coverage.enabled=false` - `corepack pnpm --filter @chat-adapter/teams exec tsup` - Targeted `ultracite check` on changed files Live verified `TeamsAdapter.postEphemeral(...)` in: - Group chat `Demo Test 2`: Teams UI showed `Only you can see this message`. - Channel `General / Teams SDK`: Teams returned message ID `1784749118197`, and the UI showed `Only you can see this message`. <img width="884" height="299" alt="Screenshot 2026-07-22 at 12 41 41 PM" src="https://github.com/user-attachments/assets/cd350ac8-c158-4779-8028-3450eb8670f2" /> <img width="1098" height="559" alt="Screenshot 2026-07-22 at 12 41 33 PM" src="https://github.com/user-attachments/assets/bf6ea12b-ab11-46ee-a3a8-ff5e9583066d" /> ## Checklist - [ ] All commits are signed and verified - unsigned commit created after local GPG/SSH signing was unavailable and user approved continuing - [ ] `pnpm validate` passes - full validate not run; targeted validation listed above - [x] Changeset added (or N/A - see [CONTRIBUTING.md](./CONTRIBUTING.md)) - [x] Documentation updated (or N/A) --------- Co-authored-by: dancer <josh@afterima.ge> Copilot-Session: 601a7414-48f0-4e6d-ba03-28fa4d2d5c0a |
||
|
|
09b72e9dd3 |
fix(whatsapp): stop duplicating card title when posting Card with files (#736)
## Description Fixes a WhatsApp adapter bug where posting a **Card together with files** caused the card title (and other card text) to appear twice: once in the media caption (from `cardToFallbackText`) and again in the interactive message header/body (from `cardToWhatsApp`). `postMessageWithMedia` now checks whether the card will be sent as an interactive message first. If so, it skips using the full card fallback as the media caption and lets the interactive message own the title, body, and buttons. Text-fallback cards + files keep the previous caption behavior (single message, no duplicate text). ## Type of Change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update - [ ] Performance improvement - [ ] Refactoring (no functional changes) ## Related Issues Fixes #735 Closes #735 Related to #735 <!-- Replace # with the issue number after opening the bug report --> ## Changes Made - In `postMessageWithMedia`, compute `cardToWhatsApp(card)` first and reuse that result. - When the card is **interactive**, do not set media caption from `cardToFallbackText` (empty caption text) so title/body are not duplicated on the image. - When the card is **text fallback**, keep captioning media with `cardToFallbackText` and avoid sending a second text message (existing behavior). - Expand unit coverage in `index.test.ts` for interactive + files (title once, no caption duplication for text/fields, multi-file, audio, HTTPS attachment) and text-fallback caption behavior. ## Testing - [x] All existing tests pass - [x] Added new tests for the changes - [x] Manually tested the changes ### Test Coverage - Built the package, then used `pnpm link` to link the built `dist` into a separate test project. - Exercised `thread.post({ card, files })` against the reported bug scenario and confirmed the title no longer appears twice (caption empty for interactive cards; title only on the interactive message). - Added / updated unit tests in `packages/adapter-whatsapp/src/index.test.ts`; all related tests pass locally (`pnpm --filter @chat-adapter/whatsapp test`). ## Screenshots/Demos <!-- Paste before/after WhatsApp screenshots here --> **Before (title duplicated on caption + interactive header):** <img width="433" height="428" alt="image" src="https://github.com/user-attachments/assets/37c776fd-b4f6-48f3-a365-6e2073316576" /> **After (title only on interactive message; media uncaptioned):** <img width="428" height="390" alt="image" src="https://github.com/user-attachments/assets/fb1f43d9-623a-4e22-83ea-dd96cd6d3877" /> <img width="408" height="405" alt="image" src="https://github.com/user-attachments/assets/3959eb04-e722-43f4-8b85-91b724faebcb" /> ## Checklist - [x] My code follows the project's code style - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings or errors - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have created a changeset (`pnpm changeset`) - [x] All commits are signed and verified - [ ] All commits are signed off for the DCO (`git commit -s`) - [x] `pnpm validate` passes - [x] Changeset added (or N/A — see [CONTRIBUTING.md](./CONTRIBUTING.md)) - [ ] Documentation updated (or N/A) ## Changeset - [x] I have created a changeset for these changes <!-- Reminder: behavioural package changes need `pnpm changeset` for `@chat-adapter/whatsapp` --> ## Additional Notes - No change to `@chat-adapter/shared`’s `cardToFallbackText` — it remains correct as a full text fallback. The bug was reusing that full fallback as a caption while also sending a full interactive card. - Card-only posts (no files) are unchanged. --------- |
||
|
|
92530dd352 |
fix(slack): return replyable thread ID from channel posts (#720)
## summary fixes #719 updates Slack channel posts to return a replyable thread ID rooted at the newly posted top-level message `postChannelMessage` still omits `thread_ts` for the initial channel post, then uses Slack's returned message `ts` to construct `slack:<channel>:<ts>` for the `SentMessage` this allows `chat.thread(sent.threadId).post(...)` to reply to a message returned by `channel.post(...)` instead of creating another top-level channel message file-only uploads without a Slack message `ts` keep their existing channel-scoped thread ID ## test plan - added a Slack adapter regression assertion that `postChannelMessage` returns `slack:C123:<message ts>` |
||
|
|
5eb8b846a7 |
feat(teams): support outbound reactions (#734)
Outbound Teams reactions were originally implemented as part of #302, then removed because the Teams feature was not fully rolled out. In [the follow-up discussion](https://github.com/vercel/chat/pull/302#issuecomment-4147056867), the Teams SDK maintainer said they were happy to add the support back once the rollout was ready. Microsoft now documents agent reaction support without a preview caveat. This PR restores that support against the current Teams SDK API: - implement `addReaction` and `removeReaction` with `conversations.addReaction` / `conversations.deleteReaction` - pass native Teams reaction IDs through unchanged and map common normalized Chat SDK emoji names to their Teams IDs - upgrade the aligned `@microsoft/teams.*` dependencies to 2.0.14 - update the Teams feature matrices and add a minor changeset The implementation stays within the existing adapter methods and does not add another abstraction or affect streaming behavior. --------- Signed-off-by: Utopia <154325211+Utopi-a@users.noreply.github.com> |
||
|
|
25f30998ce |
fix(chat): keep attachment/link-only messages in toAiMessages (#713)
- `toAiMessages` previously filtered out any message with empty or whitespace-only text (`sorted.filter((msg) => msg.text.trim())`). This discarded messages that carry meaningful content without text — e.g. an image uploaded with no caption, a file-only upload, or a link-only message. - Now messages are kept as long as they have usable content (text, image/file attachments, or links). Only messages with *none* of those are skipped. - When an attachment-only message is included, no empty `text` part is prepended (an empty text part would be rejected by the AI SDK). Link-only messages render a standalone `Links:\n...` block. ## Changes - `packages/chat/src/ai/messages.ts` — drop the text-only pre-filter; build text conditionally; skip only truly empty messages. - `packages/chat/src/ai/messages.test.ts` — add tests for image-only, link-only, interleaved, whitespace-with-attachment, and fully-empty cases. - `apps/docs/content/docs/ai/to-ai-messages.mdx` — update the documented filtering behavior. - Changeset added (`chat`: patch). --------- Co-authored-by: Cole Corrente <cole.corrente@snowflake.com> Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
e06b4b606b |
feat(teams): forward a custom token factory to the Teams SDK (#732)
`TeamsAdapterConfig` never forwards a `token` field through to the underlying `@microsoft/teams.apps` `AppOptions.token`, even though the Teams SDK already supports it as a genuine "bring your own credentials" escape hatch (`TokenCredentials['token']`). The only non-secret auth path currently exposed is `federated`, which maps to `managedIdentityClientId` and only resolves via Azure-native managed-identity sources (IMDS, AppService, CloudShell, MachineLearning, ServiceFabric). That's unreachable from serverless/edge runtimes (e.g. Vercel) that can't hit Azure IMDS but still need to mint access tokens through an external mechanism (e.g. a workload-identity federation bridge exchanging a platform-native OIDC token for an Azure AD token). We've been carrying a local patch on `@chat-adapter/teams` doing exactly this forwarding to unblock a production Teams bot running on Vercel with a user-assigned managed identity. Opening this as a proper PR instead of staying on the patch indefinitely. ## Changes - `TeamsAdapterConfig.token?: (scope: string | string[], tenantId?: string) => string | Promise<string>` — matches `TokenCredentials['token']`'s real signature. - `toAppOptions` forwards `config.token` straight through. - `clientSecret` resolution now also short-circuits when `token` is provided (alongside the existing `federated` check) — `TokenManager.initializeCredentials` checks `clientId && clientSecret` before `clientId && token`, so a stray `appPassword`/`TEAMS_APP_PASSWORD` would otherwise silently win over an explicitly configured token factory. - Unit tests in `config.test.ts` and a `createTeamsAdapter` factory test in `index.test.ts`. - Docs: added the `token` config option and a third "Authentication methods" example in `apps/docs/content/adapters/official/teams.mdx`. - Changeset (`@chat-adapter/teams`: minor). --------- Signed-off-by: CamdenA21 <camden@sandstone.ai> Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |
||
|
|
b4a93bdbc5 |
build(deps-dev): bump @hono/node-server from 2.0.2 to 2.0.10 (#733)
Bumps [@hono/node-server](https://github.com/honojs/node-server) from 2.0.2 to 2.0.10. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/honojs/node-server/releases">@hono/node-server's releases</a>.</em></p> <blockquote> <h2>v2.0.10</h2> <h2>Security fixes</h2> <p>This release includes a fix for the following security issue:</p> <h3>Unauthenticated memory-leak DoS via aborted WebSocket handshake</h3> <p>Affects: <code>upgradeWebSocket</code>. A WebSocket upgrade request with a missing or malformed <code>Sec-WebSocket-Key</code> header leaked the request's <code>IncomingMessage</code> and left a promise pending, even though no connection was established. Since the route is reachable pre-handshake without authentication, an attacker could flood it to gradually exhaust memory. <a href="https://github.com/honojs/node-server/security/advisories/GHSA-9mqv-5hh9-4cgg">GHSA-9mqv-5hh9-4cgg</a></p> <hr /> <p>Users of <code>upgradeWebSocket</code> are encouraged to upgrade to this version.</p> <h2>v2.0.9</h2> <h2>What's Changed</h2> <ul> <li>fix(websocket): polyfill missing ErrorEvent global by <a href="https://github.com/otnc"><code>@otnc</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/371">honojs/node-server#371</a></li> <li>fix(serve-static): correct Range header parsing edge cases by <a href="https://github.com/otnc"><code>@otnc</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/372">honojs/node-server#372</a></li> <li>fix: recover complete request bodies after client disconnect by <a href="https://github.com/usualoma"><code>@usualoma</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/375">honojs/node-server#375</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/otnc"><code>@otnc</code></a> made their first contribution in <a href="https://redirect.github.com/honojs/node-server/pull/371">honojs/node-server#371</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/honojs/node-server/compare/v2.0.8...v2.0.9">https://github.com/honojs/node-server/compare/v2.0.8...v2.0.9</a></p> <h2>v2.0.8</h2> <h2>What's Changed</h2> <ul> <li>ci(release): add <code>--no-git-checks</code> option for <code>pnpm stage publish</code> by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/369">honojs/node-server#369</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/honojs/node-server/compare/v2.0.7...v2.0.8">https://github.com/honojs/node-server/compare/v2.0.7...v2.0.8</a></p> <h2>v2.0.7</h2> <h2>What's Changed</h2> <ul> <li>chore: migrate to pnpm by <a href="https://github.com/BlankParticle"><code>@BlankParticle</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/367">honojs/node-server#367</a></li> <li>fix(serve-static): serve precompressed files for application/octet-stream by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/366">honojs/node-server#366</a></li> <li>chore: bump <code>supertest</code> by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/368">honojs/node-server#368</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/honojs/node-server/compare/v2.0.6...v2.0.7">https://github.com/honojs/node-server/compare/v2.0.6...v2.0.7</a></p> <h2>v2.0.6</h2> <h2>What's Changed</h2> <ul> <li>ci: publish to npm from CI with OIDC trusted publishing and bump <code>np</code> by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/361">honojs/node-server#361</a></li> <li>ci: use npm Staged publishing by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/364">honojs/node-server#364</a></li> <li>fix: preserve status and statusText when cloning a Response with liveheaders by <a href="https://github.com/usualoma"><code>@usualoma</code></a> in <a href="https://redirect.github.com/honojs/node-server/pull/363">honojs/node-server#363</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/honojs/node-server/compare/v2.0.5...v2.0.6">https://github.com/honojs/node-server/compare/v2.0.5...v2.0.6</a></p> <h2>v2.0.5</h2> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/honojs/node-server/commit/7c1457ed5536c02fdd2f001129fae67bcbca54a1"><code>7c1457e</code></a> 2.0.10</li> <li><a href="https://github.com/honojs/node-server/commit/3a21938c418340e980cb7ffa88e78369f78392d1"><code>3a21938</code></a> Merge commit from fork</li> <li><a href="https://github.com/honojs/node-server/commit/98420217e53a17a238ef1aa1a6bef0b2b70136c5"><code>9842021</code></a> 2.0.9</li> <li><a href="https://github.com/honojs/node-server/commit/51f3bf56f56d9691ec0f7e1562a96f0b485a7dd9"><code>51f3bf5</code></a> fix: recover complete request bodies after client disconnect (<a href="https://redirect.github.com/honojs/node-server/issues/375">#375</a>)</li> <li><a href="https://github.com/honojs/node-server/commit/fdb87badbe313cfbfe6bb2355e9893dc0698d2bd"><code>fdb87ba</code></a> fix(serve-static): correct Range header parsing edge cases (<a href="https://redirect.github.com/honojs/node-server/issues/372">#372</a>)</li> <li><a href="https://github.com/honojs/node-server/commit/912e3fd80c4311756f724bd566de1433c8d772d9"><code>912e3fd</code></a> fix(websocket): polyfill missing ErrorEvent global (<a href="https://redirect.github.com/honojs/node-server/issues/371">#371</a>)</li> <li><a href="https://github.com/honojs/node-server/commit/114c15efb38dabaf81af774ddb764409e3d156d8"><code>114c15e</code></a> 2.0.8</li> <li><a href="https://github.com/honojs/node-server/commit/5db2d5df662cd69ff5c4cc23b8ecb3a6f63e4e38"><code>5db2d5d</code></a> ci(release): add <code>--no-git-checks</code> option for <code>pnpm stage publish</code> (<a href="https://redirect.github.com/honojs/node-server/issues/369">#369</a>)</li> <li><a href="https://github.com/honojs/node-server/commit/a528a77ed2c28dc12775c849abc6b6df6d4cb44c"><code>a528a77</code></a> 2.0.7</li> <li><a href="https://github.com/honojs/node-server/commit/b2d610c1e37a96639fbb2eae662e858800aa8906"><code>b2d610c</code></a> chore: bump <code>supertest</code> (<a href="https://redirect.github.com/honojs/node-server/issues/368">#368</a>)</li> <li>Additional commits viewable in <a href="https://github.com/honojs/node-server/compare/v2.0.2...v2.0.10">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 <code>@hono/node-server</code> since your current version.</p> </details> <br /> [](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> |
||
|
|
4cb7e5d58e |
feat(chat): durable human-in-the-loop approvals via chat/workflow (#728)
Adds a `chat/workflow` subpath export with `requestApproval()`. This is the DX from #284, rebuilt on Workflow SDK so the approval survives deploys, restarts, and arbitrarily long waits. No in-memory promises, no approvals registry, no restart-recovery machinery: the workflow suspends on a webhook and resumes when a button is clicked. `requestApproval()` posts a card with Approve/Deny buttons whose `callbackUrl` targets a `createWebhook()` URL, suspends the workflow until a decision (or optional durable-sleep timeout), validates approvers, finalizes the card in place with the outcome (removing the buttons, leaving an audit trail), and returns the decision. ```typescript import { requestApproval } from "chat/workflow"; import type { Thread } from "chat"; export async function deployApproval(opts: { thread: Thread; version: string }) { "use workflow"; const { approved, user, timedOut } = await requestApproval(opts.thread, { title: `Deploy ${opts.version}?`, fields: { Version: opts.version }, timeout: "24h", approvers: ["U_ALICE", "U_BOB"], }); if (approved) { await deploy(opts.version); } } ``` Starting it from a handler is one line. `Thread` instances serialize across the workflow boundary automatically via the existing `@workflow/serde` hooks on `ThreadImpl` (requires `chat.registerSingleton()`): ```typescript import { start } from "workflow/api"; bot.onNewMention(async (thread, message) => { await start(deployApproval, [{ thread, version: parseVersion(message.text) }]); }); ``` **Details** - `workflow` is a new **optional** peer dependency (same pattern as `ai`); the subpath is the only code that imports it - Unauthorized clicks (when `approvers` is set) and unrecognizable payloads post a notice / are ignored, and the workflow keeps waiting - On timeout the card is finalized as timed out and the result has `timedOut: true` - Card builders (`buildApprovalCard`, `buildResolvedCard`) are exported for custom flows - Verified the published `dist` preserves the `"use step"` directives and down-levels `using` correctly, so the app-side Workflow SDK compiler handles the library code - Docs page under Interactivity; changeset (`chat` minor); 8 unit tests mocking the `workflow` primitives **Deliberate deviation from #284:** no `thread.requestApproval()` method. The function must suspend at workflow level, so hanging it off `ThreadImpl` would make `workflow` a hard dependency of core (or require prototype patching). The standalone `requestApproval(thread, options)` keeps the dependency optional. --------- Signed-off-by: Ben Sabic <bensabic@users.noreply.github.com> Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com> |