chat 4.0.2 → 4.1.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
@@ -46,6 +46,11 @@ interface ChatConfig<TAdapters extends Record<string, Adapter> = Record<string,
46
46
  * Pass "silent" to disable all logging.
47
47
  */
48
48
  logger?: Logger | LogLevel;
49
+ /**
50
+ * Update interval for fallback streaming (post + edit) in milliseconds.
51
+ * Defaults to 500ms. Lower values provide smoother updates but may hit rate limits.
52
+ */
53
+ streamingUpdateIntervalMs?: number;
49
54
  }
50
55
  /**
51
56
  * Options for webhook handling.
@@ -84,9 +89,9 @@ interface Adapter<TThreadId = unknown, TRawMessage = unknown> {
84
89
  /** Handle incoming webhook request */
85
90
  handleWebhook(request: Request, options?: WebhookOptions): Promise<Response>;
86
91
  /** Post a message to a thread */
87
- postMessage(threadId: string, message: PostableMessage): Promise<RawMessage<TRawMessage>>;
92
+ postMessage(threadId: string, message: AdapterPostableMessage): Promise<RawMessage<TRawMessage>>;
88
93
  /** Edit an existing message */
89
- editMessage(threadId: string, messageId: string, message: PostableMessage): Promise<RawMessage<TRawMessage>>;
94
+ editMessage(threadId: string, messageId: string, message: AdapterPostableMessage): Promise<RawMessage<TRawMessage>>;
90
95
  /** Delete a message */
91
96
  deleteMessage(threadId: string, messageId: string): Promise<void>;
92
97
  /** Add a reaction to a message */
@@ -133,6 +138,30 @@ interface Adapter<TThreadId = unknown, TRawMessage = unknown> {
133
138
  * @returns True if the thread is a DM, false otherwise
134
139
  */
135
140
  isDM?(threadId: string): boolean;
141
+ /**
142
+ * Stream a message using platform-native streaming APIs.
143
+ *
144
+ * The adapter consumes the async iterable and handles the entire streaming lifecycle.
145
+ * Only available on platforms with native streaming support (e.g., Slack).
146
+ *
147
+ * @param threadId - The thread to stream to
148
+ * @param textStream - Async iterable of text chunks (e.g., from AI SDK)
149
+ * @param options - Platform-specific streaming options
150
+ * @returns The raw message after streaming completes
151
+ */
152
+ stream?(threadId: string, textStream: AsyncIterable<string>, options?: StreamOptions): Promise<RawMessage<TRawMessage>>;
153
+ }
154
+ /**
155
+ * Options for streaming messages.
156
+ * Platform-specific options are passed through to the adapter.
157
+ */
158
+ interface StreamOptions {
159
+ /** Slack: The user ID to stream to (for AI assistant context) */
160
+ recipientUserId?: string;
161
+ /** Slack: The team/workspace ID */
162
+ recipientTeamId?: string;
163
+ /** Minimum interval between updates in ms (default: 1000). Used for fallback mode (GChat/Teams). */
164
+ updateIntervalMs?: number;
136
165
  }
137
166
  /** Internal interface for Chat instance passed to adapters */
138
167
  interface ChatInstance {
@@ -206,7 +235,14 @@ interface Lock {
206
235
  token: string;
207
236
  expiresAt: number;
208
237
  }
209
- interface Thread<TRawMessage = unknown> {
238
+ /** Default TTL for thread state (30 days in milliseconds) */
239
+ declare const THREAD_STATE_TTL_MS: number;
240
+ /**
241
+ * Thread interface with support for custom state.
242
+ * @template TState - Custom state type stored per-thread (default: Record<string, unknown>)
243
+ * @template TRawMessage - Platform-specific raw message type
244
+ */
245
+ interface Thread<TState = Record<string, unknown>, TRawMessage = unknown> {
210
246
  /** Unique thread ID (format: "adapter:channel:thread") */
211
247
  readonly id: string;
212
248
  /** The adapter this thread belongs to */
@@ -215,6 +251,38 @@ interface Thread<TRawMessage = unknown> {
215
251
  readonly channelId: string;
216
252
  /** Whether this is a direct message conversation */
217
253
  readonly isDM: boolean;
254
+ /**
255
+ * Get the current thread state.
256
+ * Returns null if no state has been set.
257
+ *
258
+ * @example
259
+ * ```typescript
260
+ * const state = await thread.state;
261
+ * if (state?.aiMode) {
262
+ * // AI mode is enabled
263
+ * }
264
+ * ```
265
+ */
266
+ readonly state: Promise<TState | null>;
267
+ /**
268
+ * Set the thread state. Merges with existing state by default.
269
+ * State is persisted for 30 days.
270
+ *
271
+ * @param state - Partial state to merge, or full state if replace is true
272
+ * @param options - Options for setting state
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * // Merge with existing state
277
+ * await thread.setState({ aiMode: true });
278
+ *
279
+ * // Replace entire state
280
+ * await thread.setState({ aiMode: true }, { replace: true });
281
+ * ```
282
+ */
283
+ setState(state: Partial<TState>, options?: {
284
+ replace?: boolean;
285
+ }): Promise<void>;
218
286
  /** Recently fetched messages (cached) */
219
287
  recentMessages: Message<TRawMessage>[];
220
288
  /** Async iterator for all messages in the thread */
@@ -252,7 +320,11 @@ interface Thread<TRawMessage = unknown> {
252
320
  /**
253
321
  * Post a message to this thread.
254
322
  *
255
- * @param message - String, PostableMessage, or JSX Card element to send
323
+ * Supports text, markdown, cards, and streaming from async iterables.
324
+ * When posting a stream (e.g., from AI SDK), uses platform-native streaming
325
+ * APIs when available (Slack), or falls back to post + edit with throttling.
326
+ *
327
+ * @param message - String, PostableMessage, JSX Card, or AsyncIterable<string>
256
328
  * @returns A SentMessage with methods to edit, delete, or add reactions
257
329
  *
258
330
  * @example
@@ -266,12 +338,16 @@ interface Thread<TRawMessage = unknown> {
266
338
  * // With emoji
267
339
  * await thread.post(`${emoji.thumbs_up} Great job!`);
268
340
  *
269
- * // JSX Card (with @jsxImportSource chat-sdk)
341
+ * // JSX Card (with @jsxImportSource chat)
270
342
  * await thread.post(
271
343
  * <Card title="Welcome!">
272
344
  * <Text>Hello world</Text>
273
345
  * </Card>
274
346
  * );
347
+ *
348
+ * // Stream from AI SDK
349
+ * const result = await agent.stream({ prompt: message.text });
350
+ * await thread.post(result.textStream);
275
351
  * ```
276
352
  */
277
353
  post(message: string | PostableMessage | CardJSXElement): Promise<SentMessage<TRawMessage>>;
@@ -392,6 +468,11 @@ interface SentMessage<TRawMessage = unknown> extends Message<TRawMessage> {
392
468
  /** Remove a reaction from this message */
393
469
  removeReaction(emoji: EmojiValue | string): Promise<void>;
394
470
  }
471
+ /**
472
+ * Input type for adapter postMessage/editMessage methods.
473
+ * This excludes streams since adapters handle content synchronously.
474
+ */
475
+ type AdapterPostableMessage = string | PostableRaw | PostableMarkdown | PostableAst | PostableCard | CardElement;
395
476
  /**
396
477
  * A message that can be posted to a thread.
397
478
  *
@@ -401,8 +482,9 @@ interface SentMessage<TRawMessage = unknown> extends Message<TRawMessage> {
401
482
  * - `{ ast: Root }` - mdast AST, converted to platform format
402
483
  * - `{ card: CardElement }` - Rich card with buttons (Block Kit / Adaptive Cards / GChat Cards)
403
484
  * - `CardElement` - Direct card element
485
+ * - `AsyncIterable<string>` - Streaming text (e.g., from AI SDK's textStream)
404
486
  */
405
- type PostableMessage = string | PostableRaw | PostableMarkdown | PostableAst | PostableCard | CardElement;
487
+ type PostableMessage = AdapterPostableMessage | AsyncIterable<string>;
406
488
  interface PostableRaw {
407
489
  /** Raw text passed through as-is to the platform */
408
490
  raw: string;
@@ -496,14 +578,14 @@ interface FileUpload {
496
578
  * });
497
579
  * ```
498
580
  */
499
- type MentionHandler = (thread: Thread, message: Message) => Promise<void>;
581
+ type MentionHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message) => Promise<void>;
500
582
  /**
501
583
  * Handler for messages matching a regex pattern.
502
584
  *
503
585
  * Registered via `chat.onNewMessage(pattern, handler)`. Called when a message
504
586
  * matches the pattern in an unsubscribed thread.
505
587
  */
506
- type MessageHandler = (thread: Thread, message: Message) => Promise<void>;
588
+ type MessageHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message) => Promise<void>;
507
589
  /**
508
590
  * Handler for messages in subscribed threads.
509
591
  *
@@ -527,7 +609,7 @@ type MessageHandler = (thread: Thread, message: Message) => Promise<void>;
527
609
  * });
528
610
  * ```
529
611
  */
530
- type SubscribedMessageHandler = (thread: Thread, message: Message) => Promise<void>;
612
+ type SubscribedMessageHandler<TState = Record<string, unknown>> = (thread: Thread<TState>, message: Message) => Promise<void>;
531
613
  /**
532
614
  * Well-known emoji that work across platforms (Slack and Google Chat).
533
615
  * These are normalized to a common format regardless of platform.
@@ -728,10 +810,19 @@ type Webhooks<TAdapters extends Record<string, Adapter>> = {
728
810
  [K in keyof TAdapters]: WebhookHandler;
729
811
  };
730
812
  /**
731
- * Main Chat class with type-safe adapter inference.
813
+ * Main Chat class with type-safe adapter inference and custom thread state.
814
+ *
815
+ * @template TAdapters - Map of adapter names to Adapter instances
816
+ * @template TState - Custom state type stored per-thread (default: Record<string, unknown>)
732
817
  *
733
818
  * @example
734
- * const chat = new Chat({
819
+ * // Define custom thread state type
820
+ * interface MyThreadState {
821
+ * aiMode?: boolean;
822
+ * userName?: string;
823
+ * }
824
+ *
825
+ * const chat = new Chat<typeof adapters, MyThreadState>({
735
826
  * userName: "mybot",
736
827
  * adapters: {
737
828
  * slack: createSlackAdapter({ ... }),
@@ -740,14 +831,18 @@ type Webhooks<TAdapters extends Record<string, Adapter>> = {
740
831
  * state: createMemoryState(),
741
832
  * });
742
833
  *
743
- * // Type-safe: only 'slack' and 'teams' are valid
744
- * chat.webhooks.slack(request, { waitUntil });
834
+ * // Type-safe thread state
835
+ * chat.onNewMention(async (thread, message) => {
836
+ * await thread.setState({ aiMode: true });
837
+ * const state = await thread.state; // Type: MyThreadState | null
838
+ * });
745
839
  */
746
- declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Adapter>> implements ChatInstance {
840
+ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Adapter>, TState = Record<string, unknown>> implements ChatInstance {
747
841
  private adapters;
748
- private state;
842
+ private _stateAdapter;
749
843
  private userName;
750
844
  private logger;
845
+ private _streamingUpdateIntervalMs;
751
846
  private mentionHandlers;
752
847
  private messagePatterns;
753
848
  private subscribedMessageHandlers;
@@ -804,7 +899,7 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
804
899
  * });
805
900
  * ```
806
901
  */
807
- onNewMention(handler: MentionHandler): void;
902
+ onNewMention(handler: MentionHandler<TState>): void;
808
903
  /**
809
904
  * Register a handler for messages matching a regex pattern.
810
905
  *
@@ -819,7 +914,7 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
819
914
  * });
820
915
  * ```
821
916
  */
822
- onNewMessage(pattern: RegExp, handler: MessageHandler): void;
917
+ onNewMessage(pattern: RegExp, handler: MessageHandler<TState>): void;
823
918
  /**
824
919
  * Register a handler for messages in subscribed threads.
825
920
  *
@@ -843,7 +938,7 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
843
938
  * });
844
939
  * ```
845
940
  */
846
- onSubscribedMessage(handler: SubscribedMessageHandler): void;
941
+ onSubscribedMessage(handler: SubscribedMessageHandler<TState>): void;
847
942
  /**
848
943
  * Register a handler for reaction events.
849
944
  *
@@ -959,7 +1054,7 @@ declare class Chat<TAdapters extends Record<string, Adapter> = Record<string, Ad
959
1054
  * });
960
1055
  * ```
961
1056
  */
962
- openDM(user: string | Author): Promise<Thread>;
1057
+ openDM(user: string | Author): Promise<Thread<TState>>;
963
1058
  /**
964
1059
  * Infer which adapter to use based on the userId format.
965
1060
  */
@@ -1150,6 +1245,8 @@ declare const emoji: ExtendedEmojiHelper;
1150
1245
  * Markdown parsing and conversion utilities using unified/remark.
1151
1246
  */
1152
1247
 
1248
+ type PostableMessageInput = AdapterPostableMessage;
1249
+
1153
1250
  /**
1154
1251
  * Parse markdown string into an AST.
1155
1252
  * Supports GFM (GitHub Flavored Markdown) for strikethrough, tables, etc.
@@ -1281,19 +1378,6 @@ declare abstract class BaseFormatConverter implements FormatConverter {
1281
1378
  */
1282
1379
  protected cardChildToFallbackText(child: CardChild): string | null;
1283
1380
  }
1284
- /**
1285
- * Type for PostableMessage input (for rendering to text)
1286
- */
1287
- type PostableMessageInput = string | {
1288
- raw: string;
1289
- } | {
1290
- markdown: string;
1291
- } | {
1292
- ast: Root;
1293
- } | {
1294
- card: CardElement;
1295
- fallbackText?: string;
1296
- } | CardElement;
1297
1381
 
1298
1382
  declare const Actions: typeof Actions$1;
1299
1383
  declare const Button: typeof Button$1;
@@ -1309,4 +1393,4 @@ declare const isJSX: typeof isJSX$1;
1309
1393
  declare const Section: typeof Section$1;
1310
1394
  declare const toCardElement: typeof toCardElement$1;
1311
1395
 
1312
- export { type ActionEvent, type ActionHandler, Actions, type Adapter, type Attachment, type Author, BaseFormatConverter, Button, Card, CardChild, CardElement, CardJSXElement, CardText, Chat, type ChatConfig, ChatError, type ChatInstance, ConsoleLogger, type CustomEmojiMap, DEFAULT_EMOJI_MAP, Divider, type Emoji, type EmojiFormats, type EmojiMapConfig, EmojiResolver, type EmojiValue, type FetchOptions, Field, Fields, type FileUpload, type FormatConverter, type FormattedContent, Image, type Lock, LockError, type LogLevel, type Logger, type MarkdownConverter, type MentionHandler, type Message, type MessageHandler, type MessageMetadata, NotImplementedError, type PostableAst, type PostableCard, type PostableMarkdown, type PostableMessage, type PostableRaw, RateLimitError, type RawMessage, type ReactionEvent, type ReactionHandler, Section, type SentMessage, type StateAdapter, type SubscribedMessageHandler, type Thread, type ThreadInfo, type WebhookOptions, type WellKnownEmoji, blockquote, codeBlock, convertEmojiPlaceholders, createEmoji, defaultEmojiResolver, emoji, emphasis, fromReactElement, getEmoji, inlineCode, isCardElement, isJSX, link, markdownToPlainText, paragraph, parseMarkdown, root, strikethrough, stringifyMarkdown, strong, text, toCardElement, toPlainText, walkAst };
1396
+ export { type ActionEvent, type ActionHandler, Actions, type Adapter, type AdapterPostableMessage, type Attachment, type Author, BaseFormatConverter, Button, Card, CardChild, CardElement, CardJSXElement, CardText, Chat, type ChatConfig, ChatError, type ChatInstance, ConsoleLogger, type CustomEmojiMap, DEFAULT_EMOJI_MAP, Divider, type Emoji, type EmojiFormats, type EmojiMapConfig, EmojiResolver, type EmojiValue, type FetchOptions, Field, Fields, type FileUpload, type FormatConverter, type FormattedContent, Image, type Lock, LockError, type LogLevel, type Logger, type MarkdownConverter, type MentionHandler, type Message, type MessageHandler, type MessageMetadata, NotImplementedError, type PostableAst, type PostableCard, type PostableMarkdown, type PostableMessage, type PostableRaw, RateLimitError, type RawMessage, type ReactionEvent, type ReactionHandler, Section, type SentMessage, type StateAdapter, type StreamOptions, type SubscribedMessageHandler, THREAD_STATE_TTL_MS, type Thread, type ThreadInfo, type WebhookOptions, type WellKnownEmoji, blockquote, codeBlock, convertEmojiPlaceholders, createEmoji, defaultEmojiResolver, emoji, emphasis, fromReactElement, getEmoji, inlineCode, isCardElement, isJSX, link, markdownToPlainText, paragraph, parseMarkdown, root, strikethrough, stringifyMarkdown, strong, text, toCardElement, toPlainText, walkAst };