chat 4.32.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/dist/adapters/index.d.ts +72 -1
- package/dist/adapters/index.js +162 -0
- package/dist/ai/index.d.ts +3 -3
- package/dist/index.d.ts +5 -5
- package/dist/index.js +36 -17
- package/dist/{jsx-runtime-CzthIo1o.d.ts → jsx-runtime-LBOLBP4o.d.ts} +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/{chat-Dm1vQU3i.d.ts → messages-x-XVhW8B.d.ts} +255 -255
- package/docs/api/chat.mdx +2 -2
- package/docs/create-chat-sdk.mdx +15 -0
- package/docs/meta.json +1 -0
- package/docs/usage.mdx +1 -1
- package/docs/vercel-connect.mdx +162 -0
- package/package.json +1 -1
package/dist/adapters/index.d.ts
CHANGED
|
@@ -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";
|
|
@@ -363,6 +392,27 @@ declare const ADAPTERS: {
|
|
|
363
392
|
readonly slug: "novu";
|
|
364
393
|
readonly type: "platform";
|
|
365
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
|
+
};
|
|
366
416
|
readonly postgres: {
|
|
367
417
|
readonly description: "Production state adapter using PostgreSQL for persistence and distributed locking.";
|
|
368
418
|
readonly env: {
|
|
@@ -544,6 +594,27 @@ declare const ADAPTERS: {
|
|
|
544
594
|
readonly slug: "whatsapp";
|
|
545
595
|
readonly type: "platform";
|
|
546
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
|
+
};
|
|
547
618
|
readonly zernio: {
|
|
548
619
|
readonly description: "Unified social media DM adapter covering Instagram, Facebook, Telegram, WhatsApp, X/Twitter, Bluesky, and Reddit through a single integration.";
|
|
549
620
|
readonly env: {
|
package/dist/adapters/index.js
CHANGED
|
@@ -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.")]
|
|
@@ -439,6 +491,58 @@ var ADAPTERS = {
|
|
|
439
491
|
slug: "novu",
|
|
440
492
|
type: "platform"
|
|
441
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
|
+
},
|
|
442
546
|
postgres: {
|
|
443
547
|
description: "Production state adapter using PostgreSQL for persistence and distributed locking.",
|
|
444
548
|
env: {
|
|
@@ -735,6 +839,64 @@ var ADAPTERS = {
|
|
|
735
839
|
slug: "whatsapp",
|
|
736
840
|
type: "platform"
|
|
737
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
|
+
},
|
|
738
900
|
zernio: {
|
|
739
901
|
description: "Unified social media DM adapter covering Instagram, Facebook, Telegram, WhatsApp, X/Twitter, Bluesky, and Reddit through a single integration.",
|
|
740
902
|
env: {
|
package/dist/ai/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
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-
|
|
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 {
|
|
2
|
-
export {
|
|
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 {
|
|
6
|
-
export {
|
|
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
|
/**
|
|
@@ -354,7 +354,7 @@ declare const defaultEmojiResolver: EmojiResolver;
|
|
|
354
354
|
* // Returns: "Thanks! 👍"
|
|
355
355
|
* ```
|
|
356
356
|
*/
|
|
357
|
-
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;
|
|
358
358
|
/** Base emoji object with well-known emoji as EmojiValue singletons */
|
|
359
359
|
type BaseEmojiHelper = {
|
|
360
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 =
|
|
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
|
/**
|
|
@@ -3535,7 +3535,7 @@ var Chat = class {
|
|
|
3535
3535
|
DEFAULT_LOCK_TTL_MS
|
|
3536
3536
|
);
|
|
3537
3537
|
if (!lock) {
|
|
3538
|
-
const effectiveMaxSize =
|
|
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
|
-
|
|
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
|
|
3630
|
-
|
|
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
|
|
3634
|
-
if (
|
|
3635
|
-
|
|
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:
|
|
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:
|
|
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
|
}
|
|
@@ -3814,7 +3831,7 @@ var Chat = class {
|
|
|
3814
3831
|
);
|
|
3815
3832
|
return;
|
|
3816
3833
|
}
|
|
3817
|
-
if (message.isMention || hasMention) {
|
|
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)
|
|
@@ -4486,6 +4503,8 @@ function convertEmojiPlaceholders(text2, platform, resolver = defaultEmojiResolv
|
|
|
4486
4503
|
return resolver.toGChat(emojiName);
|
|
4487
4504
|
case "whatsapp":
|
|
4488
4505
|
return resolver.toGChat(emojiName);
|
|
4506
|
+
case "x":
|
|
4507
|
+
return resolver.toGChat(emojiName);
|
|
4489
4508
|
default:
|
|
4490
4509
|
return resolver.toGChat(emojiName);
|
|
4491
4510
|
}
|
|
@@ -784,4 +784,4 @@ declare namespace JSX {
|
|
|
784
784
|
}
|
|
785
785
|
}
|
|
786
786
|
|
|
787
|
-
export { type
|
|
787
|
+
export { type LinkElement as $, type ActionsComponent as A, type ButtonComponent as B, type CardElement as C, type DividerComponent as D, type ExternalSelectComponent as E, type FieldComponent as F, type ChatElement as G, type ContainerProps as H, type ImageComponent as I, type DividerElement as J, type DividerProps as K, type LinkButtonComponent as L, type ModalComponent as M, type ExternalSelectElement as N, type ExternalSelectOptions as O, type ExternalSelectProps as P, type FieldElement as Q, type RadioSelectComponent as R, type SectionComponent as S, type TextComponent as T, type FieldProps as U, type FieldsElement as V, type ImageElement as W, type ImageProps as X, type LinkButtonElement as Y, type LinkButtonOptions as Z, type LinkButtonProps as _, type CardChild as a, type ModalChild as a0, type ModalElement as a1, type ModalOptions as a2, type ModalProps as a3, type RadioSelectElement as a4, type RadioSelectOptions as a5, type SectionElement as a6, type SelectElement as a7, type SelectOptionElement as a8, type SelectOptionProps as a9, type SelectOptions as aa, type SelectProps as ab, type TableAlignment as ac, type TableElement as ad, type TableOptions as ae, type TextElement as af, type TextInputElement as ag, type TextInputOptions as ah, type TextInputProps as ai, type TextProps as aj, type TextStyle as ak, Fragment as al, JSX as am, type TableComponent as an, type TableProps as ao, isCardLinkProps as ap, jsx as aq, jsxDEV as ar, jsxs as as, type CardComponent as b, type CardLinkComponent as c, type FieldsComponent as d, type SelectComponent as e, type SelectOptionComponent as f, Table as g, type TextInputComponent as h, cardChildToFallbackText as i, fromReactElement as j, fromReactModalElement as k, isCardElement as l, isJSX as m, isModalElement as n, toModalElement as o, type ActionsElement as p, type ButtonElement as q, type ButtonOptions as r, type ButtonProps as s, toCardElement as t, type ButtonStyle as u, type CardJSXElement as v, type CardJSXProps as w, type CardLinkProps as x, type CardOptions as y, type CardProps as z };
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { A as ActionsComponent, B as ButtonComponent,
|
|
1
|
+
export { A as ActionsComponent, B as ButtonComponent, s as ButtonProps, b as CardComponent, v as CardJSXElement, w as CardJSXProps, c as CardLinkComponent, x as CardLinkProps, z as CardProps, G as ChatElement, H as ContainerProps, D as DividerComponent, K as DividerProps, E as ExternalSelectComponent, P as ExternalSelectProps, F as FieldComponent, U as FieldProps, d as FieldsComponent, al as Fragment, I as ImageComponent, X as ImageProps, am as JSX, L as LinkButtonComponent, _ as LinkButtonProps, M as ModalComponent, a3 as ModalProps, R as RadioSelectComponent, S as SectionComponent, e as SelectComponent, f as SelectOptionComponent, a9 as SelectOptionProps, ab as SelectProps, an as TableComponent, ao as TableProps, T as TextComponent, h as TextInputComponent, ai as TextInputProps, aj as TextProps, ap as isCardLinkProps, m as isJSX, aq as jsx, ar as jsxDEV, as as jsxs, t as toCardElement, o as toModalElement } from './jsx-runtime-LBOLBP4o.js';
|
|
@@ -1,6 +1,177 @@
|
|
|
1
1
|
import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from '@workflow/serde';
|
|
2
2
|
import { Root } from 'mdast';
|
|
3
|
-
import {
|
|
3
|
+
import { G as ChatElement, C as CardElement, a1 as ModalElement, a8 as SelectOptionElement } from './jsx-runtime-LBOLBP4o.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Message class with serialization support for workflow engines.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Input data for creating a Message instance.
|
|
11
|
+
* Use this interface when constructing Message objects.
|
|
12
|
+
*/
|
|
13
|
+
interface MessageData<TRawMessage = unknown> {
|
|
14
|
+
/** Attachments */
|
|
15
|
+
attachments: Attachment[];
|
|
16
|
+
/** Message author */
|
|
17
|
+
author: Author;
|
|
18
|
+
/** Structured formatting as an AST (mdast Root) */
|
|
19
|
+
formatted: FormattedContent;
|
|
20
|
+
/** Unique message ID */
|
|
21
|
+
id: string;
|
|
22
|
+
/** Whether the bot is @-mentioned in this message */
|
|
23
|
+
isMention?: boolean;
|
|
24
|
+
/** Links found in the message */
|
|
25
|
+
links?: LinkPreview[];
|
|
26
|
+
/** Message metadata */
|
|
27
|
+
metadata: MessageMetadata;
|
|
28
|
+
/** Platform-specific raw payload (escape hatch) */
|
|
29
|
+
raw: TRawMessage;
|
|
30
|
+
/** Plain text content (all formatting stripped) */
|
|
31
|
+
text: string;
|
|
32
|
+
/** Thread this message belongs to */
|
|
33
|
+
threadId: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Serialized message data for passing to external systems (e.g., workflow engines).
|
|
37
|
+
* Dates are converted to ISO strings, and non-serializable fields are omitted.
|
|
38
|
+
*/
|
|
39
|
+
interface SerializedMessage {
|
|
40
|
+
_type: "chat:Message";
|
|
41
|
+
attachments: Array<{
|
|
42
|
+
type: "image" | "file" | "video" | "audio";
|
|
43
|
+
url?: string;
|
|
44
|
+
name?: string;
|
|
45
|
+
mimeType?: string;
|
|
46
|
+
size?: number;
|
|
47
|
+
width?: number;
|
|
48
|
+
height?: number;
|
|
49
|
+
fetchMetadata?: Record<string, string>;
|
|
50
|
+
}>;
|
|
51
|
+
author: {
|
|
52
|
+
userId: string;
|
|
53
|
+
userName: string;
|
|
54
|
+
fullName: string;
|
|
55
|
+
isBot: boolean | "unknown";
|
|
56
|
+
isMe: boolean;
|
|
57
|
+
};
|
|
58
|
+
formatted: Root;
|
|
59
|
+
id: string;
|
|
60
|
+
isMention?: boolean;
|
|
61
|
+
links?: Array<{
|
|
62
|
+
url: string;
|
|
63
|
+
title?: string;
|
|
64
|
+
description?: string;
|
|
65
|
+
imageUrl?: string;
|
|
66
|
+
siteName?: string;
|
|
67
|
+
}>;
|
|
68
|
+
metadata: {
|
|
69
|
+
dateSent: string;
|
|
70
|
+
edited: boolean;
|
|
71
|
+
editedAt?: string;
|
|
72
|
+
};
|
|
73
|
+
raw: unknown;
|
|
74
|
+
text: string;
|
|
75
|
+
threadId: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* A chat message with serialization support for workflow engines.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* // Create a message
|
|
83
|
+
* const message = new Message({
|
|
84
|
+
* id: "msg-1",
|
|
85
|
+
* threadId: "slack:C123:1234.5678",
|
|
86
|
+
* text: "Hello world",
|
|
87
|
+
* formatted: parseMarkdown("Hello world"),
|
|
88
|
+
* raw: {},
|
|
89
|
+
* author: { userId: "U123", userName: "user", fullName: "User", isBot: false, isMe: false },
|
|
90
|
+
* metadata: { dateSent: new Date(), edited: false },
|
|
91
|
+
* attachments: [],
|
|
92
|
+
* });
|
|
93
|
+
*
|
|
94
|
+
* // Serialize for workflow
|
|
95
|
+
* const serialized = message.toJSON();
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
declare class Message<TRawMessage = unknown> {
|
|
99
|
+
/** Unique message ID */
|
|
100
|
+
readonly id: string;
|
|
101
|
+
/** Thread this message belongs to */
|
|
102
|
+
readonly threadId: string;
|
|
103
|
+
/** Plain text content (all formatting stripped) */
|
|
104
|
+
text: string;
|
|
105
|
+
/**
|
|
106
|
+
* Structured formatting as an AST (mdast Root).
|
|
107
|
+
* This is the canonical representation - use this for processing.
|
|
108
|
+
* Use `stringifyMarkdown(message.formatted)` to get markdown string.
|
|
109
|
+
*/
|
|
110
|
+
formatted: FormattedContent;
|
|
111
|
+
/** Platform-specific raw payload (escape hatch) */
|
|
112
|
+
raw: TRawMessage;
|
|
113
|
+
/** Message author */
|
|
114
|
+
author: Author;
|
|
115
|
+
/** Message metadata */
|
|
116
|
+
metadata: MessageMetadata;
|
|
117
|
+
/** Attachments */
|
|
118
|
+
attachments: Attachment[];
|
|
119
|
+
/**
|
|
120
|
+
* Whether the bot is @-mentioned in this message.
|
|
121
|
+
*
|
|
122
|
+
* This is set by the Chat SDK before passing the message to handlers.
|
|
123
|
+
* It checks for `@username` in the message text using the adapter's
|
|
124
|
+
* configured `userName` and optional `botUserId`.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* chat.onSubscribedMessage(async (thread, message) => {
|
|
129
|
+
* if (message.isMention) {
|
|
130
|
+
* await thread.post("You mentioned me!");
|
|
131
|
+
* }
|
|
132
|
+
* });
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
isMention?: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Cross-platform user key for this message's author.
|
|
138
|
+
*
|
|
139
|
+
* Set by the Chat SDK before passing the message to handlers, when
|
|
140
|
+
* `ChatConfig.identity` is configured. `undefined` if no resolver is
|
|
141
|
+
* configured; `undefined` (i.e. absent) when the resolver returned null.
|
|
142
|
+
*
|
|
143
|
+
* Used by the Transcripts API to look up / append per-user transcripts.
|
|
144
|
+
*/
|
|
145
|
+
userKey?: string;
|
|
146
|
+
/** Links found in the message */
|
|
147
|
+
links: LinkPreview[];
|
|
148
|
+
private _subjectPromise?;
|
|
149
|
+
get subject(): Promise<MessageSubject | null>;
|
|
150
|
+
constructor(data: MessageData<TRawMessage>);
|
|
151
|
+
/**
|
|
152
|
+
* Serialize the message to a plain JSON object.
|
|
153
|
+
* Use this to pass message data to external systems like workflow engines.
|
|
154
|
+
*
|
|
155
|
+
* Note: Attachment `data` (Buffer) and `fetchData` (function) are omitted
|
|
156
|
+
* as they're not serializable.
|
|
157
|
+
*/
|
|
158
|
+
toJSON(): SerializedMessage;
|
|
159
|
+
/**
|
|
160
|
+
* Reconstruct a Message from serialized JSON data.
|
|
161
|
+
* Converts ISO date strings back to Date objects.
|
|
162
|
+
*/
|
|
163
|
+
static fromJSON<TRawMessage = unknown>(json: SerializedMessage): Message<TRawMessage>;
|
|
164
|
+
/**
|
|
165
|
+
* Serialize a Message instance for @workflow/serde.
|
|
166
|
+
* This static method is automatically called by workflow serialization.
|
|
167
|
+
*/
|
|
168
|
+
static [WORKFLOW_SERIALIZE](instance: Message): SerializedMessage;
|
|
169
|
+
/**
|
|
170
|
+
* Deserialize a Message from @workflow/serde.
|
|
171
|
+
* This static method is automatically called by workflow deserialization.
|
|
172
|
+
*/
|
|
173
|
+
static [WORKFLOW_DESERIALIZE](data: SerializedMessage): Message;
|
|
174
|
+
}
|
|
4
175
|
|
|
5
176
|
interface ThreadHistoryConfig {
|
|
6
177
|
/** Maximum messages to keep per thread (default: 100) */
|
|
@@ -2298,259 +2469,6 @@ interface TranscriptsApi {
|
|
|
2298
2469
|
list(query: ListQuery): Promise<TranscriptEntry[]>;
|
|
2299
2470
|
}
|
|
2300
2471
|
|
|
2301
|
-
/**
|
|
2302
|
-
* Message class with serialization support for workflow engines.
|
|
2303
|
-
*/
|
|
2304
|
-
|
|
2305
|
-
/**
|
|
2306
|
-
* Input data for creating a Message instance.
|
|
2307
|
-
* Use this interface when constructing Message objects.
|
|
2308
|
-
*/
|
|
2309
|
-
interface MessageData<TRawMessage = unknown> {
|
|
2310
|
-
/** Attachments */
|
|
2311
|
-
attachments: Attachment[];
|
|
2312
|
-
/** Message author */
|
|
2313
|
-
author: Author;
|
|
2314
|
-
/** Structured formatting as an AST (mdast Root) */
|
|
2315
|
-
formatted: FormattedContent;
|
|
2316
|
-
/** Unique message ID */
|
|
2317
|
-
id: string;
|
|
2318
|
-
/** Whether the bot is @-mentioned in this message */
|
|
2319
|
-
isMention?: boolean;
|
|
2320
|
-
/** Links found in the message */
|
|
2321
|
-
links?: LinkPreview[];
|
|
2322
|
-
/** Message metadata */
|
|
2323
|
-
metadata: MessageMetadata;
|
|
2324
|
-
/** Platform-specific raw payload (escape hatch) */
|
|
2325
|
-
raw: TRawMessage;
|
|
2326
|
-
/** Plain text content (all formatting stripped) */
|
|
2327
|
-
text: string;
|
|
2328
|
-
/** Thread this message belongs to */
|
|
2329
|
-
threadId: string;
|
|
2330
|
-
}
|
|
2331
|
-
/**
|
|
2332
|
-
* Serialized message data for passing to external systems (e.g., workflow engines).
|
|
2333
|
-
* Dates are converted to ISO strings, and non-serializable fields are omitted.
|
|
2334
|
-
*/
|
|
2335
|
-
interface SerializedMessage {
|
|
2336
|
-
_type: "chat:Message";
|
|
2337
|
-
attachments: Array<{
|
|
2338
|
-
type: "image" | "file" | "video" | "audio";
|
|
2339
|
-
url?: string;
|
|
2340
|
-
name?: string;
|
|
2341
|
-
mimeType?: string;
|
|
2342
|
-
size?: number;
|
|
2343
|
-
width?: number;
|
|
2344
|
-
height?: number;
|
|
2345
|
-
fetchMetadata?: Record<string, string>;
|
|
2346
|
-
}>;
|
|
2347
|
-
author: {
|
|
2348
|
-
userId: string;
|
|
2349
|
-
userName: string;
|
|
2350
|
-
fullName: string;
|
|
2351
|
-
isBot: boolean | "unknown";
|
|
2352
|
-
isMe: boolean;
|
|
2353
|
-
};
|
|
2354
|
-
formatted: Root;
|
|
2355
|
-
id: string;
|
|
2356
|
-
isMention?: boolean;
|
|
2357
|
-
links?: Array<{
|
|
2358
|
-
url: string;
|
|
2359
|
-
title?: string;
|
|
2360
|
-
description?: string;
|
|
2361
|
-
imageUrl?: string;
|
|
2362
|
-
siteName?: string;
|
|
2363
|
-
}>;
|
|
2364
|
-
metadata: {
|
|
2365
|
-
dateSent: string;
|
|
2366
|
-
edited: boolean;
|
|
2367
|
-
editedAt?: string;
|
|
2368
|
-
};
|
|
2369
|
-
raw: unknown;
|
|
2370
|
-
text: string;
|
|
2371
|
-
threadId: string;
|
|
2372
|
-
}
|
|
2373
|
-
/**
|
|
2374
|
-
* A chat message with serialization support for workflow engines.
|
|
2375
|
-
*
|
|
2376
|
-
* @example
|
|
2377
|
-
* ```typescript
|
|
2378
|
-
* // Create a message
|
|
2379
|
-
* const message = new Message({
|
|
2380
|
-
* id: "msg-1",
|
|
2381
|
-
* threadId: "slack:C123:1234.5678",
|
|
2382
|
-
* text: "Hello world",
|
|
2383
|
-
* formatted: parseMarkdown("Hello world"),
|
|
2384
|
-
* raw: {},
|
|
2385
|
-
* author: { userId: "U123", userName: "user", fullName: "User", isBot: false, isMe: false },
|
|
2386
|
-
* metadata: { dateSent: new Date(), edited: false },
|
|
2387
|
-
* attachments: [],
|
|
2388
|
-
* });
|
|
2389
|
-
*
|
|
2390
|
-
* // Serialize for workflow
|
|
2391
|
-
* const serialized = message.toJSON();
|
|
2392
|
-
* ```
|
|
2393
|
-
*/
|
|
2394
|
-
declare class Message<TRawMessage = unknown> {
|
|
2395
|
-
/** Unique message ID */
|
|
2396
|
-
readonly id: string;
|
|
2397
|
-
/** Thread this message belongs to */
|
|
2398
|
-
readonly threadId: string;
|
|
2399
|
-
/** Plain text content (all formatting stripped) */
|
|
2400
|
-
text: string;
|
|
2401
|
-
/**
|
|
2402
|
-
* Structured formatting as an AST (mdast Root).
|
|
2403
|
-
* This is the canonical representation - use this for processing.
|
|
2404
|
-
* Use `stringifyMarkdown(message.formatted)` to get markdown string.
|
|
2405
|
-
*/
|
|
2406
|
-
formatted: FormattedContent;
|
|
2407
|
-
/** Platform-specific raw payload (escape hatch) */
|
|
2408
|
-
raw: TRawMessage;
|
|
2409
|
-
/** Message author */
|
|
2410
|
-
author: Author;
|
|
2411
|
-
/** Message metadata */
|
|
2412
|
-
metadata: MessageMetadata;
|
|
2413
|
-
/** Attachments */
|
|
2414
|
-
attachments: Attachment[];
|
|
2415
|
-
/**
|
|
2416
|
-
* Whether the bot is @-mentioned in this message.
|
|
2417
|
-
*
|
|
2418
|
-
* This is set by the Chat SDK before passing the message to handlers.
|
|
2419
|
-
* It checks for `@username` in the message text using the adapter's
|
|
2420
|
-
* configured `userName` and optional `botUserId`.
|
|
2421
|
-
*
|
|
2422
|
-
* @example
|
|
2423
|
-
* ```typescript
|
|
2424
|
-
* chat.onSubscribedMessage(async (thread, message) => {
|
|
2425
|
-
* if (message.isMention) {
|
|
2426
|
-
* await thread.post("You mentioned me!");
|
|
2427
|
-
* }
|
|
2428
|
-
* });
|
|
2429
|
-
* ```
|
|
2430
|
-
*/
|
|
2431
|
-
isMention?: boolean;
|
|
2432
|
-
/**
|
|
2433
|
-
* Cross-platform user key for this message's author.
|
|
2434
|
-
*
|
|
2435
|
-
* Set by the Chat SDK before passing the message to handlers, when
|
|
2436
|
-
* `ChatConfig.identity` is configured. `undefined` if no resolver is
|
|
2437
|
-
* configured; `undefined` (i.e. absent) when the resolver returned null.
|
|
2438
|
-
*
|
|
2439
|
-
* Used by the Transcripts API to look up / append per-user transcripts.
|
|
2440
|
-
*/
|
|
2441
|
-
userKey?: string;
|
|
2442
|
-
/** Links found in the message */
|
|
2443
|
-
links: LinkPreview[];
|
|
2444
|
-
private _subjectPromise?;
|
|
2445
|
-
get subject(): Promise<MessageSubject | null>;
|
|
2446
|
-
constructor(data: MessageData<TRawMessage>);
|
|
2447
|
-
/**
|
|
2448
|
-
* Serialize the message to a plain JSON object.
|
|
2449
|
-
* Use this to pass message data to external systems like workflow engines.
|
|
2450
|
-
*
|
|
2451
|
-
* Note: Attachment `data` (Buffer) and `fetchData` (function) are omitted
|
|
2452
|
-
* as they're not serializable.
|
|
2453
|
-
*/
|
|
2454
|
-
toJSON(): SerializedMessage;
|
|
2455
|
-
/**
|
|
2456
|
-
* Reconstruct a Message from serialized JSON data.
|
|
2457
|
-
* Converts ISO date strings back to Date objects.
|
|
2458
|
-
*/
|
|
2459
|
-
static fromJSON<TRawMessage = unknown>(json: SerializedMessage): Message<TRawMessage>;
|
|
2460
|
-
/**
|
|
2461
|
-
* Serialize a Message instance for @workflow/serde.
|
|
2462
|
-
* This static method is automatically called by workflow serialization.
|
|
2463
|
-
*/
|
|
2464
|
-
static [WORKFLOW_SERIALIZE](instance: Message): SerializedMessage;
|
|
2465
|
-
/**
|
|
2466
|
-
* Deserialize a Message from @workflow/serde.
|
|
2467
|
-
* This static method is automatically called by workflow deserialization.
|
|
2468
|
-
*/
|
|
2469
|
-
static [WORKFLOW_DESERIALIZE](data: SerializedMessage): Message;
|
|
2470
|
-
}
|
|
2471
|
-
|
|
2472
|
-
/**
|
|
2473
|
-
* Content part types structurally identical to AI SDK's TextPart, ImagePart,
|
|
2474
|
-
* FilePart so that AiMessage[] is directly assignable to ModelMessage[].
|
|
2475
|
-
* @see https://ai-sdk.dev/docs/reference/ai-sdk-core/model-message
|
|
2476
|
-
*/
|
|
2477
|
-
/** Matches AI SDK's DataContent */
|
|
2478
|
-
type DataContent = string | Uint8Array | ArrayBuffer | Buffer;
|
|
2479
|
-
interface AiTextPart {
|
|
2480
|
-
text: string;
|
|
2481
|
-
type: "text";
|
|
2482
|
-
}
|
|
2483
|
-
interface AiImagePart {
|
|
2484
|
-
image: DataContent | URL;
|
|
2485
|
-
mediaType?: string;
|
|
2486
|
-
type: "image";
|
|
2487
|
-
}
|
|
2488
|
-
interface AiFilePart {
|
|
2489
|
-
data: DataContent | URL;
|
|
2490
|
-
filename?: string;
|
|
2491
|
-
mediaType: string;
|
|
2492
|
-
type: "file";
|
|
2493
|
-
}
|
|
2494
|
-
type AiMessagePart = AiTextPart | AiImagePart | AiFilePart;
|
|
2495
|
-
/**
|
|
2496
|
-
* A message formatted for AI SDK consumption.
|
|
2497
|
-
*
|
|
2498
|
-
* This is a discriminated union matching AI SDK's ModelMessage type:
|
|
2499
|
-
* - User messages can have text, image, and file parts
|
|
2500
|
-
* - Assistant messages have string content only
|
|
2501
|
-
*/
|
|
2502
|
-
type AiMessage = AiUserMessage | AiAssistantMessage;
|
|
2503
|
-
interface AiUserMessage {
|
|
2504
|
-
content: string | AiMessagePart[];
|
|
2505
|
-
role: "user";
|
|
2506
|
-
}
|
|
2507
|
-
interface AiAssistantMessage {
|
|
2508
|
-
content: string;
|
|
2509
|
-
role: "assistant";
|
|
2510
|
-
}
|
|
2511
|
-
/**
|
|
2512
|
-
* Options for converting messages to AI SDK format.
|
|
2513
|
-
*/
|
|
2514
|
-
interface ToAiMessagesOptions {
|
|
2515
|
-
/** When true, prefixes user messages with "[username]: " for multi-user context */
|
|
2516
|
-
includeNames?: boolean;
|
|
2517
|
-
/**
|
|
2518
|
-
* Called when an attachment type is not supported (video, audio).
|
|
2519
|
-
* Defaults to `console.warn`.
|
|
2520
|
-
*/
|
|
2521
|
-
onUnsupportedAttachment?: (attachment: Attachment, message: Message) => void;
|
|
2522
|
-
/**
|
|
2523
|
-
* Called for each message after default processing (text, links, attachments).
|
|
2524
|
-
* Return the message (modified or as-is) to include it, or `null` to skip it.
|
|
2525
|
-
*
|
|
2526
|
-
* @param aiMessage - The processed AI message
|
|
2527
|
-
* @param source - The original chat Message
|
|
2528
|
-
* @returns The message to include, or null to skip
|
|
2529
|
-
*/
|
|
2530
|
-
transformMessage?: (aiMessage: AiMessage, source: Message) => AiMessage | null | Promise<AiMessage | null>;
|
|
2531
|
-
}
|
|
2532
|
-
/**
|
|
2533
|
-
* Convert chat SDK messages to AI SDK conversation format.
|
|
2534
|
-
*
|
|
2535
|
-
* - Filters out messages with empty/whitespace-only text
|
|
2536
|
-
* - Maps `author.isMe === true` to `"assistant"`, otherwise `"user"`
|
|
2537
|
-
* - Uses `message.text` for content
|
|
2538
|
-
* - Appends link metadata when available
|
|
2539
|
-
* - Includes image attachments and text files as `FilePart`
|
|
2540
|
-
* - Uses `fetchData()` when available to include attachment data inline (base64)
|
|
2541
|
-
* - Warns on unsupported attachment types (video, audio)
|
|
2542
|
-
*
|
|
2543
|
-
* Works with `FetchResult.messages`, `thread.recentMessages`, or collected iterables.
|
|
2544
|
-
*
|
|
2545
|
-
* @example
|
|
2546
|
-
* ```typescript
|
|
2547
|
-
* const result = await thread.adapter.fetchMessages(thread.id, { limit: 20 });
|
|
2548
|
-
* const history = await toAiMessages(result.messages);
|
|
2549
|
-
* const response = await agent.stream({ prompt: history });
|
|
2550
|
-
* ```
|
|
2551
|
-
*/
|
|
2552
|
-
declare function toAiMessages(messages: Message[], options?: ToAiMessagesOptions): Promise<AiMessage[]>;
|
|
2553
|
-
|
|
2554
2472
|
/** Filter can be EmojiValue objects, emoji names, or raw emoji formats */
|
|
2555
2473
|
type EmojiFilter = EmojiValue | string;
|
|
2556
2474
|
/**
|
|
@@ -3156,4 +3074,86 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
|
|
|
3156
3074
|
private runHandlers;
|
|
3157
3075
|
}
|
|
3158
3076
|
|
|
3159
|
-
|
|
3077
|
+
/**
|
|
3078
|
+
* Content part types structurally identical to AI SDK's TextPart, ImagePart,
|
|
3079
|
+
* FilePart so that AiMessage[] is directly assignable to ModelMessage[].
|
|
3080
|
+
* @see https://ai-sdk.dev/docs/reference/ai-sdk-core/model-message
|
|
3081
|
+
*/
|
|
3082
|
+
/** Matches AI SDK's DataContent */
|
|
3083
|
+
type DataContent = string | Uint8Array | ArrayBuffer | Buffer;
|
|
3084
|
+
interface AiTextPart {
|
|
3085
|
+
text: string;
|
|
3086
|
+
type: "text";
|
|
3087
|
+
}
|
|
3088
|
+
interface AiImagePart {
|
|
3089
|
+
image: DataContent | URL;
|
|
3090
|
+
mediaType?: string;
|
|
3091
|
+
type: "image";
|
|
3092
|
+
}
|
|
3093
|
+
interface AiFilePart {
|
|
3094
|
+
data: DataContent | URL;
|
|
3095
|
+
filename?: string;
|
|
3096
|
+
mediaType: string;
|
|
3097
|
+
type: "file";
|
|
3098
|
+
}
|
|
3099
|
+
type AiMessagePart = AiTextPart | AiImagePart | AiFilePart;
|
|
3100
|
+
/**
|
|
3101
|
+
* A message formatted for AI SDK consumption.
|
|
3102
|
+
*
|
|
3103
|
+
* This is a discriminated union matching AI SDK's ModelMessage type:
|
|
3104
|
+
* - User messages can have text, image, and file parts
|
|
3105
|
+
* - Assistant messages have string content only
|
|
3106
|
+
*/
|
|
3107
|
+
type AiMessage = AiUserMessage | AiAssistantMessage;
|
|
3108
|
+
interface AiUserMessage {
|
|
3109
|
+
content: string | AiMessagePart[];
|
|
3110
|
+
role: "user";
|
|
3111
|
+
}
|
|
3112
|
+
interface AiAssistantMessage {
|
|
3113
|
+
content: string;
|
|
3114
|
+
role: "assistant";
|
|
3115
|
+
}
|
|
3116
|
+
/**
|
|
3117
|
+
* Options for converting messages to AI SDK format.
|
|
3118
|
+
*/
|
|
3119
|
+
interface ToAiMessagesOptions {
|
|
3120
|
+
/** When true, prefixes user messages with "[username]: " for multi-user context */
|
|
3121
|
+
includeNames?: boolean;
|
|
3122
|
+
/**
|
|
3123
|
+
* Called when an attachment type is not supported (video, audio).
|
|
3124
|
+
* Defaults to `console.warn`.
|
|
3125
|
+
*/
|
|
3126
|
+
onUnsupportedAttachment?: (attachment: Attachment, message: Message) => void;
|
|
3127
|
+
/**
|
|
3128
|
+
* Called for each message after default processing (text, links, attachments).
|
|
3129
|
+
* Return the message (modified or as-is) to include it, or `null` to skip it.
|
|
3130
|
+
*
|
|
3131
|
+
* @param aiMessage - The processed AI message
|
|
3132
|
+
* @param source - The original chat Message
|
|
3133
|
+
* @returns The message to include, or null to skip
|
|
3134
|
+
*/
|
|
3135
|
+
transformMessage?: (aiMessage: AiMessage, source: Message) => AiMessage | null | Promise<AiMessage | null>;
|
|
3136
|
+
}
|
|
3137
|
+
/**
|
|
3138
|
+
* Convert chat SDK messages to AI SDK conversation format.
|
|
3139
|
+
*
|
|
3140
|
+
* - Filters out messages with empty/whitespace-only text
|
|
3141
|
+
* - Maps `author.isMe === true` to `"assistant"`, otherwise `"user"`
|
|
3142
|
+
* - Uses `message.text` for content
|
|
3143
|
+
* - Appends link metadata when available
|
|
3144
|
+
* - Includes image attachments and text files as `FilePart`
|
|
3145
|
+
* - Uses `fetchData()` when available to include attachment data inline (base64)
|
|
3146
|
+
* - Warns on unsupported attachment types (video, audio)
|
|
3147
|
+
*
|
|
3148
|
+
* Works with `FetchResult.messages`, `thread.recentMessages`, or collected iterables.
|
|
3149
|
+
*
|
|
3150
|
+
* @example
|
|
3151
|
+
* ```typescript
|
|
3152
|
+
* const result = await thread.adapter.fetchMessages(thread.id, { limit: 20 });
|
|
3153
|
+
* const history = await toAiMessages(result.messages);
|
|
3154
|
+
* const response = await agent.stream({ prompt: history });
|
|
3155
|
+
* ```
|
|
3156
|
+
*/
|
|
3157
|
+
declare function toAiMessages(messages: Message[], options?: ToAiMessagesOptions): Promise<AiMessage[]>;
|
|
3158
|
+
|
|
3159
|
+
export { type FileUpload as $, type AiAssistantMessage as A, type AssistantThreadStartedHandler as B, Chat as C, type Attachment as D, type EmojiFormats as E, type Author as F, type Channel as G, ChannelImpl as H, type ChannelInfo as I, type ChatConfig as J, type ChatInstance as K, type ConcurrencyConfig as L, type ConcurrencyStrategy as M, ConsoleLogger as N, type CountQuery as O, type PostableObject as P, type DeleteTarget as Q, type DirectMessageHandler as R, type StreamChunk as S, type ToAiMessagesOptions as T, type DurationString as U, type Emoji as V, type WellKnownEmoji as W, type EphemeralMessage as X, type FetchDirection as Y, type FetchOptions as Z, type FetchResult as _, type ChannelVisibility as a, type ThreadSummary as a$, type FormattedContent as a0, type IdentityContext as a1, type IdentityResolver as a2, type LinkPreview as a3, type ListQuery as a4, type ListThreadsOptions as a5, type ListThreadsResult as a6, type Lock as a7, type LockScope as a8, type LockScopeContext as a9, type PlanUpdateChunk as aA, type PostEphemeralOptions as aB, type Postable as aC, type PostableAst as aD, type PostableCard as aE, type PostableMarkdown as aF, type PostableMessage as aG, type PostableRaw as aH, type QueueEntry as aI, type RawMessage as aJ, type ReactionEvent as aK, type ReactionHandler as aL, type ScheduledMessage as aM, type SentMessage as aN, type SerializedChannel as aO, type SerializedMessage as aP, type SerializedThread as aQ, type SlashCommandEvent as aR, type SlashCommandHandler as aS, type StateAdapter as aT, type StreamOptions as aU, type SubscribedMessageHandler as aV, THREAD_STATE_TTL_MS as aW, type TaskUpdateChunk as aX, type Thread as aY, ThreadImpl as aZ, type ThreadInfo as a_, type LogLevel as aa, type Logger as ab, type MarkdownTextChunk as ac, type MemberJoinedChannelEvent as ad, type MemberJoinedChannelHandler as ae, type MentionHandler as af, Message as ag, type MessageContext as ah, type MessageData as ai, type MessageHandler as aj, type MessageMetadata as ak, type MessageSubject as al, type ModalClearResponse as am, type ModalCloseEvent as an, type ModalCloseHandler as ao, type ModalCloseResponse as ap, type ModalErrorsResponse as aq, type ModalPushResponse as ar, type ModalResponse as as, type ModalSubmitEvent as at, type ModalSubmitHandler as au, type ModalUpdateResponse as av, type OptionsLoadEvent as aw, type OptionsLoadGroup as ax, type OptionsLoadHandler as ay, type OptionsLoadResult as az, type AiFilePart as b, type TranscriptEntry as b0, type TranscriptRole as b1, type TranscriptsApi as b2, type TranscriptsConfig as b3, type UserInfo as b4, type WebhookOptions as b5, deriveChannelId as b6, isPostableObject as b7, type AiImagePart as c, type AiMessage as d, type AiMessagePart as e, type AiTextPart as f, type AiUserMessage as g, type Adapter as h, type PostableObjectContext as i, ThreadHistoryCache as j, type ThreadHistoryConfig as k, type StreamEvent as l, type EmojiMapConfig as m, type EmojiValue as n, type CustomEmojiMap as o, type AdapterPostableMessage as p, type ActionEvent as q, type ActionHandler as r, type AppHomeOpenedEvent as s, toAiMessages as t, type AppHomeOpenedHandler as u, type AppendInput as v, type AppendOptions as w, type AssistantContextChangedEvent as x, type AssistantContextChangedHandler as y, type AssistantThreadStartedEvent as z };
|
package/docs/api/chat.mdx
CHANGED
|
@@ -27,9 +27,9 @@ const bot = new Chat(config);
|
|
|
27
27
|
type: 'Record<string, Adapter>',
|
|
28
28
|
},
|
|
29
29
|
dedupeTtlMs: {
|
|
30
|
-
description: 'TTL for message deduplication entries in milliseconds.
|
|
30
|
+
description: 'TTL for message deduplication entries in milliseconds. The default outlives the last Slack event retry (~5 minutes after original delivery); increase it if your platform redelivers later than that.',
|
|
31
31
|
type: 'number',
|
|
32
|
-
default: '
|
|
32
|
+
default: '600000',
|
|
33
33
|
},
|
|
34
34
|
state: {
|
|
35
35
|
description: 'State adapter for subscriptions, locking, and caching.',
|
package/docs/create-chat-sdk.mdx
CHANGED
|
@@ -98,6 +98,20 @@ When the [Web adapter](/adapters/official/web) is selected, the CLI also creates
|
|
|
98
98
|
|
|
99
99
|
When the [Discord adapter](/adapters/official/discord) is selected, the CLI also creates a Gateway listener at `/api/discord/gateway` and a `vercel.json` cron that calls it. Discord delivers slash commands and button clicks to the webhook route, but regular messages and reactions only arrive over the Gateway WebSocket, so the cron keeps that connection alive and forwards events to `/api/webhooks/discord`. Set a `CRON_SECRET` environment variable to authenticate the cron requests. The generated serverless Gateway cron requires [Vercel Pro or Enterprise](https://vercel.com/docs/cron-jobs/usage-and-pricing) because it runs every nine minutes.
|
|
100
100
|
|
|
101
|
+
## Vercel Connect
|
|
102
|
+
|
|
103
|
+
[Vercel Connect](/docs/vercel-connect) lets the Slack, GitHub, and Linear adapters authenticate with a connector instead of stored provider secrets. Pass `--connect` — or choose **Vercel Connect** at the interactive auth-mode prompt — to scaffold Connect wiring for any selected Slack, GitHub, or Linear adapter:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
npm create chat-sdk@latest -- my-bot --adapter slack --connect -y
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The generated `src/lib/bot.ts` spreads the matching helper from `@vercel/connect/chat` into the adapter factory, `@vercel/connect` is added to dependencies, and `.env.example` lists each connector UID (for example `SLACK_CONNECTOR`) in place of native secrets.
|
|
110
|
+
|
|
111
|
+
<Callout type="info">
|
|
112
|
+
Vercel Connect provides `VERCEL_OIDC_TOKEN` at runtime. For local development, run `vercel link` then `vercel env pull` to populate it. Connect forwards inbound webhooks only to deployed URLs, so test webhook delivery against a Vercel deployment (such as a preview) rather than localhost.
|
|
113
|
+
</Callout>
|
|
114
|
+
|
|
101
115
|
## Reference
|
|
102
116
|
|
|
103
117
|
| Option | Description |
|
|
@@ -106,6 +120,7 @@ When the [Discord adapter](/adapters/official/discord) is selected, the CLI also
|
|
|
106
120
|
| `-d, --description <text>` | Project description. |
|
|
107
121
|
| `--adapter <values...>` | Platform or state adapters to include. |
|
|
108
122
|
| `--vendor` | List only vendor-official adapters in the interactive prompt. |
|
|
123
|
+
| `--connect` | Authenticate Slack, GitHub, and Linear adapters with Vercel Connect. |
|
|
109
124
|
| `--pm <manager>` | Package manager to use: `npm`, `yarn`, `pnpm`, or `bun`. |
|
|
110
125
|
| `-y, --yes` | Skip prompts and accept defaults. |
|
|
111
126
|
| `--interactive` | Always prompt, even when a coding agent environment is detected. |
|
package/docs/meta.json
CHANGED
package/docs/usage.mdx
CHANGED
|
@@ -71,7 +71,7 @@ Your event handlers work identically across all registered adapters — the SDK
|
|
|
71
71
|
| `adapters` | `Record<string, Adapter>` | *required* | Map of adapter name to adapter instance |
|
|
72
72
|
| `state` | `StateAdapter` | *required* | State adapter for subscriptions and locking |
|
|
73
73
|
| `logger` | `Logger \| LogLevel` | `"info"` | Logger instance or log level (`"debug"`, `"info"`, `"warn"`, `"error"`, `"silent"`) |
|
|
74
|
-
| `dedupeTtlMs` | `number` | `
|
|
74
|
+
| `dedupeTtlMs` | `number` | `600000` | TTL in ms for message deduplication (10 minutes) |
|
|
75
75
|
| `concurrency` | `"drop" \| "queue" \| "debounce" \| "burst" \| "concurrent" \| ConcurrencyConfig` | `"drop"` | Strategy for overlapping messages on the same thread |
|
|
76
76
|
| `streamingUpdateIntervalMs` | `number` | `500` | Update interval in ms for post+edit streaming |
|
|
77
77
|
| `fallbackStreamingPlaceholderText` | `string \| null` | `"..."` | Placeholder text while streaming starts. Set to `null` to skip |
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Vercel Connect
|
|
3
|
+
description: Authenticate Slack, GitHub, and Linear adapters with Vercel Connect — short-lived runtime tokens for outbound calls and OIDC-verified inbound webhooks, with no stored provider secrets.
|
|
4
|
+
type: overview
|
|
5
|
+
related:
|
|
6
|
+
- /docs/usage
|
|
7
|
+
- /adapters/official/slack
|
|
8
|
+
- /adapters/official/github
|
|
9
|
+
- /adapters/official/linear
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
[Vercel Connect](https://vercel.com/docs/connect) lets your bot use a registered connector for adapter authentication instead of storing long-lived provider secrets. You register a connector once, link it to your project and environments, and your code requests scoped, short-lived tokens at runtime.
|
|
13
|
+
|
|
14
|
+
The `@vercel/connect/chat` subpath ships a helper per platform that you spread into the matching `create*Adapter` factory:
|
|
15
|
+
|
|
16
|
+
- `connectSlackAdapter`
|
|
17
|
+
- `connectGitHubAdapter`
|
|
18
|
+
- `connectLinearAdapter`
|
|
19
|
+
|
|
20
|
+
Each helper wires both directions of traffic:
|
|
21
|
+
|
|
22
|
+
- **Outbound** (your bot calls the provider API) — a function-form token field that resolves a fresh, short-lived token per call via `getToken`.
|
|
23
|
+
- **Inbound** (the provider calls your bot) — a `webhookVerifier` that validates the Vercel OIDC token Connect attaches to [trigger-forwarded](https://vercel.com/docs/connect/concepts/triggers) webhooks, replacing the provider's native signature check.
|
|
24
|
+
|
|
25
|
+
<Callout type="info">
|
|
26
|
+
Vercel Connect is in beta. Features and behavior, including available connectors and trigger forwarding, may change before general availability.
|
|
27
|
+
</Callout>
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pnpm add @vercel/connect
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`@vercel/connect` reads the deployment's OIDC token automatically. For local development, run `vercel link` followed by `vercel env pull` to download a short-lived token into `.env.local`.
|
|
36
|
+
|
|
37
|
+
## Adapter support
|
|
38
|
+
|
|
39
|
+
| Adapter | Helper | Outbound field |
|
|
40
|
+
|---------|--------|----------------|
|
|
41
|
+
| [Slack](/adapters/official/slack) | `connectSlackAdapter` | `botToken` |
|
|
42
|
+
| [GitHub](/adapters/official/github) | `connectGitHubAdapter` | `installationToken` |
|
|
43
|
+
| [Linear](/adapters/official/linear) | `connectLinearAdapter` | `accessToken` |
|
|
44
|
+
|
|
45
|
+
Each helper accepts `(connector, params?, options?)`, where `params` is the [`getToken`](https://vercel.com/docs/connect/ts-sdk-reference) parameters minus `subject` (pinned to `{ type: "app" }`), letting you pass through `installationId`, `scopes`, or `validityBufferMs`.
|
|
46
|
+
|
|
47
|
+
## Set up a connector
|
|
48
|
+
|
|
49
|
+
1. Create a connector for the provider in the [Vercel dashboard](https://vercel.com/d?to=%2F%5Bteam%5D%2F~%2Fconnect) or with the CLI, enabling trigger forwarding so inbound webhooks reach your project:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
vercel connect create slack --name acme-slack --triggers
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
2. Attach your project and register your Chat SDK webhook route (`/api/webhooks/{platform}`) as the trigger destination:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
vercel connect attach slack/acme-slack \
|
|
59
|
+
--project my-bot --environment production \
|
|
60
|
+
--triggers --trigger-path /api/webhooks/slack
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
3. Pull a development token locally (deployments get `VERCEL_OIDC_TOKEN` automatically):
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
vercel link
|
|
67
|
+
vercel env pull
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Wire up the adapter
|
|
71
|
+
|
|
72
|
+
Spread the helper into the adapter factory. The webhook route is unchanged — Connect forwards verified events to the same handler.
|
|
73
|
+
|
|
74
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
75
|
+
import { Chat } from "chat";
|
|
76
|
+
import { createSlackAdapter } from "@chat-adapter/slack";
|
|
77
|
+
import { createRedisState } from "@chat-adapter/state-redis";
|
|
78
|
+
import { connectSlackAdapter } from "@vercel/connect/chat";
|
|
79
|
+
|
|
80
|
+
export const bot = new Chat({
|
|
81
|
+
userName: "mybot",
|
|
82
|
+
adapters: {
|
|
83
|
+
slack: createSlackAdapter({
|
|
84
|
+
...connectSlackAdapter("slack/acme-slack"),
|
|
85
|
+
}),
|
|
86
|
+
},
|
|
87
|
+
state: createRedisState(),
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Replace `slack/acme-slack` with your connector UID from the Connect dashboard or `vercel connect list`. Omit `signingSecret` / `SLACK_SIGNING_SECRET` when using the helper — the OIDC `webhookVerifier` is the freshness boundary.
|
|
92
|
+
|
|
93
|
+
### GitHub
|
|
94
|
+
|
|
95
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
96
|
+
import { createGitHubAdapter } from "@chat-adapter/github";
|
|
97
|
+
import { connectGitHubAdapter } from "@vercel/connect/chat";
|
|
98
|
+
|
|
99
|
+
createGitHubAdapter({
|
|
100
|
+
...connectGitHubAdapter("github/acme-github"),
|
|
101
|
+
userName: "my-bot[bot]",
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`installationToken` is the installation access token a GitHub App would normally mint via its private-key JWT exchange — the adapter uses it directly and skips that exchange.
|
|
106
|
+
|
|
107
|
+
### Linear
|
|
108
|
+
|
|
109
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
110
|
+
import { createLinearAdapter } from "@chat-adapter/linear";
|
|
111
|
+
import { connectLinearAdapter } from "@vercel/connect/chat";
|
|
112
|
+
|
|
113
|
+
createLinearAdapter({
|
|
114
|
+
...connectLinearAdapter("linear/acme-linear"),
|
|
115
|
+
mode: "agent-sessions",
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Use `mode: "agent-sessions"` for app-actor installs. For outbound calls outside webhook handling (cron jobs, workflows), wrap them in `withInstallation()` so a request-scoped client is bound:
|
|
120
|
+
|
|
121
|
+
```typescript title="lib/jobs.ts" lineNumbers
|
|
122
|
+
await linear.withInstallation("org-id", async () => {
|
|
123
|
+
await linear.postMessage("linear:issue-id", "Hello from a background job");
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Custom webhook verification
|
|
128
|
+
|
|
129
|
+
Each helper attaches a default verifier that matches the deployment's project and environment automatically (`projectId` defaults to `VERCEL_PROJECT_ID`, `environment` to `VERCEL_TARGET_ENV` then `VERCEL_ENV`), so production, preview, and development each accept only their own tokens. Verification fails closed — if those values are absent, every request is rejected, and the issuer is pinned to `https://oidc.vercel.com`.
|
|
130
|
+
|
|
131
|
+
To add constraints (for example to accept multiple environments), build a verifier with `createConnectWebhookVerifier` and override the field:
|
|
132
|
+
|
|
133
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
134
|
+
import {
|
|
135
|
+
connectSlackAdapter,
|
|
136
|
+
createConnectWebhookVerifier,
|
|
137
|
+
} from "@vercel/connect/chat";
|
|
138
|
+
|
|
139
|
+
createSlackAdapter({
|
|
140
|
+
...connectSlackAdapter("slack/acme-slack"),
|
|
141
|
+
webhookVerifier: createConnectWebhookVerifier({
|
|
142
|
+
environment: ["production", "preview"],
|
|
143
|
+
}),
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
<Callout type="warn">
|
|
148
|
+
Avoid hardcoding `environment: "production"` unless you only forward to production — it would reject preview and development deployments.
|
|
149
|
+
</Callout>
|
|
150
|
+
|
|
151
|
+
## Notes and limitations
|
|
152
|
+
|
|
153
|
+
- **App-scoped tokens.** The helpers act as the application itself (`subject: { type: "app" }`). End-user OAuth is a separate concern.
|
|
154
|
+
- **Freshness and replay.** OIDC verification replaces each provider's native signature (and timestamp) check, so request freshness relies on the short-lived OIDC token's expiry rather than a signed timestamp, and there is no built-in delivery de-duplication. Keep your webhook handlers idempotent.
|
|
155
|
+
- **Socket Mode is incompatible.** Connect trigger forwarding is HTTP-only; it doesn't apply to the Slack adapter's Socket Mode.
|
|
156
|
+
- **Testing.** Connect forwards to deployed URLs, not `localhost` — test against a preview or development deployment.
|
|
157
|
+
|
|
158
|
+
## Related resources
|
|
159
|
+
|
|
160
|
+
- [Vercel Connect overview](https://vercel.com/docs/connect)
|
|
161
|
+
- [Vercel Connect triggers](https://vercel.com/docs/connect/concepts/triggers)
|
|
162
|
+
- [`@vercel/connect` SDK reference](https://vercel.com/docs/connect/ts-sdk-reference)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chat",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.33.0",
|
|
4
4
|
"description": "Chat SDK — universal TypeScript toolkit for building multi-platform chat bots and AI agents on Slack, Teams, Google Chat, Discord, WhatsApp, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|