Commit Graph

537 Commits

Author SHA1 Message Date
github-actions[bot] 7f5bea3fe1 Version Packages (#368)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@chat-adapter/slack@4.26.0 @chat-adapter/github@4.26.0 @chat-adapter/telegram@4.26.0 @chat-adapter/teams@4.26.0 @chat-adapter/discord@4.26.0 @chat-adapter/shared@4.26.0 @chat-adapter/state-ioredis@4.26.0 @chat-adapter/linear@4.26.0 @chat-adapter/gchat@4.26.0 chat@4.26.0 @chat-adapter/whatsapp@4.26.0 @chat-adapter/state-redis@4.26.0 @chat-adapter/state-pg@4.26.0 @chat-adapter/state-memory@4.26.0
2026-04-13 22:08:02 -04:00
Vishal Yathish 8955e71f73 [slack] create changeset for markdown table bug patch (#376) 2026-04-13 21:59:56 -04:00
Matthew Lewis 691348b74a feat: add test for empty header cells and update markdown conversion logic (#373)
Slack-Thread: https://vercel.slack.com/archives/C08077A6JDB/p1776093728715659?thread_ts=1776093728.715659&cid=C08077A6JDB

Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Matthew Lewis <29663600+malewis5@users.noreply.github.com>
2026-04-13 21:35:47 -04:00
Ben Sabic ccc042a608 docs: misc updates and fixes (#370)
* docs: misc updates and fixes

* docs: update feature matrix to show Teams modal support

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-04-13 20:17:41 +10:00
josh ddb084b3a6 fix(chat): guard fallback streaming against empty content (#357)
* fix(chat): guard fallback streaming against empty content

* test(chat): add tests for empty content guards in fallback streaming

* chore: add changeset
2026-04-13 18:45:44 +10:00
Hayden Bleasel 2235c160ca fix(chat): export standalone reviver for workflow-safe deserialization (#257)
* fix(chat): export standalone reviver for workflow-safe deserialization

Importing the Chat instance into Vercel Workflow files pulls in adapter
packages that depend on Node.js modules, which aren't available in the
workflow sandbox. This adds a standalone `reviver` function exported from
`chat` that deserializes Thread/Channel/Message objects without needing
a Chat instance or its adapter dependencies.

Also updates the durable chat sessions guide to use the standalone
reviver and dynamic bot imports inside step functions.

Closes #243

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(chat): preserve adapterName on deserialized toJSON and add standalone reviver docs

* fix: sort imports in index.ts

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: dancer <josh@afterima.ge>
Co-authored-by: Ben Sabic <27636870+bensabic@users.noreply.github.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-04-13 18:34:16 +10:00
mdnanocom 4cc87dd888 [gchat] [bug] render markdown links with Google Chat custom link syntax (#356) 2026-04-12 22:31:59 +10:00
github-actions[bot] 63515f2286 Version Packages (#351)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@chat-adapter/discord@4.25.0 chat@4.25.0 @chat-adapter/telegram@4.25.0 @chat-adapter/teams@4.25.0 @chat-adapter/state-redis@4.25.0 @chat-adapter/gchat@4.25.0 @chat-adapter/linear@4.25.0 @chat-adapter/shared@4.25.0 @chat-adapter/slack@4.25.0 @chat-adapter/whatsapp@4.25.0 @chat-adapter/state-pg@4.25.0 @chat-adapter/state-memory@4.25.0 @chat-adapter/state-ioredis@4.25.0 @chat-adapter/github@4.25.0
2026-04-10 17:01:43 -07:00
Raimond Lume 2700ce85b3 feat(chat): Enable disabling code-fencing for streamed tables per-adapter (#349)
* feat(chat): Enable disabling code-fencing for streamed tables per-adapter

As Slack now natively supports markdown tables, the code-fencing for
tables is not required and in fact stops them from being rendered
natively.

This PR adds an option to configure code-fencing tables per adapter.
By default true, false only for Slack.

* Update StreamingMarkdownRendererOptions comments

Removed comment about default behavior for wrapTablesForAppend option.
2026-04-09 11:21:53 -07:00
Aamir Jawaid ce7cd2f8f0 feat(adapter-teams): add Select and RadioSelect support (#341)
* feat(adapter-teams): add Select and RadioSelect support in card Actions

Map Select and RadioSelect card elements to Teams Adaptive Card
ChoiceSetInput (compact and expanded styles). Auto-inject a submit
button when inputs exist without explicit buttons, and fan out the
auto-submit payload into individual onAction calls per input.
2026-04-09 11:08:25 -07:00
Vishal Yathish 097c9b4630 [chat] adding plan/update plan blocks for threads (#115)
* [chat] adding plan/update plan blocks for threads

* refactor plan impl into its own file

* thread.post() instead of thread.postPlan()

* fixes

* lint fixes

* refactor postable objects

* knip

* Refactor PostableObject into dedicated module and add fallback support (#191)

* feat: refactor adapter-slack and types based on Malte's comments

Move PostableObject to dedicated file, update type exports, add fallback posts, and make PostableObject generic.

Slack-Thread: https://vercel.slack.com/archives/C0977L169MW/p1772755978706959?thread_ts=1772755978.706959&cid=C0977L169MW
Co-authored-by: Vishal Yathish <135551666+visyat@users.noreply.github.com>

* fix: fallback path for PostableObject and clean up exports

- Plan mutations (addTask, updateTask, complete) now work in fallback
  mode by using editMessage with fallback text instead of no-oping
- Revert Slack adapter to throw on unsupported kinds (caller handles
  fallback, so adapter-level fallback strings are unnecessary)
- Remove redundant re-exports of isPostableObject/PostableObject from
  plan.ts — export from canonical postable-object.ts only
- Stop exporting POSTABLE_OBJECT symbol (internal implementation detail)
- Fix nested ternary lint error in getFallbackText
- Add tests for fallback post/edit path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* Fall back to plain text instead of throwing for unsupported postable object kinds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(chat): deduplicate PostableObject handling, improve type safety and test coverage

---------

Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: dancer <josh@afterima.ge>
2026-04-09 09:54:00 +10:00
Ben Sabic 1856198f6d fix(slack): OAuth redirect handling (#307)
* Fix Slack OAuth redirect handling

* fix slack check

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-04-09 00:15:37 +10:00
Ben Sabic 21498a4a7f feat(github): add support for issue comment threads (#342)
* feat(github): add support for issue comment threads

Handle issue_comment webhooks on plain issues, not just PRs.
Issue threads use the format github:owner/repo:issue:42.

* fix(github): propagate threadType in GitHubRawMessage for issue threads

parseMessage and other methods now correctly produce issue-format thread
IDs when the raw message originated from a plain issue, not a PR.

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-04-09 00:15:13 +10:00
josh d9bc0a481c docs: remove chatbot template banner (#347) 2026-04-08 03:05:17 +10:00
github-actions[bot] a8dc522c4c Version Packages (#310)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@chat-adapter/whatsapp@4.24.0 @chat-adapter/slack@4.24.0 @chat-adapter/state-ioredis@4.24.0 @chat-adapter/state-memory@4.24.0 @chat-adapter/telegram@4.24.0 chat@4.24.0 @chat-adapter/state-redis@4.24.0 @chat-adapter/discord@4.24.0 @chat-adapter/gchat@4.24.0 @chat-adapter/teams@4.24.0 @chat-adapter/state-pg@4.24.0 @chat-adapter/shared@4.24.0 @chat-adapter/linear@4.24.0 @chat-adapter/github@4.24.0
2026-04-06 20:21:57 -07:00
Aamir Jawaid 4f5d20029f Add modal support for Teams (#325)
* feat(teams): add dialog (task module) support

Teams dialogs require modal content to be returned inline in the HTTP
response when a task/fetch invoke fires. This adds:

- `actionType: "modal"` on buttons to emit msteams task/fetch hint
- `onOpenModal` hook on WebhookOptions for inline modal interception
- dialog.open/dialog.submit handlers in Teams adapter with Promise.race
- Modal-to-AdaptiveCard converter (modals.ts)
- Bridge adapter sends empty body (not "{}") for dialog close responses

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(teams): use @microsoft/teams.cards builders for Adaptive Cards

Replace hand-rolled plain JSON objects and local type definitions with
typed builder classes from @microsoft/teams.cards. This gives compile-time
type safety and eliminates the local AdaptiveCard/AdaptiveCardElement/
AdaptiveCardAction interfaces.

Also fix ephemeral modal button missing actionType="modal", which
prevented the dialog from opening on Teams.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(teams): preserve contextId in modal update/push responses

Pass the original contextId through to re-rendered modals so subsequent
submissions can still retrieve the stored thread/message/channel context.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: address review feedback across dialog support

- Clean up timeout timer in handleDialogOpen to prevent resource leak
- Also race on actionPromise so errors surface instead of silently timing out
- Extract buildContinueResponse helper to deduplicate update/push cases
- Use typed TextInputOptions/ChoiceSetInputOptions instead of Record<string, unknown>
- Make processSlashCommand options parameter explicit (WebhookOptions | undefined)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(chat): await storeModalContext before opening modal

The state write was fire-and-forget, so a fast dialog.submit could
arrive before the context was persisted, causing retrieveModalContext
to return empty. Also adds changeset for the new public API surface.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(chat): add missing disabled prop to ButtonProps JSX interface

The ButtonElement and ButtonOptions already supported disabled, but the
JSX ButtonProps interface was missing it, causing <Button disabled> to
silently drop the prop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review feedback for dialog support

- Add unit tests for modals.ts (16 tests) and modal button actionType in cards.test.ts
- Make dialog open timeout configurable via dialogOpenTimeoutMs in TeamsAdapterConfig
- Fix ModalSubmitHandler type to accept Promise<void> returns, remove @ts-expect-error from example
- Delete stored modal context after retrieval to prevent state adapter leaks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: lint fixes and add X-User-Agent header to Teams adapter

- Fix import ordering, formatting, and non-null assertions in modals.test.ts
- Sort interface members in TeamsAdapterConfig
- Add X-User-Agent: Vercel.ChatSDK header to Teams SDK App client

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:09:25 +10:00
Nhat Bui 4304de82b7 feat: add Zalo adapter and update documentation (#336) 2026-04-07 09:02:59 +10:00
josh 8d8927411d fix: disable source maps in published packages (#337)
* fix: disable source maps in published packages

* chore: add changeset
2026-04-07 09:02:36 +10:00
Yejun Su e8dbef2bab fix(adapter-slack): replace empty table cells with single space (#327)
* fix(adapter-slack): replace empty table cells with single space

Slack's Block Kit API rejects cells with empty text fields. Fall back
to a single space in both mdastTableToSlackBlock (markdown.ts) and
convertTableToBlocks (cards.ts) to satisfy the API constraint.

* chore: add changeset for slack empty table cells fix

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-04-07 08:52:23 +10:00
josh d3f04ec92b docs: add missing JSDoc and adapter-shared README (#339)
* docs(chat): add JSDoc to onModalSubmit and onModalClose

* docs(shared): add README for adapter-shared package
2026-04-06 12:46:13 -07:00
josh cb1deebd67 fix(github): handle webhook events without repository in multi-tenant mode (#335) 2026-04-06 11:39:54 -07:00
Malte Ubl 9215740312 Add back links to /adapters from adapter detail pages (#333)
* feat: add adapters section and integrate into home page

Slack-Thread: https://vercel.slack.com/archives/C08077A6JDB/p1775418562324169?thread_ts=1775418562.324169&cid=C08077A6JDB
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>

* feat: update adapters section with new messenger links and layout changes

Slack-Thread: https://vercel.slack.com/archives/C08077A6JDB/p1775418562324169?thread_ts=1775418562.324169&cid=C08077A6JDB
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>

* feat: add navigation links and icons for adapter pages

Slack-Thread: https://vercel.slack.com/archives/C08077A6JDB/p1775418562324169?thread_ts=1775418562.324169&cid=C08077A6JDB
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>

---------

Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>
2026-04-05 13:19:46 -07:00
Malte Ubl 332c84ac02 feat: add rewrite rule for sitemap.xml and remove sitemap.ts file (#334)
Slack-Thread: https://vercel.slack.com/archives/C08077A6JDB/p1775419801951169?thread_ts=1775419801.951169&cid=C08077A6JDB

Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>
2026-04-05 13:17:23 -07:00
Malte Ubl 1fcab01302 Move messenger pages to /adapters/for/ and add browse section (#332)
* feat: refine adapter categorization and display logic in AdaptersGrid component

Slack-Thread: https://vercel.slack.com/archives/C08077A6JDB/p1775414281367229?thread_ts=1775414281.367229&cid=C08077A6JDB
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>

* feat: rename messenger to for in adapter paths and add messenger links

Slack-Thread: https://vercel.slack.com/archives/C08077A6JDB/p1775414281367229?thread_ts=1775414281.367229&cid=C08077A6JDB
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>

---------

Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>
2026-04-05 12:32:23 -07:00
Malte Ubl f93228c4ef Add Sendblue iMessage adapter and strip HTML images from READMEs (#329)
* feat: add chat-adapter-sendblue community adapter

Introduce iMessage via Sendblue adapter for community integration.

Slack-Thread: https://vercel.slack.com/archives/C08077A6JDB/p1775398069006459?thread_ts=1775398069.006459&cid=C08077A6JDB
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>

* feat: enhance readme-content.tsx to strip images from markdown

Improved markdown image removal, added HTML img tag cleanup

Slack-Thread: https://vercel.slack.com/archives/C08077A6JDB/p1775398069006459?thread_ts=1775398069.006459&cid=C08077A6JDB
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>

* fix: update SKILL.md for Sendblue adapter order

Sync SKILL.md with adapters.json for correct adapter listing.

Slack-Thread: https://vercel.slack.com/archives/C08077A6JDB/p1775398069006459?thread_ts=1775398069.006459&cid=C08077A6JDB
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>

---------

Co-authored-by: v0 <v0[bot]@users.noreply.github.com>
Co-authored-by: Malte Ubl <89679+cramforce@users.noreply.github.com>
2026-04-05 11:34:48 -07:00
Ben Sabic 6743465218 Add Liveblocks vendor official adapter (#321)
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-04-03 14:32:35 +11:00
Rich Haines 11872eae01 Send siteId as label on feedback GitHub issues (#319) 2026-04-01 23:42:31 +11:00
Aamir Jawaid a0f508eee6 Migrate from BotFramework to TeamsSDK (#302)
* Migrate Teams adapter from botbuilder to @microsoft/teams.apps

Replace botbuilder/botframework-connector with @microsoft/teams.apps (TeamsSDK v2.0.6).

Breaking changes:
- Remove certificate auth (TeamsAuthCertificate) — use token or managedIdentityClientId instead
- Env vars changed: TEAMS_APP_ID → CLIENT_ID, TEAMS_APP_PASSWORD → CLIENT_SECRET, TEAMS_APP_TENANT_ID → TENANT_ID
- Reactions now work (addReaction/removeReaction) instead of throwing NotImplementedError
- Graph API calls use @microsoft/teams.graph-endpoints typed endpoints

Key changes:
- BridgeHttpAdapter captures TeamsSDK route handler for serverless dispatch
- Event handlers registered via app.on() (message, messageReaction, card.action, conversationUpdate, installationUpdate)
- Outbound calls use app.send() and app.api.conversations.activities()
- Stream support via post+edit (native HttpStream when SDK exports it)
- Graph API uses typed endpoints from @microsoft/teams.graph-endpoints
- isMention detection via activity entities instead of bot name matching

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Align TeamsAdapterConfig with AppOptions from TeamsSDK

- Replace custom config fields with Pick<AppOptions, ...>
  clientId (was appId), clientSecret (was appPassword), tenantId (was appTenantId)
- Remove TeamsAuthFederated, appType — use managedIdentityClientId directly
- Constructor passes config through to App (App handles env var resolution)
- Use this.app.id instead of this.config.appId for bot identity checks
- 3 replay-fetch-messages tests have known failures (type shape mismatch)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove api() getter, add handler type safety

- Remove useless private api() getter, use this.app.api directly
- Type handlers with specific activity types:
  handleMessageActivity(ctx: IActivityContext<IMessageActivity>)
  handleAdaptiveCardAction(ctx: IActivityContext<IAdaptiveCardActionInvokeActivity>)
  handleReactionFromContext(ctx: IActivityContext<IMessageReactionActivity>)
- Remove unnecessary casts now that ctx.activity is properly typed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Revert bot.tsx example changes from migration branch

Keep Azure OpenAI and DM handler changes as local-only, not part of the migration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Revert example package.json from migration branch

Keep only adapters.ts config changes, revert package.json dep changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove unrelated skill files from migration branch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix

* Update README for TeamsSDK migration

- New env vars: CLIENT_ID, CLIENT_SECRET, TENANT_ID
- New config: clientId, clientSecret, tenantId, token, managedIdentityClientId
- Remove certificate auth docs (dropped)
- Reactions now supported (add/remove)
- Typing indicator now supported
- Graph API uses @microsoft/teams.graph-endpoints
- Note streaming and modals status

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Revert "Update README for TeamsSDK migration"

This reverts commit 729fe463c1.

* update readme

* Refactor adapter-teams: extract types, errors, and graph-api modules

Split the 2,114-line index.ts into focused modules:
- types.ts: TeamsAdapterConfig, TeamsThreadId, TeamsChannelContext
- errors.ts: handleTeamsError as standalone pure function
- graph-api.ts: TeamsGraphReader class with all Graph API read methods

index.ts shrinks to ~1,133 lines, delegating graph reads to TeamsGraphReader
which receives dependencies via constructor injection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Clean up tests

* Do not break public facing config.

* Use previous .env vars

* Fix tests

* Fix webhook concurrency issue

* Remove support for reactions

* Fetch aadgroup id if it doesn't exist

* Fix lint and formatting issues in Teams adapter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix README to match public API, fix 403 error mapping, correct NotImplementedError args, remove stale test aliases, and add changeset

* Fix remaining mockBotAdapter references and trailing whitespace

* fix graph pagination

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-03-31 15:31:50 +11:00
Sascha Buehrle 09f6230a51 fix(discord): recover existing thread on 160004 error (#280)
* fix(discord): recover existing thread on 160004 error (fixes #279)

* Harden 160004 error matching, add tests, and add changeset

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-03-31 13:28:00 +11:00
Samy Pessé 90cfb6a98a feat(github-adapter): Add a method getInstallationId to get the installation id for a thread (#312)
* Implement getInstallationId

* Add tests

* Format

* Fix duplicate test to cover Thread object input path

---------

Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>
2026-03-31 13:02:56 +11:00
XLor 27b34e153b fix(chat): use adapter to parse channel id (#286)
* fix(chat): use adapter to parse channel id

* test: fix cases use adapter to parse channel id

* chore: update changeset
2026-03-30 09:16:23 -07:00
James 2d6a7e6a40 feat(docs): add inline logo chips to hero description (#315)
* feat(docs): add inline logo chips to hero description

Add brand logos (Slack, Microsoft Teams, Google Chat, Discord) as
inline chips prefixed before each product name in the hero section.

- Import existing SVG logos from lib/logos.tsx
- Create LogoChip component with whitespace-nowrap to prevent
  wrapping between logo and its corresponding product name
- Update Hero component description type from string to ReactNode
- Keep plain text description for metadata/SEO

* fix(docs): logo chips line-height, comma wrapping, and spacing

- Use absolute positioning inside a zero-height inline-block container
  so the logo doesn't increase line height
- Move trailing commas inside the whitespace-nowrap span via a suffix
  prop to prevent hanging commas at line start
- Add 2px extra spacing on the right side of logos before names

* fix(docs): vertically center logos and add 2px left spacing

- Use align-middle + top-1/2 -translate-y-1/2 for true vertical
  centering relative to the text line
- Add ml-[2px] on the outer nowrap span for left-side spacing

* fix(docs): widen hero description max-width on desktop

Bump from max-w-3xl (48rem) to sm:max-w-[52rem] so the first
product (Slack) stays on the first line at typical desktop widths.

* fix(docs): resolve lint issues

- Fix import order (react type import after next)
- Replace namespace import with named imports for logos
- Sort CSS classes per biome nursery rule
- Fix formatter line wrapping

---------

Co-authored-by: jamesvclements <jamesvclements@users.noreply.github.com>
2026-03-30 11:47:33 -04:00
Miki Palet 96cdef5877 Add Zernio vendor official adapter (#314)
* feat: add Zernio vendor official adapter to adapters directory

* fix: add @zernio/chat-sdk-adapter to community adapters list in SKILL.md
2026-03-30 22:31:32 +11:00
Hayden Bleasel 67e0e1ba23 Fix Redis state typings for url and client options (#303)
* Fix Redis state typings for url and client options

* Wait for injected Redis clients to become ready

* Simplify Redis readiness guard

* Stabilize memory state TTL test with fake timers

* Handle Redis reconnect errors until client is ready

* Handle injected Redis client reconnects correctly
2026-03-28 11:18:03 +11:00
github-actions[bot] 91820173f4 Version Packages (#300) @chat-adapter/telegram@4.23.0 @chat-adapter/gchat@4.23.0 @chat-adapter/whatsapp@4.23.0 @chat-adapter/discord@4.23.0 @chat-adapter/teams@4.23.0 @chat-adapter/state-redis@4.23.0 @chat-adapter/state-pg@4.23.0 @chat-adapter/state-memory@4.23.0 @chat-adapter/state-ioredis@4.23.0 @chat-adapter/slack@4.23.0 @chat-adapter/shared@4.23.0 @chat-adapter/linear@4.23.0 @chat-adapter/github@4.23.0 chat@4.23.0 2026-03-25 21:36:16 -04:00
Fernando Rojo 4166e09dad Add channelVisibility support to Thread, Channel, and Slack adapter (#51) 2026-03-25 17:21:46 -04:00
Malte Ubl acc4a336a0 Minor docs fix (#296) 2026-03-24 14:25:29 -07:00
github-actions[bot] 434421c82f Version Packages (#295)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@chat-adapter/slack@4.22.0 chat@4.22.0 @chat-adapter/whatsapp@4.22.0 @chat-adapter/telegram@4.22.0 @chat-adapter/teams@4.22.0 @chat-adapter/state-redis@4.22.0 @chat-adapter/state-pg@4.22.0 @chat-adapter/state-memory@4.22.0 @chat-adapter/state-ioredis@4.22.0 @chat-adapter/shared@4.22.0 @chat-adapter/linear@4.22.0 @chat-adapter/github@4.22.0 @chat-adapter/gchat@4.22.0 @chat-adapter/discord@4.22.0
2026-03-24 14:22:44 -07:00
Malte Ubl f2d8957797 Docs for the new concurrency strategies (#294) 2026-03-24 14:15:44 -07:00
Malte Ubl c674284885 [RFC] add concurrency strategies for overlapping messages (queue, debounce, concurrent) (#277)
* feat: add concurrency strategies for overlapping messages (queue, debounce, concurrent)

## Problem

When multiple messages arrive on the same thread while a handler is still
processing, the SDK has only one behavior: **lock-and-drop**. The incoming
message is silently discarded (or force-released, which creates uncontrolled
concurrency). This is insufficient for most real-world use cases:

- **AI chatbots** lose user follow-up messages sent while the model is streaming
- **Customer support bots** miss messages entirely, breaking conversation flow
- **Collaborative editing bots** need to coalesce rapid corrections into one action

## Solution

Introduce a new `concurrency` option on `ChatConfig` with four strategies:

### `'drop'` (default, backward-compatible)

Existing behavior. Lock acquired or `LockError` thrown. No changes.

### `'queue'`

Messages that arrive while a handler is running are enqueued in the state
adapter. When the current handler finishes, the queue is drained: **only the
latest message is dispatched**, with all intermediate messages provided as
`context.skipped`. This gives the handler full visibility into what happened
while it was busy, without forcing it to re-process every message sequentially.

```typescript
const chat = new Chat({
  concurrency: 'queue',
  // ...
});

chat.onNewMention(async (thread, message, context) => {
  if (context && context.skipped.length > 0) {
    // "You sent 4 messages while I was thinking. Responding to your latest."
    const allMessages = [...context.skipped, message];
    // Pass all messages to the LLM for full context
  }
});
```

Flow:
```
A arrives  → acquire lock → process A
B arrives  → lock busy → enqueue B
C arrives  → lock busy → enqueue C
D arrives  → lock busy → enqueue D
A done     → drain: [B, C, D] → handler(D, { skipped: [B, C] })
D done     → queue empty → release lock
```

### `'debounce'`

Every message (including the first) starts or resets a debounce timer. Only the
**final message in a burst** is processed. The lock-holding function stays alive
through `waitUntil` during the debounce window.

```typescript
const chat = new Chat({
  concurrency: { strategy: 'debounce', debounceMs: 1500 },
  // ...
});
```

Flow:
```
A arrives  → acquire lock → store A as pending → sleep(debounceMs)
B arrives  → lock busy → overwrite pending with B (A dropped)
C arrives  → lock busy → overwrite pending with C (B dropped)
             ... debounceMs elapses with no new message ...
           → process C → release lock
```

### `'concurrent'`

No locking at all. Every message is processed immediately in its own handler
invocation. Suitable for stateless handlers (lookups, translations) where
thread ordering doesn't matter.

```typescript
const chat = new Chat({
  concurrency: 'concurrent',
  // ...
});
```

## API Surface

### ChatConfig

```typescript
interface ChatConfig {
  concurrency?: ConcurrencyStrategy | ConcurrencyConfig;
  /** @deprecated Use `concurrency` instead */
  onLockConflict?: 'force' | 'drop' | ((threadId, message) => ...);
}

type ConcurrencyStrategy = 'drop' | 'queue' | 'debounce' | 'concurrent';

interface ConcurrencyConfig {
  strategy: ConcurrencyStrategy;
  maxQueueSize?: number;           // Default: 10
  onQueueFull?: 'drop-oldest' | 'drop-newest';  // Default: 'drop-oldest'
  queueEntryTtlMs?: number;        // Default: 90_000 (90s)
  debounceMs?: number;              // Default: 1500
  maxConcurrent?: number;           // Default: Infinity
}
```

### MessageContext (new, passed to handlers)

```typescript
interface MessageContext {
  skipped: Message[];               // Intermediate messages, chronological
  totalSinceLastHandler: number;    // skipped.length + 1
}
```

All handler types (`MentionHandler`, `MessageHandler`, `SubscribedMessageHandler`,
`DirectMessageHandler`) now accept an optional `MessageContext` as their last
parameter. Existing handlers that don't use it are unaffected.

### StateAdapter (new methods)

```typescript
interface StateAdapter {
  enqueue(threadId: string, entry: QueueEntry, maxSize: number): Promise<number>;
  dequeue(threadId: string): Promise<QueueEntry | null>;
  queueDepth(threadId: string): Promise<number>;
}
```

Implemented across all four state adapters:
- **MemoryStateAdapter**: in-process array
- **RedisStateAdapter**: Lua script (RPUSH + LTRIM + PEXPIRE)
- **IoRedisStateAdapter**: same Lua approach
- **PostgresStateAdapter**: new `chat_state_queues` table with atomic dequeue

## Architecture

`handleIncomingMessage` was refactored into composable pieces:

- `dispatchToHandlers()` — shared handler dispatch logic (mention detection,
  subscription routing, pattern matching). Extracted from the old monolithic
  method so all strategies reuse it.
- `handleDrop()` — original lock-or-fail path (preserves `onLockConflict` compat)
- `handleQueueOrDebounce()` — enqueue if busy, drain or debounce after
- `handleConcurrent()` — skip locking entirely
- `drainQueue()` — collect all pending, dispatch latest with skipped context
- `debounceLoop()` — sleep/check/repeat until no new messages arrive

## Queue Entry TTL

Queued messages have a configurable TTL (`queueEntryTtlMs`, default 90s). Stale
entries are discarded on dequeue with a `message-expired` log event. This
prevents unbounded accumulation and ensures handlers don't process messages
that are no longer relevant.

## Observability

All strategies emit structured log events at `info` level:

| Event                 | Strategy         | Data                                  |
|-----------------------|------------------|---------------------------------------|
| `message-queued`      | queue            | threadId, messageId, queueDepth       |
| `message-dequeued`    | queue, debounce  | threadId, messageId, skippedCount     |
| `message-dropped`     | drop, queue      | threadId, messageId, reason           |
| `message-expired`     | queue, debounce  | threadId, messageId                   |
| `message-superseded`  | debounce         | threadId, droppedId                   |
| `message-debouncing`  | debounce         | threadId, messageId, debounceMs       |
| `message-debounce-reset` | debounce      | threadId, messageId                   |

## Backward Compatibility

- Default remains `'drop'` — zero breaking changes for existing users
- `onLockConflict` continues to work but is marked `@deprecated`
- Handler signatures are backward-compatible (new `context` param is optional)
- Deduplication always runs regardless of strategy

## Files Changed

- `packages/chat/src/types.ts` — new types, updated handler signatures
- `packages/chat/src/chat.ts` — strategy routing, drain/debounce loops
- `packages/chat/src/index.ts` — export new types
- `packages/chat/src/mock-adapter.ts` — queue methods for test mock
- `packages/state-memory/src/index.ts` — in-memory queue
- `packages/state-redis/src/index.ts` — Redis queue (Lua)
- `packages/state-ioredis/src/index.ts` — ioredis queue (Lua)
- `packages/state-pg/src/index.ts` — Postgres queue table
- `packages/chat/src/chat.test.ts` — tests for queue, debounce, concurrent

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: comprehensive test coverage for concurrency strategies and queue methods

Add tests across all state adapters and the Chat class:

**MemoryStateAdapter** (8 new tests):
- enqueue/dequeue single entry
- dequeue from empty queue returns null
- dequeue from nonexistent thread returns null
- queueDepth returns 0 for empty queue
- FIFO ordering across multiple entries
- maxSize trimming (keeps newest)
- maxSize=1 debounce behavior (last-write-wins)
- queue isolation by thread
- queue cleared on disconnect

**PostgresStateAdapter** (8 new tests):
- INSERT query for enqueue
- overflow trimming query
- depth return value
- parsed entry from dequeue
- null from empty dequeue
- atomic DELETE-RETURNING for dequeue
- queueDepth return value
- zero depth for empty queue

**RedisStateAdapter / IoRedisStateAdapter** (3+3 existence checks):
- enqueue, dequeue, queueDepth method existence

**Chat concurrency** (5 new tests):
- drop-newest policy when queue is full
- drop-oldest policy evicts oldest entries
- expired entries skipped during drain
- onNewMessage pattern handlers receive context
- onSubscribedMessage handlers receive skipped context

Total new tests: 27 (780 chat + 33 memory + 59 pg)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Address feedback

* Support a channel locking strategy, make it default for WhatsApp and Telegram

* docs: fix typo "Committment" → "Commitment" (#274)

Co-authored-by: Arif Kobel <arif.kobel@phorax.com>

* Add webhook verification to GChat (#287)

- Issues a warning if required env vars are not present (also for telegram)
- Makes telegram use a time-safe verifier

* Make adapters depend on `chat` as a real dep (#289)

Without this, changeset will make any dep change a major change

* Version Packages (#290)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Fix serialization

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Arif Kobel <102538661+ArifKobel@users.noreply.github.com>
Co-authored-by: Arif Kobel <arif.kobel@phorax.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-24 13:46:38 -07:00
github-actions[bot] 80a8a34a73 Version Packages (#290)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@chat-adapter/discord@4.21.0 @chat-adapter/whatsapp@4.21.0 @chat-adapter/telegram@4.21.0 @chat-adapter/teams@4.21.0 @chat-adapter/state-redis@4.21.0 @chat-adapter/state-pg@4.21.0 @chat-adapter/state-memory@4.21.0 @chat-adapter/state-ioredis@4.21.0 @chat-adapter/slack@4.21.0 @chat-adapter/shared@4.21.0 @chat-adapter/linear@4.21.0 @chat-adapter/github@4.21.0 @chat-adapter/gchat@4.21.0 chat@4.21.0
2026-03-23 08:04:36 -07:00
Malte Ubl d778f722af Make adapters depend on chat as a real dep (#289)
Without this, changeset will make any dep change a major change
2026-03-23 07:57:42 -07:00
Malte Ubl 000792b8f8 Add webhook verification to GChat (#287)
- Issues a warning if required env vars are not present (also for telegram)
- Makes telegram use a time-safe verifier
2026-03-23 07:21:43 -07:00
Arif Kobel 9c498f4fd7 docs: fix typo "Committment" → "Commitment" (#274)
Co-authored-by: Arif Kobel <arif.kobel@phorax.com>
2026-03-21 16:14:00 -07:00
Malte Ubl 8337173704 Programmatically ensure that SKILL.md is always up-to-date and compiles (#272)
* Update the SKILL.md and add a test that checks its consistency

* Refactor docs test

* Typed and knip
2026-03-19 16:45:38 -07:00
Malte Ubl af8c9580ac Revert "Revert "Test TS compilation of all docs (#264)" (#265)" (#266)
This reverts commit d90f50c1a3.
2026-03-17 15:17:36 -07:00
Malte Ubl d90f50c1a3 Revert "Test TS compilation of all docs (#264)" (#265)
This reverts commit 449850f8b8.
2026-03-17 15:16:33 -07:00
Malte Ubl 449850f8b8 Test TS compilation of all docs (#264)
* Test TS compilation of all docs

* Lint
2026-03-17 15:11:52 -07:00
Malte Ubl d114ebfabf toAIMessages docs improvements (#263)
* toAIMessages docs improvements

* toAIMessages docs improvements
2026-03-17 14:38:23 -07:00
Hayden Bleasel 6646702128 Security fixes (#262)
* Bump Next

* Fix code scanning issues
2026-03-17 11:23:47 -07:00