chat 4.20.2 → 4.22.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/index.d.ts +479 -332
- package/dist/index.js +389 -69
- package/dist/index.js.map +1 -1
- package/dist/{jsx-runtime-C2ATKxHQ.d.ts → jsx-runtime-DraWieqP.d.ts} +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/docs/api/chat.mdx +2 -0
- package/docs/api/index.mdx +1 -1
- package/docs/api/message.mdx +1 -1
- package/docs/api/postable-message.mdx +1 -1
- package/docs/api/to-ai-messages.mdx +190 -0
- package/docs/concurrency.mdx +223 -0
- package/docs/contributing/building.mdx +15 -1
- package/docs/guides/code-review-hono.mdx +4 -5
- package/docs/handling-events.mdx +2 -0
- package/docs/meta.json +1 -0
- package/docs/posting-messages.mdx +2 -0
- package/docs/streaming.mdx +3 -50
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,114 @@
|
|
|
1
1
|
import { WORKFLOW_SERIALIZE, WORKFLOW_DESERIALIZE } from '@workflow/serde';
|
|
2
2
|
import { Root, List, Content, Blockquote, Code, Emphasis, InlineCode, Delete, Link, ListItem, Paragraph, Strong, TableCell, Table as Table$1, TableRow, Text } from 'mdast';
|
|
3
3
|
export { Blockquote, Code, Content, Delete, Emphasis, InlineCode, Link, List, ListItem, Table as MdastTable, Paragraph, Root, Strong, TableCell, TableRow, Text } from 'mdast';
|
|
4
|
-
import { C as
|
|
5
|
-
export { r as ActionsElement, s as ButtonElement, u as ButtonOptions, V as ButtonProps, v as ButtonStyle, W as CardJSXElement, X as CardJSXProps, Y as CardLinkProps, w as CardOptions, Z as CardProps, _ as ContainerProps, x as DividerElement, $ as DividerProps, y as FieldElement, a0 as FieldProps, z as FieldsElement, E as ImageElement, a1 as ImageProps, G as LinkButtonElement, H as LinkButtonOptions, a2 as LinkButtonProps, J as LinkElement, a8 as ModalChild, a9 as ModalOptions, a3 as ModalProps, aa as RadioSelectElement, ab as RadioSelectOptions, K as SectionElement, ac as SelectElement, ad as SelectOptionElement, a4 as SelectOptionProps, ae as SelectOptions, a5 as SelectProps, N as TableAlignment, O as TableElement, P as TableOptions, Q as TextElement, af as TextInputElement, ag as TextInputOptions, a6 as TextInputProps, a7 as TextProps, U as TextStyle } from './jsx-runtime-
|
|
4
|
+
import { C as ChatElement, a as CardElement, M as ModalElement, b as CardChild, A as ActionsComponent, B as ButtonComponent, c as CardComponent, d as cardChildToFallbackText$1, e as CardLinkComponent, T as TextComponent, D as DividerComponent, F as FieldComponent, f as FieldsComponent, g as fromReactElement$1, I as ImageComponent, i as isCardElement$1, h as isJSX$1, L as LinkButtonComponent, S as SectionComponent, j as Table$2, t as toCardElement$1, k as toModalElement$1, l as fromReactModalElement$1, m as isModalElement$1, n as ModalComponent, R as RadioSelectComponent, o as SelectComponent, p as SelectOptionComponent, q as TextInputComponent } from './jsx-runtime-DraWieqP.js';
|
|
5
|
+
export { r as ActionsElement, s as ButtonElement, u as ButtonOptions, V as ButtonProps, v as ButtonStyle, W as CardJSXElement, X as CardJSXProps, Y as CardLinkProps, w as CardOptions, Z as CardProps, _ as ContainerProps, x as DividerElement, $ as DividerProps, y as FieldElement, a0 as FieldProps, z as FieldsElement, E as ImageElement, a1 as ImageProps, G as LinkButtonElement, H as LinkButtonOptions, a2 as LinkButtonProps, J as LinkElement, a8 as ModalChild, a9 as ModalOptions, a3 as ModalProps, aa as RadioSelectElement, ab as RadioSelectOptions, K as SectionElement, ac as SelectElement, ad as SelectOptionElement, a4 as SelectOptionProps, ae as SelectOptions, a5 as SelectProps, N as TableAlignment, O as TableElement, P as TableOptions, Q as TextElement, af as TextInputElement, ag as TextInputOptions, a6 as TextInputProps, a7 as TextProps, U as TextStyle } from './jsx-runtime-DraWieqP.js';
|
|
6
|
+
|
|
7
|
+
interface MessageHistoryConfig {
|
|
8
|
+
/** Maximum messages to keep per thread (default: 100) */
|
|
9
|
+
maxMessages?: number;
|
|
10
|
+
/** TTL for cached history in milliseconds (default: 7 days) */
|
|
11
|
+
ttlMs?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Persistent message history cache backed by the StateAdapter.
|
|
15
|
+
*
|
|
16
|
+
* Used by adapters that lack server-side message history APIs (e.g., WhatsApp, Telegram).
|
|
17
|
+
* Messages are atomically appended via `state.appendToList()`, which is safe
|
|
18
|
+
* without holding a thread lock.
|
|
19
|
+
*/
|
|
20
|
+
declare class MessageHistoryCache {
|
|
21
|
+
private readonly state;
|
|
22
|
+
private readonly maxMessages;
|
|
23
|
+
private readonly ttlMs;
|
|
24
|
+
constructor(state: StateAdapter, config?: MessageHistoryConfig);
|
|
25
|
+
/**
|
|
26
|
+
* Atomically append a message to the history for a thread.
|
|
27
|
+
* Trims to maxMessages (keeps newest) and refreshes TTL.
|
|
28
|
+
*/
|
|
29
|
+
append(threadId: string, message: Message): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Get messages for a thread in chronological order (oldest first).
|
|
32
|
+
*
|
|
33
|
+
* @param threadId - The thread ID
|
|
34
|
+
* @param limit - Optional limit on number of messages to return (returns newest N)
|
|
35
|
+
*/
|
|
36
|
+
getMessages(threadId: string, limit?: number): Promise<Message[]>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Serialized channel data for passing to external systems (e.g., workflow engines).
|
|
41
|
+
*/
|
|
42
|
+
interface SerializedChannel {
|
|
43
|
+
_type: "chat:Channel";
|
|
44
|
+
adapterName: string;
|
|
45
|
+
id: string;
|
|
46
|
+
isDM: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Config for creating a ChannelImpl with explicit adapter/state instances.
|
|
50
|
+
*/
|
|
51
|
+
interface ChannelImplConfigWithAdapter {
|
|
52
|
+
adapter: Adapter;
|
|
53
|
+
id: string;
|
|
54
|
+
isDM?: boolean;
|
|
55
|
+
messageHistory?: MessageHistoryCache;
|
|
56
|
+
stateAdapter: StateAdapter;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Config for creating a ChannelImpl with lazy adapter resolution.
|
|
60
|
+
*/
|
|
61
|
+
interface ChannelImplConfigLazy {
|
|
62
|
+
adapterName: string;
|
|
63
|
+
id: string;
|
|
64
|
+
isDM?: boolean;
|
|
65
|
+
}
|
|
66
|
+
type ChannelImplConfig = ChannelImplConfigWithAdapter | ChannelImplConfigLazy;
|
|
67
|
+
declare class ChannelImpl<TState = Record<string, unknown>> implements Channel<TState> {
|
|
68
|
+
readonly id: string;
|
|
69
|
+
readonly isDM: boolean;
|
|
70
|
+
private _adapter?;
|
|
71
|
+
private readonly _adapterName?;
|
|
72
|
+
private _stateAdapterInstance?;
|
|
73
|
+
private _name;
|
|
74
|
+
private readonly _messageHistory?;
|
|
75
|
+
constructor(config: ChannelImplConfig);
|
|
76
|
+
get adapter(): Adapter;
|
|
77
|
+
private get _stateAdapter();
|
|
78
|
+
get name(): string | null;
|
|
79
|
+
get state(): Promise<TState | null>;
|
|
80
|
+
setState(newState: Partial<TState>, options?: {
|
|
81
|
+
replace?: boolean;
|
|
82
|
+
}): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Iterate messages newest first (backward from most recent).
|
|
85
|
+
* Uses adapter.fetchChannelMessages if available, otherwise falls back
|
|
86
|
+
* to adapter.fetchMessages with the channel ID.
|
|
87
|
+
*/
|
|
88
|
+
get messages(): AsyncIterable<Message>;
|
|
89
|
+
/**
|
|
90
|
+
* Iterate threads in this channel, most recently active first.
|
|
91
|
+
*/
|
|
92
|
+
threads(): AsyncIterable<ThreadSummary>;
|
|
93
|
+
fetchMetadata(): Promise<ChannelInfo>;
|
|
94
|
+
post(message: string | PostableMessage | ChatElement): Promise<SentMessage>;
|
|
95
|
+
private postSingleMessage;
|
|
96
|
+
postEphemeral(user: string | Author, message: AdapterPostableMessage | ChatElement, options: PostEphemeralOptions): Promise<EphemeralMessage | null>;
|
|
97
|
+
schedule(message: AdapterPostableMessage | ChatElement, options: {
|
|
98
|
+
postAt: Date;
|
|
99
|
+
}): Promise<ScheduledMessage>;
|
|
100
|
+
startTyping(status?: string): Promise<void>;
|
|
101
|
+
mentionUser(userId: string): string;
|
|
102
|
+
toJSON(): SerializedChannel;
|
|
103
|
+
static fromJSON<TState = Record<string, unknown>>(json: SerializedChannel, adapter?: Adapter): ChannelImpl<TState>;
|
|
104
|
+
static [WORKFLOW_SERIALIZE](instance: ChannelImpl): SerializedChannel;
|
|
105
|
+
static [WORKFLOW_DESERIALIZE](data: SerializedChannel): ChannelImpl;
|
|
106
|
+
private createSentMessage;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Derive the channel ID from a thread ID.
|
|
110
|
+
*/
|
|
111
|
+
declare function deriveChannelId(adapter: Adapter, threadId: string): string;
|
|
6
112
|
|
|
7
113
|
/**
|
|
8
114
|
* Logger types and implementations for chat-sdk
|
|
@@ -31,6 +137,178 @@ declare class ConsoleLogger implements Logger {
|
|
|
31
137
|
error(message: string, ...args: unknown[]): void;
|
|
32
138
|
}
|
|
33
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Serialized thread data for passing to external systems (e.g., workflow engines).
|
|
142
|
+
*/
|
|
143
|
+
interface SerializedThread {
|
|
144
|
+
_type: "chat:Thread";
|
|
145
|
+
adapterName: string;
|
|
146
|
+
channelId: string;
|
|
147
|
+
currentMessage?: SerializedMessage;
|
|
148
|
+
id: string;
|
|
149
|
+
isDM: boolean;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Config for creating a ThreadImpl with explicit adapter/state instances.
|
|
153
|
+
*/
|
|
154
|
+
interface ThreadImplConfigWithAdapter {
|
|
155
|
+
adapter: Adapter;
|
|
156
|
+
channelId: string;
|
|
157
|
+
currentMessage?: Message;
|
|
158
|
+
fallbackStreamingPlaceholderText?: string | null;
|
|
159
|
+
id: string;
|
|
160
|
+
initialMessage?: Message;
|
|
161
|
+
isDM?: boolean;
|
|
162
|
+
isSubscribedContext?: boolean;
|
|
163
|
+
logger?: Logger;
|
|
164
|
+
messageHistory?: MessageHistoryCache;
|
|
165
|
+
stateAdapter: StateAdapter;
|
|
166
|
+
streamingUpdateIntervalMs?: number;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Config for creating a ThreadImpl with lazy adapter resolution.
|
|
170
|
+
* The adapter will be looked up from the Chat singleton on first access.
|
|
171
|
+
*/
|
|
172
|
+
interface ThreadImplConfigLazy {
|
|
173
|
+
adapterName: string;
|
|
174
|
+
channelId: string;
|
|
175
|
+
currentMessage?: Message;
|
|
176
|
+
fallbackStreamingPlaceholderText?: string | null;
|
|
177
|
+
id: string;
|
|
178
|
+
initialMessage?: Message;
|
|
179
|
+
isDM?: boolean;
|
|
180
|
+
isSubscribedContext?: boolean;
|
|
181
|
+
logger?: Logger;
|
|
182
|
+
streamingUpdateIntervalMs?: number;
|
|
183
|
+
}
|
|
184
|
+
type ThreadImplConfig = ThreadImplConfigWithAdapter | ThreadImplConfigLazy;
|
|
185
|
+
declare class ThreadImpl<TState = Record<string, unknown>> implements Thread<TState> {
|
|
186
|
+
readonly id: string;
|
|
187
|
+
readonly channelId: string;
|
|
188
|
+
readonly isDM: boolean;
|
|
189
|
+
/** Direct adapter instance (if provided) */
|
|
190
|
+
private _adapter?;
|
|
191
|
+
/** Adapter name for lazy resolution */
|
|
192
|
+
private readonly _adapterName?;
|
|
193
|
+
/** Direct state adapter instance (if provided) */
|
|
194
|
+
private _stateAdapterInstance?;
|
|
195
|
+
private _recentMessages;
|
|
196
|
+
private readonly _isSubscribedContext;
|
|
197
|
+
/** Current message context for streaming - provides userId/teamId */
|
|
198
|
+
private readonly _currentMessage?;
|
|
199
|
+
/** Update interval for fallback streaming */
|
|
200
|
+
private readonly _streamingUpdateIntervalMs;
|
|
201
|
+
/** Placeholder text for fallback streaming (post + edit) */
|
|
202
|
+
private readonly _fallbackStreamingPlaceholderText;
|
|
203
|
+
/** Cached channel instance */
|
|
204
|
+
private _channel?;
|
|
205
|
+
/** Message history cache (set only for adapters with persistMessageHistory) */
|
|
206
|
+
private readonly _messageHistory?;
|
|
207
|
+
private readonly _logger?;
|
|
208
|
+
constructor(config: ThreadImplConfig);
|
|
209
|
+
/**
|
|
210
|
+
* Get the adapter for this thread.
|
|
211
|
+
* If created with lazy config, resolves from Chat singleton on first access.
|
|
212
|
+
*/
|
|
213
|
+
get adapter(): Adapter;
|
|
214
|
+
/**
|
|
215
|
+
* Get the state adapter for this thread.
|
|
216
|
+
* If created with lazy config, resolves from Chat singleton on first access.
|
|
217
|
+
*/
|
|
218
|
+
private get _stateAdapter();
|
|
219
|
+
get recentMessages(): Message[];
|
|
220
|
+
set recentMessages(messages: Message[]);
|
|
221
|
+
/**
|
|
222
|
+
* Get the current thread state.
|
|
223
|
+
* Returns null if no state has been set.
|
|
224
|
+
*/
|
|
225
|
+
get state(): Promise<TState | null>;
|
|
226
|
+
/**
|
|
227
|
+
* Set the thread state. Merges with existing state by default.
|
|
228
|
+
* State is persisted for 30 days.
|
|
229
|
+
*/
|
|
230
|
+
setState(newState: Partial<TState>, options?: {
|
|
231
|
+
replace?: boolean;
|
|
232
|
+
}): Promise<void>;
|
|
233
|
+
/**
|
|
234
|
+
* Get the Channel containing this thread.
|
|
235
|
+
* Lazy-created and cached.
|
|
236
|
+
*/
|
|
237
|
+
get channel(): Channel<TState>;
|
|
238
|
+
/**
|
|
239
|
+
* Iterate messages newest first (backward from most recent).
|
|
240
|
+
* Auto-paginates lazily.
|
|
241
|
+
*/
|
|
242
|
+
get messages(): AsyncIterable<Message>;
|
|
243
|
+
get allMessages(): AsyncIterable<Message>;
|
|
244
|
+
isSubscribed(): Promise<boolean>;
|
|
245
|
+
subscribe(): Promise<void>;
|
|
246
|
+
unsubscribe(): Promise<void>;
|
|
247
|
+
post(message: string | PostableMessage | ChatElement): Promise<SentMessage>;
|
|
248
|
+
postEphemeral(user: string | Author, message: AdapterPostableMessage | ChatElement, options: PostEphemeralOptions): Promise<EphemeralMessage | null>;
|
|
249
|
+
schedule(message: AdapterPostableMessage | ChatElement, options: {
|
|
250
|
+
postAt: Date;
|
|
251
|
+
}): Promise<ScheduledMessage>;
|
|
252
|
+
/**
|
|
253
|
+
* Handle streaming from an AsyncIterable.
|
|
254
|
+
* Normalizes the stream (supports both textStream and fullStream from AI SDK),
|
|
255
|
+
* then uses adapter's native streaming if available, otherwise falls back to post+edit.
|
|
256
|
+
*/
|
|
257
|
+
private handleStream;
|
|
258
|
+
startTyping(status?: string): Promise<void>;
|
|
259
|
+
/**
|
|
260
|
+
* Fallback streaming implementation using post + edit.
|
|
261
|
+
* Used when adapter doesn't support native streaming.
|
|
262
|
+
* Uses recursive setTimeout to send updates every intervalMs (default 500ms).
|
|
263
|
+
* Schedules next update only after current edit completes to avoid overwhelming slow services.
|
|
264
|
+
*/
|
|
265
|
+
private fallbackStream;
|
|
266
|
+
refresh(): Promise<void>;
|
|
267
|
+
mentionUser(userId: string): string;
|
|
268
|
+
/**
|
|
269
|
+
* Serialize the thread to a plain JSON object.
|
|
270
|
+
* Use this to pass thread data to external systems like workflow engines.
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```typescript
|
|
274
|
+
* // Pass to a workflow
|
|
275
|
+
* await workflow.start("my-workflow", {
|
|
276
|
+
* thread: thread.toJSON(),
|
|
277
|
+
* message: serializeMessage(message),
|
|
278
|
+
* });
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
toJSON(): SerializedThread;
|
|
282
|
+
/**
|
|
283
|
+
* Reconstruct a Thread from serialized JSON data.
|
|
284
|
+
*
|
|
285
|
+
* Reconstructs a ThreadImpl from serialized data.
|
|
286
|
+
* Uses lazy resolution from Chat.getSingleton() for adapter and state.
|
|
287
|
+
*
|
|
288
|
+
* @param json - Serialized thread data
|
|
289
|
+
* @requires Call `chat.registerSingleton()` before deserializing threads
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* ```typescript
|
|
293
|
+
* const thread = ThreadImpl.fromJSON(serializedThread);
|
|
294
|
+
* ```
|
|
295
|
+
*/
|
|
296
|
+
static fromJSON<TState = Record<string, unknown>>(json: SerializedThread, adapter?: Adapter): ThreadImpl<TState>;
|
|
297
|
+
/**
|
|
298
|
+
* Serialize a ThreadImpl instance for @workflow/serde.
|
|
299
|
+
* This static method is automatically called by workflow serialization.
|
|
300
|
+
*/
|
|
301
|
+
static [WORKFLOW_SERIALIZE](instance: ThreadImpl): SerializedThread;
|
|
302
|
+
/**
|
|
303
|
+
* Deserialize a ThreadImpl from @workflow/serde.
|
|
304
|
+
* Uses lazy adapter resolution from Chat.getSingleton().
|
|
305
|
+
* Requires chat.registerSingleton() to have been called.
|
|
306
|
+
*/
|
|
307
|
+
static [WORKFLOW_DESERIALIZE](data: SerializedThread): ThreadImpl;
|
|
308
|
+
private createSentMessage;
|
|
309
|
+
createSentMessageFromMessage(message: Message): SentMessage;
|
|
310
|
+
}
|
|
311
|
+
|
|
34
312
|
/**
|
|
35
313
|
* Error types for chat-sdk
|
|
36
314
|
*/
|
|
@@ -58,6 +336,20 @@ declare class NotImplementedError extends ChatError {
|
|
|
58
336
|
interface ChatConfig<TAdapters extends Record<string, Adapter> = Record<string, Adapter>> {
|
|
59
337
|
/** Map of adapter name to adapter instance */
|
|
60
338
|
adapters: TAdapters;
|
|
339
|
+
/**
|
|
340
|
+
* How to handle messages that arrive while a handler is already
|
|
341
|
+
* processing on the same thread.
|
|
342
|
+
*
|
|
343
|
+
* - `'drop'` (default) — discard the message (throw `LockError`)
|
|
344
|
+
* - `'queue'` — queue the message; when the current handler finishes,
|
|
345
|
+
* process only the latest queued message with `context.skipped` containing
|
|
346
|
+
* all intermediate messages
|
|
347
|
+
* - `'debounce'` — all messages start/reset a debounce timer; only the
|
|
348
|
+
* final message in a burst is processed
|
|
349
|
+
* - `'concurrent'` — no locking; all messages processed in parallel
|
|
350
|
+
* - `ConcurrencyConfig` — fine-grained control over strategy and parameters
|
|
351
|
+
*/
|
|
352
|
+
concurrency?: ConcurrencyStrategy | ConcurrencyConfig;
|
|
61
353
|
/**
|
|
62
354
|
* TTL for message deduplication entries in milliseconds.
|
|
63
355
|
* Defaults to 300000 (5 minutes). Increase if your webhook cold starts
|
|
@@ -72,6 +364,17 @@ interface ChatConfig<TAdapters extends Record<string, Adapter> = Record<string,
|
|
|
72
364
|
* wait until some real text has been streamed before creating the message.
|
|
73
365
|
*/
|
|
74
366
|
fallbackStreamingPlaceholderText?: string | null;
|
|
367
|
+
/**
|
|
368
|
+
* Lock scope determines which messages contend for the same lock.
|
|
369
|
+
*
|
|
370
|
+
* - `'thread'`: lock per threadId (default for most adapters)
|
|
371
|
+
* - `'channel'`: lock per channelId (default for WhatsApp, Telegram)
|
|
372
|
+
* - function: resolve scope dynamically per message (async supported)
|
|
373
|
+
*
|
|
374
|
+
* When not set, falls back to the adapter's `lockScope` property,
|
|
375
|
+
* then to `'thread'`.
|
|
376
|
+
*/
|
|
377
|
+
lockScope?: LockScope | ((context: LockScopeContext) => LockScope | Promise<LockScope>);
|
|
75
378
|
/**
|
|
76
379
|
* Logger instance or log level.
|
|
77
380
|
* Pass "silent" to disable all logging.
|
|
@@ -88,6 +391,8 @@ interface ChatConfig<TAdapters extends Record<string, Adapter> = Record<string,
|
|
|
88
391
|
ttlMs?: number;
|
|
89
392
|
};
|
|
90
393
|
/**
|
|
394
|
+
* @deprecated Use `concurrency` instead.
|
|
395
|
+
*
|
|
91
396
|
* Behavior when a thread lock cannot be acquired (another handler is processing).
|
|
92
397
|
* - `'drop'` (default) — throw `LockError`, preserving current behavior
|
|
93
398
|
* - `'force'` — force-release the existing lock and re-acquire
|
|
@@ -149,6 +454,8 @@ interface Adapter<TThreadId = unknown, TRawMessage = unknown> {
|
|
|
149
454
|
decodeThreadId(threadId: string): TThreadId;
|
|
150
455
|
/** Delete a message */
|
|
151
456
|
deleteMessage(threadId: string, messageId: string): Promise<void>;
|
|
457
|
+
/** Cleanup hook called when Chat instance is shutdown */
|
|
458
|
+
disconnect?(): Promise<void>;
|
|
152
459
|
/** Edit an existing message */
|
|
153
460
|
editMessage(threadId: string, messageId: string, message: AdapterPostableMessage): Promise<RawMessage<TRawMessage>>;
|
|
154
461
|
/** Encode platform-specific data into a thread ID string */
|
|
@@ -221,6 +528,14 @@ interface Adapter<TThreadId = unknown, TRawMessage = unknown> {
|
|
|
221
528
|
* List threads in a channel.
|
|
222
529
|
*/
|
|
223
530
|
listThreads?(channelId: string, options?: ListThreadsOptions): Promise<ListThreadsResult<TRawMessage>>;
|
|
531
|
+
/**
|
|
532
|
+
* Default lock scope for this adapter.
|
|
533
|
+
* - `'thread'` (default): lock per threadId
|
|
534
|
+
* - `'channel'`: lock per channelId (for channel-based platforms like WhatsApp, Telegram)
|
|
535
|
+
*
|
|
536
|
+
* Can be overridden by `ChatConfig.lockScope`.
|
|
537
|
+
*/
|
|
538
|
+
readonly lockScope?: LockScope;
|
|
224
539
|
/** Unique name for this adapter (e.g., "slack", "teams") */
|
|
225
540
|
readonly name: string;
|
|
226
541
|
/**
|
|
@@ -436,6 +751,57 @@ interface ChatInstance {
|
|
|
436
751
|
channelId: string;
|
|
437
752
|
}, options?: WebhookOptions): void;
|
|
438
753
|
}
|
|
754
|
+
/** Lock scope determines which messages contend for the same lock. */
|
|
755
|
+
type LockScope = "thread" | "channel";
|
|
756
|
+
/** Context provided to the lockScope resolver function. */
|
|
757
|
+
interface LockScopeContext {
|
|
758
|
+
adapter: Adapter;
|
|
759
|
+
channelId: string;
|
|
760
|
+
isDM: boolean;
|
|
761
|
+
threadId: string;
|
|
762
|
+
}
|
|
763
|
+
/** Concurrency strategy for overlapping messages on the same thread. */
|
|
764
|
+
type ConcurrencyStrategy = "drop" | "queue" | "debounce" | "concurrent";
|
|
765
|
+
/** Fine-grained concurrency configuration. */
|
|
766
|
+
interface ConcurrencyConfig {
|
|
767
|
+
/** Debounce window in milliseconds (debounce strategy). Default: 1500. */
|
|
768
|
+
debounceMs?: number;
|
|
769
|
+
/** Max concurrent handlers per thread (concurrent strategy). Default: Infinity. */
|
|
770
|
+
maxConcurrent?: number;
|
|
771
|
+
/** Max queued messages per thread (queue/debounce strategy). Default: 10. */
|
|
772
|
+
maxQueueSize?: number;
|
|
773
|
+
/** What to do when queue is full. Default: 'drop-oldest'. */
|
|
774
|
+
onQueueFull?: "drop-oldest" | "drop-newest";
|
|
775
|
+
/** TTL for queued entries in milliseconds. Default: 90000 (90s). */
|
|
776
|
+
queueEntryTtlMs?: number;
|
|
777
|
+
/** The concurrency strategy to use. */
|
|
778
|
+
strategy: ConcurrencyStrategy;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* An entry in the per-thread message queue.
|
|
782
|
+
* Used by the `queue` and `debounce` concurrency strategies.
|
|
783
|
+
*/
|
|
784
|
+
interface QueueEntry {
|
|
785
|
+
/** When this entry was enqueued (Unix ms). */
|
|
786
|
+
enqueuedAt: number;
|
|
787
|
+
/** When this entry expires (Unix ms). Stale entries are discarded on dequeue. */
|
|
788
|
+
expiresAt: number;
|
|
789
|
+
/** The queued message. */
|
|
790
|
+
message: Message;
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Context provided to message handlers when messages were queued
|
|
794
|
+
* while a previous handler was running.
|
|
795
|
+
*/
|
|
796
|
+
interface MessageContext {
|
|
797
|
+
/**
|
|
798
|
+
* Messages that arrived while the previous handler was running,
|
|
799
|
+
* in chronological order, excluding the current message (which is the latest).
|
|
800
|
+
*/
|
|
801
|
+
skipped: Message[];
|
|
802
|
+
/** Total messages received since last handler ran (skipped.length + 1). */
|
|
803
|
+
totalSinceLastHandler: number;
|
|
804
|
+
}
|
|
439
805
|
interface StateAdapter {
|
|
440
806
|
/** Acquire a lock on a thread (returns null if already locked) */
|
|
441
807
|
acquireLock(threadId: string, ttlMs: number): Promise<Lock | null>;
|
|
@@ -448,8 +814,12 @@ interface StateAdapter {
|
|
|
448
814
|
connect(): Promise<void>;
|
|
449
815
|
/** Delete a cached value */
|
|
450
816
|
delete(key: string): Promise<void>;
|
|
817
|
+
/** Pop the next message from the thread's queue. Returns null if empty. */
|
|
818
|
+
dequeue(threadId: string): Promise<QueueEntry | null>;
|
|
451
819
|
/** Disconnect from the state backend */
|
|
452
820
|
disconnect(): Promise<void>;
|
|
821
|
+
/** Atomically append a message to the thread's pending queue. Returns new queue depth. */
|
|
822
|
+
enqueue(threadId: string, entry: QueueEntry, maxSize: number): Promise<number>;
|
|
453
823
|
/** Extend a lock's TTL */
|
|
454
824
|
extendLock(lock: Lock, ttlMs: number): Promise<boolean>;
|
|
455
825
|
/**
|
|
@@ -464,6 +834,8 @@ interface StateAdapter {
|
|
|
464
834
|
getList<T = unknown>(key: string): Promise<T[]>;
|
|
465
835
|
/** Check if subscribed to a thread */
|
|
466
836
|
isSubscribed(threadId: string): Promise<boolean>;
|
|
837
|
+
/** Get the current queue depth for a thread. */
|
|
838
|
+
queueDepth(threadId: string): Promise<number>;
|
|
467
839
|
/** Release a lock */
|
|
468
840
|
releaseLock(lock: Lock): Promise<void>;
|
|
469
841
|
/** Set a cached value with optional TTL in milliseconds */
|
|
@@ -566,6 +938,11 @@ interface Channel<TState = Record<string, unknown>, TRawMessage = unknown> exten
|
|
|
566
938
|
* Empty iterable on threadless platforms.
|
|
567
939
|
*/
|
|
568
940
|
threads(): AsyncIterable<ThreadSummary<TRawMessage>>;
|
|
941
|
+
/**
|
|
942
|
+
* Serialize the channel to a plain JSON object.
|
|
943
|
+
* Use this to pass channel data to external systems like workflow engines.
|
|
944
|
+
*/
|
|
945
|
+
toJSON(): SerializedChannel;
|
|
569
946
|
}
|
|
570
947
|
/**
|
|
571
948
|
* Lightweight summary of a thread within a channel.
|
|
@@ -738,6 +1115,11 @@ interface Thread<TState = Record<string, unknown>, TRawMessage = unknown> extend
|
|
|
738
1115
|
* ```
|
|
739
1116
|
*/
|
|
740
1117
|
subscribe(): Promise<void>;
|
|
1118
|
+
/**
|
|
1119
|
+
* Serialize the thread to a plain JSON object.
|
|
1120
|
+
* Use this to pass thread data to external systems like workflow engines.
|
|
1121
|
+
*/
|
|
1122
|
+
toJSON(): SerializedThread;
|
|
741
1123
|
/**
|
|
742
1124
|
* Unsubscribe from this thread.
|
|
743
1125
|
*
|
|
@@ -1059,7 +1441,7 @@ interface FileUpload {
|
|
|
1059
1441
|
* });
|
|
1060
1442
|
* ```
|
|
1061
1443
|
*/
|
|
1062
|
-
type MentionHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message) => void | Promise<void>;
|
|
1444
|
+
type MentionHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message, context?: MessageContext) => void | Promise<void>;
|
|
1063
1445
|
/**
|
|
1064
1446
|
* Handler for direct messages (1:1 conversations with the bot).
|
|
1065
1447
|
*
|
|
@@ -1068,14 +1450,14 @@ type MentionHandler<TState = Record<string, unknown>> = (thread: Thread<TState>,
|
|
|
1068
1450
|
* handlers are registered, DMs fall through to `onNewMention` for backward
|
|
1069
1451
|
* compatibility.
|
|
1070
1452
|
*/
|
|
1071
|
-
type DirectMessageHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message, channel: Channel<TState
|
|
1453
|
+
type DirectMessageHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message, channel: Channel<TState>, context?: MessageContext) => void | Promise<void>;
|
|
1072
1454
|
/**
|
|
1073
1455
|
* Handler for messages matching a regex pattern.
|
|
1074
1456
|
*
|
|
1075
1457
|
* Registered via `chat.onNewMessage(pattern, handler)`. Called when a message
|
|
1076
1458
|
* matches the pattern in an unsubscribed thread.
|
|
1077
1459
|
*/
|
|
1078
|
-
type MessageHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message) => void | Promise<void>;
|
|
1460
|
+
type MessageHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message, context?: MessageContext) => void | Promise<void>;
|
|
1079
1461
|
/**
|
|
1080
1462
|
* Handler for messages in subscribed threads.
|
|
1081
1463
|
*
|
|
@@ -1099,7 +1481,7 @@ type MessageHandler<TState = Record<string, unknown>> = (thread: Thread<TState>,
|
|
|
1099
1481
|
* });
|
|
1100
1482
|
* ```
|
|
1101
1483
|
*/
|
|
1102
|
-
type SubscribedMessageHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message) => void | Promise<void>;
|
|
1484
|
+
type SubscribedMessageHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message, context?: MessageContext) => void | Promise<void>;
|
|
1103
1485
|
/**
|
|
1104
1486
|
* Well-known emoji that work across platforms (Slack and Google Chat).
|
|
1105
1487
|
* These are normalized to a common format regardless of platform.
|
|
@@ -1684,165 +2066,59 @@ type AiMessagePart = AiTextPart | AiImagePart | AiFilePart;
|
|
|
1684
2066
|
*
|
|
1685
2067
|
* This is a discriminated union matching AI SDK's ModelMessage type:
|
|
1686
2068
|
* - User messages can have text, image, and file parts
|
|
1687
|
-
* - Assistant messages have string content only
|
|
1688
|
-
*/
|
|
1689
|
-
type AiMessage = AiUserMessage | AiAssistantMessage;
|
|
1690
|
-
interface AiUserMessage {
|
|
1691
|
-
content: string | AiMessagePart[];
|
|
1692
|
-
role: "user";
|
|
1693
|
-
}
|
|
1694
|
-
interface AiAssistantMessage {
|
|
1695
|
-
content: string;
|
|
1696
|
-
role: "assistant";
|
|
1697
|
-
}
|
|
1698
|
-
/**
|
|
1699
|
-
* Options for converting messages to AI SDK format.
|
|
1700
|
-
*/
|
|
1701
|
-
interface ToAiMessagesOptions {
|
|
1702
|
-
/** When true, prefixes user messages with "[username]: " for multi-user context */
|
|
1703
|
-
includeNames?: boolean;
|
|
1704
|
-
/**
|
|
1705
|
-
* Called when an attachment type is not supported (video, audio).
|
|
1706
|
-
* Defaults to `console.warn`.
|
|
1707
|
-
*/
|
|
1708
|
-
onUnsupportedAttachment?: (attachment: Attachment, message: Message) => void;
|
|
1709
|
-
/**
|
|
1710
|
-
* Called for each message after default processing (text, links, attachments).
|
|
1711
|
-
* Return the message (modified or as-is) to include it, or `null` to skip it.
|
|
1712
|
-
*
|
|
1713
|
-
* @param aiMessage - The processed AI message
|
|
1714
|
-
* @param source - The original chat Message
|
|
1715
|
-
* @returns The message to include, or null to skip
|
|
1716
|
-
*/
|
|
1717
|
-
transformMessage?: (aiMessage: AiMessage, source: Message) => AiMessage | null | Promise<AiMessage | null>;
|
|
1718
|
-
}
|
|
1719
|
-
/**
|
|
1720
|
-
* Convert chat SDK messages to AI SDK conversation format.
|
|
1721
|
-
*
|
|
1722
|
-
* - Filters out messages with empty/whitespace-only text
|
|
1723
|
-
* - Maps `author.isMe === true` to `"assistant"`, otherwise `"user"`
|
|
1724
|
-
* - Uses `message.text` for content
|
|
1725
|
-
* - Appends link metadata when available
|
|
1726
|
-
* - Includes image attachments and text files as `FilePart`
|
|
1727
|
-
* - Uses `fetchData()` when available to include attachment data inline (base64)
|
|
1728
|
-
* - Warns on unsupported attachment types (video, audio)
|
|
1729
|
-
*
|
|
1730
|
-
* Works with `FetchResult.messages`, `thread.recentMessages`, or collected iterables.
|
|
1731
|
-
*
|
|
1732
|
-
* @example
|
|
1733
|
-
* ```typescript
|
|
1734
|
-
* const result = await thread.adapter.fetchMessages(thread.id, { limit: 20 });
|
|
1735
|
-
* const history = await toAiMessages(result.messages);
|
|
1736
|
-
* const response = await agent.stream({ prompt: history });
|
|
1737
|
-
* ```
|
|
1738
|
-
*/
|
|
1739
|
-
declare function toAiMessages(messages: Message[], options?: ToAiMessagesOptions): Promise<AiMessage[]>;
|
|
1740
|
-
|
|
1741
|
-
interface MessageHistoryConfig {
|
|
1742
|
-
/** Maximum messages to keep per thread (default: 100) */
|
|
1743
|
-
maxMessages?: number;
|
|
1744
|
-
/** TTL for cached history in milliseconds (default: 7 days) */
|
|
1745
|
-
ttlMs?: number;
|
|
1746
|
-
}
|
|
1747
|
-
/**
|
|
1748
|
-
* Persistent message history cache backed by the StateAdapter.
|
|
1749
|
-
*
|
|
1750
|
-
* Used by adapters that lack server-side message history APIs (e.g., WhatsApp, Telegram).
|
|
1751
|
-
* Messages are atomically appended via `state.appendToList()`, which is safe
|
|
1752
|
-
* without holding a thread lock.
|
|
1753
|
-
*/
|
|
1754
|
-
declare class MessageHistoryCache {
|
|
1755
|
-
private readonly state;
|
|
1756
|
-
private readonly maxMessages;
|
|
1757
|
-
private readonly ttlMs;
|
|
1758
|
-
constructor(state: StateAdapter, config?: MessageHistoryConfig);
|
|
1759
|
-
/**
|
|
1760
|
-
* Atomically append a message to the history for a thread.
|
|
1761
|
-
* Trims to maxMessages (keeps newest) and refreshes TTL.
|
|
1762
|
-
*/
|
|
1763
|
-
append(threadId: string, message: Message): Promise<void>;
|
|
1764
|
-
/**
|
|
1765
|
-
* Get messages for a thread in chronological order (oldest first).
|
|
1766
|
-
*
|
|
1767
|
-
* @param threadId - The thread ID
|
|
1768
|
-
* @param limit - Optional limit on number of messages to return (returns newest N)
|
|
1769
|
-
*/
|
|
1770
|
-
getMessages(threadId: string, limit?: number): Promise<Message[]>;
|
|
1771
|
-
}
|
|
1772
|
-
|
|
1773
|
-
/**
|
|
1774
|
-
* Serialized channel data for passing to external systems (e.g., workflow engines).
|
|
1775
|
-
*/
|
|
1776
|
-
interface SerializedChannel {
|
|
1777
|
-
_type: "chat:Channel";
|
|
1778
|
-
adapterName: string;
|
|
1779
|
-
id: string;
|
|
1780
|
-
isDM: boolean;
|
|
1781
|
-
}
|
|
1782
|
-
/**
|
|
1783
|
-
* Config for creating a ChannelImpl with explicit adapter/state instances.
|
|
1784
|
-
*/
|
|
1785
|
-
interface ChannelImplConfigWithAdapter {
|
|
1786
|
-
adapter: Adapter;
|
|
1787
|
-
id: string;
|
|
1788
|
-
isDM?: boolean;
|
|
1789
|
-
messageHistory?: MessageHistoryCache;
|
|
1790
|
-
stateAdapter: StateAdapter;
|
|
1791
|
-
}
|
|
1792
|
-
/**
|
|
1793
|
-
* Config for creating a ChannelImpl with lazy adapter resolution.
|
|
1794
|
-
*/
|
|
1795
|
-
interface ChannelImplConfigLazy {
|
|
1796
|
-
adapterName: string;
|
|
1797
|
-
id: string;
|
|
1798
|
-
isDM?: boolean;
|
|
1799
|
-
}
|
|
1800
|
-
type ChannelImplConfig = ChannelImplConfigWithAdapter | ChannelImplConfigLazy;
|
|
1801
|
-
declare class ChannelImpl<TState = Record<string, unknown>> implements Channel<TState> {
|
|
1802
|
-
readonly id: string;
|
|
1803
|
-
readonly isDM: boolean;
|
|
1804
|
-
private _adapter?;
|
|
1805
|
-
private readonly _adapterName?;
|
|
1806
|
-
private _stateAdapterInstance?;
|
|
1807
|
-
private _name;
|
|
1808
|
-
private readonly _messageHistory?;
|
|
1809
|
-
constructor(config: ChannelImplConfig);
|
|
1810
|
-
get adapter(): Adapter;
|
|
1811
|
-
private get _stateAdapter();
|
|
1812
|
-
get name(): string | null;
|
|
1813
|
-
get state(): Promise<TState | null>;
|
|
1814
|
-
setState(newState: Partial<TState>, options?: {
|
|
1815
|
-
replace?: boolean;
|
|
1816
|
-
}): Promise<void>;
|
|
2069
|
+
* - Assistant messages have string content only
|
|
2070
|
+
*/
|
|
2071
|
+
type AiMessage = AiUserMessage | AiAssistantMessage;
|
|
2072
|
+
interface AiUserMessage {
|
|
2073
|
+
content: string | AiMessagePart[];
|
|
2074
|
+
role: "user";
|
|
2075
|
+
}
|
|
2076
|
+
interface AiAssistantMessage {
|
|
2077
|
+
content: string;
|
|
2078
|
+
role: "assistant";
|
|
2079
|
+
}
|
|
2080
|
+
/**
|
|
2081
|
+
* Options for converting messages to AI SDK format.
|
|
2082
|
+
*/
|
|
2083
|
+
interface ToAiMessagesOptions {
|
|
2084
|
+
/** When true, prefixes user messages with "[username]: " for multi-user context */
|
|
2085
|
+
includeNames?: boolean;
|
|
1817
2086
|
/**
|
|
1818
|
-
*
|
|
1819
|
-
*
|
|
1820
|
-
* to adapter.fetchMessages with the channel ID.
|
|
2087
|
+
* Called when an attachment type is not supported (video, audio).
|
|
2088
|
+
* Defaults to `console.warn`.
|
|
1821
2089
|
*/
|
|
1822
|
-
|
|
2090
|
+
onUnsupportedAttachment?: (attachment: Attachment, message: Message) => void;
|
|
1823
2091
|
/**
|
|
1824
|
-
*
|
|
2092
|
+
* Called for each message after default processing (text, links, attachments).
|
|
2093
|
+
* Return the message (modified or as-is) to include it, or `null` to skip it.
|
|
2094
|
+
*
|
|
2095
|
+
* @param aiMessage - The processed AI message
|
|
2096
|
+
* @param source - The original chat Message
|
|
2097
|
+
* @returns The message to include, or null to skip
|
|
1825
2098
|
*/
|
|
1826
|
-
|
|
1827
|
-
fetchMetadata(): Promise<ChannelInfo>;
|
|
1828
|
-
post(message: string | PostableMessage | ChatElement): Promise<SentMessage>;
|
|
1829
|
-
private postSingleMessage;
|
|
1830
|
-
postEphemeral(user: string | Author, message: AdapterPostableMessage | ChatElement, options: PostEphemeralOptions): Promise<EphemeralMessage | null>;
|
|
1831
|
-
schedule(message: AdapterPostableMessage | ChatElement, options: {
|
|
1832
|
-
postAt: Date;
|
|
1833
|
-
}): Promise<ScheduledMessage>;
|
|
1834
|
-
startTyping(status?: string): Promise<void>;
|
|
1835
|
-
mentionUser(userId: string): string;
|
|
1836
|
-
toJSON(): SerializedChannel;
|
|
1837
|
-
static fromJSON<TState = Record<string, unknown>>(json: SerializedChannel, adapter?: Adapter): ChannelImpl<TState>;
|
|
1838
|
-
static [WORKFLOW_SERIALIZE](instance: ChannelImpl): SerializedChannel;
|
|
1839
|
-
static [WORKFLOW_DESERIALIZE](data: SerializedChannel): ChannelImpl;
|
|
1840
|
-
private createSentMessage;
|
|
2099
|
+
transformMessage?: (aiMessage: AiMessage, source: Message) => AiMessage | null | Promise<AiMessage | null>;
|
|
1841
2100
|
}
|
|
1842
2101
|
/**
|
|
1843
|
-
*
|
|
2102
|
+
* Convert chat SDK messages to AI SDK conversation format.
|
|
2103
|
+
*
|
|
2104
|
+
* - Filters out messages with empty/whitespace-only text
|
|
2105
|
+
* - Maps `author.isMe === true` to `"assistant"`, otherwise `"user"`
|
|
2106
|
+
* - Uses `message.text` for content
|
|
2107
|
+
* - Appends link metadata when available
|
|
2108
|
+
* - Includes image attachments and text files as `FilePart`
|
|
2109
|
+
* - Uses `fetchData()` when available to include attachment data inline (base64)
|
|
2110
|
+
* - Warns on unsupported attachment types (video, audio)
|
|
2111
|
+
*
|
|
2112
|
+
* Works with `FetchResult.messages`, `thread.recentMessages`, or collected iterables.
|
|
2113
|
+
*
|
|
2114
|
+
* @example
|
|
2115
|
+
* ```typescript
|
|
2116
|
+
* const result = await thread.adapter.fetchMessages(thread.id, { limit: 20 });
|
|
2117
|
+
* const history = await toAiMessages(result.messages);
|
|
2118
|
+
* const response = await agent.stream({ prompt: history });
|
|
2119
|
+
* ```
|
|
1844
2120
|
*/
|
|
1845
|
-
declare function
|
|
2121
|
+
declare function toAiMessages(messages: Message[], options?: ToAiMessagesOptions): Promise<AiMessage[]>;
|
|
1846
2122
|
|
|
1847
2123
|
/** Filter can be EmojiValue objects, emoji names, or raw emoji formats */
|
|
1848
2124
|
type EmojiFilter = EmojiValue | string;
|
|
@@ -1917,6 +2193,9 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
|
|
|
1917
2193
|
private readonly _dedupeTtlMs;
|
|
1918
2194
|
private readonly _onLockConflict;
|
|
1919
2195
|
private readonly _messageHistory;
|
|
2196
|
+
private readonly _concurrencyStrategy;
|
|
2197
|
+
private readonly _concurrencyConfig;
|
|
2198
|
+
private readonly _lockScope;
|
|
1920
2199
|
private readonly mentionHandlers;
|
|
1921
2200
|
private readonly directMessageHandlers;
|
|
1922
2201
|
private readonly messagePatterns;
|
|
@@ -2286,6 +2565,12 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
|
|
|
2286
2565
|
* Infer which adapter to use based on the userId format.
|
|
2287
2566
|
*/
|
|
2288
2567
|
private inferAdapterFromUserId;
|
|
2568
|
+
/**
|
|
2569
|
+
* Resolve the lock key for a message based on lock scope.
|
|
2570
|
+
* With 'thread' scope, returns threadId. With 'channel' scope,
|
|
2571
|
+
* returns channelId (derived via adapter.channelIdFromThreadId).
|
|
2572
|
+
*/
|
|
2573
|
+
private getLockKey;
|
|
2289
2574
|
/**
|
|
2290
2575
|
* Handle an incoming message from an adapter.
|
|
2291
2576
|
* This is called by adapters when they receive a webhook.
|
|
@@ -2294,9 +2579,36 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
|
|
|
2294
2579
|
* - Deduplication: Same message may arrive multiple times (e.g., Slack sends
|
|
2295
2580
|
* both `message` and `app_mention` events, GChat sends direct webhook + Pub/Sub)
|
|
2296
2581
|
* - Bot filtering: Messages from the bot itself are skipped
|
|
2297
|
-
* -
|
|
2582
|
+
* - Concurrency: Controlled by `concurrency` config (drop, queue, debounce, concurrent)
|
|
2298
2583
|
*/
|
|
2299
2584
|
handleIncomingMessage(adapter: Adapter, threadId: string, message: Message): Promise<void>;
|
|
2585
|
+
/**
|
|
2586
|
+
* Drop strategy: acquire lock or fail. Original behavior.
|
|
2587
|
+
*/
|
|
2588
|
+
private handleDrop;
|
|
2589
|
+
/**
|
|
2590
|
+
* Queue/Debounce strategy: enqueue if lock is busy, drain after processing.
|
|
2591
|
+
*/
|
|
2592
|
+
private handleQueueOrDebounce;
|
|
2593
|
+
/**
|
|
2594
|
+
* Debounce loop: wait for debounceMs, check if newer message arrived,
|
|
2595
|
+
* repeat until no new messages, then process the final message.
|
|
2596
|
+
*/
|
|
2597
|
+
private debounceLoop;
|
|
2598
|
+
/**
|
|
2599
|
+
* Drain queue: collect all pending messages, dispatch the latest with
|
|
2600
|
+
* skipped context, then check for more.
|
|
2601
|
+
*/
|
|
2602
|
+
private drainQueue;
|
|
2603
|
+
/**
|
|
2604
|
+
* Concurrent strategy: no locking, process immediately.
|
|
2605
|
+
*/
|
|
2606
|
+
private handleConcurrent;
|
|
2607
|
+
/**
|
|
2608
|
+
* Dispatch a message to the appropriate handler chain based on
|
|
2609
|
+
* subscription status, mention detection, and pattern matching.
|
|
2610
|
+
*/
|
|
2611
|
+
private dispatchToHandlers;
|
|
2300
2612
|
private createThread;
|
|
2301
2613
|
/**
|
|
2302
2614
|
* Detect if the bot was mentioned in the message.
|
|
@@ -2304,6 +2616,13 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
|
|
|
2304
2616
|
*/
|
|
2305
2617
|
private detectMention;
|
|
2306
2618
|
private escapeRegex;
|
|
2619
|
+
/**
|
|
2620
|
+
* Reconstruct a proper Message instance from a dequeued entry.
|
|
2621
|
+
* After JSON roundtrip through the state adapter, the message is a plain
|
|
2622
|
+
* object (not a Message instance). This restores class invariants like
|
|
2623
|
+
* `links` defaulting to `[]` and `metadata.dateSent` being a Date.
|
|
2624
|
+
*/
|
|
2625
|
+
private rehydrateMessage;
|
|
2307
2626
|
private runHandlers;
|
|
2308
2627
|
}
|
|
2309
2628
|
|
|
@@ -2374,178 +2693,6 @@ declare class StreamingMarkdownRenderer {
|
|
|
2374
2693
|
finish(): string;
|
|
2375
2694
|
}
|
|
2376
2695
|
|
|
2377
|
-
/**
|
|
2378
|
-
* Serialized thread data for passing to external systems (e.g., workflow engines).
|
|
2379
|
-
*/
|
|
2380
|
-
interface SerializedThread {
|
|
2381
|
-
_type: "chat:Thread";
|
|
2382
|
-
adapterName: string;
|
|
2383
|
-
channelId: string;
|
|
2384
|
-
currentMessage?: SerializedMessage;
|
|
2385
|
-
id: string;
|
|
2386
|
-
isDM: boolean;
|
|
2387
|
-
}
|
|
2388
|
-
/**
|
|
2389
|
-
* Config for creating a ThreadImpl with explicit adapter/state instances.
|
|
2390
|
-
*/
|
|
2391
|
-
interface ThreadImplConfigWithAdapter {
|
|
2392
|
-
adapter: Adapter;
|
|
2393
|
-
channelId: string;
|
|
2394
|
-
currentMessage?: Message;
|
|
2395
|
-
fallbackStreamingPlaceholderText?: string | null;
|
|
2396
|
-
id: string;
|
|
2397
|
-
initialMessage?: Message;
|
|
2398
|
-
isDM?: boolean;
|
|
2399
|
-
isSubscribedContext?: boolean;
|
|
2400
|
-
logger?: Logger;
|
|
2401
|
-
messageHistory?: MessageHistoryCache;
|
|
2402
|
-
stateAdapter: StateAdapter;
|
|
2403
|
-
streamingUpdateIntervalMs?: number;
|
|
2404
|
-
}
|
|
2405
|
-
/**
|
|
2406
|
-
* Config for creating a ThreadImpl with lazy adapter resolution.
|
|
2407
|
-
* The adapter will be looked up from the Chat singleton on first access.
|
|
2408
|
-
*/
|
|
2409
|
-
interface ThreadImplConfigLazy {
|
|
2410
|
-
adapterName: string;
|
|
2411
|
-
channelId: string;
|
|
2412
|
-
currentMessage?: Message;
|
|
2413
|
-
fallbackStreamingPlaceholderText?: string | null;
|
|
2414
|
-
id: string;
|
|
2415
|
-
initialMessage?: Message;
|
|
2416
|
-
isDM?: boolean;
|
|
2417
|
-
isSubscribedContext?: boolean;
|
|
2418
|
-
logger?: Logger;
|
|
2419
|
-
streamingUpdateIntervalMs?: number;
|
|
2420
|
-
}
|
|
2421
|
-
type ThreadImplConfig = ThreadImplConfigWithAdapter | ThreadImplConfigLazy;
|
|
2422
|
-
declare class ThreadImpl<TState = Record<string, unknown>> implements Thread<TState> {
|
|
2423
|
-
readonly id: string;
|
|
2424
|
-
readonly channelId: string;
|
|
2425
|
-
readonly isDM: boolean;
|
|
2426
|
-
/** Direct adapter instance (if provided) */
|
|
2427
|
-
private _adapter?;
|
|
2428
|
-
/** Adapter name for lazy resolution */
|
|
2429
|
-
private readonly _adapterName?;
|
|
2430
|
-
/** Direct state adapter instance (if provided) */
|
|
2431
|
-
private _stateAdapterInstance?;
|
|
2432
|
-
private _recentMessages;
|
|
2433
|
-
private readonly _isSubscribedContext;
|
|
2434
|
-
/** Current message context for streaming - provides userId/teamId */
|
|
2435
|
-
private readonly _currentMessage?;
|
|
2436
|
-
/** Update interval for fallback streaming */
|
|
2437
|
-
private readonly _streamingUpdateIntervalMs;
|
|
2438
|
-
/** Placeholder text for fallback streaming (post + edit) */
|
|
2439
|
-
private readonly _fallbackStreamingPlaceholderText;
|
|
2440
|
-
/** Cached channel instance */
|
|
2441
|
-
private _channel?;
|
|
2442
|
-
/** Message history cache (set only for adapters with persistMessageHistory) */
|
|
2443
|
-
private readonly _messageHistory?;
|
|
2444
|
-
private readonly _logger?;
|
|
2445
|
-
constructor(config: ThreadImplConfig);
|
|
2446
|
-
/**
|
|
2447
|
-
* Get the adapter for this thread.
|
|
2448
|
-
* If created with lazy config, resolves from Chat singleton on first access.
|
|
2449
|
-
*/
|
|
2450
|
-
get adapter(): Adapter;
|
|
2451
|
-
/**
|
|
2452
|
-
* Get the state adapter for this thread.
|
|
2453
|
-
* If created with lazy config, resolves from Chat singleton on first access.
|
|
2454
|
-
*/
|
|
2455
|
-
private get _stateAdapter();
|
|
2456
|
-
get recentMessages(): Message[];
|
|
2457
|
-
set recentMessages(messages: Message[]);
|
|
2458
|
-
/**
|
|
2459
|
-
* Get the current thread state.
|
|
2460
|
-
* Returns null if no state has been set.
|
|
2461
|
-
*/
|
|
2462
|
-
get state(): Promise<TState | null>;
|
|
2463
|
-
/**
|
|
2464
|
-
* Set the thread state. Merges with existing state by default.
|
|
2465
|
-
* State is persisted for 30 days.
|
|
2466
|
-
*/
|
|
2467
|
-
setState(newState: Partial<TState>, options?: {
|
|
2468
|
-
replace?: boolean;
|
|
2469
|
-
}): Promise<void>;
|
|
2470
|
-
/**
|
|
2471
|
-
* Get the Channel containing this thread.
|
|
2472
|
-
* Lazy-created and cached.
|
|
2473
|
-
*/
|
|
2474
|
-
get channel(): Channel<TState>;
|
|
2475
|
-
/**
|
|
2476
|
-
* Iterate messages newest first (backward from most recent).
|
|
2477
|
-
* Auto-paginates lazily.
|
|
2478
|
-
*/
|
|
2479
|
-
get messages(): AsyncIterable<Message>;
|
|
2480
|
-
get allMessages(): AsyncIterable<Message>;
|
|
2481
|
-
isSubscribed(): Promise<boolean>;
|
|
2482
|
-
subscribe(): Promise<void>;
|
|
2483
|
-
unsubscribe(): Promise<void>;
|
|
2484
|
-
post(message: string | PostableMessage | ChatElement): Promise<SentMessage>;
|
|
2485
|
-
postEphemeral(user: string | Author, message: AdapterPostableMessage | ChatElement, options: PostEphemeralOptions): Promise<EphemeralMessage | null>;
|
|
2486
|
-
schedule(message: AdapterPostableMessage | ChatElement, options: {
|
|
2487
|
-
postAt: Date;
|
|
2488
|
-
}): Promise<ScheduledMessage>;
|
|
2489
|
-
/**
|
|
2490
|
-
* Handle streaming from an AsyncIterable.
|
|
2491
|
-
* Normalizes the stream (supports both textStream and fullStream from AI SDK),
|
|
2492
|
-
* then uses adapter's native streaming if available, otherwise falls back to post+edit.
|
|
2493
|
-
*/
|
|
2494
|
-
private handleStream;
|
|
2495
|
-
startTyping(status?: string): Promise<void>;
|
|
2496
|
-
/**
|
|
2497
|
-
* Fallback streaming implementation using post + edit.
|
|
2498
|
-
* Used when adapter doesn't support native streaming.
|
|
2499
|
-
* Uses recursive setTimeout to send updates every intervalMs (default 500ms).
|
|
2500
|
-
* Schedules next update only after current edit completes to avoid overwhelming slow services.
|
|
2501
|
-
*/
|
|
2502
|
-
private fallbackStream;
|
|
2503
|
-
refresh(): Promise<void>;
|
|
2504
|
-
mentionUser(userId: string): string;
|
|
2505
|
-
/**
|
|
2506
|
-
* Serialize the thread to a plain JSON object.
|
|
2507
|
-
* Use this to pass thread data to external systems like workflow engines.
|
|
2508
|
-
*
|
|
2509
|
-
* @example
|
|
2510
|
-
* ```typescript
|
|
2511
|
-
* // Pass to a workflow
|
|
2512
|
-
* await workflow.start("my-workflow", {
|
|
2513
|
-
* thread: thread.toJSON(),
|
|
2514
|
-
* message: serializeMessage(message),
|
|
2515
|
-
* });
|
|
2516
|
-
* ```
|
|
2517
|
-
*/
|
|
2518
|
-
toJSON(): SerializedThread;
|
|
2519
|
-
/**
|
|
2520
|
-
* Reconstruct a Thread from serialized JSON data.
|
|
2521
|
-
*
|
|
2522
|
-
* Reconstructs a ThreadImpl from serialized data.
|
|
2523
|
-
* Uses lazy resolution from Chat.getSingleton() for adapter and state.
|
|
2524
|
-
*
|
|
2525
|
-
* @param json - Serialized thread data
|
|
2526
|
-
* @requires Call `chat.registerSingleton()` before deserializing threads
|
|
2527
|
-
*
|
|
2528
|
-
* @example
|
|
2529
|
-
* ```typescript
|
|
2530
|
-
* const thread = ThreadImpl.fromJSON(serializedThread);
|
|
2531
|
-
* ```
|
|
2532
|
-
*/
|
|
2533
|
-
static fromJSON<TState = Record<string, unknown>>(json: SerializedThread, adapter?: Adapter): ThreadImpl<TState>;
|
|
2534
|
-
/**
|
|
2535
|
-
* Serialize a ThreadImpl instance for @workflow/serde.
|
|
2536
|
-
* This static method is automatically called by workflow serialization.
|
|
2537
|
-
*/
|
|
2538
|
-
static [WORKFLOW_SERIALIZE](instance: ThreadImpl): SerializedThread;
|
|
2539
|
-
/**
|
|
2540
|
-
* Deserialize a ThreadImpl from @workflow/serde.
|
|
2541
|
-
* Uses lazy adapter resolution from Chat.getSingleton().
|
|
2542
|
-
* Requires chat.registerSingleton() to have been called.
|
|
2543
|
-
*/
|
|
2544
|
-
static [WORKFLOW_DESERIALIZE](data: SerializedThread): ThreadImpl;
|
|
2545
|
-
private createSentMessage;
|
|
2546
|
-
createSentMessageFromMessage(message: Message): SentMessage;
|
|
2547
|
-
}
|
|
2548
|
-
|
|
2549
2696
|
/**
|
|
2550
2697
|
* Get or create an immutable singleton EmojiValue.
|
|
2551
2698
|
*
|
|
@@ -2989,4 +3136,4 @@ declare const Select: SelectComponent;
|
|
|
2989
3136
|
declare const SelectOption: SelectOptionComponent;
|
|
2990
3137
|
declare const TextInput: TextInputComponent;
|
|
2991
3138
|
|
|
2992
|
-
export { type ActionEvent, type ActionHandler, Actions, ActionsComponent, type Adapter, type AdapterPostableMessage, type AiAssistantMessage, type AiFilePart, type AiImagePart, type AiMessage, type AiMessagePart, type AiTextPart, type AiUserMessage, type AppHomeOpenedEvent, type AppHomeOpenedHandler, type AssistantContextChangedEvent, type AssistantContextChangedHandler, type AssistantThreadStartedEvent, type AssistantThreadStartedHandler, type Attachment, type Author, BaseFormatConverter, Button, ButtonComponent, Card, CardChild, CardComponent, CardElement, CardLink, CardLinkComponent, CardText, type Channel, ChannelImpl, type ChannelInfo, Chat, type ChatConfig, ChatElement, ChatError, type ChatInstance, ConsoleLogger, type CustomEmojiMap, DEFAULT_EMOJI_MAP, type DirectMessageHandler, Divider, DividerComponent, type Emoji, type EmojiFormats, type EmojiMapConfig, EmojiResolver, type EmojiValue, type EphemeralMessage, type FetchDirection, type FetchOptions, type FetchResult, Field, FieldComponent, Fields, FieldsComponent, type FileUpload, type FormatConverter, type FormattedContent, Image, ImageComponent, LinkButton, LinkButtonComponent, type LinkPreview, type ListThreadsOptions, type ListThreadsResult, type Lock, LockError, type LogLevel, type Logger, type MarkdownConverter, type MarkdownTextChunk, type MemberJoinedChannelEvent, type MemberJoinedChannelHandler, type MentionHandler, Message, type MessageData, type MessageHandler, MessageHistoryCache, type MessageHistoryConfig, type MessageMetadata, Modal, type ModalCloseEvent, type ModalCloseHandler, type ModalCloseResponse, ModalComponent, ModalElement, type ModalErrorsResponse, type ModalPushResponse, type ModalResponse, type ModalSubmitEvent, type ModalSubmitHandler, type ModalUpdateResponse, NotImplementedError, type PlanUpdateChunk, type PostEphemeralOptions, type Postable, type PostableAst, type PostableCard, type PostableMarkdown, type PostableMessage, type PostableRaw, RadioSelect, RadioSelectComponent, RateLimitError, type RawMessage, type ReactionEvent, type ReactionHandler, type ScheduledMessage, Section, SectionComponent, Select, SelectComponent, SelectOption, SelectOptionComponent, type SentMessage, type SerializedChannel, type SerializedMessage, type SerializedThread, type SlashCommandEvent, type SlashCommandHandler, type StateAdapter, type StreamChunk, type StreamEvent, type StreamOptions, StreamingMarkdownRenderer, type SubscribedMessageHandler, THREAD_STATE_TTL_MS, Table, type TaskUpdateChunk, TextComponent, TextInput, TextInputComponent, type Thread, ThreadImpl, type ThreadInfo, type ThreadSummary, type WebhookOptions, type WellKnownEmoji, blockquote, cardChildToFallbackText, codeBlock, convertEmojiPlaceholders, createEmoji, defaultEmojiResolver, deriveChannelId, emoji, emphasis, fromFullStream, fromReactElement, fromReactModalElement, getEmoji, getNodeChildren, getNodeValue, inlineCode, isBlockquoteNode, isCardElement, isCodeNode, isDeleteNode, isEmphasisNode, isInlineCodeNode, isJSX, isLinkNode, isListItemNode, isListNode, isModalElement, isParagraphNode, isStrongNode, isTableCellNode, isTableNode, isTableRowNode, isTextNode, link, markdownToPlainText, paragraph, parseMarkdown, root, strikethrough, stringifyMarkdown, strong, tableElementToAscii, tableToAscii, text, toAiMessages, toCardElement, toModalElement, toPlainText, walkAst };
|
|
3139
|
+
export { type ActionEvent, type ActionHandler, Actions, ActionsComponent, type Adapter, type AdapterPostableMessage, type AiAssistantMessage, type AiFilePart, type AiImagePart, type AiMessage, type AiMessagePart, type AiTextPart, type AiUserMessage, type AppHomeOpenedEvent, type AppHomeOpenedHandler, type AssistantContextChangedEvent, type AssistantContextChangedHandler, type AssistantThreadStartedEvent, type AssistantThreadStartedHandler, type Attachment, type Author, BaseFormatConverter, Button, ButtonComponent, Card, CardChild, CardComponent, CardElement, CardLink, CardLinkComponent, CardText, type Channel, ChannelImpl, type ChannelInfo, Chat, type ChatConfig, ChatElement, ChatError, type ChatInstance, type ConcurrencyConfig, type ConcurrencyStrategy, ConsoleLogger, type CustomEmojiMap, DEFAULT_EMOJI_MAP, type DirectMessageHandler, Divider, DividerComponent, type Emoji, type EmojiFormats, type EmojiMapConfig, EmojiResolver, type EmojiValue, type EphemeralMessage, type FetchDirection, type FetchOptions, type FetchResult, Field, FieldComponent, Fields, FieldsComponent, type FileUpload, type FormatConverter, type FormattedContent, Image, ImageComponent, LinkButton, LinkButtonComponent, type LinkPreview, type ListThreadsOptions, type ListThreadsResult, type Lock, LockError, type LockScope, type LockScopeContext, type LogLevel, type Logger, type MarkdownConverter, type MarkdownTextChunk, type MemberJoinedChannelEvent, type MemberJoinedChannelHandler, type MentionHandler, Message, type MessageContext, type MessageData, type MessageHandler, MessageHistoryCache, type MessageHistoryConfig, type MessageMetadata, Modal, type ModalCloseEvent, type ModalCloseHandler, type ModalCloseResponse, ModalComponent, ModalElement, type ModalErrorsResponse, type ModalPushResponse, type ModalResponse, type ModalSubmitEvent, type ModalSubmitHandler, type ModalUpdateResponse, NotImplementedError, type PlanUpdateChunk, type PostEphemeralOptions, type Postable, type PostableAst, type PostableCard, type PostableMarkdown, type PostableMessage, type PostableRaw, type QueueEntry, RadioSelect, RadioSelectComponent, RateLimitError, type RawMessage, type ReactionEvent, type ReactionHandler, type ScheduledMessage, Section, SectionComponent, Select, SelectComponent, SelectOption, SelectOptionComponent, type SentMessage, type SerializedChannel, type SerializedMessage, type SerializedThread, type SlashCommandEvent, type SlashCommandHandler, type StateAdapter, type StreamChunk, type StreamEvent, type StreamOptions, StreamingMarkdownRenderer, type SubscribedMessageHandler, THREAD_STATE_TTL_MS, Table, type TaskUpdateChunk, TextComponent, TextInput, TextInputComponent, type Thread, ThreadImpl, type ThreadInfo, type ThreadSummary, type WebhookOptions, type WellKnownEmoji, blockquote, cardChildToFallbackText, codeBlock, convertEmojiPlaceholders, createEmoji, defaultEmojiResolver, deriveChannelId, emoji, emphasis, fromFullStream, fromReactElement, fromReactModalElement, getEmoji, getNodeChildren, getNodeValue, inlineCode, isBlockquoteNode, isCardElement, isCodeNode, isDeleteNode, isEmphasisNode, isInlineCodeNode, isJSX, isLinkNode, isListItemNode, isListNode, isModalElement, isParagraphNode, isStrongNode, isTableCellNode, isTableNode, isTableRowNode, isTextNode, link, markdownToPlainText, paragraph, parseMarkdown, root, strikethrough, stringifyMarkdown, strong, tableElementToAscii, tableToAscii, text, toAiMessages, toCardElement, toModalElement, toPlainText, walkAst };
|