chat 4.20.1 → 4.21.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 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 CardElement, M as ModalElement, a as ChatElement, 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-C2ATKxHQ.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-C2ATKxHQ.js';
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
  */
@@ -149,6 +427,8 @@ interface Adapter<TThreadId = unknown, TRawMessage = unknown> {
149
427
  decodeThreadId(threadId: string): TThreadId;
150
428
  /** Delete a message */
151
429
  deleteMessage(threadId: string, messageId: string): Promise<void>;
430
+ /** Cleanup hook called when Chat instance is shutdown */
431
+ disconnect?(): Promise<void>;
152
432
  /** Edit an existing message */
153
433
  editMessage(threadId: string, messageId: string, message: AdapterPostableMessage): Promise<RawMessage<TRawMessage>>;
154
434
  /** Encode platform-specific data into a thread ID string */
@@ -566,6 +846,11 @@ interface Channel<TState = Record<string, unknown>, TRawMessage = unknown> exten
566
846
  * Empty iterable on threadless platforms.
567
847
  */
568
848
  threads(): AsyncIterable<ThreadSummary<TRawMessage>>;
849
+ /**
850
+ * Serialize the channel to a plain JSON object.
851
+ * Use this to pass channel data to external systems like workflow engines.
852
+ */
853
+ toJSON(): SerializedChannel;
569
854
  }
570
855
  /**
571
856
  * Lightweight summary of a thread within a channel.
@@ -738,6 +1023,11 @@ interface Thread<TState = Record<string, unknown>, TRawMessage = unknown> extend
738
1023
  * ```
739
1024
  */
740
1025
  subscribe(): Promise<void>;
1026
+ /**
1027
+ * Serialize the thread to a plain JSON object.
1028
+ * Use this to pass thread data to external systems like workflow engines.
1029
+ */
1030
+ toJSON(): SerializedThread;
741
1031
  /**
742
1032
  * Unsubscribe from this thread.
743
1033
  *
@@ -1688,161 +1978,55 @@ type AiMessagePart = AiTextPart | AiImagePart | AiFilePart;
1688
1978
  */
1689
1979
  type AiMessage = AiUserMessage | AiAssistantMessage;
1690
1980
  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;
1981
+ content: string | AiMessagePart[];
1982
+ role: "user";
1983
+ }
1984
+ interface AiAssistantMessage {
1985
+ content: string;
1986
+ role: "assistant";
1791
1987
  }
1792
1988
  /**
1793
- * Config for creating a ChannelImpl with lazy adapter resolution.
1989
+ * Options for converting messages to AI SDK format.
1794
1990
  */
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>;
1991
+ interface ToAiMessagesOptions {
1992
+ /** When true, prefixes user messages with "[username]: " for multi-user context */
1993
+ includeNames?: boolean;
1817
1994
  /**
1818
- * Iterate messages newest first (backward from most recent).
1819
- * Uses adapter.fetchChannelMessages if available, otherwise falls back
1820
- * to adapter.fetchMessages with the channel ID.
1995
+ * Called when an attachment type is not supported (video, audio).
1996
+ * Defaults to `console.warn`.
1821
1997
  */
1822
- get messages(): AsyncIterable<Message>;
1998
+ onUnsupportedAttachment?: (attachment: Attachment, message: Message) => void;
1823
1999
  /**
1824
- * Iterate threads in this channel, most recently active first.
2000
+ * Called for each message after default processing (text, links, attachments).
2001
+ * Return the message (modified or as-is) to include it, or `null` to skip it.
2002
+ *
2003
+ * @param aiMessage - The processed AI message
2004
+ * @param source - The original chat Message
2005
+ * @returns The message to include, or null to skip
1825
2006
  */
1826
- threads(): AsyncIterable<ThreadSummary>;
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;
2007
+ transformMessage?: (aiMessage: AiMessage, source: Message) => AiMessage | null | Promise<AiMessage | null>;
1841
2008
  }
1842
2009
  /**
1843
- * Derive the channel ID from a thread ID.
2010
+ * Convert chat SDK messages to AI SDK conversation format.
2011
+ *
2012
+ * - Filters out messages with empty/whitespace-only text
2013
+ * - Maps `author.isMe === true` to `"assistant"`, otherwise `"user"`
2014
+ * - Uses `message.text` for content
2015
+ * - Appends link metadata when available
2016
+ * - Includes image attachments and text files as `FilePart`
2017
+ * - Uses `fetchData()` when available to include attachment data inline (base64)
2018
+ * - Warns on unsupported attachment types (video, audio)
2019
+ *
2020
+ * Works with `FetchResult.messages`, `thread.recentMessages`, or collected iterables.
2021
+ *
2022
+ * @example
2023
+ * ```typescript
2024
+ * const result = await thread.adapter.fetchMessages(thread.id, { limit: 20 });
2025
+ * const history = await toAiMessages(result.messages);
2026
+ * const response = await agent.stream({ prompt: history });
2027
+ * ```
1844
2028
  */
1845
- declare function deriveChannelId(adapter: Adapter, threadId: string): string;
2029
+ declare function toAiMessages(messages: Message[], options?: ToAiMessagesOptions): Promise<AiMessage[]>;
1846
2030
 
1847
2031
  /** Filter can be EmojiValue objects, emoji names, or raw emoji formats */
1848
2032
  type EmojiFilter = EmojiValue | string;
@@ -2374,178 +2558,6 @@ declare class StreamingMarkdownRenderer {
2374
2558
  finish(): string;
2375
2559
  }
2376
2560
 
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
2561
  /**
2550
2562
  * Get or create an immutable singleton EmojiValue.
2551
2563
  *