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.
- package/dist/{chunk-OPV5U4WG.js → chunk-AN7MRAVW.js} +39 -0
- package/dist/index.d.ts +220 -6
- package/dist/index.js +321 -50
- package/dist/{jsx-runtime-DxATbnrP.d.ts → jsx-runtime-Co9uV6l7.d.ts} +39 -5
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/docs/adapters.mdx +28 -28
- package/docs/api/chat.mdx +85 -1
- package/docs/api/message.mdx +5 -1
- package/docs/api/thread.mdx +23 -1
- package/docs/contributing/publishing.mdx +33 -0
- package/docs/files.mdx +1 -0
- package/docs/getting-started.mdx +1 -11
- package/docs/meta.json +0 -2
- package/docs/modals.mdx +73 -1
- package/docs/streaming.mdx +13 -5
- package/docs/threads-messages-channels.mdx +34 -0
- package/package.json +3 -2
- package/resources/guides/create-a-discord-support-bot-with-nuxt-and-redis.md +180 -0
- package/resources/guides/how-to-build-a-slack-bot-with-next-js-and-redis.md +134 -0
- package/resources/guides/how-to-build-an-ai-agent-for-slack-with-chat-sdk-and-ai-sdk.md +220 -0
- package/resources/guides/run-and-track-deploys-from-slack.md +270 -0
- package/resources/guides/ship-a-github-code-review-bot-with-hono-and-redis.md +147 -0
- package/resources/guides/triage-form-submissions-with-chat-sdk.md +178 -0
- package/resources/templates.json +19 -0
- package/docs/guides/code-review-hono.mdx +0 -241
- package/docs/guides/discord-nuxt.mdx +0 -227
- package/docs/guides/durable-chat-sessions-nextjs.mdx +0 -337
- package/docs/guides/meta.json +0 -10
- package/docs/guides/scheduled-posts-neon.mdx +0 -447
- 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-
|
|
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
|
-
|
|
1453
|
-
|
|
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 = /^
|
|
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 (
|
|
2885
|
-
const adapter = this.adapters.get("
|
|
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 (
|
|
2891
|
-
const adapter = this.adapters.get("
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
3348
|
-
}
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
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
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
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
|
|
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 };
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { A as ActionsComponent, B as ButtonComponent,
|
|
1
|
+
export { A as ActionsComponent, B as ButtonComponent, 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';
|