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.
- package/{_executeModel-C5K4UL5I.js → _executeModel-XCNYHC6S.js} +13 -13
- package/{agentDeleteCommand-7RESZDRC.js → agentDeleteCommand-Z3DTLQEG.js} +5 -5
- package/{agentEmailCommands-KES5FG2E.js → agentEmailCommands-DFK2MIXR.js} +14 -14
- package/{agentListCommands-VFBLREFU.js → agentListCommands-FSX7RY7U.js} +5 -5
- package/{agentMachineCommands-UJ77TKWZ.js → agentMachineCommands-FYPV45TJ.js} +6 -6
- package/{agentRecordCommands-MZBPYUGL.js → agentRecordCommands-SXOCVBX7.js} +14 -14
- package/{agentRunCommand-R3RWG53B.js → agentRunCommand-XISX4ICI.js} +14 -14
- package/{agentRuntimeLocal-BD7R3OJL.js → agentRuntimeLocal-2ENB2B2Z.js} +5 -5
- package/{agentSlice-UP66DIC2.js → agentSlice-QLZWET7H.js} +1 -1
- package/{appDeleteCommands-X3UF4ZHF.js → appDeleteCommands-XKAUWKUI.js} +5 -5
- package/{appDeployCommands-MFHLJIYZ.js → appDeployCommands-SNXZY5IX.js} +5 -5
- package/{appDeployStatusCommands-BGXSUHY6.js → appDeployStatusCommands-NXUJ6LXS.js} +5 -5
- package/{appGetCommands-KEA6FZTF.js → appGetCommands-DNRYKGOK.js} +5 -5
- package/{appListCommands-CZGMZW3L.js → appListCommands-URESGUKU.js} +5 -5
- package/{chatQueueReduxAdapter-VVXE2NXW.js → chatQueueReduxAdapter-FNXZNIAT.js} +4 -4
- package/{chunk-HQ3ZLBSI.js → chunk-2XENHR3P.js} +96 -0
- package/{chunk-TDTSQVDX.js → chunk-3E67YXGD.js} +85 -88
- package/{chunk-RCNQCXPM.js → chunk-5JTJG4OG.js} +115 -121
- package/{chunk-MN2XJEWL.js → chunk-7NG5APVZ.js} +16 -133
- package/{chunk-UZXOOSHF.js → chunk-AUA5DTWI.js} +15 -14
- package/{chunk-HPRMNGAM.js → chunk-IX6H4NKR.js} +1 -1
- package/{chunk-UBWLW3KY.js → chunk-IY2BLZKO.js} +3 -3
- package/{chunk-5DUAG5G7.js → chunk-K4326DRU.js} +202 -11729
- package/{chunk-AVJQ4TDL.js → chunk-K5YS7FAN.js} +1 -1
- package/{chunk-TTTW4DIT.js → chunk-LNOW66U4.js} +6 -6
- package/{chunk-NFTTUZ3L.js → chunk-LTLZPAO7.js} +1 -1
- package/{chunk-QPXRNDI3.js → chunk-MIN5X7GI.js} +2 -2
- package/{chunk-OHJWIXXW.js → chunk-RLZ6HZSX.js} +3 -3
- package/{chunk-BG7ZGBKH.js → chunk-SM4ED2LZ.js} +4 -4
- package/{chunk-FPT2E44F.js → chunk-VHADFQCI.js} +2 -2
- package/{chunk-UNAVSDC5.js → chunk-XHNOCBUU.js} +4 -2
- package/chunk-XNO3T6RB.js +18504 -0
- package/chunk-Z6S2JBE4.js +2471 -0
- package/{chunk-M3HN7RBV.js → chunk-ZCVO2HLZ.js} +1 -1
- package/{contentThunks-BHML6O7K.js → contentThunks-6K4RZXKH.js} +5 -5
- package/{createAgentAutomationAction-K5YJO4IA.js → createAgentAutomationAction-6XYIZ3GS.js} +5 -5
- package/{createDialogAction-SFMZLPS4.js → createDialogAction-TJWDXAKL.js} +6 -6
- package/{createPageAction-UD7BSFQS.js → createPageAction-EZ2LPB6K.js} +5 -5
- package/{dialogCommands-2ABSL4ND.js → dialogCommands-ULXMRIAM.js} +5 -5
- package/{dialogSlice-DEC5GV6X.js → dialogSlice-5DRM6AQQ.js} +4 -4
- package/{docCreateCommands-2QZCW4HZ.js → docCreateCommands-PPHO6KUM.js} +5 -5
- package/{docDeleteCommands-WKZKQAKM.js → docDeleteCommands-U2GVGQPR.js} +5 -5
- package/{docReadCommands-WMKJCR4Q.js → docReadCommands-CYY3DJXY.js} +5 -5
- package/{docStore-IBPCRTTX.js → docStore-OJXM46BB.js} +1 -1
- package/{docUpdateCommands-KPLM63NK.js → docUpdateCommands-B5UVFLJU.js} +5 -5
- package/{handleSendMessageAction-C7CZNGMB.js → handleSendMessageAction-EWY3J2AV.js} +4 -4
- package/index.js +41 -41
- package/{machineCommands-6BG3AHT5.js → machineCommands-B76BYAJF.js} +14 -14
- package/{machineWsRunDispatch-G2KJ6NQF.js → machineWsRunDispatch-LN6274EL.js} +14 -14
- package/package.json +1 -1
- package/{readlineWorkspace-5LZ3EDIQ.js → readlineWorkspace-UFHEJIDS.js} +77 -18
- package/{runAgentClientLoop-CICP3O2T.js → runAgentClientLoop-MAER6Y5K.js} +11 -11
- package/{spaceCommands-NQOIERT6.js → spaceCommands-2YT7C56D.js} +5 -5
- package/{streamAgentChatTurn-QUD4FY5I.js → streamAgentChatTurn-AKUDQL5W.js} +14 -14
- package/{tools-MAP6O2YZ.js → tools-NM36O7ZG.js} +8 -8
- package/{tuiSummaryLlmCaller-VL5RDGLT.js → tuiSummaryLlmCaller-ZGATEM35.js} +2 -2
- package/{updateDialogTitleAction-L6CCRVUK.js → updateDialogTitleAction-RHH353JB.js} +5 -5
- package/chunk-CLZYOOI3.js +0 -4463
- 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
|
-
};
|