chat 4.26.0 → 4.27.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.
Files changed (31) hide show
  1. package/dist/{chunk-OPV5U4WG.js → chunk-AN7MRAVW.js} +39 -0
  2. package/dist/index.d.ts +220 -6
  3. package/dist/index.js +321 -50
  4. package/dist/{jsx-runtime-DxATbnrP.d.ts → jsx-runtime-Co9uV6l7.d.ts} +39 -5
  5. package/dist/jsx-runtime.d.ts +1 -1
  6. package/dist/jsx-runtime.js +1 -1
  7. package/docs/adapters.mdx +28 -28
  8. package/docs/api/chat.mdx +85 -1
  9. package/docs/api/message.mdx +5 -1
  10. package/docs/api/thread.mdx +23 -1
  11. package/docs/contributing/publishing.mdx +33 -0
  12. package/docs/files.mdx +1 -0
  13. package/docs/getting-started.mdx +1 -11
  14. package/docs/meta.json +0 -2
  15. package/docs/modals.mdx +73 -1
  16. package/docs/streaming.mdx +13 -5
  17. package/docs/threads-messages-channels.mdx +34 -0
  18. package/package.json +3 -2
  19. package/resources/guides/create-a-discord-support-bot-with-nuxt-and-redis.md +180 -0
  20. package/resources/guides/how-to-build-a-slack-bot-with-next-js-and-redis.md +134 -0
  21. package/resources/guides/how-to-build-an-ai-agent-for-slack-with-chat-sdk-and-ai-sdk.md +220 -0
  22. package/resources/guides/run-and-track-deploys-from-slack.md +270 -0
  23. package/resources/guides/ship-a-github-code-review-bot-with-hono-and-redis.md +147 -0
  24. package/resources/guides/triage-form-submissions-with-chat-sdk.md +178 -0
  25. package/resources/templates.json +19 -0
  26. package/docs/guides/code-review-hono.mdx +0 -241
  27. package/docs/guides/discord-nuxt.mdx +0 -227
  28. package/docs/guides/durable-chat-sessions-nextjs.mdx +0 -337
  29. package/docs/guides/meta.json +0 -10
  30. package/docs/guides/scheduled-posts-neon.mdx +0 -447
  31. package/docs/guides/slack-nextjs.mdx +0 -234
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  CardLink,
7
7
  CardText,
8
8
  Divider,
9
+ ExternalSelect,
9
10
  Field,
10
11
  Fields,
11
12
  Image,
@@ -59,7 +60,7 @@ import {
59
60
  toModalElement,
60
61
  toPlainText,
61
62
  walkAst
62
- } from "./chunk-OPV5U4WG.js";
63
+ } from "./chunk-AN7MRAVW.js";
63
64
 
64
65
  // src/ai.ts
65
66
  var TEXT_MIME_PREFIXES = [
@@ -330,7 +331,8 @@ var Message = class _Message {
330
331
  mimeType: att.mimeType,
331
332
  size: att.size,
332
333
  width: att.width,
333
- height: att.height
334
+ height: att.height,
335
+ fetchMetadata: att.fetchMetadata
334
336
  })),
335
337
  isMention: this.isMention,
336
338
  links: this.links.length > 0 ? this.links.map((link2) => ({
@@ -1338,6 +1340,19 @@ var ThreadImpl = class _ThreadImpl {
1338
1340
  }
1339
1341
  };
1340
1342
  }
1343
+ async getParticipants() {
1344
+ const seen = /* @__PURE__ */ new Map();
1345
+ if (this._currentMessage && !this._currentMessage.author.isMe && !this._currentMessage.author.isBot) {
1346
+ seen.set(this._currentMessage.author.userId, this._currentMessage.author);
1347
+ }
1348
+ for await (const message of this.allMessages) {
1349
+ if (message.author.isMe || message.author.isBot || seen.has(message.author.userId)) {
1350
+ continue;
1351
+ }
1352
+ seen.set(message.author.userId, message.author);
1353
+ }
1354
+ return [...seen.values()];
1355
+ }
1341
1356
  async isSubscribed() {
1342
1357
  if (this._isSubscribedContext) {
1343
1358
  return true;
@@ -1355,6 +1370,16 @@ var ThreadImpl = class _ThreadImpl {
1355
1370
  }
1356
1371
  async post(message) {
1357
1372
  if (isPostableObject(message)) {
1373
+ if (message.kind === "stream") {
1374
+ const data = message.getPostData();
1375
+ const streamOptions = {
1376
+ ...data.options.updateIntervalMs ? { updateIntervalMs: data.options.updateIntervalMs } : {},
1377
+ ...data.options.groupTasks ? { taskDisplayMode: data.options.groupTasks } : {},
1378
+ ...data.options.endWith ? { stopBlocks: data.options.endWith } : {}
1379
+ };
1380
+ await this.handleStream(data.stream, streamOptions);
1381
+ return message;
1382
+ }
1358
1383
  await this.handlePostableObject(message);
1359
1384
  return message;
1360
1385
  }
@@ -1444,13 +1469,14 @@ var ThreadImpl = class _ThreadImpl {
1444
1469
  * Normalizes the stream (supports both textStream and fullStream from AI SDK),
1445
1470
  * then uses adapter's native streaming if available, otherwise falls back to post+edit.
1446
1471
  */
1447
- async handleStream(rawStream) {
1472
+ async handleStream(rawStream, callerOptions) {
1448
1473
  const textStream = fromFullStream(rawStream);
1449
- const options = {};
1474
+ const options = { ...callerOptions };
1450
1475
  if (this._currentMessage) {
1451
1476
  options.recipientUserId = this._currentMessage.author.userId;
1452
- const raw = this._currentMessage.raw;
1453
- options.recipientTeamId = raw?.team_id ?? raw?.team;
1477
+ options.recipientTeamId = this.extractSlackRecipientTeamId(
1478
+ this._currentMessage.raw
1479
+ );
1454
1480
  }
1455
1481
  if (this.adapter.stream) {
1456
1482
  let accumulated = "";
@@ -1508,6 +1534,31 @@ var ThreadImpl = class _ThreadImpl {
1508
1534
  };
1509
1535
  return this.fallbackStream(textOnlyStream, options);
1510
1536
  }
1537
+ /**
1538
+ * Slack payloads carry the workspace ID in a few different shapes depending on
1539
+ * the webhook type:
1540
+ * - Message events: `team_id` or `team` as a string
1541
+ * - `block_actions` payloads: `team.id` (object), with `user.team_id` as a fallback
1542
+ */
1543
+ extractSlackRecipientTeamId(raw) {
1544
+ if (!raw || typeof raw !== "object") {
1545
+ return void 0;
1546
+ }
1547
+ const payload = raw;
1548
+ if (typeof payload.team_id === "string" && payload.team_id) {
1549
+ return payload.team_id;
1550
+ }
1551
+ if (typeof payload.team === "string" && payload.team) {
1552
+ return payload.team;
1553
+ }
1554
+ if (payload.team && typeof payload.team === "object" && typeof payload.team.id === "string" && payload.team.id) {
1555
+ return payload.team.id;
1556
+ }
1557
+ if (typeof payload.user?.team_id === "string" && payload.user.team_id) {
1558
+ return payload.user.team_id;
1559
+ }
1560
+ return void 0;
1561
+ }
1511
1562
  async startTyping(status) {
1512
1563
  await this.adapter.startTyping(this.id, status);
1513
1564
  }
@@ -1856,8 +1907,10 @@ var DEFAULT_LOCK_TTL_MS = 3e4;
1856
1907
  function sleep(ms) {
1857
1908
  return new Promise((resolve) => setTimeout(resolve, ms));
1858
1909
  }
1859
- var SLACK_USER_ID_REGEX = /^U[A-Z0-9]+$/i;
1910
+ var SLACK_USER_ID_REGEX = /^[UW][A-Z0-9]+$/;
1860
1911
  var DISCORD_SNOWFLAKE_REGEX = /^\d{17,19}$/;
1912
+ var LINEAR_UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1913
+ var NUMERIC_REGEX = /^\d+$/;
1861
1914
  var DEDUPE_TTL_MS = 5 * 60 * 1e3;
1862
1915
  var MODAL_CONTEXT_TTL_MS = 24 * 60 * 60 * 1e3;
1863
1916
  var Chat = class {
@@ -1902,6 +1955,7 @@ var Chat = class {
1902
1955
  _messageHistory;
1903
1956
  _concurrencyStrategy;
1904
1957
  _concurrencyConfig;
1958
+ _concurrentSlots = /* @__PURE__ */ new Map();
1905
1959
  _lockScope;
1906
1960
  mentionHandlers = [];
1907
1961
  directMessageHandlers = [];
@@ -1909,6 +1963,7 @@ var Chat = class {
1909
1963
  subscribedMessageHandlers = [];
1910
1964
  reactionHandlers = [];
1911
1965
  actionHandlers = [];
1966
+ optionsLoadHandlers = [];
1912
1967
  modalSubmitHandlers = [];
1913
1968
  modalCloseHandlers = [];
1914
1969
  slashCommandHandlers = [];
@@ -1934,6 +1989,11 @@ var Chat = class {
1934
1989
  this._dedupeTtlMs = config.dedupeTtlMs ?? DEDUPE_TTL_MS;
1935
1990
  this._onLockConflict = config.onLockConflict;
1936
1991
  this._lockScope = config.lockScope;
1992
+ if (typeof config.logger === "string") {
1993
+ this.logger = new ConsoleLogger(config.logger);
1994
+ } else {
1995
+ this.logger = config.logger || new ConsoleLogger("info");
1996
+ }
1937
1997
  const concurrency = config.concurrency;
1938
1998
  if (concurrency) {
1939
1999
  if (typeof concurrency === "string") {
@@ -1946,6 +2006,16 @@ var Chat = class {
1946
2006
  queueEntryTtlMs: 9e4
1947
2007
  };
1948
2008
  } else {
2009
+ if (concurrency.maxConcurrent !== void 0 && concurrency.maxConcurrent < 1) {
2010
+ throw new Error(
2011
+ `concurrency.maxConcurrent must be >= 1 (got ${concurrency.maxConcurrent})`
2012
+ );
2013
+ }
2014
+ if (concurrency.maxConcurrent !== void 0 && concurrency.strategy !== "concurrent") {
2015
+ this.logger.warn(
2016
+ `concurrency.maxConcurrent has no effect when strategy is "${concurrency.strategy}" \u2014 it only applies to the "concurrent" strategy.`
2017
+ );
2018
+ }
1949
2019
  this._concurrencyStrategy = concurrency.strategy;
1950
2020
  this._concurrencyConfig = {
1951
2021
  debounceMs: concurrency.debounceMs ?? 1500,
@@ -1969,11 +2039,6 @@ var Chat = class {
1969
2039
  this._stateAdapter,
1970
2040
  config.messageHistory
1971
2041
  );
1972
- if (typeof config.logger === "string") {
1973
- this.logger = new ConsoleLogger(config.logger);
1974
- } else {
1975
- this.logger = config.logger || new ConsoleLogger("info");
1976
- }
1977
2042
  const webhooks = {};
1978
2043
  for (const [name, adapter] of Object.entries(config.adapters)) {
1979
2044
  this.adapters.set(name, adapter);
@@ -2180,6 +2245,19 @@ var Chat = class {
2180
2245
  this.logger.debug("Registered action handler", { actionIds });
2181
2246
  }
2182
2247
  }
2248
+ onOptionsLoad(actionIdOrHandler, handler) {
2249
+ if (typeof actionIdOrHandler === "function") {
2250
+ this.optionsLoadHandlers.push({
2251
+ actionIds: [],
2252
+ handler: actionIdOrHandler
2253
+ });
2254
+ this.logger.debug("Registered options load handler for all action IDs");
2255
+ } else if (handler) {
2256
+ const actionIds = Array.isArray(actionIdOrHandler) ? actionIdOrHandler : [actionIdOrHandler];
2257
+ this.optionsLoadHandlers.push({ actionIds, handler });
2258
+ this.logger.debug("Registered options load handler", { actionIds });
2259
+ }
2260
+ }
2183
2261
  onModalSubmit(callbackIdOrHandler, handler) {
2184
2262
  if (typeof callbackIdOrHandler === "function") {
2185
2263
  this.modalSubmitHandlers.push({
@@ -2319,6 +2397,29 @@ var Chat = class {
2319
2397
  }
2320
2398
  return task;
2321
2399
  }
2400
+ async processOptionsLoad(event, _options) {
2401
+ const matchingHandlers = [
2402
+ ...this.optionsLoadHandlers.filter(
2403
+ ({ actionIds }) => actionIds.length > 0 && actionIds.includes(event.actionId)
2404
+ ),
2405
+ ...this.optionsLoadHandlers.filter(
2406
+ ({ actionIds }) => actionIds.length === 0
2407
+ )
2408
+ ];
2409
+ for (const { handler } of matchingHandlers) {
2410
+ try {
2411
+ const options = await handler(event);
2412
+ if (options) {
2413
+ return options;
2414
+ }
2415
+ } catch (err) {
2416
+ this.logger.error("Options load handler error", {
2417
+ error: err,
2418
+ actionId: event.actionId
2419
+ });
2420
+ }
2421
+ }
2422
+ }
2322
2423
  async processModalSubmit(event, contextId, _options) {
2323
2424
  const { relatedThread, relatedMessage, relatedChannel } = await this.retrieveModalContext(event.adapter.name, contextId);
2324
2425
  const fullEvent = {
@@ -2818,6 +2919,33 @@ var Chat = class {
2818
2919
  const threadId = await adapter.openDM(userId);
2819
2920
  return this.createThread(adapter, threadId, {}, false);
2820
2921
  }
2922
+ /**
2923
+ * Look up user information by user ID.
2924
+ *
2925
+ * The adapter is automatically inferred from the user ID format.
2926
+ * Returns user details including email (where available — requires
2927
+ * appropriate scopes on some platforms, e.g. `users:read.email` on Slack).
2928
+ *
2929
+ * @param user - Platform-specific user ID string, or an Author object
2930
+ * @returns User info, or null if user not found
2931
+ *
2932
+ * @example
2933
+ * ```typescript
2934
+ * const user = await chat.getUser("U123456");
2935
+ * console.log(user?.email); // "alice@company.com"
2936
+ * ```
2937
+ */
2938
+ async getUser(user) {
2939
+ const userId = typeof user === "string" ? user : user.userId;
2940
+ const adapter = this.inferAdapterFromUserId(userId);
2941
+ if (!adapter.getUser) {
2942
+ throw new ChatError(
2943
+ `Adapter "${adapter.name}" does not support getUser`,
2944
+ "NOT_SUPPORTED"
2945
+ );
2946
+ }
2947
+ return adapter.getUser(userId);
2948
+ }
2821
2949
  /**
2822
2950
  * Get a Channel by its channel ID.
2823
2951
  *
@@ -2865,6 +2993,37 @@ var Chat = class {
2865
2993
  stateAdapter: this._stateAdapter
2866
2994
  });
2867
2995
  }
2996
+ /**
2997
+ * Get a Thread handle by its thread ID.
2998
+ *
2999
+ * The adapter is automatically inferred from the thread ID prefix.
3000
+ *
3001
+ * @param threadId - Full thread ID (e.g., "slack:C123ABC:1234567890.123456")
3002
+ * @returns A Thread that can be used to post messages, subscribe, etc.
3003
+ *
3004
+ * @example
3005
+ * ```typescript
3006
+ * const thread = chat.thread("slack:C123ABC:1234567890.123456");
3007
+ * await thread.post("Hello from outside a webhook!");
3008
+ * ```
3009
+ */
3010
+ thread(threadId) {
3011
+ const adapterName = threadId.split(":")[0];
3012
+ if (!adapterName) {
3013
+ throw new ChatError(
3014
+ `Invalid thread ID: ${threadId}`,
3015
+ "INVALID_THREAD_ID"
3016
+ );
3017
+ }
3018
+ const adapter = this.adapters.get(adapterName);
3019
+ if (!adapter) {
3020
+ throw new ChatError(
3021
+ `Adapter "${adapterName}" not found for thread ID "${threadId}"`,
3022
+ "ADAPTER_NOT_FOUND"
3023
+ );
3024
+ }
3025
+ return this.createThread(adapter, threadId, {}, false);
3026
+ }
2868
3027
  /**
2869
3028
  * Infer which adapter to use based on the userId format.
2870
3029
  */
@@ -2881,20 +3040,44 @@ var Chat = class {
2881
3040
  return adapter;
2882
3041
  }
2883
3042
  }
2884
- if (SLACK_USER_ID_REGEX.test(userId)) {
2885
- const adapter = this.adapters.get("slack");
3043
+ if (LINEAR_UUID_REGEX.test(userId)) {
3044
+ const adapter = this.adapters.get("linear");
2886
3045
  if (adapter) {
2887
3046
  return adapter;
2888
3047
  }
2889
3048
  }
2890
- if (DISCORD_SNOWFLAKE_REGEX.test(userId)) {
2891
- const adapter = this.adapters.get("discord");
3049
+ if (SLACK_USER_ID_REGEX.test(userId)) {
3050
+ const adapter = this.adapters.get("slack");
2892
3051
  if (adapter) {
2893
3052
  return adapter;
2894
3053
  }
2895
3054
  }
3055
+ if (NUMERIC_REGEX.test(userId)) {
3056
+ const candidates = [];
3057
+ if (DISCORD_SNOWFLAKE_REGEX.test(userId) && this.adapters.has("discord")) {
3058
+ candidates.push("discord");
3059
+ }
3060
+ if (this.adapters.has("telegram")) {
3061
+ candidates.push("telegram");
3062
+ }
3063
+ if (this.adapters.has("github")) {
3064
+ candidates.push("github");
3065
+ }
3066
+ if (candidates.length === 1) {
3067
+ const adapter = this.adapters.get(candidates[0]);
3068
+ if (adapter) {
3069
+ return adapter;
3070
+ }
3071
+ }
3072
+ if (candidates.length > 1) {
3073
+ throw new ChatError(
3074
+ `Numeric userId "${userId}" is ambiguous between adapters: ${candidates.join(", ")}. Call the platform's adapter directly (e.g. \`adapter.getUser(userId)\`).`,
3075
+ "AMBIGUOUS_USER_ID"
3076
+ );
3077
+ }
3078
+ }
2896
3079
  throw new ChatError(
2897
- `Cannot infer adapter from userId "${userId}". Expected format: Slack (U...), Teams (29:...), Google Chat (users/...), or Discord (numeric snowflake).`,
3080
+ `Cannot infer adapter from userId "${userId}". Expected: Slack ("U..."), Teams ("29:..."), Google Chat ("users/..."), Linear (UUID), or Discord/Telegram/GitHub (numeric).`,
2898
3081
  "UNKNOWN_USER_ID_FORMAT"
2899
3082
  );
2900
3083
  }
@@ -3116,7 +3299,7 @@ var Chat = class {
3116
3299
  if (!entry) {
3117
3300
  break;
3118
3301
  }
3119
- const msg = this.rehydrateMessage(entry.message);
3302
+ const msg = this.rehydrateMessage(entry.message, adapter);
3120
3303
  if (Date.now() > entry.expiresAt) {
3121
3304
  this.logger.info("message-expired", {
3122
3305
  threadId,
@@ -3155,7 +3338,7 @@ var Chat = class {
3155
3338
  if (!entry) {
3156
3339
  break;
3157
3340
  }
3158
- const msg = this.rehydrateMessage(entry.message);
3341
+ const msg = this.rehydrateMessage(entry.message, adapter);
3159
3342
  if (Date.now() <= entry.expiresAt) {
3160
3343
  pending.push({ message: msg, expiresAt: entry.expiresAt });
3161
3344
  } else {
@@ -3190,10 +3373,50 @@ var Chat = class {
3190
3373
  }
3191
3374
  }
3192
3375
  /**
3193
- * Concurrent strategy: no locking, process immediately.
3376
+ * Concurrent strategy: no locking, process immediately — but cap
3377
+ * simultaneous handlers per thread at `maxConcurrent` (default Infinity).
3194
3378
  */
3195
3379
  async handleConcurrent(adapter, threadId, message) {
3196
- await this.dispatchToHandlers(adapter, threadId, message);
3380
+ const { maxConcurrent } = this._concurrencyConfig;
3381
+ if (!Number.isFinite(maxConcurrent)) {
3382
+ await this.dispatchToHandlers(adapter, threadId, message);
3383
+ return;
3384
+ }
3385
+ await this.acquireConcurrentSlot(threadId, maxConcurrent);
3386
+ try {
3387
+ await this.dispatchToHandlers(adapter, threadId, message);
3388
+ } finally {
3389
+ this.releaseConcurrentSlot(threadId);
3390
+ }
3391
+ }
3392
+ acquireConcurrentSlot(threadId, maxConcurrent) {
3393
+ let slot = this._concurrentSlots.get(threadId);
3394
+ if (!slot) {
3395
+ slot = { inFlight: 0, waiters: [] };
3396
+ this._concurrentSlots.set(threadId, slot);
3397
+ }
3398
+ if (slot.inFlight < maxConcurrent) {
3399
+ slot.inFlight++;
3400
+ return Promise.resolve();
3401
+ }
3402
+ return new Promise((resolve) => {
3403
+ slot.waiters.push(resolve);
3404
+ });
3405
+ }
3406
+ releaseConcurrentSlot(threadId) {
3407
+ const slot = this._concurrentSlots.get(threadId);
3408
+ if (!slot) {
3409
+ return;
3410
+ }
3411
+ const next = slot.waiters.shift();
3412
+ if (next) {
3413
+ next();
3414
+ return;
3415
+ }
3416
+ slot.inFlight--;
3417
+ if (slot.inFlight === 0 && slot.waiters.length === 0) {
3418
+ this._concurrentSlots.delete(threadId);
3419
+ }
3197
3420
  }
3198
3421
  /**
3199
3422
  * Dispatch a message to the appropriate handler chain based on
@@ -3338,35 +3561,44 @@ var Chat = class {
3338
3561
  * object (not a Message instance). This restores class invariants like
3339
3562
  * `links` defaulting to `[]` and `metadata.dateSent` being a Date.
3340
3563
  */
3341
- rehydrateMessage(raw) {
3564
+ rehydrateMessage(raw, adapter) {
3342
3565
  if (raw instanceof Message) {
3343
3566
  return raw;
3344
3567
  }
3345
3568
  const obj = raw;
3569
+ let msg;
3346
3570
  if (obj._type === "chat:Message") {
3347
- return Message.fromJSON(obj);
3348
- }
3349
- const metadata = obj.metadata;
3350
- const dateSent = metadata.dateSent;
3351
- const editedAt = metadata.editedAt;
3352
- return new Message({
3353
- id: obj.id,
3354
- threadId: obj.threadId,
3355
- text: obj.text,
3356
- formatted: obj.formatted,
3357
- raw: obj.raw,
3358
- author: obj.author,
3359
- metadata: {
3360
- dateSent: dateSent instanceof Date ? dateSent : new Date(dateSent),
3361
- edited: metadata.edited,
3362
- editedAt: editedAt ? new Date(
3363
- editedAt instanceof Date ? editedAt.toISOString() : editedAt
3364
- ) : void 0
3365
- },
3366
- attachments: obj.attachments ?? [],
3367
- isMention: obj.isMention,
3368
- links: obj.links ?? []
3369
- });
3571
+ msg = Message.fromJSON(obj);
3572
+ } else {
3573
+ const metadata = obj.metadata;
3574
+ const dateSent = metadata.dateSent;
3575
+ const editedAt = metadata.editedAt;
3576
+ msg = new Message({
3577
+ id: obj.id,
3578
+ threadId: obj.threadId,
3579
+ text: obj.text,
3580
+ formatted: obj.formatted,
3581
+ raw: obj.raw,
3582
+ author: obj.author,
3583
+ metadata: {
3584
+ dateSent: dateSent instanceof Date ? dateSent : new Date(dateSent),
3585
+ edited: metadata.edited,
3586
+ editedAt: editedAt ? new Date(
3587
+ editedAt instanceof Date ? editedAt.toISOString() : editedAt
3588
+ ) : void 0
3589
+ },
3590
+ attachments: obj.attachments ?? [],
3591
+ isMention: obj.isMention,
3592
+ links: obj.links ?? []
3593
+ });
3594
+ }
3595
+ const rehydrate = adapter?.rehydrateAttachment?.bind(adapter);
3596
+ if (rehydrate && msg.attachments.length > 0) {
3597
+ msg.attachments = msg.attachments.map(
3598
+ (att) => att.fetchData ? att : rehydrate(att)
3599
+ );
3600
+ }
3601
+ return msg;
3370
3602
  }
3371
3603
  async runHandlers(handlers, thread, message, context) {
3372
3604
  for (const handler of handlers) {
@@ -3494,13 +3726,17 @@ var Plan = class {
3494
3726
  return null;
3495
3727
  }
3496
3728
  let current;
3497
- for (let i = this._model.tasks.length - 1; i >= 0; i--) {
3498
- if (this._model.tasks[i].status === "in_progress") {
3499
- current = this._model.tasks[i];
3500
- break;
3729
+ if (typeof update === "object" && update !== null && "id" in update && update.id) {
3730
+ current = this._model.tasks.find((t) => t.id === update.id);
3731
+ } else {
3732
+ for (let i = this._model.tasks.length - 1; i >= 0; i--) {
3733
+ if (this._model.tasks[i].status === "in_progress") {
3734
+ current = this._model.tasks[i];
3735
+ break;
3736
+ }
3501
3737
  }
3738
+ current ??= this._model.tasks.at(-1);
3502
3739
  }
3503
- current ??= this._model.tasks.at(-1);
3504
3740
  if (!current) {
3505
3741
  return null;
3506
3742
  }
@@ -3589,6 +3825,38 @@ var Plan = class {
3589
3825
  }
3590
3826
  };
3591
3827
 
3828
+ // src/streaming-plan.ts
3829
+ var StreamingPlan = class {
3830
+ $$typeof = POSTABLE_OBJECT;
3831
+ kind = "stream";
3832
+ _stream;
3833
+ _options;
3834
+ constructor(stream, options = {}) {
3835
+ this._stream = stream;
3836
+ this._options = options;
3837
+ }
3838
+ get stream() {
3839
+ return this._stream;
3840
+ }
3841
+ get options() {
3842
+ return this._options;
3843
+ }
3844
+ getFallbackText() {
3845
+ return "";
3846
+ }
3847
+ getPostData() {
3848
+ return {
3849
+ stream: this._stream,
3850
+ options: this._options
3851
+ };
3852
+ }
3853
+ isSupported(_adapter) {
3854
+ return true;
3855
+ }
3856
+ onPosted(_context) {
3857
+ }
3858
+ };
3859
+
3592
3860
  // src/emoji.ts
3593
3861
  var emojiRegistry = /* @__PURE__ */ new Map();
3594
3862
  function getEmoji(name) {
@@ -3999,6 +4267,7 @@ var toCardElement2 = toCardElement;
3999
4267
  var toModalElement2 = toModalElement;
4000
4268
  var fromReactModalElement2 = fromReactModalElement;
4001
4269
  var isModalElement2 = isModalElement;
4270
+ var ExternalSelect2 = ExternalSelect;
4002
4271
  var Modal2 = Modal;
4003
4272
  var RadioSelect2 = RadioSelect;
4004
4273
  var Select2 = Select;
@@ -4018,6 +4287,7 @@ export {
4018
4287
  DEFAULT_EMOJI_MAP,
4019
4288
  Divider2 as Divider,
4020
4289
  EmojiResolver,
4290
+ ExternalSelect2 as ExternalSelect,
4021
4291
  Field2 as Field,
4022
4292
  Fields2 as Fields,
4023
4293
  Image2 as Image,
@@ -4034,6 +4304,7 @@ export {
4034
4304
  Select2 as Select,
4035
4305
  SelectOption2 as SelectOption,
4036
4306
  StreamingMarkdownRenderer,
4307
+ StreamingPlan,
4037
4308
  THREAD_STATE_TTL_MS,
4038
4309
  Table2 as Table,
4039
4310
  TextInput2 as TextInput,
@@ -371,7 +371,7 @@ declare function cardChildToFallbackText(child: CardChild): string | null;
371
371
  * Modal elements for form dialogs.
372
372
  */
373
373
 
374
- type ModalChild = TextInputElement | SelectElement | RadioSelectElement | TextElement | FieldsElement;
374
+ type ModalChild = TextInputElement | SelectElement | ExternalSelectElement | RadioSelectElement | TextElement | FieldsElement;
375
375
  interface ModalElement {
376
376
  callbackId: string;
377
377
  children: ModalChild[];
@@ -402,6 +402,15 @@ interface SelectElement {
402
402
  placeholder?: string;
403
403
  type: "select";
404
404
  }
405
+ interface ExternalSelectElement {
406
+ id: string;
407
+ initialOption?: SelectOptionElement;
408
+ label: string;
409
+ minQueryLength?: number;
410
+ optional?: boolean;
411
+ placeholder?: string;
412
+ type: "external_select";
413
+ }
405
414
  interface SelectOptionElement {
406
415
  description?: string;
407
416
  label: string;
@@ -446,6 +455,15 @@ interface SelectOptions {
446
455
  placeholder?: string;
447
456
  }
448
457
  declare function Select(options: SelectOptions): SelectElement;
458
+ interface ExternalSelectOptions {
459
+ id: string;
460
+ initialOption?: SelectOptionElement;
461
+ label: string;
462
+ minQueryLength?: number;
463
+ optional?: boolean;
464
+ placeholder?: string;
465
+ }
466
+ declare function ExternalSelect(options: ExternalSelectOptions): ExternalSelectElement;
449
467
  declare function SelectOption(options: {
450
468
  label: string;
451
469
  value: string;
@@ -574,6 +592,18 @@ interface SelectProps {
574
592
  optional?: boolean;
575
593
  placeholder?: string;
576
594
  }
595
+ /** Props for ExternalSelect component in JSX */
596
+ interface ExternalSelectProps {
597
+ id: string;
598
+ initialOption?: {
599
+ label: string;
600
+ value: string;
601
+ };
602
+ label: string;
603
+ minQueryLength?: number;
604
+ optional?: boolean;
605
+ placeholder?: string;
606
+ }
577
607
  /** Props for SelectOption component in JSX */
578
608
  interface SelectOptionProps {
579
609
  description?: string;
@@ -586,9 +616,9 @@ interface TableProps {
586
616
  rows: string[][];
587
617
  }
588
618
  /** Union of all valid JSX props */
589
- type CardJSXProps = CardProps | TextProps | ButtonProps | LinkButtonProps | CardLinkProps | ImageProps | FieldProps | ContainerProps | DividerProps | ModalProps | TextInputProps | SelectProps | SelectOptionProps | TableProps;
619
+ type CardJSXProps = CardProps | TextProps | ButtonProps | LinkButtonProps | CardLinkProps | ImageProps | FieldProps | ContainerProps | DividerProps | ModalProps | TextInputProps | SelectProps | ExternalSelectProps | SelectOptionProps | TableProps;
590
620
  /** Component function type with proper overloads */
591
- type CardComponentFunction = typeof Card | typeof Text | typeof Button | typeof LinkButton | typeof CardLink | typeof Image | typeof Field | typeof Divider | typeof Section | typeof Actions | typeof Fields | typeof Modal | typeof TextInput | typeof Select | typeof RadioSelect | typeof SelectOption | typeof Table;
621
+ type CardComponentFunction = typeof Card | typeof Text | typeof Button | typeof LinkButton | typeof CardLink | typeof Image | typeof Field | typeof Divider | typeof Section | typeof Actions | typeof Fields | typeof Modal | typeof TextInput | typeof Select | typeof ExternalSelect | typeof RadioSelect | typeof SelectOption | typeof Table;
592
622
  /**
593
623
  * Represents a JSX element from the chat JSX runtime.
594
624
  * This is the type returned when using JSX syntax with chat components.
@@ -600,7 +630,7 @@ interface CardJSXElement<P extends CardJSXProps = CardJSXProps> {
600
630
  type: CardComponentFunction;
601
631
  }
602
632
  /** Union of all element types that can be produced by chat components */
603
- type ChatElement = CardJSXElement | CardElement | TextElement | ButtonElement | LinkButtonElement | LinkElement | ImageElement | DividerElement | ActionsElement | SectionElement | FieldsElement | FieldElement | ModalElement | TextInputElement | SelectElement | SelectOptionElement | RadioSelectElement | TableElement;
633
+ type ChatElement = CardJSXElement | CardElement | TextElement | ButtonElement | LinkButtonElement | LinkElement | ImageElement | DividerElement | ActionsElement | SectionElement | FieldsElement | FieldElement | ModalElement | TextInputElement | SelectElement | ExternalSelectElement | SelectOptionElement | RadioSelectElement | TableElement;
604
634
  interface CardComponent {
605
635
  (options?: CardOptions): CardElement;
606
636
  (props: CardProps): ChatElement;
@@ -668,6 +698,10 @@ interface SelectComponent {
668
698
  (options: SelectOptions): SelectElement;
669
699
  (props: SelectProps): ChatElement;
670
700
  }
701
+ interface ExternalSelectComponent {
702
+ (options: ExternalSelectOptions): ExternalSelectElement;
703
+ (props: ExternalSelectProps): ChatElement;
704
+ }
671
705
  interface SelectOptionComponent {
672
706
  (options: {
673
707
  label: string;
@@ -735,4 +769,4 @@ declare namespace JSX {
735
769
  }
736
770
  }
737
771
 
738
- export { type DividerProps as $, type ActionsComponent as A, type ButtonComponent as B, type ChatElement as C, type DividerComponent as D, type ImageElement as E, type FieldComponent as F, type LinkButtonElement as G, type LinkButtonOptions as H, type ImageComponent as I, type LinkElement as J, type SectionElement as K, type LinkButtonComponent as L, type ModalElement as M, type TableAlignment as N, type TableElement as O, type TableOptions as P, type TextElement as Q, type RadioSelectComponent as R, type SectionComponent as S, type TextComponent as T, type TextStyle as U, type ButtonProps as V, type CardJSXElement as W, type CardJSXProps as X, type CardLinkProps as Y, type CardProps as Z, type ContainerProps as _, type CardElement as a, type FieldProps as a0, type ImageProps as a1, type LinkButtonProps as a2, type ModalProps as a3, type SelectOptionProps as a4, type SelectProps as a5, type TextInputProps as a6, type TextProps as a7, type ModalChild as a8, type ModalOptions as a9, type RadioSelectElement as aa, type RadioSelectOptions as ab, type SelectElement as ac, type SelectOptionElement as ad, type SelectOptions as ae, type TextInputElement as af, type TextInputOptions as ag, type TableProps as ah, type TableComponent as ai, isCardLinkProps as aj, jsx as ak, jsxs as al, jsxDEV as am, Fragment as an, JSX as ao, type CardChild as b, type CardComponent as c, cardChildToFallbackText as d, type CardLinkComponent as e, type FieldsComponent as f, fromReactElement as g, isJSX as h, isCardElement as i, Table as j, toModalElement as k, fromReactModalElement as l, isModalElement as m, type ModalComponent as n, type SelectComponent as o, type SelectOptionComponent as p, type TextInputComponent as q, type ActionsElement as r, type ButtonElement as s, toCardElement as t, type ButtonOptions as u, type ButtonStyle as v, type CardOptions as w, type DividerElement as x, type FieldElement as y, type FieldsElement as z };
772
+ export { type CardProps as $, type ActionsComponent as A, type ButtonComponent as B, type ChatElement as C, type DividerComponent as D, type ExternalSelectComponent as E, type FieldComponent as F, type FieldsElement as G, type ImageElement as H, type ImageComponent as I, type LinkButtonElement as J, type LinkButtonOptions as K, type LinkButtonComponent as L, type ModalElement as M, type LinkElement as N, type SectionElement as O, type TableAlignment as P, type TableElement as Q, type RadioSelectComponent as R, type SelectOptionElement as S, type TextComponent as T, type TableOptions as U, type TextElement as V, type TextStyle as W, type ButtonProps as X, type CardJSXElement as Y, type CardJSXProps as Z, type CardLinkProps as _, type CardElement as a, type ContainerProps as a0, type DividerProps as a1, type ExternalSelectProps as a2, type FieldProps as a3, type ImageProps as a4, type LinkButtonProps as a5, type ModalProps as a6, type SelectOptionProps as a7, type SelectProps as a8, type TextInputProps as a9, type TextProps as aa, type ExternalSelectElement as ab, type ExternalSelectOptions as ac, type ModalChild as ad, type ModalOptions as ae, type RadioSelectElement as af, type RadioSelectOptions as ag, type SelectElement as ah, type SelectOptions as ai, type TextInputElement as aj, type TextInputOptions as ak, type TableProps as al, type TableComponent as am, isCardLinkProps as an, jsx as ao, jsxs as ap, jsxDEV as aq, Fragment as ar, JSX as as, type CardChild as b, type CardComponent as c, cardChildToFallbackText as d, type CardLinkComponent as e, type FieldsComponent as f, fromReactElement as g, isJSX as h, isCardElement as i, type SectionComponent as j, Table as k, toModalElement as l, fromReactModalElement as m, isModalElement as n, type ModalComponent as o, type SelectComponent as p, type SelectOptionComponent as q, type TextInputComponent as r, type ActionsElement as s, toCardElement as t, type ButtonElement as u, type ButtonOptions as v, type ButtonStyle as w, type CardOptions as x, type DividerElement as y, type FieldElement as z };
@@ -1 +1 @@
1
- export { A as ActionsComponent, B as ButtonComponent, V as ButtonProps, c as CardComponent, W as CardJSXElement, X as CardJSXProps, e as CardLinkComponent, Y as CardLinkProps, Z as CardProps, C as ChatElement, _ as ContainerProps, D as DividerComponent, $ as DividerProps, F as FieldComponent, a0 as FieldProps, f as FieldsComponent, an as Fragment, I as ImageComponent, a1 as ImageProps, ao as JSX, L as LinkButtonComponent, a2 as LinkButtonProps, n as ModalComponent, a3 as ModalProps, R as RadioSelectComponent, S as SectionComponent, o as SelectComponent, p as SelectOptionComponent, a4 as SelectOptionProps, a5 as SelectProps, ai as TableComponent, ah as TableProps, T as TextComponent, q as TextInputComponent, a6 as TextInputProps, a7 as TextProps, aj as isCardLinkProps, h as isJSX, ak as jsx, am as jsxDEV, al as jsxs, t as toCardElement, k as toModalElement } from './jsx-runtime-DxATbnrP.js';
1
+ export { A as ActionsComponent, B as ButtonComponent, X as ButtonProps, c as CardComponent, Y as CardJSXElement, Z as CardJSXProps, e as CardLinkComponent, _ as CardLinkProps, $ as CardProps, C as ChatElement, a0 as ContainerProps, D as DividerComponent, a1 as DividerProps, E as ExternalSelectComponent, a2 as ExternalSelectProps, F as FieldComponent, a3 as FieldProps, f as FieldsComponent, ar as Fragment, I as ImageComponent, a4 as ImageProps, as as JSX, L as LinkButtonComponent, a5 as LinkButtonProps, o as ModalComponent, a6 as ModalProps, R as RadioSelectComponent, j as SectionComponent, p as SelectComponent, q as SelectOptionComponent, a7 as SelectOptionProps, a8 as SelectProps, am as TableComponent, al as TableProps, T as TextComponent, r as TextInputComponent, a9 as TextInputProps, aa as TextProps, an as isCardLinkProps, h as isJSX, ao as jsx, aq as jsxDEV, ap as jsxs, t as toCardElement, l as toModalElement } from './jsx-runtime-Co9uV6l7.js';