chat 4.31.0 → 4.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  > npm package: [`chat`](https://www.npmjs.com/package/chat)
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/chat)](https://www.npmjs.com/package/chat)
6
- [![npm downloads](https://img.shields.io/npm/dm/chat)](https://www.npmjs.com/package/chat)
5
+ [![Agent Stack](https://img.shields.io/badge/Agent%20Stack-000?style=flat-square&logo=vercel&logoColor=FFF&labelColor=000&color=000)](https://vercel.com/kb/agent-stack)
6
+ [![MIT License](https://img.shields.io/badge/License-MIT-000?style=flat-square&logo=opensourceinitiative&logoColor=white&labelColor=000&color=000)](../../LICENSE)
7
7
 
8
8
  Universal TypeScript SDK for building multi-platform chat bots and AI agents on Slack, Teams, Google Chat, Discord, WhatsApp, and more. Provides the `Chat` class, event handlers, JSX cards, emoji helpers, and type-safe message formatting.
9
9
 
@@ -148,6 +148,35 @@ declare const ADAPTERS: {
148
148
  readonly slug: "agentphone";
149
149
  readonly type: "platform";
150
150
  };
151
+ readonly "cloudflare-agents": {
152
+ readonly description: "Cloudflare Agents state adapter for Chat SDK. Stores subscriptions, locks, queues, and history in Durable Object SQLite via ChatSdkStateAgent sub-agents.";
153
+ readonly env: {
154
+ readonly config: readonly ["parent", "agent", "name", "shardKey", "keyShard"];
155
+ readonly notes: "No environment variables are required. State is stored in Durable Object SQLite via ChatSdkStateAgent sub-agents; add the parent Agent to your Durable Object migration and re-export ChatSdkStateAgent from the Worker entry point.";
156
+ };
157
+ readonly factoryExport: "createChatSdkState";
158
+ readonly group: "vendor-official";
159
+ readonly name: "Cloudflare Agents";
160
+ readonly packageName: "agents";
161
+ readonly peerDeps: readonly [];
162
+ readonly slug: "cloudflare-agents";
163
+ readonly type: "state";
164
+ };
165
+ readonly dial: {
166
+ readonly description: "SMS, MMS, iMessage, and inbound voice-call transcripts for Chat SDK, built and maintained by Dial. One handler answers phone traffic the same way it answers Slack/Teams/Discord, with HMAC-signed webhooks and replies over @getdial/sdk.";
167
+ readonly env: {
168
+ readonly config: readonly ["apiBaseUrl", "botName", "logger"];
169
+ readonly optional: readonly [EnvVar, EnvVar, EnvVar];
170
+ readonly required: readonly [EnvVar, EnvVar];
171
+ };
172
+ readonly factoryExport: "createDialAdapter";
173
+ readonly group: "vendor-official";
174
+ readonly name: "Dial";
175
+ readonly packageName: "@getdial/chat-sdk-adapter";
176
+ readonly peerDeps: readonly [];
177
+ readonly slug: "dial";
178
+ readonly type: "platform";
179
+ };
151
180
  readonly discord: {
152
181
  readonly description: "Create Discord bots with slash commands, threads, and rich embeds.";
153
182
  readonly env: {
@@ -172,7 +201,7 @@ declare const ADAPTERS: {
172
201
  readonly label: "GitHub App";
173
202
  readonly vars: readonly [EnvVar, EnvVar];
174
203
  }];
175
- readonly optional: readonly [EnvVar, EnvVar, EnvVar];
204
+ readonly optional: readonly [EnvVar, EnvVar, EnvVar, EnvVar];
176
205
  readonly required: readonly [EnvVar];
177
206
  };
178
207
  readonly factoryExport: "createGitHubAdapter";
@@ -273,6 +302,20 @@ declare const ADAPTERS: {
273
302
  readonly slug: "linear";
274
303
  readonly type: "platform";
275
304
  };
305
+ readonly linq: {
306
+ readonly description: "iMessage and SMS adapter for Chat SDK, built and maintained by Linq.";
307
+ readonly env: {
308
+ readonly config: readonly ["baseURL"];
309
+ readonly required: readonly [EnvVar, EnvVar];
310
+ };
311
+ readonly factoryExport: "createLinqAdapter";
312
+ readonly group: "vendor-official";
313
+ readonly name: "Linq";
314
+ readonly packageName: "@linqapp/chat-sdk-adapter";
315
+ readonly peerDeps: readonly [];
316
+ readonly slug: "linq";
317
+ readonly type: "platform";
318
+ };
276
319
  readonly liveblocks: {
277
320
  readonly description: "Liveblocks Comments adapter for building conversational bots on top of Liveblocks rooms, threads, and comments.";
278
321
  readonly env: {
@@ -335,6 +378,41 @@ declare const ADAPTERS: {
335
378
  readonly slug: "messenger";
336
379
  readonly type: "platform";
337
380
  };
381
+ readonly novu: {
382
+ readonly description: "Multi-channel agents with one-click channel setup, identity and multi-tenancy";
383
+ readonly env: {
384
+ readonly optional: readonly [EnvVar];
385
+ readonly required: readonly [EnvVar, EnvVar];
386
+ };
387
+ readonly factoryExport: "createNovuAdapter";
388
+ readonly group: "vendor-official";
389
+ readonly name: "Novu";
390
+ readonly packageName: "@novu/chat-sdk-adapter";
391
+ readonly peerDeps: readonly [];
392
+ readonly slug: "novu";
393
+ readonly type: "platform";
394
+ };
395
+ readonly photon: {
396
+ readonly description: "iMessage adapter for Chat SDK, built and maintained by Photon. Cloud, self-hosted, and on-device (macOS) iMessage over spectrum-ts.";
397
+ readonly env: {
398
+ readonly config: readonly ["clients", "logger"];
399
+ readonly credentialModes: readonly [{
400
+ readonly label: "Spectrum Cloud";
401
+ readonly vars: readonly [EnvVar, EnvVar];
402
+ }, {
403
+ readonly label: "Self-hosted";
404
+ readonly vars: readonly [EnvVar, EnvVar];
405
+ }];
406
+ readonly optional: readonly [EnvVar, EnvVar, EnvVar];
407
+ };
408
+ readonly factoryExport: "createiMessageAdapter";
409
+ readonly group: "vendor-official";
410
+ readonly name: "Photon";
411
+ readonly packageName: "@photon-ai/chat-adapter-imessage";
412
+ readonly peerDeps: readonly [];
413
+ readonly slug: "photon";
414
+ readonly type: "platform";
415
+ };
338
416
  readonly postgres: {
339
417
  readonly description: "Production state adapter using PostgreSQL for persistence and distributed locking.";
340
418
  readonly env: {
@@ -474,7 +552,7 @@ declare const ADAPTERS: {
474
552
  readonly type: "platform";
475
553
  };
476
554
  readonly velt: {
477
- readonly description: "Velt Comments adapter for building bots that read and respond in Velt comment threads on documents, text editors, and canvases.";
555
+ readonly description: "Velt Comments adapter for bots that read, reply, mention, and start threads in anchored comments across documents, rich-text editors, canvases, PDFs, and video. Includes per-comment document context and an AI streaming-reply sample app.";
478
556
  readonly env: {
479
557
  readonly config: readonly ["botUserId", "botUserName", "webhookVersion", "resolveUsers", "selfHostingConfig"];
480
558
  readonly optional: readonly [EnvVar, EnvVar];
@@ -516,6 +594,27 @@ declare const ADAPTERS: {
516
594
  readonly slug: "whatsapp";
517
595
  readonly type: "platform";
518
596
  };
597
+ readonly x: {
598
+ readonly description: "Reply to public mentions and hold direct message conversations on X (Twitter) with the X API v2.";
599
+ readonly env: {
600
+ readonly credentialModes: readonly [{
601
+ readonly label: "Static access token";
602
+ readonly vars: readonly [EnvVar];
603
+ }, {
604
+ readonly label: "Managed OAuth refresh";
605
+ readonly vars: readonly [EnvVar, EnvVar];
606
+ }];
607
+ readonly optional: readonly [EnvVar, EnvVar, EnvVar, EnvVar, EnvVar];
608
+ readonly required: readonly [EnvVar];
609
+ };
610
+ readonly factoryExport: "createXAdapter";
611
+ readonly group: "official";
612
+ readonly name: "X";
613
+ readonly packageName: "@chat-adapter/x";
614
+ readonly peerDeps: readonly [];
615
+ readonly slug: "x";
616
+ readonly type: "platform";
617
+ };
519
618
  readonly zernio: {
520
619
  readonly description: "Unified social media DM adapter covering Instagram, Facebook, Telegram, WhatsApp, X/Twitter, Bluesky, and Reddit through a single integration.";
521
620
  readonly env: {
@@ -40,6 +40,54 @@ var ADAPTERS = {
40
40
  slug: "agentphone",
41
41
  type: "platform"
42
42
  },
43
+ "cloudflare-agents": {
44
+ description: "Cloudflare Agents state adapter for Chat SDK. Stores subscriptions, locks, queues, and history in Durable Object SQLite via ChatSdkStateAgent sub-agents.",
45
+ env: {
46
+ config: ["parent", "agent", "name", "shardKey", "keyShard"],
47
+ notes: "No environment variables are required. State is stored in Durable Object SQLite via ChatSdkStateAgent sub-agents; add the parent Agent to your Durable Object migration and re-export ChatSdkStateAgent from the Worker entry point."
48
+ },
49
+ factoryExport: "createChatSdkState",
50
+ group: "vendor-official",
51
+ name: "Cloudflare Agents",
52
+ packageName: "agents",
53
+ peerDeps: [],
54
+ slug: "cloudflare-agents",
55
+ type: "state"
56
+ },
57
+ dial: {
58
+ description: "SMS, MMS, iMessage, and inbound voice-call transcripts for Chat SDK, built and maintained by Dial. One handler answers phone traffic the same way it answers Slack/Teams/Discord, with HMAC-signed webhooks and replies over @getdial/sdk.",
59
+ env: {
60
+ config: ["apiBaseUrl", "botName", "logger"],
61
+ optional: [
62
+ secretEnv(
63
+ "DIAL_WEBHOOK_SECRET",
64
+ "HMAC-SHA256 signing secret from the Dial webhook subscription; enables signature verification of inbound requests."
65
+ ),
66
+ env(
67
+ "DIAL_API_URL",
68
+ "Override the Dial API host. Defaults to https://api.getdial.ai."
69
+ ),
70
+ env(
71
+ "BOT_USERNAME",
72
+ 'Display name Chat SDK uses for the bot. Defaults to "bot".'
73
+ )
74
+ ],
75
+ required: [
76
+ secretEnv("DIAL_API_KEY", "Dial API key (sk_live_\u2026)."),
77
+ env(
78
+ "DIAL_FROM_NUMBER_ID",
79
+ "Dial's ID of the phone number the bot sends from."
80
+ )
81
+ ]
82
+ },
83
+ factoryExport: "createDialAdapter",
84
+ group: "vendor-official",
85
+ name: "Dial",
86
+ packageName: "@getdial/chat-sdk-adapter",
87
+ peerDeps: [],
88
+ slug: "dial",
89
+ type: "platform"
90
+ },
43
91
  discord: {
44
92
  description: "Create Discord bots with slash commands, threads, and rich embeds.",
45
93
  env: {
@@ -86,6 +134,10 @@ var ADAPTERS = {
86
134
  "Installation ID for single-installation app deployments."
87
135
  ),
88
136
  env("GITHUB_BOT_USERNAME", "Bot username for mention detection."),
137
+ env(
138
+ "GITHUB_BOT_USER_ID",
139
+ "Numeric bot user ID for self-message detection; recommended on serverless and with Vercel Connect to prevent reply loops."
140
+ ),
89
141
  urlEnv("GITHUB_API_URL", "Override the GitHub API base URL.")
90
142
  ],
91
143
  required: [secretEnv("GITHUB_WEBHOOK_SECRET", "Webhook signing secret.")]
@@ -281,6 +333,26 @@ var ADAPTERS = {
281
333
  slug: "linear",
282
334
  type: "platform"
283
335
  },
336
+ linq: {
337
+ description: "iMessage and SMS adapter for Chat SDK, built and maintained by Linq.",
338
+ env: {
339
+ config: ["baseURL"],
340
+ required: [
341
+ secretEnv("LINQ_API_KEY", "Linq API key for outbound API calls."),
342
+ secretEnv(
343
+ "LINQ_WEBHOOK_SECRET",
344
+ "Webhook signing secret used to verify inbound HMAC-SHA256 signatures."
345
+ )
346
+ ]
347
+ },
348
+ factoryExport: "createLinqAdapter",
349
+ group: "vendor-official",
350
+ name: "Linq",
351
+ packageName: "@linqapp/chat-sdk-adapter",
352
+ peerDeps: [],
353
+ slug: "linq",
354
+ type: "platform"
355
+ },
284
356
  liveblocks: {
285
357
  description: "Liveblocks Comments adapter for building conversational bots on top of Liveblocks rooms, threads, and comments.",
286
358
  env: {
@@ -391,6 +463,86 @@ var ADAPTERS = {
391
463
  slug: "messenger",
392
464
  type: "platform"
393
465
  },
466
+ novu: {
467
+ description: "Multi-channel agents with one-click channel setup, identity and multi-tenancy",
468
+ env: {
469
+ optional: [
470
+ urlEnv(
471
+ "NOVU_API_BASE_URL",
472
+ "API base URL. Defaults to https://api.novu.co."
473
+ )
474
+ ],
475
+ required: [
476
+ secretEnv(
477
+ "NOVU_SECRET_KEY",
478
+ "Novu API key that authorizes replies and verifies the inbound HMAC. Set automatically by npx novu connect."
479
+ ),
480
+ env(
481
+ "NOVU_AGENT_IDENTIFIER",
482
+ "Bridge agent ID set automatically by npx novu connect."
483
+ )
484
+ ]
485
+ },
486
+ factoryExport: "createNovuAdapter",
487
+ group: "vendor-official",
488
+ name: "Novu",
489
+ packageName: "@novu/chat-sdk-adapter",
490
+ peerDeps: [],
491
+ slug: "novu",
492
+ type: "platform"
493
+ },
494
+ photon: {
495
+ description: "iMessage adapter for Chat SDK, built and maintained by Photon. Cloud, self-hosted, and on-device (macOS) iMessage over spectrum-ts.",
496
+ env: {
497
+ config: ["clients", "logger"],
498
+ credentialModes: [
499
+ {
500
+ label: "Spectrum Cloud",
501
+ vars: [
502
+ env("IMESSAGE_PROJECT_ID", "Spectrum Cloud project ID."),
503
+ secretEnv(
504
+ "IMESSAGE_PROJECT_SECRET",
505
+ "Spectrum Cloud project secret."
506
+ )
507
+ ]
508
+ },
509
+ {
510
+ label: "Self-hosted",
511
+ vars: [
512
+ urlEnv(
513
+ "IMESSAGE_SERVER_URL",
514
+ "gRPC host:port of a self-hosted iMessage server (not an https URL)."
515
+ ),
516
+ secretEnv(
517
+ "IMESSAGE_API_KEY",
518
+ "Auth token for the self-hosted server."
519
+ )
520
+ ]
521
+ }
522
+ ],
523
+ optional: [
524
+ env(
525
+ "IMESSAGE_LOCAL",
526
+ 'Set to "false" for cloud/self-host; on-device (local, macOS) mode is the default.'
527
+ ),
528
+ secretEnv(
529
+ "IMESSAGE_WEBHOOK_SECRET",
530
+ "Per-webhook signing secret for verifying Spectrum Cloud deliveries."
531
+ ),
532
+ env(
533
+ "IMESSAGE_PHONE",
534
+ "Routing/identity phone for multi-number setups."
535
+ )
536
+ ]
537
+ },
538
+ factoryExport: "createiMessageAdapter",
539
+ group: "vendor-official",
540
+ name: "Photon",
541
+ packageName: "@photon-ai/chat-adapter-imessage",
542
+ peerDeps: [],
543
+ slug: "photon",
544
+ type: "platform"
545
+ },
394
546
  postgres: {
395
547
  description: "Production state adapter using PostgreSQL for persistence and distributed locking.",
396
548
  env: {
@@ -616,7 +768,7 @@ var ADAPTERS = {
616
768
  type: "platform"
617
769
  },
618
770
  velt: {
619
- description: "Velt Comments adapter for building bots that read and respond in Velt comment threads on documents, text editors, and canvases.",
771
+ description: "Velt Comments adapter for bots that read, reply, mention, and start threads in anchored comments across documents, rich-text editors, canvases, PDFs, and video. Includes per-comment document context and an AI streaming-reply sample app.",
620
772
  env: {
621
773
  config: [
622
774
  "botUserId",
@@ -687,6 +839,64 @@ var ADAPTERS = {
687
839
  slug: "whatsapp",
688
840
  type: "platform"
689
841
  },
842
+ x: {
843
+ description: "Reply to public mentions and hold direct message conversations on X (Twitter) with the X API v2.",
844
+ env: {
845
+ credentialModes: [
846
+ {
847
+ label: "Static access token",
848
+ vars: [
849
+ secretEnv(
850
+ "X_USER_ACCESS_TOKEN",
851
+ "OAuth 2.0 user-context access token for outbound API calls."
852
+ )
853
+ ]
854
+ },
855
+ {
856
+ label: "Managed OAuth refresh",
857
+ vars: [
858
+ env("X_CLIENT_ID", "OAuth 2.0 client ID."),
859
+ secretEnv(
860
+ "X_REFRESH_TOKEN",
861
+ "OAuth 2.0 refresh token (requires the offline.access scope)."
862
+ )
863
+ ]
864
+ }
865
+ ],
866
+ optional: [
867
+ secretEnv(
868
+ "X_CLIENT_SECRET",
869
+ "OAuth 2.0 client secret for confidential clients."
870
+ ),
871
+ secretEnv(
872
+ "X_ENCRYPTION_KEY",
873
+ "AES-256-GCM key for encrypting stored OAuth tokens."
874
+ ),
875
+ env(
876
+ "X_USER_ID",
877
+ "Bot account user ID. Fetched from /2/users/me when omitted."
878
+ ),
879
+ env(
880
+ "X_USERNAME",
881
+ "Bot account handle used for mention detection. Fetched when omitted."
882
+ ),
883
+ urlEnv("X_API_BASE_URL", "Override the X API base URL.")
884
+ ],
885
+ required: [
886
+ secretEnv(
887
+ "X_CONSUMER_SECRET",
888
+ "App API key secret used for webhook CRC and signature verification."
889
+ )
890
+ ]
891
+ },
892
+ factoryExport: "createXAdapter",
893
+ group: "official",
894
+ name: "X",
895
+ packageName: "@chat-adapter/x",
896
+ peerDeps: [],
897
+ slug: "x",
898
+ type: "platform"
899
+ },
690
900
  zernio: {
691
901
  description: "Unified social media DM adapter covering Instagram, Facebook, Telegram, WhatsApp, X/Twitter, Bluesky, and Reddit through a single integration.",
692
902
  env: {
@@ -1,10 +1,10 @@
1
- import { x as Chat, w as ChannelVisibility } from '../chat-BjhJs_sP.js';
2
- export { d as AiAssistantMessage, e as AiFilePart, f as AiImagePart, g as AiMessage, h as AiMessagePart, i as AiTextPart, j as AiUserMessage, aZ as ToAiMessagesOptions, b7 as toAiMessages } from '../chat-BjhJs_sP.js';
1
+ import { C as Chat, a as ChannelVisibility } from '../messages-x-XVhW8B.js';
2
+ export { A as AiAssistantMessage, b as AiFilePart, c as AiImagePart, d as AiMessage, e as AiMessagePart, f as AiTextPart, g as AiUserMessage, T as ToAiMessagesOptions, t as toAiMessages } from '../messages-x-XVhW8B.js';
3
3
  import * as ai from 'ai';
4
4
  import { Tool } from 'ai';
5
5
  import '@workflow/serde';
6
6
  import 'mdast';
7
- import '../jsx-runtime-CzthIo1o.js';
7
+ import '../jsx-runtime-LBOLBP4o.js';
8
8
 
9
9
  /**
10
10
  * The Chat instance used by all tools to dispatch operations.
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { ay as PostableObject, b as Adapter, az as PostableObjectContext, aN as StreamChunk, aU as ThreadHistoryCache, aV as ThreadHistoryConfig, aO as StreamEvent, L as EmojiFormats, M as EmojiMapConfig, N as EmojiValue, b4 as WellKnownEmoji, G as CustomEmojiMap, c as AdapterPostableMessage } from './chat-BjhJs_sP.js';
2
- export { A as ActionEvent, a as ActionHandler, d as AiAssistantMessage, e as AiFilePart, f as AiImagePart, g as AiMessage, h as AiMessagePart, i as AiTextPart, j as AiUserMessage, k as AppHomeOpenedEvent, l as AppHomeOpenedHandler, m as AppendInput, n as AppendOptions, o as AssistantContextChangedEvent, p as AssistantContextChangedHandler, q as AssistantThreadStartedEvent, r as AssistantThreadStartedHandler, s as Attachment, t as Author, C as Channel, u as ChannelImpl, v as ChannelInfo, w as ChannelVisibility, x as Chat, y as ChatConfig, z as ChatInstance, B as ConcurrencyConfig, D as ConcurrencyStrategy, E as ConsoleLogger, F as CountQuery, H as DeleteTarget, I as DirectMessageHandler, J as DurationString, K as Emoji, O as EphemeralMessage, P as FetchDirection, Q as FetchOptions, R as FetchResult, S as FileUpload, T as FormattedContent, U as IdentityContext, V as IdentityResolver, W as LinkPreview, X as ListQuery, Y as ListThreadsOptions, Z as ListThreadsResult, _ as Lock, $ as LockScope, a0 as LockScopeContext, a1 as LogLevel, a2 as Logger, a3 as MarkdownTextChunk, a4 as MemberJoinedChannelEvent, a5 as MemberJoinedChannelHandler, a6 as MentionHandler, a7 as Message, a8 as MessageContext, a9 as MessageData, aa as MessageHandler, ab as MessageMetadata, ac as MessageSubject, ad as ModalClearResponse, ae as ModalCloseEvent, af as ModalCloseHandler, ag as ModalCloseResponse, ah as ModalErrorsResponse, ai as ModalPushResponse, aj as ModalResponse, ak as ModalSubmitEvent, al as ModalSubmitHandler, am as ModalUpdateResponse, an as OptionsLoadEvent, ao as OptionsLoadGroup, ap as OptionsLoadHandler, aq as OptionsLoadResult, ar as PlanUpdateChunk, as as PostEphemeralOptions, at as Postable, au as PostableAst, av as PostableCard, aw as PostableMarkdown, ax as PostableMessage, aA as PostableRaw, aB as QueueEntry, aC as RawMessage, aD as ReactionEvent, aE as ReactionHandler, aF as ScheduledMessage, aG as SentMessage, aH as SerializedChannel, aI as SerializedMessage, aJ as SerializedThread, aK as SlashCommandEvent, aL as SlashCommandHandler, aM as StateAdapter, aP as StreamOptions, aQ as SubscribedMessageHandler, aR as THREAD_STATE_TTL_MS, aS as TaskUpdateChunk, aT as Thread, aW as ThreadImpl, aX as ThreadInfo, aY as ThreadSummary, aZ as ToAiMessagesOptions, a_ as TranscriptEntry, a$ as TranscriptRole, b0 as TranscriptsApi, b1 as TranscriptsConfig, b2 as UserInfo, b3 as WebhookOptions, b5 as deriveChannelId, b6 as isPostableObject, b7 as toAiMessages } from './chat-BjhJs_sP.js';
1
+ import { P as PostableObject, h as Adapter, i as PostableObjectContext, S as StreamChunk, j as ThreadHistoryCache, k as ThreadHistoryConfig, l as StreamEvent, E as EmojiFormats, m as EmojiMapConfig, n as EmojiValue, W as WellKnownEmoji, o as CustomEmojiMap, p as AdapterPostableMessage } from './messages-x-XVhW8B.js';
2
+ export { q as ActionEvent, r as ActionHandler, A as AiAssistantMessage, b as AiFilePart, c as AiImagePart, d as AiMessage, e as AiMessagePart, f as AiTextPart, g as AiUserMessage, s as AppHomeOpenedEvent, u as AppHomeOpenedHandler, v as AppendInput, w as AppendOptions, x as AssistantContextChangedEvent, y as AssistantContextChangedHandler, z as AssistantThreadStartedEvent, B as AssistantThreadStartedHandler, D as Attachment, F as Author, G as Channel, H as ChannelImpl, I as ChannelInfo, a as ChannelVisibility, C as Chat, J as ChatConfig, K as ChatInstance, L as ConcurrencyConfig, M as ConcurrencyStrategy, N as ConsoleLogger, O as CountQuery, Q as DeleteTarget, R as DirectMessageHandler, U as DurationString, V as Emoji, X as EphemeralMessage, Y as FetchDirection, Z as FetchOptions, _ as FetchResult, $ as FileUpload, a0 as FormattedContent, a1 as IdentityContext, a2 as IdentityResolver, a3 as LinkPreview, a4 as ListQuery, a5 as ListThreadsOptions, a6 as ListThreadsResult, a7 as Lock, a8 as LockScope, a9 as LockScopeContext, aa as LogLevel, ab as Logger, ac as MarkdownTextChunk, ad as MemberJoinedChannelEvent, ae as MemberJoinedChannelHandler, af as MentionHandler, ag as Message, ah as MessageContext, ai as MessageData, aj as MessageHandler, ak as MessageMetadata, al as MessageSubject, am as ModalClearResponse, an as ModalCloseEvent, ao as ModalCloseHandler, ap as ModalCloseResponse, aq as ModalErrorsResponse, ar as ModalPushResponse, as as ModalResponse, at as ModalSubmitEvent, au as ModalSubmitHandler, av as ModalUpdateResponse, aw as OptionsLoadEvent, ax as OptionsLoadGroup, ay as OptionsLoadHandler, az as OptionsLoadResult, aA as PlanUpdateChunk, aB as PostEphemeralOptions, aC as Postable, aD as PostableAst, aE as PostableCard, aF as PostableMarkdown, aG as PostableMessage, aH as PostableRaw, aI as QueueEntry, aJ as RawMessage, aK as ReactionEvent, aL as ReactionHandler, aM as ScheduledMessage, aN as SentMessage, aO as SerializedChannel, aP as SerializedMessage, aQ as SerializedThread, aR as SlashCommandEvent, aS as SlashCommandHandler, aT as StateAdapter, aU as StreamOptions, aV as SubscribedMessageHandler, aW as THREAD_STATE_TTL_MS, aX as TaskUpdateChunk, aY as Thread, aZ as ThreadImpl, a_ as ThreadInfo, a$ as ThreadSummary, T as ToAiMessagesOptions, b0 as TranscriptEntry, b1 as TranscriptRole, b2 as TranscriptsApi, b3 as TranscriptsConfig, b4 as UserInfo, b5 as WebhookOptions, b6 as deriveChannelId, b7 as isPostableObject, t as toAiMessages } from './messages-x-XVhW8B.js';
3
3
  import { Root, List, Content, Blockquote, Code, Emphasis, InlineCode, Delete, Link, ListItem, Paragraph, Strong, TableCell, Table as Table$1, TableRow, Text } from 'mdast';
4
4
  export { Blockquote, Code, Content, Delete, Emphasis, InlineCode, Link, List, ListItem, Table as MdastTable, Nodes, Paragraph, Root, Strong, TableCell, TableRow, Text } from 'mdast';
5
- import { g as CardElement, C as CardChild, A as ActionsComponent, B as ButtonComponent, f as CardComponent, j as CardLinkComponent, a9 as TextComponent, D as DividerComponent, E as ExternalSelectComponent, F as FieldComponent, w as FieldsComponent, I as ImageComponent, L as LinkButtonComponent, P as ModalComponent, T as RadioSelectComponent, W as SectionComponent, Y as SelectComponent, _ as SelectOptionComponent, a3 as Table$2, ab as TextInputComponent, ah as cardChildToFallbackText$1, ai as fromReactElement$1, aj as fromReactModalElement$1, ak as isCardElement$1, am as isJSX$1, an as isModalElement$1, ar as toCardElement$1, as as toModalElement$1 } from './jsx-runtime-CzthIo1o.js';
6
- export { a as ActionsElement, b as ButtonElement, c as ButtonOptions, d as ButtonProps, e as ButtonStyle, h as CardJSXElement, i as CardJSXProps, k as CardLinkProps, l as CardOptions, m as CardProps, n as ChatElement, o as ContainerProps, p as DividerElement, q as DividerProps, r as ExternalSelectElement, s as ExternalSelectOptions, t as ExternalSelectProps, u as FieldElement, v as FieldProps, x as FieldsElement, z as ImageElement, G as ImageProps, H as LinkButtonElement, K as LinkButtonOptions, M as LinkButtonProps, N as LinkElement, O as ModalChild, Q as ModalElement, R as ModalOptions, S as ModalProps, U as RadioSelectElement, V as RadioSelectOptions, X as SectionElement, Z as SelectElement, $ as SelectOptionElement, a0 as SelectOptionProps, a1 as SelectOptions, a2 as SelectProps, a4 as TableAlignment, a6 as TableElement, a7 as TableOptions, aa as TextElement, ac as TextInputElement, ad as TextInputOptions, ae as TextInputProps, af as TextProps, ag as TextStyle } from './jsx-runtime-CzthIo1o.js';
5
+ import { C as CardElement, a as CardChild, A as ActionsComponent, B as ButtonComponent, b as CardComponent, c as CardLinkComponent, T as TextComponent, D as DividerComponent, E as ExternalSelectComponent, F as FieldComponent, d as FieldsComponent, I as ImageComponent, L as LinkButtonComponent, M as ModalComponent, R as RadioSelectComponent, S as SectionComponent, e as SelectComponent, f as SelectOptionComponent, g as Table$2, h as TextInputComponent, i as cardChildToFallbackText$1, j as fromReactElement$1, k as fromReactModalElement$1, l as isCardElement$1, m as isJSX$1, n as isModalElement$1, t as toCardElement$1, o as toModalElement$1 } from './jsx-runtime-LBOLBP4o.js';
6
+ export { p as ActionsElement, q as ButtonElement, r as ButtonOptions, s as ButtonProps, u as ButtonStyle, v as CardJSXElement, w as CardJSXProps, x as CardLinkProps, y as CardOptions, z as CardProps, G as ChatElement, H as ContainerProps, J as DividerElement, K as DividerProps, N as ExternalSelectElement, O as ExternalSelectOptions, P as ExternalSelectProps, Q as FieldElement, U as FieldProps, V as FieldsElement, W as ImageElement, X as ImageProps, Y as LinkButtonElement, Z as LinkButtonOptions, _ as LinkButtonProps, $ as LinkElement, a0 as ModalChild, a1 as ModalElement, a2 as ModalOptions, a3 as ModalProps, a4 as RadioSelectElement, a5 as RadioSelectOptions, a6 as SectionElement, a7 as SelectElement, a8 as SelectOptionElement, a9 as SelectOptionProps, aa as SelectOptions, ab as SelectProps, ac as TableAlignment, ad as TableElement, ae as TableOptions, af as TextElement, ag as TextInputElement, ah as TextInputOptions, ai as TextInputProps, aj as TextProps, ak as TextStyle } from './jsx-runtime-LBOLBP4o.js';
7
7
  import '@workflow/serde';
8
8
 
9
9
  /**
@@ -53,6 +53,8 @@ interface StartPlanOptions {
53
53
  initialMessage: PlanContent;
54
54
  }
55
55
  interface AddTaskOptions {
56
+ /** When true (default), mark existing in_progress tasks complete before adding. */
57
+ autoCompletePrevious?: boolean;
56
58
  /** Task details/substeps. */
57
59
  children?: PlanContent;
58
60
  title: PlanContent;
@@ -74,6 +76,7 @@ interface CompletePlanOptions {
74
76
  *
75
77
  * Create a plan with `new Plan({ initialMessage: "..." })` and post it with `thread.post(plan)`.
76
78
  * After posting, use methods like `addTask()`, `updateTask()`, and `complete()` to update it.
79
+ * For parallel steps, pass `autoCompletePrevious: false` to `addTask()` and use `updateTask({ id })` to update individual tasks.
77
80
  *
78
81
  * @example
79
82
  * ```typescript
@@ -351,7 +354,7 @@ declare const defaultEmojiResolver: EmojiResolver;
351
354
  * // Returns: "Thanks! 👍"
352
355
  * ```
353
356
  */
354
- declare function convertEmojiPlaceholders(text: string, platform: "slack" | "gchat" | "teams" | "discord" | "messenger" | "github" | "linear" | "whatsapp", resolver?: EmojiResolver): string;
357
+ declare function convertEmojiPlaceholders(text: string, platform: "slack" | "gchat" | "teams" | "discord" | "messenger" | "github" | "linear" | "whatsapp" | "x", resolver?: EmojiResolver): string;
355
358
  /** Base emoji object with well-known emoji as EmojiValue singletons */
356
359
  type BaseEmojiHelper = {
357
360
  [K in WellKnownEmoji]: EmojiValue;
package/dist/index.js CHANGED
@@ -2119,7 +2119,7 @@ var SLACK_USER_ID_REGEX = /^[UW][A-Z0-9]+$/;
2119
2119
  var DISCORD_SNOWFLAKE_REGEX = /^\d{17,19}$/;
2120
2120
  var LINEAR_UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2121
2121
  var NUMERIC_REGEX = /^\d+$/;
2122
- var DEDUPE_TTL_MS = 5 * 60 * 1e3;
2122
+ var DEDUPE_TTL_MS = 10 * 60 * 1e3;
2123
2123
  var MODAL_CONTEXT_TTL_MS = 24 * 60 * 60 * 1e3;
2124
2124
  var Chat = class {
2125
2125
  /**
@@ -3020,7 +3020,7 @@ var Chat = class {
3020
3020
  author: event.user,
3021
3021
  metadata: { dateSent: /* @__PURE__ */ new Date(), edited: false },
3022
3022
  attachments: []
3023
- }) : {};
3023
+ }) : void 0;
3024
3024
  const thread = event.threadId ? await this.createThread(
3025
3025
  event.adapter,
3026
3026
  event.threadId,
@@ -3140,7 +3140,7 @@ var Chat = class {
3140
3140
  const thread = await this.createThread(
3141
3141
  event.adapter,
3142
3142
  event.threadId,
3143
- event.message ?? {},
3143
+ event.message,
3144
3144
  isSubscribed
3145
3145
  );
3146
3146
  const fullEvent = {
@@ -3228,7 +3228,7 @@ var Chat = class {
3228
3228
  );
3229
3229
  }
3230
3230
  const threadId = await adapter.openDM(userId);
3231
- return this.createThread(adapter, threadId, {}, false);
3231
+ return this.createThread(adapter, threadId, void 0, false);
3232
3232
  }
3233
3233
  /**
3234
3234
  * Look up user information by user ID.
@@ -3333,7 +3333,7 @@ var Chat = class {
3333
3333
  "ADAPTER_NOT_FOUND"
3334
3334
  );
3335
3335
  }
3336
- return this.createThread(adapter, threadId, {}, false);
3336
+ return this.createThread(adapter, threadId, void 0, false);
3337
3337
  }
3338
3338
  /**
3339
3339
  * Infer which adapter to use based on the userId format.
@@ -3535,7 +3535,7 @@ var Chat = class {
3535
3535
  DEFAULT_LOCK_TTL_MS
3536
3536
  );
3537
3537
  if (!lock) {
3538
- const effectiveMaxSize = strategy === "debounce" ? 1 : maxQueueSize;
3538
+ const effectiveMaxSize = maxQueueSize;
3539
3539
  const depth = await this._stateAdapter.queueDepth(lockKey);
3540
3540
  if (depth >= effectiveMaxSize && strategy !== "debounce" && onQueueFull === "drop-newest") {
3541
3541
  this.logger.info("message-dropped", {
@@ -3580,7 +3580,7 @@ var Chat = class {
3580
3580
  enqueuedAt: Date.now(),
3581
3581
  expiresAt: Date.now() + queueEntryTtlMs
3582
3582
  },
3583
- 1
3583
+ maxQueueSize
3584
3584
  );
3585
3585
  this.logger.info("message-debouncing", {
3586
3586
  threadId,
@@ -3623,37 +3623,54 @@ var Chat = class {
3623
3623
  */
3624
3624
  async debounceLoop(lock, adapter, threadId, lockKey) {
3625
3625
  const { debounceMs } = this._concurrencyConfig;
3626
+ const skipped = [];
3626
3627
  while (true) {
3627
3628
  await sleep(debounceMs);
3628
3629
  await this._stateAdapter.extendLock(lock, DEFAULT_LOCK_TTL_MS);
3629
- const entry = await this._stateAdapter.dequeue(lockKey);
3630
- if (!entry) {
3630
+ const pending = [];
3631
+ while (true) {
3632
+ const entry = await this._stateAdapter.dequeue(lockKey);
3633
+ if (!entry) {
3634
+ break;
3635
+ }
3636
+ const msg = this.rehydrateMessage(entry.message, adapter);
3637
+ if (Date.now() <= entry.expiresAt) {
3638
+ pending.push({ message: msg, expiresAt: entry.expiresAt });
3639
+ } else {
3640
+ this.logger.info("message-expired", {
3641
+ threadId,
3642
+ lockKey,
3643
+ messageId: msg.id
3644
+ });
3645
+ }
3646
+ }
3647
+ if (pending.length === 0) {
3631
3648
  break;
3632
3649
  }
3633
- const msg = this.rehydrateMessage(entry.message, adapter);
3634
- if (Date.now() > entry.expiresAt) {
3635
- this.logger.info("message-expired", {
3636
- threadId,
3637
- lockKey,
3638
- messageId: msg.id
3639
- });
3640
- continue;
3650
+ const latest = pending.at(-1);
3651
+ if (!latest) {
3652
+ break;
3641
3653
  }
3654
+ skipped.push(...pending.slice(0, -1).map((entry) => entry.message));
3642
3655
  const depth = await this._stateAdapter.queueDepth(lockKey);
3643
3656
  if (depth > 0) {
3657
+ skipped.push(latest.message);
3644
3658
  this.logger.info("message-superseded", {
3645
3659
  threadId,
3646
3660
  lockKey,
3647
- droppedId: msg.id
3661
+ droppedId: latest.message.id
3648
3662
  });
3649
3663
  continue;
3650
3664
  }
3651
3665
  this.logger.info("message-dequeued", {
3652
3666
  threadId,
3653
3667
  lockKey,
3654
- messageId: msg.id
3668
+ messageId: latest.message.id
3669
+ });
3670
+ await this.dispatchToHandlers(adapter, threadId, latest.message, {
3671
+ skipped,
3672
+ totalSinceLastHandler: skipped.length + 1
3655
3673
  });
3656
- await this.dispatchToHandlers(adapter, threadId, msg);
3657
3674
  break;
3658
3675
  }
3659
3676
  }
@@ -3754,7 +3771,7 @@ var Chat = class {
3754
3771
  * subscription status, mention detection, and pattern matching.
3755
3772
  */
3756
3773
  async dispatchToHandlers(adapter, threadId, message, context) {
3757
- message.isMention = message.isMention || this.detectMention(adapter, message);
3774
+ const hasMention = this.setMentionFlags(adapter, message, context);
3758
3775
  const isSubscribed = await this._stateAdapter.isSubscribed(threadId);
3759
3776
  this.logger.debug("Subscription check", {
3760
3777
  threadId,
@@ -3814,7 +3831,7 @@ var Chat = class {
3814
3831
  );
3815
3832
  return;
3816
3833
  }
3817
- if (message.isMention) {
3834
+ if (message.isMention || hasMention && this.mentionHandlers.length > 0) {
3818
3835
  this.logger.debug("Bot mentioned", {
3819
3836
  threadId,
3820
3837
  text: message.text.slice(0, 100)
@@ -3850,6 +3867,15 @@ var Chat = class {
3850
3867
  });
3851
3868
  }
3852
3869
  }
3870
+ setMentionFlags(adapter, message, context) {
3871
+ message.isMention = message.isMention || this.detectMention(adapter, message);
3872
+ let hasMention = message.isMention === true;
3873
+ for (const skipped of context?.skipped ?? []) {
3874
+ skipped.isMention = skipped.isMention || this.detectMention(adapter, skipped);
3875
+ hasMention = hasMention || skipped.isMention === true;
3876
+ }
3877
+ return hasMention;
3878
+ }
3853
3879
  createThread(adapter, threadId, initialMessage, isSubscribedContext = false) {
3854
3880
  const channelId = adapter.channelIdFromThreadId(threadId);
3855
3881
  const isDM = adapter.isDM?.(threadId) ?? false;
@@ -4064,9 +4090,12 @@ var Plan = class {
4064
4090
  return null;
4065
4091
  }
4066
4092
  const title = contentToPlainText(options.title) || "Task";
4067
- for (const task of this._model.tasks) {
4068
- if (task.status === "in_progress") {
4069
- task.status = "complete";
4093
+ const autoCompletePrevious = options.autoCompletePrevious ?? true;
4094
+ if (autoCompletePrevious) {
4095
+ for (const task of this._model.tasks) {
4096
+ if (task.status === "in_progress") {
4097
+ task.status = "complete";
4098
+ }
4070
4099
  }
4071
4100
  }
4072
4101
  const nextTask = {
@@ -4474,6 +4503,8 @@ function convertEmojiPlaceholders(text2, platform, resolver = defaultEmojiResolv
4474
4503
  return resolver.toGChat(emojiName);
4475
4504
  case "whatsapp":
4476
4505
  return resolver.toGChat(emojiName);
4506
+ case "x":
4507
+ return resolver.toGChat(emojiName);
4477
4508
  default:
4478
4509
  return resolver.toGChat(emojiName);
4479
4510
  }