nolo-cli 0.67.0 → 0.68.0-alpha.2

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 (59) hide show
  1. package/{_executeModel-C5K4UL5I.js → _executeModel-XCNYHC6S.js} +13 -13
  2. package/{agentDeleteCommand-7RESZDRC.js → agentDeleteCommand-Z3DTLQEG.js} +5 -5
  3. package/{agentEmailCommands-KES5FG2E.js → agentEmailCommands-DFK2MIXR.js} +14 -14
  4. package/{agentListCommands-VFBLREFU.js → agentListCommands-FSX7RY7U.js} +5 -5
  5. package/{agentMachineCommands-UJ77TKWZ.js → agentMachineCommands-FYPV45TJ.js} +6 -6
  6. package/{agentRecordCommands-MZBPYUGL.js → agentRecordCommands-SXOCVBX7.js} +14 -14
  7. package/{agentRunCommand-R3RWG53B.js → agentRunCommand-XISX4ICI.js} +14 -14
  8. package/{agentRuntimeLocal-BD7R3OJL.js → agentRuntimeLocal-2ENB2B2Z.js} +5 -5
  9. package/{agentSlice-UP66DIC2.js → agentSlice-QLZWET7H.js} +1 -1
  10. package/{appDeleteCommands-X3UF4ZHF.js → appDeleteCommands-XKAUWKUI.js} +5 -5
  11. package/{appDeployCommands-MFHLJIYZ.js → appDeployCommands-SNXZY5IX.js} +5 -5
  12. package/{appDeployStatusCommands-BGXSUHY6.js → appDeployStatusCommands-NXUJ6LXS.js} +5 -5
  13. package/{appGetCommands-KEA6FZTF.js → appGetCommands-DNRYKGOK.js} +5 -5
  14. package/{appListCommands-CZGMZW3L.js → appListCommands-URESGUKU.js} +5 -5
  15. package/{chatQueueReduxAdapter-VVXE2NXW.js → chatQueueReduxAdapter-FNXZNIAT.js} +4 -4
  16. package/{chunk-HQ3ZLBSI.js → chunk-2XENHR3P.js} +96 -0
  17. package/{chunk-TDTSQVDX.js → chunk-3E67YXGD.js} +85 -88
  18. package/{chunk-RCNQCXPM.js → chunk-5JTJG4OG.js} +115 -121
  19. package/{chunk-MN2XJEWL.js → chunk-7NG5APVZ.js} +16 -133
  20. package/{chunk-UZXOOSHF.js → chunk-AUA5DTWI.js} +15 -14
  21. package/{chunk-HPRMNGAM.js → chunk-IX6H4NKR.js} +1 -1
  22. package/{chunk-UBWLW3KY.js → chunk-IY2BLZKO.js} +3 -3
  23. package/{chunk-5DUAG5G7.js → chunk-K4326DRU.js} +202 -11729
  24. package/{chunk-AVJQ4TDL.js → chunk-K5YS7FAN.js} +1 -1
  25. package/{chunk-TTTW4DIT.js → chunk-LNOW66U4.js} +6 -6
  26. package/{chunk-NFTTUZ3L.js → chunk-LTLZPAO7.js} +1 -1
  27. package/{chunk-QPXRNDI3.js → chunk-MIN5X7GI.js} +2 -2
  28. package/{chunk-OHJWIXXW.js → chunk-RLZ6HZSX.js} +3 -3
  29. package/{chunk-BG7ZGBKH.js → chunk-SM4ED2LZ.js} +4 -4
  30. package/{chunk-FPT2E44F.js → chunk-VHADFQCI.js} +2 -2
  31. package/{chunk-UNAVSDC5.js → chunk-XHNOCBUU.js} +4 -2
  32. package/chunk-XNO3T6RB.js +18504 -0
  33. package/chunk-Z6S2JBE4.js +2471 -0
  34. package/{chunk-M3HN7RBV.js → chunk-ZCVO2HLZ.js} +1 -1
  35. package/{contentThunks-BHML6O7K.js → contentThunks-6K4RZXKH.js} +5 -5
  36. package/{createAgentAutomationAction-K5YJO4IA.js → createAgentAutomationAction-6XYIZ3GS.js} +5 -5
  37. package/{createDialogAction-SFMZLPS4.js → createDialogAction-TJWDXAKL.js} +6 -6
  38. package/{createPageAction-UD7BSFQS.js → createPageAction-EZ2LPB6K.js} +5 -5
  39. package/{dialogCommands-2ABSL4ND.js → dialogCommands-ULXMRIAM.js} +5 -5
  40. package/{dialogSlice-DEC5GV6X.js → dialogSlice-5DRM6AQQ.js} +4 -4
  41. package/{docCreateCommands-2QZCW4HZ.js → docCreateCommands-PPHO6KUM.js} +5 -5
  42. package/{docDeleteCommands-WKZKQAKM.js → docDeleteCommands-U2GVGQPR.js} +5 -5
  43. package/{docReadCommands-WMKJCR4Q.js → docReadCommands-CYY3DJXY.js} +5 -5
  44. package/{docStore-IBPCRTTX.js → docStore-OJXM46BB.js} +1 -1
  45. package/{docUpdateCommands-KPLM63NK.js → docUpdateCommands-B5UVFLJU.js} +5 -5
  46. package/{handleSendMessageAction-C7CZNGMB.js → handleSendMessageAction-EWY3J2AV.js} +4 -4
  47. package/index.js +41 -41
  48. package/{machineCommands-6BG3AHT5.js → machineCommands-B76BYAJF.js} +14 -14
  49. package/{machineWsRunDispatch-G2KJ6NQF.js → machineWsRunDispatch-LN6274EL.js} +14 -14
  50. package/package.json +1 -1
  51. package/{readlineWorkspace-5LZ3EDIQ.js → readlineWorkspace-UFHEJIDS.js} +77 -18
  52. package/{runAgentClientLoop-CICP3O2T.js → runAgentClientLoop-MAER6Y5K.js} +11 -11
  53. package/{spaceCommands-NQOIERT6.js → spaceCommands-2YT7C56D.js} +5 -5
  54. package/{streamAgentChatTurn-QUD4FY5I.js → streamAgentChatTurn-AKUDQL5W.js} +14 -14
  55. package/{tools-MAP6O2YZ.js → tools-NM36O7ZG.js} +8 -8
  56. package/{tuiSummaryLlmCaller-VL5RDGLT.js → tuiSummaryLlmCaller-ZGATEM35.js} +2 -2
  57. package/{updateDialogTitleAction-L6CCRVUK.js → updateDialogTitleAction-RHH353JB.js} +5 -5
  58. package/chunk-CLZYOOI3.js +0 -4463
  59. package/chunk-IF6UQNAK.js +0 -5062
package/chunk-CLZYOOI3.js DELETED
@@ -1,4463 +0,0 @@
1
- import {
2
- BUILTIN_SUMMARY_LLM_CONFIG
3
- } from "./chunk-EVBFYPDC.js";
4
- import {
5
- buildDialogAttachmentPlan,
6
- extractFileContentIds
7
- } from "./chunk-HQUORJTM.js";
8
- import {
9
- isOAuthApiKeyRef
10
- } from "./chunk-YYLHWIW6.js";
11
- import {
12
- getApproxPricePerImage
13
- } from "./chunk-AGGIDPCZ.js";
14
- import {
15
- runLlm
16
- } from "./chunk-OHJWIXXW.js";
17
- import {
18
- cleanupCliSessionForDialog
19
- } from "./chunk-76JAMDUT.js";
20
- import {
21
- getActiveDialogAgentId,
22
- getDialogAgentIds,
23
- getPrimaryDialogAgentId
24
- } from "./chunk-5RGU3J7P.js";
25
- import {
26
- abortActiveControllers,
27
- addPageReferenceToRuntime,
28
- applyClearDialogStateRuntime,
29
- applyUpdateTokensFulfilled,
30
- clearActiveControllers,
31
- deleteDialogRuntime,
32
- getActiveDialogKey,
33
- getDialogRuntimeTokens,
34
- resetDialogRuntimeSessionState,
35
- selectCurrentDialogKey,
36
- setActiveDialogKey,
37
- setDialogConfigError
38
- } from "./chunk-6YTOJY35.js";
39
- import {
40
- require_date_fns
41
- } from "./chunk-M76ECQRD.js";
42
- import {
43
- require_react
44
- } from "./chunk-YDH3FDFQ.js";
45
- import {
46
- DEFAULT_AUTO_EXECUTION_PROFILE,
47
- DEFAULT_CONTEXT_WINDOW,
48
- EMPTY_ASSISTANT_FALLBACK_MESSAGE,
49
- LENGTH_TRUNCATED_FALLBACK_MESSAGE,
50
- REPETITION_LOOP_FALLBACK_MESSAGE,
51
- STAGNANT_TOOL_CALLS_FALLBACK_MESSAGE,
52
- STREAM_TRUNCATED_FALLBACK_MESSAGE,
53
- getModelContextWindow,
54
- getModelInfo,
55
- readCacheCreationInputTokens,
56
- readCacheReadInputTokens,
57
- resolveAutoExecutionProfile
58
- } from "./chunk-HQ3ZLBSI.js";
59
- import {
60
- COMPACTION_SUMMARY_SYSTEM_PROMPT,
61
- buildCompactionMetricsFromPlan,
62
- buildCompactionUserContent,
63
- formatCompactionMetricsLog,
64
- formatFileOperationsFromMessages,
65
- formatMessagesForSummaryWithTruncation,
66
- normalizeAssistantContentBuffer,
67
- normalizeTimingMs,
68
- planCompression,
69
- serializeMessageContent
70
- } from "./chunk-TDTSQVDX.js";
71
- import {
72
- estimateTokenCount
73
- } from "./chunk-PSCNXBYA.js";
74
- import {
75
- findModelConfig,
76
- getModelConfig
77
- } from "./chunk-TQC77XVE.js";
78
- import {
79
- toErrorMessage
80
- } from "./chunk-HNMXYYJR.js";
81
- import {
82
- fetchMessages
83
- } from "./chunk-BYEJ7K2Z.js";
84
- import {
85
- PLATFORM_HOSTED_DEEPSEEK_FLASH_MODEL,
86
- PLATFORM_HOSTED_DEEPSEEK_PRO_MODEL,
87
- PLATFORM_HOSTED_GLM_53_FLASH_BASETEN_PRICE,
88
- PLATFORM_HOSTED_GLM_53_FLASH_MODEL,
89
- getPlatformHostedDeepSeekV4Price,
90
- isPlatformHostedClaudeModel,
91
- isPlatformHostedDeepSeekV4Model,
92
- isPlatformHostedImageModel,
93
- isPlatformHostedOpenAIImageModel
94
- } from "./chunk-5YIL5WDC.js";
95
- import {
96
- nolotusId
97
- } from "./chunk-OPNHMILE.js";
98
- import {
99
- asRecordOrEmpty
100
- } from "./chunk-KX6YBIHG.js";
101
- import {
102
- patch,
103
- read,
104
- remove,
105
- selectById,
106
- write
107
- } from "./chunk-4K6DB3GJ.js";
108
- import {
109
- buildDialogAgentListIndexDeleteOps,
110
- createDialogMessageKeyAndId,
111
- createKey,
112
- createTokenKey,
113
- createTokenStatsKey,
114
- dialogMessageKey,
115
- isDialogRecordKey,
116
- isPageKey,
117
- isTableMetaKey
118
- } from "./chunk-NHRQCXIQ.js";
119
- import {
120
- asOptionalFiniteNumber
121
- } from "./chunk-WWC7I6TA.js";
122
- import {
123
- asTrimmedNonEmptyStringArray
124
- } from "./chunk-I42VC5KR.js";
125
- import {
126
- asTrimmedLowercaseString
127
- } from "./chunk-QSJ3HFEF.js";
128
- import {
129
- builtinAgentCatalogEntryById,
130
- builtinRuntimeFallbackEntries,
131
- isBuiltinPlatformAgentKey
132
- } from "./chunk-4MKPBCTN.js";
133
- import {
134
- extractCustomId,
135
- extractUserId,
136
- parsePublicAgentId,
137
- publicAgentKey
138
- } from "./chunk-BJIRLHJR.js";
139
- import {
140
- asyncThunkCreator,
141
- buildCreateSlice,
142
- createAsyncThunk,
143
- createEntityAdapter,
144
- createSelector,
145
- getRuntimeServerContext,
146
- parseOwnerUserIdFromDbKey,
147
- scheduleDeleteReplication
148
- } from "./chunk-3RAG2NAD.js";
149
- import {
150
- createClientLogger,
151
- isAbortError
152
- } from "./chunk-QOKAKDPE.js";
153
- import {
154
- selectIdentityToken,
155
- selectIdentityUser,
156
- selectIdentityUserId
157
- } from "./chunk-SEJ5OS6F.js";
158
- import {
159
- isTombstoneRecord,
160
- shouldReplaceWithNextRecord
161
- } from "./chunk-GBRG75BQ.js";
162
- import {
163
- asTrimmedString
164
- } from "./chunk-3EUW3WEO.js";
165
- import {
166
- isRecord
167
- } from "./chunk-KUG52IAP.js";
168
- import {
169
- asOptionalTrimmedString
170
- } from "./chunk-G3SUCT4W.js";
171
- import {
172
- __toESM
173
- } from "./chunk-4VNS5WPM.js";
174
-
175
- // packages/chat/dialog/actions/addReferenceKeysAction.ts
176
- var extractReferenceKeys = (content) => {
177
- const keys = /* @__PURE__ */ new Set();
178
- if (Array.isArray(content)) {
179
- for (const part of content) {
180
- if (part && typeof part === "object") {
181
- if (part.pageKey) keys.add(part.pageKey);
182
- if (part.dialogKey) keys.add(part.dialogKey);
183
- }
184
- }
185
- } else if (content && typeof content === "object") {
186
- if (content.pageKey) keys.add(content.pageKey);
187
- if (content.dialogKey) keys.add(content.dialogKey);
188
- }
189
- return Array.from(keys);
190
- };
191
- var addReferenceKeysAction = createAsyncThunk(
192
- "dialog/addReferenceKeys",
193
- async (args, { getState, dispatch }) => {
194
- const { content, dialogKey } = args;
195
- const newKeys = extractReferenceKeys(content);
196
- if (newKeys.length === 0) return;
197
- const state = getState();
198
- const dialogConfig = selectById(state, dialogKey);
199
- if (!dialogConfig) return;
200
- const existingKeys = new Set(dialogConfig.referenceKeys || []);
201
- const keysToAdd = newKeys.filter((k) => !existingKeys.has(k));
202
- if (keysToAdd.length === 0) return;
203
- const updatedKeys = [...Array.from(existingKeys), ...keysToAdd];
204
- await dispatch(
205
- patch({
206
- dbKey: dialogKey,
207
- changes: {
208
- referenceKeys: updatedKeys
209
- }
210
- })
211
- );
212
- }
213
- );
214
-
215
- // packages/chat/messages/toolPresentation.ts
216
- var SUMMARY_EMOJI_PREFIX = new RegExp("^(\\p{Emoji_Presentation}|\\p{Extended_Pictographic}|\\[[vx!]\\])\\s*", "u");
217
-
218
- // packages/chat/messages/assistantMessageFacts.ts
219
- var isAssistantToolStub = (msg) => msg?.role === "assistant" && (msg.content == null || typeof msg.content === "string" && msg.content.trim().length === 0 || Array.isArray(msg.content) && msg.content.length === 0) && Array.isArray(msg?.tool_calls) && msg.tool_calls.length > 0;
220
-
221
- // packages/chat/messages/messageDeleteCascade.ts
222
- function planDeleteMessageCascade(msg, entities) {
223
- const msgId = msg?.id;
224
- let extraRemoveId;
225
- let extraRemoveDbKey;
226
- if (msg?.role === "tool" && msg.parentMessageId) {
227
- const parent = entities[msg.parentMessageId];
228
- if (parent && parent.role === "assistant" && isAssistantToolStub(parent)) {
229
- const hasOtherToolMsgs = Object.values(entities).some(
230
- (m) => m && m.role === "tool" && m.parentMessageId === msg.parentMessageId && m.dbKey !== msg.dbKey
231
- );
232
- if (!hasOtherToolMsgs) {
233
- extraRemoveId = parent.id;
234
- extraRemoveDbKey = parent.dbKey;
235
- }
236
- }
237
- }
238
- return { id: msgId, extraRemoveId, extraRemoveDbKey };
239
- }
240
-
241
- // packages/chat/messages/messageEditContent.ts
242
- var buildEditedMessageContent = (originalContent, nextText) => {
243
- const trimmedText = nextText.trim();
244
- if (typeof originalContent === "string") {
245
- return trimmedText;
246
- }
247
- if (Array.isArray(originalContent)) {
248
- const nextParts = originalContent.filter(
249
- (part) => part && typeof part === "object" && part.type !== "text"
250
- );
251
- if (trimmedText) {
252
- nextParts.unshift({ type: "text", text: trimmedText });
253
- }
254
- return nextParts;
255
- }
256
- return trimmedText;
257
- };
258
-
259
- // packages/chat/messages/messageEditReplayPlan.ts
260
- function planEditUserMessageAndReplay(input) {
261
- const { messages, messageId, originalContent, nextText } = input;
262
- const targetIndex = messages.findIndex((message) => message.id === messageId);
263
- if (targetIndex < 0) {
264
- return {
265
- ok: false,
266
- error: "target_not_found",
267
- message: "editUserMessageAndReplay: target message not found."
268
- };
269
- }
270
- const targetMessage = messages[targetIndex];
271
- if (!targetMessage || targetMessage.role !== "user") {
272
- return {
273
- ok: false,
274
- error: "not_user_message",
275
- message: "\u53EA\u80FD\u7F16\u8F91\u7528\u6237\u6D88\u606F\u3002"
276
- };
277
- }
278
- if (messages.some((message) => message.isStreaming)) {
279
- return {
280
- ok: false,
281
- error: "streaming_in_progress",
282
- message: "\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u5B8C\u6210\u540E\u518D\u7F16\u8F91\u5386\u53F2\u6D88\u606F\u3002"
283
- };
284
- }
285
- const nextContent = buildEditedMessageContent(
286
- originalContent ?? targetMessage.content,
287
- nextText
288
- );
289
- const trailingMessages = messages.slice(targetIndex + 1);
290
- return {
291
- ok: true,
292
- targetMessage,
293
- nextContent,
294
- trailingMessages
295
- };
296
- }
297
-
298
- // packages/chat/messages/messageFinalizeOnError.ts
299
- function messageHasDisplayContent(content) {
300
- if (typeof content === "string") {
301
- return content.trim().length > 0;
302
- }
303
- return Array.isArray(content) && content.length > 0;
304
- }
305
- function resolveFinalizeTransientOnError(existing, error) {
306
- if (!existing) return { kind: "noop" };
307
- if (!messageHasDisplayContent(existing.content)) {
308
- return { kind: "remove" };
309
- }
310
- return {
311
- kind: "markError",
312
- changes: {
313
- isStreaming: false,
314
- metadata: {
315
- ...existing.metadata ?? {},
316
- error: true,
317
- ...error ? { message: error } : {}
318
- }
319
- }
320
- };
321
- }
322
-
323
- // packages/chat/messages/messageInitMsgsPolicy.ts
324
- function resolveInitMsgsFulfilledWriteMode(input) {
325
- if (input.isNew || input.hasLocalStreaming) return "upsert";
326
- return "replace";
327
- }
328
- function resolveInitMsgsHasMoreOlder(input) {
329
- const { limit, fetchedCount } = input;
330
- if (typeof limit === "number" && Number.isFinite(limit) && limit > 0) {
331
- return fetchedCount >= limit;
332
- }
333
- return false;
334
- }
335
-
336
- // packages/chat/messages/messageInitMsgsSummaryResume.ts
337
- function findDialogConfigByDialogId(entities, dialogId) {
338
- return Object.values(entities ?? {}).find(
339
- (entity) => {
340
- if (!entity || typeof entity !== "object") return false;
341
- const value = entity;
342
- return value.type === "dialog" /* DIALOG */ && value.id === dialogId;
343
- }
344
- );
345
- }
346
- function resolveInitMsgsSummaryResume(input) {
347
- const dialogConfig = findDialogConfigByDialogId(input.entities, input.dialogId);
348
- if (dialogConfig && dialogConfig.summaryPending && dialogConfig.dbKey) {
349
- return { resume: true, dialogKey: dialogConfig.dbKey };
350
- }
351
- return { resume: false };
352
- }
353
-
354
- // packages/chat/messages/messageValidation.ts
355
- var isValidMessage = (msg) => !!msg && typeof msg === "object" && typeof msg.id === "string";
356
-
357
- // packages/chat/messages/fetchConvMsgs.ts
358
- var FETCH_TIMEOUT = 5e3;
359
- var fetchConvMsgs = async (server, token, {
360
- dialogId,
361
- dialogKey,
362
- limit,
363
- beforeKey
364
- }, options = {}) => {
365
- const { signal: externalSignal } = options;
366
- const controller = new AbortController();
367
- const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT);
368
- const onExternalAbort = () => controller.abort();
369
- externalSignal?.addEventListener("abort", onExternalAbort);
370
- try {
371
- const response = await fetch(`${server}/rpc/getConvMsgs`, {
372
- method: "POST",
373
- headers: {
374
- Authorization: `Bearer ${token}`,
375
- "Content-Type": "application/json"
376
- },
377
- body: JSON.stringify({
378
- dialogId,
379
- ...dialogKey && { dialogKey },
380
- limit,
381
- ...beforeKey && { beforeKey }
382
- }),
383
- signal: controller.signal
384
- });
385
- clearTimeout(timeoutId);
386
- externalSignal?.removeEventListener("abort", onExternalAbort);
387
- if (!response.ok) {
388
- console.error(`fetchConvMsgs: Failed ${response.status} from ${server}`);
389
- return [];
390
- }
391
- const data = await response.json();
392
- return Array.isArray(data) ? data : [];
393
- } catch (error) {
394
- clearTimeout(timeoutId);
395
- externalSignal?.removeEventListener("abort", onExternalAbort);
396
- if (externalSignal?.aborted) {
397
- throw error;
398
- }
399
- console.error(`fetchConvMsgs: Error fetching from ${server}:`, error);
400
- return [];
401
- }
402
- };
403
-
404
- // packages/app/utils/async.ts
405
- function swallowNonAbortError(promise, fallback, signal) {
406
- return promise.catch((err) => {
407
- if (isAbortError(err) || signal?.aborted) {
408
- throw err;
409
- }
410
- console.error("Non-abort error in async op:", err);
411
- return fallback;
412
- });
413
- }
414
-
415
- // packages/chat/messages/fetchAndCacheMessages.ts
416
- var fetchAndCacheMessagesLocalFirst = async ({
417
- db,
418
- dialogId,
419
- dialogKey,
420
- // Default: full dialog history (no 50-message window that blinds multi-turn agents).
421
- limit,
422
- beforeKey,
423
- token,
424
- remoteServers = [],
425
- signal
426
- }) => {
427
- const startedAt = typeof performance !== "undefined" ? performance.now() : Date.now();
428
- const localPromise = fetchMessages(db, dialogId, {
429
- limit,
430
- beforeKey,
431
- throwOnError: false,
432
- includeDeleted: true
433
- }).catch(() => []);
434
- const remotePromise = (async () => {
435
- if (!token || remoteServers.length === 0) return [];
436
- const results = await Promise.all(
437
- remoteServers.map(
438
- (server) => swallowNonAbortError(
439
- fetchConvMsgs(
440
- server,
441
- token,
442
- { dialogId, dialogKey, limit, beforeKey },
443
- { signal }
444
- ),
445
- [],
446
- void 0
447
- )
448
- )
449
- );
450
- return results.flat();
451
- })();
452
- let localSettledAt = null;
453
- const localTimingPromise = localPromise.then((value) => {
454
- localSettledAt = typeof performance !== "undefined" ? performance.now() : Date.now();
455
- return value;
456
- });
457
- const localMsgs = await localTimingPromise;
458
- const localMs = localSettledAt !== null ? Math.round(localSettledAt - startedAt) : null;
459
- const earlyReturned = localMsgs.length > 0;
460
- const remotePromiseWithMerge = (async () => {
461
- let remoteSettledAt = null;
462
- const remoteMsgs = await remotePromise.then((value) => {
463
- remoteSettledAt = typeof performance !== "undefined" ? performance.now() : Date.now();
464
- return value;
465
- });
466
- const freshLocalMsgs = await fetchMessages(db, dialogId, {
467
- limit,
468
- beforeKey,
469
- throwOnError: false,
470
- includeDeleted: true
471
- }).catch(() => []);
472
- const uniqueMap = /* @__PURE__ */ new Map();
473
- const changedMessagesToCache = /* @__PURE__ */ new Map();
474
- const put = (m, trackChange = false) => {
475
- if (!m || !m.id) return;
476
- const existing = uniqueMap.get(m.id);
477
- if (existing && !shouldReplaceWithNextRecord(m, existing)) return;
478
- uniqueMap.set(m.id, m);
479
- if (trackChange) changedMessagesToCache.set(m.id, m);
480
- };
481
- localMsgs.forEach((m) => put(m));
482
- freshLocalMsgs.forEach((m) => put(m));
483
- remoteMsgs.forEach((m) => put(m, true));
484
- if (changedMessagesToCache.size > 0) {
485
- try {
486
- const ops = Array.from(changedMessagesToCache.values()).map((msg) => {
487
- let key = msg.dbKey || msg.dbKey;
488
- if (!key) {
489
- key = dialogMessageKey(dialogId, msg.id);
490
- }
491
- return {
492
- type: "put",
493
- key,
494
- value: {
495
- ...msg,
496
- dbKey: key,
497
- type: "msg" /* MSG */
498
- }
499
- };
500
- });
501
- await db.batch(ops);
502
- } catch {
503
- }
504
- }
505
- console.info("[fetchAndCacheMessages-perf]", {
506
- dialogId,
507
- localMs,
508
- remoteMs: remoteSettledAt !== null ? Math.round(remoteSettledAt - startedAt) : null,
509
- totalMs: Math.round(
510
- (typeof performance !== "undefined" ? performance.now() : Date.now()) - startedAt
511
- ),
512
- localCount: localMsgs.length,
513
- remoteCount: remoteMsgs.length,
514
- remoteServerCount: remoteServers.length,
515
- hasToken: !!token,
516
- earlyReturned
517
- });
518
- return Array.from(uniqueMap.values()).filter((message) => !isTombstoneRecord(message)).sort((a, b) => {
519
- const aCreated = a && typeof a === "object" && "createdAt" in a ? a.createdAt : void 0;
520
- const bCreated = b && typeof b === "object" && "createdAt" in b ? b.createdAt : void 0;
521
- const tA = new Date(aCreated || 0).getTime();
522
- const tB = new Date(bCreated || 0).getTime();
523
- return tB - tA;
524
- });
525
- })();
526
- if (!earlyReturned) {
527
- const mergedMessages = await remotePromiseWithMerge;
528
- return {
529
- localMessages: mergedMessages,
530
- remotePromise: Promise.resolve(mergedMessages),
531
- earlyReturned: false
532
- };
533
- }
534
- return {
535
- localMessages: localMsgs,
536
- remotePromise: remotePromiseWithMerge,
537
- earlyReturned: true
538
- };
539
- };
540
- var fetchAndCacheMessages = async (options) => {
541
- const { remotePromise } = await fetchAndCacheMessagesLocalFirst(options);
542
- return remotePromise;
543
- };
544
-
545
- // packages/chat/messages/parseJsonRecord.ts
546
- function asOptionalJsonRecord(value) {
547
- if (typeof value === "string") {
548
- if (!value.trim()) return void 0;
549
- try {
550
- const parsed = JSON.parse(value);
551
- return isRecord(parsed) ? parsed : void 0;
552
- } catch {
553
- return void 0;
554
- }
555
- }
556
- return isRecord(value) ? value : void 0;
557
- }
558
-
559
- // packages/chat/dialog/actions/extractReferenceKeys.ts
560
- var REFERENCE_ARG_FIELDS = [
561
- "pageKey",
562
- "dialogKey",
563
- "dbKey",
564
- "docKey",
565
- "key",
566
- "id",
567
- "rowDbKey",
568
- "tableKey",
569
- "table"
570
- ];
571
- var isLoadableReferenceKey = (key) => isPageKey(key) || isDialogRecordKey(key) || isTableMetaKey(key);
572
- var extractKeysFromArgs = (args, out) => {
573
- if (!args) return;
574
- for (const field of REFERENCE_ARG_FIELDS) {
575
- const value = args[field];
576
- const key = asTrimmedString(value);
577
- if (key && isLoadableReferenceKey(key)) {
578
- out.add(key);
579
- }
580
- }
581
- };
582
- var extractKeysFromToolCalls = (msg, out) => {
583
- const toolCalls = msg.tool_calls;
584
- if (!Array.isArray(toolCalls)) return;
585
- for (const call of toolCalls) {
586
- const fn = call.function;
587
- const argumentsText = asTrimmedString(fn.arguments);
588
- if (!argumentsText) continue;
589
- const parsed = asOptionalJsonRecord(argumentsText);
590
- if (parsed) extractKeysFromArgs(parsed, out);
591
- }
592
- };
593
- var extractKeysFromToolPayload = (toolPayload, out) => {
594
- if (!toolPayload) return;
595
- if (isRecord(toolPayload.input)) {
596
- extractKeysFromArgs(
597
- toolPayload.input,
598
- out
599
- );
600
- return;
601
- }
602
- const rawToolCall = toolPayload.rawToolCall;
603
- if (isRecord(rawToolCall)) {
604
- const fn = rawToolCall.function;
605
- if (isRecord(fn)) {
606
- const argumentsText = asTrimmedString(fn.arguments);
607
- if (argumentsText) {
608
- const parsed = asOptionalJsonRecord(argumentsText);
609
- if (parsed) extractKeysFromArgs(parsed, out);
610
- }
611
- }
612
- }
613
- };
614
- var extractKeysFromContent = (msg, out) => {
615
- const content = msg.content;
616
- if (!content) return;
617
- const parts = Array.isArray(content) ? content : [content];
618
- for (const part of parts) {
619
- if (!isRecord(part)) continue;
620
- const pageKey = asTrimmedString(part.pageKey);
621
- if (pageKey) out.add(pageKey);
622
- const dialogKey = asTrimmedString(part.dialogKey);
623
- if (dialogKey) out.add(dialogKey);
624
- }
625
- };
626
- var extractReferenceKeysFromMessage = (msg) => {
627
- const keys = /* @__PURE__ */ new Set();
628
- extractKeysFromContent(msg, keys);
629
- extractKeysFromToolCalls(msg, keys);
630
- extractKeysFromToolPayload(msg.toolPayload, keys);
631
- return Array.from(keys);
632
- };
633
-
634
- // packages/chat/dialog/actions/updateDialogSummaryAction.ts
635
- var getMessagesForDialogFromState = (state, dialogId) => {
636
- const msgsState = state.message.dialogStateById[dialogId]?.msgs;
637
- if (!msgsState || !msgsState.ids) return [];
638
- return msgsState.ids.flatMap((id) => {
639
- const msg = msgsState.entities[id];
640
- return msg ? [msg] : [];
641
- });
642
- };
643
- var identityCanonicalName = (name) => name;
644
- var summarizingDialogs = /* @__PURE__ */ new Set();
645
- var updateDialogSummaryAction = async (args, thunkApi) => {
646
- const { dialogKey, preFetchedMessages, force = false } = args;
647
- if (summarizingDialogs.has(dialogKey)) return;
648
- summarizingDialogs.add(dialogKey);
649
- const { dispatch, getState } = thunkApi;
650
- try {
651
- const state = getState();
652
- const dialogId = extractCustomId(dialogKey);
653
- const dialogConfig = selectById(state, dialogKey);
654
- if (!dialogConfig) return;
655
- let contextWindow = DEFAULT_CONTEXT_WINDOW;
656
- if (dialogConfig.cybots && dialogConfig.cybots.length > 0) {
657
- const agentId = dialogConfig.cybots[0];
658
- const agent = selectById(state, agentId);
659
- if (agent?.model) {
660
- contextWindow = getModelContextWindow(agent.model);
661
- }
662
- }
663
- const allMsgs = preFetchedMessages || getMessagesForDialogFromState(state, dialogId);
664
- const plan = planCompression({
665
- allMsgs,
666
- summarizedBeforeId: dialogConfig.summarizedBeforeId,
667
- summary: dialogConfig.summary || "",
668
- contextWindow,
669
- force,
670
- reason: args.reason,
671
- // 防死亡螺旋:用 summary 长度作为上次压缩后的基线。
672
- lastCompactedTokenCount: dialogConfig.summary ? estimateTokenCount(dialogConfig.summary) : void 0
673
- });
674
- if (!plan.shouldCompress) return;
675
- const { msgsToCompress, newSummarizedBeforeId } = plan;
676
- const extractedKeys = new Set(dialogConfig.referenceKeys || []);
677
- for (const msg of msgsToCompress) {
678
- for (const key of extractReferenceKeysFromMessage(msg)) {
679
- extractedKeys.add(key);
680
- }
681
- }
682
- const previousSummary = dialogConfig.summary || "";
683
- const messagesText = formatMessagesForSummaryWithTruncation(msgsToCompress);
684
- const fileOpsText = formatFileOperationsFromMessages(
685
- msgsToCompress,
686
- identityCanonicalName
687
- );
688
- const promptContent = buildCompactionUserContent({
689
- previousSummary,
690
- messagesText,
691
- fileOpsText
692
- });
693
- try {
694
- const newSummary = await dispatch(
695
- runLlm({
696
- llmConfig: {
697
- ...BUILTIN_SUMMARY_LLM_CONFIG,
698
- prompt: COMPACTION_SUMMARY_SYSTEM_PROMPT
699
- },
700
- content: promptContent,
701
- billingDialogKey: dialogKey
702
- })
703
- ).unwrap();
704
- if (newSummary && typeof newSummary === "string" && newSummary.trim()) {
705
- const currentCount = dialogConfig.compressionCount || 0;
706
- await dispatch(
707
- patch({
708
- dbKey: dialogKey,
709
- changes: {
710
- summary: newSummary.trim(),
711
- summarizedBeforeId: newSummarizedBeforeId,
712
- referenceKeys: Array.from(extractedKeys),
713
- compressionCount: currentCount + 1,
714
- summaryPending: false
715
- // Explicitly clear pending flag
716
- }
717
- })
718
- ).unwrap();
719
- const metrics = buildCompactionMetricsFromPlan({
720
- reason: args.reason || "context_budget",
721
- previousSummary: dialogConfig.summary || "",
722
- plan,
723
- newSummary: newSummary.trim()
724
- // web 端 runLlm 只返回摘要字符串,不含 usage。
725
- // summaryUsage 需要 runLlm 改造才能获取,当前留空。
726
- });
727
- console.log(formatCompactionMetricsLog(metrics));
728
- }
729
- } catch (err) {
730
- console.error("[ContextCompression] Failed:", err);
731
- }
732
- } finally {
733
- summarizingDialogs.delete(dialogKey);
734
- }
735
- };
736
-
737
- // packages/chat/messages/normalizeHistoricalReasoning.ts
738
- var HISTORICAL_REASONING_FALLBACK_MESSAGES = /* @__PURE__ */ new Set([
739
- EMPTY_ASSISTANT_FALLBACK_MESSAGE,
740
- LENGTH_TRUNCATED_FALLBACK_MESSAGE,
741
- STREAM_TRUNCATED_FALLBACK_MESSAGE,
742
- REPETITION_LOOP_FALLBACK_MESSAGE,
743
- STAGNANT_TOOL_CALLS_FALLBACK_MESSAGE
744
- ]);
745
- function normalizeHistoricalReasoningMessage(message) {
746
- if (!message || typeof message !== "object") {
747
- return message;
748
- }
749
- if (message.role !== "assistant") {
750
- return message;
751
- }
752
- if (typeof message.thinkContent === "string" && message.thinkContent.trim().length > 0) {
753
- return message;
754
- }
755
- const reasoning = message.reasoning_content;
756
- if (typeof reasoning !== "string" || reasoning.trim().length === 0) {
757
- return message;
758
- }
759
- const content = message.content;
760
- if (typeof content !== "string" || !HISTORICAL_REASONING_FALLBACK_MESSAGES.has(content.trim())) {
761
- return message;
762
- }
763
- return {
764
- ...message,
765
- thinkContent: reasoning
766
- };
767
- }
768
-
769
- // packages/chat/messages/messageContract.ts
770
- function separateThinkContent(contentBuffer) {
771
- let thinkContent = "";
772
- let normalContent = "";
773
- const combinedText = contentBuffer.flatMap(
774
- (c) => c.type === "text" && "text" in c && c.text ? [c.text] : []
775
- ).join("");
776
- const thinkMatches = combinedText.match(/<think\b[^>]*>(.*?)<\/think>/gis);
777
- if (thinkMatches) {
778
- thinkContent = thinkMatches.map((m) => m.replace(/<think\b[^>]*>|<\/think>/gi, "")).join("\n\n");
779
- normalContent = combinedText.replace(/<think\b[^>]*>.*?<\/think>/gis, "").trim();
780
- } else {
781
- normalContent = combinedText;
782
- }
783
- return { thinkContent, normalContent };
784
- }
785
- function countImageParts(content) {
786
- if (!Array.isArray(content)) return 0;
787
- return content.filter((part) => part?.type === "image_url").length;
788
- }
789
- function finalizeAssistantMessageContent(normalizedContentBuffer, reasoningBuffer = "") {
790
- const { thinkContent: tagThink, normalContent } = separateThinkContent(normalizedContentBuffer);
791
- const thinkContent = `${tagThink}${reasoningBuffer}`.trim();
792
- const hasNonTextParts = normalizedContentBuffer.some(
793
- (part) => part && part.type && part.type !== "text"
794
- );
795
- return {
796
- thinkContent,
797
- textContent: normalContent || "",
798
- visibleContent: hasNonTextParts ? normalizedContentBuffer : normalContent || "",
799
- hasNonTextParts,
800
- imagePartCount: countImageParts(normalizedContentBuffer)
801
- };
802
- }
803
- function appendSaveFailureToContent(content) {
804
- const failureText = "[Failed to save message]";
805
- if (Array.isArray(content)) {
806
- return [...content, { type: "text", text: failureText }];
807
- }
808
- if (typeof content === "string" && content.length > 0) {
809
- return `${content}
810
- ${failureText}`;
811
- }
812
- return failureText;
813
- }
814
-
815
- // packages/create/space/contentKeyUtils.ts
816
- var isAppContentKey = (contentKey) => typeof contentKey === "string" && contentKey.startsWith("app-");
817
- var normalizeAppRouteId = (contentKey) => isAppContentKey(contentKey) ? contentKey : `app-${contentKey}`;
818
-
819
- // packages/ai/tools/uiAskChoiceTool.ts
820
- var uiAskChoiceFunctionSchema = {
821
- name: "ask_user",
822
- description: "\u8BA9\u7528\u6237\u5728 2\uFF5E5 \u4E2A\u4E92\u65A5\u9009\u9879\u4E4B\u95F4\u505A\u9009\u62E9\u7684\u901A\u7528\u201C\u51FA\u9009\u9879\u201D\u5DE5\u5177\uFF08\u9700\u6C42\u6A21\u7CCA\u3001\u5206\u652F\u51B3\u7B56\u3001\u95EE\u5377\u7B49\uFF09\u3002\u8C03\u7528\u524D\u987B\u5148\u5728\u666E\u901A\u56DE\u590D\u6587\u672C\u91CC\u89E3\u91CA\u80CC\u666F\u4E0E\u6743\u8861\uFF08\u5148\u89E3\u91CA\uFF0C\u518D\u8C03\u7528\uFF09\u3002\u591A\u95EE\u9898\u4F20 questions\uFF0C\u5355\u95EE\u9898\u4F20 question+choices\u3002",
823
- parameters: {
824
- type: "object",
825
- properties: {
826
- question: {
827
- type: "string",
828
- description: "\u5C55\u793A\u7ED9\u7528\u6237\u7684\u95EE\u9898\u6587\u6848\uFF08\u5355\u95EE\u9898\u6A21\u5F0F\uFF09\u3002\u4E0E questions \u4E8C\u9009\u4E00\u3002"
829
- },
830
- choices: {
831
- type: "array",
832
- description: "\u5907\u9009\u9879\u5217\u8868\uFF0C\u6E32\u67D3\u4E3A\u6309\u94AE\u4F9B\u7528\u6237\u70B9\u51FB\u3002",
833
- items: {
834
- type: "object",
835
- properties: {
836
- id: {
837
- type: "string",
838
- description: "\u9009\u9879\u6807\u8BC6\u3002"
839
- },
840
- label: {
841
- type: "string",
842
- description: "\u6309\u94AE\u6587\u5B57\uFF0C\u5982\u201C\u751F\u6210\u672C\u5468\u5468\u62A5\u201D\u3002"
843
- },
844
- detail: {
845
- type: "string",
846
- description: "\u7B80\u77ED\u8865\u5145\uFF08\u5EFA\u8BAE\u4E00\u53E5\u8BDD\uFF09\uFF0C\u957F\u89E3\u91CA\u5199\u8FDB\u8C03\u7528\u524D\u7684\u56DE\u590D\u6587\u672C\u3002"
847
- },
848
- recommended: {
849
- type: "boolean",
850
- description: "\u6807\u8BB0\u4E3A\u63A8\u8350\u9879\uFF08\u653E\u9996\u4F4D\u5E76\u7F6E true\uFF0C\u65E0\u63A8\u8350\u5219\u7701\u7565\uFF09\u3002"
851
- },
852
- userMessage: {
853
- type: "string",
854
- description: "\u70B9\u51FB\u540E\u4F5C\u4E3A\u4E0B\u4E00\u6761 user \u6D88\u606F\u53D1\u9001\u7684\u6587\u6848\uFF08\u7559\u7A7A\u9ED8\u8BA4\u7528 label\uFF09\u3002"
855
- }
856
- },
857
- required: ["id", "label"]
858
- }
859
- },
860
- questions: {
861
- type: "array",
862
- description: "\u591A\u95EE\u9898\u6A21\u5F0F\uFF08\u591A tab \u6E32\u67D3\uFF0C\u4E0E question+choices \u4E8C\u9009\u4E00\uFF09\u3002",
863
- items: {
864
- type: "object",
865
- properties: {
866
- id: {
867
- type: "string",
868
- description: "\u95EE\u9898\u6807\u8BC6\u3002"
869
- },
870
- header: {
871
- type: "string",
872
- description: "\u591A\u95EE\u9898 tab \u680F\u663E\u793A\u7684\u77ED\u6807\u7B7E\uFF08\u226412 \u5B57\u7B26\uFF0C\u5982\u201C\u683C\u5F0F/\u8BED\u8A00/\u8303\u56F4\u201D\uFF09\uFF0C\u7F3A\u7701\u7528 Qn\u3002"
873
- },
874
- question: {
875
- type: "string",
876
- description: "\u95EE\u9898\u6587\u6848\u3002"
877
- },
878
- choices: {
879
- type: "array",
880
- description: "\u8BE5\u95EE\u9898\u7684\u5907\u9009\u9879\u3002",
881
- items: {
882
- type: "object",
883
- properties: {
884
- id: { type: "string" },
885
- label: { type: "string" },
886
- detail: {
887
- type: "string",
888
- description: "\u7B80\u77ED\u8865\u5145\uFF08\u5EFA\u8BAE\u4E00\u53E5\u8BDD\uFF09\uFF0C\u957F\u89E3\u91CA\u5199\u8FDB\u8C03\u7528\u524D\u7684\u56DE\u590D\u6587\u672C\u3002"
889
- },
890
- recommended: {
891
- type: "boolean",
892
- description: "\u63A8\u8350\u9879\u6807\u8BB0\uFF08\u7F6E true \u6807\u63A8\u8350\uFF0C\u65E0\u5219\u7701\u7565\uFF09\u3002"
893
- },
894
- userMessage: { type: "string" }
895
- },
896
- required: ["id", "label"]
897
- }
898
- },
899
- multiSelect: {
900
- type: "boolean",
901
- description: "\u5141\u8BB8\u591A\u9009\uFF0C\u9ED8\u8BA4 false\u3002"
902
- },
903
- allowOther: {
904
- type: "boolean",
905
- description: "\u663E\u793A\u201C\u5176\u4ED6\u201D\u81EA\u7531\u8F93\u5165\u884C\uFF0C\u9ED8\u8BA4 true\u3002"
906
- },
907
- required: {
908
- type: "boolean",
909
- description: "\u662F\u5426\u5FC5\u987B\u56DE\u7B54\u624D\u80FD\u63D0\u4EA4\uFF0C\u9ED8\u8BA4 true\u3002"
910
- }
911
- },
912
- required: ["id", "question", "choices"]
913
- }
914
- },
915
- blocking: {
916
- type: "boolean",
917
- description: "\u662F\u5426\u7B49\u5F85\u7528\u6237\u9009\u62E9\u540E\u518D\u7EE7\u7EED\u6D41\u7A0B\uFF0C\u9ED8\u8BA4 true\u3002"
918
- }
919
- },
920
- required: []
921
- }
922
- };
923
- async function uiAskChoiceFunc(args, _thunkApi) {
924
- const blocking = args?.blocking !== false;
925
- if (Array.isArray(args?.questions) && args.questions.length > 0) {
926
- const firstQ = args.questions[0];
927
- return {
928
- rawData: {
929
- type: "ask_user",
930
- question: firstQ?.question ?? "",
931
- choices: firstQ?.choices ?? [],
932
- blocking,
933
- questions: args.questions
934
- },
935
- displayData: args.questions.map((q) => q.question).join(" / ")
936
- };
937
- }
938
- const question = String(args?.question ?? "").trim();
939
- const choices = Array.isArray(args?.choices) ? args.choices : [];
940
- if (!question || choices.length === 0) {
941
- throw new Error("ask_user \u9700\u8981 question+choices \u6216 questions\u3002");
942
- }
943
- return {
944
- rawData: {
945
- type: "ask_user",
946
- question,
947
- choices,
948
- blocking
949
- },
950
- displayData: question
951
- };
952
- }
953
- function parseUiAskChoiceContent(rawContent) {
954
- const parsed = typeof rawContent === "string" ? (() => {
955
- try {
956
- return JSON.parse(rawContent);
957
- } catch {
958
- return null;
959
- }
960
- })() : rawContent;
961
- if (!parsed || typeof parsed !== "object") return null;
962
- if (parsed.type !== "ask_user") return null;
963
- return parsed;
964
- }
965
-
966
- // packages/ai/policy/personalizationDialog.ts
967
- var PERSONALIZATION_DIALOG_CATEGORY = "user-overlay-profile";
968
- var PERSONALIZATION_DIALOG_EXTRA_TOOLS = [
969
- "ask_user",
970
- "updateUserPreferenceProfile"
971
- ];
972
- var buildPersonalizationRuntimeOptions = (runtimeOptions) => ({
973
- ...runtimeOptions,
974
- extraTools: Array.from(
975
- /* @__PURE__ */ new Set([
976
- ...runtimeOptions?.extraTools ?? [],
977
- ...PERSONALIZATION_DIALOG_EXTRA_TOOLS
978
- ])
979
- )
980
- });
981
- var buildPersonalizationDialogPolicyContext = () => [
982
- "\u5F53\u524D\u5BF9\u8BDD\u662F\u201C\u7528\u6237\u4E2A\u6027\u5316\u8BBE\u7F6E\u201D\u6A21\u5F0F\uFF0C\u4E0D\u662F\u666E\u901A\u95F2\u804A\u3002",
983
- "\u4F60\u7684\u76EE\u6807\u662F\u7528\u7B80\u77ED\u5BF9\u8BDD\u5E2E\u52A9\u7528\u6237\u786E\u8BA4 tone\u3001knowledge_capture\u3001space_context \u8FD9\u4E09\u9879\u504F\u597D\u3002",
984
- "\u5982\u679C\u7528\u6237\u5148\u4ECB\u7ECD\u81EA\u5DF1\u3001\u5DE5\u4F5C\u65B9\u5F0F\u6216\u957F\u671F\u6C9F\u901A\u504F\u597D\uFF0C\u8BF7\u628A\u8FD9\u4E9B\u53EF\u590D\u7528\u4FE1\u606F\u6574\u7406\u6210\u7B80\u6D01\u7684 globalPrompt \u8349\u6848\uFF0C\u5E76\u5728\u7528\u6237\u786E\u8BA4\u540E\u901A\u8FC7 updateUserPreferenceProfile \u4FDD\u5B58\u3002",
985
- "\u4F18\u5148\u4E00\u6B21\u53EA\u95EE\u4E00\u4E2A\u95EE\u9898\uFF1B\u5F53\u5B58\u5728\u6E05\u6670\u4E92\u65A5\u9009\u9879\u65F6\uFF0C\u4F18\u5148\u8C03\u7528 ask_user\u3002",
986
- "\u6536\u96C6\u5230\u8DB3\u591F\u4FE1\u606F\u540E\uFF0C\u8C03\u7528 updateUserPreferenceProfile \u4FDD\u5B58\u7ED3\u679C\uFF0C\u7136\u540E\u7528\u81EA\u7136\u8BED\u8A00\u603B\u7ED3\u5DF2\u4FDD\u5B58\u7684\u8BBE\u7F6E\u3002",
987
- "\u4FDD\u5B58\u5B8C\u6210\u540E\uFF0C\u8981\u63D0\u9192\u7528\u6237\uFF1A\u4EE5\u540E\u4E5F\u53EF\u4EE5\u5728\u8BBE\u7F6E\u91CC\u4FEE\u6539 globalPrompt \u548C\u8FD9\u4E9B\u504F\u597D\uFF0C\u6216\u8005\u518D\u6B21\u6253\u5F00\u8FD9\u4E2A\u5165\u53E3\u7EE7\u7EED\u8C03\u6574\u3002",
988
- "\u4E2A\u6027\u5316\u8BBE\u7F6E\u5B8C\u6210\u540E\uFF0C\u53EF\u987A\u624B\u5F15\u5BFC\u7528\u6237\u5C1D\u8BD5 1 \u5230 2 \u4E2A\u76F8\u5173\u529F\u80FD\uFF0C\u4F8B\u5982\u9996\u9875\u5FEB\u6377\u5BF9\u8BDD\u3001\u521B\u5EFA\u7B14\u8BB0\u3001\u521B\u5EFA AI\uFF0C\u4F46\u4E0D\u8981\u4E00\u6B21\u63A8\u8350\u592A\u591A\u3002",
989
- "\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\uFF0C\u5426\u5219\u4E0D\u8981\u521B\u5EFA\u6587\u6863\uFF0C\u4E0D\u8981\u521B\u5EFA\u6216\u4FEE\u6539\u4EFB\u4F55 agent\u3002"
990
- ].join("\n");
991
-
992
- // packages/agent-runtime/builtinPlatformAgentRoute.ts
993
- function resolveBuiltinAgentRuntimeFields(agentKey) {
994
- if (!isBuiltinPlatformAgentKey(agentKey)) return null;
995
- const entry = builtinAgentCatalogEntryById(parsePublicAgentId(agentKey));
996
- if (!entry) return null;
997
- return { provider: entry.provider, model: entry.model };
998
- }
999
-
1000
- // packages/agent-runtime/builtinPlatformAgentConfigs.ts
1001
- function buildConfig(e) {
1002
- const key = publicAgentKey(e.id);
1003
- const rawRecord = {
1004
- dbKey: key,
1005
- isPublic: true,
1006
- provider: e.provider,
1007
- model: e.model,
1008
- apiSource: e.apiSource ?? "platform",
1009
- useServerProxy: e.useServerProxy ?? true
1010
- };
1011
- if (e.hasImageOutput) rawRecord.hasImageOutput = true;
1012
- if (e.imageModel) rawRecord.imageModel = e.imageModel;
1013
- if (e.imageWorkflow) rawRecord.imageWorkflow = e.imageWorkflow;
1014
- if (e.imageConfig) rawRecord.imageConfig = e.imageConfig;
1015
- return {
1016
- key,
1017
- name: e.name,
1018
- provider: e.provider,
1019
- model: e.model,
1020
- apiSource: e.apiSource ?? "platform",
1021
- useServerProxy: e.useServerProxy ?? true,
1022
- rawRecord
1023
- };
1024
- }
1025
- var BUILTIN_PLATFORM_AGENT_CONFIGS = Object.fromEntries(
1026
- builtinRuntimeFallbackEntries().map((e) => [publicAgentKey(e.id), buildConfig(e)])
1027
- );
1028
- function resolveBuiltinPlatformAgentConfig(agentRef) {
1029
- return BUILTIN_PLATFORM_AGENT_CONFIGS[agentRef] ?? null;
1030
- }
1031
- function resolveBuiltinPlatformAgentRecord(agentRef) {
1032
- const config = resolveBuiltinPlatformAgentConfig(agentRef);
1033
- if (!config) return null;
1034
- return {
1035
- ...config.rawRecord,
1036
- dbKey: agentRef,
1037
- ...config.name ? { name: config.name } : {}
1038
- };
1039
- }
1040
- function applyBuiltinAgentRuntimeOverride(agentKey, record) {
1041
- const fields = resolveBuiltinAgentRuntimeFields(agentKey);
1042
- if (!fields) return record;
1043
- const current = record;
1044
- const rawNeedsOverride = current.rawRecord != null && (current.rawRecord.provider !== fields.provider || current.rawRecord.model !== fields.model);
1045
- if (current.provider === fields.provider && current.model === fields.model && !rawNeedsOverride) {
1046
- return record;
1047
- }
1048
- return {
1049
- ...record,
1050
- provider: fields.provider,
1051
- model: fields.model,
1052
- ...current.rawRecord ? {
1053
- rawRecord: {
1054
- ...current.rawRecord,
1055
- provider: fields.provider,
1056
- model: fields.model
1057
- }
1058
- } : {}
1059
- };
1060
- }
1061
-
1062
- // packages/chat/dialog/dialogAgentPolicy.ts
1063
- var resolveDialogAgentMode = (dialog) => {
1064
- if (dialog?.agentMode === "auto") return "auto";
1065
- if (dialog?.agentMode === "fixed") return "fixed";
1066
- return getActiveDialogAgentId(dialog) ? "fixed" : "auto";
1067
- };
1068
- var isAutoDialog = (dialog) => resolveDialogAgentMode(dialog) === "auto";
1069
- var resolveDialogAutoTier = (dialog) => {
1070
- const tier = asOptionalTrimmedString(dialog?.autoRoute?.stickyTier);
1071
- if (tier === "image") return "flash";
1072
- return tier === "flash" || tier === "balanced" || tier === "quality" ? tier : void 0;
1073
- };
1074
- var resolveDialogRuntimeAgentKey = (dialog, explicitAgentKey) => {
1075
- const explicit = asOptionalTrimmedString(explicitAgentKey);
1076
- if (explicit) return explicit;
1077
- if (resolveDialogAgentMode(dialog) === "fixed") {
1078
- const fixed = getActiveDialogAgentId(dialog);
1079
- if (fixed) return fixed;
1080
- }
1081
- return resolveAutoExecutionProfile(
1082
- resolveDialogAutoTier(dialog) ?? DEFAULT_AUTO_EXECUTION_PROFILE.tier
1083
- ).legacyAgentKey;
1084
- };
1085
- var resolveDialogRuntimeAgentConfig = (dialog, explicitAgentKey) => {
1086
- if (!isAutoDialog(dialog)) return null;
1087
- const key = resolveDialogRuntimeAgentKey(dialog, explicitAgentKey);
1088
- return resolveBuiltinPlatformAgentRecord(key) ?? null;
1089
- };
1090
-
1091
- // packages/chat/dialog/actions/handleSendMessageResolver.ts
1092
- function resolveHandleSendMessageContext(input) {
1093
- const { dialogConfig, targetAgentKey, runtimeOptions } = input;
1094
- return {
1095
- agentKeyToUse: resolveDialogRuntimeAgentKey(dialogConfig, targetAgentKey),
1096
- agentConfigToUse: resolveDialogRuntimeAgentConfig(dialogConfig, targetAgentKey) ?? void 0,
1097
- effectiveRuntimeOptions: dialogConfig.category === PERSONALIZATION_DIALOG_CATEGORY ? buildPersonalizationRuntimeOptions(runtimeOptions ?? {}) : runtimeOptions
1098
- };
1099
- }
1100
-
1101
- // packages/chat/messages/resolveMessageOwner.ts
1102
- var resolveMessageOwner = (input) => {
1103
- const dialogConfigUserId = asOptionalTrimmedString(input.dialogConfigUserId) ?? null;
1104
- const currentAccountUserId = asOptionalTrimmedString(input.currentAccountUserId) ?? null;
1105
- const resolvedKeyOwner = parseOwnerUserIdFromDbKey(input.dialogKey, {
1106
- candidateOwnerUserIds: [dialogConfigUserId, currentAccountUserId, "local"]
1107
- });
1108
- return dialogConfigUserId ?? resolvedKeyOwner ?? currentAccountUserId ?? "local";
1109
- };
1110
-
1111
- // packages/chat/messages/messageUserPersistAssemble.ts
1112
- function assemblePersistedUserMessage(input) {
1113
- const {
1114
- message,
1115
- dialogId,
1116
- dialogKey,
1117
- currentAccountUserId,
1118
- dialogConfigUserId
1119
- } = input;
1120
- const userId = resolveMessageOwner({
1121
- dialogConfigUserId,
1122
- dialogKey,
1123
- currentAccountUserId
1124
- });
1125
- const { key: messageDbKey, messageId } = createDialogMessageKeyAndId(
1126
- dialogId
1127
- );
1128
- const fullMessage = {
1129
- ...message,
1130
- id: messageId,
1131
- dbKey: messageDbKey,
1132
- userId
1133
- };
1134
- return { fullMessage, dialogId, dialogKey };
1135
- }
1136
-
1137
- // packages/chat/messages/messageStreamEndAssemble.ts
1138
- function assembleFinalAssistantMessage(input) {
1139
- const {
1140
- messageId,
1141
- msgKey,
1142
- finalVisibleContent,
1143
- thinkContent,
1144
- agentConfig,
1145
- finalUsageData,
1146
- toolCalls,
1147
- finishReason,
1148
- otherPersistedMessageMetadata,
1149
- finalMetadata,
1150
- agentName,
1151
- userId
1152
- } = input;
1153
- const message = {
1154
- id: messageId,
1155
- dbKey: msgKey,
1156
- content: finalVisibleContent,
1157
- thinkContent,
1158
- role: "assistant",
1159
- agentKey: agentConfig.dbKey,
1160
- cybotKey: agentConfig.dbKey,
1161
- usage: finalUsageData,
1162
- isStreaming: false,
1163
- ...otherPersistedMessageMetadata,
1164
- ...finalMetadata ? { metadata: finalMetadata } : {},
1165
- ...agentName ? { agentName } : {},
1166
- ...toolCalls && toolCalls.length > 0 ? { tool_calls: toolCalls } : {},
1167
- // finishReason: 只存需要用户知道的值。
1168
- // "stop" 是正常结束,丢弃;null/undefined 也丢弃,避免写 undefined 进记录。
1169
- // 保留 "length" / "content_filter" / "tool_calls",让界面能据此提示截断。
1170
- ...finishReason && finishReason !== "stop" ? { finishReason } : {},
1171
- // Authoritative owner last so metadata cannot overwrite it.
1172
- userId
1173
- };
1174
- message.isStreaming = false;
1175
- message.userId = userId;
1176
- return message;
1177
- }
1178
-
1179
- // packages/chat/messages/messageStreamApply.ts
1180
- function applyMessageStreamingUpsert(existing, chunk) {
1181
- const merged = {
1182
- isStreaming: true,
1183
- content: "",
1184
- thinkContent: "",
1185
- ...chunk
1186
- };
1187
- merged.isStreaming = true;
1188
- if (existing && existing.role === "assistant" && merged.role === "assistant" && typeof existing.content === "string" && existing.content.length > 0 && typeof merged.content === "string" && merged.content.length < existing.content.length && existing.content.startsWith(merged.content)) {
1189
- merged.content = existing.content;
1190
- }
1191
- if (existing && existing.role === "assistant" && merged.role === "assistant" && typeof existing.thinkContent === "string" && existing.thinkContent.length > 0 && typeof merged.thinkContent === "string" && merged.thinkContent.length < existing.thinkContent.length && existing.thinkContent.startsWith(merged.thinkContent)) {
1192
- merged.thinkContent = existing.thinkContent;
1193
- }
1194
- return merged;
1195
- }
1196
-
1197
- // packages/ai/token/missingUsageEstimate.ts
1198
- var APPROX_CHARS_PER_TOKEN = 4;
1199
- var stringifyContent = (content) => {
1200
- if (typeof content === "string") return content;
1201
- if (Array.isArray(content)) {
1202
- return content.map((part) => {
1203
- if (typeof part === "string") return part;
1204
- if (part && typeof part === "object" && "text" in part) {
1205
- return String(part.text ?? "");
1206
- }
1207
- return "";
1208
- }).join("\n");
1209
- }
1210
- if (content == null) return "";
1211
- return String(content);
1212
- };
1213
- var estimateMissingUsage = ({
1214
- content,
1215
- minimumOutputTokens = 1
1216
- }) => {
1217
- const text = stringifyContent(content);
1218
- const estimatedOutputTokens = Math.max(
1219
- minimumOutputTokens,
1220
- Math.ceil(text.length / APPROX_CHARS_PER_TOKEN)
1221
- );
1222
- return {
1223
- input_tokens: 0,
1224
- output_tokens: estimatedOutputTokens,
1225
- cache_creation_input_tokens: 0,
1226
- cache_read_input_tokens: 0,
1227
- billing_estimated: true
1228
- };
1229
- };
1230
-
1231
- // packages/ai/token/openaiImageGenerationUsage.ts
1232
- var isOpenAIBuiltInImageGenerationAgent = (agentConfig) => String(agentConfig?.provider || "").toLowerCase() === "openai" && !getModelInfo(String(agentConfig?.model || ""))?.hasImageOutput && !!agentConfig?.imageConfig?.enabled;
1233
- var withImageGenerationCount = (usage, imageGenerationCount) => {
1234
- if (!usage || !Number.isFinite(imageGenerationCount) || imageGenerationCount <= 0) {
1235
- return usage;
1236
- }
1237
- const existingCount = asOptionalFiniteNumber(usage.image_generation_count) ?? 0;
1238
- return {
1239
- ...usage,
1240
- image_generation_count: Math.max(existingCount, imageGenerationCount)
1241
- };
1242
- };
1243
- var countImageGenerationOutputsInContent = (content) => countImageParts(content);
1244
-
1245
- // packages/chat/messages/messageStreamEndBilling.ts
1246
- function resolveStreamEndBillingUsages(input) {
1247
- const { agentConfig, totalUsage, finalVisibleContent } = input;
1248
- const imageGenerationCount = countImageGenerationOutputsInContent(finalVisibleContent);
1249
- const billedUsage = isOpenAIBuiltInImageGenerationAgent(agentConfig) ? withImageGenerationCount(totalUsage, imageGenerationCount) : totalUsage;
1250
- const rawEstimatedUsage = estimateMissingUsage({
1251
- content: finalVisibleContent
1252
- });
1253
- const providerCallId = typeof totalUsage === "object" && totalUsage !== null ? totalUsage.provider_call_id : void 0;
1254
- const estimatedUsage = providerCallId ? { ...rawEstimatedUsage, provider_call_id: providerCallId } : rawEstimatedUsage;
1255
- const billedEstimatedUsage = isOpenAIBuiltInImageGenerationAgent(agentConfig) ? withImageGenerationCount(estimatedUsage, imageGenerationCount) : estimatedUsage;
1256
- const titleEligibleContent = serializeMessageContent(finalVisibleContent, "[\u56FE\u7247]") ?? "";
1257
- const hasReportedTokens = Boolean(
1258
- totalUsage && typeof totalUsage === "object" && ([
1259
- "prompt_tokens",
1260
- "completion_tokens",
1261
- "total_tokens",
1262
- "input_tokens",
1263
- "output_tokens"
1264
- ].some((field) => Object.prototype.hasOwnProperty.call(totalUsage, field)) || Object.prototype.hasOwnProperty.call(totalUsage, "cost") && typeof totalUsage.cost === "number")
1265
- );
1266
- return {
1267
- imageGenerationCount,
1268
- billedUsage,
1269
- billedEstimatedUsage,
1270
- hasReportedUsage: hasReportedTokens,
1271
- titleEligible: titleEligibleContent.trim() !== ""
1272
- };
1273
- }
1274
-
1275
- // packages/chat/messages/web/toolDisplayName.ts
1276
- var LEGACY_VERSION_ACTIVITY_TITLES = {
1277
- \u7528\u7248\u672C\u7BA1\u7406\u68C0\u67E5\u6539\u52A8: "\u68C0\u67E5\u6539\u52A8",
1278
- \u7528\u7248\u672C\u7BA1\u7406\u67E5\u770B\u6539\u52A8: "\u67E5\u770B\u6539\u52A8",
1279
- \u7528\u7248\u672C\u7BA1\u7406\u67E5\u770B\u5386\u53F2: "\u67E5\u770B\u5386\u53F2",
1280
- \u7528\u7248\u672C\u7BA1\u7406\u6682\u5B58\u6539\u52A8: "\u6682\u5B58",
1281
- \u7528\u7248\u672C\u7BA1\u7406\u4FDD\u5B58\u6539\u52A8: "\u63D0\u4EA4",
1282
- \u7528\u7248\u672C\u7BA1\u7406\u540C\u6B65\u6539\u52A8: "\u63A8\u9001"
1283
- };
1284
- function shortenActivityTitle(title) {
1285
- const trimmed = title.trim();
1286
- if (!trimmed) return trimmed;
1287
- const mapped = LEGACY_VERSION_ACTIVITY_TITLES[trimmed];
1288
- if (mapped) return mapped;
1289
- if (trimmed.startsWith("\u7528\u7248\u672C\u7BA1\u7406")) {
1290
- const rest = trimmed.slice("\u7528\u7248\u672C\u7BA1\u7406".length).trim();
1291
- return rest || trimmed;
1292
- }
1293
- return trimmed;
1294
- }
1295
- function extractToolCallArgs(toolPayload) {
1296
- if (isRecord(toolPayload?.input)) {
1297
- return toolPayload.input;
1298
- }
1299
- const rawArguments = toolPayload?.rawToolCall;
1300
- if (isRecord(rawArguments)) {
1301
- const fn = rawArguments.function;
1302
- if (isRecord(fn)) {
1303
- const argumentsText = asTrimmedString(fn.arguments);
1304
- if (argumentsText) {
1305
- const parsed = asOptionalJsonRecord(argumentsText);
1306
- if (parsed) return parsed;
1307
- }
1308
- }
1309
- }
1310
- return void 0;
1311
- }
1312
- var SHELL_COMMAND_CLASSIFIERS = [
1313
- {
1314
- pattern: /\bgit\s+(status)\b/,
1315
- label: () => "\u68C0\u67E5\u6539\u52A8"
1316
- },
1317
- {
1318
- pattern: /\bgit\s+diff\b/,
1319
- label: () => "\u67E5\u770B\u6539\u52A8"
1320
- },
1321
- {
1322
- pattern: /\bgit\s+log\b/,
1323
- label: () => "\u67E5\u770B\u5386\u53F2"
1324
- },
1325
- {
1326
- pattern: /\bgit\s+add\b/,
1327
- label: () => "\u6682\u5B58"
1328
- },
1329
- {
1330
- pattern: /\bgit\s+commit\b/,
1331
- label: () => "\u63D0\u4EA4"
1332
- },
1333
- {
1334
- pattern: /\bgit\s+push\b/,
1335
- label: () => "\u63A8\u9001"
1336
- },
1337
- {
1338
- pattern: /\bgit\s+pull\b/,
1339
- label: () => "\u62C9\u53D6"
1340
- },
1341
- {
1342
- pattern: /\bgit\s+fetch\b/,
1343
- label: () => "\u83B7\u53D6\u66F4\u65B0"
1344
- },
1345
- {
1346
- pattern: /\bgit\s+checkout\b|\bgit\s+switch\b/,
1347
- label: () => "\u5207\u6362\u5206\u652F"
1348
- },
1349
- {
1350
- pattern: /\bgit\s+branch\b/,
1351
- label: () => "\u67E5\u770B\u5206\u652F"
1352
- },
1353
- {
1354
- pattern: /\bgit\s+stash\b/,
1355
- label: () => "\u8D2E\u85CF"
1356
- },
1357
- {
1358
- pattern: /\bgit\s+merge\b/,
1359
- label: () => "\u5408\u5E76"
1360
- },
1361
- {
1362
- pattern: /\bgit\s+rebase\b/,
1363
- label: () => "\u53D8\u57FA"
1364
- },
1365
- {
1366
- pattern: /\bgit\s+clone\b/,
1367
- label: () => "\u514B\u9686"
1368
- },
1369
- {
1370
- pattern: /\bgit\s+remote\b/,
1371
- label: () => "\u8FDC\u7A0B"
1372
- },
1373
- {
1374
- pattern: /\bgit\s+reset\b/,
1375
- label: () => "\u91CD\u7F6E"
1376
- },
1377
- {
1378
- pattern: /\bgit\s+restore\b/,
1379
- label: () => "\u8FD8\u539F"
1380
- },
1381
- {
1382
- pattern: /\bgit\b/,
1383
- label: () => "\u7248\u672C\u64CD\u4F5C"
1384
- },
1385
- {
1386
- pattern: /\b(rg|grep)\b/,
1387
- label: (cmd) => {
1388
- const match = cmd.match(/(?:rg|grep)\s+(?:-[^\s]*\s+)*['"]?([^\s'"]+)['"]?/);
1389
- return match ? `\u641C\u7D22 "${match[1]}"` : "\u641C\u7D22\u4EE3\u7801";
1390
- }
1391
- },
1392
- {
1393
- pattern: /\b(bun\s+test|jest|vitest|mocha|pytest|go\s+test)\b/,
1394
- label: () => "\u8FD0\u884C\u6D4B\u8BD5"
1395
- },
1396
- {
1397
- pattern: /\b(bun\s+run\s+build|npm\s+run\s+build|yarn\s+build|make\s+build)\b/,
1398
- label: () => "\u6784\u5EFA\u9879\u76EE"
1399
- },
1400
- {
1401
- pattern: /\b(bun\s+install|npm\s+install|yarn\s+install|pnpm\s+install)\b/,
1402
- label: () => "\u5B89\u88C5\u4F9D\u8D56"
1403
- },
1404
- {
1405
- pattern: /\b(bun\s+run\s+dev|npm\s+run\s+dev|yarn\s+dev)\b/,
1406
- label: () => "\u542F\u52A8\u5F00\u53D1\u670D\u52A1\u5668"
1407
- },
1408
- {
1409
- pattern: /\bcurl\b/,
1410
- label: (cmd) => {
1411
- const match = cmd.match(/curl\s+(?:-[^\s]*\s+)*(https?:\/\/[^\s'"]+)/);
1412
- return match ? `\u8BF7\u6C42 ${match[1]}` : "\u53D1\u9001 HTTP \u8BF7\u6C42";
1413
- }
1414
- },
1415
- {
1416
- pattern: /\blsof\b/,
1417
- label: () => "\u67E5\u770B\u7AEF\u53E3\u5360\u7528"
1418
- }
1419
- ];
1420
- function classifyShellCommand(command) {
1421
- const trimmed = command.trim();
1422
- for (const { pattern, label } of SHELL_COMMAND_CLASSIFIERS) {
1423
- if (pattern.test(trimmed)) return label(trimmed);
1424
- }
1425
- return "\u8FD0\u884C\u547D\u4EE4";
1426
- }
1427
- function buildFallbackActivity(toolName, args) {
1428
- const normalized = asTrimmedString(toolName);
1429
- if (!normalized || !args) return void 0;
1430
- switch (normalized) {
1431
- case "readFile": {
1432
- const path = asTrimmedString(args.path);
1433
- return path ? { title: "\u67E5\u770B\u76F8\u5173\u6587\u4EF6", refs: [{ type: "file", path }] } : void 0;
1434
- }
1435
- case "writeFile": {
1436
- const path = asTrimmedString(args.path);
1437
- return path ? { title: "\u5199\u5165\u6587\u4EF6", refs: [{ type: "file", path }] } : void 0;
1438
- }
1439
- case "editFile": {
1440
- const path = asTrimmedString(args.path);
1441
- return path ? { title: "\u4FEE\u6539\u6587\u4EF6", refs: [{ type: "file", path }] } : void 0;
1442
- }
1443
- case "codeSearch":
1444
- case "code_search": {
1445
- const query = asTrimmedString(args.query);
1446
- return query ? { title: "\u5728\u4EE3\u7801\u91CC\u627E\u7EBF\u7D22", detail: query } : void 0;
1447
- }
1448
- case "globFiles": {
1449
- const pattern = asTrimmedString(
1450
- typeof args.pattern === "string" ? args.pattern : args.glob
1451
- );
1452
- return pattern ? { title: "\u67E5\u627E\u76F8\u5173\u6587\u4EF6", detail: pattern } : void 0;
1453
- }
1454
- case "loadSkill": {
1455
- const name = asTrimmedString(args.name);
1456
- return name ? { title: "\u52A0\u8F7D\u6280\u80FD", detail: name } : void 0;
1457
- }
1458
- case "execShell": {
1459
- const command = asTrimmedString(
1460
- typeof args.cmd === "string" ? args.cmd : args.command
1461
- );
1462
- if (!command) return void 0;
1463
- const label = classifyShellCommand(command);
1464
- return { title: label, detail: command.length <= 120 ? command : `${command.slice(0, 117)}...` };
1465
- }
1466
- default:
1467
- return void 0;
1468
- }
1469
- }
1470
- function normalizeString(value) {
1471
- return asOptionalTrimmedString(value);
1472
- }
1473
- function normalizeStatus(value) {
1474
- return value === "pending" || value === "running" || value === "success" || value === "failed" ? value : void 0;
1475
- }
1476
- function normalizeKind(value) {
1477
- return value === "read" || value === "write" || value === "edit" || value === "search" || value === "terminal" || value === "version" || value === "test" || value === "build" || value === "preview" || value === "other" ? value : void 0;
1478
- }
1479
- function normalizeRefs(value) {
1480
- if (!Array.isArray(value)) return void 0;
1481
- const refs = value.flatMap((item) => {
1482
- if (!isRecord(item)) return [];
1483
- if (item.type === "file") {
1484
- const path = normalizeString(item.path);
1485
- return path ? [{ type: "file", path }] : [];
1486
- }
1487
- if (item.type === "terminal") {
1488
- const id = normalizeString(item.id);
1489
- const label = normalizeString(item.label);
1490
- return id || label ? [{ type: "terminal", ...id ? { id } : {}, ...label ? { label } : {} }] : [];
1491
- }
1492
- if (item.type === "url") {
1493
- const url = normalizeString(item.url);
1494
- const label = normalizeString(item.label);
1495
- return url ? [{ type: "url", url, ...label ? { label } : {} }] : [];
1496
- }
1497
- return [];
1498
- });
1499
- return refs.length ? refs : void 0;
1500
- }
1501
- function normalizeActivityAction(value) {
1502
- if (!isRecord(value)) return void 0;
1503
- const title = normalizeString(value.title);
1504
- if (!title) return void 0;
1505
- const detail = normalizeString(value.detail);
1506
- const kind = normalizeKind(value.kind);
1507
- const refs = normalizeRefs(value.refs);
1508
- return {
1509
- title: shortenActivityTitle(title),
1510
- ...kind ? { kind } : {},
1511
- ...detail ? { detail } : {},
1512
- ...refs ? { refs } : {}
1513
- };
1514
- }
1515
- function normalizeActivityPhase(value) {
1516
- if (!isRecord(value)) return void 0;
1517
- const title = normalizeString(value.title);
1518
- if (!title) return void 0;
1519
- const id = normalizeString(value.id) || title.toLowerCase().replace(/\s+/g, "-");
1520
- const index = asOptionalFiniteNumber(value.index);
1521
- const total = asOptionalFiniteNumber(value.total);
1522
- const status = normalizeStatus(value.status);
1523
- return {
1524
- id,
1525
- title,
1526
- ...index !== void 0 ? { index } : {},
1527
- ...total !== void 0 ? { total } : {},
1528
- ...status ? { status } : {}
1529
- };
1530
- }
1531
- function normalizeActivityPlan(value) {
1532
- if (!isRecord(value)) return void 0;
1533
- if (!Array.isArray(value.phases)) return void 0;
1534
- const phases = value.phases.flatMap((item, index) => {
1535
- const phase = normalizeActivityPhase(item);
1536
- if (!phase) return [];
1537
- return [{
1538
- id: phase.id,
1539
- title: phase.title,
1540
- index: phase.index ?? index + 1,
1541
- ...phase.status ? { status: phase.status } : {}
1542
- }];
1543
- });
1544
- if (phases.length === 0) return void 0;
1545
- const title = normalizeString(value.title);
1546
- return {
1547
- ...title ? { title } : {},
1548
- phases
1549
- };
1550
- }
1551
- function normalizeActivitySignal(value) {
1552
- if (!isRecord(value)) return void 0;
1553
- const nestedAction = normalizeActivityAction(value.action);
1554
- const legacyAction = normalizeActivityAction(value);
1555
- const action2 = nestedAction || legacyAction;
1556
- const phase = normalizeActivityPhase(value.phase);
1557
- const plan = normalizeActivityPlan(value.plan);
1558
- if (!action2 && !phase && !plan) return void 0;
1559
- return {
1560
- ...action2 ? { action: action2 } : {},
1561
- ...phase ? { phase } : {},
1562
- ...plan ? { plan } : {}
1563
- };
1564
- }
1565
- function normalizeToolActivity(value) {
1566
- const signal = normalizeActivitySignal(value);
1567
- if (!signal?.action) return void 0;
1568
- return {
1569
- ...signal.action,
1570
- ...signal.phase ? { phase: signal.phase } : {},
1571
- ...signal.action ? { action: signal.action } : {},
1572
- ...signal.plan ? { plan: signal.plan } : {}
1573
- };
1574
- }
1575
- function formatActivityAction(activity) {
1576
- const firstRef = activity.refs?.[0];
1577
- const refLabel = firstRef?.type === "file" ? firstRef.path : firstRef?.type === "terminal" ? firstRef.label || firstRef.id : firstRef?.type === "url" ? firstRef.label || firstRef.url : void 0;
1578
- const suffix = refLabel || activity.detail;
1579
- return suffix ? `${activity.title} \xB7 ${suffix}` : activity.title;
1580
- }
1581
- function getMessageStatus(msg) {
1582
- const rawData = typeof msg?.content === "string" ? asOptionalJsonRecord(msg.content) : msg?.content;
1583
- const isError = msg?.toolPayload?.status === "failed" || !!msg?.toolPayload?.error || !!rawData?.error;
1584
- if (msg?.isStreaming || msg?.toolPayload?.status === "running") return "running";
1585
- if (isError) return "failed";
1586
- if (msg?.toolPayload?.status === "pending") return "pending";
1587
- return "success";
1588
- }
1589
- function mergeStatuses(current, next) {
1590
- if (current === "running" || next === "running") return "running";
1591
- if (current === "failed" || next === "failed") return "failed";
1592
- if (current === "pending" || next === "pending") return "pending";
1593
- return "success";
1594
- }
1595
- function readMessageActivitySignal(msg) {
1596
- const meta = msg.metadata;
1597
- const explicit = normalizeActivitySignal(meta?.activity) || normalizeActivitySignal(msg.toolPayload?.activity);
1598
- if (explicit) return explicit;
1599
- const parsedArgs = tryParseToolArgs(msg);
1600
- const fallback = buildFallbackActivity(msg.toolName, parsedArgs);
1601
- const fallbackActivity = fallback ? normalizeToolActivity(fallback) : void 0;
1602
- return fallbackActivity ? {
1603
- action: fallbackActivity.action || fallbackActivity,
1604
- ...fallbackActivity.phase ? { phase: fallbackActivity.phase } : {},
1605
- ...fallbackActivity.plan ? { plan: fallbackActivity.plan } : {}
1606
- } : void 0;
1607
- }
1608
- function readMessageActivityPlan(msg) {
1609
- const meta = msg.metadata;
1610
- const metadataActivity = isRecord(meta?.activity) ? meta.activity : void 0;
1611
- const payloadActivity = isRecord(msg.toolPayload?.activity) ? msg.toolPayload.activity : void 0;
1612
- return normalizeActivitySignal(metadataActivity)?.plan || normalizeActivitySignal(payloadActivity)?.plan;
1613
- }
1614
- function buildActivityTimeline(messages, activityPlan, options = {}) {
1615
- const phases = [];
1616
- const phaseById = /* @__PURE__ */ new Map();
1617
- let implicitPhase;
1618
- let declaredTotal = 0;
1619
- const includePlan = options.includePlan !== false;
1620
- const declaredPlan = includePlan ? normalizeActivityPlan(activityPlan) || messages.map(readMessageActivityPlan).find(Boolean) : void 0;
1621
- const ensurePlanPhase = (phaseDef) => {
1622
- let phase = phaseById.get(phaseDef.id);
1623
- if (!phase) {
1624
- phase = {
1625
- id: phaseDef.id,
1626
- title: phaseDef.title,
1627
- ...phaseDef.index !== void 0 ? { index: phaseDef.index } : {},
1628
- ...declaredPlan ? { total: declaredPlan.phases.length } : {},
1629
- status: phaseDef.status || "pending",
1630
- actions: []
1631
- };
1632
- phaseById.set(phaseDef.id, phase);
1633
- phases.push(phase);
1634
- }
1635
- return phase;
1636
- };
1637
- if (declaredPlan) {
1638
- declaredTotal = declaredPlan.phases.length;
1639
- for (const phaseDef of declaredPlan.phases) {
1640
- ensurePlanPhase(phaseDef);
1641
- }
1642
- }
1643
- for (const msg of messages) {
1644
- const signal = readMessageActivitySignal(msg);
1645
- if (!signal) continue;
1646
- if (includePlan && !declaredPlan && signal.plan) {
1647
- declaredTotal = Math.max(declaredTotal, signal.plan.phases.length);
1648
- for (const phaseDef2 of signal.plan.phases) {
1649
- ensurePlanPhase(phaseDef2);
1650
- }
1651
- }
1652
- const status = getMessageStatus(msg);
1653
- const activityAction = signal.action;
1654
- const phaseDef = signal.phase;
1655
- if (!activityAction && !phaseDef) continue;
1656
- const phaseId = phaseDef?.id || "__implicit_tools__";
1657
- const phaseTitle = phaseDef?.title || "\u6267\u884C\u5DE5\u5177\u6B65\u9AA4";
1658
- const phaseStatus = phaseDef?.status || (activityAction ? status : "pending");
1659
- let phase = phaseById.get(phaseId);
1660
- if (!phase) {
1661
- phase = {
1662
- id: phaseId,
1663
- title: phaseTitle,
1664
- ...phaseDef?.index !== void 0 ? { index: phaseDef.index } : {},
1665
- ...phaseDef?.total !== void 0 ? { total: phaseDef.total } : {},
1666
- status: phaseStatus,
1667
- actions: []
1668
- };
1669
- phaseById.set(phaseId, phase);
1670
- phases.push(phase);
1671
- if (!phaseDef) implicitPhase = phase;
1672
- } else {
1673
- phase.status = mergeStatuses(phase.status, phaseStatus);
1674
- if (phase.status === "pending") {
1675
- phase.status = phaseStatus;
1676
- }
1677
- }
1678
- if (phaseDef?.total && phaseDef.total > declaredTotal) {
1679
- declaredTotal = phaseDef.total;
1680
- }
1681
- if (activityAction) {
1682
- const action2 = {
1683
- ...activityAction,
1684
- id: normalizeString(msg.id) || normalizeString(msg.dbKey) || normalizeString(msg.toolCallId) || normalizeString(msg.tool_call_id) || `tool-action-${phase.actions.length + 1}`,
1685
- label: formatActivityAction(activityAction),
1686
- status,
1687
- message: msg
1688
- };
1689
- phase.actions.push(action2);
1690
- }
1691
- }
1692
- if (implicitPhase && phases.length > 1 && implicitPhase.actions.length === 0) {
1693
- phaseById.delete(implicitPhase.id);
1694
- }
1695
- const completedPhases = phases.filter((phase) => phase.status === "success").length;
1696
- return {
1697
- phases,
1698
- completedPhases,
1699
- totalPhases: declaredTotal || phases.length
1700
- };
1701
- }
1702
- function tryParseToolArgs(msg) {
1703
- const payloadArgs = extractToolCallArgs(msg.toolPayload);
1704
- if (payloadArgs) return payloadArgs;
1705
- const meta = msg.metadata;
1706
- if (meta) {
1707
- const derived = {};
1708
- let hasField = false;
1709
- const path = normalizeString(meta.path);
1710
- if (path) {
1711
- derived.path = path;
1712
- hasField = true;
1713
- }
1714
- const command = normalizeString(meta.command);
1715
- if (command) {
1716
- derived.command = command;
1717
- hasField = true;
1718
- }
1719
- const cmd = normalizeString(meta.cmd);
1720
- if (cmd) {
1721
- derived.cmd = cmd;
1722
- hasField = true;
1723
- }
1724
- const query = normalizeString(meta.query);
1725
- if (query) {
1726
- derived.query = query;
1727
- hasField = true;
1728
- }
1729
- const pattern = normalizeString(meta.pattern);
1730
- if (pattern) {
1731
- derived.pattern = pattern;
1732
- hasField = true;
1733
- }
1734
- if (hasField) return derived;
1735
- }
1736
- const content = normalizeString(msg.content);
1737
- if (content) {
1738
- try {
1739
- const parsed = JSON.parse(content);
1740
- if (isRecord(parsed)) {
1741
- return parsed;
1742
- }
1743
- } catch {
1744
- }
1745
- }
1746
- return void 0;
1747
- }
1748
-
1749
- // packages/chat/messages/activityCompletion.ts
1750
- var FINAL_DELIVERY_PHASE_PATTERNS = [
1751
- /汇报/,
1752
- /回复/,
1753
- /总结/,
1754
- /结果/,
1755
- /交付/,
1756
- /可视化/,
1757
- /图表/,
1758
- /report/i,
1759
- /deliver/i,
1760
- /result/i,
1761
- /summary/i,
1762
- /visual/i,
1763
- /chart/i
1764
- ];
1765
- var FAILED_FINAL_CONTENT_PATTERNS = [
1766
- /抱歉/,
1767
- /无法/,
1768
- /不能/,
1769
- /失败/,
1770
- /出错/,
1771
- /未完成/,
1772
- /cannot/i,
1773
- /can't/i,
1774
- /failed/i,
1775
- /error/i,
1776
- /unable/i
1777
- ];
1778
- function isLikelyFinalDeliveryPhase(title) {
1779
- return FINAL_DELIVERY_PHASE_PATTERNS.some((pattern) => pattern.test(title));
1780
- }
1781
- function isLikelyFailedFinalContent(text) {
1782
- return FAILED_FINAL_CONTENT_PATTERNS.some((pattern) => pattern.test(text));
1783
- }
1784
- function inferAssistantActivityCompletionMetadata({
1785
- messages,
1786
- finalContent
1787
- }) {
1788
- const finalText = serializeMessageContent(finalContent, "[\u56FE\u7247]")?.trim();
1789
- if (!finalText || isLikelyFailedFinalContent(finalText)) return void 0;
1790
- const timeline = buildActivityTimeline(messages);
1791
- if (timeline.totalPhases <= 1 || timeline.completedPhases >= timeline.totalPhases) {
1792
- return void 0;
1793
- }
1794
- const finalPhase = timeline.phases[timeline.phases.length - 1];
1795
- if (!finalPhase || finalPhase.status !== "pending") return void 0;
1796
- const priorPhases = timeline.phases.slice(0, -1);
1797
- if (priorPhases.length === 0 || priorPhases.some((phase) => phase.status !== "success")) {
1798
- return void 0;
1799
- }
1800
- if (!isLikelyFinalDeliveryPhase(finalPhase.title)) return void 0;
1801
- return {
1802
- activity: {
1803
- phase: {
1804
- id: finalPhase.id,
1805
- title: finalPhase.title,
1806
- ...finalPhase.index !== void 0 ? { index: finalPhase.index } : {},
1807
- ...finalPhase.total !== void 0 ? { total: finalPhase.total } : {},
1808
- status: "success"
1809
- }
1810
- }
1811
- };
1812
- }
1813
-
1814
- // packages/chat/messages/messageStreamEndFinalMetadata.ts
1815
- function resolveStreamEndFinalMetadata(input) {
1816
- const { persistedMetadata, toolCalls, messages, finalContent } = input;
1817
- const shouldInfer = !persistedMetadata?.activity && (!toolCalls || toolCalls.length === 0);
1818
- const inferred = shouldInfer ? inferAssistantActivityCompletionMetadata({
1819
- messages,
1820
- finalContent
1821
- }) : void 0;
1822
- const finalMetadata = inferred ? { ...persistedMetadata ?? {}, ...inferred } : persistedMetadata ?? void 0;
1823
- return { finalMetadata };
1824
- }
1825
-
1826
- // packages/chat/messages/messageStreamEndPostWritePolicy.ts
1827
- function resolveStreamEndPostWritePolicy(input) {
1828
- const { hasReportedUsage, billingFailed, skipBilling, agentProvider, titleEligible, textContent, toolCalls } = input;
1829
- const billingMode = billingFailed || skipBilling ? "skip" : hasReportedUsage ? "reported" : agentProvider && agentProvider !== "custom" ? "estimated" : "skip";
1830
- const hasText = textContent.trim() !== "";
1831
- const noTools = !toolCalls || toolCalls.length === 0;
1832
- return {
1833
- billingMode,
1834
- updateTitle: titleEligible,
1835
- updateSummary: hasText,
1836
- addRefs: hasText,
1837
- summaryForce: noTools,
1838
- summaryReason: noTools ? "task_completed" : "context_budget"
1839
- };
1840
- }
1841
-
1842
- // packages/chat/messages/messageStreamEndBillingDispatch.ts
1843
- async function dispatchStreamEndBilling(input) {
1844
- const {
1845
- dispatch,
1846
- updateTokensAction: updateTokensAction2,
1847
- billingMode,
1848
- billingUsageRecords,
1849
- billedUsage,
1850
- billedEstimatedUsage,
1851
- dialogId,
1852
- dialogKey,
1853
- agentConfig
1854
- } = input;
1855
- try {
1856
- if (billingMode === "reported") {
1857
- const fallbackCallId = typeof billedUsage?.provider_call_id === "string" && billedUsage.provider_call_id.trim() ? billedUsage.provider_call_id.trim() : void 0;
1858
- const usageRecords = billingUsageRecords?.length ? billingUsageRecords : [{ callId: fallbackCallId, usage: billedUsage }];
1859
- for (const usageRecord of usageRecords) {
1860
- await dispatch(
1861
- updateTokensAction2({
1862
- dialogId,
1863
- dialogKey,
1864
- usageRecord,
1865
- agentConfig
1866
- })
1867
- ).unwrap();
1868
- }
1869
- } else if (billingMode === "estimated") {
1870
- await dispatch(
1871
- updateTokensAction2({
1872
- dialogId,
1873
- dialogKey,
1874
- usage: billedEstimatedUsage,
1875
- agentConfig
1876
- })
1877
- ).unwrap();
1878
- console.warn(
1879
- "[billing] Missing usage at messageStreamEnd; using estimated token update",
1880
- {
1881
- dialogId,
1882
- dialogKey,
1883
- provider: agentConfig.provider,
1884
- model: agentConfig.model,
1885
- endpointKey: agentConfig.endpointKey
1886
- }
1887
- );
1888
- }
1889
- } catch (billingError) {
1890
- console.error(
1891
- "[billing] updateTokens failed (best-effort, message already saved):",
1892
- billingError
1893
- );
1894
- }
1895
- }
1896
-
1897
- // packages/chat/messages/messageStreamEndPersistPrep.ts
1898
- function prepareStreamEndPersistInputs(input) {
1899
- const { totalUsage, agentConfig, messageMetadata } = input;
1900
- const completionTokens = totalUsage?.completion_tokens ?? totalUsage?.output_tokens;
1901
- const finalUsageData = totalUsage && completionTokens != null ? { completion_tokens: completionTokens } : void 0;
1902
- const agentName = asTrimmedString(agentConfig?.name) || void 0;
1903
- const {
1904
- imageGenerationState: _transientImageGenerationState,
1905
- ...persistedMessageMetadata
1906
- } = messageMetadata ?? {};
1907
- const {
1908
- metadata: persistedMetadata,
1909
- ...otherPersistedMessageMetadata
1910
- } = persistedMessageMetadata;
1911
- return {
1912
- finalUsageData,
1913
- agentName,
1914
- persistedMetadata,
1915
- otherPersistedMessageMetadata
1916
- };
1917
- }
1918
-
1919
- // packages/chat/messages/messageUnderstandingCapture.ts
1920
- function getLatestUserInputFromMessages(messages) {
1921
- for (let index = messages.length - 1; index >= 0; index -= 1) {
1922
- const message = messages[index];
1923
- if (!message || message.role !== "user") continue;
1924
- const serialized = serializeMessageContent(message.content, "[\u56FE\u7247]")?.trim();
1925
- if (serialized) return serialized;
1926
- }
1927
- return null;
1928
- }
1929
- function getDialogSpaceIdFromState(state, dialogKey) {
1930
- if (!dialogKey) return void 0;
1931
- const dialog = selectById(state, dialogKey);
1932
- return typeof dialog?.spaceId === "string" ? dialog.spaceId : void 0;
1933
- }
1934
- function resolveMemoryCaptureBaseUrl(state) {
1935
- const currentServer = typeof state?.settings?.currentServer === "string" ? state.settings.currentServer : null;
1936
- const _window = globalThis.window;
1937
- if (!_window) return (currentServer || "").replace(/\/+$/, "");
1938
- if (!currentServer) return _window.location.origin;
1939
- return currentServer.replace(/\/+$/, "");
1940
- }
1941
- async function captureUnderstandingFromCompletedUiTurn(input) {
1942
- if (input.assistantText.trim() === "") return;
1943
- if (input.toolCalls && input.toolCalls.length > 0) return;
1944
- if (!input.agentKey) return;
1945
- const latestUserInput = getLatestUserInputFromMessages(input.messages);
1946
- if (!latestUserInput) return;
1947
- const state = input.state;
1948
- const token = selectIdentityToken(state) ?? null;
1949
- const baseUrl = resolveMemoryCaptureBaseUrl(state);
1950
- if (!token || !baseUrl) return;
1951
- const dialog = input.dialogKey ? selectById(state, input.dialogKey) : void 0;
1952
- try {
1953
- await fetch(`${baseUrl}/api/memory/capture-turn`, {
1954
- method: "POST",
1955
- headers: {
1956
- "Content-Type": "application/json",
1957
- Authorization: `Bearer ${token}`
1958
- },
1959
- body: JSON.stringify({
1960
- agentKey: input.agentKey,
1961
- dialogId: input.dialogId,
1962
- userInput: latestUserInput,
1963
- assistantText: input.assistantText,
1964
- spaceId: input.spaceId ?? getDialogSpaceIdFromState(state, input.dialogKey)
1965
- })
1966
- });
1967
- } catch {
1968
- }
1969
- }
1970
-
1971
- // packages/chat/messages/messageSessionStore.ts
1972
- var import_react = __toESM(require_react());
1973
- var GLOBAL_MESSAGE_DIALOG_ID = "__global__";
1974
- var createEmptyMessageSessionState = () => ({
1975
- firstStreamProcessed: false,
1976
- isLoadingInitial: false,
1977
- isLoadingOlder: false,
1978
- hasMoreOlder: true,
1979
- error: null,
1980
- lastStreamTimestamp: 0,
1981
- currentInitMsgsRequestId: void 0,
1982
- currentLoadOlderRequestId: void 0,
1983
- streamingMessageId: null,
1984
- lastAbortTimestamp: 0
1985
- });
1986
- var activeDialogId = null;
1987
- var sessionByDialogId = {
1988
- [GLOBAL_MESSAGE_DIALOG_ID]: createEmptyMessageSessionState()
1989
- };
1990
- var listeners = /* @__PURE__ */ new Set();
1991
- var version = 0;
1992
- var notify = () => {
1993
- version += 1;
1994
- for (const listener of listeners) {
1995
- try {
1996
- listener();
1997
- } catch {
1998
- }
1999
- }
2000
- };
2001
- var action = (type, payload) => ({ type, payload });
2002
- function setActiveMessageDialogId(dialogId) {
2003
- activeDialogId = dialogId;
2004
- notify();
2005
- }
2006
- function getActiveMessageDialogId() {
2007
- return activeDialogId;
2008
- }
2009
- var resolveDialogId = (dialogId) => dialogId ?? activeDialogId ?? GLOBAL_MESSAGE_DIALOG_ID;
2010
- function ensureMessageSession(dialogId) {
2011
- const key = resolveDialogId(dialogId);
2012
- if (!sessionByDialogId[key]) {
2013
- sessionByDialogId[key] = createEmptyMessageSessionState();
2014
- }
2015
- return sessionByDialogId[key];
2016
- }
2017
- function getMessageSession(dialogId) {
2018
- return sessionByDialogId[resolveDialogId(dialogId)] ?? createEmptyMessageSessionState();
2019
- }
2020
- function patchMessageSession(dialogId, patch2) {
2021
- const session = ensureMessageSession(dialogId);
2022
- Object.assign(session, patch2);
2023
- notify();
2024
- return action("messageSession/patch", { dialogId, patch: patch2 });
2025
- }
2026
- function deleteMessageSession(dialogId) {
2027
- delete sessionByDialogId[dialogId];
2028
- if (activeDialogId === dialogId) {
2029
- activeDialogId = null;
2030
- }
2031
- if (!sessionByDialogId[GLOBAL_MESSAGE_DIALOG_ID]) {
2032
- sessionByDialogId[GLOBAL_MESSAGE_DIALOG_ID] = createEmptyMessageSessionState();
2033
- }
2034
- notify();
2035
- return action("messageSession/delete", { dialogId });
2036
- }
2037
- function resetAllMessageSessions() {
2038
- for (const key of Object.keys(sessionByDialogId)) {
2039
- delete sessionByDialogId[key];
2040
- }
2041
- sessionByDialogId[GLOBAL_MESSAGE_DIALOG_ID] = createEmptyMessageSessionState();
2042
- activeDialogId = null;
2043
- notify();
2044
- return action("messageSession/resetAll");
2045
- }
2046
- function markMessageStreamActivity(dialogId) {
2047
- const session = ensureMessageSession(dialogId);
2048
- session.firstStreamProcessed = true;
2049
- session.lastStreamTimestamp = Date.now();
2050
- notify();
2051
- return action("messageSession/streamActivity", { dialogId });
2052
- }
2053
- function markMessageSessionAbort(dialogId) {
2054
- const session = ensureMessageSession(dialogId);
2055
- session.lastAbortTimestamp = Date.now();
2056
- notify();
2057
- return action("messageSession/abort", { dialogId });
2058
- }
2059
- function setStreamingMessageId(dialogId, messageId) {
2060
- const session = ensureMessageSession(dialogId);
2061
- if (session.streamingMessageId === messageId) return;
2062
- session.streamingMessageId = messageId;
2063
- notify();
2064
- }
2065
- function getHasStreamingMessage(dialogId) {
2066
- if (dialogId === null) return false;
2067
- return !!getMessageSession(dialogId).streamingMessageId;
2068
- }
2069
- var selectCurrentDialogId = (_state) => getActiveMessageDialogId();
2070
-
2071
- // packages/chat/messages/messageSlice.ts
2072
- var OLDER_LOAD_LIMIT = 30;
2073
- var createSliceWithThunks = buildCreateSlice({
2074
- creators: { asyncThunk: asyncThunkCreator }
2075
- });
2076
- var messagesAdapter = createEntityAdapter({
2077
- selectId: (message) => message.id,
2078
- sortComparer: (a, b) => a.id.localeCompare(b.id)
2079
- });
2080
- var createEmptyMessageDialogState = () => ({
2081
- msgs: messagesAdapter.getInitialState()
2082
- });
2083
- var initialState = {
2084
- dialogStateById: {
2085
- [GLOBAL_MESSAGE_DIALOG_ID]: createEmptyMessageDialogState()
2086
- }
2087
- };
2088
- var captureUnderstandingFromCompletedUiTurn2 = async (input) => captureUnderstandingFromCompletedUiTurn({
2089
- ...input,
2090
- messages: input.messages ?? selectAllMsgs(input.state, input.dialogId)
2091
- });
2092
- var resolveMessageDialogId = (_state, dialogId, dialogKey) => dialogId ?? (dialogKey ? extractCustomId(dialogKey) : null) ?? getActiveMessageDialogId() ?? GLOBAL_MESSAGE_DIALOG_ID;
2093
- var ensureMessageDialogState = (state, dialogId, dialogKey) => {
2094
- const resolvedDialogId = resolveMessageDialogId(state, dialogId, dialogKey);
2095
- if (!state.dialogStateById) {
2096
- state.dialogStateById = {
2097
- [GLOBAL_MESSAGE_DIALOG_ID]: createEmptyMessageDialogState()
2098
- };
2099
- }
2100
- if (!state.dialogStateById[resolvedDialogId]) {
2101
- state.dialogStateById[resolvedDialogId] = createEmptyMessageDialogState();
2102
- }
2103
- return state.dialogStateById[resolvedDialogId];
2104
- };
2105
- var getMessageDialogState = (state, dialogId, dialogKey) => {
2106
- const dialogStateById = state.dialogStateById ?? {};
2107
- const resolvedDialogId = resolveMessageDialogId(state, dialogId, dialogKey);
2108
- const bucket = dialogStateById[resolvedDialogId];
2109
- if (bucket) return bucket;
2110
- const legacyMsgs = state.msgs;
2111
- if (legacyMsgs && typeof legacyMsgs === "object") {
2112
- return { msgs: legacyMsgs };
2113
- }
2114
- return createEmptyMessageDialogState();
2115
- };
2116
- var inferDialogIdFromDbKey = (dbKey) => {
2117
- if (!dbKey) return null;
2118
- const parts = dbKey.split("-");
2119
- if (parts.length >= 4 && parts[0] === "dialog" /* DIALOG */ && parts[2] === "msg") {
2120
- return parts[1];
2121
- }
2122
- return null;
2123
- };
2124
- var inferDialogIdFromMessage = (message) => message.dialogId ?? inferDialogIdFromDbKey(message.dbKey);
2125
- var findDialogIdByMessageId = (state, messageId) => {
2126
- for (const [dialogId, dialogState] of Object.entries(state.dialogStateById)) {
2127
- if (dialogState.msgs.entities[messageId]) {
2128
- return dialogId;
2129
- }
2130
- }
2131
- return null;
2132
- };
2133
- var findDialogIdByMessageDbKey = (state, dbKey) => {
2134
- for (const [dialogId, dialogState] of Object.entries(state.dialogStateById)) {
2135
- const hasDbKey = Object.values(dialogState.msgs.entities).some(
2136
- (message) => message?.dbKey === dbKey
2137
- );
2138
- if (hasDbKey) {
2139
- return dialogId;
2140
- }
2141
- }
2142
- return inferDialogIdFromDbKey(dbKey);
2143
- };
2144
- var upsertOneMessage = (dialogState, message) => {
2145
- dialogState.msgs = messagesAdapter.upsertOne(
2146
- dialogState.msgs,
2147
- normalizeHistoricalReasoningMessage(message)
2148
- );
2149
- };
2150
- var upsertManyMessages = (dialogState, messages) => {
2151
- dialogState.msgs = messagesAdapter.upsertMany(
2152
- dialogState.msgs,
2153
- messages.map(normalizeHistoricalReasoningMessage)
2154
- );
2155
- };
2156
- var addOneMessage = (dialogState, message) => {
2157
- dialogState.msgs = messagesAdapter.addOne(
2158
- dialogState.msgs,
2159
- normalizeHistoricalReasoningMessage(message)
2160
- );
2161
- };
2162
- var updateOneMessage = (dialogState, payload) => {
2163
- dialogState.msgs = messagesAdapter.updateOne(dialogState.msgs, payload);
2164
- };
2165
- var updateManyMessages = (dialogState, payload) => {
2166
- dialogState.msgs = messagesAdapter.updateMany(dialogState.msgs, payload);
2167
- };
2168
- var removeOneMessage = (dialogState, messageId) => {
2169
- dialogState.msgs = messagesAdapter.removeOne(dialogState.msgs, messageId);
2170
- };
2171
- var removeAllMessages = (dialogState) => {
2172
- dialogState.msgs = messagesAdapter.removeAll(dialogState.msgs);
2173
- };
2174
- var setAllMessages = (dialogState, messages) => {
2175
- dialogState.msgs = messagesAdapter.setAll(
2176
- dialogState.msgs,
2177
- messages.map(normalizeHistoricalReasoningMessage)
2178
- );
2179
- };
2180
- var messageActions;
2181
- var messageSlice = createSliceWithThunks({
2182
- name: "message",
2183
- initialState,
2184
- reducers: (create) => ({
2185
- addUserMessage: create.reducer((state, action2) => {
2186
- const { dialogId, ...message } = action2.payload;
2187
- const dialogState = ensureMessageDialogState(
2188
- state,
2189
- dialogId ?? inferDialogIdFromMessage(action2.payload)
2190
- );
2191
- upsertOneMessage(dialogState, {
2192
- ...message,
2193
- isStreaming: false
2194
- });
2195
- }),
2196
- messageStreaming: create.reducer(
2197
- (state, action2) => {
2198
- const { dialogId, ...message } = action2.payload;
2199
- const resolvedDialogId = dialogId ?? inferDialogIdFromMessage(action2.payload);
2200
- const dialogState = ensureMessageDialogState(state, resolvedDialogId);
2201
- const existing = dialogState.msgs.entities[message.id];
2202
- upsertOneMessage(
2203
- dialogState,
2204
- applyMessageStreamingUpsert(existing, message)
2205
- );
2206
- setStreamingMessageId(resolvedDialogId, message.id);
2207
- markMessageStreamActivity(resolvedDialogId);
2208
- }
2209
- ),
2210
- resetMsgs: create.reducer((state, action2) => {
2211
- if (action2.payload?.all) {
2212
- state.dialogStateById = {
2213
- [GLOBAL_MESSAGE_DIALOG_ID]: createEmptyMessageDialogState()
2214
- };
2215
- resetAllMessageSessions();
2216
- return;
2217
- }
2218
- const dialogId = resolveMessageDialogId(
2219
- state,
2220
- action2.payload?.dialogId,
2221
- action2.payload?.dialogKey
2222
- );
2223
- delete state.dialogStateById[dialogId];
2224
- deleteMessageSession(dialogId);
2225
- if (dialogId === getActiveMessageDialogId()) {
2226
- setActiveMessageDialogId(null);
2227
- }
2228
- if (!state.dialogStateById[GLOBAL_MESSAGE_DIALOG_ID]) {
2229
- state.dialogStateById[GLOBAL_MESSAGE_DIALOG_ID] = createEmptyMessageDialogState();
2230
- }
2231
- }),
2232
- clearAllStreaming: create.reducer((state, action2) => {
2233
- const targetStates = action2.payload?.all ? Object.entries(state.dialogStateById) : [[
2234
- resolveMessageDialogId(
2235
- state,
2236
- action2.payload?.dialogId,
2237
- action2.payload?.dialogKey
2238
- ),
2239
- getMessageDialogState(state, action2.payload?.dialogId, action2.payload?.dialogKey)
2240
- ]];
2241
- targetStates.forEach(([dialogId, dialogState]) => {
2242
- const updates = Object.values(dialogState.msgs.entities).filter((m) => m?.isStreaming).map((m) => ({ id: m.id, changes: { isStreaming: false } }));
2243
- if (updates.length > 0) {
2244
- updateManyMessages(dialogState, updates);
2245
- }
2246
- setStreamingMessageId(dialogId, null);
2247
- markMessageSessionAbort(dialogId);
2248
- });
2249
- }),
2250
- removeTransientMessage: create.reducer(
2251
- (state, action2) => {
2252
- const payload = typeof action2.payload === "string" ? { id: action2.payload } : action2.payload;
2253
- const dialogId = payload.dialogId ?? findDialogIdByMessageId(state, payload.id);
2254
- const dialogState = ensureMessageDialogState(state, dialogId);
2255
- removeOneMessage(dialogState, payload.id);
2256
- }
2257
- ),
2258
- // Error-path finalizer: keep whatever the transient message already shows
2259
- // instead of wiping the trace. Decision rules live in messageFinalizeOnError
2260
- // (Wave15); this reducer applies them + clears the streaming index.
2261
- finalizeTransientMessageOnError: create.reducer(
2262
- (state, action2) => {
2263
- const payload = typeof action2.payload === "string" ? { id: action2.payload } : action2.payload;
2264
- const dialogId = payload.dialogId ?? findDialogIdByMessageId(state, payload.id);
2265
- const dialogState = ensureMessageDialogState(state, dialogId);
2266
- const existing = dialogState.msgs.entities[payload.id];
2267
- const decision = resolveFinalizeTransientOnError(
2268
- existing,
2269
- payload.error
2270
- );
2271
- if (decision.kind === "noop") return;
2272
- if (decision.kind === "remove") {
2273
- removeOneMessage(dialogState, payload.id);
2274
- setStreamingMessageId(dialogId, null);
2275
- return;
2276
- }
2277
- updateOneMessage(dialogState, {
2278
- id: payload.id,
2279
- changes: decision.changes
2280
- });
2281
- setStreamingMessageId(dialogId, null);
2282
- }
2283
- ),
2284
- addToolMessage: create.reducer((state, action2) => {
2285
- const dialogState = ensureMessageDialogState(
2286
- state,
2287
- inferDialogIdFromMessage(action2.payload)
2288
- );
2289
- addOneMessage(dialogState, action2.payload);
2290
- }),
2291
- updateToolMessage: create.reducer((state, action2) => {
2292
- const dialogState = ensureMessageDialogState(
2293
- state,
2294
- action2.payload.dialogId ?? findDialogIdByMessageId(state, action2.payload.id)
2295
- );
2296
- updateOneMessage(dialogState, action2.payload);
2297
- }),
2298
- removeMessagesByIds: create.reducer((state, action2) => {
2299
- const dialogState = ensureMessageDialogState(state, action2.payload.dialogId);
2300
- dialogState.msgs = messagesAdapter.removeMany(dialogState.msgs, action2.payload.ids);
2301
- }),
2302
- setMessages: create.reducer((state, action2) => {
2303
- const dialogState = ensureMessageDialogState(state, action2.payload.dialogId);
2304
- if (action2.payload.replace) {
2305
- setAllMessages(dialogState, action2.payload.messages);
2306
- } else {
2307
- upsertManyMessages(dialogState, action2.payload.messages);
2308
- }
2309
- if (action2.payload.isLoadingInitial !== void 0) {
2310
- patchMessageSession(action2.payload.dialogId, {
2311
- isLoadingInitial: action2.payload.isLoadingInitial
2312
- });
2313
- }
2314
- }),
2315
- prepareAndPersistMessage: create.asyncThunk(
2316
- async (args, thunkApi) => {
2317
- const { message, dialogConfig } = args;
2318
- const { getState, dispatch, rejectWithValue } = thunkApi;
2319
- const state = getState();
2320
- if (!dialogConfig) {
2321
- return rejectWithValue("Missing dialogConfig");
2322
- }
2323
- const dialogKey = dialogConfig.dbKey || dialogConfig.id;
2324
- const dialogId = extractCustomId(dialogKey);
2325
- const currentAccountUserId = selectIdentityUserId(state) ?? null;
2326
- const dialogConfigUserId = dialogConfig.userId;
2327
- const { fullMessage } = assemblePersistedUserMessage({
2328
- message,
2329
- dialogId,
2330
- dialogKey,
2331
- currentAccountUserId,
2332
- dialogConfigUserId: typeof dialogConfigUserId === "string" ? dialogConfigUserId : null
2333
- });
2334
- const userId = fullMessage.userId;
2335
- dispatch(
2336
- addReferenceKeysAction({
2337
- content: message.content,
2338
- dialogKey
2339
- })
2340
- ).catch((err) => console.error("Failed to add refs:", err));
2341
- dispatch(messageActions.addUserMessage({ ...fullMessage, dialogId }));
2342
- const { controller, ...messageToWrite } = fullMessage;
2343
- await dispatch(
2344
- write({
2345
- data: { ...messageToWrite, type: "msg" /* MSG */ },
2346
- customKey: fullMessage.dbKey,
2347
- userId
2348
- })
2349
- ).unwrap();
2350
- return fullMessage;
2351
- }
2352
- ),
2353
- prepareAndPersistUserMessage: create.asyncThunk(
2354
- async (args, thunkApi) => {
2355
- const { userInput, dialogConfig } = args;
2356
- const { dispatch } = thunkApi;
2357
- return dispatch(
2358
- messageActions.prepareAndPersistMessage({
2359
- message: {
2360
- role: "user",
2361
- content: userInput
2362
- },
2363
- dialogConfig
2364
- })
2365
- ).unwrap();
2366
- }
2367
- ),
2368
- /**
2369
- * 初始化当前对话消息
2370
- */
2371
- initMsgs: create.asyncThunk(
2372
- async ({
2373
- dialogId,
2374
- dialogKey,
2375
- limit,
2376
- isNew
2377
- }, thunkApi) => {
2378
- const { db } = thunkApi.extra;
2379
- const { getState, signal, dispatch } = thunkApi;
2380
- const state = getState();
2381
- const { currentToken: token, remoteServers } = getRuntimeServerContext(state);
2382
- const { localMessages, remotePromise, earlyReturned } = await fetchAndCacheMessagesLocalFirst({
2383
- db,
2384
- dialogId,
2385
- dialogKey,
2386
- limit,
2387
- token,
2388
- remoteServers,
2389
- signal
2390
- });
2391
- const validLocalMessages = localMessages.filter(isValidMessage);
2392
- if (earlyReturned) {
2393
- dispatch(
2394
- messageActions.setMessages({
2395
- dialogId,
2396
- messages: validLocalMessages,
2397
- isLoadingInitial: false
2398
- })
2399
- );
2400
- remotePromise.then((finalMessages2) => {
2401
- dispatch(
2402
- messageActions.setMessages({
2403
- dialogId,
2404
- messages: finalMessages2.filter(isValidMessage)
2405
- })
2406
- );
2407
- }).catch((err) => {
2408
- console.error("[initMsgs] background remote revalidate failed:", err);
2409
- });
2410
- return validLocalMessages;
2411
- }
2412
- const finalMessages = (await remotePromise).filter(isValidMessage);
2413
- try {
2414
- const rootState = getState();
2415
- const decision = resolveInitMsgsSummaryResume({
2416
- entities: rootState.db?.entities,
2417
- dialogId
2418
- });
2419
- if (decision.resume) {
2420
- console.log("[initMsgs] Found suspended summary task, resuming...", decision.dialogKey);
2421
- thunkApi.dispatch(patch({ dbKey: decision.dialogKey, changes: { summaryPending: false } }));
2422
- updateDialogSummaryAction(
2423
- { dialogKey: decision.dialogKey, preFetchedMessages: finalMessages },
2424
- thunkApi
2425
- ).catch((err) => console.error("Resume summary failed:", err));
2426
- }
2427
- } catch {
2428
- console.error("[initMsgs] Failed to resume summary");
2429
- }
2430
- return finalMessages;
2431
- },
2432
- {
2433
- pending: (state, action2) => {
2434
- const { dialogId, isNew, limit } = action2.meta.arg;
2435
- const dialogState = ensureMessageDialogState(state, dialogId);
2436
- if (isNew) {
2437
- if (Object.keys(dialogState.msgs.entities).length === 0) {
2438
- removeAllMessages(dialogState);
2439
- }
2440
- }
2441
- ensureMessageSession(dialogId);
2442
- setActiveMessageDialogId(dialogId);
2443
- patchMessageSession(dialogId, {
2444
- firstStreamProcessed: false,
2445
- isLoadingInitial: true,
2446
- isLoadingOlder: false,
2447
- // Full-history init: no older page. Partial limit still allows load-older.
2448
- hasMoreOlder: typeof limit === "number" && Number.isFinite(limit) && limit > 0,
2449
- error: null,
2450
- lastStreamTimestamp: 0,
2451
- currentInitMsgsRequestId: action2.meta.requestId
2452
- });
2453
- },
2454
- fulfilled: (state, action2) => {
2455
- const dialogId = action2.meta.arg.dialogId;
2456
- const dialogState = ensureMessageDialogState(state, dialogId);
2457
- const session = getMessageSession(dialogId);
2458
- if (session.currentInitMsgsRequestId !== action2.meta.requestId) {
2459
- return;
2460
- }
2461
- const limit = action2.meta.arg.limit;
2462
- patchMessageSession(dialogId, {
2463
- currentInitMsgsRequestId: void 0,
2464
- isLoadingInitial: false,
2465
- hasMoreOlder: resolveInitMsgsHasMoreOlder({
2466
- limit,
2467
- fetchedCount: action2.payload.length
2468
- })
2469
- });
2470
- const hasLocalStreaming = getHasStreamingMessage(dialogId) || Object.values(dialogState.msgs.entities).some(
2471
- (message) => message?.isStreaming
2472
- );
2473
- const writeMode = resolveInitMsgsFulfilledWriteMode({
2474
- isNew: action2.meta.arg.isNew,
2475
- hasLocalStreaming
2476
- });
2477
- if (writeMode === "upsert") {
2478
- upsertManyMessages(dialogState, action2.payload);
2479
- } else {
2480
- setAllMessages(dialogState, action2.payload);
2481
- }
2482
- },
2483
- rejected: (state, action2) => {
2484
- const dialogId = action2.meta.arg.dialogId;
2485
- ensureMessageDialogState(state, dialogId);
2486
- const session = getMessageSession(dialogId);
2487
- if (session.currentInitMsgsRequestId !== action2.meta.requestId) {
2488
- return;
2489
- }
2490
- if (action2.meta?.aborted) {
2491
- patchMessageSession(dialogId, {
2492
- currentInitMsgsRequestId: void 0,
2493
- isLoadingInitial: false
2494
- });
2495
- return;
2496
- }
2497
- patchMessageSession(dialogId, {
2498
- currentInitMsgsRequestId: void 0,
2499
- isLoadingInitial: false,
2500
- error: action2.error instanceof Error ? action2.error : new Error(String(action2.error))
2501
- });
2502
- console.error(`${action2.type} failed:`, action2.error);
2503
- }
2504
- }
2505
- ),
2506
- /**
2507
- * 加载更早的历史消息
2508
- */
2509
- loadOlderMessages: create.asyncThunk(
2510
- async ({
2511
- dialogId,
2512
- dialogKey,
2513
- beforeKey,
2514
- limit = OLDER_LOAD_LIMIT
2515
- }, thunkApi) => {
2516
- const { getState, extra, signal } = thunkApi;
2517
- const { db } = extra;
2518
- const state = getState();
2519
- const { currentToken: token, remoteServers } = getRuntimeServerContext(state);
2520
- const messages = (await fetchAndCacheMessages({
2521
- db,
2522
- dialogId,
2523
- dialogKey,
2524
- limit,
2525
- beforeKey,
2526
- token,
2527
- remoteServers,
2528
- signal
2529
- })).filter(isValidMessage);
2530
- return { messages, limit };
2531
- },
2532
- {
2533
- pending: (state, action2) => {
2534
- const dialogId = action2.meta.arg.dialogId;
2535
- ensureMessageDialogState(state, dialogId);
2536
- patchMessageSession(dialogId, {
2537
- isLoadingOlder: true,
2538
- error: null,
2539
- currentLoadOlderRequestId: action2.meta.requestId
2540
- });
2541
- },
2542
- fulfilled: (state, action2) => {
2543
- const dialogId = action2.meta.arg.dialogId;
2544
- const dialogState = ensureMessageDialogState(state, dialogId);
2545
- const session = getMessageSession(dialogId);
2546
- if (session.currentLoadOlderRequestId !== action2.meta.requestId) {
2547
- return;
2548
- }
2549
- const { messages, limit } = action2.payload;
2550
- patchMessageSession(dialogId, {
2551
- isLoadingOlder: false,
2552
- currentLoadOlderRequestId: void 0,
2553
- ...messages.length < limit ? { hasMoreOlder: false } : {}
2554
- });
2555
- if (messages.length > 0) {
2556
- upsertManyMessages(dialogState, messages);
2557
- }
2558
- },
2559
- rejected: (state, action2) => {
2560
- const dialogId = action2.meta.arg.dialogId;
2561
- ensureMessageDialogState(state, dialogId);
2562
- const session = getMessageSession(dialogId);
2563
- if (session.currentLoadOlderRequestId !== action2.meta.requestId) {
2564
- return;
2565
- }
2566
- if (action2.meta?.aborted) {
2567
- patchMessageSession(dialogId, {
2568
- isLoadingOlder: false,
2569
- currentLoadOlderRequestId: void 0
2570
- });
2571
- return;
2572
- }
2573
- patchMessageSession(dialogId, {
2574
- isLoadingOlder: false,
2575
- currentLoadOlderRequestId: void 0,
2576
- error: action2.error instanceof Error ? action2.error : new Error(String(action2.error))
2577
- });
2578
- console.error(`${action2.type} failed:`, action2.error);
2579
- }
2580
- }
2581
- ),
2582
- /**
2583
- * 一条流式回复结束
2584
- */
2585
- messageStreamEnd: create.asyncThunk(
2586
- async (payload, { dispatch, getState }) => {
2587
- const {
2588
- finalContentBuffer,
2589
- totalUsage,
2590
- billingUsageRecords,
2591
- msgKey,
2592
- agentConfig,
2593
- dialogId,
2594
- dialogKey,
2595
- messageId,
2596
- reasoningBuffer,
2597
- toolCalls,
2598
- finishReason,
2599
- billingFailed,
2600
- skipBilling
2601
- } = payload;
2602
- const spaceId = payload.spaceId;
2603
- const rawAgentName = asTrimmedString(agentConfig?.name);
2604
- const normalizedContentBuffer = await normalizeAssistantContentBuffer(
2605
- finalContentBuffer,
2606
- dialogId,
2607
- messageId,
2608
- dispatch,
2609
- getState,
2610
- spaceId ? { spaceId, agentName: rawAgentName || void 0 } : void 0
2611
- );
2612
- const {
2613
- thinkContent,
2614
- textContent,
2615
- visibleContent: finalVisibleContent
2616
- } = finalizeAssistantMessageContent(
2617
- normalizedContentBuffer,
2618
- reasoningBuffer
2619
- );
2620
- const {
2621
- billedUsage,
2622
- billedEstimatedUsage,
2623
- hasReportedUsage,
2624
- titleEligible
2625
- } = resolveStreamEndBillingUsages({
2626
- agentConfig,
2627
- totalUsage,
2628
- finalVisibleContent
2629
- });
2630
- const {
2631
- finalUsageData,
2632
- agentName,
2633
- persistedMetadata,
2634
- otherPersistedMessageMetadata
2635
- } = prepareStreamEndPersistInputs({
2636
- totalUsage,
2637
- agentConfig,
2638
- messageMetadata: payload.messageMetadata
2639
- });
2640
- const { finalMetadata } = resolveStreamEndFinalMetadata({
2641
- persistedMetadata,
2642
- toolCalls,
2643
- messages: selectAllMsgs(getState(), dialogId),
2644
- finalContent: finalVisibleContent
2645
- });
2646
- const state = getState();
2647
- const dialogConfig = selectById(state, dialogKey);
2648
- const dialogConfigUserId = dialogConfig?.userId;
2649
- const currentAccountUserId = selectIdentityUserId(state) ?? null;
2650
- const userId = resolveMessageOwner({
2651
- dialogConfigUserId: typeof dialogConfigUserId === "string" ? dialogConfigUserId : null,
2652
- dialogKey,
2653
- currentAccountUserId
2654
- });
2655
- const finalMessage = assembleFinalAssistantMessage({
2656
- messageId,
2657
- msgKey,
2658
- finalVisibleContent,
2659
- thinkContent,
2660
- agentConfig,
2661
- finalUsageData,
2662
- toolCalls,
2663
- finishReason,
2664
- otherPersistedMessageMetadata,
2665
- finalMetadata,
2666
- agentName,
2667
- // Authoritative owner last so metadata cannot overwrite it.
2668
- userId
2669
- });
2670
- const { controller, ...messageToWrite } = finalMessage;
2671
- await dispatch(
2672
- write({
2673
- data: { ...messageToWrite, type: "msg" /* MSG */ },
2674
- customKey: msgKey,
2675
- userId
2676
- })
2677
- ).unwrap();
2678
- const {
2679
- billingMode,
2680
- updateTitle,
2681
- updateSummary,
2682
- summaryForce,
2683
- summaryReason,
2684
- addRefs
2685
- } = resolveStreamEndPostWritePolicy({
2686
- hasReportedUsage,
2687
- billingFailed,
2688
- skipBilling,
2689
- agentProvider: agentConfig?.provider,
2690
- titleEligible,
2691
- textContent,
2692
- toolCalls
2693
- });
2694
- await dispatchStreamEndBilling({
2695
- dispatch,
2696
- updateTokensAction: updateTokens,
2697
- billingMode,
2698
- billingUsageRecords,
2699
- billedUsage,
2700
- billedEstimatedUsage,
2701
- dialogId,
2702
- dialogKey,
2703
- agentConfig
2704
- });
2705
- if (updateTitle) {
2706
- dispatch(updateDialogTitle({ dialogKey, agentConfig }));
2707
- }
2708
- if (updateSummary) {
2709
- const messagesForSummary = [
2710
- ...selectAllMsgs(getState(), dialogId),
2711
- finalMessage
2712
- ];
2713
- updateDialogSummaryAction(
2714
- {
2715
- dialogKey,
2716
- preFetchedMessages: messagesForSummary,
2717
- force: summaryForce,
2718
- reason: summaryReason
2719
- },
2720
- { dispatch, getState }
2721
- ).catch((err) => console.error("Summary update failed:", err));
2722
- if (addRefs) {
2723
- dispatch(addReferenceKeysAction({
2724
- content: finalVisibleContent,
2725
- dialogKey
2726
- })).catch((err) => console.error("Failed to add assistant refs:", err));
2727
- }
2728
- }
2729
- captureUnderstandingFromCompletedUiTurn2({
2730
- state: getState(),
2731
- agentKey: agentConfig?.dbKey,
2732
- dialogId,
2733
- dialogKey,
2734
- spaceId: payload.spaceId,
2735
- assistantText: textContent,
2736
- toolCalls
2737
- }).catch(
2738
- (err) => console.error("Understanding memory capture failed:", err)
2739
- );
2740
- return {
2741
- id: messageId,
2742
- dbKey: msgKey,
2743
- role: "assistant",
2744
- content: finalMessage.content,
2745
- thinkContent: finalMessage.thinkContent,
2746
- usage: finalMessage.usage,
2747
- agentKey: finalMessage.agentKey,
2748
- cybotKey: finalMessage.cybotKey,
2749
- tool_calls: finalMessage.tool_calls,
2750
- dialogId,
2751
- agentName: finalMessage.agentName
2752
- };
2753
- },
2754
- {
2755
- fulfilled: (state, action2) => {
2756
- const payload = action2.payload;
2757
- const dialogState = ensureMessageDialogState(state, payload.dialogId);
2758
- const existing = dialogState.msgs.entities[payload.id];
2759
- upsertOneMessage(dialogState, {
2760
- ...existing ?? {},
2761
- ...payload,
2762
- role: payload.role ?? existing?.role ?? "assistant",
2763
- dbKey: payload.dbKey ?? existing?.dbKey ?? action2.meta.arg.msgKey,
2764
- isStreaming: false,
2765
- imageGenerationState: void 0
2766
- });
2767
- setStreamingMessageId(payload.dialogId, null);
2768
- },
2769
- rejected: (state, action2) => {
2770
- const arg = action2.meta?.arg;
2771
- const messageId = arg?.messageId;
2772
- const dialogId = arg?.dialogId;
2773
- console.error("messageStreamEnd failed:", action2.error);
2774
- if (messageId && dialogId) {
2775
- const dialogState = ensureMessageDialogState(state, dialogId);
2776
- updateOneMessage(dialogState, {
2777
- id: messageId,
2778
- changes: {
2779
- isStreaming: false,
2780
- imageGenerationState: void 0,
2781
- content: appendSaveFailureToContent(
2782
- dialogState.msgs.entities[messageId]?.content
2783
- )
2784
- }
2785
- });
2786
- }
2787
- if (dialogId) {
2788
- setStreamingMessageId(dialogId, null);
2789
- }
2790
- }
2791
- }
2792
- ),
2793
- deleteMessage: create.asyncThunk(
2794
- async (dbKey, { dispatch, getState }) => {
2795
- const state = getState();
2796
- const dialogId = findDialogIdByMessageDbKey(state.message, dbKey);
2797
- const dialogState = dialogId ? state.message.dialogStateById[dialogId] : void 0;
2798
- const entities = dialogState?.msgs.entities ?? {};
2799
- const msg = Object.values(entities).find((m) => m?.dbKey === dbKey);
2800
- const { id: msgId, extraRemoveId, extraRemoveDbKey } = planDeleteMessageCascade(msg, entities);
2801
- await dispatch(remove(dbKey));
2802
- if (extraRemoveDbKey) {
2803
- await dispatch(remove(extraRemoveDbKey));
2804
- }
2805
- return { id: msgId, extraRemoveId, dialogId };
2806
- },
2807
- {
2808
- fulfilled: (state, action2) => {
2809
- const { id, extraRemoveId, dialogId } = action2.payload;
2810
- const dialogState = ensureMessageDialogState(state, dialogId);
2811
- if (id) {
2812
- removeOneMessage(dialogState, id);
2813
- }
2814
- if (extraRemoveId) {
2815
- removeOneMessage(dialogState, extraRemoveId);
2816
- }
2817
- }
2818
- }
2819
- ),
2820
- editUserMessageAndReplay: create.asyncThunk(
2821
- async (args, thunkApi) => {
2822
- const { dispatch, getState, rejectWithValue } = thunkApi;
2823
- try {
2824
- const state = getState();
2825
- const dialogKey = args.dialogKey ?? selectCurrentDialogKey(state);
2826
- if (!dialogKey) {
2827
- throw new Error("editUserMessageAndReplay: dialogKey is required.");
2828
- }
2829
- const dialogConfig = selectById(state, dialogKey);
2830
- if (!dialogConfig) {
2831
- throw new Error("editUserMessageAndReplay: dialog config is missing.");
2832
- }
2833
- const dialogId = dialogConfig.id ?? extractCustomId(dialogKey);
2834
- const messages = selectAllMsgs(state, dialogId);
2835
- const plan = planEditUserMessageAndReplay({
2836
- messages,
2837
- messageId: args.messageId,
2838
- originalContent: args.originalContent,
2839
- nextText: args.nextText
2840
- });
2841
- if (!plan.ok) {
2842
- throw new Error(plan.message);
2843
- }
2844
- const { targetMessage, nextContent, trailingMessages } = plan;
2845
- dispatch(
2846
- messageActions.updateToolMessage({
2847
- id: targetMessage.id,
2848
- dialogId,
2849
- changes: {
2850
- content: nextContent
2851
- }
2852
- })
2853
- );
2854
- if (trailingMessages.length > 0) {
2855
- dispatch(
2856
- messageActions.removeMessagesByIds({
2857
- dialogId,
2858
- ids: trailingMessages.map((message) => message.id)
2859
- })
2860
- );
2861
- }
2862
- await dispatch(
2863
- patch({
2864
- dbKey: targetMessage.dbKey,
2865
- changes: {
2866
- content: nextContent
2867
- }
2868
- })
2869
- ).unwrap();
2870
- await dispatch(
2871
- patch({
2872
- dbKey: dialogKey,
2873
- changes: {
2874
- summary: null,
2875
- summarizedBeforeId: null
2876
- }
2877
- })
2878
- ).unwrap();
2879
- await Promise.all(
2880
- trailingMessages.map(
2881
- (m) => m?.dbKey ? dispatch(remove(m.dbKey)).unwrap() : Promise.resolve()
2882
- )
2883
- );
2884
- const { agentKeyToUse, agentConfigToUse, effectiveRuntimeOptions } = resolveHandleSendMessageContext({
2885
- dialogConfig,
2886
- targetAgentKey: args.targetAgentKey,
2887
- runtimeOptions: args.runtimeOptions
2888
- });
2889
- if (agentKeyToUse) {
2890
- const { streamAgentChatTurn } = await import("./agentSlice-UP66DIC2.js");
2891
- await dispatch(
2892
- streamAgentChatTurn({
2893
- agentKey: agentKeyToUse,
2894
- ...agentConfigToUse ? { agentConfig: agentConfigToUse } : {},
2895
- userInput: nextContent,
2896
- dialogKey,
2897
- parentMessageId: void 0,
2898
- runtimeOptions: effectiveRuntimeOptions,
2899
- quickChatPerfStartedAt: args.quickChatPerfStartedAt
2900
- })
2901
- ).unwrap();
2902
- }
2903
- return {
2904
- editedMessageId: targetMessage.id,
2905
- removedMessageIds: trailingMessages.map((message) => message.id)
2906
- };
2907
- } catch (error) {
2908
- return rejectWithValue(toErrorMessage(error));
2909
- }
2910
- }
2911
- )
2912
- }),
2913
- selectors: {}
2914
- });
2915
- messageActions = messageSlice.actions;
2916
- var dialogMessageSelectors = messagesAdapter.getSelectors(
2917
- (dialogState) => dialogState.msgs
2918
- );
2919
- var selectMessageDialogState = (state, dialogId) => getMessageDialogState(state.message, dialogId);
2920
- var selectAllMsgs = createSelector(
2921
- [
2922
- (state, dialogId) => selectMessageDialogState(state, dialogId)
2923
- ],
2924
- (dialogState) => dialogMessageSelectors.selectAll(dialogState)
2925
- );
2926
- var selectMsgById = (state, messageId, dialogId) => dialogMessageSelectors.selectById(
2927
- getMessageDialogState(state.message, dialogId),
2928
- messageId
2929
- );
2930
- var {
2931
- addUserMessage,
2932
- messageStreaming,
2933
- setMessages,
2934
- resetMsgs,
2935
- clearAllStreaming,
2936
- removeTransientMessage,
2937
- finalizeTransientMessageOnError,
2938
- prepareAndPersistMessage,
2939
- prepareAndPersistUserMessage,
2940
- initMsgs,
2941
- loadOlderMessages,
2942
- messageStreamEnd,
2943
- deleteMessage,
2944
- editUserMessageAndReplay,
2945
- addToolMessage,
2946
- updateToolMessage,
2947
- removeMessagesByIds
2948
- } = messageSlice.actions;
2949
- var messageSlice_default = messageSlice.reducer;
2950
-
2951
- // packages/chat/dialog/actions/updateTokensAction.ts
2952
- var import_date_fns = __toESM(require_date_fns());
2953
- import { ulid } from "ulid";
2954
-
2955
- // packages/render/web/ui/toastStore.ts
2956
- var EXIT_MS = 320;
2957
- var raf = typeof globalThis.requestAnimationFrame === "function" ? (cb) => globalThis.requestAnimationFrame(cb) : (cb) => {
2958
- setTimeout(cb, 16);
2959
- };
2960
- var ToastStore = class {
2961
- toasts = [];
2962
- listeners = /* @__PURE__ */ new Set();
2963
- nextId = 0;
2964
- subscribe = (listener) => {
2965
- this.listeners.add(listener);
2966
- return () => this.listeners.delete(listener);
2967
- };
2968
- getSnapshot = () => this.toasts;
2969
- add(item) {
2970
- const id = item.id ?? `toast-${++this.nextId}`;
2971
- const filtered = this.toasts.filter((t) => t.id !== id);
2972
- const entry = { ...item, id, phase: "entering" };
2973
- this.toasts = [...filtered, entry];
2974
- this.notify();
2975
- raf(
2976
- () => raf(() => {
2977
- this.toasts = this.toasts.map(
2978
- (t) => t.id === id ? { ...t, phase: "visible" } : t
2979
- );
2980
- this.notify();
2981
- })
2982
- );
2983
- if (item.timeout && item.timeout > 0) {
2984
- setTimeout(() => this.close(id), item.timeout);
2985
- }
2986
- return id;
2987
- }
2988
- close(id) {
2989
- if (id) {
2990
- if (!this.toasts.some((t) => t.id === id)) return;
2991
- this.toasts = this.toasts.map(
2992
- (t) => t.id === id ? { ...t, phase: "exiting" } : t
2993
- );
2994
- } else {
2995
- this.toasts = this.toasts.map((t) => ({ ...t, phase: "exiting" }));
2996
- }
2997
- this.notify();
2998
- setTimeout(() => {
2999
- this.toasts = id ? this.toasts.filter((t) => t.id !== id) : [];
3000
- this.notify();
3001
- }, EXIT_MS);
3002
- }
3003
- notify = () => {
3004
- this.listeners.forEach((fn) => fn());
3005
- };
3006
- };
3007
- var toastManager = new ToastStore();
3008
-
3009
- // packages/app/utils/toast.ts
3010
- var DEFAULT_TIMEOUT = 4e3;
3011
- function add(message, type, options) {
3012
- const timeout = options?.timeout ?? options?.duration;
3013
- return toastManager.add({
3014
- id: options?.id,
3015
- title: message,
3016
- type,
3017
- icon: options?.icon,
3018
- description: options?.description,
3019
- action: options?.action,
3020
- position: options?.position,
3021
- // loading toasts stay until explicitly replaced/closed (timeout=0)
3022
- timeout: type === "loading" ? timeout ?? 0 : timeout ?? DEFAULT_TIMEOUT
3023
- });
3024
- }
3025
- var toast = Object.assign(
3026
- (message, options) => add(message, "default", options),
3027
- {
3028
- success: (message, options) => add(message, "success", options),
3029
- error: (message, options) => add(message, "error", options),
3030
- info: (message, options) => add(message, "default", options),
3031
- loading: (message, options) => add(message, "loading", options),
3032
- dismiss: (id) => toastManager.close(id)
3033
- }
3034
- );
3035
-
3036
- // packages/ai/token/saveTokenRecord.ts
3037
- var logger = createClientLogger("token-record");
3038
- var createTokenRecord = (data, { cost, inputPrice, outputPrice } = {}) => ({
3039
- ...data,
3040
- cost: cost || data.cost,
3041
- inputPrice,
3042
- outputPrice
3043
- });
3044
- var saveTokenRecord = async (tokenData, record, thunkApi, callId) => {
3045
- const ownerUserId = tokenData.userId || record.userId;
3046
- const eventTime = tokenData.timestamp ?? record.createdAt ?? Date.now();
3047
- const key = callId ? createTokenKey.recordForStableCall(ownerUserId, callId) : createTokenKey.record(ownerUserId, eventTime);
3048
- try {
3049
- await thunkApi.dispatch(
3050
- write({
3051
- data: { ...record, id: key, type: "token" /* TOKEN */, userId: ownerUserId },
3052
- customKey: key,
3053
- userId: ownerUserId
3054
- })
3055
- ).unwrap();
3056
- } catch (error) {
3057
- logger.error(
3058
- {
3059
- key,
3060
- userId: tokenData.userId,
3061
- error: toErrorMessage(error)
3062
- },
3063
- "Failed to save token record"
3064
- );
3065
- toast.error("Failed to save token record");
3066
- throw error;
3067
- }
3068
- };
3069
-
3070
- // packages/ai/token/calculatePrice.ts
3071
- var sanitizeCost = (raw) => {
3072
- const rounded = Number(raw.toFixed(6));
3073
- return Number.isFinite(rounded) && rounded > 0 ? rounded : 0;
3074
- };
3075
- var resolveModelPrice = (model, usage) => {
3076
- let activePrice = { ...model.price };
3077
- if (model.pricingStrategy?.type === "tiered_context") {
3078
- const contextSize = usage.input_tokens || 0;
3079
- const tiers = model.pricingStrategy.tiers || [];
3080
- const sortedTiers = [...tiers].sort((a, b) => a.minContext - b.minContext);
3081
- for (const tier of sortedTiers) {
3082
- if (contextSize >= tier.minContext) {
3083
- activePrice = { ...tier.price };
3084
- }
3085
- }
3086
- }
3087
- return activePrice;
3088
- };
3089
- var scaleModelInputOutputPrice = (price, multiplier) => ({
3090
- ...price,
3091
- input: price.input * multiplier,
3092
- output: price.output * multiplier
3093
- });
3094
- var scaleModelServiceTierPrice = (price, inputOutputMultiplier, cacheMultiplier) => ({
3095
- ...price,
3096
- input: price.input * inputOutputMultiplier,
3097
- output: price.output * inputOutputMultiplier,
3098
- ...typeof cacheMultiplier === "number" && typeof price.cachingWrite === "number" ? { cachingWrite: price.cachingWrite * cacheMultiplier } : {},
3099
- ...typeof cacheMultiplier === "number" && typeof price.cachingRead === "number" ? { cachingRead: price.cachingRead * cacheMultiplier } : {}
3100
- });
3101
- var resolveGoogleServiceTierPrice = (model, price, billingServiceTier) => {
3102
- const normalizedTier = asTrimmedLowercaseString(billingServiceTier);
3103
- const imageOutputPrice = typeof model.imageTokenPricePerMillion === "number" ? model.imageTokenPricePerMillion : void 0;
3104
- const priceWithImageOutput = typeof imageOutputPrice === "number" ? { ...price, output: imageOutputPrice } : price;
3105
- const serviceTierMultiplier = normalizedTier === "batch" || normalizedTier === "flex" || normalizedTier === "priority" ? model.serviceTierPriceMultipliers?.[normalizedTier] : void 0;
3106
- if (serviceTierMultiplier) {
3107
- return scaleModelServiceTierPrice(
3108
- priceWithImageOutput,
3109
- serviceTierMultiplier.inputOutput,
3110
- serviceTierMultiplier.cache
3111
- );
3112
- }
3113
- if (normalizedTier === "flex" || normalizedTier === "batch") {
3114
- return scaleModelInputOutputPrice(priceWithImageOutput, 0.5);
3115
- }
3116
- if (normalizedTier === "priority") {
3117
- return scaleModelInputOutputPrice(priceWithImageOutput, 1.8);
3118
- }
3119
- return priceWithImageOutput;
3120
- };
3121
- var resolveEffectiveModelPrice = ({
3122
- model,
3123
- usage,
3124
- provider,
3125
- billingServiceTier,
3126
- nowMs
3127
- }) => {
3128
- const resolvedPrice = resolveModelPrice(model, usage);
3129
- if ((provider === "nolo" || provider === "deepseek") && isPlatformHostedDeepSeekV4Model(model.name)) {
3130
- return getPlatformHostedDeepSeekV4Price(model.name, nowMs);
3131
- }
3132
- if (provider === "google") {
3133
- return resolveGoogleServiceTierPrice(model, resolvedPrice, billingServiceTier);
3134
- }
3135
- if (provider === "runinfra" || provider === "baseten") {
3136
- return resolvedPrice;
3137
- }
3138
- return resolvedPrice;
3139
- };
3140
- var getEffectivePrices = (resolvedPrice, externalPrice) => {
3141
- const effectiveInputPrice = Math.max(
3142
- externalPrice?.input || 0,
3143
- resolvedPrice.input
3144
- );
3145
- const effectiveOutputPrice = Math.max(
3146
- externalPrice?.output || 0,
3147
- resolvedPrice.output
3148
- );
3149
- return {
3150
- input: effectiveInputPrice,
3151
- output: effectiveOutputPrice,
3152
- cachingWrite: resolvedPrice.cachingWrite || 0,
3153
- cachingRead: resolvedPrice.cachingRead || 0
3154
- };
3155
- };
3156
- var calculateAnthropicCost = (resolvedPrice, usage, externalPrice) => {
3157
- const {
3158
- input_tokens,
3159
- output_tokens,
3160
- cache_creation_input_tokens,
3161
- cache_read_input_tokens
3162
- } = usage;
3163
- const {
3164
- input: effectiveInputPrice,
3165
- output: effectiveOutputPrice,
3166
- cachingWrite: effectiveCachingWritePrice,
3167
- cachingRead: effectiveCachingReadPrice
3168
- } = getEffectivePrices(resolvedPrice, externalPrice);
3169
- const regularInputTokens = input_tokens - cache_read_input_tokens;
3170
- const regularTotal = (regularInputTokens * resolvedPrice.input + output_tokens * resolvedPrice.output + cache_creation_input_tokens * (resolvedPrice.cachingWrite || 0) + cache_read_input_tokens * (resolvedPrice.cachingRead || 0)) / 1e6;
3171
- const chargeTotal = (regularInputTokens * effectiveInputPrice + output_tokens * effectiveOutputPrice + cache_creation_input_tokens * effectiveCachingWritePrice + cache_read_input_tokens * effectiveCachingReadPrice) / 1e6;
3172
- return {
3173
- regular: regularTotal,
3174
- charge: chargeTotal,
3175
- details: {
3176
- inputCost: regularInputTokens * resolvedPrice.input / 1e6,
3177
- outputCost: output_tokens * resolvedPrice.output / 1e6,
3178
- cachingWriteCost: cache_creation_input_tokens * (resolvedPrice.cachingWrite || 0) / 1e6,
3179
- cachingReadCost: cache_read_input_tokens * (resolvedPrice.cachingRead || 0) / 1e6
3180
- }
3181
- };
3182
- };
3183
- var calculateCacheBasedCost = (resolvedPrice, usage, externalPrice) => {
3184
- const { input_tokens, output_tokens, cache_read_input_tokens } = usage;
3185
- const { input: effectiveInputPrice, output: effectiveOutputPrice } = getEffectivePrices(resolvedPrice, externalPrice);
3186
- const inputTokens = Math.max(0, input_tokens ?? 0);
3187
- const cacheRead = Math.min(
3188
- Math.max(0, cache_read_input_tokens ?? 0),
3189
- inputTokens
3190
- );
3191
- const outputTokens = Math.max(0, output_tokens ?? 0);
3192
- const cacheMissTokens = inputTokens - cacheRead;
3193
- const cacheHitPrice = resolvedPrice.inputCacheHit || 0;
3194
- const regularTotal = (cacheMissTokens * resolvedPrice.input + cacheRead * cacheHitPrice + outputTokens * resolvedPrice.output) / 1e6;
3195
- const chargeTotal = (cacheMissTokens * effectiveInputPrice + cacheRead * cacheHitPrice + outputTokens * effectiveOutputPrice) / 1e6;
3196
- return {
3197
- regular: regularTotal,
3198
- charge: chargeTotal,
3199
- details: {
3200
- inputCost: cacheMissTokens * resolvedPrice.input / 1e6,
3201
- outputCost: outputTokens * resolvedPrice.output / 1e6,
3202
- cachingReadCost: cacheRead * cacheHitPrice / 1e6,
3203
- cachingWriteCost: 0
3204
- }
3205
- };
3206
- };
3207
- var calculateSimpleCost = (resolvedPrice, usage, externalPrice) => {
3208
- const { input_tokens, output_tokens } = usage;
3209
- const { input: effectiveInputPrice, output: effectiveOutputPrice } = getEffectivePrices(resolvedPrice, externalPrice);
3210
- const regularTotal = (input_tokens * resolvedPrice.input + output_tokens * resolvedPrice.output) / 1e6;
3211
- const chargeTotal = (input_tokens * effectiveInputPrice + output_tokens * effectiveOutputPrice) / 1e6;
3212
- return {
3213
- regular: regularTotal,
3214
- charge: chargeTotal,
3215
- details: {
3216
- inputCost: input_tokens * resolvedPrice.input / 1e6,
3217
- outputCost: output_tokens * resolvedPrice.output / 1e6,
3218
- cachingWriteCost: 0,
3219
- cachingReadCost: 0
3220
- }
3221
- };
3222
- };
3223
- var calculateOpenRouterFallbackCost = (resolvedPrice, usage, externalPrice) => {
3224
- if (typeof resolvedPrice.cachingWrite === "number" || typeof resolvedPrice.cachingRead === "number") {
3225
- return calculateAnthropicCost(resolvedPrice, usage, externalPrice);
3226
- }
3227
- if (typeof resolvedPrice.inputCacheHit === "number") {
3228
- return calculateCacheBasedCost(resolvedPrice, usage, externalPrice);
3229
- }
3230
- return calculateSimpleCost(resolvedPrice, usage, externalPrice);
3231
- };
3232
- var API_REPORTED_COST_MULTIPLIER = 8;
3233
- var zeroCostBreakdown = () => ({
3234
- regular: 0,
3235
- charge: 0,
3236
- details: {
3237
- inputCost: 0,
3238
- outputCost: 0,
3239
- cachingWriteCost: 0,
3240
- cachingReadCost: 0
3241
- }
3242
- });
3243
- var calculateApiReportedCost = (usage) => {
3244
- if (!usage || typeof usage.cost !== "number" || usage.cost <= 0) {
3245
- return zeroCostBreakdown();
3246
- }
3247
- const regular = usage.cost * API_REPORTED_COST_MULTIPLIER;
3248
- return {
3249
- regular,
3250
- charge: regular,
3251
- details: {
3252
- inputCost: regular,
3253
- outputCost: 0,
3254
- cachingWriteCost: 0,
3255
- cachingReadCost: 0
3256
- }
3257
- };
3258
- };
3259
- var resolveOpenAIBuiltInImageSurcharge = (model, usage) => {
3260
- const imageGenerationCount = asOptionalFiniteNumber(usage.image_generation_count) ?? 0;
3261
- const pricePerImage = getApproxPricePerImage(model) ?? // gpt-image-2 已收进 nolo 平台托管目录(provider=nolo)
3262
- getApproxPricePerImage(findModelConfig("nolo", "gpt-image-2")) ?? 0;
3263
- if (imageGenerationCount <= 0 || pricePerImage <= 0) return 0;
3264
- return imageGenerationCount * pricePerImage;
3265
- };
3266
- var calculateBasicCost = (model, usage, provider, externalPrice, billingServiceTier, nowMs) => {
3267
- if (!usage || typeof usage.input_tokens !== "number") {
3268
- throw new Error("Invalid usage data");
3269
- }
3270
- const resolvedPrice = resolveEffectiveModelPrice({
3271
- model,
3272
- usage,
3273
- provider,
3274
- billingServiceTier,
3275
- nowMs
3276
- });
3277
- switch (provider) {
3278
- case "deepseek":
3279
- case "openai":
3280
- case "deepinfra":
3281
- case "runinfra":
3282
- case "baseten":
3283
- return calculateCacheBasedCost(resolvedPrice, usage, externalPrice);
3284
- // without it keep simple full-price billing so cached tokens are not
3285
- // priced at 0 — but a platform-hosted model用于 agentic 循环时必须补上
3286
- // 这一项,否则每轮重放的上下文会被按 input 原价重复计费。
3287
- case "nolo":
3288
- case "upstream-k3":
3289
- return typeof resolvedPrice.inputCacheHit === "number" ? calculateCacheBasedCost(resolvedPrice, usage, externalPrice) : calculateSimpleCost(resolvedPrice, usage, externalPrice);
3290
- case "anthropic":
3291
- return calculateAnthropicCost(resolvedPrice, usage, externalPrice);
3292
- case "google":
3293
- if (model.name.includes("gemini-3")) {
3294
- return calculateAnthropicCost(resolvedPrice, usage, externalPrice);
3295
- }
3296
- return calculateSimpleCost(resolvedPrice, usage, externalPrice);
3297
- case "openrouter": {
3298
- const reported = calculateApiReportedCost(usage);
3299
- if (reported.regular > 0) return reported;
3300
- return calculateOpenRouterFallbackCost(
3301
- resolvedPrice,
3302
- usage,
3303
- externalPrice
3304
- );
3305
- }
3306
- case "xai": {
3307
- const reported = calculateApiReportedCost(usage);
3308
- if (reported.regular > 0) return reported;
3309
- return calculateSimpleCost(resolvedPrice, usage, externalPrice);
3310
- }
3311
- case "mistral":
3312
- case "fireworks":
3313
- default:
3314
- return calculateSimpleCost(resolvedPrice, usage, externalPrice);
3315
- }
3316
- };
3317
- var calculatePayDistribution = (costs, externalPrice, sharingLevel = "default") => {
3318
- const pay = {};
3319
- pay[nolotusId] = costs.regular;
3320
- const sharingRatios = {
3321
- default: 0,
3322
- split: 0.5,
3323
- full: 1
3324
- };
3325
- if (externalPrice?.creatorId) {
3326
- const profit = Math.max(0, costs.charge - costs.regular);
3327
- if (profit > 0) {
3328
- switch (sharingLevel) {
3329
- case "split":
3330
- pay[externalPrice.creatorId] = profit * sharingRatios.split;
3331
- break;
3332
- case "full":
3333
- pay[externalPrice.creatorId] = profit;
3334
- break;
3335
- default:
3336
- break;
3337
- }
3338
- }
3339
- }
3340
- return Object.fromEntries(
3341
- Object.entries(pay).map(([key, value]) => [
3342
- key,
3343
- Number(value.toFixed(6))
3344
- ])
3345
- );
3346
- };
3347
- var calculatePrice = ({
3348
- modelName,
3349
- usage,
3350
- externalPrice,
3351
- // 不设默认值,undefined 表示 custom/未知 provider,走 zeroCostModel 路径
3352
- provider,
3353
- billingServiceTier,
3354
- nowMs,
3355
- sharingLevel = "default"
3356
- }) => {
3357
- let model;
3358
- try {
3359
- model = getModelConfig(provider, modelName);
3360
- } catch {
3361
- if (provider === "baseten" && /^(?:zai-org\/)?glm-5[.-]3-flash$/i.test(modelName)) {
3362
- const costs3 = calculateBasicCost(
3363
- { name: modelName, hasVision: true, price: PLATFORM_HOSTED_GLM_53_FLASH_BASETEN_PRICE },
3364
- usage,
3365
- "baseten",
3366
- externalPrice,
3367
- billingServiceTier,
3368
- nowMs
3369
- );
3370
- const pay3 = calculatePayDistribution(costs3, externalPrice, sharingLevel);
3371
- return { cost: sanitizeCost(costs3.charge), pay: pay3 };
3372
- }
3373
- if (isPlatformHostedImageModel(modelName)) {
3374
- const hostedImageModel = getModelConfig("nolo", modelName);
3375
- const costs3 = calculateBasicCost(
3376
- hostedImageModel,
3377
- usage,
3378
- provider ?? "nolo",
3379
- externalPrice,
3380
- billingServiceTier,
3381
- nowMs
3382
- );
3383
- const surcharge = isPlatformHostedOpenAIImageModel(modelName) ? resolveOpenAIBuiltInImageSurcharge(hostedImageModel, usage) : 0;
3384
- const adjusted = surcharge > 0 ? {
3385
- ...costs3,
3386
- regular: costs3.regular + surcharge,
3387
- charge: costs3.charge + surcharge
3388
- } : costs3;
3389
- const pay3 = calculatePayDistribution(adjusted, externalPrice, sharingLevel);
3390
- return { cost: sanitizeCost(adjusted.charge), pay: pay3 };
3391
- }
3392
- if ((provider === "nolo" || provider === "deepseek") && isPlatformHostedDeepSeekV4Model(modelName)) {
3393
- const hostedModel = getModelConfig(
3394
- "nolo",
3395
- asTrimmedLowercaseString(modelName) === PLATFORM_HOSTED_DEEPSEEK_PRO_MODEL ? PLATFORM_HOSTED_DEEPSEEK_PRO_MODEL : PLATFORM_HOSTED_DEEPSEEK_FLASH_MODEL
3396
- );
3397
- const costs3 = calculateBasicCost(
3398
- hostedModel,
3399
- usage,
3400
- provider,
3401
- externalPrice,
3402
- billingServiceTier,
3403
- nowMs
3404
- );
3405
- const pay3 = calculatePayDistribution(costs3, externalPrice, sharingLevel);
3406
- return { cost: sanitizeCost(costs3.charge), pay: pay3 };
3407
- }
3408
- if (provider === "nolo" && isPlatformHostedClaudeModel(modelName)) {
3409
- const compatModel = getModelConfig("nolo", PLATFORM_HOSTED_GLM_53_FLASH_MODEL);
3410
- const costs3 = calculateBasicCost(
3411
- compatModel,
3412
- usage,
3413
- provider,
3414
- externalPrice,
3415
- billingServiceTier,
3416
- nowMs
3417
- );
3418
- const pay3 = calculatePayDistribution(costs3, externalPrice, sharingLevel);
3419
- return { cost: sanitizeCost(costs3.charge), pay: pay3 };
3420
- }
3421
- const zeroCostModel = {
3422
- name: modelName,
3423
- hasVision: false,
3424
- price: { input: 0, output: 0 }
3425
- };
3426
- const costs2 = calculateBasicCost(
3427
- zeroCostModel,
3428
- usage,
3429
- "custom",
3430
- externalPrice,
3431
- billingServiceTier,
3432
- nowMs
3433
- );
3434
- const pay2 = calculatePayDistribution(costs2, externalPrice, sharingLevel);
3435
- return { cost: sanitizeCost(costs2.charge), pay: pay2 };
3436
- }
3437
- const costs = calculateBasicCost(
3438
- model,
3439
- usage,
3440
- provider || "custom",
3441
- externalPrice,
3442
- billingServiceTier,
3443
- nowMs
3444
- );
3445
- const openAIImageSurcharge = provider === "openai" ? resolveOpenAIBuiltInImageSurcharge(model, usage) : 0;
3446
- const adjustedCosts = openAIImageSurcharge > 0 ? {
3447
- ...costs,
3448
- regular: costs.regular + openAIImageSurcharge,
3449
- charge: costs.charge + openAIImageSurcharge,
3450
- details: costs.details ? {
3451
- ...costs.details,
3452
- outputCost: costs.details.outputCost + openAIImageSurcharge
3453
- } : costs.details
3454
- } : costs;
3455
- const pay = calculatePayDistribution(adjustedCosts, externalPrice, sharingLevel);
3456
- return {
3457
- cost: sanitizeCost(adjustedCosts.charge),
3458
- pay
3459
- };
3460
- };
3461
-
3462
- // packages/ai/token/normalizeUsage.ts
3463
- var normalizeStringArray = (value) => {
3464
- if (!Array.isArray(value)) return void 0;
3465
- const normalized = [...new Set(asTrimmedNonEmptyStringArray(value))];
3466
- return normalized.length > 0 ? normalized : void 0;
3467
- };
3468
- var finiteTokenCount = (value) => {
3469
- const finite = asOptionalFiniteNumber(value);
3470
- if (finite === void 0) return void 0;
3471
- return Math.max(0, Math.floor(finite));
3472
- };
3473
- var readFiniteNumberField = (usage, field) => {
3474
- if (!usage || typeof usage !== "object") return void 0;
3475
- if (!(field in usage)) return void 0;
3476
- const candidate = usage[field];
3477
- return asOptionalFiniteNumber(candidate);
3478
- };
3479
- var readCostInUsdTicks = (usage) => readFiniteNumberField(usage, "cost_in_usd_ticks");
3480
- var normalizeUsage = (usage) => {
3481
- if (!usage || typeof usage !== "object") {
3482
- return {
3483
- input_tokens: 0,
3484
- output_tokens: 0,
3485
- total_tokens: 0,
3486
- cache_creation_input_tokens: 0,
3487
- cache_read_input_tokens: 0,
3488
- cost: 0
3489
- };
3490
- }
3491
- const inputTokens = "input_tokens" in usage ? usage.input_tokens ?? 0 : "prompt_tokens" in usage ? usage.prompt_tokens : 0;
3492
- const outputTokens = "output_tokens" in usage ? usage.output_tokens ?? 0 : "completion_tokens" in usage ? usage.completion_tokens : 0;
3493
- const cacheCreationInputTokens = readCacheCreationInputTokens(usage);
3494
- const cacheReadInputTokens = readCacheReadInputTokens(usage);
3495
- let cost = 0;
3496
- const providedCost = readFiniteNumberField(usage, "cost");
3497
- if (providedCost !== void 0) {
3498
- cost = providedCost;
3499
- }
3500
- const xaiTicks = readCostInUsdTicks(usage);
3501
- if (xaiTicks !== void 0 && providedCost === void 0) {
3502
- cost = xaiTicks / 1e10;
3503
- }
3504
- const billingProvider = asOptionalTrimmedString(usage.billing_provider);
3505
- const billingModel = asOptionalTrimmedString(usage.billing_model);
3506
- const billingServiceTier = asOptionalTrimmedString(usage.billing_service_tier);
3507
- const billingEstimated = "billing_estimated" in usage && usage.billing_estimated === true;
3508
- const serverBilled = "server_billed" in usage && usage.server_billed === true;
3509
- const providerCallId = asOptionalTrimmedString(usage.provider_call_id);
3510
- const imageGenerationCount = "image_generation_count" in usage ? asOptionalFiniteNumber(usage.image_generation_count) : void 0;
3511
- const providerResponseIds = normalizeStringArray(
3512
- usage.provider_response_ids
3513
- );
3514
- const providerRequestIds = normalizeStringArray(
3515
- usage.provider_request_ids
3516
- );
3517
- const firstOutputMs = normalizeTimingMs(
3518
- readFiniteNumberField(usage, "firstOutputMs") ?? readFiniteNumberField(usage, "firstTokenMs")
3519
- );
3520
- const callDurationMs = normalizeTimingMs(
3521
- readFiniteNumberField(usage, "callDurationMs") ?? readFiniteNumberField(usage, "durationMs")
3522
- );
3523
- return {
3524
- input_tokens: inputTokens,
3525
- output_tokens: outputTokens,
3526
- total_tokens: finiteTokenCount(usage.total_tokens) ?? inputTokens + outputTokens,
3527
- cache_creation_input_tokens: cacheCreationInputTokens,
3528
- cache_read_input_tokens: cacheReadInputTokens,
3529
- cost,
3530
- ...typeof imageGenerationCount === "number" ? { image_generation_count: imageGenerationCount } : {},
3531
- ...providerResponseIds ? { provider_response_ids: providerResponseIds } : {},
3532
- ...providerRequestIds ? { provider_request_ids: providerRequestIds } : {},
3533
- ...billingProvider ? { billing_provider: billingProvider } : {},
3534
- ...billingModel ? { billing_model: billingModel } : {},
3535
- ...billingServiceTier ? { billing_service_tier: billingServiceTier } : {},
3536
- ...billingEstimated ? { billing_estimated: true } : {},
3537
- ...serverBilled ? { server_billed: true } : {},
3538
- ...providerCallId ? { provider_call_id: providerCallId } : {},
3539
- ...xaiTicks !== void 0 ? { cost_in_usd_ticks: xaiTicks } : {},
3540
- ...firstOutputMs !== void 0 ? { firstOutputMs } : {},
3541
- ...callDurationMs !== void 0 ? { callDurationMs } : {}
3542
- };
3543
- };
3544
-
3545
- // packages/ai/token/resolveBillingTarget.ts
3546
- var normalizeString2 = (value) => {
3547
- const trimmed = asTrimmedString(value);
3548
- return trimmed || void 0;
3549
- };
3550
- var resolveBillingModel = (usageModel, fallbackModel) => {
3551
- const model = normalizeString2(usageModel) ?? normalizeString2(fallbackModel);
3552
- if (!model) {
3553
- throw new Error("Billing model is required");
3554
- }
3555
- return model;
3556
- };
3557
- var resolveBillingTarget = ({
3558
- usage,
3559
- fallbackProvider,
3560
- fallbackModel
3561
- }) => {
3562
- const provider = normalizeString2(usage?.billing_provider) ?? normalizeString2(fallbackProvider);
3563
- const model = resolveBillingModel(usage?.billing_model, fallbackModel);
3564
- const serviceTier = normalizeString2(usage?.billing_service_tier);
3565
- return {
3566
- provider,
3567
- model,
3568
- serviceTier
3569
- };
3570
- };
3571
-
3572
- // packages/ai/token/usageConstants.ts
3573
- var LOCAL_USER_ID = "local";
3574
-
3575
- // packages/ai/token/prepareTokenUsageData.ts
3576
- function resolveTokenUsagePricing(args) {
3577
- const { rawUsage, agentConfig, nowMs } = args;
3578
- const usage = normalizeUsage(rawUsage);
3579
- const billingTarget = resolveBillingTarget({
3580
- usage,
3581
- fallbackProvider: agentConfig.provider,
3582
- fallbackModel: agentConfig.model
3583
- });
3584
- const billedProvider = billingTarget.provider;
3585
- const billedModel = billingTarget.model;
3586
- const billedServiceTier = billingTarget.serviceTier;
3587
- const canonicalAgentId = args.agentId?.trim();
3588
- const isCodeOwnedBuiltin = isBuiltinPlatformAgentKey(canonicalAgentId);
3589
- const isPlatformBilled = agentConfig.apiSource === "platform";
3590
- const hasPersistedPrices = agentConfig.inputPrice !== void 0 && agentConfig.inputPrice > 0 || agentConfig.outputPrice !== void 0 && agentConfig.outputPrice > 0;
3591
- if (isPlatformBilled && !isCodeOwnedBuiltin && hasPersistedPrices) {
3592
- console.warn(
3593
- `[billing] platform agent ignored persisted prices (input=${agentConfig.inputPrice}, output=${agentConfig.outputPrice}); canonical key missing or not in builtin set: "${canonicalAgentId || ""}"`
3594
- );
3595
- }
3596
- const hasExternalPrice = !isCodeOwnedBuiltin && !isPlatformBilled && hasPersistedPrices;
3597
- const { cost, pay } = calculatePrice({
3598
- provider: billedProvider,
3599
- modelName: billedModel,
3600
- billingServiceTier: billedServiceTier,
3601
- usage,
3602
- externalPrice: hasExternalPrice ? {
3603
- input: agentConfig.inputPrice ?? 0,
3604
- output: agentConfig.outputPrice ?? 0,
3605
- creatorId: agentConfig.userId ?? (agentConfig.id ? extractUserId(agentConfig.id) : "")
3606
- } : void 0,
3607
- sharingLevel: agentConfig.sharingLevel,
3608
- nowMs
3609
- });
3610
- return {
3611
- usage,
3612
- billedProvider,
3613
- billedModel,
3614
- billedServiceTier,
3615
- cost,
3616
- pay,
3617
- hasExternalPrice
3618
- };
3619
- }
3620
- function resolveBillable(input) {
3621
- const uid = input.userId?.trim();
3622
- if (!uid || uid === LOCAL_USER_ID) return false;
3623
- const apiSource = input.apiSource;
3624
- if (apiSource === "cli") return false;
3625
- if (isOAuthApiKeyRef(input.apiKeyRef)) return false;
3626
- if (input.cost <= 0) return false;
3627
- if (apiSource === "platform") return true;
3628
- if (apiSource === "custom") return input.hasExternalPrice;
3629
- if (apiSource == null || apiSource === "") return true;
3630
- return false;
3631
- }
3632
- function resolveBillableForAgent(input) {
3633
- const { usage, cost, userId, agentConfig } = input;
3634
- const hasExternalPrice = input.hasExternalPrice ?? (agentConfig.inputPrice !== void 0 && agentConfig.inputPrice > 0 || agentConfig.outputPrice !== void 0 && agentConfig.outputPrice > 0);
3635
- return resolveBillable({
3636
- usage,
3637
- userId,
3638
- apiSource: agentConfig.apiSource,
3639
- apiKeyRef: agentConfig.apiKeyRef,
3640
- cost,
3641
- hasExternalPrice
3642
- });
3643
- }
3644
- var prepareTokenUsageData = ({
3645
- rawUsage,
3646
- agentConfig,
3647
- userId,
3648
- username,
3649
- agentId,
3650
- cybotId,
3651
- dialogId,
3652
- timestamp = Date.now(),
3653
- stable_prefix_hash,
3654
- stable_prefix_estimated_tokens,
3655
- entry_path
3656
- }) => {
3657
- const resolvedAgentId = typeof agentId === "string" && agentId.trim() || typeof cybotId === "string" && cybotId.trim() || "";
3658
- const { usage, billedProvider, billedModel, billedServiceTier, cost, pay, hasExternalPrice } = resolveTokenUsagePricing({
3659
- rawUsage,
3660
- agentConfig,
3661
- agentId: resolvedAgentId,
3662
- nowMs: timestamp
3663
- });
3664
- const recordProvider = billedProvider ?? agentConfig.provider ?? "unknown";
3665
- const billable = resolveBillableForAgent({
3666
- usage,
3667
- cost,
3668
- userId,
3669
- agentConfig,
3670
- hasExternalPrice
3671
- });
3672
- return {
3673
- usage,
3674
- billedProvider,
3675
- billedModel,
3676
- billedServiceTier,
3677
- recordProvider,
3678
- tokenData: {
3679
- ...usage,
3680
- userId,
3681
- username,
3682
- agentId: resolvedAgentId,
3683
- cybotId: resolvedAgentId,
3684
- model: billedModel,
3685
- provider: recordProvider,
3686
- billing_service_tier: billedServiceTier,
3687
- dialogId,
3688
- cost,
3689
- pay,
3690
- timestamp,
3691
- billable,
3692
- ...stable_prefix_hash !== void 0 ? { stable_prefix_hash } : {},
3693
- ...stable_prefix_estimated_tokens !== void 0 ? { stable_prefix_estimated_tokens } : {},
3694
- ...entry_path !== void 0 ? { entry_path } : {}
3695
- }
3696
- };
3697
- };
3698
-
3699
- // packages/ai/token/applyTokenUsageToDayStats.ts
3700
- var ZERO_STATS = {
3701
- count: 0,
3702
- tokens: { input: 0, output: 0, cacheRead: 0, cacheCreation: 0 },
3703
- cost: 0,
3704
- failedCount: 0
3705
- };
3706
- function normalizeStats(s) {
3707
- if (!s) return { ...ZERO_STATS };
3708
- const t = s.tokens;
3709
- return {
3710
- count: s.count ?? 0,
3711
- tokens: {
3712
- input: t?.input ?? 0,
3713
- output: t?.output ?? 0,
3714
- cacheRead: t?.cacheRead ?? t?.cache_read ?? 0,
3715
- cacheCreation: t?.cacheCreation ?? t?.cache_creation ?? 0
3716
- },
3717
- cost: s.cost ?? 0,
3718
- failedCount: s.failedCount ?? 0
3719
- };
3720
- }
3721
- function normalizeDayStats(prev, userId, timeKey) {
3722
- if (!prev) {
3723
- return {
3724
- userId,
3725
- period: "day",
3726
- timeKey,
3727
- total: { ...ZERO_STATS },
3728
- models: {},
3729
- providers: {},
3730
- agents: {},
3731
- entryPaths: {},
3732
- categories: {},
3733
- modelCategories: {}
3734
- };
3735
- }
3736
- const normalizeMap = (m) => {
3737
- if (!m) return {};
3738
- const out = {};
3739
- for (const [k, v] of Object.entries(m)) out[k] = normalizeStats(v);
3740
- return out;
3741
- };
3742
- const normalizedTotal = normalizeStats(prev.total);
3743
- const normalizedModels = normalizeMap(prev.models);
3744
- const normalizedProviders = normalizeMap(prev.providers);
3745
- const normalizedAgents = normalizeMap(prev.agents);
3746
- const normalizedEntryPaths = normalizeMap(prev.entryPaths);
3747
- let categories = normalizeMap(prev.categories);
3748
- let modelCategories = normalizeMap(prev.modelCategories);
3749
- const hasCategories = Object.keys(categories).length > 0;
3750
- const hasModelCategories = Object.keys(modelCategories).length > 0;
3751
- if (!hasCategories) {
3752
- const hasActivity = normalizedTotal.count > 0 || normalizedTotal.failedCount > 0 || normalizedTotal.cost > 0 || normalizedTotal.tokens.input > 0 || normalizedTotal.tokens.output > 0;
3753
- if (hasActivity) {
3754
- categories = { platform: { ...normalizedTotal } };
3755
- }
3756
- }
3757
- if (!hasModelCategories && Object.keys(normalizedModels).length > 0) {
3758
- const legacyModelCats = {};
3759
- for (const [modelKey, modelStat] of Object.entries(normalizedModels)) {
3760
- legacyModelCats[`${modelKey}:::platform`] = { ...modelStat };
3761
- }
3762
- modelCategories = legacyModelCats;
3763
- }
3764
- return {
3765
- ...prev,
3766
- total: normalizedTotal,
3767
- models: normalizedModels,
3768
- providers: normalizedProviders,
3769
- agents: normalizedAgents,
3770
- entryPaths: normalizedEntryPaths,
3771
- categories,
3772
- modelCategories
3773
- };
3774
- }
3775
- function applyTokenUsageToDayStats(prev, delta) {
3776
- const base = normalizeDayStats(prev, delta.userId, delta.timeKey);
3777
- const modelName = delta.model || "unknown";
3778
- const providerName = delta.provider || "unknown";
3779
- const cacheRead = delta.cache_read_input_tokens ?? 0;
3780
- const cacheCreation = delta.cache_creation_input_tokens ?? 0;
3781
- const isFailed = delta.status === "failed";
3782
- const category = delta.billingCategory || "platform";
3783
- const modelCategoryKey = `${modelName}:::${category}`;
3784
- const inc = (s) => {
3785
- const n = normalizeStats(s);
3786
- if (isFailed) {
3787
- return {
3788
- ...n,
3789
- failedCount: n.failedCount + 1
3790
- };
3791
- }
3792
- return {
3793
- count: n.count + 1,
3794
- tokens: {
3795
- input: n.tokens.input + delta.input_tokens,
3796
- output: n.tokens.output + delta.output_tokens,
3797
- cacheRead: n.tokens.cacheRead + cacheRead,
3798
- cacheCreation: n.tokens.cacheCreation + cacheCreation
3799
- },
3800
- // 非计费记录(订阅/OAuth/CLI,billable=false)不向平台积分统计贡献 cost:
3801
- // 订阅已付费、不按 token 计费,若不归零,图表「成本」视图会把订阅用量误显示为积分消耗。
3802
- cost: Number((n.cost + (category === "subscription" ? 0 : delta.cost)).toFixed(6)),
3803
- failedCount: n.failedCount
3804
- };
3805
- };
3806
- const result = {
3807
- ...base,
3808
- total: inc(base.total),
3809
- models: {
3810
- ...base.models,
3811
- [modelName]: inc(base.models[modelName])
3812
- },
3813
- providers: {
3814
- ...base.providers,
3815
- [providerName]: inc(base.providers[providerName])
3816
- },
3817
- categories: {
3818
- ...base.categories,
3819
- [category]: inc(base.categories?.[category])
3820
- },
3821
- modelCategories: {
3822
- ...base.modelCategories,
3823
- [modelCategoryKey]: inc(base.modelCategories?.[modelCategoryKey])
3824
- }
3825
- };
3826
- if (delta.agentId !== void 0) {
3827
- const agentKey = delta.agentId || "unknown";
3828
- result.agents = {
3829
- ...base.agents,
3830
- [agentKey]: inc(base.agents[agentKey])
3831
- };
3832
- }
3833
- if (delta.entry_path !== void 0) {
3834
- const entryKey = delta.entry_path || "unknown";
3835
- result.entryPaths = {
3836
- ...base.entryPaths,
3837
- [entryKey]: inc(base.entryPaths[entryKey])
3838
- };
3839
- }
3840
- return result;
3841
- }
3842
-
3843
- // packages/core/keyedTaskQueue.ts
3844
- var queues = /* @__PURE__ */ new Map();
3845
- async function runKeyed(key, task) {
3846
- const previous = queues.get(key) ?? Promise.resolve();
3847
- const next = previous.catch(() => void 0).then(task);
3848
- const cleanup = next.then(
3849
- () => void 0,
3850
- () => void 0
3851
- );
3852
- queues.set(key, cleanup);
3853
- try {
3854
- return await next;
3855
- } finally {
3856
- if (queues.get(key) === cleanup) {
3857
- queues.delete(key);
3858
- }
3859
- }
3860
- }
3861
-
3862
- // packages/chat/dialog/actions/updateTokensAction.ts
3863
- var logger2 = createClientLogger("token-usage");
3864
- var dialogTokenPatchQueue = /* @__PURE__ */ new Map();
3865
- var queueDialogTokenPatch = async (dialogKey, task) => {
3866
- const previousTask = dialogTokenPatchQueue.get(dialogKey) ?? Promise.resolve();
3867
- const nextTask = previousTask.catch(() => void 0).then(task);
3868
- const queueEntry = nextTask.then(
3869
- () => void 0,
3870
- () => void 0
3871
- );
3872
- dialogTokenPatchQueue.set(dialogKey, queueEntry);
3873
- try {
3874
- return await nextTask;
3875
- } finally {
3876
- if (dialogTokenPatchQueue.get(dialogKey) === queueEntry) {
3877
- dialogTokenPatchQueue.delete(dialogKey);
3878
- }
3879
- }
3880
- };
3881
- var updateStats = async (data, existingStats, key, thunkApi) => {
3882
- try {
3883
- const dateKey = (0, import_date_fns.format)(data.timestamp ?? Date.now(), "yyyy-MM-dd");
3884
- const newStats = applyTokenUsageToDayStats(existingStats, {
3885
- userId: data.userId ?? "",
3886
- timeKey: dateKey,
3887
- model: data.model || "unknown",
3888
- provider: data.provider || "unknown",
3889
- input_tokens: data.input_tokens,
3890
- output_tokens: data.output_tokens,
3891
- cost: data.cost,
3892
- cache_read_input_tokens: data.cache_read_input_tokens,
3893
- cache_creation_input_tokens: data.cache_creation_input_tokens,
3894
- agentId: data.agentId ?? data.cybotId,
3895
- entry_path: data.entry_path,
3896
- billingCategory: data.billable ? "platform" : "subscription"
3897
- });
3898
- await thunkApi.dispatch(
3899
- write({
3900
- data: { ...newStats, id: key, type: "token" /* TOKEN */ },
3901
- customKey: key,
3902
- userId: data.userId
3903
- })
3904
- ).unwrap();
3905
- return newStats;
3906
- } catch (error) {
3907
- logger2.error(
3908
- { key, userId: data.userId, error: error.message },
3909
- "Failed to update token stats"
3910
- );
3911
- toast.error("Failed to update token stats");
3912
- throw error;
3913
- }
3914
- };
3915
- var saveTokenUsage = async (data, thunkApi) => {
3916
- const dateKey = (0, import_date_fns.format)(data.timestamp ?? Date.now(), "yyyy-MM-dd");
3917
- const tokenDayStatsKey = createTokenStatsKey(data.userId ?? "", dateKey);
3918
- return runKeyed(tokenDayStatsKey, async () => {
3919
- try {
3920
- let currentStats = null;
3921
- try {
3922
- currentStats = await thunkApi.dispatch(read({
3923
- dbKey: tokenDayStatsKey
3924
- })).unwrap();
3925
- } catch (err) {
3926
- logger2.warn({ tokenDayStatsKey }, "No existing stats found");
3927
- }
3928
- const updatedStats = await updateStats(
3929
- data,
3930
- currentStats,
3931
- tokenDayStatsKey,
3932
- thunkApi
3933
- );
3934
- return {
3935
- success: true,
3936
- id: ulid(Date.now()),
3937
- record: updatedStats
3938
- };
3939
- } catch (error) {
3940
- logger2.error(
3941
- {
3942
- key: tokenDayStatsKey,
3943
- userId: data.userId,
3944
- error: error.message,
3945
- tokenData: {
3946
- input: data.input_tokens,
3947
- output: data.output_tokens,
3948
- model: data.model
3949
- }
3950
- },
3951
- "Failed to process token usage"
3952
- );
3953
- toast.error("Failed to process token usage");
3954
- throw error;
3955
- }
3956
- });
3957
- };
3958
- var updateTokensAction = async ({ dialogId, dialogKey, usage: legacyUsage, usageRecord, agentConfig }, thunkApi) => {
3959
- const state = thunkApi.getState();
3960
- const currentUser = selectIdentityUser(state);
3961
- const dialogConfig = dialogKey ? selectById(state, dialogKey) : null;
3962
- const dialogConfigUserId = dialogConfig?.userId;
3963
- const ownerUserId = resolveMessageOwner({
3964
- dialogConfigUserId: typeof dialogConfigUserId === "string" ? dialogConfigUserId : null,
3965
- dialogKey: typeof dialogKey === "string" ? dialogKey : "",
3966
- currentAccountUserId: currentUser?.userId ?? null
3967
- });
3968
- const timestamp = Date.now();
3969
- const usageRaw = usageRecord?.usage ?? legacyUsage;
3970
- const callId = (typeof usageRecord?.callId === "string" && usageRecord.callId.trim() ? usageRecord.callId.trim() : void 0) ?? (typeof usageRaw?.provider_call_id === "string" && usageRaw.provider_call_id.trim() ? usageRaw.provider_call_id.trim() : void 0);
3971
- const usageWithStableCallId = callId && !usageRaw?.provider_call_id ? { ...usageRaw, provider_call_id: callId } : usageRaw;
3972
- const callAgentConfig = {
3973
- ...agentConfig,
3974
- ...typeof usageRecord?.model === "string" ? { model: usageRecord.model } : {},
3975
- ...typeof usageRecord?.provider === "string" ? { provider: usageRecord.provider } : {}
3976
- };
3977
- const prepared = prepareTokenUsageData({
3978
- rawUsage: usageWithStableCallId,
3979
- agentConfig: callAgentConfig,
3980
- userId: ownerUserId,
3981
- username: currentUser?.username,
3982
- // agentConfig.id is the canonical ulid; dbKey (agent-<userId>-<id>) is
3983
- // always present on db records. Quick-chat may construct agentConfig with
3984
- // only dbKey, so fall back to keep billing working (matches serverTokenWriter
3985
- // which passes agentKey = dbKey directly).
3986
- agentId: agentConfig.id || agentConfig.dbKey,
3987
- dialogId,
3988
- timestamp,
3989
- entry_path: "web-chat"
3990
- });
3991
- const { usage, tokenData, recordProvider, billedModel } = prepared;
3992
- const result = { cost: tokenData.cost, pay: tokenData.pay };
3993
- const persistedTokenData = {
3994
- ...tokenData,
3995
- type: "token" /* TOKEN */,
3996
- id: ulid(timestamp),
3997
- dateKey: (0, import_date_fns.format)(timestamp, "yyyy-MM-dd"),
3998
- // Keep the same clock used for id/dateKey so record keys never see
3999
- // undefined when a prepare helper omits timestamp.
4000
- timestamp
4001
- };
4002
- const stableTokenKey = callId ? createTokenKey.recordForStableCall(ownerUserId, callId) : null;
4003
- const accountingAlreadyProjected = stableTokenKey ? Boolean(selectById(state, stableTokenKey)) : false;
4004
- const billedCatalog = findModelConfig(recordProvider, billedModel)?.price;
4005
- const record = createTokenRecord(persistedTokenData, {
4006
- cost: result.cost,
4007
- inputPrice: billedCatalog?.input ?? agentConfig.inputPrice,
4008
- outputPrice: billedCatalog?.output ?? agentConfig.outputPrice
4009
- });
4010
- await saveTokenRecord(persistedTokenData, record, thunkApi, callId);
4011
- if (accountingAlreadyProjected) {
4012
- return {
4013
- input_tokens: usage.input_tokens,
4014
- output_tokens: usage.output_tokens,
4015
- cost: result.cost
4016
- };
4017
- }
4018
- await saveTokenUsage(persistedTokenData, thunkApi);
4019
- if (persistedTokenData.billable === true || persistedTokenData.billable === void 0 && result.cost > 0) {
4020
- thunkApi.extra?.accountSession?.deductBalance(result.cost);
4021
- }
4022
- if (dialogKey) {
4023
- await queueDialogTokenPatch(dialogKey, async () => {
4024
- const latestState = thunkApi.getState();
4025
- const dialogConfig2 = selectById(latestState, dialogKey) ?? await thunkApi.dispatch(read({ dbKey: dialogKey })).unwrap();
4026
- if (!dialogConfig2) {
4027
- throw new Error(`Dialog not found for token update: ${dialogKey}`);
4028
- }
4029
- await thunkApi.dispatch(
4030
- patch({
4031
- dbKey: dialogKey,
4032
- changes: {
4033
- inputTokens: (dialogConfig2.inputTokens ?? 0) + usage.input_tokens,
4034
- outputTokens: (dialogConfig2.outputTokens ?? 0) + usage.output_tokens,
4035
- totalCost: (dialogConfig2.totalCost ?? 0) + result.cost
4036
- }
4037
- })
4038
- ).unwrap();
4039
- });
4040
- }
4041
- return {
4042
- input_tokens: usage.input_tokens,
4043
- output_tokens: usage.output_tokens,
4044
- cost: result.cost
4045
- };
4046
- };
4047
-
4048
- // packages/chat/dialog/dialogTokenStats.ts
4049
- var mergeDialogTokenStats = (dialogConfig, runtimeTokens) => ({
4050
- inputTokens: (dialogConfig?.inputTokens ?? 0) + runtimeTokens.inputTokens,
4051
- outputTokens: (dialogConfig?.outputTokens ?? 0) + runtimeTokens.outputTokens,
4052
- totalCost: (dialogConfig?.totalCost ?? 0) + runtimeTokens.totalCost
4053
- });
4054
-
4055
- // packages/chat/dialog/deleteDialogOrchestration.ts
4056
- var collectKeys = async (prefix, db) => {
4057
- const keys = [];
4058
- let iterator = db.iterator({
4059
- gte: prefix,
4060
- lte: prefix + "\uFFFF"
4061
- });
4062
- if (iterator && typeof iterator.then === "function") {
4063
- iterator = await iterator;
4064
- }
4065
- for await (const [key] of iterator) {
4066
- keys.push(key);
4067
- }
4068
- return keys;
4069
- };
4070
- var collectEntries = async (prefix, db) => {
4071
- const entries = [];
4072
- let iterator = db.iterator({
4073
- gte: prefix,
4074
- lte: prefix + "\uFFFF"
4075
- });
4076
- if (iterator && typeof iterator.then === "function") {
4077
- iterator = await iterator;
4078
- }
4079
- for await (const [key, value] of iterator) {
4080
- entries.push([key, value]);
4081
- }
4082
- return entries;
4083
- };
4084
- var dbGetOrNull = async (db, key) => {
4085
- if (!db || typeof db.get !== "function") return null;
4086
- try {
4087
- return await db.get(key);
4088
- } catch {
4089
- return null;
4090
- }
4091
- };
4092
- var readLocalFileMetadata = async (db, fileId) => {
4093
- const direct = await dbGetOrNull(db, fileId);
4094
- if (direct) return direct;
4095
- const index = await dbGetOrNull(db, createKey("file", "id", fileId));
4096
- const mainKey = asOptionalTrimmedString(index?.mainKey) ?? null;
4097
- return mainKey ? await dbGetOrNull(db, mainKey) : null;
4098
- };
4099
- var normalizeDeleteDialogPayload = (payload) => typeof payload === "string" ? { dialogKey: payload, includeAttachments: false } : {
4100
- dialogKey: payload.dialogKey,
4101
- includeAttachments: payload.includeAttachments === true
4102
- };
4103
- var deleteOwnedDialogAttachments = async (args) => {
4104
- const messages = args.entries.map(
4105
- ([dbKey, value]) => ({
4106
- ...asRecordOrEmpty(value),
4107
- dbKey
4108
- })
4109
- );
4110
- const fileIds = [
4111
- ...new Set(messages.flatMap((message) => extractFileContentIds(message)))
4112
- ];
4113
- const metadataByFileId = {};
4114
- const metadataReadFailures = [];
4115
- for (const fileId of fileIds) {
4116
- const metadata = await readLocalFileMetadata(args.db, fileId);
4117
- if (metadata) {
4118
- metadataByFileId[fileId] = metadata;
4119
- } else {
4120
- metadataReadFailures.push({
4121
- fileId,
4122
- error: "local file metadata not found"
4123
- });
4124
- }
4125
- }
4126
- const plan = buildDialogAttachmentPlan({
4127
- dialogId: args.dialogId,
4128
- messages,
4129
- metadataByFileId,
4130
- metadataReadFailures
4131
- });
4132
- if (!plan.deleteCandidates.length) return plan;
4133
- const { deleteFileAction } = await import("./deleteFile-LWSR674W.js");
4134
- for (const candidate of plan.deleteCandidates) {
4135
- if (candidate.fileDbKey) {
4136
- await deleteFileAction(candidate.fileDbKey, args.thunkApi);
4137
- }
4138
- }
4139
- return plan;
4140
- };
4141
- var deleteDialogThunk = async (payload, thunkApi) => {
4142
- const { dialogKey, includeAttachments } = normalizeDeleteDialogPayload(payload);
4143
- const { dispatch, getState, extra } = thunkApi;
4144
- const { db } = extra;
4145
- const state = getState();
4146
- const { currentServer, syncServers } = getRuntimeServerContext(state);
4147
- const currentDialogKey = getActiveDialogKey();
4148
- const currentDialogId = currentDialogKey ? extractCustomId(currentDialogKey) : null;
4149
- const targetDialogId = extractCustomId(dialogKey);
4150
- const targetDialogConfig = selectById(state, dialogKey);
4151
- const isCurrentDialog = currentDialogId !== null && currentDialogId === targetDialogId;
4152
- await cleanupCliSessionForDialog(
4153
- { dispatch, getState },
4154
- targetDialogConfig
4155
- );
4156
- const dialogOwnerId = typeof targetDialogConfig?.userId === "string" && String(targetDialogConfig.userId).trim() || (() => {
4157
- const rest = dialogKey.startsWith("dialog-") ? dialogKey.slice("dialog-".length) : "";
4158
- const last = rest.lastIndexOf("-");
4159
- return last > 0 ? rest.slice(0, last) : "";
4160
- })();
4161
- const agentListIndexDels = buildDialogAgentListIndexDeleteOps({
4162
- userId: dialogOwnerId,
4163
- dialogKey,
4164
- dialogId: targetDialogId || void 0,
4165
- previousRecord: targetDialogConfig ? targetDialogConfig : null
4166
- });
4167
- await dispatch(remove(dialogKey));
4168
- const prefix = createKey("dialog", targetDialogId, "msg");
4169
- const deletedEntries = includeAttachments ? await collectEntries(prefix, db) : [];
4170
- const attachmentPlan = includeAttachments && targetDialogId ? await deleteOwnedDialogAttachments({
4171
- db,
4172
- dialogId: targetDialogId,
4173
- entries: deletedEntries,
4174
- thunkApi
4175
- }) : null;
4176
- const deletedIds = includeAttachments ? deletedEntries.map(([key]) => key) : await collectKeys(prefix, db);
4177
- const ops = [
4178
- ...agentListIndexDels,
4179
- ...deletedIds.map((key) => ({ type: "del", key }))
4180
- ];
4181
- if (ops.length > 0) {
4182
- await db.batch(ops);
4183
- }
4184
- if (deletedIds.length > 0) {
4185
- scheduleDeleteReplication({
4186
- currentServer,
4187
- syncServers,
4188
- dbKey: targetDialogId,
4189
- deleteOptions: { type: "messages" },
4190
- state
4191
- });
4192
- }
4193
- if (isCurrentDialog) {
4194
- await thunkApi.dispatch(resetMsgs());
4195
- const { clearPendingAttachments: clearPendingAttachments2 } = await import("./dialogSlice-DEC5GV6X.js");
4196
- dispatch(clearPendingAttachments2());
4197
- }
4198
- return { dialogKey, isCurrentDialog, attachmentPlan };
4199
- };
4200
-
4201
- // packages/chat/dialog/dialogSlice.ts
4202
- var runCreateDialogAction = async (args, thunkApi) => {
4203
- const { createDialogAction } = await import("./createDialogAction-SFMZLPS4.js");
4204
- return createDialogAction(args, thunkApi);
4205
- };
4206
- var runCreateAgentAutomationAction = async (args, thunkApi) => {
4207
- const { createAgentAutomationAction } = await import("./createAgentAutomationAction-K5YJO4IA.js");
4208
- return createAgentAutomationAction(args, thunkApi);
4209
- };
4210
- var runUpdateDialogTitleAction = async (args, thunkApi) => {
4211
- const { updateDialogTitleAction } = await import("./updateDialogTitleAction-L6CCRVUK.js");
4212
- return updateDialogTitleAction(args, thunkApi);
4213
- };
4214
- var runAddDialogAgentAction = async (args, thunkApi) => {
4215
- const { addDialogAgentAction } = await import("./addDialogAgentAction-EUBNJ5SS.js");
4216
- return addDialogAgentAction(args, thunkApi);
4217
- };
4218
- var runRemoveDialogAgentAction = async (args, thunkApi) => {
4219
- const { removeDialogAgentAction } = await import("./removeDialogAgentAction-BVU6E27N.js");
4220
- return removeDialogAgentAction(args, thunkApi);
4221
- };
4222
- var runSetPrimaryDialogAgentAction = async (args, thunkApi) => {
4223
- const { setPrimaryDialogAgentAction } = await import("./setPrimaryDialogAgentAction-HMHZWURC.js");
4224
- return setPrimaryDialogAgentAction(args, thunkApi);
4225
- };
4226
- var runSwitchDialogAgentAction = async (args, thunkApi) => {
4227
- const { switchDialogAgentAction } = await import("./switchDialogAgentAction-Y66ZTIGP.js");
4228
- return switchDialogAgentAction(args, thunkApi);
4229
- };
4230
- var runSetDialogExtraReferencesAction = async (args, thunkApi) => {
4231
- const { setDialogExtraReferencesAction } = await import("./setDialogExtraReferencesAction-AUKADSTQ.js");
4232
- return setDialogExtraReferencesAction(args, thunkApi);
4233
- };
4234
- var runHandleSendMessageAction = async (args, thunkApi) => {
4235
- const { handleSendMessageAction } = await import("./handleSendMessageAction-C7CZNGMB.js");
4236
- return handleSendMessageAction(args, thunkApi);
4237
- };
4238
- function clearDialogState() {
4239
- applyClearDialogStateRuntime();
4240
- return { type: "dialog/clearDialogState" };
4241
- }
4242
- clearDialogState.type = "dialog/clearDialogState";
4243
- var createPageAndAddReference = createAsyncThunk(
4244
- "dialog/createPageAndAddReference",
4245
- async (payload, { dispatch, getState, rejectWithValue }) => {
4246
- const { slateData, jsonData, title, type, fileId, groupId, dialogKey } = payload;
4247
- try {
4248
- const { createDocState } = await import("./docStore-IBPCRTTX.js");
4249
- const pageKey = await createDocState(
4250
- { slateData, title },
4251
- { dispatch, getState }
4252
- );
4253
- const newReference = {
4254
- id: fileId,
4255
- name: title,
4256
- pageKey,
4257
- dialogKey,
4258
- type,
4259
- groupId
4260
- };
4261
- const newRawData = jsonData ? { pageKey, jsonData } : null;
4262
- addPageReferenceToRuntime({
4263
- reference: newReference,
4264
- rawData: newRawData,
4265
- dialogKey
4266
- });
4267
- return { reference: newReference, rawData: newRawData, dialogKey };
4268
- } catch (error) {
4269
- console.error("\u521B\u5EFA\u9875\u9762\u6216\u5F15\u7528\u5931\u8D25:", error);
4270
- return rejectWithValue(error.message);
4271
- }
4272
- }
4273
- );
4274
- var deleteDialog = createAsyncThunk(
4275
- "dialog/deleteDialog",
4276
- async (payload, thunkApi) => {
4277
- const result = await deleteDialogThunk(payload, thunkApi);
4278
- deleteDialogRuntime(result.dialogKey);
4279
- if (result.isCurrentDialog) {
4280
- setActiveDialogKey(null);
4281
- }
4282
- return result;
4283
- }
4284
- );
4285
- var initDialog = createAsyncThunk(
4286
- "dialog/initDialog",
4287
- async (id, { dispatch, signal, getState }) => {
4288
- setActiveDialogKey(id);
4289
- resetDialogRuntimeSessionState(id);
4290
- try {
4291
- const { currentServer: preferredServerOrigin } = getRuntimeServerContext(
4292
- getState()
4293
- );
4294
- return await dispatch(
4295
- read({
4296
- dbKey: id,
4297
- signal,
4298
- preferredServerOrigin
4299
- })
4300
- ).unwrap();
4301
- } catch (error) {
4302
- const err = error;
4303
- const isAborted = isAbortError(err) || err?.message === "Aborted";
4304
- const isCurrentDialog = getActiveDialogKey() === id;
4305
- if (!isAborted && isCurrentDialog) {
4306
- setDialogConfigError(err?.message || "Failed to load dialog");
4307
- console.info("Failed to load dialog config:", err?.message);
4308
- }
4309
- throw error;
4310
- }
4311
- }
4312
- );
4313
- var handleSendMessage = createAsyncThunk(
4314
- "dialog/handleSendMessage",
4315
- runHandleSendMessageAction
4316
- );
4317
- var abortAllMessages = createAsyncThunk(
4318
- "dialog/abortAllMessages",
4319
- async (args, { dispatch }) => {
4320
- abortActiveControllers(args);
4321
- dispatch(clearAllStreaming(args));
4322
- clearActiveControllers(args);
4323
- }
4324
- );
4325
- var updateTokens = createAsyncThunk(
4326
- "dialog/updateTokens",
4327
- async (args, thunkApi) => {
4328
- const payload = await updateTokensAction(args, thunkApi);
4329
- const dialogKey = args?.dialogKey;
4330
- if (dialogKey && payload) {
4331
- applyUpdateTokensFulfilled({
4332
- dialogKey,
4333
- input_tokens: payload.input_tokens,
4334
- output_tokens: payload.output_tokens,
4335
- cost: payload.cost
4336
- });
4337
- }
4338
- return payload;
4339
- }
4340
- );
4341
- var createDialog = createAsyncThunk(
4342
- "dialog/createDialog",
4343
- runCreateDialogAction
4344
- );
4345
- var createAgentAutomation = createAsyncThunk(
4346
- "dialog/createAgentAutomation",
4347
- runCreateAgentAutomationAction
4348
- );
4349
- var updateDialogTitle = createAsyncThunk(
4350
- "dialog/updateDialogTitle",
4351
- runUpdateDialogTitleAction
4352
- );
4353
- var addDialogAgent = createAsyncThunk(
4354
- "dialog/addDialogAgent",
4355
- runAddDialogAgentAction
4356
- );
4357
- var removeDialogAgent = createAsyncThunk(
4358
- "dialog/removeDialogAgent",
4359
- runRemoveDialogAgentAction
4360
- );
4361
- var setPrimaryDialogAgent = createAsyncThunk(
4362
- "dialog/setPrimaryDialogAgent",
4363
- runSetPrimaryDialogAgentAction
4364
- );
4365
- var switchDialogAgent = createAsyncThunk(
4366
- "dialog/switchDialogAgent",
4367
- runSwitchDialogAgentAction
4368
- );
4369
- var setDialogExtraReferences = createAsyncThunk(
4370
- "dialog/setDialogExtraReferences",
4371
- runSetDialogExtraReferencesAction
4372
- );
4373
- function selectCurrentDialogConfig(state) {
4374
- const key = getActiveDialogKey();
4375
- return key ? selectById(state, key) : null;
4376
- }
4377
- var selectCurrentDialogAgentIds = createSelector(
4378
- (state) => selectCurrentDialogConfig(state),
4379
- (dialogConfig) => getDialogAgentIds(dialogConfig)
4380
- );
4381
- var selectCurrentPrimaryAgentId = createSelector(
4382
- (state) => selectCurrentDialogConfig(state),
4383
- (dialogConfig) => getPrimaryDialogAgentId(dialogConfig)
4384
- );
4385
- var selectDialogConfigByKey = createSelector(
4386
- (state) => state,
4387
- (_, dialogKey) => dialogKey,
4388
- (state, dialogKey) => dialogKey ? selectById(state, dialogKey) : null
4389
- );
4390
- var selectCurrentDialogTokens = createSelector(
4391
- (state) => state,
4392
- selectCurrentDialogConfig,
4393
- (_state, dialogKey) => dialogKey,
4394
- (state, currentDialog, dialogKey) => {
4395
- if (dialogKey) {
4396
- const dialogConfig = selectById(state, dialogKey);
4397
- return mergeDialogTokenStats(
4398
- dialogConfig,
4399
- getDialogRuntimeTokens(dialogKey)
4400
- );
4401
- }
4402
- return mergeDialogTokenStats(currentDialog, getDialogRuntimeTokens());
4403
- }
4404
- );
4405
- var selectTotalDialogTokens = selectCurrentDialogTokens;
4406
-
4407
- export {
4408
- isAssistantToolStub,
4409
- fetchAndCacheMessages,
4410
- extractReferenceKeysFromMessage,
4411
- normalizeAppRouteId,
4412
- uiAskChoiceFunctionSchema,
4413
- uiAskChoiceFunc,
4414
- parseUiAskChoiceContent,
4415
- PERSONALIZATION_DIALOG_CATEGORY,
4416
- buildPersonalizationDialogPolicyContext,
4417
- resolveBuiltinPlatformAgentConfig,
4418
- resolveBuiltinPlatformAgentRecord,
4419
- applyBuiltinAgentRuntimeOverride,
4420
- resolveDialogRuntimeAgentKey,
4421
- resolveHandleSendMessageContext,
4422
- estimateMissingUsage,
4423
- selectCurrentDialogId,
4424
- selectAllMsgs,
4425
- selectMsgById,
4426
- addUserMessage,
4427
- messageStreaming,
4428
- removeTransientMessage,
4429
- finalizeTransientMessageOnError,
4430
- prepareAndPersistMessage,
4431
- prepareAndPersistUserMessage,
4432
- messageStreamEnd,
4433
- addToolMessage,
4434
- updateToolMessage,
4435
- toast,
4436
- API_REPORTED_COST_MULTIPLIER,
4437
- normalizeUsage,
4438
- prepareTokenUsageData,
4439
- applyTokenUsageToDayStats,
4440
- runKeyed,
4441
- updateTokensAction,
4442
- clearDialogState,
4443
- createPageAndAddReference,
4444
- deleteDialog,
4445
- initDialog,
4446
- handleSendMessage,
4447
- abortAllMessages,
4448
- updateTokens,
4449
- createDialog,
4450
- createAgentAutomation,
4451
- updateDialogTitle,
4452
- addDialogAgent,
4453
- removeDialogAgent,
4454
- setPrimaryDialogAgent,
4455
- switchDialogAgent,
4456
- setDialogExtraReferences,
4457
- selectCurrentDialogConfig,
4458
- selectCurrentDialogAgentIds,
4459
- selectCurrentPrimaryAgentId,
4460
- selectDialogConfigByKey,
4461
- selectCurrentDialogTokens,
4462
- selectTotalDialogTokens
4463
- };