nolo-cli 0.7.0 → 0.8.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/_executeModel-GPU2276G.js +198 -0
  2. package/action-PAXRPJJF.js +27 -0
  3. package/addContentAction-CZVWF3QZ.js +25 -0
  4. package/addDialogAgentAction-CCIDTPHC.js +67 -0
  5. package/agentDeleteCommand-4ZZFM6AT.js +323 -0
  6. package/agentEmailCommands-C4FIVQYV.js +621 -0
  7. package/agentListCommands-VQAKVNEX.js +219 -0
  8. package/agentMachineCommands-ONFDXZUQ.js +421 -0
  9. package/agentPullCommand-O2MTUAFR.js +122 -0
  10. package/agentRecordCommands-QANUGHLK.js +89 -0
  11. package/agentRunCommand-A3OSRB5Q.js +102 -0
  12. package/agentRunControl-K4VKNEHF.js +57 -0
  13. package/agentRuntimeLocal-62ZB2ODP.js +99 -0
  14. package/agentSlice-GCGLVR2N.js +41 -0
  15. package/authCommand-WXMD3IPR.js +574 -0
  16. package/authCommands-X74AFDTC.js +26 -0
  17. package/chunk-2EISRLRC.js +238 -0
  18. package/chunk-2FTTDCD4.js +675 -0
  19. package/chunk-2MALU52L.js +51 -0
  20. package/chunk-2UZXR7WO.js +3631 -0
  21. package/chunk-3ASDTTEI.js +1774 -0
  22. package/chunk-3EUW3WEO.js +8 -0
  23. package/chunk-3LY4F7SV.js +9293 -0
  24. package/chunk-4CQLVGRV.js +50 -0
  25. package/chunk-4IJYA27C.js +342 -0
  26. package/chunk-4SN6J65J.js +38 -0
  27. package/chunk-4VNS5WPM.js +42 -0
  28. package/chunk-53DNV5AT.js +421 -0
  29. package/chunk-572EKYLF.js +792 -0
  30. package/chunk-5MIDPSSK.js +206 -0
  31. package/chunk-5MMAK75Q.js +15 -0
  32. package/chunk-63W5N6P3.js +150 -0
  33. package/chunk-6B7G54GE.js +1078 -0
  34. package/chunk-6HYVJV7B.js +102 -0
  35. package/chunk-6WD3OOJS.js +20 -0
  36. package/chunk-7OC5VCLW.js +929 -0
  37. package/chunk-7YLKNMOM.js +562 -0
  38. package/chunk-ATNTHIZI.js +13 -0
  39. package/chunk-AUGHVUFE.js +69 -0
  40. package/chunk-AVMKZHBC.js +85 -0
  41. package/chunk-AZPCASRE.js +36 -0
  42. package/chunk-BR2WP3DF.js +548 -0
  43. package/chunk-BSTNFPHD.js +231 -0
  44. package/chunk-CF2WZF4N.js +134 -0
  45. package/chunk-CF7PE763.js +10 -0
  46. package/chunk-CJH2VTEU.js +360 -0
  47. package/chunk-CKOJQDKR.js +198 -0
  48. package/chunk-CM54RSSA.js +206 -0
  49. package/chunk-CQAHS7YO.js +4300 -0
  50. package/chunk-CWMSB67P.js +34 -0
  51. package/chunk-DFFIZ25G.js +30 -0
  52. package/chunk-DWLEOOGR.js +8 -0
  53. package/chunk-DZ3XJVET.js +231 -0
  54. package/chunk-EHLHSX7R.js +1433 -0
  55. package/chunk-ELRRLDWI.js +478 -0
  56. package/chunk-EYEEHCU4.js +3066 -0
  57. package/chunk-F6QQI5YI.js +19 -0
  58. package/chunk-G3SUCT4W.js +8 -0
  59. package/chunk-G5H7RNFL.js +807 -0
  60. package/chunk-GAKEBQD6.js +30 -0
  61. package/chunk-GBRG75BQ.js +86 -0
  62. package/chunk-GCMRDRCQ.js +190 -0
  63. package/chunk-GGUO4FKF.js +27158 -0
  64. package/chunk-GGXABIPP.js +628 -0
  65. package/chunk-H2RMRZJE.js +113 -0
  66. package/chunk-H33743XH.js +25 -0
  67. package/chunk-HEIIIZBX.js +104 -0
  68. package/chunk-HNMXYYJR.js +12 -0
  69. package/chunk-I3D64LRJ.js +1447 -0
  70. package/chunk-IAXBCTTE.js +175 -0
  71. package/chunk-IDZTNRP2.js +85 -0
  72. package/chunk-ISNCLGUZ.js +146 -0
  73. package/chunk-IYQV26RA.js +138 -0
  74. package/chunk-J4576WMJ.js +91 -0
  75. package/chunk-J5KV47ZW.js +222 -0
  76. package/chunk-JBTJAPUF.js +35 -0
  77. package/chunk-JZPBVBIY.js +94 -0
  78. package/chunk-KB7YFGL6.js +34 -0
  79. package/chunk-KKY4B2Q2.js +21 -0
  80. package/chunk-KQHGZWSV.js +63 -0
  81. package/chunk-KUG52IAP.js +8 -0
  82. package/chunk-KX6YBIHG.js +8 -0
  83. package/chunk-LAWBMYBC.js +171 -0
  84. package/chunk-LCBAMY2M.js +60 -0
  85. package/chunk-LM25IZBJ.js +902 -0
  86. package/chunk-LM6IYQ3F.js +16 -0
  87. package/chunk-M76ECQRD.js +13658 -0
  88. package/chunk-MRC4Q34M.js +188 -0
  89. package/chunk-NXZGF7F7.js +2878 -0
  90. package/chunk-OF5H3QWS.js +300 -0
  91. package/chunk-OLZBQWZU.js +6 -0
  92. package/chunk-OWOHNGCN.js +50 -0
  93. package/chunk-PN7AFLOK.js +3401 -0
  94. package/chunk-QR5IPGT3.js +24674 -0
  95. package/chunk-QSJ3HFEF.js +8 -0
  96. package/chunk-QYXLLLGL.js +4519 -0
  97. package/chunk-R2HXWML7.js +1949 -0
  98. package/chunk-ROWQEJRP.js +139 -0
  99. package/chunk-S7Z2HMCN.js +25 -0
  100. package/chunk-SYOF5TAS.js +962 -0
  101. package/chunk-TDIQFT2F.js +301 -0
  102. package/chunk-TILFE6LV.js +381 -0
  103. package/chunk-TZNCFAUP.js +2157 -0
  104. package/chunk-U4TRT5V4.js +246 -0
  105. package/chunk-U6VC4MU4.js +8 -0
  106. package/chunk-UAD2WT54.js +64 -0
  107. package/chunk-USZMK5UT.js +105 -0
  108. package/chunk-VEJLAVTC.js +2052 -0
  109. package/chunk-VF4K2QE6.js +21 -0
  110. package/chunk-VHBWHNVT.js +59 -0
  111. package/chunk-VIDPVFP3.js +20 -0
  112. package/chunk-VP4WJWKW.js +8882 -0
  113. package/chunk-VQ2AJRGD.js +148 -0
  114. package/chunk-W4NVOSFF.js +37 -0
  115. package/chunk-WWC7I6TA.js +8 -0
  116. package/chunk-X7W4TNB4.js +1550 -0
  117. package/chunk-XBIUN5CR.js +191 -0
  118. package/chunk-XDVAYP26.js +537 -0
  119. package/chunk-XKIMRZO2.js +221 -0
  120. package/chunk-Y5GCAMGP.js +9 -0
  121. package/chunk-YOUZDXU7.js +9013 -0
  122. package/chunk-Z4NR32XR.js +50 -0
  123. package/chunk-ZNFJWEN4.js +56 -0
  124. package/cliExecutor-DNE7TCC4.js +36 -0
  125. package/clipboardy-BVE3LVEH.js +12001 -0
  126. package/createAgentAutomationAction-537X433B.js +864 -0
  127. package/createDialogAction-YUD4RKBS.js +52 -0
  128. package/createPageAction-KJMFHL4C.js +169 -0
  129. package/db-HCJ5PRB5.js +271 -0
  130. package/dbSlice-C4UJLRZP.js +59 -0
  131. package/deleteFile-4SKGPHOZ.js +41 -0
  132. package/dialogCommands-H74KJKHC.js +59 -0
  133. package/dialogSlice-ETSD4YWS.js +146 -0
  134. package/docCreateCommands-ADUSU34K.js +215 -0
  135. package/docDeleteCommands-ZXV3S5OS.js +176 -0
  136. package/docReadCommands-YYYI6LT7.js +129 -0
  137. package/docStore-ZBF5DDKR.js +96 -0
  138. package/docUpdateCommands-7MGJ3BYA.js +313 -0
  139. package/fetchMessages-JOCYIFKL.js +16 -0
  140. package/getPricing-PWPJ6MNV.js +30 -0
  141. package/handleSendMessageAction-MGKI62Y6.js +183 -0
  142. package/index.js +184 -112288
  143. package/lib-FYYBQIXS.js +19839 -0
  144. package/localDialogRead-D3BELSTF.js +26 -0
  145. package/localFirstLog-DHNOY2NA.js +19 -0
  146. package/localRuntimeAuthority-TEGCOWX4.js +471 -0
  147. package/localRuntimeDb-LGDF6FQP.js +12 -0
  148. package/machineCommands-RMTMN7VQ.js +774 -0
  149. package/machineInfo-M6KB6HZN.js +10 -0
  150. package/machineWsRunDispatch-UIP355FN.js +105 -0
  151. package/memoryCommands-O4MIPIWQ.js +476 -0
  152. package/models-XLEOET3E.js +9 -0
  153. package/offlineMarxistsAgentCommand-BCPJITJL.js +242 -0
  154. package/package.json +3 -25
  155. package/read-RIJCIVKX.js +17 -0
  156. package/readDocTool-GZD2N3LO.js +16 -0
  157. package/readlineWorkspace-CRNQRZ6D.js +5374 -0
  158. package/removeDialogAgentAction-CXLST3N6.js +72 -0
  159. package/runAgentClientLoop-2S334SGA.js +288 -0
  160. package/runtimeDoctorCommands-LRHLPDRC.js +289 -0
  161. package/setDialogExtraReferencesAction-LP6VYGU7.js +59 -0
  162. package/setPrimaryDialogAgentAction-D3GGH23T.js +79 -0
  163. package/settingSlice-J4I3Z5H7.js +198 -0
  164. package/skillSummaryMarker-42HKSXYY.js +9 -0
  165. package/slateToRenderMarkdown-Y5IYN73U.js +7 -0
  166. package/slateUtils-2M7MUTWX.js +19 -0
  167. package/spaceCommands-NDEWMFZJ.js +450 -0
  168. package/spaceSlice-RLB6RTHO.js +145 -0
  169. package/streamAgentChatTurn-Y2TTYPBD.js +4503 -0
  170. package/tableCommands-GOFP7QKA.js +1286 -0
  171. package/toolApiClient-QI3YBNWB.js +26 -0
  172. package/tools-YZYLY2ZQ.js +83 -0
  173. package/understanding-HCSFPE7R.js +318 -0
  174. package/updateCommands-VOSPKXFF.js +31 -0
  175. package/updateDialogTitleAction-LQV6QLBW.js +185 -0
@@ -0,0 +1,1949 @@
1
+ import {
2
+ prepareTools
3
+ } from "./chunk-LAWBMYBC.js";
4
+ import {
5
+ getPublicImageAgentMode
6
+ } from "./chunk-VIDPVFP3.js";
7
+ import {
8
+ performFetchRequest
9
+ } from "./chunk-TZNCFAUP.js";
10
+ import {
11
+ createSSEParser,
12
+ createToolRunId,
13
+ findToolExecutor,
14
+ getToolResultErrorData,
15
+ toolDefinitionsByName,
16
+ toolRunFailed,
17
+ toolRunSetPending,
18
+ toolRunStarted,
19
+ toolRunSucceeded
20
+ } from "./chunk-GGUO4FKF.js";
21
+ import {
22
+ addToolMessage,
23
+ getModelInfo,
24
+ messageStreamEnd,
25
+ messageStreaming,
26
+ selectCurrentSpaceId,
27
+ updateToolMessage
28
+ } from "./chunk-QR5IPGT3.js";
29
+ import {
30
+ streamAgentChatTurn
31
+ } from "./chunk-7YLKNMOM.js";
32
+ import {
33
+ EMPTY_ASSISTANT_REPAIR_PROMPT,
34
+ createThinkParserState,
35
+ flushThinkParser,
36
+ processThinkChunk
37
+ } from "./chunk-SYOF5TAS.js";
38
+ import {
39
+ getApiEndpoint
40
+ } from "./chunk-572EKYLF.js";
41
+ import {
42
+ isNoloHostedProvider
43
+ } from "./chunk-BR2WP3DF.js";
44
+ import {
45
+ extractCustomId
46
+ } from "./chunk-DFFIZ25G.js";
47
+ import {
48
+ addActiveController,
49
+ removeActiveController,
50
+ tokenUsageLiveUpdate
51
+ } from "./chunk-3ASDTTEI.js";
52
+ import {
53
+ toErrorMessage
54
+ } from "./chunk-HNMXYYJR.js";
55
+ import {
56
+ selectCurrentServer
57
+ } from "./chunk-VEJLAVTC.js";
58
+ import {
59
+ write
60
+ } from "./chunk-G5H7RNFL.js";
61
+ import {
62
+ createDialogMessageKeyAndId,
63
+ dialogMessageKey,
64
+ toTrimmedString
65
+ } from "./chunk-PN7AFLOK.js";
66
+ import {
67
+ createAsyncThunk,
68
+ selectIdentityToken
69
+ } from "./chunk-EYEEHCU4.js";
70
+ import {
71
+ isAbortError
72
+ } from "./chunk-QYXLLLGL.js";
73
+ import {
74
+ asTrimmedString
75
+ } from "./chunk-3EUW3WEO.js";
76
+ import {
77
+ asOptionalTrimmedString
78
+ } from "./chunk-G3SUCT4W.js";
79
+ import {
80
+ isRecord
81
+ } from "./chunk-KUG52IAP.js";
82
+
83
+ // packages/integrations/openai/filterAndCleanMessages.ts
84
+ var TOOL_CONTEXT_MAX_CHARS = 4e3;
85
+ var truncateText = (text, maxChars = TOOL_CONTEXT_MAX_CHARS) => {
86
+ if (text.length <= maxChars) return text;
87
+ return `${text.slice(0, maxChars)}
88
+ \u2026[\u622A\u65AD\uFF0C\u539F\u59CB\u957F\u5EA6 ${text.length} \u5B57\u7B26]`;
89
+ };
90
+ var isValidMessagePart = (part) => {
91
+ if (!part || typeof part !== "object") return false;
92
+ if (part.type === "text") return typeof part.text === "string";
93
+ if (part.type === "image_url") {
94
+ const img = part.image_url;
95
+ return img && typeof img === "object" && typeof img.url === "string" && img.url.length > 0;
96
+ }
97
+ return false;
98
+ };
99
+ var extractContent = (msg) => {
100
+ if (msg.role === "tool") {
101
+ const llmContext = asTrimmedString(msg.toolPayload?.llmContext);
102
+ if (llmContext) return truncateText(llmContext);
103
+ const summary = asTrimmedString(msg.toolPayload?.summary);
104
+ if (summary) return truncateText(summary);
105
+ if (typeof msg.content === "string") return truncateText(msg.content);
106
+ if (msg.content != null) return truncateText(JSON.stringify(msg.content));
107
+ return null;
108
+ }
109
+ if (typeof msg.content === "string") return msg.content;
110
+ if (Array.isArray(msg.content)) {
111
+ const parts = msg.content.filter(isValidMessagePart);
112
+ return parts.length > 0 ? parts : null;
113
+ }
114
+ if (msg.content && typeof msg.content === "object" && isValidMessagePart(msg.content)) {
115
+ return [msg.content];
116
+ }
117
+ return null;
118
+ };
119
+ var extractToolCalls = (msg) => {
120
+ const calls = msg.tool_calls ?? msg.toolCalls;
121
+ return Array.isArray(calls) && calls.length > 0 ? calls : void 0;
122
+ };
123
+ var extractToolCallId = (msg) => msg.tool_call_id ?? msg.toolCallId ?? msg.toolPayload?.rawToolCall?.id;
124
+ var extractName = (msg) => {
125
+ if (typeof msg.name === "string") return msg.name;
126
+ if (typeof msg.toolName === "string") return msg.toolName;
127
+ if (typeof msg.toolPayload?.toolName === "string") return msg.toolPayload.toolName;
128
+ return void 0;
129
+ };
130
+ var getToolName = (msg) => msg?.toolName ?? msg?.toolPayload?.toolName;
131
+ var isHandoffToolMessage = (msg) => {
132
+ const toolName = getToolName(msg);
133
+ return toolName === "runStreamingAgent";
134
+ };
135
+ var getToolMessageCallId = (msg) => msg?.tool_call_id ?? msg?.toolCallId ?? msg?.toolPayload?.rawToolCall?.id;
136
+ var collectHandoffToolCallIds = (msgs) => {
137
+ const ids = /* @__PURE__ */ new Set();
138
+ for (const msg of msgs) {
139
+ if (msg?.role !== "tool" || !isHandoffToolMessage(msg)) continue;
140
+ const id = getToolMessageCallId(msg);
141
+ if (id) ids.add(id);
142
+ }
143
+ return ids;
144
+ };
145
+ var stripHandoffToolMessage = (msg) => msg?.role === "tool" && isHandoffToolMessage(msg) ? null : msg;
146
+ var removeToolCallsById = (calls, ids) => calls?.filter((call) => !ids.has(call.id));
147
+ var stripHandoffToolCallsFromAssistant = (msg, handoffIds) => {
148
+ if (msg?.role !== "assistant") return msg;
149
+ const calls = msg.tool_calls ?? msg.toolCalls;
150
+ if (!calls?.some((call) => handoffIds.has(call.id))) return msg;
151
+ const kept = removeToolCallsById(calls, handoffIds);
152
+ return {
153
+ ...msg,
154
+ tool_calls: kept?.length ? kept : void 0,
155
+ toolCalls: kept?.length ? kept : void 0
156
+ };
157
+ };
158
+ var stripHandoffToolMessages = (msgs) => {
159
+ const handoffIds = collectHandoffToolCallIds(msgs);
160
+ if (handoffIds.size === 0) return msgs;
161
+ const out = [];
162
+ for (const raw of msgs) {
163
+ const stripped = stripHandoffToolMessage(raw);
164
+ if (!stripped) continue;
165
+ out.push(stripHandoffToolCallsFromAssistant(stripped, handoffIds));
166
+ }
167
+ return out;
168
+ };
169
+ var toOpenAIMessage = (rawMsg) => {
170
+ const msg = rawMsg;
171
+ const { role, id } = msg;
172
+ if (!role || !["system", "user", "assistant", "tool"].includes(role)) return null;
173
+ const toolCalls = extractToolCalls(msg);
174
+ let content = extractContent(msg);
175
+ if (content === null) {
176
+ if (role === "assistant" && toolCalls) content = "";
177
+ else return null;
178
+ }
179
+ const cleaned = { role, content };
180
+ if (id) cleaned.id = id;
181
+ const name = extractName(msg);
182
+ if (name) cleaned.name = name;
183
+ if (role === "assistant" && toolCalls) {
184
+ cleaned.tool_calls = toolCalls;
185
+ }
186
+ if (role === "tool") {
187
+ const toolCallId = extractToolCallId(msg);
188
+ if (toolCallId) cleaned.tool_call_id = toolCallId;
189
+ if (!cleaned.tool_call_id) {
190
+ console.warn("[filterAndCleanMessages] \u4E22\u5F03\u65E0\u6548 tool \u6D88\u606F\uFF1A\u7F3A\u5C11 tool_call_id", msg);
191
+ return null;
192
+ }
193
+ }
194
+ return cleaned;
195
+ };
196
+ var removeOrphanedToolPairs = (msgs) => {
197
+ const dropIndexes = /* @__PURE__ */ new Set();
198
+ const toolToAssistant = /* @__PURE__ */ new Map();
199
+ for (let i = 0; i < msgs.length; i++) {
200
+ if (msgs[i].role !== "tool") continue;
201
+ for (let j = i - 1; j >= 0; j--) {
202
+ if (msgs[j].role === "assistant") {
203
+ toolToAssistant.set(i, j);
204
+ break;
205
+ }
206
+ }
207
+ }
208
+ for (let i = 0; i < msgs.length; i++) {
209
+ if (msgs[i].role === "tool" && !toolToAssistant.has(i)) {
210
+ dropIndexes.add(i);
211
+ console.warn("[filterAndCleanMessages] \u4E22\u5F03\u5B64\u7ACB tool \u6D88\u606F\uFF1A\u7F3A\u5C11\u524D\u7F6E assistant", msgs[i].tool_call_id);
212
+ }
213
+ }
214
+ for (const [toolIdx, assistantIdx] of toolToAssistant) {
215
+ const toolMsg = msgs[toolIdx];
216
+ if (!toolMsg.tool_call_id) continue;
217
+ const knownIds = new Set((msgs[assistantIdx].tool_calls ?? []).map((tc) => tc.id));
218
+ if (!knownIds.has(toolMsg.tool_call_id)) {
219
+ dropIndexes.add(toolIdx);
220
+ console.warn("[filterAndCleanMessages] \u4E22\u5F03\u5B64\u7ACB tool \u6D88\u606F:", toolMsg.tool_call_id);
221
+ }
222
+ }
223
+ for (const assistantIdx of new Set(toolToAssistant.values())) {
224
+ if (dropIndexes.has(assistantIdx)) continue;
225
+ const stub = msgs[assistantIdx];
226
+ const content = typeof stub.content === "string" ? stub.content.trim() : stub.content;
227
+ const isEmpty = content === "" || Array.isArray(content) && content.length === 0;
228
+ if (!isEmpty) continue;
229
+ const allToolsDropped = (stub.tool_calls ?? []).every((tc) => {
230
+ return msgs.every(
231
+ (m, idx) => m.role !== "tool" || m.tool_call_id !== tc.id || dropIndexes.has(idx)
232
+ );
233
+ });
234
+ if (allToolsDropped) {
235
+ dropIndexes.add(assistantIdx);
236
+ console.warn("[filterAndCleanMessages] \u4E00\u5E76\u4E22\u5F03\u5B64\u7ACB assistant stub\uFF08index:", assistantIdx, ")");
237
+ }
238
+ }
239
+ if (dropIndexes.size === 0) return msgs;
240
+ return msgs.filter((_, idx) => !dropIndexes.has(idx));
241
+ };
242
+ var filterAndCleanMessages = (msgs) => {
243
+ if (!Array.isArray(msgs)) return [];
244
+ const flat = msgs.flat();
245
+ const preprocessed = stripHandoffToolMessages(flat);
246
+ const cleaned = preprocessed.map(toOpenAIMessage).filter((m) => m !== null);
247
+ return removeOrphanedToolPairs(cleaned);
248
+ };
249
+
250
+ // packages/chat/messages/persistToolMessage.ts
251
+ async function persistToolMessage(dispatch, message, options = {}) {
252
+ const id = asOptionalTrimmedString(message?.id);
253
+ const dbKey = asOptionalTrimmedString(message?.dbKey);
254
+ if (!id || !dbKey) {
255
+ const err = new Error(
256
+ `[persistToolMessage] missing id/dbKey (id=${String(id)} dbKey=${String(dbKey)})`
257
+ );
258
+ if (options.soft) {
259
+ console.error(err.message);
260
+ return;
261
+ }
262
+ throw err;
263
+ }
264
+ const { controller: _controller, ...rest } = message;
265
+ const isStreaming = options.isStreaming !== void 0 ? options.isStreaming : Boolean(rest.isStreaming);
266
+ try {
267
+ const writeRequest = dispatch(
268
+ write({
269
+ data: {
270
+ ...rest,
271
+ id,
272
+ dbKey,
273
+ role: "tool",
274
+ isStreaming,
275
+ type: "msg" /* MSG */
276
+ },
277
+ customKey: dbKey
278
+ })
279
+ );
280
+ if (writeRequest && typeof writeRequest.unwrap === "function") {
281
+ await writeRequest.unwrap();
282
+ return;
283
+ }
284
+ await writeRequest;
285
+ } catch (error) {
286
+ console.error("[persistToolMessage] write failed", { id, dbKey, error });
287
+ if (!options.soft) throw error;
288
+ }
289
+ }
290
+ async function persistToolMessages(dispatch, messages, options = {}) {
291
+ for (const message of messages) {
292
+ await persistToolMessage(dispatch, message, options);
293
+ }
294
+ }
295
+
296
+ // packages/ai/chat/updateTotalUsage.ts
297
+ function updateTotalUsage(currentUsage, newUsageChunk) {
298
+ if (!newUsageChunk) {
299
+ return currentUsage;
300
+ }
301
+ if (!currentUsage) {
302
+ return {
303
+ completion_tokens: 0,
304
+ prompt_tokens: 0,
305
+ total_tokens: 0,
306
+ ...newUsageChunk
307
+ };
308
+ }
309
+ const updatedUsage = { ...currentUsage };
310
+ if (newUsageChunk.completion_tokens !== void 0) updatedUsage.completion_tokens = newUsageChunk.completion_tokens;
311
+ if (newUsageChunk.prompt_tokens !== void 0) updatedUsage.prompt_tokens = newUsageChunk.prompt_tokens;
312
+ if (newUsageChunk.total_tokens !== void 0) updatedUsage.total_tokens = newUsageChunk.total_tokens;
313
+ if (newUsageChunk.prompt_tokens_details) {
314
+ updatedUsage.prompt_tokens_details = {
315
+ ...updatedUsage.prompt_tokens_details || {},
316
+ ...newUsageChunk.prompt_tokens_details
317
+ };
318
+ }
319
+ if (newUsageChunk.completion_tokens_details) {
320
+ updatedUsage.completion_tokens_details = {
321
+ ...updatedUsage.completion_tokens_details || {},
322
+ ...newUsageChunk.completion_tokens_details
323
+ };
324
+ }
325
+ if (typeof newUsageChunk.cost === "number") {
326
+ updatedUsage.cost = newUsageChunk.cost;
327
+ }
328
+ if (newUsageChunk.cost_details) {
329
+ updatedUsage.cost_details = {
330
+ ...updatedUsage.cost_details || {},
331
+ ...newUsageChunk.cost_details
332
+ };
333
+ }
334
+ const billingProvider = asOptionalTrimmedString(newUsageChunk.billing_provider);
335
+ if (billingProvider) {
336
+ updatedUsage.billing_provider = billingProvider;
337
+ }
338
+ const billingModel = asOptionalTrimmedString(newUsageChunk.billing_model);
339
+ if (billingModel) {
340
+ updatedUsage.billing_model = billingModel;
341
+ }
342
+ return updatedUsage;
343
+ }
344
+
345
+ // packages/chat/messages/toolThunks.ts
346
+ var TOOL_ARGS_SENTINELS = [
347
+ "<|tool_calls_section_end|>",
348
+ "<|tool_calls_end|>",
349
+ "<|endofjson|>"
350
+ ];
351
+ function cleanToolArguments(argStr) {
352
+ if (!argStr) return argStr;
353
+ let cleaned = argStr;
354
+ for (const s of TOOL_ARGS_SENTINELS) {
355
+ const idx = cleaned.indexOf(s);
356
+ if (idx >= 0) {
357
+ cleaned = cleaned.slice(0, idx);
358
+ }
359
+ }
360
+ return cleaned.trim();
361
+ }
362
+ var defaultSummary = (toolName, status) => {
363
+ if (status === "pending") return `\u23F8\uFE0F ${toolName} \u7B49\u5F85\u786E\u8BA4/\u6388\u6743`;
364
+ if (status === "running") return `\u23F3 ${toolName} \u6267\u884C\u4E2D\u2026`;
365
+ if (status === "failed") return `\u274C ${toolName} \u6267\u884C\u5931\u8D25`;
366
+ return `\u2705 ${toolName} \u6267\u884C\u5B8C\u6210`;
367
+ };
368
+ var processToolData = createAsyncThunk(
369
+ "message/processToolData",
370
+ async (args, thunkApi) => {
371
+ const { toolCall, parentMessageId, toolRunId } = args;
372
+ const { dispatch, rejectWithValue } = thunkApi;
373
+ const func = toolCall.function;
374
+ if (!func || !func.name) {
375
+ throw new Error(
376
+ "Invalid tool call data: missing function or function.name"
377
+ );
378
+ }
379
+ const toolCallId = toolCall.id || `call_${Date.now()}_${Math.random().toString(36).slice(2)}`;
380
+ const rawToolName = func.name;
381
+ let toolArgs = func.arguments;
382
+ const found = findToolExecutor(rawToolName);
383
+ const canonicalName = found.canonicalName;
384
+ const def = toolDefinitionsByName[canonicalName];
385
+ const behavior = def?.behavior;
386
+ const interaction = def?.interaction ?? "auto";
387
+ if (typeof toolArgs === "string") {
388
+ const cleaned = cleanToolArguments(toolArgs);
389
+ try {
390
+ toolArgs = JSON.parse(cleaned);
391
+ } catch (e) {
392
+ console.error(
393
+ "[ToolThunks/processToolData] toolArgs JSON.parse failed:",
394
+ toolArgs
395
+ );
396
+ throw new Error(`Failed to parse tool arguments JSON: ${e}`);
397
+ }
398
+ }
399
+ const activity = isRecord(toolArgs) && isRecord(toolArgs._activity) ? toolArgs._activity : void 0;
400
+ const executionToolArgs = isRecord(toolArgs) && Object.prototype.hasOwnProperty.call(toolArgs, "_activity") ? (({ _activity: _ignored, ...rest }) => rest)(toolArgs) : toolArgs;
401
+ const inputSummary = JSON.stringify(executionToolArgs).slice(0, 400);
402
+ toolRunStarted({
403
+ id: toolRunId,
404
+ messageId: parentMessageId,
405
+ toolName: canonicalName,
406
+ behavior,
407
+ inputSummary,
408
+ interaction,
409
+ input: executionToolArgs
410
+ });
411
+ if (interaction === "confirm" || interaction === "authorize") {
412
+ try {
413
+ toolRunSetPending({ id: toolRunId });
414
+ const previewExecutor = def?.previewExecutor;
415
+ const previewResult = previewExecutor ? await previewExecutor(executionToolArgs, thunkApi, { parentMessageId }) : {
416
+ rawData: {
417
+ previewOnly: true,
418
+ toolName: canonicalName,
419
+ interaction
420
+ }
421
+ };
422
+ const rawData = previewResult?.rawData ?? previewResult;
423
+ const summary = typeof previewResult?.displayData === "string" && previewResult.displayData.trim() || (interaction === "authorize" ? `\u{1F510} ${canonicalName} \u9700\u8981\u6388\u6743\u540E\u6267\u884C` : `\u26A0\uFE0F ${canonicalName} \u9700\u8981\u786E\u8BA4\u540E\u6267\u884C`);
424
+ const toolPayload = {
425
+ toolName: canonicalName,
426
+ status: "pending",
427
+ input: executionToolArgs,
428
+ rawToolCall: toolCall,
429
+ toolRunId,
430
+ summary,
431
+ ...activity ? { activity } : {}
432
+ };
433
+ return {
434
+ toolCallId,
435
+ rawResult: rawData,
436
+ summary,
437
+ toolName: canonicalName,
438
+ toolRunId,
439
+ toolPayload,
440
+ hasPendingInteraction: true
441
+ // ✅ 暂停点
442
+ };
443
+ } catch (e) {
444
+ const errorMessage = toErrorMessage(e);
445
+ const structured = getToolResultErrorData(e);
446
+ const rawErrorResult = structured?.rawData !== void 0 ? structured.rawData : { error: errorMessage };
447
+ const summary = asOptionalTrimmedString(structured?.displayData) || `\u274C ${canonicalName} \u9884\u89C8\u5931\u8D25: ${errorMessage}`;
448
+ toolRunFailed({
449
+ id: toolRunId,
450
+ error: errorMessage,
451
+ outputSummary: summary
452
+ });
453
+ const errorPayload = {
454
+ type: e?.name || "Error",
455
+ message: errorMessage,
456
+ code: structured?.code ?? e?.code,
457
+ retryable: structured?.retryable ?? e?.retryable ?? true
458
+ };
459
+ const toolPayload = {
460
+ toolName: canonicalName,
461
+ status: "failed",
462
+ input: executionToolArgs,
463
+ rawToolCall: toolCall,
464
+ error: errorPayload,
465
+ toolRunId,
466
+ summary,
467
+ ...activity ? { activity } : {}
468
+ };
469
+ return rejectWithValue({
470
+ toolCallId,
471
+ rawResult: rawErrorResult,
472
+ summary,
473
+ toolName: canonicalName,
474
+ toolRunId,
475
+ toolPayload,
476
+ hasPendingInteraction: true
477
+ });
478
+ }
479
+ }
480
+ try {
481
+ const toolResult = await found.executor(executionToolArgs, thunkApi, {
482
+ parentMessageId,
483
+ toolRunId
484
+ });
485
+ const rawData = toolResult?.rawData ?? toolResult;
486
+ const llmContext = asOptionalTrimmedString(toolResult?.llmContext);
487
+ const summary = asOptionalTrimmedString(toolResult?.displayData) || defaultSummary(canonicalName, "succeeded");
488
+ toolRunSucceeded({
489
+ id: toolRunId,
490
+ outputSummary: summary
491
+ });
492
+ const toolPayload = {
493
+ toolName: canonicalName,
494
+ status: "succeeded",
495
+ input: executionToolArgs,
496
+ rawToolCall: toolCall,
497
+ toolRunId,
498
+ summary,
499
+ ...llmContext ? { llmContext } : {},
500
+ ...activity ? { activity } : {}
501
+ };
502
+ const isUiAskChoice = canonicalName === "ui_ask_choice";
503
+ const blocking = typeof executionToolArgs?.blocking === "boolean" ? executionToolArgs.blocking : true;
504
+ const hasPendingInteraction = isUiAskChoice && blocking === true;
505
+ return {
506
+ toolCallId,
507
+ rawResult: rawData,
508
+ summary,
509
+ toolName: canonicalName,
510
+ toolRunId,
511
+ toolPayload,
512
+ hasPendingInteraction
513
+ };
514
+ } catch (e) {
515
+ const errorMessage = toErrorMessage(e);
516
+ const structured = getToolResultErrorData(e);
517
+ const requiresConfirmation = structured?.code === "self_evolution_requires_confirmation" || structured?.code === "agent_update_requires_confirmation";
518
+ if (requiresConfirmation) {
519
+ const confirmedInput = {
520
+ ...executionToolArgs ?? {},
521
+ __confirmedSelfEvolution: true
522
+ };
523
+ const summary2 = typeof structured?.displayData === "string" && structured.displayData.trim() || `\u26A0\uFE0F ${canonicalName} \u9700\u8981\u786E\u8BA4\u540E\u6267\u884C`;
524
+ toolRunStarted({
525
+ id: toolRunId,
526
+ messageId: parentMessageId,
527
+ toolName: canonicalName,
528
+ behavior,
529
+ inputSummary: JSON.stringify(confirmedInput).slice(0, 400),
530
+ interaction: "confirm",
531
+ input: confirmedInput
532
+ });
533
+ toolRunSetPending({ id: toolRunId });
534
+ const toolPayload2 = {
535
+ toolName: canonicalName,
536
+ status: "pending",
537
+ input: confirmedInput,
538
+ rawToolCall: toolCall,
539
+ toolRunId,
540
+ summary: summary2,
541
+ ...activity ? { activity } : {}
542
+ };
543
+ return {
544
+ toolCallId,
545
+ rawResult: structured?.rawData !== void 0 ? structured.rawData : { error: "self_evolution_requires_confirmation" },
546
+ summary: summary2,
547
+ toolName: canonicalName,
548
+ toolRunId,
549
+ toolPayload: toolPayload2,
550
+ hasPendingInteraction: true
551
+ };
552
+ }
553
+ const rawErrorResult = structured?.rawData !== void 0 ? structured.rawData : { error: errorMessage };
554
+ const summary = asOptionalTrimmedString(structured?.displayData) || `\u274C ${canonicalName} \u6267\u884C\u5931\u8D25: ${errorMessage}`;
555
+ toolRunFailed({
556
+ id: toolRunId,
557
+ error: errorMessage,
558
+ outputSummary: summary
559
+ });
560
+ const errorPayload = {
561
+ type: e?.name || "Error",
562
+ message: errorMessage,
563
+ code: structured?.code ?? e?.code,
564
+ retryable: structured?.retryable ?? e?.retryable ?? true
565
+ };
566
+ const toolPayload = {
567
+ toolName: canonicalName,
568
+ status: "failed",
569
+ input: executionToolArgs,
570
+ rawToolCall: toolCall,
571
+ error: errorPayload,
572
+ toolRunId,
573
+ summary,
574
+ ...activity ? { activity } : {}
575
+ };
576
+ return rejectWithValue({
577
+ toolCallId,
578
+ rawResult: rawErrorResult,
579
+ summary,
580
+ toolName: canonicalName,
581
+ toolRunId,
582
+ toolPayload,
583
+ hasPendingInteraction: false
584
+ });
585
+ }
586
+ }
587
+ );
588
+ var handleToolCalls = createAsyncThunk(
589
+ "message/handleToolCalls",
590
+ async (args, thunkApi) => {
591
+ const {
592
+ accumulatedCalls,
593
+ currentContentBuffer,
594
+ agentConfig,
595
+ messageId,
596
+ dialogId,
597
+ dialogKey
598
+ } = args;
599
+ const { dispatch } = thunkApi;
600
+ const updatedContentBuffer = [...currentContentBuffer];
601
+ let hasHandedOff = false;
602
+ let hasPendingInteraction = false;
603
+ for (let toolIndex = 0; toolIndex < accumulatedCalls.length; toolIndex++) {
604
+ const toolCall = accumulatedCalls[toolIndex];
605
+ if (!toolCall.function?.name) continue;
606
+ const toolCallId = toolCall.id || `call_${Date.now()}_${Math.random().toString(36).slice(2)}`;
607
+ const toolRunId = createToolRunId();
608
+ const canonicalToolName = findToolExecutor(toolCall.function.name).canonicalName;
609
+ const runningToolMessageId = `${messageId}-t${String(toolIndex).padStart(3, "0")}`;
610
+ const runningToolDbKey = dialogMessageKey(dialogId, runningToolMessageId);
611
+ const runningToolMessage = {
612
+ id: runningToolMessageId,
613
+ dbKey: runningToolDbKey,
614
+ role: "tool",
615
+ content: JSON.stringify({ pending: true }),
616
+ toolCallId,
617
+ thinkContent: "",
618
+ cybotKey: agentConfig.dbKey,
619
+ isStreaming: true,
620
+ toolName: canonicalToolName,
621
+ parentMessageId: messageId,
622
+ toolRunId,
623
+ toolPayload: {
624
+ toolName: canonicalToolName,
625
+ status: "running",
626
+ input: {},
627
+ rawToolCall: toolCall,
628
+ toolRunId,
629
+ summary: defaultSummary(canonicalToolName, "running")
630
+ }
631
+ };
632
+ dispatch(addToolMessage(runningToolMessage));
633
+ await persistToolMessage(dispatch, runningToolMessage, {
634
+ isStreaming: true,
635
+ soft: true
636
+ });
637
+ try {
638
+ const result = await dispatch(
639
+ processToolData({
640
+ toolCall: { ...toolCall, id: toolCallId },
641
+ parentMessageId: messageId,
642
+ toolRunId
643
+ })
644
+ ).unwrap();
645
+ const toolName = result.toolName;
646
+ let rawResult = result.rawResult;
647
+ let toolPayload = result.toolPayload;
648
+ if (toolName) {
649
+ const completedToolMessage = {
650
+ ...runningToolMessage,
651
+ content: JSON.stringify(rawResult),
652
+ toolCallId: result.toolCallId,
653
+ isStreaming: false,
654
+ toolName,
655
+ toolRunId: result.toolRunId,
656
+ toolPayload
657
+ };
658
+ dispatch(
659
+ updateToolMessage({
660
+ id: runningToolMessageId,
661
+ changes: {
662
+ content: completedToolMessage.content,
663
+ toolCallId: completedToolMessage.toolCallId,
664
+ isStreaming: false,
665
+ toolName,
666
+ toolRunId: result.toolRunId,
667
+ toolPayload
668
+ }
669
+ })
670
+ );
671
+ await persistToolMessage(dispatch, completedToolMessage, {
672
+ isStreaming: false,
673
+ soft: true
674
+ });
675
+ if (result.hasPendingInteraction) {
676
+ hasPendingInteraction = true;
677
+ }
678
+ if (toolName === "runStreamingAgent") {
679
+ const raw = result.rawResult ?? {};
680
+ const agentKey = raw.agentKey;
681
+ const userInput = raw.userInput;
682
+ const serverBase = asOptionalTrimmedString(raw.serverBase);
683
+ if (agentKey && userInput) {
684
+ hasHandedOff = true;
685
+ void dispatch(
686
+ streamAgentChatTurn({
687
+ agentKey,
688
+ userInput,
689
+ ...dialogKey ? { dialogKey } : {},
690
+ ...serverBase ? { serverBase } : {}
691
+ })
692
+ );
693
+ }
694
+ }
695
+ }
696
+ } catch (rejectedValue) {
697
+ console.error(
698
+ "[ToolThunks/handleToolCalls] processToolData rejected:",
699
+ rejectedValue
700
+ );
701
+ if (rejectedValue.toolName) {
702
+ const errorResult = {
703
+ error: true,
704
+ message: rejectedValue.toolPayload?.error?.message || "\u672A\u77E5\u9519\u8BEF"
705
+ };
706
+ const failedToolMessage = {
707
+ ...runningToolMessage,
708
+ content: JSON.stringify(errorResult),
709
+ toolCallId: rejectedValue.toolCallId,
710
+ isStreaming: false,
711
+ toolName: rejectedValue.toolName,
712
+ toolRunId: rejectedValue.toolRunId,
713
+ toolPayload: rejectedValue.toolPayload
714
+ };
715
+ dispatch(
716
+ updateToolMessage({
717
+ id: runningToolMessageId,
718
+ changes: {
719
+ content: failedToolMessage.content,
720
+ toolCallId: failedToolMessage.toolCallId,
721
+ isStreaming: false,
722
+ toolName: rejectedValue.toolName,
723
+ toolRunId: rejectedValue.toolRunId,
724
+ toolPayload: rejectedValue.toolPayload
725
+ }
726
+ })
727
+ );
728
+ await persistToolMessage(dispatch, failedToolMessage, {
729
+ isStreaming: false,
730
+ soft: true
731
+ });
732
+ if (rejectedValue.hasPendingInteraction) {
733
+ hasPendingInteraction = true;
734
+ }
735
+ }
736
+ }
737
+ }
738
+ return {
739
+ finalContentBuffer: updatedContentBuffer,
740
+ hasHandedOff,
741
+ hasPendingInteraction
742
+ };
743
+ }
744
+ );
745
+
746
+ // packages/ai/chat/parseApiError.ts
747
+ async function parseApiError(response) {
748
+ const errorBody = await response.text();
749
+ const truncateErrorMessage = (message, maxChars = 320) => message.length <= maxChars ? message : `${message.slice(0, maxChars)}\u2026`;
750
+ const isContextOverflow = (message) => /maximum context length|context length|context_length_exceeded|requested about .*tokens|too many tokens/i.test(message);
751
+ let defaultMessage = `\u72B6\u6001\u7801 ${response.status} ${response.statusText}`;
752
+ let errorMessage = defaultMessage;
753
+ let errorCode = `E${response.status}`;
754
+ try {
755
+ const errorJson = JSON.parse(errorBody);
756
+ errorMessage = errorJson?.error?.message || errorJson?.message || errorJson?.msg || errorBody || defaultMessage;
757
+ errorCode = errorJson?.error?.code || errorJson?.code || errorCode;
758
+ } catch (_e) {
759
+ if (errorBody) {
760
+ errorMessage = errorBody;
761
+ }
762
+ }
763
+ switch (response.status) {
764
+ case 400:
765
+ if (isContextOverflow(errorMessage) || isContextOverflow(errorBody) || errorCode === "UPSTREAM_400") {
766
+ return "\u4E0A\u4E0B\u6587\u8FC7\u957F\uFF1A\u672C\u8F6E\u6D88\u606F\u6216\u5DE5\u5177\u7ED3\u679C\u592A\u5927\u3002\u8BF7\u7F29\u5C0F\u8303\u56F4\uFF0C\u6216\u5148\u8BFB\u53D6\u66F4\u5C0F\u7247\u6BB5\u540E\u518D\u7EE7\u7EED\u3002";
767
+ }
768
+ if (errorCode === "MISSING_PROVIDER_API_KEY") {
769
+ return truncateErrorMessage(errorMessage);
770
+ }
771
+ if (errorMessage && errorMessage !== defaultMessage) {
772
+ return `\u8BF7\u6C42\u53C2\u6570\u9519\u8BEF: ${truncateErrorMessage(errorMessage)}`;
773
+ }
774
+ return "\u8BF7\u6C42\u53C2\u6570\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u8F93\u5165";
775
+ case 413:
776
+ return "\u8BF7\u6C42\u5185\u5BB9\u8FC7\u5927\uFF1A\u8BF7\u51CF\u5C11\u4E00\u6B21\u53D1\u9001\u7684\u6D88\u606F\u3001\u6587\u4EF6\u6216\u5DE5\u5177\u7ED3\u679C\u3002";
777
+ case 401:
778
+ switch (errorCode) {
779
+ case "AUTH_TOKEN_EXPIRED":
780
+ return "\u767B\u5F55\u72B6\u6001\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u5148\u767B\u51FA\u540E\u91CD\u65B0\u767B\u5F55";
781
+ case "AUTH_ACCOUNT_INVALID":
782
+ return "\u8D26\u6237\u65E0\u6548\u6216\u5DF2\u88AB\u505C\u7528\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458";
783
+ case "AUTH_NO_TOKEN":
784
+ return "\u672A\u68C0\u6D4B\u5230\u767B\u5F55\u72B6\u6001\uFF0C\u8BF7\u5148\u767B\u5F55";
785
+ case "AUTH_INVALID_TOKEN":
786
+ return "\u767B\u5F55\u51ED\u8BC1\u65E0\u6548\uFF0C\u8BF7\u5148\u767B\u51FA\u540E\u91CD\u65B0\u767B\u5F55";
787
+ case "AUTH_TOKEN_NOT_ACTIVE":
788
+ return "\u4EE4\u724C\u5C1A\u672A\u751F\u6548\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5";
789
+ default:
790
+ return errorMessage && errorMessage !== `\u72B6\u6001\u7801 401 Unauthorized` ? `\u8BA4\u8BC1\u9519\u8BEF: ${truncateErrorMessage(errorMessage)}` : "\u8EAB\u4EFD\u9A8C\u8BC1\u5931\u8D25\uFF0C\u8BF7\u5148\u767B\u51FA\u540E\u91CD\u65B0\u767B\u5F55";
791
+ }
792
+ case 503:
793
+ return errorMessage && errorMessage !== `\u72B6\u6001\u7801 503 Service Unavailable` ? truncateErrorMessage(errorMessage) : "\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5";
794
+ case 504:
795
+ return "\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5";
796
+ default:
797
+ return `API\u8BF7\u6C42\u5931\u8D25: ${truncateErrorMessage(errorMessage)}`;
798
+ }
799
+ }
800
+
801
+ // packages/ai/chat/accumulateToolCallChunks.ts
802
+ function accumulateToolCallChunks(currentAccumulatedCalls, toolCallChunks) {
803
+ const out = [...currentAccumulatedCalls];
804
+ for (const chunk of toolCallChunks) {
805
+ const { index, id, type, function: fn } = chunk;
806
+ if (index !== void 0) {
807
+ while (out.length <= index) {
808
+ out.push({
809
+ id: "",
810
+ type: "function",
811
+ function: { name: "", arguments: "" }
812
+ });
813
+ }
814
+ const cur = out[index];
815
+ if (id && !cur.id) cur.id = id;
816
+ if (type && !cur.type) cur.type = type;
817
+ if (!cur.function) cur.function = { name: "", arguments: "" };
818
+ if (fn) {
819
+ if (fn.name) cur.function.name += fn.name;
820
+ if (fn.arguments) {
821
+ if (typeof fn.arguments === "string") {
822
+ const currentArgs = typeof cur.function.arguments === "string" ? cur.function.arguments : "";
823
+ cur.function.arguments = currentArgs + fn.arguments;
824
+ } else {
825
+ cur.function.arguments = fn.arguments;
826
+ }
827
+ }
828
+ }
829
+ continue;
830
+ }
831
+ if (fn?.name || fn?.arguments) {
832
+ let targetIndex = -1;
833
+ if (id) {
834
+ targetIndex = out.findIndex((c) => c.id === id);
835
+ } else if (out.length > 0) {
836
+ targetIndex = out.length - 1;
837
+ }
838
+ if (targetIndex >= 0) {
839
+ const target = out[targetIndex];
840
+ if (fn.name) target.function.name += fn.name;
841
+ if (fn.arguments) {
842
+ if (typeof fn.arguments === "string") {
843
+ const currentArgs = typeof target.function.arguments === "string" ? target.function.arguments : "";
844
+ target.function.arguments = currentArgs + fn.arguments;
845
+ } else {
846
+ target.function.arguments = fn.arguments;
847
+ }
848
+ }
849
+ } else if (id) {
850
+ const newCall = {
851
+ id,
852
+ type: type || "function",
853
+ function: {
854
+ name: fn.name || "",
855
+ arguments: fn.arguments || (!fn.arguments && typeof fn.arguments === "object" ? {} : "")
856
+ // Initial empty value based on type? Or just default string
857
+ }
858
+ };
859
+ if (fn.arguments) {
860
+ newCall.function.arguments = fn.arguments;
861
+ } else {
862
+ newCall.function.arguments = "";
863
+ }
864
+ out.push(newCall);
865
+ }
866
+ }
867
+ }
868
+ return out;
869
+ }
870
+
871
+ // packages/ai/chat/toolCallArgumentGuard.ts
872
+ var INVALID_TOOL_ARGS_REPLACEMENT = '{"_invalid":true,"_reason":"arguments truncated or malformed"}';
873
+ var INVALID_TOOL_ARGS_OUTBOUND_REPLACEMENT = '{"_invalid":true}';
874
+ var INVALID_TOOL_RESULT_HINT = "\u5DE5\u5177\u53C2\u6570 JSON \u88AB\u622A\u65AD\uFF08\u5927\u6982\u7387\u8D85\u51FA\u8F93\u51FA\u957F\u5EA6\uFF09\u3002\u4E0D\u8981\u628A\u5B8C\u6574\u6E90\u7801\u585E\u8FDB\u4E00\u6B21\u5DE5\u5177\u8C03\u7528\uFF1A\u5148\u7528 appFileWrite \u5206\u6587\u4EF6\u591A\u6B21\u5199\u5165\uFF0C\u518D\u8C03\u7528\u4E0D\u5E26\u5185\u8054\u5927\u53C2\u6570\u7684 appPreflight/appDeploy\u3002";
875
+ var ORPHAN_TOOL_RESULT_PLACEHOLDER = '{"error":"tool call was interrupted"}';
876
+ function parseToolCallArguments(args) {
877
+ if (isRecord(args)) {
878
+ return { valid: true, parsed: args };
879
+ }
880
+ if (typeof args !== "string") return { valid: false };
881
+ const trimmed = args.trim();
882
+ if (!trimmed) return { valid: false };
883
+ try {
884
+ const parsed = JSON.parse(trimmed);
885
+ if (!isRecord(parsed)) {
886
+ return { valid: false };
887
+ }
888
+ return { valid: true, parsed };
889
+ } catch {
890
+ return { valid: false };
891
+ }
892
+ }
893
+ function buildInvalidToolCallSelfHealResult(callId, toolName) {
894
+ return JSON.stringify({
895
+ error: true,
896
+ toolCallId: callId,
897
+ ...toolName ? { toolName } : {},
898
+ message: INVALID_TOOL_RESULT_HINT
899
+ });
900
+ }
901
+ function normalizeToolCallArgumentsInPlace(call, replacement) {
902
+ if (!call || typeof call !== "object") return;
903
+ const fn = call.function;
904
+ if (!fn || typeof fn !== "object") return;
905
+ const { valid } = parseToolCallArguments(fn.arguments);
906
+ if (!valid) {
907
+ fn.arguments = replacement;
908
+ } else if (typeof fn.arguments !== "string") {
909
+ try {
910
+ fn.arguments = JSON.stringify(fn.arguments);
911
+ } catch {
912
+ fn.arguments = replacement;
913
+ }
914
+ }
915
+ }
916
+ function sanitizeOutboundMessages(messages, opts = {}) {
917
+ if (!Array.isArray(messages) || messages.length === 0) return messages ?? [];
918
+ const argsReplacement = opts.argsReplacement ?? INVALID_TOOL_ARGS_OUTBOUND_REPLACEMENT;
919
+ const orphanReplacement = opts.orphanReplacement ?? ORPHAN_TOOL_RESULT_PLACEHOLDER;
920
+ const cloned = messages.map((msg) => ({ ...msg }));
921
+ const answeredCallIds = /* @__PURE__ */ new Set();
922
+ for (const msg of cloned) {
923
+ if (msg?.role === "tool" && typeof msg.tool_call_id === "string") {
924
+ answeredCallIds.add(msg.tool_call_id);
925
+ }
926
+ }
927
+ const result = [];
928
+ for (const msg of cloned) {
929
+ if (msg?.role === "assistant" && Array.isArray(msg.tool_calls)) {
930
+ msg.tool_calls = msg.tool_calls.map((call) => ({
931
+ ...call,
932
+ function: { ...call?.function ?? {} }
933
+ }));
934
+ for (const call of msg.tool_calls) {
935
+ normalizeToolCallArgumentsInPlace(call, argsReplacement);
936
+ }
937
+ result.push(msg);
938
+ for (const call of msg.tool_calls) {
939
+ const callId = typeof call?.id === "string" ? call.id : void 0;
940
+ if (!callId) continue;
941
+ if (answeredCallIds.has(callId)) continue;
942
+ answeredCallIds.add(callId);
943
+ result.push({
944
+ role: "tool",
945
+ tool_call_id: callId,
946
+ content: orphanReplacement
947
+ });
948
+ }
949
+ continue;
950
+ }
951
+ result.push(msg);
952
+ }
953
+ return result;
954
+ }
955
+ function sanitizeOutboundResponsesInput(input, opts = {}) {
956
+ if (!Array.isArray(input) || input.length === 0) return input ?? [];
957
+ const argsReplacement = opts.argsReplacement ?? INVALID_TOOL_ARGS_OUTBOUND_REPLACEMENT;
958
+ const orphanReplacement = opts.orphanReplacement ?? ORPHAN_TOOL_RESULT_PLACEHOLDER;
959
+ const answeredCallIds = /* @__PURE__ */ new Set();
960
+ for (const item of input) {
961
+ if (item?.type === "function_call_output" && typeof item.call_id === "string") {
962
+ answeredCallIds.add(item.call_id);
963
+ }
964
+ }
965
+ const result = [];
966
+ for (const item of input) {
967
+ if (item?.type === "function_call") {
968
+ const cloned = { ...item };
969
+ const { valid } = parseToolCallArguments(cloned.arguments);
970
+ if (!valid) {
971
+ cloned.arguments = argsReplacement;
972
+ } else if (typeof cloned.arguments !== "string") {
973
+ try {
974
+ cloned.arguments = JSON.stringify(cloned.arguments);
975
+ } catch {
976
+ cloned.arguments = argsReplacement;
977
+ }
978
+ }
979
+ result.push(cloned);
980
+ const callId = typeof cloned.call_id === "string" ? cloned.call_id : void 0;
981
+ if (callId && !answeredCallIds.has(callId)) {
982
+ answeredCallIds.add(callId);
983
+ result.push({
984
+ type: "function_call_output",
985
+ call_id: callId,
986
+ output: orphanReplacement
987
+ });
988
+ }
989
+ continue;
990
+ }
991
+ result.push(item);
992
+ }
993
+ return result;
994
+ }
995
+
996
+ // packages/ai/chat/inlineImageUrlsForCustomProvider.ts
997
+ var FILE_CONTENT_PATH = "/api/v1/db/file/content/";
998
+ var shouldInlineImageUrlsForAgent = (agentConfig) => {
999
+ const apiSource = agentConfig?.apiSource?.toLowerCase();
1000
+ const provider = agentConfig?.provider?.toLowerCase();
1001
+ const model = agentConfig?.model?.toLowerCase();
1002
+ if (apiSource === "custom" || provider === "custom") return true;
1003
+ if (isNoloHostedProvider(provider)) return true;
1004
+ return provider === "openrouter" && model === "minimax/minimax-m3";
1005
+ };
1006
+ var isInlineCandidate = (url) => /^https?:\/\//i.test(url) && url.includes(FILE_CONTENT_PATH);
1007
+ var bytesToBase64 = (bytes) => {
1008
+ let binary = "";
1009
+ for (const byte of bytes) {
1010
+ binary += String.fromCharCode(byte);
1011
+ }
1012
+ return btoa(binary);
1013
+ };
1014
+ var defaultFetchImage = async (url) => {
1015
+ const response = await fetch(url);
1016
+ if (!response.ok) {
1017
+ return {
1018
+ ok: false,
1019
+ error: `HTTP ${response.status}`
1020
+ };
1021
+ }
1022
+ const bytes = new Uint8Array(await response.arrayBuffer());
1023
+ return {
1024
+ ok: true,
1025
+ mimeType: response.headers.get("content-type") ?? "application/octet-stream",
1026
+ bytes
1027
+ };
1028
+ };
1029
+ var cloneImagePartWithDataUrl = async (part, fetchImage) => {
1030
+ const url = part?.image_url?.url;
1031
+ if (typeof url !== "string" || !isInlineCandidate(url)) return part;
1032
+ const result = await fetchImage(url);
1033
+ if (!result.ok || !result.bytes) {
1034
+ throw new Error(
1035
+ `Failed to inline custom provider image URL ${url}: ${result.error ?? "unknown error"}`
1036
+ );
1037
+ }
1038
+ const mimeType = result.mimeType || "application/octet-stream";
1039
+ return {
1040
+ ...part,
1041
+ image_url: {
1042
+ ...part.image_url,
1043
+ url: `data:${mimeType};base64,${bytesToBase64(result.bytes)}`
1044
+ }
1045
+ };
1046
+ };
1047
+ var inlineImageUrlsForCustomProvider = async (bodyData, options) => {
1048
+ if (!options.shouldInline) return bodyData;
1049
+ const body = bodyData;
1050
+ if (!Array.isArray(body?.messages)) return bodyData;
1051
+ const fetchImage = options.fetchImage ?? defaultFetchImage;
1052
+ let changed = false;
1053
+ const messages = [];
1054
+ for (const message of body.messages) {
1055
+ if (!Array.isArray(message?.content)) {
1056
+ messages.push(message);
1057
+ continue;
1058
+ }
1059
+ const content = await Promise.all(
1060
+ message.content.map(async (part) => {
1061
+ if (part?.type !== "image_url") return part;
1062
+ return cloneImagePartWithDataUrl(part, fetchImage);
1063
+ })
1064
+ );
1065
+ let messageChanged = false;
1066
+ for (let i = 0; i < content.length; i++) {
1067
+ if (content[i] !== message.content[i]) {
1068
+ changed = true;
1069
+ messageChanged = true;
1070
+ break;
1071
+ }
1072
+ }
1073
+ messages.push(messageChanged ? { ...message, content } : message);
1074
+ }
1075
+ if (!changed) return bodyData;
1076
+ return {
1077
+ ...body,
1078
+ messages
1079
+ };
1080
+ };
1081
+
1082
+ // packages/ai/chat/streamReader.ts
1083
+ function createAbortError(message = "The operation was aborted.") {
1084
+ return new DOMException(message, "AbortError");
1085
+ }
1086
+ async function readStreamChunk(reader, options) {
1087
+ const signal = options?.signal;
1088
+ if (signal?.aborted) {
1089
+ throw createAbortError();
1090
+ }
1091
+ const timeoutMs = options?.timeoutMs;
1092
+ if (!signal && !(timeoutMs && timeoutMs > 0)) {
1093
+ return reader.read();
1094
+ }
1095
+ let settled = false;
1096
+ let timeoutId;
1097
+ let onAbort;
1098
+ return new Promise((resolve, reject) => {
1099
+ const finish = (cb) => {
1100
+ if (settled) return;
1101
+ settled = true;
1102
+ if (timeoutId) clearTimeout(timeoutId);
1103
+ if (onAbort && signal) signal.removeEventListener("abort", onAbort);
1104
+ cb();
1105
+ };
1106
+ onAbort = () => {
1107
+ void reader.cancel().catch(() => {
1108
+ });
1109
+ finish(() => reject(createAbortError()));
1110
+ };
1111
+ signal?.addEventListener("abort", onAbort);
1112
+ if (timeoutMs && timeoutMs > 0) {
1113
+ timeoutId = setTimeout(() => {
1114
+ finish(
1115
+ () => reject(
1116
+ new Error(
1117
+ options?.timeoutErrorMessage ?? `Stream stalled for ${Math.round(timeoutMs / 1e3)}s`
1118
+ )
1119
+ )
1120
+ );
1121
+ }, timeoutMs);
1122
+ }
1123
+ reader.read().then(
1124
+ (result) => finish(() => resolve(result)),
1125
+ (err) => finish(() => reject(err))
1126
+ );
1127
+ });
1128
+ }
1129
+
1130
+ // packages/ai/agent/utils/imageOutput.ts
1131
+ var LEGACY_IMAGE_MODELS = /* @__PURE__ */ new Set([
1132
+ "google/gemini-3-pro-image-preview",
1133
+ "google/gemini-3.1-flash-image-preview"
1134
+ ]);
1135
+ function supportsImageGeneration(agent) {
1136
+ if (agent.hasImageOutput === true) return true;
1137
+ if (getPublicImageAgentMode(agent) === "continuous") return true;
1138
+ const modelName = toTrimmedString(agent.model);
1139
+ if (!modelName) return false;
1140
+ const modelInfo = getModelInfo(modelName);
1141
+ if (modelInfo) {
1142
+ return !!(modelInfo.hasImageOutput ?? modelInfo.supportsImageOutput);
1143
+ }
1144
+ const normalized = modelName.toLowerCase();
1145
+ if (LEGACY_IMAGE_MODELS.has(normalized)) return true;
1146
+ if (agent.imageConfig?.enabled && agent.hasVision) return true;
1147
+ if (getPublicImageAgentMode(agent) === "continuous") return true;
1148
+ return normalized.includes("image-preview") || normalized.includes("flash-image") || normalized.includes("seedream") || normalized.includes("flux.");
1149
+ }
1150
+
1151
+ // packages/ai/chat/sendOpenAICompletionsRequest.ts
1152
+ function appendTextChunk(currentContentBuffer, textChunk) {
1153
+ if (!textChunk) return currentContentBuffer;
1154
+ const updatedContentBuffer = [...currentContentBuffer];
1155
+ const lastIndex = updatedContentBuffer.length - 1;
1156
+ if (lastIndex >= 0 && updatedContentBuffer[lastIndex].type === "text") {
1157
+ const last = updatedContentBuffer[lastIndex];
1158
+ updatedContentBuffer[lastIndex] = {
1159
+ ...last,
1160
+ text: (last.text || "") + textChunk
1161
+ };
1162
+ } else {
1163
+ updatedContentBuffer.push({ type: "text", text: textChunk });
1164
+ }
1165
+ return updatedContentBuffer;
1166
+ }
1167
+ var EXPLICIT_IMAGE_TOOL_NAMES = /* @__PURE__ */ new Set([
1168
+ "openAIGptImage",
1169
+ "openAIGptImageGenerate",
1170
+ "chatgptWebImageGenerate",
1171
+ "openAIGptImageEdit",
1172
+ "geminiProImagePreview"
1173
+ ]);
1174
+ function getStreamErrorMessage(data) {
1175
+ const message = asOptionalTrimmedString(data?.error?.message) ?? asOptionalTrimmedString(data?.error?.msg) ?? asOptionalTrimmedString(data?.message);
1176
+ if (message) return message;
1177
+ const code = asOptionalTrimmedString(data?.error?.code) ?? asOptionalTrimmedString(data?.code);
1178
+ if (code) return code;
1179
+ const type = asOptionalTrimmedString(data?.error?.type);
1180
+ if (type) return type;
1181
+ return "Unknown error";
1182
+ }
1183
+ function formatStreamErrorMessage(data) {
1184
+ const rawMessage = getStreamErrorMessage(data);
1185
+ if (/prohibited|violation|terms\s+of\s+service|content\s+policy|safety/i.test(
1186
+ rawMessage
1187
+ )) {
1188
+ return "\u5F53\u524D\u6A21\u578B\u670D\u52A1\u5546\u62D2\u7EDD\u4E86\u8FD9\u6B21\u8BF7\u6C42\u3002\u4F60\u53EF\u4EE5\u7A0D\u540E\u91CD\u8BD5\uFF0C\u6216\u5207\u6362\u5230\u5176\u4ED6\u6A21\u578B\u7EE7\u7EED\u3002";
1189
+ }
1190
+ return rawMessage;
1191
+ }
1192
+ function getChoiceFinishErrorMessage(data, choice) {
1193
+ if (choice?.error || choice?.message || choice?.code) {
1194
+ const message = formatStreamErrorMessage(choice);
1195
+ if (message && message !== "Unknown error") return message;
1196
+ }
1197
+ if (data?.error || data?.message || data?.code) {
1198
+ const message = formatStreamErrorMessage(data);
1199
+ if (message && message !== "Unknown error") return message;
1200
+ }
1201
+ const messageContent = asOptionalTrimmedString(choice?.message?.content);
1202
+ if (messageContent) return messageContent;
1203
+ return null;
1204
+ }
1205
+ var withImageGenerationStage = (messageMetadata, stage) => {
1206
+ const previousState = messageMetadata?.imageGenerationState;
1207
+ if (previousState?.kind !== "image_generation") {
1208
+ return messageMetadata;
1209
+ }
1210
+ return {
1211
+ ...messageMetadata ?? {},
1212
+ imageGenerationState: {
1213
+ ...previousState,
1214
+ stage
1215
+ }
1216
+ };
1217
+ };
1218
+ var shouldShowImageSavingState = (contentBuffer) => contentBuffer.some((part) => part?.type === "image_url") && !contentBuffer.some(
1219
+ (part) => part?.type === "text" && typeof part.text === "string" && part.text.trim().length > 0
1220
+ );
1221
+ var STREAM_READ_TIMEOUT_MS = 45e3;
1222
+ var logQuickChatPerfStage = (startedAt, stage, details) => {
1223
+ if (!startedAt) return;
1224
+ const now = typeof performance !== "undefined" ? performance.now() : Date.now();
1225
+ console.info("[QuickChatPerf]", {
1226
+ stage,
1227
+ elapsedMs: now - startedAt,
1228
+ ...typeof performance !== "undefined" ? { atMs: now } : {},
1229
+ ...details ?? {}
1230
+ });
1231
+ };
1232
+ function createInitialStreamState() {
1233
+ return {
1234
+ contentBuffer: [],
1235
+ totalUsage: null,
1236
+ accumulatedToolCalls: [],
1237
+ reasoningBuffer: "",
1238
+ thinkState: createThinkParserState(),
1239
+ assistantToolCalls: void 0,
1240
+ hasHandedOff: false,
1241
+ hasProcessedToolCalls: false,
1242
+ alreadyFinalized: false,
1243
+ finishReason: null
1244
+ };
1245
+ }
1246
+ function buildRequestBodyWithTools(bodyData, agentConfig, disableToolsForThisRequest) {
1247
+ const messagesForBody = Array.isArray(bodyData?.messages) ? sanitizeOutboundMessages(bodyData.messages) : bodyData?.messages;
1248
+ const baseBody = messagesForBody !== bodyData?.messages ? { ...bodyData, messages: messagesForBody } : bodyData;
1249
+ if (disableToolsForThisRequest) return baseBody;
1250
+ const modelInfo = getModelInfo(agentConfig.model);
1251
+ if (modelInfo?.hasImageOutput) {
1252
+ return baseBody;
1253
+ }
1254
+ const rawTools = agentConfig.tools;
1255
+ if (!Array.isArray(rawTools) || rawTools.length === 0) return baseBody;
1256
+ const hasExplicitImageTool = rawTools.some(
1257
+ (toolName) => typeof toolName === "string" && EXPLICIT_IMAGE_TOOL_NAMES.has(toolName)
1258
+ );
1259
+ if (supportsImageGeneration(agentConfig) && !hasExplicitImageTool) {
1260
+ return baseBody;
1261
+ }
1262
+ const tools = prepareTools(rawTools, { provider: agentConfig.provider });
1263
+ if (!tools.length) return baseBody;
1264
+ return {
1265
+ ...baseBody,
1266
+ tools,
1267
+ tool_choice: baseBody.tool_choice ?? "auto"
1268
+ };
1269
+ }
1270
+ async function finalizeStream(state, ctx) {
1271
+ if (state.hasHandedOff || state.alreadyFinalized) return state;
1272
+ const savingMetadata = withImageGenerationStage(
1273
+ ctx.messageMetadata,
1274
+ "saving"
1275
+ );
1276
+ if (savingMetadata && shouldShowImageSavingState(state.contentBuffer)) {
1277
+ ctx.dispatch(
1278
+ messageStreaming({
1279
+ id: ctx.messageId,
1280
+ dialogId: ctx.dialogId,
1281
+ dbKey: ctx.msgKey,
1282
+ content: "",
1283
+ thinkContent: state.reasoningBuffer,
1284
+ role: "assistant",
1285
+ agentKey: ctx.agentConfig.dbKey,
1286
+ cybotKey: ctx.agentConfig.dbKey,
1287
+ ...asOptionalTrimmedString(ctx.agentConfig?.name) ? { agentName: asOptionalTrimmedString(ctx.agentConfig?.name) } : {},
1288
+ ...savingMetadata ?? {}
1289
+ })
1290
+ );
1291
+ ctx.messageMetadata = savingMetadata;
1292
+ }
1293
+ await ctx.dispatch(
1294
+ messageStreamEnd({
1295
+ finalContentBuffer: state.contentBuffer,
1296
+ totalUsage: state.totalUsage,
1297
+ msgKey: ctx.msgKey,
1298
+ agentConfig: ctx.agentConfig,
1299
+ dialogId: ctx.dialogId,
1300
+ dialogKey: ctx.dialogKey,
1301
+ messageId: ctx.messageId,
1302
+ reasoningBuffer: state.reasoningBuffer,
1303
+ messageMetadata: ctx.messageMetadata,
1304
+ toolCalls: state.assistantToolCalls,
1305
+ spaceId: ctx.spaceId
1306
+ })
1307
+ );
1308
+ return {
1309
+ ...state,
1310
+ alreadyFinalized: true
1311
+ };
1312
+ }
1313
+ var EMPTY_UPSTREAM_STREAM_MESSAGE = "\u6A21\u578B\u8FD4\u56DE\u4E86\u7A7A\u54CD\u5E94\uFF0C\u8BF7\u91CD\u8BD5\u6216\u5207\u6362\u5176\u4ED6\u6A21\u578B";
1314
+ function markEmptyCompletionAsError(state, ctx) {
1315
+ const producedNothing = state.contentBuffer.length === 0 && !state.reasoningBuffer.trim() && (state.assistantToolCalls?.length ?? 0) === 0;
1316
+ if (!producedNothing || state.hasHandedOff || state.alreadyFinalized) {
1317
+ return state;
1318
+ }
1319
+ markStreamMessageAborted(ctx, EMPTY_UPSTREAM_STREAM_MESSAGE);
1320
+ return {
1321
+ ...state,
1322
+ contentBuffer: appendTextChunk(
1323
+ state.contentBuffer,
1324
+ `[\u9519\u8BEF: ${EMPTY_UPSTREAM_STREAM_MESSAGE}]`
1325
+ )
1326
+ };
1327
+ }
1328
+ function markStreamMessageAborted(ctx, errorMessage) {
1329
+ const base = ctx.messageMetadata ?? {};
1330
+ const previousMetadata = base.metadata && typeof base.metadata === "object" ? base.metadata : {};
1331
+ ctx.messageMetadata = {
1332
+ ...base,
1333
+ metadata: {
1334
+ ...previousMetadata,
1335
+ error: true,
1336
+ message: errorMessage
1337
+ }
1338
+ };
1339
+ }
1340
+ function applyUsage(state, data) {
1341
+ if (!data.usage) return state;
1342
+ return {
1343
+ ...state,
1344
+ totalUsage: updateTotalUsage(state.totalUsage, data.usage)
1345
+ };
1346
+ }
1347
+ function applyDelta(state, delta) {
1348
+ let hasNewVisibleContent = false;
1349
+ let next = { ...state };
1350
+ const reasoningChunk = delta.reasoning_content ?? delta.reasoning ?? "";
1351
+ if (reasoningChunk) {
1352
+ next.reasoningBuffer = (next.reasoningBuffer || "") + reasoningChunk;
1353
+ }
1354
+ if (Array.isArray(delta.tool_calls) && delta.tool_calls.length > 0) {
1355
+ const accumulated = accumulateToolCallChunks(
1356
+ next.accumulatedToolCalls,
1357
+ delta.tool_calls
1358
+ );
1359
+ next = {
1360
+ ...next,
1361
+ accumulatedToolCalls: accumulated,
1362
+ assistantToolCalls: accumulated.map((call) => ({
1363
+ id: call.id,
1364
+ type: "function",
1365
+ function: {
1366
+ name: call.function?.name,
1367
+ arguments: typeof call.function?.arguments === "string" ? call.function.arguments : JSON.stringify(call.function?.arguments ?? {})
1368
+ }
1369
+ }))
1370
+ };
1371
+ }
1372
+ const deltaAny = delta;
1373
+ if (Array.isArray(deltaAny.images) && deltaAny.images.length > 0) {
1374
+ next = {
1375
+ ...next,
1376
+ contentBuffer: [...next.contentBuffer, ...deltaAny.images]
1377
+ };
1378
+ hasNewVisibleContent = true;
1379
+ }
1380
+ const contentChunk = delta.content || "";
1381
+ if (contentChunk) {
1382
+ const parsed = processThinkChunk(contentChunk, next.thinkState);
1383
+ next.thinkState = parsed.state;
1384
+ if (parsed.reasoning) {
1385
+ next.reasoningBuffer = (next.reasoningBuffer || "") + parsed.reasoning;
1386
+ }
1387
+ if (parsed.content) {
1388
+ next = {
1389
+ ...next,
1390
+ contentBuffer: appendTextChunk(next.contentBuffer, parsed.content)
1391
+ };
1392
+ hasNewVisibleContent = true;
1393
+ }
1394
+ }
1395
+ return { state: next, hasNewVisibleContent };
1396
+ }
1397
+ function emitStreamingUpdate(hasNewVisibleContent, state, ctx) {
1398
+ if (!hasNewVisibleContent) return;
1399
+ ctx.dispatch(
1400
+ messageStreaming({
1401
+ id: ctx.messageId,
1402
+ dialogId: ctx.dialogId,
1403
+ dbKey: ctx.msgKey,
1404
+ content: state.contentBuffer,
1405
+ thinkContent: state.reasoningBuffer,
1406
+ role: "assistant",
1407
+ agentKey: ctx.agentConfig.dbKey,
1408
+ cybotKey: ctx.agentConfig.dbKey,
1409
+ ...asOptionalTrimmedString(ctx.agentConfig?.name) ? { agentName: asOptionalTrimmedString(ctx.agentConfig?.name) } : {},
1410
+ ...ctx.messageMetadata ?? {}
1411
+ })
1412
+ );
1413
+ }
1414
+ function validateAndPartitionToolCalls(state) {
1415
+ const validCalls = [];
1416
+ const invalidCalls = [];
1417
+ for (const call of state.accumulatedToolCalls) {
1418
+ if (!call) continue;
1419
+ const argsValid = parseToolCallArguments(call?.function?.arguments).valid;
1420
+ if (argsValid) {
1421
+ validCalls.push(call);
1422
+ } else {
1423
+ const sanitized = {
1424
+ ...call,
1425
+ function: {
1426
+ ...call.function ?? {},
1427
+ name: call?.function?.name ?? "",
1428
+ arguments: INVALID_TOOL_ARGS_REPLACEMENT
1429
+ }
1430
+ };
1431
+ invalidCalls.push(sanitized);
1432
+ }
1433
+ }
1434
+ return { validCalls, invalidCalls };
1435
+ }
1436
+ function syncAssistantToolCallsAfterSanitize(state, invalidCalls) {
1437
+ if (!invalidCalls.length) return state.assistantToolCalls ?? [];
1438
+ const invalidById = /* @__PURE__ */ new Map();
1439
+ for (const call of invalidCalls) {
1440
+ if (call?.id) invalidById.set(call.id, call);
1441
+ }
1442
+ const base = Array.isArray(state.assistantToolCalls) ? state.assistantToolCalls : state.accumulatedToolCalls.map((call) => ({
1443
+ id: call.id,
1444
+ type: "function",
1445
+ function: {
1446
+ name: call.function?.name,
1447
+ arguments: typeof call.function?.arguments === "string" ? call.function.arguments : JSON.stringify(call.function?.arguments ?? {})
1448
+ }
1449
+ }));
1450
+ return base.map((call) => {
1451
+ if (!call?.id) return call;
1452
+ const invalid = invalidById.get(call.id);
1453
+ if (!invalid) return call;
1454
+ return {
1455
+ ...call,
1456
+ type: "function",
1457
+ function: {
1458
+ name: invalid.function?.name ?? call.function?.name ?? "",
1459
+ arguments: INVALID_TOOL_ARGS_REPLACEMENT
1460
+ }
1461
+ };
1462
+ });
1463
+ }
1464
+ async function persistInvalidToolCallResults(invalidCalls, ctx, startIndex) {
1465
+ for (let i = 0; i < invalidCalls.length; i++) {
1466
+ const call = invalidCalls[i];
1467
+ const callId = call?.id || `call_${Date.now()}_${Math.random().toString(36).slice(2)}`;
1468
+ const toolIndex = startIndex + i;
1469
+ const runningToolMessageId = `${ctx.messageId}-t${String(toolIndex).padStart(3, "0")}`;
1470
+ const runningToolDbKey = dialogMessageKey(ctx.dialogId, runningToolMessageId);
1471
+ const toolName = call?.function?.name || "unknown";
1472
+ const selfHealContent = buildInvalidToolCallSelfHealResult(callId, toolName);
1473
+ const toolMessage = {
1474
+ id: runningToolMessageId,
1475
+ dbKey: runningToolDbKey,
1476
+ role: "tool",
1477
+ content: selfHealContent,
1478
+ toolCallId: callId,
1479
+ thinkContent: "",
1480
+ cybotKey: ctx.agentConfig.dbKey,
1481
+ isStreaming: false,
1482
+ toolName,
1483
+ parentMessageId: ctx.messageId,
1484
+ toolPayload: {
1485
+ toolName,
1486
+ status: "failed",
1487
+ input: {},
1488
+ rawToolCall: call,
1489
+ error: {
1490
+ type: "InvalidToolCallArguments",
1491
+ message: "\u5DE5\u5177\u53C2\u6570 JSON \u88AB\u622A\u65AD\u6216\u975E\u6CD5\uFF0C\u5DF2\u8DF3\u8FC7\u6267\u884C\u5E76\u66FF\u6362\u4E3A\u5360\u4F4D arguments\u3002",
1492
+ retryable: true
1493
+ },
1494
+ summary: `\u274C ${toolName} \u53C2\u6570\u88AB\u622A\u65AD\uFF0C\u5DF2\u8DF3\u8FC7`
1495
+ }
1496
+ };
1497
+ ctx.dispatch(addToolMessage(toolMessage));
1498
+ await persistToolMessage(ctx.dispatch, toolMessage, {
1499
+ isStreaming: false,
1500
+ soft: true
1501
+ });
1502
+ }
1503
+ }
1504
+ async function processAccumulatedToolCalls(state, ctx) {
1505
+ if (!state.accumulatedToolCalls.length) {
1506
+ return {
1507
+ state,
1508
+ hasHandedOff: false,
1509
+ hasPendingInteraction: false
1510
+ };
1511
+ }
1512
+ const { validCalls, invalidCalls } = validateAndPartitionToolCalls(state);
1513
+ const sanitizedAssistantToolCalls = syncAssistantToolCallsAfterSanitize(
1514
+ state,
1515
+ invalidCalls
1516
+ );
1517
+ if (invalidCalls.length > 0) {
1518
+ await persistInvalidToolCallResults(
1519
+ invalidCalls,
1520
+ ctx,
1521
+ validCalls.length
1522
+ );
1523
+ }
1524
+ if (!validCalls.length) {
1525
+ const nextState2 = {
1526
+ ...state,
1527
+ accumulatedToolCalls: [],
1528
+ assistantToolCalls: sanitizedAssistantToolCalls,
1529
+ hasProcessedToolCalls: true,
1530
+ hasHandedOff: false
1531
+ };
1532
+ return {
1533
+ state: nextState2,
1534
+ hasHandedOff: false,
1535
+ hasPendingInteraction: false
1536
+ };
1537
+ }
1538
+ const result = await ctx.dispatch(
1539
+ handleToolCalls({
1540
+ accumulatedCalls: validCalls,
1541
+ currentContentBuffer: state.contentBuffer,
1542
+ agentConfig: ctx.agentConfig,
1543
+ messageId: ctx.messageId,
1544
+ dialogId: ctx.dialogId,
1545
+ dialogKey: ctx.dialogKey
1546
+ })
1547
+ ).unwrap();
1548
+ const nextState = {
1549
+ ...state,
1550
+ contentBuffer: result.finalContentBuffer,
1551
+ accumulatedToolCalls: [],
1552
+ assistantToolCalls: sanitizedAssistantToolCalls,
1553
+ hasProcessedToolCalls: true,
1554
+ hasHandedOff: result.hasHandedOff
1555
+ };
1556
+ return {
1557
+ state: nextState,
1558
+ hasHandedOff: result.hasHandedOff,
1559
+ hasPendingInteraction: result.hasPendingInteraction
1560
+ };
1561
+ }
1562
+ async function readStreamChunkWithTimeout(reader, signal) {
1563
+ return readStreamChunk(reader, {
1564
+ signal,
1565
+ timeoutMs: STREAM_READ_TIMEOUT_MS,
1566
+ timeoutErrorMessage: `\u6A21\u578B\u54CD\u5E94\u6D41 ${Math.round(STREAM_READ_TIMEOUT_MS / 1e3)} \u79D2\u5185\u6CA1\u6709\u8FD4\u56DE\u65B0\u5185\u5BB9`
1567
+ });
1568
+ }
1569
+ async function handleStreamCompletion(state, ctx, finalizeCtx) {
1570
+ let hasHandedOff = false;
1571
+ let hasPendingInteraction = false;
1572
+ const flushed = flushThinkParser(state.thinkState);
1573
+ state.thinkState = flushed.state;
1574
+ if (flushed.reasoning) {
1575
+ state.reasoningBuffer = (state.reasoningBuffer || "") + flushed.reasoning;
1576
+ }
1577
+ if (flushed.content) {
1578
+ state = {
1579
+ ...state,
1580
+ contentBuffer: appendTextChunk(state.contentBuffer, flushed.content)
1581
+ };
1582
+ }
1583
+ if (!state.hasProcessedToolCalls && state.accumulatedToolCalls.length > 0) {
1584
+ if (state.totalUsage) {
1585
+ ctx.dispatch(tokenUsageLiveUpdate({
1586
+ input_tokens: state.totalUsage.prompt_tokens ?? state.totalUsage.input_tokens,
1587
+ output_tokens: state.totalUsage.completion_tokens ?? state.totalUsage.output_tokens,
1588
+ cost: state.totalUsage.cost,
1589
+ dialogKey: ctx.dialogKey
1590
+ }));
1591
+ }
1592
+ const toolResult = await processAccumulatedToolCalls(state, {
1593
+ dispatch: ctx.dispatch,
1594
+ agentConfig: ctx.agentConfig,
1595
+ dialogId: ctx.dialogId,
1596
+ dialogKey: ctx.dialogKey,
1597
+ messageId: ctx.messageId
1598
+ });
1599
+ let next = toolResult.state;
1600
+ hasHandedOff ||= toolResult.hasHandedOff;
1601
+ hasPendingInteraction ||= toolResult.hasPendingInteraction;
1602
+ next = await finalizeStream(next, finalizeCtx);
1603
+ return { state: next, hasHandedOff, hasPendingInteraction };
1604
+ }
1605
+ state = markEmptyCompletionAsError(state, finalizeCtx);
1606
+ const finalized = await finalizeStream(state, finalizeCtx);
1607
+ return { state: finalized, hasHandedOff, hasPendingInteraction };
1608
+ }
1609
+ var sendOpenAICompletionsRequest = async ({
1610
+ bodyData,
1611
+ agentConfig,
1612
+ thunkApi,
1613
+ dialogKey,
1614
+ parentMessageId,
1615
+ messageMetadata,
1616
+ disableToolsForThisRequest = false,
1617
+ quickChatPerfStartedAt
1618
+ }) => {
1619
+ const { dispatch, getState, signal: thunkSignal } = thunkApi;
1620
+ const dialogId = extractCustomId(dialogKey);
1621
+ const controller = new AbortController();
1622
+ thunkSignal.addEventListener("abort", () => controller.abort());
1623
+ const signal = controller.signal;
1624
+ const streamSpaceId = selectCurrentSpaceId(getState()) || void 0;
1625
+ let messageId;
1626
+ let msgKey;
1627
+ if (parentMessageId) {
1628
+ messageId = parentMessageId;
1629
+ msgKey = `msg:${dialogId}:${messageId}`;
1630
+ } else {
1631
+ const newIds = createDialogMessageKeyAndId(dialogId);
1632
+ messageId = newIds.messageId;
1633
+ msgKey = newIds.key;
1634
+ }
1635
+ dispatch(addActiveController({ messageId, controller, dialogKey }));
1636
+ const requestBody = await inlineImageUrlsForCustomProvider(
1637
+ buildRequestBodyWithTools(
1638
+ bodyData,
1639
+ agentConfig,
1640
+ disableToolsForThisRequest
1641
+ ),
1642
+ {
1643
+ shouldInline: shouldInlineImageUrlsForAgent(agentConfig)
1644
+ }
1645
+ );
1646
+ let streamState = createInitialStreamState();
1647
+ let parseSSE = createSSEParser();
1648
+ let reader;
1649
+ const finalizeCtx = {
1650
+ dispatch,
1651
+ msgKey,
1652
+ dialogId,
1653
+ dialogKey,
1654
+ messageId,
1655
+ agentConfig,
1656
+ spaceId: streamSpaceId,
1657
+ messageMetadata
1658
+ };
1659
+ let hasHandedOffOverall = false;
1660
+ let hasPendingInteractionOverall = false;
1661
+ let lastFinishReason = null;
1662
+ let activeMessageMetadata = messageMetadata;
1663
+ let emptyCompletionRetryUsed = false;
1664
+ const buildMeta = () => ({
1665
+ hasToolCalls: Array.isArray(streamState.assistantToolCalls) && streamState.assistantToolCalls.length > 0,
1666
+ hasPendingInteraction: hasPendingInteractionOverall,
1667
+ hasHandedOff: hasHandedOffOverall,
1668
+ finishReason: lastFinishReason,
1669
+ messageId,
1670
+ usage: streamState.totalUsage ?? void 0
1671
+ });
1672
+ try {
1673
+ if (!parentMessageId) {
1674
+ dispatch(
1675
+ messageStreaming({
1676
+ id: messageId,
1677
+ dialogId,
1678
+ dbKey: msgKey,
1679
+ content: "",
1680
+ role: "assistant",
1681
+ agentKey: agentConfig.dbKey,
1682
+ cybotKey: agentConfig.dbKey,
1683
+ ...asOptionalTrimmedString(agentConfig?.name) ? { agentName: asOptionalTrimmedString(agentConfig?.name) } : {},
1684
+ ...activeMessageMetadata ?? {},
1685
+ isStreaming: true
1686
+ })
1687
+ );
1688
+ }
1689
+ const api = getApiEndpoint(agentConfig);
1690
+ const token = selectIdentityToken(getState()) ?? "";
1691
+ logQuickChatPerfStage(quickChatPerfStartedAt, "openai-completions-fetch-starting", {
1692
+ api,
1693
+ dialogKey
1694
+ });
1695
+ const response = await performFetchRequest({
1696
+ agentConfig,
1697
+ api,
1698
+ bodyData: requestBody,
1699
+ currentServer: selectCurrentServer(getState()),
1700
+ signal,
1701
+ token,
1702
+ dialogId
1703
+ });
1704
+ logQuickChatPerfStage(quickChatPerfStartedAt, "openai-completions-fetch-response", {
1705
+ ok: response.ok,
1706
+ status: response.status,
1707
+ dialogKey
1708
+ });
1709
+ activeMessageMetadata = withImageGenerationStage(
1710
+ activeMessageMetadata,
1711
+ "generating"
1712
+ );
1713
+ finalizeCtx.messageMetadata = activeMessageMetadata;
1714
+ if (!parentMessageId && activeMessageMetadata?.imageGenerationState) {
1715
+ dispatch(
1716
+ messageStreaming({
1717
+ id: messageId,
1718
+ dialogId,
1719
+ dbKey: msgKey,
1720
+ content: "",
1721
+ role: "assistant",
1722
+ agentKey: agentConfig.dbKey,
1723
+ cybotKey: agentConfig.dbKey,
1724
+ ...asOptionalTrimmedString(agentConfig?.name) ? { agentName: asOptionalTrimmedString(agentConfig?.name) } : {},
1725
+ ...activeMessageMetadata ?? {},
1726
+ isStreaming: true
1727
+ })
1728
+ );
1729
+ }
1730
+ if (!response.ok) {
1731
+ const errorMessage = await parseApiError(response);
1732
+ streamState = {
1733
+ ...streamState,
1734
+ contentBuffer: appendTextChunk(
1735
+ streamState.contentBuffer,
1736
+ `[\u9519\u8BEF: ${errorMessage}]`
1737
+ )
1738
+ };
1739
+ streamState = await finalizeStream(streamState, finalizeCtx);
1740
+ return buildMeta();
1741
+ }
1742
+ reader = response.body?.getReader();
1743
+ if (!reader) {
1744
+ streamState = markEmptyCompletionAsError(streamState, finalizeCtx);
1745
+ streamState = await finalizeStream(streamState, finalizeCtx);
1746
+ return buildMeta();
1747
+ }
1748
+ let decoder = new TextDecoder();
1749
+ let loggedFirstStreamChunk = false;
1750
+ let loggedFirstParsedEvent = false;
1751
+ let loggedFirstVisibleDelta = false;
1752
+ while (true) {
1753
+ const { done, value } = await readStreamChunkWithTimeout(reader, signal);
1754
+ if (done) {
1755
+ const producedNothing = streamState.contentBuffer.length === 0 && !streamState.reasoningBuffer.trim() && (streamState.assistantToolCalls?.length ?? 0) === 0;
1756
+ if (producedNothing && !emptyCompletionRetryUsed && !streamState.hasHandedOff && !streamState.alreadyFinalized && !signal.aborted) {
1757
+ emptyCompletionRetryUsed = true;
1758
+ const retryResponse = await performFetchRequest({
1759
+ agentConfig,
1760
+ api,
1761
+ bodyData: {
1762
+ ...requestBody,
1763
+ messages: [
1764
+ ...requestBody.messages ?? [],
1765
+ { role: "user", content: EMPTY_ASSISTANT_REPAIR_PROMPT }
1766
+ ]
1767
+ },
1768
+ currentServer: selectCurrentServer(getState()),
1769
+ signal,
1770
+ token,
1771
+ dialogId
1772
+ });
1773
+ if (retryResponse.ok && retryResponse.body) {
1774
+ streamState = createInitialStreamState();
1775
+ parseSSE = createSSEParser();
1776
+ decoder = new TextDecoder();
1777
+ reader = retryResponse.body.getReader();
1778
+ continue;
1779
+ }
1780
+ }
1781
+ const completion = await handleStreamCompletion(
1782
+ streamState,
1783
+ {
1784
+ dispatch,
1785
+ dialogId,
1786
+ dialogKey: finalizeCtx.dialogKey,
1787
+ messageId,
1788
+ agentConfig
1789
+ },
1790
+ finalizeCtx
1791
+ );
1792
+ streamState = completion.state;
1793
+ hasHandedOffOverall ||= completion.hasHandedOff;
1794
+ hasPendingInteractionOverall ||= completion.hasPendingInteraction;
1795
+ break;
1796
+ }
1797
+ if (!loggedFirstStreamChunk) {
1798
+ loggedFirstStreamChunk = true;
1799
+ logQuickChatPerfStage(
1800
+ quickChatPerfStartedAt,
1801
+ "openai-completions-first-stream-chunk",
1802
+ { dialogKey, byteLength: value.byteLength }
1803
+ );
1804
+ }
1805
+ const chunk = decoder.decode(value, { stream: true });
1806
+ const parsedResults = parseSSE(chunk);
1807
+ if (parsedResults.length > 0 && !loggedFirstParsedEvent) {
1808
+ loggedFirstParsedEvent = true;
1809
+ logQuickChatPerfStage(
1810
+ quickChatPerfStartedAt,
1811
+ "openai-completions-first-sse-event",
1812
+ { dialogKey, eventCount: parsedResults.length }
1813
+ );
1814
+ }
1815
+ for (const parsedData of parsedResults) {
1816
+ const dataList = Array.isArray(parsedData) ? parsedData : [parsedData];
1817
+ for (const data of dataList) {
1818
+ streamState = applyUsage(streamState, data);
1819
+ if (data === "[DONE]") {
1820
+ continue;
1821
+ }
1822
+ if (data.error) {
1823
+ const errorMsg = `Error: ${formatStreamErrorMessage(data)}`;
1824
+ streamState = {
1825
+ ...streamState,
1826
+ contentBuffer: appendTextChunk(
1827
+ streamState.contentBuffer,
1828
+ `
1829
+ [API Error] ${errorMsg}`
1830
+ )
1831
+ };
1832
+ await reader.cancel();
1833
+ break;
1834
+ }
1835
+ const choice = data.choices?.[0];
1836
+ if (!choice) continue;
1837
+ const delta = choice.delta || {};
1838
+ const { state: updatedState, hasNewVisibleContent } = applyDelta(
1839
+ streamState,
1840
+ delta
1841
+ );
1842
+ streamState = updatedState;
1843
+ if (hasNewVisibleContent && !loggedFirstVisibleDelta) {
1844
+ loggedFirstVisibleDelta = true;
1845
+ logQuickChatPerfStage(
1846
+ quickChatPerfStartedAt,
1847
+ "openai-completions-first-visible-delta",
1848
+ { dialogKey }
1849
+ );
1850
+ }
1851
+ emitStreamingUpdate(hasNewVisibleContent, streamState, {
1852
+ dispatch,
1853
+ agentConfig,
1854
+ messageId,
1855
+ msgKey,
1856
+ dialogId,
1857
+ messageMetadata: activeMessageMetadata
1858
+ });
1859
+ const finishReason = choice.finish_reason;
1860
+ if (finishReason) {
1861
+ lastFinishReason = finishReason;
1862
+ streamState.finishReason = finishReason;
1863
+ if (finishReason === "tool_calls") {
1864
+ if (streamState.totalUsage) {
1865
+ dispatch(tokenUsageLiveUpdate({
1866
+ input_tokens: streamState.totalUsage.prompt_tokens ?? streamState.totalUsage.input_tokens,
1867
+ output_tokens: streamState.totalUsage.completion_tokens ?? streamState.totalUsage.output_tokens,
1868
+ cost: streamState.totalUsage.cost,
1869
+ dialogKey
1870
+ }));
1871
+ }
1872
+ const toolResult = await processAccumulatedToolCalls(
1873
+ streamState,
1874
+ {
1875
+ dispatch,
1876
+ agentConfig,
1877
+ dialogId,
1878
+ dialogKey,
1879
+ messageId,
1880
+ messageMetadata
1881
+ }
1882
+ );
1883
+ streamState = toolResult.state;
1884
+ hasHandedOffOverall ||= toolResult.hasHandedOff;
1885
+ hasPendingInteractionOverall ||= toolResult.hasPendingInteraction;
1886
+ streamState = await finalizeStream(streamState, finalizeCtx);
1887
+ } else if (finishReason !== "stop") {
1888
+ const finishErrorMessage = finishReason === "error" ? getChoiceFinishErrorMessage(data, choice) : null;
1889
+ streamState = {
1890
+ ...streamState,
1891
+ contentBuffer: appendTextChunk(
1892
+ streamState.contentBuffer,
1893
+ finishErrorMessage ? `
1894
+ [API Error] Error: ${finishErrorMessage}` : finishReason === "error" ? "\n[API Error] Error: \u6A21\u578B\u54CD\u5E94\u4EE5 error \u7ED3\u675F\uFF0C\u4F46\u4E0A\u6E38\u672A\u8FD4\u56DE\u5177\u4F53\u9519\u8BEF\u3002\u8BF7\u91CD\u8BD5\uFF0C\u6216\u5207\u6362\u5230\u5176\u4ED6\u652F\u6301\u56FE\u7247\u8F93\u5165\u7684\u6A21\u578B\u3002" : `
1895
+ [\u6D41\u7ED3\u675F\u539F\u56E0: ${finishReason}]`
1896
+ )
1897
+ };
1898
+ }
1899
+ }
1900
+ }
1901
+ }
1902
+ }
1903
+ } catch (error) {
1904
+ let errorText;
1905
+ const isAbort = isAbortError(error);
1906
+ if (isAbort) {
1907
+ errorText = "\n[\u7528\u6237\u4E2D\u65AD]";
1908
+ } else {
1909
+ errorText = `
1910
+ [\u9519\u8BEF: ${toErrorMessage(error)}]`;
1911
+ }
1912
+ console.error("[SSE] sendOpenAICompletionsRequest error:", error);
1913
+ streamState = {
1914
+ ...streamState,
1915
+ contentBuffer: appendTextChunk(streamState.contentBuffer, errorText)
1916
+ };
1917
+ if (!isAbort) {
1918
+ markStreamMessageAborted(
1919
+ finalizeCtx,
1920
+ toErrorMessage(error)
1921
+ );
1922
+ }
1923
+ streamState = await finalizeStream(streamState, finalizeCtx);
1924
+ } finally {
1925
+ logQuickChatPerfStage(quickChatPerfStartedAt, "openai-completions-stream-finished", {
1926
+ dialogKey
1927
+ });
1928
+ dispatch(removeActiveController({ messageId, dialogKey }));
1929
+ try {
1930
+ await reader?.cancel();
1931
+ } catch (_e) {
1932
+ }
1933
+ }
1934
+ return buildMeta();
1935
+ };
1936
+
1937
+ export {
1938
+ filterAndCleanMessages,
1939
+ persistToolMessages,
1940
+ handleToolCalls,
1941
+ parseApiError,
1942
+ updateTotalUsage,
1943
+ INVALID_TOOL_ARGS_REPLACEMENT,
1944
+ parseToolCallArguments,
1945
+ buildInvalidToolCallSelfHealResult,
1946
+ sanitizeOutboundResponsesInput,
1947
+ readStreamChunk,
1948
+ sendOpenAICompletionsRequest
1949
+ };