nolo-cli 0.8.0 → 0.9.1

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 (183) hide show
  1. package/_executeModel-UD44KGZ4.js +203 -0
  2. package/action-ZJWE3Y5S.js +28 -0
  3. package/addContentAction-TVDBNJM5.js +26 -0
  4. package/addDialogAgentAction-EKH774VT.js +68 -0
  5. package/agentDeleteCommand-TCPEFJTF.js +327 -0
  6. package/agentEmailCommands-CZ3UILZ4.js +626 -0
  7. package/agentListCommands-SJKO2FFB.js +223 -0
  8. package/agentMachineCommands-PSNABISZ.js +425 -0
  9. package/agentPullCommand-O2MTUAFR.js +122 -0
  10. package/agentRecordCommands-MH2JKFHS.js +94 -0
  11. package/agentRunCommand-4KH6MIZR.js +110 -0
  12. package/agentRunControl-K4VKNEHF.js +57 -0
  13. package/agentRuntimeLocal-SKHJUWSS.js +104 -0
  14. package/agentSlice-3WXXN4VK.js +42 -0
  15. package/authCommand-PXFX6JDT.js +581 -0
  16. package/authCommands-356AYWEK.js +35 -0
  17. package/chunk-2EISRLRC.js +238 -0
  18. package/chunk-2FTTDCD4.js +675 -0
  19. package/chunk-2K2ECKSG.js +222 -0
  20. package/chunk-2PUGVR6E.js +19 -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-3TZDXYSF.js +71 -0
  25. package/chunk-3WYQEUBI.js +34 -0
  26. package/chunk-4CQLVGRV.js +50 -0
  27. package/chunk-4IJYA27C.js +342 -0
  28. package/chunk-4K2KKCSD.js +577 -0
  29. package/chunk-4SN6J65J.js +38 -0
  30. package/chunk-4VNS5WPM.js +42 -0
  31. package/chunk-4ZDM73SD.js +34 -0
  32. package/chunk-5CS33IBL.js +301 -0
  33. package/chunk-5KLGBAAR.js +386 -0
  34. package/chunk-5MIDPSSK.js +206 -0
  35. package/chunk-5MMAK75Q.js +15 -0
  36. package/chunk-5PJ3VWCS.js +360 -0
  37. package/chunk-63SLEOLK.js +175 -0
  38. package/chunk-63W5N6P3.js +150 -0
  39. package/chunk-6GANEXVO.js +231 -0
  40. package/chunk-6HYVJV7B.js +102 -0
  41. package/chunk-6WD3OOJS.js +20 -0
  42. package/chunk-7OOXPE3N.js +628 -0
  43. package/chunk-7QRKCBOP.js +1078 -0
  44. package/chunk-ATNTHIZI.js +13 -0
  45. package/chunk-AUQ747NZ.js +902 -0
  46. package/chunk-AVMKZHBC.js +85 -0
  47. package/chunk-AZPCASRE.js +36 -0
  48. package/chunk-BBYVOSU2.js +792 -0
  49. package/chunk-C3RUNRHT.js +51 -0
  50. package/chunk-CF2WZF4N.js +134 -0
  51. package/chunk-CF7PE763.js +10 -0
  52. package/chunk-CKOJQDKR.js +198 -0
  53. package/chunk-COMXDWNM.js +807 -0
  54. package/chunk-CPB2YM4D.js +171 -0
  55. package/chunk-CWMSB67P.js +34 -0
  56. package/chunk-DCOA4QSN.js +105 -0
  57. package/chunk-DFFIZ25G.js +30 -0
  58. package/chunk-DWLEOOGR.js +8 -0
  59. package/chunk-DZ3XJVET.js +231 -0
  60. package/chunk-EHLHSX7R.js +1433 -0
  61. package/chunk-ELRRLDWI.js +478 -0
  62. package/chunk-EXTIQUCI.js +482 -0
  63. package/chunk-EYEEHCU4.js +3066 -0
  64. package/chunk-G3SUCT4W.js +8 -0
  65. package/chunk-G43KEVSC.js +1447 -0
  66. package/chunk-GAKEBQD6.js +30 -0
  67. package/chunk-GBRG75BQ.js +86 -0
  68. package/chunk-GG4AJPSR.js +191 -0
  69. package/chunk-H33743XH.js +25 -0
  70. package/chunk-HNMXYYJR.js +12 -0
  71. package/chunk-I42VC5KR.js +15 -0
  72. package/chunk-IDZTNRP2.js +85 -0
  73. package/chunk-ISNCLGUZ.js +146 -0
  74. package/chunk-IWX4UW2E.js +548 -0
  75. package/chunk-JBTJAPUF.js +35 -0
  76. package/chunk-JEXVIMYZ.js +55 -0
  77. package/chunk-JRKKFRAV.js +537 -0
  78. package/chunk-JZPBVBIY.js +94 -0
  79. package/chunk-KKY4B2Q2.js +21 -0
  80. package/chunk-KOCA5FCS.js +4750 -0
  81. package/chunk-KQHGZWSV.js +63 -0
  82. package/chunk-KTVVPRJS.js +138 -0
  83. package/chunk-KUG52IAP.js +8 -0
  84. package/chunk-KX6YBIHG.js +8 -0
  85. package/chunk-LARL2V6G.js +9017 -0
  86. package/chunk-LCBAMY2M.js +60 -0
  87. package/chunk-LM6IYQ3F.js +16 -0
  88. package/chunk-M76ECQRD.js +13658 -0
  89. package/chunk-MGOJ5R6J.js +113 -0
  90. package/chunk-MKMWT7SA.js +27196 -0
  91. package/chunk-MRC4Q34M.js +188 -0
  92. package/chunk-OLZBQWZU.js +6 -0
  93. package/chunk-OPZYGHUC.js +89 -0
  94. package/chunk-OWOHNGCN.js +50 -0
  95. package/chunk-PAKN26FP.js +239 -0
  96. package/chunk-PCWC3JTN.js +91 -0
  97. package/chunk-PG5PNA7Y.js +939 -0
  98. package/chunk-Q2YZULBH.js +104 -0
  99. package/chunk-QSJ3HFEF.js +8 -0
  100. package/chunk-QYXLLLGL.js +4519 -0
  101. package/chunk-ROWQEJRP.js +139 -0
  102. package/chunk-S7Z2HMCN.js +25 -0
  103. package/chunk-SBR32ZZS.js +1901 -0
  104. package/chunk-SH2CFQOH.js +3391 -0
  105. package/chunk-SL35K7AH.js +226 -0
  106. package/chunk-TILFE6LV.js +381 -0
  107. package/chunk-TSS3XJY4.js +2052 -0
  108. package/chunk-U4TRT5V4.js +246 -0
  109. package/chunk-U6VC4MU4.js +8 -0
  110. package/chunk-UAD2WT54.js +64 -0
  111. package/chunk-UUJDGGAK.js +421 -0
  112. package/chunk-VF4K2QE6.js +21 -0
  113. package/chunk-VHBWHNVT.js +59 -0
  114. package/chunk-VIDPVFP3.js +20 -0
  115. package/chunk-VP4WJWKW.js +8882 -0
  116. package/chunk-W4NVOSFF.js +37 -0
  117. package/chunk-WKM6FH35.js +190 -0
  118. package/chunk-WWC7I6TA.js +8 -0
  119. package/chunk-X7W4TNB4.js +1550 -0
  120. package/chunk-XE635NI4.js +1948 -0
  121. package/chunk-XKIMRZO2.js +221 -0
  122. package/chunk-XS466O7S.js +933 -0
  123. package/chunk-Y5GCAMGP.js +9 -0
  124. package/chunk-YBWOP46I.js +3272 -0
  125. package/chunk-YPRZSPF3.js +148 -0
  126. package/chunk-YYUCRDOK.js +69 -0
  127. package/chunk-Z4NR32XR.js +50 -0
  128. package/chunk-ZIG5LJ7X.js +24765 -0
  129. package/chunk-ZNFJWEN4.js +56 -0
  130. package/chunk-ZQ2UM4KG.js +2878 -0
  131. package/cliExecutor-DNE7TCC4.js +36 -0
  132. package/clipboardy-BVE3LVEH.js +12001 -0
  133. package/createAgentAutomationAction-63OIP6X5.js +866 -0
  134. package/createDialogAction-ZLYZDYBB.js +54 -0
  135. package/createPageAction-AL5FSDCK.js +171 -0
  136. package/db-HCJ5PRB5.js +271 -0
  137. package/dbSlice-PR44QPXY.js +60 -0
  138. package/deleteFile-4SKGPHOZ.js +41 -0
  139. package/dialogCommands-F6YI5742.js +63 -0
  140. package/dialogSlice-JSBNZRLR.js +148 -0
  141. package/docCreateCommands-4CTO7ERT.js +219 -0
  142. package/docDeleteCommands-VBWERDRG.js +180 -0
  143. package/docReadCommands-KNP4MFYB.js +133 -0
  144. package/docStore-ADP5VYY4.js +98 -0
  145. package/docUpdateCommands-4BCBJQHA.js +317 -0
  146. package/fetchMessages-U6ZHN56A.js +17 -0
  147. package/getPricing-3E6UNPKL.js +30 -0
  148. package/handleSendMessageAction-IJDQ6ARA.js +185 -0
  149. package/index.js +188 -112943
  150. package/lib-FYYBQIXS.js +19839 -0
  151. package/localDialogRead-Z5UTAJPU.js +26 -0
  152. package/localFirstLog-DHNOY2NA.js +19 -0
  153. package/localRuntimeAuthority-TEGCOWX4.js +471 -0
  154. package/localRuntimeDb-LGDF6FQP.js +12 -0
  155. package/machineCommands-EA3M4XTN.js +779 -0
  156. package/machineInfo-M6KB6HZN.js +10 -0
  157. package/machineWsRunDispatch-NAPKE5ZA.js +110 -0
  158. package/memoryCommands-O4MIPIWQ.js +476 -0
  159. package/models-4OPOOLFS.js +9 -0
  160. package/offlineMarxistsAgentCommand-BCPJITJL.js +242 -0
  161. package/package.json +3 -25
  162. package/read-RIJCIVKX.js +17 -0
  163. package/readDocTool-GZD2N3LO.js +16 -0
  164. package/readlineWorkspace-KMWT4T4S.js +5509 -0
  165. package/removeDialogAgentAction-GJQJNDW6.js +73 -0
  166. package/runAgentClientLoop-U5Q6NDTJ.js +291 -0
  167. package/runtimeDoctorCommands-LRHLPDRC.js +289 -0
  168. package/setDialogExtraReferencesAction-M7OQG54N.js +60 -0
  169. package/setPrimaryDialogAgentAction-46UNFJDL.js +80 -0
  170. package/settingSlice-FVUUH4JA.js +199 -0
  171. package/skillSummaryMarker-42HKSXYY.js +9 -0
  172. package/slateToRenderMarkdown-Y5IYN73U.js +7 -0
  173. package/slateUtils-2M7MUTWX.js +19 -0
  174. package/spaceCommands-E2CFRPZJ.js +454 -0
  175. package/spaceSlice-L3R6IMXE.js +147 -0
  176. package/streamAgentChatTurn-UBDAOQWE.js +4528 -0
  177. package/tableCommands-GOFP7QKA.js +1286 -0
  178. package/toolApiClient-QI3YBNWB.js +26 -0
  179. package/tools-TMJXZTCA.js +85 -0
  180. package/tuiSummaryLlmCaller-RV3THLZF.js +78 -0
  181. package/understanding-GQKNDDWM.js +271 -0
  182. package/updateCommands-VOSPKXFF.js +31 -0
  183. package/updateDialogTitleAction-ZTWRDXI2.js +188 -0
@@ -0,0 +1,4528 @@
1
+ import {
2
+ applyModelLayerOverride,
3
+ buildLinkedSpacesSection,
4
+ buildSpaceContextLayer
5
+ } from "./chunk-SL35K7AH.js";
6
+ import {
7
+ buildStaticUserPolicyContext,
8
+ resolveSpaceContextPreloadPlan
9
+ } from "./chunk-6GANEXVO.js";
10
+ import {
11
+ getFinalPrice,
12
+ getModelPricing,
13
+ getPrices,
14
+ hasExplicitAgentPricing
15
+ } from "./chunk-YPRZSPF3.js";
16
+ import {
17
+ buildCliPrompt
18
+ } from "./chunk-ATNTHIZI.js";
19
+ import {
20
+ INVALID_TOOL_ARGS_REPLACEMENT,
21
+ buildInvalidToolCallSelfHealResult,
22
+ filterAndCleanMessages,
23
+ handleToolCalls,
24
+ parseApiError,
25
+ parseToolCallArguments,
26
+ persistToolMessages,
27
+ readStreamChunk,
28
+ sanitizeOutboundResponsesInput,
29
+ sendOpenAICompletionsRequest,
30
+ updateTotalUsage
31
+ } from "./chunk-XE635NI4.js";
32
+ import "./chunk-JEXVIMYZ.js";
33
+ import {
34
+ prepareTools
35
+ } from "./chunk-CPB2YM4D.js";
36
+ import {
37
+ getPublicImageAgentDefaultProfile,
38
+ getPublicImageAgentMode
39
+ } from "./chunk-VIDPVFP3.js";
40
+ import {
41
+ fetchReferenceContents,
42
+ generateRequestBody,
43
+ mergeReferences,
44
+ performFetchRequest,
45
+ performServerProxyFetchWithRetry,
46
+ resolveAgentCallPlan,
47
+ resolveClientWire,
48
+ resolveReferenceAssets,
49
+ resolveToolsFromKeys
50
+ } from "./chunk-SBR32ZZS.js";
51
+ import "./chunk-KKY4B2Q2.js";
52
+ import "./chunk-C3RUNRHT.js";
53
+ import {
54
+ TOOL_PACKS,
55
+ applyDefaultWebToolPacks,
56
+ applyDisabledTools,
57
+ createSSEParser,
58
+ expandEnabledPacks,
59
+ getAllToolRuns,
60
+ shouldBlockForGptPro
61
+ } from "./chunk-MKMWT7SA.js";
62
+ import "./chunk-GAKEBQD6.js";
63
+ import "./chunk-KQHGZWSV.js";
64
+ import "./chunk-XKIMRZO2.js";
65
+ import "./chunk-3LY4F7SV.js";
66
+ import {
67
+ extractCategorizedMentions
68
+ } from "./chunk-VP4WJWKW.js";
69
+ import "./chunk-63W5N6P3.js";
70
+ import {
71
+ getDocState
72
+ } from "./chunk-UUJDGGAK.js";
73
+ import "./chunk-PG5PNA7Y.js";
74
+ import "./chunk-ZQ2UM4KG.js";
75
+ import "./chunk-Q2YZULBH.js";
76
+ import {
77
+ PERSONALIZATION_DIALOG_CATEGORY,
78
+ addToolMessage,
79
+ addUserMessage,
80
+ buildPersonalizationDialogPolicyContext,
81
+ estimateMissingUsage,
82
+ estimateTokenCount,
83
+ extractReferenceKeysFromMessage,
84
+ finalizeTransientMessageOnError,
85
+ getModelContextWindow,
86
+ getModelInfo,
87
+ messageStreamEnd,
88
+ messageStreaming,
89
+ planContextUsage,
90
+ prepareAndPersistUserMessage,
91
+ removeTransientMessage,
92
+ selectAllMsgs,
93
+ selectCurrentDialogConfig,
94
+ selectCurrentSpaceId,
95
+ selectCurrentTable,
96
+ selectCurrentUserBalance,
97
+ selectDialogConfigByKey,
98
+ selectTableRows,
99
+ selectViewMode,
100
+ updateTokens
101
+ } from "./chunk-ZIG5LJ7X.js";
102
+ import "./chunk-4ZDM73SD.js";
103
+ import "./chunk-MRC4Q34M.js";
104
+ import "./chunk-PCWC3JTN.js";
105
+ import "./chunk-CWMSB67P.js";
106
+ import "./chunk-4K2KKCSD.js";
107
+ import {
108
+ createCliChatTurnStream,
109
+ getCliChatSession,
110
+ startCliChatSession
111
+ } from "./chunk-KTVVPRJS.js";
112
+ import "./chunk-Z4NR32XR.js";
113
+ import "./chunk-M76ECQRD.js";
114
+ import "./chunk-YYUCRDOK.js";
115
+ import "./chunk-MGOJ5R6J.js";
116
+ import "./chunk-UAD2WT54.js";
117
+ import "./chunk-DCOA4QSN.js";
118
+ import {
119
+ assertDesktopAgentRuntimeTurnBodyHasNoRawSecrets,
120
+ buildDesktopAgentRuntimeAgentConfigSnapshot,
121
+ buildDesktopAgentRuntimeDialogHistorySnapshot
122
+ } from "./chunk-TILFE6LV.js";
123
+ import {
124
+ resolveAgentImageInputSupport
125
+ } from "./chunk-XS466O7S.js";
126
+ import "./chunk-OPZYGHUC.js";
127
+ import "./chunk-PAKN26FP.js";
128
+ import {
129
+ extractImagePartsFromResponseOutput,
130
+ extractTextFromResponseOutput,
131
+ toResponsesTools
132
+ } from "./chunk-JRKKFRAV.js";
133
+ import {
134
+ canonicalizeToolNames,
135
+ prioritizeToolNames,
136
+ resolveRuntimeToolSurfaceForAgent
137
+ } from "./chunk-AUQ747NZ.js";
138
+ import "./chunk-5MMAK75Q.js";
139
+ import {
140
+ getApiEndpoint,
141
+ getModelConfig,
142
+ getProviderByModelName
143
+ } from "./chunk-BBYVOSU2.js";
144
+ import "./chunk-5CS33IBL.js";
145
+ import "./chunk-JZPBVBIY.js";
146
+ import "./chunk-IWX4UW2E.js";
147
+ import {
148
+ resolveToolBaseUrl
149
+ } from "./chunk-5MIDPSSK.js";
150
+ import {
151
+ extractCustomId
152
+ } from "./chunk-DFFIZ25G.js";
153
+ import {
154
+ addActiveController,
155
+ clearPendingUserInputQueue,
156
+ dequeueUserInput,
157
+ removeActiveController,
158
+ selectActiveControllers,
159
+ selectPendingFiles,
160
+ selectPendingUserInputQueue,
161
+ tokenUsageLiveUpdate
162
+ } from "./chunk-3ASDTTEI.js";
163
+ import "./chunk-DWLEOOGR.js";
164
+ import {
165
+ toErrorMessage
166
+ } from "./chunk-HNMXYYJR.js";
167
+ import "./chunk-63SLEOLK.js";
168
+ import {
169
+ selectAiRecentContentLimit,
170
+ selectCurrentServer,
171
+ selectGlobalPrompt,
172
+ selectKnowledgeCaptureLevel,
173
+ selectMaxExecutionTime,
174
+ selectSpaceContextLevel,
175
+ selectUserTonePreset
176
+ } from "./chunk-TSS3XJY4.js";
177
+ import "./chunk-Y5GCAMGP.js";
178
+ import {
179
+ patch,
180
+ read,
181
+ selectById,
182
+ write
183
+ } from "./chunk-COMXDWNM.js";
184
+ import "./chunk-AZPCASRE.js";
185
+ import "./chunk-2EISRLRC.js";
186
+ import {
187
+ asRecordOrEmpty
188
+ } from "./chunk-KX6YBIHG.js";
189
+ import {
190
+ createDialogMessageKeyAndId,
191
+ dialogMessageKey
192
+ } from "./chunk-SH2CFQOH.js";
193
+ import {
194
+ asNonEmptyStringArray
195
+ } from "./chunk-I42VC5KR.js";
196
+ import {
197
+ asOptionalFiniteNumber
198
+ } from "./chunk-WWC7I6TA.js";
199
+ import "./chunk-QSJ3HFEF.js";
200
+ import "./chunk-ELRRLDWI.js";
201
+ import {
202
+ selectIdentityToken,
203
+ selectIdentityUser,
204
+ selectIdentityUserId,
205
+ selectRuntimeCurrentServer
206
+ } from "./chunk-EYEEHCU4.js";
207
+ import {
208
+ getIsDesktopApp,
209
+ isAbortError
210
+ } from "./chunk-QYXLLLGL.js";
211
+ import "./chunk-GBRG75BQ.js";
212
+ import "./chunk-4SN6J65J.js";
213
+ import "./chunk-LCBAMY2M.js";
214
+ import {
215
+ asTrimmedString
216
+ } from "./chunk-3EUW3WEO.js";
217
+ import "./chunk-U6VC4MU4.js";
218
+ import "./chunk-CF7PE763.js";
219
+ import {
220
+ asOptionalTrimmedString
221
+ } from "./chunk-G3SUCT4W.js";
222
+ import {
223
+ isRecord
224
+ } from "./chunk-KUG52IAP.js";
225
+ import "./chunk-4VNS5WPM.js";
226
+
227
+ // packages/ai/agent/isVoiceModel.ts
228
+ function isVoiceModel(model, provider) {
229
+ const providerLower = String(provider || "").toLowerCase();
230
+ const modelLower = String(model || "").toLowerCase();
231
+ if (providerLower === "google" && modelLower.includes("live")) return true;
232
+ if (modelLower.includes("live-preview")) return true;
233
+ if (modelLower.includes("live-001")) return true;
234
+ if (modelLower.includes("native-audio")) return true;
235
+ return false;
236
+ }
237
+
238
+ // packages/ai/agent/isLiveAudioOnlyAgent.ts
239
+ function isLiveAudioOnlyAgent(agent) {
240
+ if (agent.defaultInteractionMode !== "live_audio") return false;
241
+ return isVoiceModel(agent.model, agent.provider);
242
+ }
243
+
244
+ // packages/ai/agent/projectDesktopToolUiContent.ts
245
+ var DESKTOP_TOOL_UI_CONTENT_MAX_CHARS = 48e3;
246
+ function clipUiText(value, max = DESKTOP_TOOL_UI_CONTENT_MAX_CHARS) {
247
+ if (value.length <= max) return value;
248
+ return `${value.slice(0, Math.max(0, max - 20))}
249
+ \u2026[truncated for UI]`;
250
+ }
251
+ function tryParseJsonRecord(text) {
252
+ const trimmed = text.trim();
253
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
254
+ try {
255
+ const parsed = JSON.parse(trimmed);
256
+ return isRecord(parsed) ? parsed : null;
257
+ } catch {
258
+ return null;
259
+ }
260
+ }
261
+ function parseShellToolTextContent(content) {
262
+ const text = content ?? "";
263
+ if (!text.trim()) return { stdout: "", stderr: "" };
264
+ const exitMatch = text.match(/(?:^|\n)exitCode:\s*(-?\d+)\s*$/);
265
+ const exitCode = exitMatch ? Number(exitMatch[1]) : void 0;
266
+ const body = (exitMatch ? text.slice(0, exitMatch.index) : text).replace(
267
+ /\s+$/,
268
+ ""
269
+ );
270
+ let stdout = "";
271
+ let stderr = "";
272
+ if (body.startsWith("stdout:\n") || body.includes("\nstdout:\n")) {
273
+ const afterStdout = body.replace(/^[\s\S]*?stdout:\n/, "");
274
+ if (afterStdout.includes("\n\nstderr:\n")) {
275
+ const [out, err] = afterStdout.split("\n\nstderr:\n");
276
+ stdout = out ?? "";
277
+ stderr = err ?? "";
278
+ } else if (afterStdout.startsWith("stderr:\n")) {
279
+ stderr = afterStdout.slice("stderr:\n".length);
280
+ } else {
281
+ stdout = afterStdout;
282
+ }
283
+ } else if (body.startsWith("stderr:\n") || body.includes("\nstderr:\n")) {
284
+ stderr = body.replace(/^[\s\S]*?stderr:\n/, "");
285
+ } else {
286
+ stdout = body;
287
+ }
288
+ return {
289
+ stdout,
290
+ stderr,
291
+ ...typeof exitCode === "number" && Number.isFinite(exitCode) ? { exitCode } : {}
292
+ };
293
+ }
294
+ function resolveShellCommand(metadata, argumentsPreview) {
295
+ return asOptionalTrimmedString(metadata.command) || asOptionalTrimmedString(metadata.cmd) || asOptionalTrimmedString(argumentsPreview) || "";
296
+ }
297
+ function projectDesktopToolUiContent(args) {
298
+ const toolName = asOptionalTrimmedString(args.toolName) || "tool";
299
+ const metadata = isRecord(args.metadata) ? args.metadata : {};
300
+ const rawContent = typeof args.content === "string" ? args.content : typeof args.summary === "string" ? args.summary : typeof args.message === "string" ? args.message : "";
301
+ if (toolName === "execShell") {
302
+ const existing = tryParseJsonRecord(rawContent);
303
+ if (existing && (typeof existing.stdout === "string" || typeof existing.command === "string" || typeof existing.stderr === "string")) {
304
+ const command2 = asOptionalTrimmedString(existing.command) || resolveShellCommand(metadata, args.argumentsPreview);
305
+ return JSON.stringify({
306
+ ...existing,
307
+ command: command2,
308
+ cwd: asOptionalTrimmedString(existing.cwd) || asOptionalTrimmedString(metadata.cwd) || null,
309
+ exitCode: asOptionalFiniteNumber(existing.exitCode) ?? asOptionalFiniteNumber(metadata.exitCode)
310
+ });
311
+ }
312
+ const parsed = parseShellToolTextContent(rawContent);
313
+ const command = resolveShellCommand(metadata, args.argumentsPreview);
314
+ return JSON.stringify({
315
+ command,
316
+ cwd: asOptionalTrimmedString(metadata.cwd) || null,
317
+ stdout: clipUiText(parsed.stdout),
318
+ stderr: clipUiText(parsed.stderr),
319
+ exitCode: asOptionalFiniteNumber(metadata.exitCode) ?? parsed.exitCode,
320
+ timedOut: metadata.timedOut === true,
321
+ blocked: metadata.blocked === true
322
+ });
323
+ }
324
+ if (toolName === "readFile" || toolName === "read_file") {
325
+ const filePath = asOptionalTrimmedString(metadata.path) || asOptionalTrimmedString(metadata.filePath) || asOptionalTrimmedString(metadata.file_path) || asOptionalTrimmedString(args.argumentsPreview) || "";
326
+ const body = typeof args.content === "string" && args.content || typeof args.summary === "string" && args.summary || typeof args.message === "string" && args.message || "";
327
+ return JSON.stringify({
328
+ filePath,
329
+ content: clipUiText(body),
330
+ ...asOptionalFiniteNumber(metadata.startLine) != null ? { startLine: asOptionalFiniteNumber(metadata.startLine) } : {},
331
+ ...asOptionalFiniteNumber(metadata.endLine) != null ? { endLine: asOptionalFiniteNumber(metadata.endLine) } : {},
332
+ ...asOptionalFiniteNumber(metadata.totalLines) != null ? { totalLines: asOptionalFiniteNumber(metadata.totalLines) } : {},
333
+ ...metadata.truncated === true ? { truncated: true } : {}
334
+ });
335
+ }
336
+ const preferred = typeof args.content === "string" && args.content || typeof args.summary === "string" && args.summary || typeof args.message === "string" && args.message || "";
337
+ return clipUiText(preferred);
338
+ }
339
+
340
+ // packages/ai/agent/desktopTurnSegments.ts
341
+ function attachToolCallIdToSegment(segments, callId) {
342
+ if (!segments || segments.length === 0) return;
343
+ const current = segments[segments.length - 1];
344
+ if (!current.toolCallIds) {
345
+ current.toolCallIds = [];
346
+ }
347
+ current.toolCallIds.push(callId);
348
+ }
349
+ function resolveSegmentToolCalls(toolCallIds, turnMessages) {
350
+ if (!toolCallIds || toolCallIds.length === 0 || !Array.isArray(turnMessages) || turnMessages.length === 0) {
351
+ return [];
352
+ }
353
+ const callMap = /* @__PURE__ */ new Map();
354
+ for (const msg of turnMessages) {
355
+ if (Array.isArray(msg?.tool_calls)) {
356
+ for (const tc of msg.tool_calls) {
357
+ if (tc && typeof tc.id === "string") {
358
+ callMap.set(tc.id, tc);
359
+ }
360
+ }
361
+ }
362
+ }
363
+ const resolved = [];
364
+ for (const id of toolCallIds) {
365
+ const tc = callMap.get(id);
366
+ if (tc) {
367
+ resolved.push(tc);
368
+ }
369
+ }
370
+ return resolved;
371
+ }
372
+ function buildMinimalToolCallsFromIds(toolCallIds, toolNameById) {
373
+ if (!toolCallIds || toolCallIds.length === 0) return [];
374
+ const result = [];
375
+ for (const id of toolCallIds) {
376
+ if (!toolNameById.has(id)) continue;
377
+ const name = toolNameById.get(id) || "tool";
378
+ result.push({ id, type: "function", function: { name, arguments: "{}" } });
379
+ }
380
+ return result;
381
+ }
382
+ function selectPersistableFinalizedSegments(segments) {
383
+ if (!Array.isArray(segments)) return [];
384
+ return segments.filter(
385
+ (segment) => segment.finalized && (segment.content.length > 0 || segment.toolCallIds && segment.toolCallIds.length > 0)
386
+ );
387
+ }
388
+
389
+ // packages/chat/queue/chatQueueLifecycleActions.ts
390
+ function runChatQueueTurnEnd(payload) {
391
+ return (_dispatch, _getState, extra) => {
392
+ const adapter = extra?.chatQueueAdapter;
393
+ if (!adapter) return;
394
+ void adapter.notifyTurnEnd(payload.dialogKey, {
395
+ ok: payload.ok,
396
+ aborted: payload.aborted
397
+ });
398
+ };
399
+ }
400
+
401
+ // packages/ai/agent/getFullChatContextKeys.ts
402
+ var difference = (arrA, arrB) => {
403
+ if (!arrA.length) return [];
404
+ if (!arrB.length) return [...arrA];
405
+ const exclude = new Set(arrB);
406
+ return arrA.filter((item) => !exclude.has(item));
407
+ };
408
+ var getFullChatContextKeys = async (state, dispatch, agentConfig, userInput, dialogConfig) => {
409
+ const msgs = selectAllMsgs(
410
+ state,
411
+ dialogConfig?.dbKey ? extractCustomId(dialogConfig.dbKey) : dialogConfig?.id
412
+ );
413
+ const botInstructionKeys = /* @__PURE__ */ new Set();
414
+ const botKnowledgeKeys = /* @__PURE__ */ new Set();
415
+ if (Array.isArray(agentConfig.references)) {
416
+ for (const ref of agentConfig.references) {
417
+ if (!ref?.dbKey) continue;
418
+ if (ref.type === "instruction") {
419
+ botInstructionKeys.add(ref.dbKey);
420
+ } else {
421
+ botKnowledgeKeys.add(ref.dbKey);
422
+ }
423
+ }
424
+ }
425
+ const currentInputKeys = /* @__PURE__ */ new Set();
426
+ if (Array.isArray(userInput)) {
427
+ for (const part of userInput) {
428
+ if (part?.pageKey) currentInputKeys.add(part.pageKey);
429
+ if (part?.dialogKey) currentInputKeys.add(part.dialogKey);
430
+ }
431
+ }
432
+ const historyKeys = /* @__PURE__ */ new Set();
433
+ const savedKeys = dialogConfig?.referenceKeys;
434
+ if (Array.isArray(savedKeys)) {
435
+ savedKeys.forEach((k) => historyKeys.add(k));
436
+ }
437
+ const scanContentParts = (msg) => {
438
+ if (!msg) return;
439
+ for (const key of extractReferenceKeysFromMessage(msg)) {
440
+ historyKeys.add(key);
441
+ }
442
+ };
443
+ if (msgs && msgs.length > 0) {
444
+ const summarizedBeforeId = dialogConfig?.summarizedBeforeId;
445
+ if (!summarizedBeforeId) {
446
+ for (const msg of msgs) scanContentParts(msg);
447
+ } else {
448
+ let foundMarker = false;
449
+ let startScan = false;
450
+ for (const msg of msgs) {
451
+ if (!startScan) {
452
+ if (msg.id === summarizedBeforeId) {
453
+ foundMarker = true;
454
+ startScan = true;
455
+ }
456
+ continue;
457
+ }
458
+ scanContentParts(msg);
459
+ }
460
+ if (!foundMarker) {
461
+ console.warn(`[getFullChatContextKeys] marker ${summarizedBeforeId} not found, scanning all`);
462
+ for (const msg of msgs) scanContentParts(msg);
463
+ }
464
+ }
465
+ }
466
+ return {
467
+ botInstructionKeys,
468
+ currentInputKeys,
469
+ historyKeys,
470
+ botKnowledgeKeys
471
+ };
472
+ };
473
+ var deduplicateContextKeys = (keys) => {
474
+ const {
475
+ botInstructionKeys,
476
+ currentInputKeys,
477
+ historyKeys,
478
+ botKnowledgeKeys
479
+ } = keys;
480
+ const finalBotInstructionKeys = Array.from(botInstructionKeys);
481
+ const finalCurrentInputKeys = difference(
482
+ Array.from(currentInputKeys),
483
+ finalBotInstructionKeys
484
+ );
485
+ const finalHistoryKeys = difference(Array.from(historyKeys), [
486
+ ...finalBotInstructionKeys,
487
+ ...finalCurrentInputKeys
488
+ ]);
489
+ const finalBotKnowledgeKeys = difference(Array.from(botKnowledgeKeys), [
490
+ ...finalBotInstructionKeys,
491
+ ...finalCurrentInputKeys,
492
+ ...finalHistoryKeys
493
+ ]);
494
+ return {
495
+ botInstructionsContext: finalBotInstructionKeys,
496
+ currentInputContext: finalCurrentInputKeys,
497
+ historyContext: finalHistoryKeys,
498
+ botKnowledgeContext: finalBotKnowledgeKeys
499
+ };
500
+ };
501
+
502
+ // packages/ai/chat/streamRetry.ts
503
+ var MAX_INITIAL_STREAM_RETRIES = 1;
504
+ var DEFAULT_INITIAL_STREAM_RETRY_AFTER_MS = 1500;
505
+ var normalizeInitialStreamRetryAfterMs = (value) => {
506
+ const parsed = Number(value);
507
+ return Number.isFinite(parsed) && parsed >= 0 ? Math.round(parsed) : DEFAULT_INITIAL_STREAM_RETRY_AFTER_MS;
508
+ };
509
+ var isRetryableInitialStreamError = (error) => {
510
+ if (!error || isAbortError(error)) return false;
511
+ const message = typeof error?.message === "string" ? error.message : String(error);
512
+ return /ECONNRESET|ECONNREFUSED|EPIPE|socket hang up|network error|failed to fetch|fetch failed|load failed|connection closed|stream ended before first visible delta|response stream ended before first visible delta|模型响应流 .* 秒内没有返回新内容/i.test(
513
+ message
514
+ );
515
+ };
516
+ var waitForInitialStreamRetry = async (retryAfterMs, signal) => {
517
+ if (signal?.aborted) {
518
+ const abortError = new Error("Aborted");
519
+ abortError.name = "AbortError";
520
+ throw abortError;
521
+ }
522
+ await new Promise((resolve, reject) => {
523
+ const onAbort = () => {
524
+ clearTimeout(timeoutId);
525
+ signal?.removeEventListener("abort", onAbort);
526
+ const abortError = new Error("Aborted");
527
+ abortError.name = "AbortError";
528
+ reject(abortError);
529
+ };
530
+ const timeoutId = setTimeout(() => {
531
+ signal?.removeEventListener("abort", onAbort);
532
+ resolve();
533
+ }, normalizeInitialStreamRetryAfterMs(retryAfterMs));
534
+ signal?.addEventListener("abort", onAbort, { once: true });
535
+ });
536
+ };
537
+
538
+ // packages/ai/chat/sendOpenAIResponseRequest.ts
539
+ var seg = (txt) => [{ type: "text", text: txt ?? "" }];
540
+ var shouldEnableBuiltInImageGeneration = (agentConfig) => String(agentConfig?.provider || "").toLowerCase() === "openai" && !getModelInfo(String(agentConfig?.model || ""))?.hasImageOutput && !!agentConfig?.imageConfig?.enabled;
541
+ var withImageGenerationStage = (messageMetadata, stage) => {
542
+ const previousState = messageMetadata?.imageGenerationState;
543
+ if (previousState?.kind !== "image_generation") {
544
+ return messageMetadata;
545
+ }
546
+ return {
547
+ ...messageMetadata ?? {},
548
+ imageGenerationState: {
549
+ ...previousState,
550
+ stage
551
+ }
552
+ };
553
+ };
554
+ var shouldShowImageSavingState = (contentBuffer) => contentBuffer.some((part) => part?.type === "image_url") && !contentBuffer.some(
555
+ (part) => part?.type === "text" && typeof part.text === "string" && part.text.trim()
556
+ );
557
+ var logQuickChatPerfStage = (startedAt, stage, details) => {
558
+ if (!startedAt) return;
559
+ const now = typeof performance !== "undefined" ? performance.now() : Date.now();
560
+ console.info("[QuickChatPerf]", {
561
+ stage,
562
+ elapsedMs: now - startedAt,
563
+ ...typeof performance !== "undefined" ? { atMs: now } : {},
564
+ ...details ?? {}
565
+ });
566
+ };
567
+ var safeCancel = async (reader) => {
568
+ if (!reader) return;
569
+ try {
570
+ await reader.cancel();
571
+ } catch {
572
+ }
573
+ };
574
+ var ensureToolCall = (state, key, partial) => {
575
+ let toolCall = state.assistantToolCalls.find((call) => call.id === key);
576
+ if (!toolCall) {
577
+ toolCall = {
578
+ id: key,
579
+ type: "function",
580
+ function: { name: "", arguments: "" }
581
+ };
582
+ state.assistantToolCalls.push(toolCall);
583
+ }
584
+ if (partial.id) toolCall.id = partial.id;
585
+ if (partial.function?.name) toolCall.function.name = partial.function.name;
586
+ if (typeof partial.function?.arguments === "string") {
587
+ toolCall.function.arguments = partial.function.arguments;
588
+ }
589
+ return toolCall;
590
+ };
591
+ var extractTextFromOutputItem = (item) => {
592
+ if (item?.type !== "message" || !Array.isArray(item.content)) return "";
593
+ return item.content.filter(
594
+ (content) => content?.type === "output_text" && typeof content.text === "string"
595
+ ).map((content) => content.text).join("");
596
+ };
597
+ var getStreamErrorMessage = (event) => {
598
+ const directMessage = asOptionalTrimmedString(event?.message);
599
+ if (directMessage) return directMessage;
600
+ const nestedMessage = asOptionalTrimmedString(event?.error?.message) ?? asOptionalTrimmedString(event?.error?.msg);
601
+ if (nestedMessage) return nestedMessage;
602
+ const nestedCode = asOptionalTrimmedString(event?.error?.code) ?? asOptionalTrimmedString(event?.code);
603
+ if (nestedCode) return nestedCode;
604
+ const nestedType = asOptionalTrimmedString(event?.error?.type);
605
+ if (nestedType) return nestedType;
606
+ const eventType = asOptionalTrimmedString(event?.type);
607
+ if (eventType && eventType !== "error") return eventType;
608
+ return "Unknown error";
609
+ };
610
+ var sendOpenAIResponseRequest = async ({
611
+ bodyData,
612
+ agentConfig,
613
+ thunkApi,
614
+ dialogKey,
615
+ parentMessageId,
616
+ messageMetadata,
617
+ quickChatPerfStartedAt
618
+ }) => {
619
+ const { dispatch, getState, signal: thunkSignal } = thunkApi;
620
+ const dialogId = extractCustomId(dialogKey);
621
+ const controller = new AbortController();
622
+ thunkSignal.addEventListener("abort", () => controller.abort());
623
+ const signal = controller.signal;
624
+ const streamSpaceId = selectCurrentSpaceId(getState()) || void 0;
625
+ let messageId;
626
+ let msgKey;
627
+ if (parentMessageId) {
628
+ messageId = parentMessageId;
629
+ msgKey = `msg:${dialogId}:${messageId}`;
630
+ } else {
631
+ const newIds = createDialogMessageKeyAndId(dialogId);
632
+ messageId = newIds.messageId;
633
+ msgKey = newIds.key;
634
+ }
635
+ dispatch(addActiveController({ messageId, controller, dialogKey }));
636
+ const state = {
637
+ content: "",
638
+ contentBuffer: [],
639
+ reasoning: "",
640
+ usage: null,
641
+ assistantToolCalls: [],
642
+ completedResponse: null
643
+ };
644
+ let activeMessageMetadata = messageMetadata;
645
+ const buildMeta = (hasPendingInteraction = false, hasHandedOff = false, finishReason = null) => ({
646
+ hasToolCalls: state.assistantToolCalls.length > 0,
647
+ hasPendingInteraction,
648
+ hasHandedOff,
649
+ finishReason,
650
+ messageId,
651
+ usage: state.usage ?? void 0
652
+ });
653
+ const resetStateForRetry = () => {
654
+ state.content = "";
655
+ state.contentBuffer = [];
656
+ state.reasoning = "";
657
+ state.usage = null;
658
+ state.assistantToolCalls = [];
659
+ state.completedResponse = null;
660
+ activeMessageMetadata = messageMetadata;
661
+ };
662
+ const canRetryInitialResponseAttempt = (attempt, loggedFirstVisibleDelta, finishReason) => attempt < MAX_INITIAL_STREAM_RETRIES && !loggedFirstVisibleDelta && !state.assistantToolCalls.length && !finishReason && !state.completedResponse;
663
+ const flush = () => dispatch(
664
+ messageStreaming({
665
+ id: messageId,
666
+ dialogId,
667
+ dbKey: msgKey,
668
+ content: state.contentBuffer,
669
+ thinkContent: state.reasoning,
670
+ role: "assistant",
671
+ agentKey: agentConfig.dbKey,
672
+ cybotKey: agentConfig.dbKey,
673
+ ...asOptionalTrimmedString(agentConfig?.name) ? { agentName: asOptionalTrimmedString(agentConfig?.name) } : {},
674
+ ...activeMessageMetadata ?? {}
675
+ })
676
+ );
677
+ const finalize = async () => {
678
+ if (!state.content) {
679
+ const completedText = extractTextFromResponseOutput(state.completedResponse);
680
+ if (completedText) {
681
+ state.content = completedText;
682
+ }
683
+ }
684
+ const completedImages = extractImagePartsFromResponseOutput(state.completedResponse);
685
+ if (state.contentBuffer.length === 0) {
686
+ state.contentBuffer = [
687
+ ...state.content ? seg(state.content) : [],
688
+ ...completedImages
689
+ ];
690
+ } else if (completedImages.length > 0 && !state.contentBuffer.some((part) => part.type === "image_url")) {
691
+ state.contentBuffer = [...state.contentBuffer, ...completedImages];
692
+ }
693
+ if (state.contentBuffer.length === 0 && state.content) {
694
+ state.contentBuffer = seg(state.content);
695
+ }
696
+ activeMessageMetadata = withImageGenerationStage(
697
+ activeMessageMetadata,
698
+ "saving"
699
+ );
700
+ if (activeMessageMetadata?.imageGenerationState && shouldShowImageSavingState(state.contentBuffer)) {
701
+ dispatch(
702
+ messageStreaming({
703
+ id: messageId,
704
+ dialogId,
705
+ dbKey: msgKey,
706
+ content: "",
707
+ thinkContent: state.reasoning,
708
+ role: "assistant",
709
+ agentKey: agentConfig.dbKey,
710
+ cybotKey: agentConfig.dbKey,
711
+ ...asOptionalTrimmedString(agentConfig?.name) ? { agentName: asOptionalTrimmedString(agentConfig?.name) } : {},
712
+ ...activeMessageMetadata ?? {}
713
+ })
714
+ );
715
+ } else {
716
+ flush();
717
+ }
718
+ await dispatch(
719
+ messageStreamEnd({
720
+ finalContentBuffer: state.contentBuffer,
721
+ totalUsage: state.usage,
722
+ msgKey,
723
+ agentConfig,
724
+ dialogId,
725
+ dialogKey,
726
+ messageId,
727
+ reasoningBuffer: state.reasoning,
728
+ messageMetadata: activeMessageMetadata,
729
+ toolCalls: state.assistantToolCalls,
730
+ spaceId: streamSpaceId
731
+ })
732
+ );
733
+ };
734
+ const processToolCalls = async () => {
735
+ if (!state.assistantToolCalls.length) {
736
+ await finalize();
737
+ return buildMeta(false, false, null);
738
+ }
739
+ const validCalls = [];
740
+ const invalidCalls = [];
741
+ for (const call of state.assistantToolCalls) {
742
+ if (!call) continue;
743
+ if (parseToolCallArguments(call?.function?.arguments).valid) {
744
+ validCalls.push(call);
745
+ } else {
746
+ invalidCalls.push({
747
+ ...call,
748
+ type: "function",
749
+ function: {
750
+ name: call?.function?.name ?? "",
751
+ arguments: INVALID_TOOL_ARGS_REPLACEMENT
752
+ }
753
+ });
754
+ }
755
+ }
756
+ if (invalidCalls.length > 0) {
757
+ const invalidById = /* @__PURE__ */ new Map();
758
+ for (const call of invalidCalls) {
759
+ if (call?.id) invalidById.set(call.id, call);
760
+ }
761
+ state.assistantToolCalls = state.assistantToolCalls.map((call) => {
762
+ const invalid = call?.id ? invalidById.get(call.id) : void 0;
763
+ if (!invalid) return call;
764
+ return {
765
+ ...call,
766
+ type: "function",
767
+ function: {
768
+ name: invalid.function?.name ?? call.function?.name ?? "",
769
+ arguments: INVALID_TOOL_ARGS_REPLACEMENT
770
+ }
771
+ };
772
+ });
773
+ for (let i = 0; i < invalidCalls.length; i++) {
774
+ const call = invalidCalls[i];
775
+ const callId = call?.id || `call_${Date.now()}_${Math.random().toString(36).slice(2)}`;
776
+ const toolIndex = validCalls.length + i;
777
+ const runningToolMessageId = `${messageId}-t${String(toolIndex).padStart(3, "0")}`;
778
+ const runningToolDbKey = dialogMessageKey(dialogId, runningToolMessageId);
779
+ const toolName = call?.function?.name || "unknown";
780
+ const selfHealContent = buildInvalidToolCallSelfHealResult(callId, toolName);
781
+ const toolMessage = {
782
+ id: runningToolMessageId,
783
+ dbKey: runningToolDbKey,
784
+ role: "tool",
785
+ content: selfHealContent,
786
+ toolCallId: callId,
787
+ thinkContent: "",
788
+ cybotKey: agentConfig.dbKey,
789
+ isStreaming: false,
790
+ toolName,
791
+ parentMessageId: messageId,
792
+ toolPayload: {
793
+ toolName,
794
+ status: "failed",
795
+ input: {},
796
+ rawToolCall: call,
797
+ error: {
798
+ type: "InvalidToolCallArguments",
799
+ 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",
800
+ retryable: true
801
+ },
802
+ summary: `\u274C ${toolName} \u53C2\u6570\u88AB\u622A\u65AD\uFF0C\u5DF2\u8DF3\u8FC7`
803
+ }
804
+ };
805
+ dispatch(addToolMessage(toolMessage));
806
+ const { controller: _c, ...messageToWrite } = toolMessage;
807
+ await dispatch(
808
+ write({
809
+ data: { ...messageToWrite, type: "msg" /* MSG */ },
810
+ customKey: runningToolDbKey
811
+ })
812
+ );
813
+ }
814
+ }
815
+ if (!validCalls.length) {
816
+ await finalize();
817
+ return buildMeta(false, false, null);
818
+ }
819
+ if (state.usage) {
820
+ dispatch(
821
+ tokenUsageLiveUpdate({
822
+ input_tokens: state.usage.prompt_tokens ?? state.usage.input_tokens,
823
+ output_tokens: state.usage.completion_tokens ?? state.usage.output_tokens,
824
+ cost: state.usage.cost,
825
+ dialogKey
826
+ })
827
+ );
828
+ }
829
+ const result = await dispatch(
830
+ handleToolCalls({
831
+ accumulatedCalls: validCalls,
832
+ currentContentBuffer: state.contentBuffer,
833
+ agentConfig,
834
+ messageId,
835
+ dialogId,
836
+ dialogKey
837
+ })
838
+ ).unwrap();
839
+ state.content = Array.isArray(result.finalContentBuffer) ? result.finalContentBuffer.filter((part) => part?.type === "text").map((part) => part.text ?? "").join("") : state.content;
840
+ state.contentBuffer = Array.isArray(result.finalContentBuffer) ? result.finalContentBuffer : state.contentBuffer;
841
+ await finalize();
842
+ return buildMeta(result.hasPendingInteraction, result.hasHandedOff, null);
843
+ };
844
+ let reader;
845
+ try {
846
+ if (!parentMessageId) {
847
+ dispatch(
848
+ messageStreaming({
849
+ id: messageId,
850
+ dialogId,
851
+ dbKey: msgKey,
852
+ content: "",
853
+ role: "assistant",
854
+ agentKey: agentConfig.dbKey,
855
+ cybotKey: agentConfig.dbKey,
856
+ ...asOptionalTrimmedString(agentConfig?.name) ? { agentName: asOptionalTrimmedString(agentConfig?.name) } : {},
857
+ ...activeMessageMetadata ?? {},
858
+ isStreaming: true
859
+ })
860
+ );
861
+ }
862
+ const functionTools = getModelInfo(agentConfig.model)?.hasImageOutput ? [] : prepareTools(agentConfig.tools ?? [], { provider: agentConfig.provider });
863
+ const imageMode = getPublicImageAgentMode(agentConfig);
864
+ const imageProfile = imageMode === "continuous" ? getPublicImageAgentDefaultProfile("continuous") : null;
865
+ const tools = [
866
+ ...toResponsesTools(functionTools) ?? [],
867
+ ...shouldEnableBuiltInImageGeneration(agentConfig) ? [{ type: "image_generation" }] : [],
868
+ ...imageMode === "continuous" ? [
869
+ {
870
+ type: "image_generation",
871
+ action: "auto",
872
+ quality: imageProfile?.quality,
873
+ output_format: imageProfile?.outputFormat
874
+ }
875
+ ] : []
876
+ ];
877
+ const sanitizedInput = Array.isArray(bodyData?.input) ? sanitizeOutboundResponsesInput(bodyData.input) : bodyData?.input;
878
+ const baseBodyData = sanitizedInput !== bodyData?.input ? { ...bodyData, input: sanitizedInput } : bodyData;
879
+ const requestBody = {
880
+ ...baseBodyData,
881
+ ...tools.length ? { tools, tool_choice: baseBodyData.tool_choice ?? "auto" } : {},
882
+ stream: true
883
+ };
884
+ const api = getApiEndpoint(agentConfig);
885
+ const token = selectIdentityToken(getState());
886
+ logQuickChatPerfStage(quickChatPerfStartedAt, "openai-response-fetch-starting", {
887
+ api,
888
+ dialogKey
889
+ });
890
+ attemptLoop:
891
+ for (let attempt = 0; attempt <= MAX_INITIAL_STREAM_RETRIES; attempt += 1) {
892
+ const response = await performFetchRequest({
893
+ agentConfig,
894
+ api,
895
+ bodyData: requestBody,
896
+ currentServer: selectRuntimeCurrentServer(getState()),
897
+ signal,
898
+ token: token ?? "",
899
+ dialogId
900
+ });
901
+ logQuickChatPerfStage(quickChatPerfStartedAt, "openai-response-fetch-response", {
902
+ ok: response.ok,
903
+ status: response.status,
904
+ dialogKey
905
+ });
906
+ activeMessageMetadata = withImageGenerationStage(
907
+ activeMessageMetadata,
908
+ "generating"
909
+ );
910
+ if (!parentMessageId && activeMessageMetadata?.imageGenerationState) {
911
+ dispatch(
912
+ messageStreaming({
913
+ id: messageId,
914
+ dialogId,
915
+ dbKey: msgKey,
916
+ content: "",
917
+ role: "assistant",
918
+ agentKey: agentConfig.dbKey,
919
+ cybotKey: agentConfig.dbKey,
920
+ ...asOptionalTrimmedString(agentConfig?.name) ? { agentName: asOptionalTrimmedString(agentConfig?.name) } : {},
921
+ ...activeMessageMetadata ?? {},
922
+ isStreaming: true
923
+ })
924
+ );
925
+ }
926
+ if (!response.ok) {
927
+ const errorMessage = await parseApiError(response);
928
+ state.content = `[\u9519\u8BEF: ${errorMessage}]`;
929
+ await finalize();
930
+ return buildMeta();
931
+ }
932
+ reader = response.body?.getReader();
933
+ if (!reader) {
934
+ if (canRetryInitialResponseAttempt(attempt, false, null)) {
935
+ resetStateForRetry();
936
+ await waitForInitialStreamRetry(1500, signal);
937
+ continue;
938
+ }
939
+ await finalize();
940
+ return buildMeta();
941
+ }
942
+ const parseSSE = createSSEParser();
943
+ const decoder = new TextDecoder();
944
+ let finishReason = null;
945
+ let loggedFirstStreamChunk = false;
946
+ let loggedFirstParsedEvent = false;
947
+ let loggedFirstVisibleDelta = false;
948
+ try {
949
+ while (true) {
950
+ const { done, value } = await readStreamChunk(reader, { signal });
951
+ if (done) {
952
+ if (canRetryInitialResponseAttempt(attempt, loggedFirstVisibleDelta, finishReason)) {
953
+ await safeCancel(reader);
954
+ reader = void 0;
955
+ resetStateForRetry();
956
+ await waitForInitialStreamRetry(1500, signal);
957
+ continue attemptLoop;
958
+ }
959
+ const meta = await processToolCalls();
960
+ return {
961
+ ...meta,
962
+ finishReason: meta.finishReason ?? finishReason
963
+ };
964
+ }
965
+ if (!loggedFirstStreamChunk) {
966
+ loggedFirstStreamChunk = true;
967
+ logQuickChatPerfStage(
968
+ quickChatPerfStartedAt,
969
+ "openai-response-first-stream-chunk",
970
+ { dialogKey, byteLength: value.byteLength }
971
+ );
972
+ }
973
+ const chunk = decoder.decode(value, { stream: true });
974
+ const events = parseSSE(chunk);
975
+ if (events.length > 0 && !loggedFirstParsedEvent) {
976
+ loggedFirstParsedEvent = true;
977
+ logQuickChatPerfStage(
978
+ quickChatPerfStartedAt,
979
+ "openai-response-first-sse-event",
980
+ { dialogKey, eventCount: events.length }
981
+ );
982
+ }
983
+ const eventList = Array.isArray(events) ? events : [events];
984
+ for (const event of eventList) {
985
+ if (event?.usage) {
986
+ state.usage = updateTotalUsage(state.usage, event.usage);
987
+ }
988
+ if (event?.type === "error" || event?.error) {
989
+ const streamError = new Error(getStreamErrorMessage(event));
990
+ if (canRetryInitialResponseAttempt(attempt, loggedFirstVisibleDelta, finishReason) && isRetryableInitialStreamError(streamError)) {
991
+ await safeCancel(reader);
992
+ reader = void 0;
993
+ resetStateForRetry();
994
+ await waitForInitialStreamRetry(1500, signal);
995
+ continue attemptLoop;
996
+ }
997
+ state.content += `
998
+ [Error: ${getStreamErrorMessage(event)}]`;
999
+ await finalize();
1000
+ return buildMeta();
1001
+ }
1002
+ switch (event?.type) {
1003
+ case "response.output_text.delta":
1004
+ if (event.delta) {
1005
+ state.content += event.delta;
1006
+ state.contentBuffer = seg(state.content);
1007
+ if (!loggedFirstVisibleDelta) {
1008
+ loggedFirstVisibleDelta = true;
1009
+ logQuickChatPerfStage(
1010
+ quickChatPerfStartedAt,
1011
+ "openai-response-first-visible-delta",
1012
+ { dialogKey }
1013
+ );
1014
+ }
1015
+ flush();
1016
+ }
1017
+ break;
1018
+ case "response.reasoning.delta":
1019
+ if (event.delta?.text) {
1020
+ state.reasoning += event.delta.text;
1021
+ flush();
1022
+ }
1023
+ break;
1024
+ case "response.reasoning.done":
1025
+ if (event.text) {
1026
+ state.reasoning += event.text;
1027
+ flush();
1028
+ }
1029
+ break;
1030
+ case "response.output_item.added":
1031
+ case "response.output_item.done": {
1032
+ const item = event.item;
1033
+ if (!state.content) {
1034
+ const itemText = extractTextFromOutputItem(item);
1035
+ if (itemText) {
1036
+ state.content = itemText;
1037
+ state.contentBuffer = seg(state.content);
1038
+ if (!loggedFirstVisibleDelta) {
1039
+ loggedFirstVisibleDelta = true;
1040
+ logQuickChatPerfStage(
1041
+ quickChatPerfStartedAt,
1042
+ "openai-response-first-visible-delta",
1043
+ { dialogKey }
1044
+ );
1045
+ }
1046
+ flush();
1047
+ }
1048
+ }
1049
+ if (item?.type === "function_call") {
1050
+ ensureToolCall(state, item.call_id || item.id, {
1051
+ id: item.call_id || item.id,
1052
+ function: {
1053
+ name: item.name || "",
1054
+ arguments: typeof item.arguments === "string" ? item.arguments : ""
1055
+ }
1056
+ });
1057
+ }
1058
+ break;
1059
+ }
1060
+ case "response.function_call_arguments.delta": {
1061
+ const key = event.call_id || event.item_id || `${event.output_index ?? 0}`;
1062
+ const toolCall = ensureToolCall(state, key, {
1063
+ id: event.call_id || key,
1064
+ function: { name: event.name || "", arguments: "" }
1065
+ });
1066
+ toolCall.function.arguments += event.delta ?? "";
1067
+ break;
1068
+ }
1069
+ case "response.function_call_arguments.done": {
1070
+ const key = event.call_id || event.item_id || `${event.output_index ?? 0}`;
1071
+ ensureToolCall(state, key, {
1072
+ id: event.call_id || key,
1073
+ function: {
1074
+ name: event.name || "",
1075
+ arguments: typeof event.arguments === "string" ? event.arguments : typeof event.output?.arguments === "string" ? event.output.arguments : ""
1076
+ }
1077
+ });
1078
+ break;
1079
+ }
1080
+ case "response.completed":
1081
+ state.completedResponse = event.response ?? null;
1082
+ finishReason = event.response?.status === "completed" ? "stop" : event.response?.status ?? null;
1083
+ if (event.response?.usage) {
1084
+ state.usage = updateTotalUsage(state.usage, event.response.usage);
1085
+ }
1086
+ break;
1087
+ case "response.failed":
1088
+ state.content += `
1089
+ [API Failed: ${event.response?.error?.message || "unknown"}]`;
1090
+ finishReason = "error";
1091
+ await finalize();
1092
+ return buildMeta(false, false, finishReason);
1093
+ case "response.incomplete":
1094
+ state.content += `
1095
+ [Incomplete: ${event.response?.incomplete_details?.reason || "unknown"}]`;
1096
+ finishReason = "incomplete";
1097
+ await finalize();
1098
+ return buildMeta(false, false, finishReason);
1099
+ default:
1100
+ break;
1101
+ }
1102
+ }
1103
+ }
1104
+ } catch (error) {
1105
+ if (canRetryInitialResponseAttempt(attempt, loggedFirstVisibleDelta, finishReason) && isRetryableInitialStreamError(
1106
+ error ?? new Error("response stream ended before first visible delta")
1107
+ )) {
1108
+ await safeCancel(reader);
1109
+ reader = void 0;
1110
+ resetStateForRetry();
1111
+ await waitForInitialStreamRetry(1500, signal);
1112
+ continue;
1113
+ }
1114
+ throw error;
1115
+ }
1116
+ }
1117
+ return buildMeta(false, false, null);
1118
+ } catch (error) {
1119
+ state.content += isAbortError(error) ? "[\u7528\u6237\u4E2D\u65AD]" : `[\u5F02\u5E38: ${error?.message || "unknown"}]`;
1120
+ await finalize();
1121
+ return buildMeta(false, false, "error");
1122
+ } finally {
1123
+ logQuickChatPerfStage(quickChatPerfStartedAt, "openai-response-stream-finished", {
1124
+ dialogKey
1125
+ });
1126
+ dispatch(removeActiveController({ messageId, dialogKey }));
1127
+ await safeCancel(reader);
1128
+ }
1129
+ };
1130
+
1131
+ // packages/ai/agent/cleanAgentMessages.ts
1132
+ var isEmptyContent = (content) => {
1133
+ if (content == null) return true;
1134
+ if (typeof content === "string") {
1135
+ return content.trim().length === 0;
1136
+ }
1137
+ if (Array.isArray(content)) {
1138
+ return content.length === 0;
1139
+ }
1140
+ return false;
1141
+ };
1142
+ var buildAgentViewMessages = (allMessages, currentAgentKey) => {
1143
+ const result = [];
1144
+ for (const msg of allMessages) {
1145
+ if (!msg) continue;
1146
+ const role = msg.role;
1147
+ if (!role) continue;
1148
+ const hasToolCalls = Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 || Array.isArray(msg.toolCalls) && msg.toolCalls.length > 0;
1149
+ const empty = isEmptyContent(msg.content);
1150
+ if (role === "assistant" && empty && !hasToolCalls) {
1151
+ continue;
1152
+ }
1153
+ const isCurrentAgent = msg.cybotKey === currentAgentKey;
1154
+ if (role === "user") {
1155
+ result.push(msg);
1156
+ continue;
1157
+ }
1158
+ if (role === "assistant") {
1159
+ if (isCurrentAgent) {
1160
+ result.push(msg);
1161
+ } else {
1162
+ const cloned = { ...msg };
1163
+ if (cloned.tool_calls) {
1164
+ delete cloned.tool_calls;
1165
+ }
1166
+ if (cloned.toolCalls) {
1167
+ delete cloned.toolCalls;
1168
+ }
1169
+ const rawAgentName = cloned.agentName;
1170
+ const agentName = rawAgentName && String(rawAgentName).trim() ? String(rawAgentName).trim() : "\u5176\u4ED6 Agent";
1171
+ if (typeof cloned.content === "string") {
1172
+ const trimmed = cloned.content.trim();
1173
+ if (trimmed) {
1174
+ cloned.content = `\u3010${agentName}\u3011 ${trimmed}`;
1175
+ } else {
1176
+ cloned.content = `\u3010${agentName}\u3011\uFF08\u4F7F\u7528\u4E86\u5DE5\u5177\u751F\u6210\u56DE\u590D\uFF09`;
1177
+ }
1178
+ } else {
1179
+ cloned.content = `\u3010${agentName}\u3011\uFF08\u4F7F\u7528\u4E86\u5DE5\u5177\u751F\u6210\u56DE\u590D\uFF09`;
1180
+ }
1181
+ result.push(cloned);
1182
+ }
1183
+ continue;
1184
+ }
1185
+ if (role === "tool") {
1186
+ if (isCurrentAgent) {
1187
+ result.push(msg);
1188
+ } else {
1189
+ continue;
1190
+ }
1191
+ continue;
1192
+ }
1193
+ result.push(msg);
1194
+ }
1195
+ return result;
1196
+ };
1197
+
1198
+ // packages/ai/agent/quickChatModelOverride.ts
1199
+ function applyQuickChatModelOverride(base, override) {
1200
+ return applyModelLayerOverride(
1201
+ base,
1202
+ override
1203
+ );
1204
+ }
1205
+
1206
+ // packages/ai/agent/canvasEditingContext.ts
1207
+ function buildCanvasNodeEditingContextSummary(runtimeOptions) {
1208
+ if (runtimeOptions?.editingTarget?.kind !== "canvas_node") return null;
1209
+ const editingTarget = runtimeOptions.editingTarget;
1210
+ const metadata = editingTarget.metadata ?? {};
1211
+ const selectedNodeId = typeof metadata.selectedNodeId === "string" ? metadata.selectedNodeId : editingTarget.key ?? "(\u672A\u77E5\u8282\u70B9)";
1212
+ const part = typeof metadata.part === "string" ? metadata.part : editingTarget.title ?? selectedNodeId;
1213
+ const nodeType = typeof metadata.type === "string" ? metadata.type : "(\u672A\u77E5\u7C7B\u578B)";
1214
+ const path = Array.isArray(metadata.path) ? metadata.path.filter((item) => typeof item === "string") : [];
1215
+ const props = asRecordOrEmpty(metadata.props);
1216
+ const style = asRecordOrEmpty(metadata.style);
1217
+ return [
1218
+ "\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1ACanvas Tree \u4E2D\u7684\u4E00\u4E2A\u9009\u4E2D\u8282\u70B9\u3002",
1219
+ `- \u8282\u70B9 ID: ${selectedNodeId}`,
1220
+ `- part: ${part}`,
1221
+ `- \u8282\u70B9\u7C7B\u578B: ${nodeType}`,
1222
+ ...path.length ? [`- \u8282\u70B9\u8DEF\u5F84: ${path.join(" > ")}`] : [],
1223
+ "",
1224
+ "\u5F53\u524D\u8282\u70B9 props:",
1225
+ JSON.stringify(props, null, 2),
1226
+ "",
1227
+ "\u5F53\u524D\u8282\u70B9 style:",
1228
+ JSON.stringify(style, null, 2),
1229
+ "",
1230
+ "\u3010\u7ED9 AI \u7684\u64CD\u4F5C\u6307\u5357 / \u975E\u7528\u6237\u539F\u8BDD\u3011",
1231
+ `1. \u5982\u679C\u7528\u6237\u8981\u6C42\u4FEE\u6539\u5F53\u524D\u6A21\u5757\uFF0C\u53EA\u8F93\u51FA updateNode\uFF0C\u76EE\u6807 id \u5FC5\u987B\u662F ${selectedNodeId}\u3002`,
1232
+ "2. \u4E0D\u8981\u91CD\u5EFA root/shell\uFF0C\u4E0D\u8981\u91CD\u65B0 append \u5DF2\u5B58\u5728\u7684\u5927\u5757\u5185\u5BB9\u3002",
1233
+ "3. \u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u65B0\u589E\u5B50\u6A21\u5757\uFF0C\u5426\u5219\u4E0D\u8981 appendNode\u3002",
1234
+ "4. \u56DE\u590D\u4ECD\u5FC5\u987B\u9075\u5B88 Canvas Tree MVP \u534F\u8BAE\uFF1A\u53EA\u8F93\u51FA canvas_snapshot NDJSON\uFF0C\u4E0D\u8981\u8F93\u51FA\u89E3\u91CA\u6216\u6E90\u7801\u3002"
1235
+ ].join("\n");
1236
+ }
1237
+
1238
+ // packages/ai/agent/buildEditingContext.ts
1239
+ var buildAppConstraintPacks = (args) => {
1240
+ const imports = new Set(args.externalImports);
1241
+ const fileSet = new Set(args.fileNames);
1242
+ const packs = [
1243
+ {
1244
+ id: "repair-loop",
1245
+ title: "\u9884\u68C0\u4E0E\u5B9A\u70B9\u4FEE\u590D",
1246
+ rules: [
1247
+ "\u6BCF\u6B21\u6539\u5B8C\u4EE3\u7801\u540E\uFF0C\u5148\u8C03\u7528 appPreflight\uFF0C\u53EA\u6709\u9884\u68C0\u901A\u8FC7\u540E\u518D\u8C03\u7528 appDeploy\u3002",
1248
+ "\u5982\u679C preflight / deploy \u5931\u8D25\uFF0C\u4F18\u5148\u6839\u636E\u8FD4\u56DE\u7684 issues \u505A\u5B9A\u70B9\u4FEE\u590D\uFF0C\u7136\u540E\u91CD\u65B0 preflight\uFF1B\u4E0D\u8981\u65E0\u5173\u91CD\u5199\u6574\u9875\u5E94\u7528\u3002",
1249
+ "\u5982\u679C\u5DE5\u5177\u7ED3\u679C\u91CC\u5E26\u6709 repairPlan\uFF0C\u9ED8\u8BA4\u7ACB\u5373\u6267\u884C repairPlan \u4E2D\u7684\u5C40\u90E8\u4FEE\u590D\u6B65\u9AA4\uFF0C\u4E0D\u8981\u5148\u505C\u4E0B\u6765\u95EE\u7528\u6237\u3002",
1250
+ "\u5982\u679C\u5DE5\u5177\u7ED3\u679C\u660E\u786E\u8BF4\u660E\u662F HTML / \u975E JSON \u54CD\u5E94\u3001transport failure \u6216 retryable=false\uFF0C\u505C\u6B62\u81EA\u52A8 deploy \u91CD\u8BD5\uFF1B\u8FD9\u8BF4\u660E\u5F53\u524D\u662F\u5E73\u53F0\u901A\u9053\u5F02\u5E38\uFF0C\u4E0D\u662F\u4EE3\u7801\u95EE\u9898\u3002"
1251
+ ]
1252
+ },
1253
+ {
1254
+ id: "design-system",
1255
+ title: "\u8BBE\u8BA1\u7CFB\u7EDF\u4E0E\u5C0F\u6539\u52A8\u7EA6\u675F",
1256
+ rules: [
1257
+ "\u5148\u68C0\u67E5\u5F53\u524D\u5E94\u7528\u662F\u5426\u5DF2\u7ECF\u6709 theme / tokens / designSystem / \u5171\u4EAB\u6837\u5F0F\u5E38\u91CF\uFF1B\u5982\u679C\u5DF2\u6709\uFF0C\u4F18\u5148\u6CBF\u7528\u8FD9\u5957\u8BBE\u8BA1\u7CFB\u7EDF\uFF0C\u4E0D\u8981\u5E73\u884C\u518D\u9020\u4E00\u5957\u3002",
1258
+ "\u5982\u679C\u5F53\u524D\u5E94\u7528\u8FD8\u6CA1\u6709\u8BBE\u8BA1\u7CFB\u7EDF\uFF0C\u800C\u7528\u6237\u9700\u6C42\u6D89\u53CA UI / \u6837\u5F0F / \u65B0\u9875\u9762\uFF0C\u4F18\u5148\u8865\u4E00\u5C42\u6700\u5C0F\u5171\u4EAB token\uFF08colors\u3001typography\u3001spacing\u3001radius\u3001shadow\uFF09\uFF0C\u518D\u8BA9\u7EC4\u4EF6\u6D88\u8D39\u8FD9\u4E9B token\u3002",
1259
+ "\u5982\u679C\u5F53\u524D\u5E94\u7528\u662F\u65E7\u5199\u6CD5\uFF1A\u89C6\u89C9\u503C\u6563\u843D\u5728\u591A\u4E2A\u7EC4\u4EF6\u7684\u786C\u7F16\u7801 style / \u5E38\u91CF\u91CC\uFF0C\u800C\u672C\u6B21\u9700\u6C42\u53EA\u662F\u8C03\u5B57\u4F53\u3001\u989C\u8272\u3001\u95F4\u8DDD\u3001\u5706\u89D2\u3001\u9634\u5F71\uFF0C\u9ED8\u8BA4\u6267\u884C\u4E00\u6B21\u6700\u5C0F token \u8FC1\u79FB\uFF0C\u518D\u5728 token \u5C42\u5B8C\u6210\u8C03\u6574\uFF1B\u4E0D\u8981\u7EE7\u7EED\u628A\u65B0\u6570\u5B57\u6563\u843D\u5199\u56DE\u591A\u4E2A\u4F4D\u7F6E\u3002",
1260
+ "\u5F53\u7528\u6237\u53EA\u662F\u60F3\u8C03\u5B57\u4F53\u5927\u5C0F\u3001\u5B57\u91CD\u3001\u989C\u8272\u3001\u5706\u89D2\u3001\u9634\u5F71\u3001\u95F4\u8DDD\u7B49\u89C6\u89C9\u53C2\u6570\u65F6\uFF0C\u4F18\u5148\u4FEE\u6539 token \u6216\u547D\u4E2D\u7684\u5C40\u90E8\u7EC4\u4EF6\uFF0C\u4E0D\u8981\u987A\u624B\u91CD\u5199\u6574\u4E2A\u9875\u9762\u7ED3\u6784\u3002",
1261
+ "\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u6574\u4F53\u6539\u7248\u6216\u91CD\u505A\u98CE\u683C\uFF0C\u5426\u5219\u4E0D\u8981\u8FDE\u5E26\u4FEE\u6539\u5E03\u5C40\u3001\u7EC4\u4EF6\u6811\u3001\u6587\u6848\u3001\u6570\u636E\u6D41\u3001\u8DEF\u7531\u6216\u672A\u547D\u4E2D\u7684\u9875\u9762\u3002",
1262
+ "\u5982\u679C\u53EA\u662F\u5C0F\u6539\u4E00\u5904\uFF0C\u5C3D\u91CF\u628A\u53D8\u66F4\u6536\u655B\u5728\u5C11\u6570\u6587\u4EF6\uFF0C\u5E76\u4FDD\u6301\u672A\u547D\u4E2D\u6587\u4EF6\u7684\u7ED3\u6784\u4E0E\u547D\u540D\u7A33\u5B9A\u3002"
1263
+ ]
1264
+ }
1265
+ ];
1266
+ if (args.framework === "react-spa" || fileSet.has("main.tsx") || fileSet.has("App.tsx")) {
1267
+ packs.push({
1268
+ id: "react-spa-core",
1269
+ title: "React SPA \u5F62\u6001\u4FDD\u6301",
1270
+ rules: [
1271
+ '\u7EE7\u7EED\u6CBF\u7528 framework: "react-spa" + files\uFF0C\u4E0D\u8981\u9000\u56DE\u5355\u6587\u4EF6 Worker\u3002',
1272
+ "\u4FDD\u7559\u7A33\u5B9A\u5165\u53E3\u7ED3\u6784\uFF0C\u4F18\u5148\u7EF4\u62A4 main.tsx + App.tsx\uFF0C\u518D\u5C40\u90E8\u4FEE\u6539\u7EC4\u4EF6\u6587\u4EF6\u3002"
1273
+ ]
1274
+ });
1275
+ }
1276
+ if (imports.has("react-icons/lu")) {
1277
+ packs.push({
1278
+ id: "react-icons-lu",
1279
+ title: "Lucide \u56FE\u6807\u5B89\u5168\u89C4\u5219",
1280
+ rules: [
1281
+ "\u53EA\u80FD\u4F7F\u7528 react-icons/lu \u4E2D\u771F\u5B9E\u5B58\u5728\u7684\u56FE\u6807\u540D\uFF0C\u4E0D\u8981\u731C\u6D4B\u53D8\u4F53\u540D\u3002",
1282
+ "\u5982\u679C\u4E0D\u786E\u5B9A\u56FE\u6807\u540D\uFF0C\u4F18\u5148\u4F7F\u7528 LuCircle\u3001LuCheck\u3001LuX\u3001LuInfo\u3001LuArrowRight \u8FD9\u7C7B\u57FA\u7840\u56FE\u6807\u3002"
1283
+ ]
1284
+ });
1285
+ }
1286
+ if (imports.has("leaflet") || imports.has("react-leaflet")) {
1287
+ packs.push({
1288
+ id: "leaflet",
1289
+ title: "Leaflet \u5730\u56FE\u7EA6\u675F",
1290
+ rules: [
1291
+ "\u4E0D\u8981\u624B\u52A8 import leaflet.css\uFF1B\u5E73\u53F0\u4F1A\u81EA\u52A8\u6CE8\u5165 Leaflet \u6837\u5F0F\u3002",
1292
+ "\u4FEE\u6539\u5730\u56FE\u65F6\u4F18\u5148\u4FDD\u7559\u73B0\u6709\u5750\u6807\u3001\u7F29\u653E\u548C\u56FE\u5C42\u7ED3\u6784\uFF0C\u53EA\u505A\u5FC5\u8981\u7684\u4EA4\u4E92\u6216\u89C6\u89C9\u8C03\u6574\u3002"
1293
+ ]
1294
+ });
1295
+ }
1296
+ if (imports.has("@xyflow/react")) {
1297
+ packs.push({
1298
+ id: "xyflow",
1299
+ title: "Flow \u56FE\u7F16\u8F91\u7EA6\u675F",
1300
+ rules: [
1301
+ "\u4E0D\u8981\u65B0\u589E\u5916\u90E8 CSS import\uFF1B\u9700\u8981\u6837\u5F0F\u65F6\u76F4\u63A5\u8865\u6700\u5C0F\u5FC5\u8981\u5185\u8054\u6837\u5F0F\u6216\u7EC4\u4EF6\u5185 style \u6807\u7B7E\u3002",
1302
+ "\u4F18\u5148\u590D\u7528\u73B0\u6709\u8282\u70B9/\u8FB9\u6570\u636E\u7ED3\u6784\uFF0C\u907F\u514D\u91CD\u5199\u6574\u5957 flow \u753B\u5E03\u3002"
1303
+ ]
1304
+ });
1305
+ }
1306
+ if (imports.has("echarts") || imports.has("echarts-for-react")) {
1307
+ packs.push({
1308
+ id: "echarts",
1309
+ title: "\u56FE\u8868\u6539\u52A8\u7EA6\u675F",
1310
+ rules: [
1311
+ "\u4F18\u5148\u5C40\u90E8\u4FEE\u6539 option \u914D\u7F6E\u3001\u6570\u636E\u6620\u5C04\u548C\u7EC4\u4EF6 props\uFF0C\u4E0D\u8981\u91CD\u5199\u6574\u4E2A\u56FE\u8868\u9875\u9762\u3002",
1312
+ "\u54CD\u5E94\u5F0F\u5E03\u5C40\u4F18\u5148\u9760\u5BB9\u5668\u5C3A\u5BF8\u548C\u73B0\u6709\u7EC4\u4EF6\u7ED3\u6784\u8C03\u6574\uFF0C\u4E0D\u8981\u989D\u5916\u5F15\u5165 CSS \u6587\u4EF6\u3002"
1313
+ ]
1314
+ });
1315
+ }
1316
+ if (imports.has("docx") || imports.has("xlsx")) {
1317
+ packs.push({
1318
+ id: "file-processing",
1319
+ title: "\u6587\u6863/\u8868\u683C\u5904\u7406\u7EA6\u675F",
1320
+ rules: [
1321
+ "\u4E0D\u8981\u628A\u5927\u578B\u6570\u636E\u6216\u6A21\u677F\u5185\u5BB9\u76F4\u63A5\u5185\u5D4C\u8FDB\u4EE3\u7801\u5E38\u91CF\uFF1B\u4F18\u5148\u4FDD\u7559\u8FD0\u884C\u65F6\u52A0\u8F7D\u65B9\u5F0F\u3002",
1322
+ "\u4FEE\u6539\u5BFC\u5165\u5BFC\u51FA\u903B\u8F91\u65F6\uFF0C\u4F18\u5148\u6CBF\u7528\u73B0\u6709\u6587\u4EF6\u5904\u7406\u94FE\u8DEF\u548C\u6570\u636E\u7ED3\u6784\u3002"
1323
+ ]
1324
+ });
1325
+ }
1326
+ return packs;
1327
+ };
1328
+ var formatAppConstraintPacks = (packs) => {
1329
+ if (packs.length === 0) return [];
1330
+ return [
1331
+ "",
1332
+ "\u5F53\u524D\u6FC0\u6D3B\u7EA6\u675F\u5305\uFF08\u6309\u5F53\u524D\u5E94\u7528\u4F9D\u8D56/\u5F62\u6001\u52A8\u6001\u6CE8\u5165\uFF09\uFF1A",
1333
+ ...packs.flatMap((pack) => [
1334
+ `- ${pack.title}\uFF08${pack.id}\uFF09`,
1335
+ ...pack.rules.map((rule) => ` - ${rule}`)
1336
+ ])
1337
+ ];
1338
+ };
1339
+ var buildEditingContextSummary = (state, runtimeOptions) => {
1340
+ const targetKind = runtimeOptions?.editingTarget?.kind;
1341
+ if (targetKind === "table") {
1342
+ const table = selectCurrentTable(state);
1343
+ const rows = selectTableRows(state);
1344
+ const metadata = runtimeOptions?.editingTarget?.metadata;
1345
+ const focusContext = metadata && typeof metadata === "object" ? metadata.focusContext : null;
1346
+ if (!table) return null;
1347
+ const columns = Array.isArray(table.columns) ? table.columns : [];
1348
+ const columnSummaries = columns.length ? columns.map((c) => {
1349
+ const displayName = c.label || c.name;
1350
+ const type = c.type || "text";
1351
+ const requiredFlag = c.required ? "\u5FC5\u586B" : "\u53EF\u9009";
1352
+ const primaryFlag = c.isPrimary ? "\uFF0C\u4E3B\u5B57\u6BB5" : "";
1353
+ const optionsStr = Array.isArray(c.options) && c.options.length ? `\uFF0C\u53EF\u9009\u503C\uFF1A${c.options.join(" | ")}` : "";
1354
+ const descStr = c.description ? `\u3002\u8BF4\u660E\uFF1A${c.description}` : "";
1355
+ return `- ${c.name}\uFF08\u663E\u793A\u540D\uFF1A${displayName}\uFF0C\u7C7B\u578B\uFF1A${type}\uFF0C${requiredFlag}${primaryFlag}${optionsStr}${descStr}\uFF09`;
1356
+ }) : ["- (\u5F53\u524D\u8868\u5C1A\u672A\u5B9A\u4E49\u5B57\u6BB5)"];
1357
+ const sampleRows = Array.isArray(rows) ? rows.slice(0, 20) : [];
1358
+ const rowsPreview = sampleRows.length ? JSON.stringify(sampleRows, null, 2) : "(\u5F53\u524D\u8868\u6682\u65E0\u884C\u6570\u636E)";
1359
+ const tableTitle = table.displayName ?? table.tableId ?? "(\u672A\u547D\u540D\u8868)";
1360
+ const tableDesc = table.description ? `\u7528\u9014\u8BF4\u660E\uFF1A${table.description}` : "(\u6682\u65E0\u7528\u9014\u8BF4\u660E)";
1361
+ const tableTagsLine = Array.isArray(table.tags) && table.tags.length ? `- \u5173\u952E\u8BCD\u6807\u7B7E: ${table.tags.join(", ")}` : null;
1362
+ return [
1363
+ "\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1A\u4E00\u5F20\u6570\u636E\u8868\uFF08Editing Table\uFF09\u3002",
1364
+ `- \u8868 ID: ${table.tableId}`,
1365
+ `- \u663E\u793A\u540D\u79F0: ${tableTitle}`,
1366
+ `- ${tableDesc}`,
1367
+ ...tableTagsLine ? [tableTagsLine] : [],
1368
+ ...focusContext && typeof focusContext === "object" && "columnName" in focusContext ? [
1369
+ "",
1370
+ "\u5F53\u524D\u7126\u70B9\uFF08Focus Context\uFF09\uFF1A",
1371
+ `- \u5F53\u524D\u5355\u5143\u683C\u5217: ${String(focusContext.columnName ?? "(\u672A\u77E5\u5217)")}`,
1372
+ ...focusContext.rowTitle ? [`- \u5F53\u524D\u884C\u6807\u9898: ${String(focusContext.rowTitle)}`] : [],
1373
+ ...focusContext.rowIndex !== null && focusContext.rowIndex !== void 0 ? [`- \u5F53\u524D\u884C\u53F7: ${Number(focusContext.rowIndex) + 1}`] : [],
1374
+ ...focusContext.cellPreview ? [`- \u5F53\u524D\u5355\u5143\u683C\u5185\u5BB9\u9884\u89C8: ${String(focusContext.cellPreview)}`] : []
1375
+ ] : [],
1376
+ "",
1377
+ "\u5B57\u6BB5\u5B9A\u4E49\uFF08Field Schema\uFF09\uFF1A",
1378
+ ...columnSummaries,
1379
+ "",
1380
+ "\u3010\u7ED9 AI \u7684\u64CD\u4F5C\u6307\u5357 / \u975E\u7528\u6237\u539F\u8BDD\u3011",
1381
+ "\u5F53\u7528\u6237\u5E0C\u671B\u5728\u5F53\u524D\u8868\u4E2D\u201C\u65B0\u589E\u4E00\u884C / \u65B0\u589E\u8BB0\u5F55 / \u63D2\u5165\u4E00\u6761 / \u5E2E\u6211\u8BB0\u4E00\u6761 xxx\u201D\u65F6\uFF1A",
1382
+ "1. \u5FC5\u987B\u8C03\u7528\u5DE5\u5177 addTableRow\uFF08\u800C\u4E0D\u662F\u53EA\u5728\u56DE\u7B54\u4E2D\u53E3\u5934\u63CF\u8FF0\u8981\u65B0\u589E\u7684\u6570\u636E\uFF09\u3002",
1383
+ "2. \u8C03\u7528 addTableRow \u65F6\uFF1A",
1384
+ " - \u4F7F\u7528\u53C2\u6570 values\uFF08\u4E00\u4E2A\u5BF9\u8C61\uFF09\uFF0C\u5176\u4E2D\u6BCF\u4E2A key \u5FC5\u987B\u662F\u4E0A\u9762\u5B57\u6BB5\u540D\u4E4B\u4E00\uFF08name\uFF0C\u800C\u4E0D\u662F label\uFF09\u3002",
1385
+ ' - \u4F8B\u5982\uFF1A{"values":{"title":"\u4FEE Bug #123","status":"todo","note":"\u9AD8\u4F18\u5148\u7EA7"}}\u3002',
1386
+ " - \u5C3D\u91CF\u4ECE\u7528\u6237\u7684\u81EA\u7136\u8BED\u8A00\u4E2D\u63A8\u65AD\u5E76\u586B\u6EE1\u6240\u6709\u76F8\u5173\u5B57\u6BB5\uFF1B\u5BF9\u4E8E\u5FC5\u586B\u5B57\u6BB5\uFF08required=true\uFF09\u5C24\u5176\u8981\u6CE8\u610F\u3002",
1387
+ ' - \u7528\u6237\u6CA1\u6709\u63D0\u5230\u7684\u5B57\u6BB5\uFF0C\u53EF\u4EE5\u4F7F\u7528\u7A7A\u5B57\u7B26\u4E32 "" \u6216 null \u4F5C\u4E3A\u5360\u4F4D\u3002',
1388
+ " - \u7EDD\u4E0D\u8981\u4F20\u5165\u7A7A\u5BF9\u8C61 {} \u4F5C\u4E3A values\u3002",
1389
+ "",
1390
+ "\u4EE5\u4E0B\u662F\u90E8\u5206\u793A\u4F8B\u884C\uFF08\u6700\u591A 20 \u884C\uFF0C\u7528\u4E8E\u5E2E\u52A9\u4F60\u7406\u89E3\u5217\u542B\u4E49\uFF0C\u8BF7\u907F\u514D\u5728\u56DE\u7B54\u4E2D\u5B8C\u6574\u7C98\u8D34\u6574\u8868\uFF09\uFF1A",
1391
+ rowsPreview
1392
+ ].join("\n");
1393
+ }
1394
+ if (targetKind === "page" || targetKind === "article") {
1395
+ const page = getDocState();
1396
+ const metadata = runtimeOptions?.editingTarget?.metadata;
1397
+ const focusContext = metadata && typeof metadata === "object" ? metadata.focusContext : null;
1398
+ if (!page) return null;
1399
+ const title = page.title ?? "(\u672A\u547D\u540D\u9875\u9762)";
1400
+ return [
1401
+ "\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1A\u4E00\u4E2A\u9875\u9762 / \u6587\u7AE0\uFF08Editing Document\uFF09\u3002",
1402
+ `- \u6807\u9898: ${title}`,
1403
+ ...focusContext && typeof focusContext === "object" && "anchorPath" in focusContext ? [
1404
+ "",
1405
+ "\u5F53\u524D\u7126\u70B9\uFF08Focus Context\uFF09\uFF1A",
1406
+ `- \u5149\u6807\u662F\u5426\u6298\u53E0: ${Boolean(focusContext.isCollapsed) ? "\u662F" : "\u5426"}`,
1407
+ ...focusContext.blockType ? [`- \u5F53\u524D\u5757\u7C7B\u578B: ${String(focusContext.blockType)}`] : [],
1408
+ ...focusContext.selectedText ? [`- \u5F53\u524D\u9009\u4E2D\u6587\u672C: ${String(focusContext.selectedText)}`] : [],
1409
+ ...focusContext.anchorPath?.length ? [`- \u5F53\u524D\u951A\u70B9\u8DEF\u5F84: ${focusContext.anchorPath.join(" > ")}`] : []
1410
+ ] : [],
1411
+ "",
1412
+ "\u5982\u679C\u7528\u6237\u8981\u6C42\u4F60\u5BF9\u8FD9\u7BC7\u6587\u7AE0\u8FDB\u884C\u4FEE\u6539\u6216\u4F18\u5316\uFF0C\u8BF7\u5728\u56DE\u7B54\u4E2D\u660E\u786E\u6307\u51FA\u4FEE\u6539\u65B9\u5411\u3002",
1413
+ "\u5982\u679C\u5B58\u5728\u5F53\u524D\u9009\u533A\u6216\u5149\u6807\u4E0A\u4E0B\u6587\uFF0C\u4F18\u5148\u56F4\u7ED5\u8BE5\u5C40\u90E8\u4F4D\u7F6E\u505A\u5B9A\u70B9\u6539\u5199\uFF0C\u800C\u4E0D\u662F\u6CDB\u6CDB\u91CD\u5199\u6574\u7BC7\u6587\u6863\u3002"
1414
+ ].join("\n");
1415
+ }
1416
+ if (targetKind === "app") {
1417
+ const editingTarget = runtimeOptions?.editingTarget;
1418
+ const metadata = editingTarget?.metadata;
1419
+ const appId = editingTarget?.key ?? "(\u672A\u77E5 appId)";
1420
+ const title = editingTarget?.title ?? "(\u672A\u547D\u540D\u5E94\u7528)";
1421
+ const framework = typeof metadata?.framework === "string" ? metadata.framework : "worker";
1422
+ const appUrl = typeof metadata?.appUrl === "string" ? metadata.appUrl : null;
1423
+ const fileNames = Array.isArray(metadata?.fileNames) ? metadata.fileNames.filter((name) => typeof name === "string") : [];
1424
+ const externalImports = Array.isArray(metadata?.externalImports) ? metadata.externalImports.filter(
1425
+ (name) => typeof name === "string"
1426
+ ) : [];
1427
+ const sourceSummary = asOptionalTrimmedString(editingTarget?.summary) ?? null;
1428
+ const selectedNode = metadata && typeof metadata === "object" && metadata.selectedNode && typeof metadata.selectedNode === "object" ? metadata.selectedNode : null;
1429
+ const constraintPacks = buildAppConstraintPacks({
1430
+ framework,
1431
+ fileNames,
1432
+ externalImports
1433
+ });
1434
+ if (selectedNode && typeof selectedNode.cssPath === "string") {
1435
+ const tagName = typeof selectedNode.tagName === "string" && selectedNode.tagName ? selectedNode.tagName : "\u5143\u7D20";
1436
+ const cssPath = String(selectedNode.cssPath);
1437
+ const outerHTMLSnippet = typeof selectedNode.outerHTMLSnippet === "string" ? selectedNode.outerHTMLSnippet : "";
1438
+ const textSnippet = typeof selectedNode.textSnippet === "string" ? selectedNode.textSnippet : "";
1439
+ const noloLoc = typeof selectedNode.noloLoc === "string" ? selectedNode.noloLoc : "";
1440
+ constraintPacks.push({
1441
+ id: "selected-node",
1442
+ title: "\u7528\u6237\u9009\u4E2D\u8282\u70B9\uFF08\u5B9A\u70B9\u4FEE\u6539\uFF09",
1443
+ rules: [
1444
+ `\u7528\u6237\u5DF2\u5728\u9884\u89C8\u4E2D\u7CBE\u51C6\u9009\u4E2D\u4E00\u4E2A\u5143\u7D20\uFF1A<${tagName}> \uFF0CCSS \u8DEF\u5F84\uFF1A${cssPath}${noloLoc ? `\uFF0C\u6E90\u7801\u4F4D\u7F6E\uFF1A${noloLoc}` : ""}\u3002\u672C\u8F6E\u4FEE\u6539\u5FC5\u987B\u4EE5\u8FD9\u4E2A\u5143\u7D20\u4E3A\u4E2D\u5FC3\u3002`,
1445
+ `\u9009\u4E2D\u5143\u7D20\u7684 HTML \u7247\u6BB5\uFF08\u53EF\u80FD\u622A\u65AD\uFF09\uFF1A${outerHTMLSnippet}${textSnippet ? `\uFF1B\u53EF\u89C1\u6587\u672C\uFF1A${textSnippet}` : ""}\u3002\u5148\u5728\u6E90\u7801\u6587\u4EF6\u4E2D\u5B9A\u4F4D\u5230\u751F\u6210\u8FD9\u6BB5 HTML \u7684\u4EE3\u7801\uFF0C\u518D\u52A8\u624B\u3002`,
1446
+ "\u4FEE\u6539\u6536\u655B\u5728\u8BE5\u5143\u7D20\u53CA\u5176\u76F4\u63A5\u6837\u5F0F\u6765\u6E90\uFF08\u547D\u4E2D\u7684\u7EC4\u4EF6/\u7C7B/design token\uFF09\uFF1B\u8C03\u89C6\u89C9\u53C2\u6570\u4F18\u5148\u6539 token \u6216\u5C40\u90E8\u7EC4\u4EF6\u3002",
1447
+ "\u7981\u6B62\u91CD\u5199\u672A\u547D\u4E2D\u7684\u9875\u9762\u7ED3\u6784\u3001\u5E03\u5C40\u3001\u6587\u6848\u3001\u6570\u636E\u6D41\u6216\u5176\u4ED6\u7EC4\u4EF6\uFF1B\u4FDD\u6301\u672A\u547D\u4E2D\u6587\u4EF6\u4E0D\u53D8\u3002",
1448
+ "\u5982\u679C\u6309 CSS \u8DEF\u5F84\u548C HTML \u7247\u6BB5\u5728\u6E90\u7801\u4E2D\u627E\u4E0D\u5230\u5BF9\u5E94\u4F4D\u7F6E\uFF0C\u5148\u5411\u7528\u6237\u8BF4\u660E\u5E76\u8BF7\u7528\u6237\u91CD\u65B0\u9009\u62E9\uFF0C\u4E0D\u8981\u51ED\u731C\u6D4B\u5927\u8303\u56F4\u6539\u52A8\u3002"
1449
+ ]
1450
+ });
1451
+ }
1452
+ return [
1453
+ "\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1A\u4E00\u4E2A Web \u5E94\u7528\uFF08Editing App\uFF09\u3002",
1454
+ `- \u5E94\u7528 ID: ${appId}`,
1455
+ `- \u540D\u79F0: ${title}`,
1456
+ `- \u6280\u672F\u5F62\u6001: ${framework}`,
1457
+ ...appUrl ? [`- \u5F53\u524D\u8BBF\u95EE\u5730\u5740: ${appUrl}`] : [],
1458
+ ...fileNames.length ? [`- \u5F53\u524D\u6E90\u7801\u6587\u4EF6: ${fileNames.join(", ")}`] : ["- \u5F53\u524D\u6E90\u7801\u6587\u4EF6: (\u672A\u63D0\u4F9B\u591A\u6587\u4EF6\u6E05\u5355\uFF1B\u53EF\u80FD\u662F\u5355\u6587\u4EF6\u6E90\u7801\uFF0C\u4E5F\u53EF\u80FD\u53EA\u5269\u90E8\u7F72\u4EA7\u7269)"],
1459
+ ...externalImports.length ? [`- \u5F53\u524D\u4F9D\u8D56\u767D\u540D\u5355\u547D\u4E2D: ${externalImports.join(", ")}`] : [],
1460
+ ...sourceSummary ? ["", sourceSummary] : [],
1461
+ "",
1462
+ "\u3010\u7ED9 AI \u7684\u64CD\u4F5C\u6307\u5357 / \u975E\u7528\u6237\u539F\u8BDD\u3011",
1463
+ "1. \u7528\u6237\u8981\u6C42\u4FEE\u6539\u5F53\u524D\u5E94\u7528\u65F6\uFF0C\u5148\u8C03\u7528 appRead \u83B7\u53D6\u5F53\u524D\u4EE3\u7801/\u6587\u4EF6\uFF0C\u518D\u57FA\u4E8E\u73B0\u6709\u5B9E\u73B0\u4FEE\u6539\u3002",
1464
+ "2. \u5982\u679C appRead \u8FD4\u56DE workspaceRef/sourceFiles/sourceOmitted\uFF0C\u4E0D\u8981\u6574\u7AD9\u91CD\u5199\uFF1B\u4F7F\u7528 App Builder \u7684\u53D7\u9650 workspace \u6587\u4EF6\u5DE5\u5177\uFF1AappFileList=listFiles\u3001appFileSearch=searchFiles\u3001appFileRead=readFile\u3001appFileReplace=editFile\u3001appFileWrite=writeFile\u3002\u5148\u5B9A\u4F4D\u6587\u4EF6\u4E0E\u547D\u4E2D\u884C\uFF0C\u5927\u6587\u4EF6\u53EA\u8BFB\u53D6\u5FC5\u8981\u884C\u8303\u56F4\uFF1B\u6587\u5B57\u3001\u6837\u5F0F\u3001token\u3001\u5C40\u90E8\u903B\u8F91\u7B49\u5C0F\u6539\u52A8\u5FC5\u987B\u4F18\u5148\u7528 appFileReplace \u7CBE\u786E\u66FF\u6362\u552F\u4E00\u7247\u6BB5\uFF0C\u53EA\u6709\u65B0\u5EFA\u6587\u4EF6\u6216\u786E\u5B9E\u9700\u8981\u6574\u6587\u4EF6\u91CD\u5199\u65F6\u624D\u7528 appFileWrite\u3002",
1465
+ "3. \u5148\u8BC6\u522B\u5F53\u524D\u5E94\u7528\u662F\u5426\u5DF2\u6709 theme / tokens / design system\uFF1B\u5DF2\u6709\u5C31\u4F18\u5148\u6539\u8FD9\u5C42\uFF0C\u6CA1\u6709\u518D\u8865\u4E00\u5C42\u6700\u5C0F\u5171\u4EAB token\uFF0C\u518D\u57FA\u4E8E token \u8C03\u6574\u7EC4\u4EF6\u3002",
1466
+ "4. \u5982\u679C\u5F53\u524D\u5E94\u7528\u8FD8\u662F\u65E7\u5199\u6CD5\uFF1A\u89C6\u89C9\u503C\u6563\u843D\u5728\u7EC4\u4EF6\u786C\u7F16\u7801 style \u91CC\uFF0C\u800C\u7528\u6237\u53EA\u662F\u505A\u5B57\u4F53/\u989C\u8272/\u95F4\u8DDD\u7B49\u89C6\u89C9\u5FAE\u8C03\uFF0C\u9ED8\u8BA4\u5148\u628A\u547D\u4E2D\u7684\u89C6\u89C9\u503C\u62BD\u5230\u6700\u5C0F token \u5C42\uFF0C\u518D\u5B8C\u6210\u672C\u6B21\u4FEE\u6539\uFF1B\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u4E0D\u8981\u91CD\u6784\u3002",
1467
+ `5. \u91CD\u65B0\u90E8\u7F72\u5F53\u524D\u5E94\u7528\u65F6\uFF0CappDeploy \u5FC5\u987B\u7EE7\u7EED\u4F20\u540C\u4E00\u4E2A appId\uFF08${appId}\uFF09\uFF0C\u907F\u514D\u521B\u5EFA\u65B0\u5E94\u7528\u3002`,
1468
+ framework === "nolo-react" ? "6. \u5F53\u524D\u5E94\u7528\u662F Nolo React SSR\uFF0C\u4FEE\u6539\u65F6\u4F18\u5148\u4F7F\u7528\u53D7\u9650 app workspace \u6587\u4EF6\u5DE5\u5177\u64CD\u4F5C\u6E90\u7801\u5DE5\u4F5C\u533A\uFF0C\u7136\u540E appPreflight/appDeploy\uFF1B\u4E0D\u8981\u9000\u56DE react-spa \u6216\u5355\u6587\u4EF6 Worker\u3002" : framework === "react-spa" ? '6. \u5F53\u524D\u5E94\u7528\u662F React SPA\uFF0C\u4FEE\u6539\u65F6\u7EE7\u7EED\u6CBF\u7528 framework: "react-spa" + files\uFF0C\u4E0D\u8981\u9000\u56DE\u5355\u6587\u4EF6 Worker\u3002' : "6. \u5F53\u524D\u5E94\u7528\u76EE\u524D\u662F Worker \u5F62\u6001\uFF1B\u5982\u679C\u9700\u6C42\u53D8\u6210\u590D\u6742\u4EA4\u4E92\u6216\u56FE\u8868\uFF0C\u53EF\u4EE5\u8BC4\u4F30\u5347\u7EA7\u4E3A React SPA\u3002",
1469
+ ...fileNames.length ? [] : [
1470
+ "7. \u5F53\u524D\u6CA1\u6709\u6E90\u7801\u6587\u4EF6\u6E05\u5355\u65F6\uFF0C\u5FC5\u987B\u5148\u7528 appRead \u5224\u65AD\u8BFB\u5230\u7684\u662F\u53EF\u7EF4\u62A4\u6E90\u7801\u8FD8\u662F\u90E8\u7F72\u4EA7\u7269 / \u6253\u5305 bundle\u3002",
1471
+ "8. \u5982\u679C appRead \u8FD4\u56DE\u7684\u662F HTML \u58F3\u3001importmap\u3001\u538B\u7F29 bundle \u6216\u660E\u663E\u4E0D\u662F\u539F\u59CB\u6E90\u7801\u6587\u4EF6\uFF0C\u7981\u6B62\u5728\u672A\u544A\u77E5\u7528\u6237\u98CE\u9669\u7684\u60C5\u51B5\u4E0B\u6574\u7AD9\u91CD\u5199\uFF1B\u5E94\u5148\u8BF4\u660E\u201C\u5F53\u524D\u7F3A\u5C11\u539F\u59CB\u6E90\u7801\u5FEB\u7167\uFF0C\u7EE7\u7EED\u4FEE\u6539\u66F4\u50CF\u6574\u4F53\u91CD\u5EFA\u201D\uFF0C\u7B49\u7528\u6237\u786E\u8BA4\u540E\u518D\u7EE7\u7EED\u3002"
1472
+ ],
1473
+ "9. \u5982\u679C\u7528\u6237\u53EA\u662F\u8981\u8C03\u5B57\u4F53\u5927\u5C0F\u3001\u914D\u8272\u3001\u5706\u89D2\u3001\u9634\u5F71\u3001\u7559\u767D\u7B49\u89C6\u89C9\u7EC6\u8282\uFF0C\u9ED8\u8BA4\u4F18\u5148\u6539\u8BBE\u8BA1 token \u6216\u547D\u4E2D\u7684\u5C40\u90E8\u7EC4\u4EF6\uFF1B\u5BF9\u65E7\u5199\u6CD5\u5E94\u7528\u5219\u4F18\u5148\u505A\u6700\u5C0F token \u8FC1\u79FB\uFF0C\u4E0D\u8981\u53EA\u6539\u6563\u843D\u786C\u7F16\u7801\u3002",
1474
+ "10. \u6BCF\u6B21\u4FEE\u6539\u5B8C\u6210\u540E\uFF0C\u5148 appPreflight\uFF0C\u518D appDeploy\uFF1B\u5982\u679C\u5931\u8D25\uFF0C\u6309\u8FD4\u56DE issues \u5B9A\u70B9\u4FEE\u590D\u3002",
1475
+ "11. \u56DE\u590D\u7528\u6237\u65F6\u4F18\u5148\u8BF4\u660E\u505A\u4E86\u4EC0\u4E48\u53D8\u5316\u3001\u73B0\u5728\u5E94\u7528\u53EF\u4EE5\u600E\u4E48\u7528\uFF0C\u800C\u4E0D\u662F\u76F4\u63A5\u5806\u4EE3\u7801\u3002",
1476
+ ...formatAppConstraintPacks(constraintPacks)
1477
+ ].join("\n");
1478
+ }
1479
+ if (targetKind === "image" || targetKind === "file") {
1480
+ const editingTarget = runtimeOptions?.editingTarget;
1481
+ const metadata = editingTarget?.metadata;
1482
+ const title = editingTarget?.title ?? "(\u672A\u547D\u540D\u5BF9\u8C61)";
1483
+ const objectKey = editingTarget?.key ?? "(\u672A\u77E5 key)";
1484
+ const fileId = typeof metadata?.fileId === "string" ? metadata.fileId : null;
1485
+ const url = typeof metadata?.url === "string" ? metadata.url : null;
1486
+ const size = typeof metadata?.size === "number" ? metadata.size : null;
1487
+ return [
1488
+ `\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1A\u4E00\u4E2A${targetKind === "image" ? "\u56FE\u7247" : "\u6587\u4EF6"}\u5BF9\u8C61\uFF08Editing ${targetKind === "image" ? "Image" : "File"}\uFF09\u3002`,
1489
+ `- \u5BF9\u8C61 key: ${objectKey}`,
1490
+ `- \u6807\u9898: ${title}`,
1491
+ ...fileId ? [`- fileId: ${fileId}`] : [],
1492
+ ...url ? [`- \u8D44\u6E90\u5730\u5740: ${url}`] : [],
1493
+ ...size !== null ? [`- \u6587\u4EF6\u5927\u5C0F: ${size} bytes`] : [],
1494
+ "",
1495
+ "\u3010\u7ED9 AI \u7684\u64CD\u4F5C\u6307\u5357 / \u975E\u7528\u6237\u539F\u8BDD\u3011",
1496
+ targetKind === "image" ? "\u5F53\u524D\u9636\u6BB5\u4F18\u5148\u5E2E\u52A9\u7528\u6237\u7406\u89E3\u56FE\u7247\u5185\u5BB9\u3001\u63D0\u70BC\u91CD\u70B9\u3001\u547D\u540D\u5F52\u7C7B\u548C\u4E0B\u4E00\u6B65\u5904\u7406\u5EFA\u8BAE\u3002\u4E0D\u8981\u5047\u88C5\u5DF2\u7ECF\u5B8C\u6210\u590D\u6742\u56FE\u7247\u7F16\u8F91\u3002" : "\u5F53\u524D\u9636\u6BB5\u4F18\u5148\u5E2E\u52A9\u7528\u6237\u7406\u89E3\u6587\u4EF6\u7528\u9014\u3001\u63D0\u53D6\u5904\u7406\u601D\u8DEF\u3001\u7ED9\u51FA\u6574\u7406\u5EFA\u8BAE\u548C\u4E0B\u4E00\u6B65\u64CD\u4F5C\u5EFA\u8BAE\u3002\u4E0D\u8981\u5047\u88C5\u5DF2\u7ECF\u5B8C\u6574\u89E3\u6790\u6587\u4EF6\u5185\u5BB9\u3002"
1497
+ ].join("\n");
1498
+ }
1499
+ if (targetKind === "canvas_node") {
1500
+ return buildCanvasNodeEditingContextSummary(runtimeOptions);
1501
+ }
1502
+ return null;
1503
+ };
1504
+
1505
+ // packages/ai/agent/appWorkingMemory.ts
1506
+ var APP_TOOL_NAMES = /* @__PURE__ */ new Set([
1507
+ "appList",
1508
+ "appRead",
1509
+ "appDeploy",
1510
+ "appPreflight",
1511
+ "appDelete"
1512
+ ]);
1513
+ var contentToText = (content) => {
1514
+ if (!content) return "";
1515
+ if (typeof content === "string") return content;
1516
+ if (Array.isArray(content)) {
1517
+ return content.map((part) => "text" in part ? part.text ?? "" : "").join("\n");
1518
+ }
1519
+ return "";
1520
+ };
1521
+ var parseAppListEntries = (text) => text.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("- **") && line.includes("(appId:"));
1522
+ var buildRecentAppToolMemory = (messages, toolRuns) => {
1523
+ const messageById = new Map(messages.map((msg) => [msg.id, msg]));
1524
+ const recentRuns = [...toolRuns].filter((run) => APP_TOOL_NAMES.has(run.toolName)).sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0)).slice(0, 8);
1525
+ if (recentRuns.length === 0) return null;
1526
+ const lines = [
1527
+ "\u8FD9\u4E9B\u4FE1\u606F\u6765\u81EA\u5F53\u524D\u5BF9\u8BDD\u91CC\u6700\u8FD1\u7684 app \u5DE5\u5177\u8C03\u7528\uFF0C\u4E0D\u4F9D\u8D56\u53F3\u4FA7\u7F16\u8F91\u6001\u3002"
1528
+ ];
1529
+ const latestDeployLike = recentRuns.find(
1530
+ (run) => ["appDeploy", "appRead", "appPreflight"].includes(run.toolName)
1531
+ );
1532
+ if (latestDeployLike) {
1533
+ const input = latestDeployLike.input ?? {};
1534
+ const parts = [
1535
+ `- \u6700\u8FD1\u4E00\u6B21\u5173\u952E app \u64CD\u4F5C: ${latestDeployLike.toolName}`,
1536
+ typeof input.appId === "string" ? `appId=${input.appId}` : null,
1537
+ typeof input.name === "string" ? `name=${input.name}` : null,
1538
+ typeof input.framework === "string" ? `framework=${input.framework}` : null
1539
+ ].filter(Boolean);
1540
+ lines.push(parts.join("\uFF0C"));
1541
+ }
1542
+ const relatedMessages = recentRuns.map((run) => messageById.get(run.messageId)).filter((msg) => !!msg);
1543
+ const appListMessage = relatedMessages.find((msg) => msg.toolName === "appList");
1544
+ if (appListMessage) {
1545
+ const entries = parseAppListEntries(contentToText(appListMessage.content)).slice(0, 5);
1546
+ if (entries.length > 0) {
1547
+ lines.push("- \u6700\u8FD1\u4E00\u6B21 appList \u7ED3\u679C\uFF1A");
1548
+ lines.push(...entries.map((entry) => ` ${entry}`));
1549
+ }
1550
+ }
1551
+ const latestReadMessage = relatedMessages.find((msg) => msg.toolName === "appRead");
1552
+ if (latestReadMessage) {
1553
+ const text = contentToText(latestReadMessage.content);
1554
+ const appId = text.match(/- appId:\s*(.+)/)?.[1]?.trim();
1555
+ const url = text.match(/- 访问地址:\s*(.+)/)?.[1]?.trim();
1556
+ if (appId || url) {
1557
+ lines.push(
1558
+ [
1559
+ "- \u6700\u8FD1\u4E00\u6B21 appRead \u771F\u503C:",
1560
+ appId ? `appId=${appId}` : null,
1561
+ url ? `url=${url}` : null
1562
+ ].filter(Boolean).join("\uFF0C")
1563
+ );
1564
+ }
1565
+ }
1566
+ const latestPreflightRun = recentRuns.find((run) => run.toolName === "appPreflight");
1567
+ if (latestPreflightRun) {
1568
+ lines.push(
1569
+ [
1570
+ "- \u6700\u8FD1\u4E00\u6B21 appPreflight:",
1571
+ latestPreflightRun.status === "failed" ? "\u5931\u8D25" : "\u5DF2\u6267\u884C",
1572
+ latestPreflightRun.outputSummary ? `\u6458\u8981=${latestPreflightRun.outputSummary}` : null
1573
+ ].filter(Boolean).join("\uFF0C")
1574
+ );
1575
+ }
1576
+ const latestDeployMessage = relatedMessages.find((msg) => msg.toolName === "appDeploy");
1577
+ if (latestDeployMessage) {
1578
+ const text = contentToText(latestDeployMessage.content);
1579
+ const appId = text.match(/- appId:\s*(.+)/)?.[1]?.trim();
1580
+ const url = text.match(/- 访问地址:\s*(.+)/)?.[1]?.trim();
1581
+ if (appId || url) {
1582
+ lines.push(
1583
+ [
1584
+ "- \u6700\u8FD1\u4E00\u6B21 appDeploy \u7ED3\u679C:",
1585
+ appId ? `appId=${appId}` : null,
1586
+ url ? `url=${url}` : null
1587
+ ].filter(Boolean).join("\uFF0C")
1588
+ );
1589
+ }
1590
+ }
1591
+ lines.push(
1592
+ "- \u5982\u679C\u7528\u6237\u8BF4\u201C\u521A\u624D\u90A3\u4E2A app / \u90A3\u4E2A\u7F51\u7AD9\u201D\uFF0C\u4F18\u5148\u628A\u5B83\u7406\u89E3\u4E3A\u4E0A\u9762\u6700\u8FD1\u4E00\u6B21\u88AB\u8BFB\u53D6\u3001\u9884\u68C0\u6216\u90E8\u7F72\u7684\u5E94\u7528\uFF1B\u82E5\u4ECD\u6709\u6B67\u4E49\uFF0C\u518D\u7528 appList \u6216 appRead \u786E\u8BA4\u3002"
1593
+ );
1594
+ return lines.join("\n");
1595
+ };
1596
+
1597
+ // packages/ai/agent/streamAgentChatTurnUtils.ts
1598
+ var BROWSER_UNAVAILABLE_CORE_TOOLS = {
1599
+ queryModelUsage: true,
1600
+ createAgentAutomation: true,
1601
+ notifyUser: true
1602
+ };
1603
+ var getRuntimeCoreTools = () => {
1604
+ if (typeof window === "undefined") {
1605
+ return [...TOOL_PACKS.CORE];
1606
+ }
1607
+ return TOOL_PACKS.CORE.filter(
1608
+ (toolName) => !BROWSER_UNAVAILABLE_CORE_TOOLS[toolName]
1609
+ );
1610
+ };
1611
+ var isInlineVisualArtifactAgent = (agentConfig) => {
1612
+ const tags = Array.isArray(agentConfig.tags) ? agentConfig.tags : [];
1613
+ return tags.some(
1614
+ (tag) => typeof tag === "string" && ["inline-artifact", "streaming-ui"].includes(tag)
1615
+ );
1616
+ };
1617
+ var estimateTokensOfMessage = (msg) => {
1618
+ let content = "";
1619
+ if (typeof msg.content === "string") {
1620
+ content = msg.content;
1621
+ } else if (Array.isArray(msg.content)) {
1622
+ content = msg.content.map((p) => {
1623
+ if (p.type === "text") return p.text || "";
1624
+ if (p.type === "image_url") return "[image]";
1625
+ return "[non-text]";
1626
+ }).join("");
1627
+ } else if (msg.content && typeof msg.content === "object") {
1628
+ content = JSON.stringify(msg.content);
1629
+ }
1630
+ let extraTokens = 0;
1631
+ if (Array.isArray(msg.tool_calls)) {
1632
+ const toolsStr = JSON.stringify(msg.tool_calls);
1633
+ extraTokens = estimateTokenCount(toolsStr);
1634
+ }
1635
+ return estimateTokenCount(content) + extraTokens;
1636
+ };
1637
+ var classifyConversationLoad = (messages) => {
1638
+ const N = 20;
1639
+ if (!Array.isArray(messages) || messages.length === 0) return "light";
1640
+ const tail = messages.slice(-N);
1641
+ const tokenSamples = tail.map(estimateTokensOfMessage);
1642
+ if (tokenSamples.length === 0) return "light";
1643
+ const sum = tokenSamples.reduce((acc, v) => acc + v, 0);
1644
+ const avg = sum / tokenSamples.length;
1645
+ const sorted = [...tokenSamples].sort((a, b) => a - b);
1646
+ const p95 = sorted[Math.floor((sorted.length - 1) * 0.95)];
1647
+ if (p95 < 200 && avg < 120) {
1648
+ return "light";
1649
+ }
1650
+ if (p95 > 2e3 || avg > 1200) {
1651
+ return "heavy";
1652
+ }
1653
+ return "medium";
1654
+ };
1655
+ var compressOldToolResults = (messages, maxChars = 800) => {
1656
+ let lastToolCallAssistantIdx = -1;
1657
+ for (let i = messages.length - 1; i >= 0; i--) {
1658
+ if (messages[i].role === "assistant" && Array.isArray(messages[i].tool_calls) && messages[i].tool_calls.length > 0) {
1659
+ lastToolCallAssistantIdx = i;
1660
+ break;
1661
+ }
1662
+ }
1663
+ return messages.map((msg, idx) => {
1664
+ if (msg.role !== "tool") return msg;
1665
+ if (idx > lastToolCallAssistantIdx) return msg;
1666
+ const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
1667
+ if (content.length <= maxChars) return msg;
1668
+ return {
1669
+ ...msg,
1670
+ content: content.slice(0, maxChars) + `
1671
+ \u2026[\u622A\u65AD\uFF0C\u539F\u59CB\u957F\u5EA6 ${content.length} \u5B57\u7B26]`
1672
+ };
1673
+ });
1674
+ };
1675
+ var trimMessagesWithSummary = (messages, contextWindow, summaryTokenCount) => {
1676
+ const recentLoad = classifyConversationLoad(messages);
1677
+ const { rawMessageBudget, minTailTokens } = planContextUsage({
1678
+ contextWindow,
1679
+ summaryTokens: summaryTokenCount,
1680
+ recentLoad
1681
+ });
1682
+ if (!Array.isArray(messages) || messages.length === 0) return messages;
1683
+ let totalTokens = 0;
1684
+ let keepCount = 0;
1685
+ for (let i = messages.length - 1; i >= 0; i--) {
1686
+ const t = estimateTokensOfMessage(messages[i]);
1687
+ if (totalTokens + t > rawMessageBudget) break;
1688
+ totalTokens += t;
1689
+ keepCount++;
1690
+ }
1691
+ if (keepCount >= messages.length) {
1692
+ return messages;
1693
+ }
1694
+ if (totalTokens < minTailTokens) {
1695
+ const maxBudgetWithSlack = rawMessageBudget * 1.2;
1696
+ for (let i = messages.length - 1 - keepCount; i >= 0; i--) {
1697
+ const t = estimateTokensOfMessage(messages[i]);
1698
+ if (totalTokens + t > maxBudgetWithSlack) break;
1699
+ totalTokens += t;
1700
+ keepCount++;
1701
+ if (totalTokens >= minTailTokens) break;
1702
+ }
1703
+ }
1704
+ if (keepCount === 0 && messages.length > 0) {
1705
+ keepCount = Math.min(2, messages.length);
1706
+ }
1707
+ let cutIndex = messages.length - keepCount;
1708
+ if (cutIndex < 0) cutIndex = 0;
1709
+ while (cutIndex < messages.length && messages[cutIndex].role === "tool") {
1710
+ cutIndex++;
1711
+ }
1712
+ return messages.slice(cutIndex);
1713
+ };
1714
+ var createDbSliceTurnContextSource = (dispatch) => ({
1715
+ readRecord: async (dbKey) => {
1716
+ const result = await dispatch(read({ dbKey })).unwrap();
1717
+ return result ?? null;
1718
+ }
1719
+ });
1720
+ var joinMapValues = (map) => Array.from(map.values()).join("");
1721
+ var hasImageInMessages = (messages) => {
1722
+ if (!Array.isArray(messages)) return false;
1723
+ return messages.some((msg) => {
1724
+ const content = msg.content;
1725
+ if (!Array.isArray(content)) return false;
1726
+ return content.some(
1727
+ (part) => part && typeof part === "object" && part.type === "image_url" && part.image_url && typeof part.image_url.url === "string" && part.image_url.url.trim() !== ""
1728
+ );
1729
+ });
1730
+ };
1731
+ var REJECT_NO_VISION_MESSAGE = "\u5F53\u524D Agent \u4E0D\u652F\u6301\u56FE\u7247\u8F93\u5165\uFF0C\u8BF7\u6539\u7528\u6587\u672C\u6216\u6587\u6863\u3002";
1732
+ function shouldRejectImageInputForAgent(agentConfig, messages) {
1733
+ const agentHasVision = resolveAgentImageInputSupport(agentConfig);
1734
+ if (!agentHasVision && hasImageInMessages(messages)) {
1735
+ return REJECT_NO_VISION_MESSAGE;
1736
+ }
1737
+ return null;
1738
+ }
1739
+ var formatCurrentInputContext = (pendingFiles, currentInputMap) => {
1740
+ if (pendingFiles.length === 0 || currentInputMap.size === 0) {
1741
+ return joinMapValues(currentInputMap);
1742
+ }
1743
+ const relevantPendingFiles = pendingFiles.filter((file) => {
1744
+ const key = file.sourceDialogKey || file.dialogKey || file.pageKey;
1745
+ return key && currentInputMap.has(key);
1746
+ });
1747
+ if (relevantPendingFiles.length === 0) {
1748
+ return joinMapValues(currentInputMap);
1749
+ }
1750
+ const filesByGroup = /* @__PURE__ */ new Map();
1751
+ for (const file of relevantPendingFiles) {
1752
+ const groupKey = file.groupId || file.id;
1753
+ const group = filesByGroup.get(groupKey);
1754
+ if (group) {
1755
+ group.push(file);
1756
+ } else {
1757
+ filesByGroup.set(groupKey, [file]);
1758
+ }
1759
+ }
1760
+ let sourceCounter = 1;
1761
+ let output = "";
1762
+ filesByGroup.forEach((filesInGroup) => {
1763
+ const isGroup = filesInGroup.length > 1;
1764
+ const sourceName = isGroup ? filesInGroup[0].name.split(" (")[0] : filesInGroup[0].name;
1765
+ output += `--- Source ${sourceCounter}: "${sourceName}" ---
1766
+ `;
1767
+ filesInGroup.forEach((file) => {
1768
+ const key = file.sourceDialogKey || file.dialogKey || file.pageKey;
1769
+ if (!key) return;
1770
+ const content = currentInputMap.get(key);
1771
+ if (!content) return;
1772
+ if (isGroup) {
1773
+ output += `### Document: "${file.name}"
1774
+ ${content}
1775
+ `;
1776
+ } else {
1777
+ output += `${content}
1778
+ `;
1779
+ }
1780
+ });
1781
+ output += `--- End of Source ${sourceCounter} ---
1782
+
1783
+ `;
1784
+ sourceCounter++;
1785
+ });
1786
+ return output;
1787
+ };
1788
+ var validateAccessAndBalance = (agentConfig, state) => {
1789
+ const userBalance = selectCurrentUserBalance(state);
1790
+ const currentUserId = selectIdentityUserId(state);
1791
+ const isCustomApi = agentConfig.apiSource === "custom";
1792
+ const isCliApi = agentConfig.apiSource === "cli";
1793
+ const isDeviceLocalOwner = agentConfig.userId === "local" && !currentUserId;
1794
+ const isOwner = isDeviceLocalOwner || Boolean(currentUserId) && agentConfig.userId === currentUserId;
1795
+ if (!isOwner) {
1796
+ const hasWhitelist = Array.isArray(agentConfig.whitelist) && agentConfig.whitelist.length > 0;
1797
+ if (hasWhitelist) {
1798
+ const isUserInWhitelist = !!currentUserId && agentConfig.whitelist?.includes(currentUserId);
1799
+ if (!isUserInWhitelist) {
1800
+ return "\u60A8\u4E0D\u5728\u8BE5\u5E94\u7528\u7684\u767D\u540D\u5355\u4E2D\uFF0C\u65E0\u6CD5\u4F7F\u7528\u3002";
1801
+ }
1802
+ }
1803
+ }
1804
+ if (isCustomApi || isCliApi) {
1805
+ return null;
1806
+ }
1807
+ const SUBSCRIPTION_OAUTH_REFS = /* @__PURE__ */ new Set([
1808
+ "cursor",
1809
+ "chatgpt",
1810
+ "xai",
1811
+ "antigravity",
1812
+ "claude"
1813
+ ]);
1814
+ if (SUBSCRIPTION_OAUTH_REFS.has((agentConfig.apiKeyRef ?? "").trim().toLowerCase())) {
1815
+ return null;
1816
+ }
1817
+ const isPlatformApi = agentConfig.apiSource === "platform" || agentConfig.useServerProxy === true;
1818
+ if (isDeviceLocalOwner && !isPlatformApi) {
1819
+ return null;
1820
+ }
1821
+ if (typeof userBalance !== "number") {
1822
+ const hasSessionUser = Boolean(
1823
+ state?.auth?.currentUser?.userId
1824
+ );
1825
+ if (!currentUserId || !hasSessionUser) {
1826
+ return "\u8BF7\u767B\u5F55\u540E\u4F7F\u7528\u5E73\u53F0\u6A21\u578B\uFF0C\u6216\u6539\u7528\u672C\u5730\u81EA\u5B9A\u4E49/API/CLI Agent\u3002";
1827
+ }
1828
+ return "\u6B63\u5728\u83B7\u53D6\u7528\u6237\u4F59\u989D\uFF0C\u8BF7\u7A0D\u5019...";
1829
+ }
1830
+ const serverPrices = getModelPricing(agentConfig.provider || "", agentConfig.model);
1831
+ if (!serverPrices && !hasExplicitAgentPricing(agentConfig)) {
1832
+ return "\u65E0\u6CD5\u83B7\u53D6\u6A21\u578B\u5B9A\u4EF7\u4FE1\u606F\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
1833
+ }
1834
+ const prices = getPrices(agentConfig, serverPrices ?? null);
1835
+ const maxPrice = getFinalPrice(prices);
1836
+ if (userBalance < maxPrice) {
1837
+ return "\u4F59\u989D\u4E0D\u8DB3\uFF0C\u8BF7\u5145\u503C\u540E\u518D\u8BD5\u3002";
1838
+ }
1839
+ return null;
1840
+ };
1841
+ var fetchMemoryOverlayContext = async (state, agentConfig, userInput, dialogConfig) => {
1842
+ const token = typeof state?.auth?.currentToken === "string" ? state.auth.currentToken : null;
1843
+ const currentServer = typeof state?.settings?.currentServer === "string" ? state.settings.currentServer : null;
1844
+ const agentKey = asOptionalTrimmedString(agentConfig.dbKey) ?? "";
1845
+ if (!token || !currentServer || !agentKey) return null;
1846
+ const baseUrl = resolveToolBaseUrl(currentServer);
1847
+ if (!baseUrl) return null;
1848
+ const inputText = typeof userInput === "string" ? userInput : JSON.stringify(userInput ?? "");
1849
+ const spaceId = asOptionalTrimmedString(dialogConfig?.spaceId) ?? (state?.space?.viewMode === "all" ? void 0 : asOptionalTrimmedString(state?.space?.currentSpaceId));
1850
+ try {
1851
+ const response = await fetch(`${baseUrl}/api/memory/query`, {
1852
+ method: "POST",
1853
+ headers: {
1854
+ "Content-Type": "application/json",
1855
+ Authorization: `Bearer ${token}`
1856
+ },
1857
+ body: JSON.stringify({
1858
+ agentKey,
1859
+ userInput: inputText,
1860
+ ...spaceId ? { spaceId } : {}
1861
+ })
1862
+ });
1863
+ if (!response.ok) return null;
1864
+ const payload = await response.json().catch(() => null);
1865
+ return asOptionalTrimmedString(payload?.promptBlock) ?? null;
1866
+ } catch {
1867
+ return null;
1868
+ }
1869
+ };
1870
+ var buildStaticContexts = async (state, dispatch, agentConfig, dialogConfig, referenceContentCache) => {
1871
+ const keySets = await getFullChatContextKeys(
1872
+ state,
1873
+ dispatch,
1874
+ agentConfig,
1875
+ "",
1876
+ // 静态上下文不需要 userInput
1877
+ void 0
1878
+ // 静态上下文不需要 dialogConfig
1879
+ );
1880
+ const finalKeys = deduplicateContextKeys(keySets);
1881
+ const fetchReferences = (keys) => fetchReferenceContents(keys, dispatch, {
1882
+ format: "simplified_markdown",
1883
+ inlineMentionMeta: true,
1884
+ preloaded: referenceContentCache
1885
+ });
1886
+ const [botInstructionsMap, botKnowledgeMap] = await Promise.all([
1887
+ fetchReferences(finalKeys.botInstructionsContext),
1888
+ fetchReferences(finalKeys.botKnowledgeContext)
1889
+ ]);
1890
+ const globalPrompt = selectGlobalPrompt(state);
1891
+ const userTonePreset = selectUserTonePreset(state);
1892
+ const knowledgeCaptureLevel = selectKnowledgeCaptureLevel(state);
1893
+ const spaceContextLevel = selectSpaceContextLevel(state);
1894
+ const userRecentLimit = selectAiRecentContentLimit(state);
1895
+ const contextWindow = getModelContextWindow(agentConfig.model) || 128e3;
1896
+ const preloadPlan = resolveSpaceContextPreloadPlan(spaceContextLevel);
1897
+ const dynamicLimit = Math.floor(contextWindow * preloadPlan.preloadBudgetRatio / 150);
1898
+ const recentLimit = preloadPlan.includeRecentContent ? Math.max(3, Math.min(userRecentLimit, Math.max(3, dynamicLimit))) : 0;
1899
+ const turnContextSource = createDbSliceTurnContextSource(dispatch);
1900
+ let spaceContext = null;
1901
+ if (spaceContextLevel > 1) {
1902
+ const spaceLayer = await buildSpaceContextLayer({
1903
+ source: turnContextSource,
1904
+ spaceId: dialogConfig?.spaceId,
1905
+ recentContentLimit: recentLimit
1906
+ });
1907
+ spaceContext = spaceLayer ? spaceLayer.content.trim() : null;
1908
+ }
1909
+ const linkedSpaceIds = agentConfig.linkedSpaces || [];
1910
+ if (linkedSpaceIds.length > 0 && spaceContextLevel > 1) {
1911
+ const linkedSection = await buildLinkedSpacesSection({
1912
+ source: turnContextSource,
1913
+ linkedSpaceIds
1914
+ });
1915
+ if (linkedSection) {
1916
+ spaceContext = (spaceContext ?? "") + `
1917
+
1918
+ ${linkedSection}`;
1919
+ }
1920
+ }
1921
+ const dialogPolicyContext = dialogConfig?.category === PERSONALIZATION_DIALOG_CATEGORY ? buildPersonalizationDialogPolicyContext() : null;
1922
+ return {
1923
+ botInstructionsContext: joinMapValues(botInstructionsMap),
1924
+ botKnowledgeContext: joinMapValues(botKnowledgeMap),
1925
+ spaceContext,
1926
+ userGlobalPrompt: globalPrompt,
1927
+ userPolicyContext: [
1928
+ buildStaticUserPolicyContext({
1929
+ agentConfig,
1930
+ settingsRecord: {
1931
+ userTonePreset,
1932
+ knowledgeCaptureLevel,
1933
+ spaceContextLevel,
1934
+ enableReadCurrentSpace: spaceContextLevel > 1
1935
+ }
1936
+ }),
1937
+ dialogPolicyContext
1938
+ ].filter(Boolean).join("\n")
1939
+ };
1940
+ };
1941
+ var buildDynamicContexts = async (state, dispatch, agentConfig, userInput, runtimeOptions, referenceContentCache, dialogKey) => {
1942
+ let dialogSummary = null;
1943
+ let dialogConfig;
1944
+ if (dialogKey) {
1945
+ dialogConfig = selectById(state, dialogKey);
1946
+ if (dialogConfig?.summary) {
1947
+ dialogSummary = dialogConfig.summary;
1948
+ }
1949
+ }
1950
+ const keySets = await getFullChatContextKeys(
1951
+ state,
1952
+ dispatch,
1953
+ agentConfig,
1954
+ userInput,
1955
+ dialogConfig
1956
+ );
1957
+ const finalKeys = deduplicateContextKeys(keySets);
1958
+ const fetchReferences = (keys) => fetchReferenceContents(keys, dispatch, {
1959
+ format: "simplified_markdown",
1960
+ inlineMentionMeta: true,
1961
+ preloaded: referenceContentCache
1962
+ });
1963
+ const [currentInputMap, historyMap] = await Promise.all([
1964
+ fetchReferences(finalKeys.currentInputContext),
1965
+ fetchReferences(finalKeys.historyContext)
1966
+ ]);
1967
+ const pendingFiles = selectPendingFiles(state);
1968
+ const formattedCurrentInputContext = formatCurrentInputContext(
1969
+ pendingFiles,
1970
+ currentInputMap
1971
+ );
1972
+ const dialogId = dialogConfig?.id ?? null;
1973
+ const currentDialogMessages = selectAllMsgs(state, dialogId);
1974
+ const currentDialogMessageIds = new Set(currentDialogMessages.map((msg) => msg.id));
1975
+ const currentDialogToolRuns = getAllToolRuns().filter(
1976
+ (run) => currentDialogMessageIds.has(run.messageId)
1977
+ );
1978
+ const editingContext = buildEditingContextSummary(state, runtimeOptions);
1979
+ const appWorkingMemory = buildRecentAppToolMemory(
1980
+ currentDialogMessages,
1981
+ currentDialogToolRuns
1982
+ );
1983
+ const memoryOverlay = await fetchMemoryOverlayContext(
1984
+ state,
1985
+ agentConfig,
1986
+ userInput,
1987
+ dialogConfig
1988
+ );
1989
+ return {
1990
+ currentInputContext: formattedCurrentInputContext.trim() || null,
1991
+ historyContext: joinMapValues(historyMap),
1992
+ editingContext,
1993
+ appWorkingMemory,
1994
+ memoryOverlay,
1995
+ dialogSummary,
1996
+ referenceKeys: dialogConfig?.referenceKeys || []
1997
+ };
1998
+ };
1999
+ var mergeContexts = (staticCtx, dynamicCtx) => ({
2000
+ botInstructionsContext: staticCtx.botInstructionsContext || void 0,
2001
+ botKnowledgeContext: staticCtx.botKnowledgeContext || void 0,
2002
+ spaceContext: staticCtx.spaceContext || void 0,
2003
+ userGlobalPrompt: staticCtx.userGlobalPrompt || void 0,
2004
+ userPolicyContext: staticCtx.userPolicyContext || void 0,
2005
+ currentInputContext: dynamicCtx.currentInputContext,
2006
+ historyContext: dynamicCtx.historyContext || void 0,
2007
+ editingContext: dynamicCtx.editingContext,
2008
+ appWorkingMemory: dynamicCtx.appWorkingMemory,
2009
+ memoryOverlay: dynamicCtx.memoryOverlay,
2010
+ dialogSummary: dynamicCtx.dialogSummary,
2011
+ referenceKeys: dynamicCtx.referenceKeys
2012
+ });
2013
+ var mergeAgentToolsWithRuntime = (agentConfig, referencedTools, mentionedTools, runtimeOptions, state) => {
2014
+ const rawBaseTools = Array.isArray(agentConfig.tools) ? agentConfig.tools : [];
2015
+ const agentEnabledPacks = agentConfig?.enabledPacks;
2016
+ const isInlineArtifact = isInlineVisualArtifactAgent(agentConfig);
2017
+ const effectiveEnabledPacks = Array.isArray(agentEnabledPacks) && agentEnabledPacks.length > 0 ? agentEnabledPacks : isInlineArtifact ? agentEnabledPacks ?? [] : ["long-term-memory"];
2018
+ const expandedPackTools = expandEnabledPacks(
2019
+ effectiveEnabledPacks,
2020
+ rawBaseTools
2021
+ );
2022
+ const baseTools = canonicalizeToolNames(expandedPackTools);
2023
+ const requiredSkillTools = canonicalizeToolNames(
2024
+ agentConfig.referencedTools ?? []
2025
+ );
2026
+ const recommendedSkillTools = canonicalizeToolNames(
2027
+ agentConfig.recommendedSkillTools ?? []
2028
+ );
2029
+ const recommendedSkillHints = [
2030
+ ...new Set(asNonEmptyStringArray(agentConfig.recommendedSkillHints))
2031
+ ];
2032
+ const skillPromptPatches = [
2033
+ ...new Set(asNonEmptyStringArray(agentConfig.skillPromptPatches))
2034
+ ];
2035
+ const webPadded = applyDefaultWebToolPacks({
2036
+ toolNames: baseTools,
2037
+ skipWeb: isInlineVisualArtifactAgent(agentConfig)
2038
+ });
2039
+ const enhancedTools = /* @__PURE__ */ new Set([
2040
+ ...webPadded,
2041
+ ...isInlineVisualArtifactAgent(agentConfig) ? [] : getRuntimeCoreTools(),
2042
+ ...isInlineVisualArtifactAgent(agentConfig) ? [] : requiredSkillTools,
2043
+ ...isInlineVisualArtifactAgent(agentConfig) ? [] : canonicalizeToolNames(referencedTools),
2044
+ ...isInlineVisualArtifactAgent(agentConfig) ? [] : canonicalizeToolNames(mentionedTools)
2045
+ ]);
2046
+ const extraTools = isInlineVisualArtifactAgent(agentConfig) ? [] : canonicalizeToolNames(runtimeOptions?.extraTools ?? []);
2047
+ for (const t of extraTools) {
2048
+ enhancedTools.add(t);
2049
+ }
2050
+ if (!isInlineVisualArtifactAgent(agentConfig)) {
2051
+ const viewMode = state ? selectViewMode(state) : "categories";
2052
+ if (viewMode === "all") {
2053
+ enhancedTools.delete("search_workspace");
2054
+ enhancedTools.add("search_all_spaces");
2055
+ } else {
2056
+ enhancedTools.delete("search_all_spaces");
2057
+ enhancedTools.add("search_workspace");
2058
+ }
2059
+ }
2060
+ return {
2061
+ ...agentConfig,
2062
+ tools: applyDisabledTools(
2063
+ prioritizeToolNames(
2064
+ Array.from(enhancedTools),
2065
+ recommendedSkillTools
2066
+ ),
2067
+ agentConfig?.disabledTools
2068
+ ),
2069
+ recommendedSkillTools,
2070
+ recommendedSkillHints,
2071
+ skillPromptPatches
2072
+ };
2073
+ };
2074
+ var applyImageConfigRuntimeOverride = (agentConfig, runtimeOptions) => {
2075
+ const override = runtimeOptions?.imageConfigOverride;
2076
+ if (!override) {
2077
+ return agentConfig;
2078
+ }
2079
+ const baseImageConfig = agentConfig.imageConfig ?? {};
2080
+ return {
2081
+ ...agentConfig,
2082
+ ...override.imageModelOverride ? { model: override.imageModelOverride } : {},
2083
+ imageConfig: {
2084
+ ...baseImageConfig,
2085
+ ...override
2086
+ }
2087
+ };
2088
+ };
2089
+ var formatImageWaitHint = (range) => {
2090
+ if (!range || typeof range.min !== "number" || typeof range.max !== "number") {
2091
+ return void 0;
2092
+ }
2093
+ return `\u901A\u5E38\u9700\u8981 ${range.min}-${range.max} \u79D2`;
2094
+ };
2095
+ var resolveAgentImageModelIdentity = (agentConfig) => {
2096
+ let providerKey = (agentConfig.provider || "").toLowerCase();
2097
+ let modelName = agentConfig.model ?? "";
2098
+ if (modelName.includes("/")) {
2099
+ const slash = modelName.indexOf("/");
2100
+ if (!providerKey) providerKey = modelName.slice(0, slash);
2101
+ modelName = modelName.slice(slash + 1);
2102
+ }
2103
+ try {
2104
+ return {
2105
+ providerKey,
2106
+ modelConfig: getModelConfig(providerKey, modelName)
2107
+ };
2108
+ } catch {
2109
+ try {
2110
+ const detected = getProviderByModelName(modelName);
2111
+ if (!detected) {
2112
+ return { providerKey, modelConfig: null };
2113
+ }
2114
+ return {
2115
+ providerKey: detected,
2116
+ modelConfig: getModelConfig(detected, modelName)
2117
+ };
2118
+ } catch {
2119
+ return { providerKey, modelConfig: null };
2120
+ }
2121
+ }
2122
+ };
2123
+ var EXPLICIT_IMAGE_GENERATION_TOOL_NAMES = /* @__PURE__ */ new Set([
2124
+ "openAIGptImage",
2125
+ "openAIGptImageGenerate",
2126
+ "openAIGptImageEdit",
2127
+ "chatgptWebImageGenerate",
2128
+ "geminiFlashImage",
2129
+ "geminiProImagePreview"
2130
+ ]);
2131
+ var agentUsesExplicitImageGenerationTool = (agentConfig) => {
2132
+ const toolNames = Array.isArray(agentConfig.tools) ? agentConfig.tools : Array.isArray(agentConfig.toolNames) ? agentConfig.toolNames : [];
2133
+ return toolNames.some(
2134
+ (name) => typeof name === "string" && EXPLICIT_IMAGE_GENERATION_TOOL_NAMES.has(name.trim())
2135
+ );
2136
+ };
2137
+ var resolveImageGenerationStreamingState = (agentConfig, args) => {
2138
+ const { modelConfig } = resolveAgentImageModelIdentity(agentConfig);
2139
+ const hasImageOutput = !!(modelConfig?.hasImageOutput ?? modelConfig?.supportsImageOutput) || agentConfig.imageConfig?.enabled === true || agentUsesExplicitImageGenerationTool(agentConfig);
2140
+ if (!hasImageOutput) {
2141
+ return void 0;
2142
+ }
2143
+ const currentProfile = modelConfig?.imageGenerationProfiles?.find(
2144
+ (profile) => profile.imageModel === modelConfig.name
2145
+ );
2146
+ const usesWebImageTool = agentUsesExplicitImageGenerationTool(agentConfig) && (Array.isArray(agentConfig.tools) ? agentConfig.tools : []).includes("chatgptWebImageGenerate");
2147
+ return {
2148
+ kind: "image_generation",
2149
+ stage: args?.stage ?? args?.previous?.stage ?? "submitted",
2150
+ startedAt: args?.previous?.startedAt ?? Date.now(),
2151
+ waitHint: formatImageWaitHint(modelConfig?.imageGenerationWaitTimeSeconds) ?? (usesWebImageTool ? "\u7F51\u9875\u751F\u56FE\u901A\u5E38\u9700\u8981 30 \u79D2\u5230\u51E0\u5206\u949F\uFF0C\u5207\u6362\u5BF9\u8BDD\u4E0D\u4F1A\u4E2D\u65AD" : "\u901A\u5E38\u9700\u8981\u51E0\u5341\u79D2"),
2152
+ profileLabel: currentProfile?.label
2153
+ };
2154
+ };
2155
+
2156
+ // packages/ai/agent/persistMessageWithFixedId.ts
2157
+ async function persistMessageWithFixedId(dispatch, message) {
2158
+ dispatch(addUserMessage(message));
2159
+ const { controller, ...messageToWrite } = message;
2160
+ try {
2161
+ const writeRequest = dispatch(
2162
+ write({
2163
+ data: {
2164
+ ...messageToWrite,
2165
+ type: "msg" /* MSG */
2166
+ },
2167
+ customKey: message.dbKey
2168
+ })
2169
+ );
2170
+ if (writeRequest && typeof writeRequest.unwrap === "function") {
2171
+ await writeRequest.unwrap();
2172
+ return;
2173
+ }
2174
+ await writeRequest;
2175
+ } catch (error) {
2176
+ console.error(
2177
+ "[persistMessageWithFixedId] Failed to persist fixed-id message:",
2178
+ error
2179
+ );
2180
+ }
2181
+ }
2182
+
2183
+ // packages/ai/agent/serverOrigin.ts
2184
+ var normalizeServerOrigin = (base) => {
2185
+ try {
2186
+ return new URL(base).origin.replace(/\/+$/, "");
2187
+ } catch {
2188
+ return null;
2189
+ }
2190
+ };
2191
+
2192
+ // packages/app/utils/desktopAgentRuntimeTurnClient.ts
2193
+ var DESKTOP_AGENT_CONFIG_SNAPSHOT_BUILD_FAILED = "desktop_agent_config_snapshot_invalid";
2194
+ function buildDesktopAgentRuntimeTurnBody(args) {
2195
+ const continueDialogId = asTrimmedString(args.continueDialogId);
2196
+ let agentConfigSnapshot;
2197
+ if (args.agentConfigSnapshot && typeof args.agentConfigSnapshot === "object") {
2198
+ const built = buildDesktopAgentRuntimeAgentConfigSnapshot(
2199
+ args.agentConfigSnapshot,
2200
+ args.agentRef
2201
+ );
2202
+ if (!built) {
2203
+ throw new Error(DESKTOP_AGENT_CONFIG_SNAPSHOT_BUILD_FAILED);
2204
+ }
2205
+ agentConfigSnapshot = built;
2206
+ }
2207
+ let dialogHistorySnapshot;
2208
+ if (args.dialogHistorySnapshot && typeof args.dialogHistorySnapshot === "object") {
2209
+ dialogHistorySnapshot = args.dialogHistorySnapshot;
2210
+ } else if (Array.isArray(args.dialogMessages) && continueDialogId) {
2211
+ dialogHistorySnapshot = buildDesktopAgentRuntimeDialogHistorySnapshot({
2212
+ dialogId: continueDialogId,
2213
+ messages: args.dialogMessages,
2214
+ currentInput: args.input
2215
+ }) ?? void 0;
2216
+ }
2217
+ const body = {
2218
+ agentRef: args.agentRef,
2219
+ input: args.input,
2220
+ ...args.runtimeContext ? { runtimeContext: args.runtimeContext } : {},
2221
+ ...continueDialogId ? { continueDialogId } : {},
2222
+ ...continueDialogId && asTrimmedString(args.dialogKey) ? { dialogKey: asTrimmedString(args.dialogKey) } : {},
2223
+ ...args.cwd ? { cwd: args.cwd } : {},
2224
+ ...args.restrictShellToWorkspace ? { restrictShellToWorkspace: true } : {},
2225
+ ...args.workspaceToolsHint ? { workspaceToolsHint: true } : {},
2226
+ ...agentConfigSnapshot ? { agentConfigSnapshot } : {},
2227
+ ...dialogHistorySnapshot ? { dialogHistorySnapshot } : {}
2228
+ };
2229
+ assertDesktopAgentRuntimeTurnBodyHasNoRawSecrets(body);
2230
+ return body;
2231
+ }
2232
+ function normalizeDesktopAgentRuntimeTurnError(data) {
2233
+ return typeof data?.error === "string" ? data.error : "Failed to run desktop agent runtime turn";
2234
+ }
2235
+ async function* runDesktopAgentRuntimeTurnStream({
2236
+ fetchImpl = fetch,
2237
+ signal,
2238
+ ...args
2239
+ }) {
2240
+ try {
2241
+ if (signal?.aborted) {
2242
+ yield { type: "error", error: "The operation was aborted." };
2243
+ return;
2244
+ }
2245
+ const response = await fetchImpl("/api/desktop/agent-runtime/turn", {
2246
+ method: "POST",
2247
+ headers: { "Content-Type": "application/json" },
2248
+ body: JSON.stringify(buildDesktopAgentRuntimeTurnBody(args)),
2249
+ signal
2250
+ });
2251
+ if (!response.ok) {
2252
+ const data = await response.clone().json().catch(() => null);
2253
+ yield {
2254
+ type: "error",
2255
+ error: data ? normalizeDesktopAgentRuntimeTurnError(data) : `HTTP ${response.status}: ${response.statusText}`
2256
+ };
2257
+ return;
2258
+ }
2259
+ const contentType = response.headers.get("content-type") ?? "";
2260
+ if (!contentType.includes("text/event-stream")) {
2261
+ const data = await response.json().catch(() => ({}));
2262
+ if (data?.ok === false) {
2263
+ yield { type: "error", error: normalizeDesktopAgentRuntimeTurnError(data) };
2264
+ } else if (data?.result) {
2265
+ yield { type: "done", result: data.result };
2266
+ } else {
2267
+ yield { type: "error", error: "Desktop runtime response did not include a result" };
2268
+ }
2269
+ return;
2270
+ }
2271
+ const reader = response.body?.getReader();
2272
+ if (!reader) {
2273
+ yield { type: "error", error: "Response body reader not available" };
2274
+ return;
2275
+ }
2276
+ const decoder = new TextDecoder();
2277
+ let buffer = "";
2278
+ const readLine = (line) => {
2279
+ const trimmed = line.trim();
2280
+ if (!trimmed || !trimmed.startsWith("data: ")) return null;
2281
+ try {
2282
+ return JSON.parse(trimmed.slice(6));
2283
+ } catch (e) {
2284
+ console.error("[desktop-client] Failed to parse stream line:", trimmed, e);
2285
+ return null;
2286
+ }
2287
+ };
2288
+ try {
2289
+ while (true) {
2290
+ if (signal?.aborted) {
2291
+ yield { type: "error", error: "The operation was aborted." };
2292
+ return;
2293
+ }
2294
+ const { done, value } = await readStreamChunk(reader, { signal });
2295
+ if (done) break;
2296
+ buffer += decoder.decode(value, { stream: true });
2297
+ const lines = buffer.split("\n");
2298
+ buffer = lines.pop() || "";
2299
+ for (const line of lines) {
2300
+ const event2 = readLine(line);
2301
+ if (event2) yield event2;
2302
+ }
2303
+ }
2304
+ buffer += decoder.decode();
2305
+ const event = readLine(buffer);
2306
+ if (event) yield event;
2307
+ } catch (error) {
2308
+ if (isAbortError(error) || signal?.aborted) {
2309
+ yield { type: "error", error: "The operation was aborted." };
2310
+ return;
2311
+ }
2312
+ yield {
2313
+ type: "error",
2314
+ error: toErrorMessage(error)
2315
+ };
2316
+ } finally {
2317
+ try {
2318
+ await reader.cancel();
2319
+ } catch {
2320
+ }
2321
+ try {
2322
+ reader.releaseLock();
2323
+ } catch {
2324
+ }
2325
+ }
2326
+ } catch (error) {
2327
+ if (isAbortError(error) || signal?.aborted) {
2328
+ yield { type: "error", error: "The operation was aborted." };
2329
+ return;
2330
+ }
2331
+ yield {
2332
+ type: "error",
2333
+ error: toErrorMessage(error)
2334
+ };
2335
+ }
2336
+ }
2337
+
2338
+ // packages/ai/agent/streamTurnMessageBuild.ts
2339
+ var buildMessageMetadata = (agentConfig) => {
2340
+ const rawName = asTrimmedString(agentConfig?.name);
2341
+ return {
2342
+ agentKey: agentConfig.dbKey,
2343
+ cybotKey: agentConfig.dbKey,
2344
+ ...rawName ? { agentName: rawName } : {}
2345
+ };
2346
+ };
2347
+ var buildDesktopRuntimeToolMessagesForUi = ({
2348
+ dialogId,
2349
+ turnMessages
2350
+ }) => {
2351
+ if (!Array.isArray(turnMessages) || turnMessages.length === 0) return [];
2352
+ const toolNamesByCallId = /* @__PURE__ */ new Map();
2353
+ const activityByCallId = /* @__PURE__ */ new Map();
2354
+ const projected = [];
2355
+ for (const message of turnMessages) {
2356
+ if (Array.isArray(message?.tool_calls)) {
2357
+ for (const call of message.tool_calls) {
2358
+ const callId = asTrimmedString(call?.id);
2359
+ const toolName2 = asTrimmedString(call?.function?.name);
2360
+ if (callId && toolName2) toolNamesByCallId.set(callId, toolName2);
2361
+ if (callId) {
2362
+ try {
2363
+ const args = typeof call?.function?.arguments === "string" ? JSON.parse(call.function.arguments) : call?.function?.arguments;
2364
+ const rawActivity = isRecord(args) ? args._activity : void 0;
2365
+ const activity2 = isRecord(rawActivity) ? rawActivity : void 0;
2366
+ const legacyTitle = typeof activity2?.title === "string" && activity2.title.trim();
2367
+ const action = activity2?.action;
2368
+ const actionTitle = isRecord(action) && typeof action.title === "string" && action.title.trim();
2369
+ const plan = activity2?.plan;
2370
+ const hasPlan = isRecord(plan) && Array.isArray(plan.phases) && plan.phases.some((phase) => {
2371
+ if (!isRecord(phase)) return false;
2372
+ return typeof phase.title === "string" && !!phase.title.trim();
2373
+ });
2374
+ if (activity2 && (legacyTitle || actionTitle || hasPlan)) {
2375
+ activityByCallId.set(callId, args._activity);
2376
+ }
2377
+ } catch {
2378
+ }
2379
+ }
2380
+ }
2381
+ continue;
2382
+ }
2383
+ if (message?.role !== "tool") continue;
2384
+ const toolCallId = asTrimmedString(message.tool_call_id);
2385
+ const metadata = asRecordOrEmpty(message.tool_result_metadata);
2386
+ const metadataToolName = asTrimmedString(metadata.toolName);
2387
+ const toolName = metadataToolName || (toolCallId ? toolNamesByCallId.get(toolCallId) : "") || "tool";
2388
+ const { key: dbKey, messageId } = createDialogMessageKeyAndId(dialogId);
2389
+ const resultActivity = metadata.activity && typeof metadata.activity === "object" ? metadata.activity : void 0;
2390
+ const callActivity = toolCallId ? activityByCallId.get(toolCallId) : void 0;
2391
+ const activity = resultActivity || callActivity;
2392
+ const mergedMetadata = activity ? { ...metadata, activity } : metadata;
2393
+ projected.push({
2394
+ id: messageId,
2395
+ dialogId,
2396
+ dbKey,
2397
+ role: "tool",
2398
+ content: projectDesktopToolUiContent({
2399
+ toolName,
2400
+ content: typeof message.content === "string" ? message.content : "",
2401
+ metadata: mergedMetadata
2402
+ }),
2403
+ isStreaming: false,
2404
+ toolName,
2405
+ ...toolCallId ? { toolCallId } : {},
2406
+ ...Object.keys(mergedMetadata).length ? { metadata: mergedMetadata } : {}
2407
+ });
2408
+ }
2409
+ return projected;
2410
+ };
2411
+ var toolMessageWillPersist = (toolMsg) => {
2412
+ const content = toolMsg?.content;
2413
+ if (typeof content === "string") return content.trim().length > 0;
2414
+ return Array.isArray(content) && content.length > 0;
2415
+ };
2416
+ var shouldUseDesktopLocalRuntime = (agentConfig) => {
2417
+ if (!getIsDesktopApp()) return false;
2418
+ return agentConfig?.apiSource !== "cli";
2419
+ };
2420
+ var readCurrentDesktopMachineId = () => {
2421
+ const fromProcess = typeof process !== "undefined" ? (process.env?.NOLO_CURRENT_MACHINE_ID || process.env?.NOLO_MACHINE_ID || "").trim() : "";
2422
+ if (fromProcess) return fromProcess;
2423
+ const w = typeof globalThis !== "undefined" && globalThis.window ? globalThis.window : null;
2424
+ const fromWindow = asTrimmedString(w?.__NOLO_CURRENT_MACHINE_ID__) || asTrimmedString(w?.__NOLO_MACHINE_ID__);
2425
+ return fromWindow;
2426
+ };
2427
+ var resolveRemoteBoundMachineId = (machineId) => {
2428
+ if (!machineId || !getIsDesktopApp()) return machineId;
2429
+ const currentMachineId = readCurrentDesktopMachineId();
2430
+ return currentMachineId && currentMachineId === machineId ? "" : machineId;
2431
+ };
2432
+ var resolveWebAgentRuntimeToolSurface = (agentConfig, state) => {
2433
+ const toolSurface = resolveRuntimeToolSurfaceForAgent({
2434
+ explicitToolNames: Array.isArray(agentConfig.tools) ? agentConfig.tools : [],
2435
+ currentUserId: selectIdentityUserId(state),
2436
+ agentOwnerId: typeof agentConfig.userId === "string" ? agentConfig.userId : null,
2437
+ agentKey: agentConfig.dbKey ?? agentConfig.agentKey,
2438
+ isPublic: agentConfig.isPublic === true,
2439
+ sharingLevel: typeof agentConfig.sharingLevel === "string" ? agentConfig.sharingLevel : null,
2440
+ runtimeHost: "web"
2441
+ });
2442
+ return {
2443
+ ...agentConfig,
2444
+ tools: toolSurface.finalToolNames,
2445
+ runtimeToolSurface: toolSurface
2446
+ };
2447
+ };
2448
+ var formatMachineAgentRunError = async (response) => {
2449
+ const errorText = await response.text();
2450
+ let payload = null;
2451
+ try {
2452
+ payload = errorText ? JSON.parse(errorText) : null;
2453
+ } catch {
2454
+ payload = null;
2455
+ }
2456
+ const reason = typeof payload?.reason === "string" ? payload.reason : "";
2457
+ if (response.status === 409) {
2458
+ if (reason === "bound_machine_unavailable") {
2459
+ return "\u7ED1\u5B9A\u7684\u7535\u8111\u4E0D\u5728\u7EBF\u3002\u8BF7\u786E\u8BA4\u8FD9\u53F0\u7535\u8111\u5DF2\u5F00\u673A\u5E76\u91CD\u65B0\u8FD0\u884C\u8FDE\u63A5\u547D\u4EE4\u3002";
2460
+ }
2461
+ if (reason === "bound_machine_owner_mismatch") {
2462
+ return "\u8FD9\u53F0\u7535\u8111\u662F\u5728\u7EBF\u7684\uFF0C\u4F46\u5F53\u524D\u8D26\u53F7\u548C Agent \u7ED1\u5B9A\u8D26\u53F7\u4E0D\u4E00\u81F4\u3002\u8BF7\u91CD\u65B0\u7ED1\u5B9A Agent\uFF0C\u6216\u5728\u7ED1\u5B9A\u8D26\u53F7\u4E0B\u91CD\u65B0\u8FDE\u63A5\u8FD9\u53F0\u7535\u8111\u3002";
2463
+ }
2464
+ if (reason === "connector_offline") {
2465
+ return "\u7535\u8111\u5728\u7EBF\uFF0C\u4F46\u8FDE\u63A5\u5668\u672A\u8FDE\u63A5\u3002\u8BF7\u5728\u8FD9\u53F0\u7535\u8111\u4E0A\u91CD\u65B0\u8FD0\u884C\u8FDE\u63A5\u547D\u4EE4\u540E\u518D\u8BD5\u3002";
2466
+ }
2467
+ if (reason === "missing_capability") {
2468
+ return "\u8FD9\u53F0\u7535\u8111\u6CA1\u6709\u5BF9\u5E94\u7684 CLI \u80FD\u529B\u3002\u8BF7\u5B89\u88C5\u5BF9\u5E94 CLI\uFF0C\u6216\u628A Agent \u7ED1\u5B9A\u5230\u53E6\u4E00\u53F0\u7535\u8111\u3002";
2469
+ }
2470
+ }
2471
+ const message = asOptionalTrimmedString(payload?.message) ?? asOptionalTrimmedString(payload?.error) ?? errorText.trim();
2472
+ return message || `Machine agent run failed (${response.status})`;
2473
+ };
2474
+ var normalizeThreadMetadataPatch = (value) => {
2475
+ if (!isRecord(value)) return null;
2476
+ const record = value;
2477
+ const changes = {};
2478
+ const threadKind = asOptionalTrimmedString(record.threadKind);
2479
+ if (threadKind) {
2480
+ changes.threadKind = threadKind;
2481
+ }
2482
+ const presentationIntent = asOptionalTrimmedString(record.presentationIntent);
2483
+ if (presentationIntent) {
2484
+ changes.presentationIntent = presentationIntent;
2485
+ }
2486
+ return Object.keys(changes).length > 0 ? changes : null;
2487
+ };
2488
+ var patchDialogThreadMetadata = async (dispatch, dialogKey, metadata) => {
2489
+ const changes = normalizeThreadMetadataPatch(metadata);
2490
+ if (!changes) return;
2491
+ await dispatch(
2492
+ patch({
2493
+ dbKey: dialogKey,
2494
+ changes
2495
+ })
2496
+ ).unwrap?.();
2497
+ };
2498
+ var patchDialogActiveAgent = async (dispatch, dialogKey, agentKey) => {
2499
+ if (typeof agentKey !== "string" || !agentKey.trim()) return;
2500
+ await dispatch(
2501
+ patch({
2502
+ dbKey: dialogKey,
2503
+ changes: {
2504
+ primaryAgentKey: agentKey.trim()
2505
+ }
2506
+ })
2507
+ ).unwrap?.();
2508
+ };
2509
+ function appendCliCapabilityWarnings(content, warnings) {
2510
+ if (!warnings.length) return content;
2511
+ const warningBlock = `
2512
+
2513
+ [CLI \u80FD\u529B\u63D0\u793A]
2514
+ ${warnings.map((warning) => `- ${warning}`).join("\n")}`;
2515
+ return `${content}${warningBlock}`;
2516
+ }
2517
+
2518
+ // packages/ai/agent/streamTurnStreamConsumer.ts
2519
+ async function readAgentRunStreamChunk(reader, signal, isAborted) {
2520
+ if (isAborted() || signal?.aborted) {
2521
+ void reader.cancel().catch(() => {
2522
+ });
2523
+ throw new DOMException("The operation was aborted.", "AbortError");
2524
+ }
2525
+ if (!signal) {
2526
+ return reader.read();
2527
+ }
2528
+ let settled = false;
2529
+ return new Promise((resolve, reject) => {
2530
+ const finish = (cb) => {
2531
+ if (settled) return;
2532
+ settled = true;
2533
+ signal.removeEventListener("abort", onAbort);
2534
+ cb();
2535
+ };
2536
+ const onAbort = () => {
2537
+ void reader.cancel().catch(() => {
2538
+ });
2539
+ finish(
2540
+ () => reject(new DOMException("The operation was aborted.", "AbortError"))
2541
+ );
2542
+ };
2543
+ signal.addEventListener("abort", onAbort);
2544
+ reader.read().then(
2545
+ (result) => finish(() => resolve(result)),
2546
+ (err) => finish(() => reject(err))
2547
+ );
2548
+ });
2549
+ }
2550
+ async function consumeAgentRunStream(handlers) {
2551
+ const {
2552
+ reader,
2553
+ decoder,
2554
+ parseChunk,
2555
+ onPayload,
2556
+ isDoneEvent,
2557
+ isAborted,
2558
+ signal,
2559
+ onAbort
2560
+ } = handlers;
2561
+ let sawDone = false;
2562
+ try {
2563
+ while (true) {
2564
+ let done;
2565
+ let value;
2566
+ try {
2567
+ ({ done, value } = await readAgentRunStreamChunk(
2568
+ reader,
2569
+ signal,
2570
+ isAborted
2571
+ ));
2572
+ } catch (error) {
2573
+ if (isAbortError(error) || isAborted() || signal?.aborted) {
2574
+ await onAbort();
2575
+ return { outcome: "aborted" };
2576
+ }
2577
+ throw error;
2578
+ }
2579
+ if (isAborted() || signal?.aborted) {
2580
+ await onAbort();
2581
+ return { outcome: "aborted" };
2582
+ }
2583
+ if (done) {
2584
+ return { outcome: "streamEnded", sawDone };
2585
+ }
2586
+ const payloads = parseChunk(
2587
+ decoder.decode(value, { stream: true })
2588
+ );
2589
+ for (const payload of payloads) {
2590
+ if (isAborted() || signal?.aborted) {
2591
+ await onAbort();
2592
+ return { outcome: "aborted" };
2593
+ }
2594
+ const directive = await onPayload(payload);
2595
+ if (directive?.reject !== void 0) {
2596
+ return { outcome: "rejected", message: directive.reject };
2597
+ }
2598
+ if (directive?.abort) {
2599
+ await onAbort();
2600
+ return { outcome: "aborted" };
2601
+ }
2602
+ if (isDoneEvent(payload)) {
2603
+ sawDone = true;
2604
+ }
2605
+ }
2606
+ }
2607
+ } catch (error) {
2608
+ if (isAbortError(error) || isAborted() || signal?.aborted) {
2609
+ await onAbort();
2610
+ return { outcome: "aborted" };
2611
+ }
2612
+ throw error;
2613
+ }
2614
+ }
2615
+
2616
+ // packages/ai/llm/isResponseAPIModel.ts
2617
+ var isResponseAPIModel = (agentConfig) => {
2618
+ if (agentConfig.provider !== "openai") return false;
2619
+ if (agentConfig.endpointKey === "responses") return true;
2620
+ if (!agentConfig.model) return false;
2621
+ try {
2622
+ return getModelConfig("openai", agentConfig.model).endpointKey === "responses";
2623
+ } catch {
2624
+ return false;
2625
+ }
2626
+ };
2627
+
2628
+ // packages/ai/agent/streamTurnQuickChat.ts
2629
+ var QUICK_CHAT_AGENT_CONFIG_READ_TIMEOUT_MS = 1e4;
2630
+ var QUICK_CHAT_DYNAMIC_CONTEXT_TIMEOUT_MS = 5e3;
2631
+ var EMPTY_DYNAMIC_CONTEXTS = {
2632
+ currentInputContext: null,
2633
+ historyContext: "",
2634
+ editingContext: null,
2635
+ appWorkingMemory: null,
2636
+ memoryOverlay: null,
2637
+ dialogSummary: null,
2638
+ referenceKeys: []
2639
+ };
2640
+ var logQuickChatPerfStage2 = (startedAt, stage, details = {}) => {
2641
+ if (!startedAt) return;
2642
+ const now = typeof performance !== "undefined" ? performance.now() : Date.now();
2643
+ console.info("[QuickChatPerf]", {
2644
+ stage,
2645
+ elapsedMs: now - startedAt,
2646
+ ...typeof performance !== "undefined" ? { atMs: now } : {},
2647
+ ...details
2648
+ });
2649
+ };
2650
+ var readAgentConfigForTurn = async (dispatch, agentKey, quickChatPerfStartedAt) => {
2651
+ const readPromise = dispatch(read({ dbKey: agentKey })).unwrap();
2652
+ if (!quickChatPerfStartedAt) return readPromise;
2653
+ let timeoutId;
2654
+ try {
2655
+ return await Promise.race([
2656
+ readPromise,
2657
+ new Promise((_, reject) => {
2658
+ timeoutId = setTimeout(() => {
2659
+ logQuickChatPerfStage2(
2660
+ quickChatPerfStartedAt,
2661
+ "quick-chat-agent-config-read-timeout",
2662
+ { agentKey, timeoutMs: QUICK_CHAT_AGENT_CONFIG_READ_TIMEOUT_MS }
2663
+ );
2664
+ reject(
2665
+ new Error("\u8BFB\u53D6 Agent \u914D\u7F6E\u8D85\u65F6\uFF0C\u672A\u80FD\u542F\u52A8\u6A21\u578B\u56DE\u590D\u3002")
2666
+ );
2667
+ }, QUICK_CHAT_AGENT_CONFIG_READ_TIMEOUT_MS);
2668
+ })
2669
+ ]);
2670
+ } finally {
2671
+ if (timeoutId) clearTimeout(timeoutId);
2672
+ }
2673
+ };
2674
+ var buildDynamicContextsForTurn = async (state, dispatch, agentConfig, userInput, runtimeOptions, mergedContentCache, dialogKey, quickChatPerfStartedAt) => {
2675
+ if (!quickChatPerfStartedAt) {
2676
+ return buildDynamicContexts(
2677
+ state,
2678
+ dispatch,
2679
+ agentConfig,
2680
+ userInput,
2681
+ runtimeOptions,
2682
+ mergedContentCache,
2683
+ dialogKey
2684
+ );
2685
+ }
2686
+ let timeoutId;
2687
+ try {
2688
+ const timeoutPromise = new Promise((resolve) => {
2689
+ timeoutId = setTimeout(() => {
2690
+ logQuickChatPerfStage2(
2691
+ quickChatPerfStartedAt,
2692
+ "quick-chat-dynamic-context-timeout",
2693
+ { agentKey: agentConfig.dbKey, dialogKey, timeoutMs: QUICK_CHAT_DYNAMIC_CONTEXT_TIMEOUT_MS }
2694
+ );
2695
+ resolve(EMPTY_DYNAMIC_CONTEXTS);
2696
+ }, QUICK_CHAT_DYNAMIC_CONTEXT_TIMEOUT_MS);
2697
+ });
2698
+ logQuickChatPerfStage2(
2699
+ quickChatPerfStartedAt,
2700
+ "stream-agent-dynamic-context-starting",
2701
+ { responseApi: isResponseAPIModel(agentConfig) }
2702
+ );
2703
+ const contextPromise = buildDynamicContexts(
2704
+ state,
2705
+ dispatch,
2706
+ agentConfig,
2707
+ userInput,
2708
+ runtimeOptions,
2709
+ mergedContentCache,
2710
+ dialogKey
2711
+ );
2712
+ return await Promise.race([
2713
+ contextPromise,
2714
+ timeoutPromise
2715
+ ]);
2716
+ } finally {
2717
+ if (timeoutId) clearTimeout(timeoutId);
2718
+ }
2719
+ };
2720
+ var finalizeQuickChatAgentTurnFailure = async (dispatch, dialogKey, agentKey, error) => {
2721
+ const dialogId = extractCustomId(dialogKey);
2722
+ const { key: msgKey, messageId } = createDialogMessageKeyAndId(dialogId);
2723
+ const reason = error instanceof Error && error.message.trim() ? error.message.trim() : typeof error === "string" && error.trim() ? error.trim() : error && typeof error === "object" && typeof error.message === "string" && error.message.trim() ? error.message.trim() : "\u672A\u80FD\u542F\u52A8\u6A21\u578B\u56DE\u590D\uFF0C\u8BF7\u91CD\u8BD5\u3002";
2724
+ await dispatch(
2725
+ messageStreamEnd({
2726
+ finalContentBuffer: [
2727
+ { type: "text", text: `[\u9519\u8BEF: ${reason}]` }
2728
+ ],
2729
+ totalUsage: null,
2730
+ msgKey,
2731
+ agentConfig: { dbKey: agentKey },
2732
+ dialogId,
2733
+ dialogKey,
2734
+ messageId,
2735
+ reasoningBuffer: ""
2736
+ })
2737
+ ).unwrap?.();
2738
+ };
2739
+ var normalizeAgentRunUserInput = (userInput) => {
2740
+ if (typeof userInput === "string") return userInput;
2741
+ if (!Array.isArray(userInput)) return "";
2742
+ return userInput.filter((part) => {
2743
+ if (!part || typeof part !== "object") return false;
2744
+ if (part.type === "text") return typeof part.text === "string";
2745
+ return part.type === "image_url" && typeof part.image_url?.url === "string" && !!part.image_url.url.trim();
2746
+ });
2747
+ };
2748
+ var isSimpleTextInput = (userInput) => {
2749
+ if (typeof userInput === "string") return true;
2750
+ if (!Array.isArray(userInput)) return false;
2751
+ return userInput.every(
2752
+ (part) => part && typeof part === "object" && part.type === "text" && typeof part.text === "string"
2753
+ );
2754
+ };
2755
+ var canUseQuickChatEmptyDynamicContexts = (quickChatPerfStartedAt, userInput, runtimeOptions, dialogConfig, agentConfig) => {
2756
+ if (!quickChatPerfStartedAt) return false;
2757
+ if (runtimeOptions) return false;
2758
+ if (agentConfig?.tools?.includes("rememberMemory")) return false;
2759
+ if (!isSimpleTextInput(userInput)) return false;
2760
+ if (dialogConfig?.referenceKeys?.length) return false;
2761
+ return true;
2762
+ };
2763
+ var QUICK_CHAT_DIRECT_ANSWER_PATTERN = /(只回复|只输出|只回答|直接回复|直接回答|不要解释|无需解释|不用解释|简短回答|一句话)/i;
2764
+ var QUICK_CHAT_TOOL_INTENT_PATTERN = /(调用|转交|agent|助手|应用|网页|页面|图表|图片|生成图|画图|删除|清理|空间|商品|链接|https?:\/\/|www\.|@)/i;
2765
+ var shouldDisableQuickChatToolsForDirectAnswer = (quickChatPerfStartedAt, userInput, runtimeOptions, dialogConfig) => {
2766
+ if (!canUseQuickChatEmptyDynamicContexts(
2767
+ quickChatPerfStartedAt,
2768
+ userInput,
2769
+ runtimeOptions,
2770
+ dialogConfig,
2771
+ void 0
2772
+ )) {
2773
+ return false;
2774
+ }
2775
+ const text = extractAgentRunUserText(userInput);
2776
+ if (!text || text.length > 500) return false;
2777
+ if (!QUICK_CHAT_DIRECT_ANSWER_PATTERN.test(text)) return false;
2778
+ return !QUICK_CHAT_TOOL_INTENT_PATTERN.test(text);
2779
+ };
2780
+ var classifyQuickChatAccessError = (accessError) => {
2781
+ if (accessError.includes("\u83B7\u53D6\u7528\u6237\u4F59\u989D")) return "balance-loading";
2782
+ if (accessError.includes("\u4F59\u989D")) return "balance";
2783
+ if (accessError.includes("\u767D\u540D\u5355")) return "whitelist";
2784
+ if (accessError.includes("\u5B9A\u4EF7")) return "pricing";
2785
+ return "unknown";
2786
+ };
2787
+ var isUsableAgentConfig = (value) => !!value && typeof value === "object" && value.__ssrPreviewOnly !== true && typeof value.dbKey === "string" && !!value.dbKey && typeof value.model === "string" && !!value.model && typeof value.provider === "string" && !!value.provider;
2788
+ var extractAgentRunUserText = (userInput) => {
2789
+ if (typeof userInput === "string") return userInput.trim();
2790
+ if (!Array.isArray(userInput)) return "";
2791
+ return userInput.filter((part) => part?.type === "text" && typeof part.text === "string").map((part) => part.text).join("").trim();
2792
+ };
2793
+ var hasAgentRunUserInputContent = (userInput) => {
2794
+ if (typeof userInput === "string") return userInput.trim().length > 0;
2795
+ return Array.isArray(userInput) && userInput.length > 0;
2796
+ };
2797
+ var isLastMessageMatchingUserInput = (visibleMessages, userInput) => {
2798
+ if (visibleMessages.length === 0) return false;
2799
+ const lastMsg = visibleMessages[visibleMessages.length - 1];
2800
+ if (lastMsg.role !== "user") return false;
2801
+ const content1 = lastMsg.content;
2802
+ const content2 = userInput;
2803
+ const normalize = (content) => {
2804
+ if (typeof content === "string") return content.trim();
2805
+ if (Array.isArray(content)) {
2806
+ if (content.length === 1 && content[0]?.type === "text") {
2807
+ return (content[0].text || "").trim();
2808
+ }
2809
+ return content.map((part) => {
2810
+ if (part?.type === "text") return { type: "text", text: part.text?.trim() };
2811
+ if (part?.type === "image_url") return { type: "image_url", url: part.image_url?.url };
2812
+ return part;
2813
+ });
2814
+ }
2815
+ return content;
2816
+ };
2817
+ const norm1 = normalize(content1);
2818
+ const norm2 = normalize(content2);
2819
+ if (typeof norm1 === "string" && typeof norm2 === "string") {
2820
+ return norm1 === norm2;
2821
+ }
2822
+ return JSON.stringify(norm1) === JSON.stringify(norm2);
2823
+ };
2824
+ var setLoopStopReason = (reason) => {
2825
+ const w = typeof globalThis !== "undefined" && globalThis.window ? globalThis.window : null;
2826
+ if (w) w.__LOOP_STOP_REASON__ = reason;
2827
+ };
2828
+ var prewarmPreparedToolsForAgent = (agentConfig) => {
2829
+ const tools = agentConfig?.tools;
2830
+ if (!Array.isArray(tools) || tools.length === 0) return;
2831
+ try {
2832
+ prepareTools(tools, { provider: agentConfig.provider });
2833
+ } catch {
2834
+ }
2835
+ };
2836
+ var buildStaticContextsWithToolsPrewarm = async (state, dispatch, agentConfig, currentDialog, mergedContentCache) => {
2837
+ const [staticContexts] = await Promise.all([
2838
+ buildStaticContexts(
2839
+ state,
2840
+ dispatch,
2841
+ agentConfig,
2842
+ currentDialog ?? void 0,
2843
+ mergedContentCache
2844
+ ),
2845
+ Promise.resolve().then(() => prewarmPreparedToolsForAgent(agentConfig))
2846
+ ]);
2847
+ return staticContexts;
2848
+ };
2849
+
2850
+ // packages/ai/agent/streamAgentChatTurn.ts
2851
+ function hasInlineExecutedToolCalls(result) {
2852
+ const output = result?.output;
2853
+ return Array.isArray(output) && output.some((b) => b?.type === "toolCall" && b?.result != null);
2854
+ }
2855
+ var streamAgentChatTurnHandler = async (args, thunkApi) => {
2856
+ const {
2857
+ agentKey,
2858
+ userInput,
2859
+ dialogKey: explicitDialogKey,
2860
+ parentMessageId,
2861
+ runtimeOptions,
2862
+ quickChatPerfStartedAt
2863
+ } = args;
2864
+ const { getState, dispatch, rejectWithValue } = thunkApi;
2865
+ const state = getState();
2866
+ const loopController = new AbortController();
2867
+ const isTurnAborted = (error) => isAbortError(error) || loopController.signal.aborted || thunkApi.signal.aborted;
2868
+ const onAbort = () => loopController.abort();
2869
+ thunkApi.signal.addEventListener("abort", onAbort);
2870
+ let loopKey = null;
2871
+ let runtimeDialogKey = explicitDialogKey ?? null;
2872
+ let remoteTransientMessageId = null;
2873
+ let remoteTransientMessageFinalized = false;
2874
+ let modelRequestStarted = false;
2875
+ let turnAborted = false;
2876
+ if (explicitDialogKey) {
2877
+ const dialogId = extractCustomId(explicitDialogKey);
2878
+ const existingLoopKey = `loop:${dialogId}`;
2879
+ const activeControllers = selectActiveControllers(
2880
+ getState(),
2881
+ explicitDialogKey
2882
+ );
2883
+ if (activeControllers[existingLoopKey]) {
2884
+ console.warn(
2885
+ "[streamAgentChatTurn] Rejected concurrent turn for dialog",
2886
+ { dialogId, agentKey }
2887
+ );
2888
+ return rejectWithValue("Agent is already responding for this dialog");
2889
+ }
2890
+ }
2891
+ try {
2892
+ let totalTurnUsage = null;
2893
+ const agentRunUserInput = normalizeAgentRunUserInput(userInput);
2894
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-entered", {
2895
+ agentKey,
2896
+ dialogKey: explicitDialogKey ?? null
2897
+ });
2898
+ const cachedAgentConfig = selectById(
2899
+ getState(),
2900
+ agentKey
2901
+ );
2902
+ let rawAgentConfig = null;
2903
+ rawAgentConfig = isUsableAgentConfig(cachedAgentConfig) ? cachedAgentConfig : await readAgentConfigForTurn(
2904
+ dispatch,
2905
+ agentKey,
2906
+ quickChatPerfStartedAt
2907
+ );
2908
+ if (!rawAgentConfig) {
2909
+ return rejectWithValue(
2910
+ `Agent config not found for ID: ${agentKey}`
2911
+ );
2912
+ }
2913
+ if (runtimeOptions?.quickChatModelOverride) {
2914
+ rawAgentConfig = applyQuickChatModelOverride(
2915
+ rawAgentConfig,
2916
+ runtimeOptions.quickChatModelOverride
2917
+ );
2918
+ }
2919
+ if (isLiveAudioOnlyAgent(rawAgentConfig)) {
2920
+ return rejectWithValue(
2921
+ "\u6B64 Agent \u4EC5\u652F\u6301\u5B9E\u65F6\u8BED\u97F3\u6A21\u5F0F\uFF0C\u8BF7\u4F7F\u7528\u8BED\u97F3\u9762\u677F\u8FDB\u884C\u5BF9\u8BDD\u3002"
2922
+ );
2923
+ }
2924
+ const agentConfig = resolveWebAgentRuntimeToolSurface(
2925
+ rawAgentConfig,
2926
+ getState()
2927
+ );
2928
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-config-read", {
2929
+ agentKey,
2930
+ model: agentConfig.model,
2931
+ provider: agentConfig.provider,
2932
+ apiSource: agentConfig.apiSource,
2933
+ source: rawAgentConfig === cachedAgentConfig ? "cache" : "read"
2934
+ });
2935
+ const gptProCheck = shouldBlockForGptPro(
2936
+ agentConfig,
2937
+ selectIdentityUser(getState())?.gptProAccess?.status
2938
+ );
2939
+ if (gptProCheck.blocked) {
2940
+ return rejectWithValue(gptProCheck.message);
2941
+ }
2942
+ const configuredBoundMachineId = asTrimmedString(
2943
+ agentConfig.runtimeBinding?.machineId
2944
+ );
2945
+ const boundMachineId = resolveRemoteBoundMachineId(configuredBoundMachineId);
2946
+ if (agentConfig.apiSource === "cli" || boundMachineId && !getIsDesktopApp()) {
2947
+ console.info("[streamAgentChatTurn] Triggered CLI/machine route. apiSource:", agentConfig.apiSource, "boundMachineId:", boundMachineId, "agentKey:", agentKey);
2948
+ const currentState = getState();
2949
+ const w2 = typeof globalThis !== "undefined" && globalThis.window ? globalThis.window : null;
2950
+ if (w2) w2.__LOOP_STOP_REASON__ = null;
2951
+ const userText = extractAgentRunUserText(userInput);
2952
+ const prompt = buildCliPrompt(agentConfig.prompt, userText);
2953
+ const dialogConfig = selectDialogConfigByKey(currentState, explicitDialogKey) ?? selectCurrentDialogConfig(currentState);
2954
+ if (!dialogConfig) {
2955
+ return rejectWithValue("Dialog config not found");
2956
+ }
2957
+ const dialogKey2 = explicitDialogKey || dialogConfig.dbKey;
2958
+ if (!dialogKey2) {
2959
+ return rejectWithValue("\u5F53\u524D\u5BF9\u8BDD\u4E0D\u5B58\u5728\uFF0C\u65E0\u6CD5\u53D1\u9001\u6D88\u606F\u3002");
2960
+ }
2961
+ runtimeDialogKey = dialogKey2;
2962
+ const dialogId2 = extractCustomId(dialogKey2);
2963
+ loopKey = `loop:${dialogId2}`;
2964
+ dispatch(addActiveController({ messageId: loopKey, controller: loopController, dialogKey: dialogKey2 }));
2965
+ const { key: msgKey, messageId } = createDialogMessageKeyAndId(dialogId2);
2966
+ const cliMessageMetadata = buildMessageMetadata(agentConfig);
2967
+ if (boundMachineId) {
2968
+ const token = selectIdentityToken(currentState);
2969
+ const authHeader = token ? `Bearer ${token}` : "";
2970
+ const rawMessages = selectAllMsgs(currentState, dialogId2);
2971
+ const visibleMessages = buildAgentViewMessages(
2972
+ rawMessages,
2973
+ agentConfig.dbKey
2974
+ );
2975
+ const cleanedMessages = filterAndCleanMessages(visibleMessages);
2976
+ const currentServer2 = selectCurrentServer(currentState);
2977
+ remoteTransientMessageId = messageId;
2978
+ let accumulated2 = "";
2979
+ let totalTurnUsage2 = void 0;
2980
+ const buildMachineAssistantMessage = () => ({
2981
+ id: messageId,
2982
+ dbKey: msgKey,
2983
+ role: "assistant",
2984
+ content: accumulated2,
2985
+ ...cliMessageMetadata,
2986
+ userId: selectIdentityUserId(getState())
2987
+ });
2988
+ dispatch(messageStreaming({
2989
+ id: messageId,
2990
+ dialogId: dialogId2,
2991
+ dbKey: msgKey,
2992
+ content: "",
2993
+ role: "assistant",
2994
+ ...cliMessageMetadata
2995
+ }));
2996
+ const rejectMachineStream = async (message) => {
2997
+ if (accumulated2.length > 0) {
2998
+ await persistMessageWithFixedId(dispatch, buildMachineAssistantMessage());
2999
+ } else {
3000
+ dispatch(removeTransientMessage(messageId));
3001
+ }
3002
+ setLoopStopReason("error");
3003
+ remoteTransientMessageFinalized = true;
3004
+ return rejectWithValue(message);
3005
+ };
3006
+ const machineResponse = await fetch(`${currentServer2.replace(/\/+$/, "")}/api/agent/run`, {
3007
+ method: "POST",
3008
+ headers: {
3009
+ "Content-Type": "application/json",
3010
+ Accept: "text/event-stream",
3011
+ ...authHeader ? { Authorization: authHeader } : {}
3012
+ },
3013
+ body: JSON.stringify({
3014
+ agentKey,
3015
+ userInput: agentRunUserInput,
3016
+ messages: cleanedMessages,
3017
+ stream: true,
3018
+ persistDialog: false,
3019
+ clientDialogId: dialogId2,
3020
+ runtimeContext: {
3021
+ surface: "web",
3022
+ host: "browser",
3023
+ runtime: "react",
3024
+ entrypoint: "chat-dialog",
3025
+ capabilities: ["streaming", "dialog-ui", "machine-bound-cli"]
3026
+ },
3027
+ ...dialogConfig?.spaceId ? { spaceId: dialogConfig.spaceId } : {}
3028
+ }),
3029
+ signal: loopController.signal
3030
+ });
3031
+ if (!machineResponse.ok) {
3032
+ return await rejectMachineStream(
3033
+ await formatMachineAgentRunError(machineResponse)
3034
+ );
3035
+ }
3036
+ const reader2 = machineResponse.body?.getReader();
3037
+ if (!reader2) {
3038
+ return await rejectMachineStream("\u65E0\u6CD5\u8BFB\u53D6\u7535\u8111\u7AEF Agent \u6D41\u5F0F\u54CD\u5E94");
3039
+ }
3040
+ const decoder2 = new TextDecoder();
3041
+ const parseSSE = createSSEParser();
3042
+ const abortMachineStream = async () => {
3043
+ if (w2) w2.__LOOP_STOP_REASON__ = "aborted";
3044
+ if (accumulated2.length <= 0) return;
3045
+ await persistMessageWithFixedId(dispatch, buildMachineAssistantMessage());
3046
+ };
3047
+ try {
3048
+ const result = await consumeAgentRunStream({
3049
+ reader: reader2,
3050
+ decoder: decoder2,
3051
+ parseChunk: (raw) => parseSSE(raw),
3052
+ isAborted: () => loopController.signal.aborted || thunkApi.signal.aborted,
3053
+ signal: loopController.signal,
3054
+ onAbort: abortMachineStream,
3055
+ isDoneEvent: (payload) => payload?.type === "done",
3056
+ onPayload: (payload) => {
3057
+ if (payload.type === "error") {
3058
+ return { reject: payload.message || "\u7535\u8111\u7AEF Agent \u6267\u884C\u5931\u8D25" };
3059
+ }
3060
+ if (payload.type === "text" && typeof payload.content === "string") {
3061
+ accumulated2 += payload.content;
3062
+ dispatch(messageStreaming({
3063
+ id: messageId,
3064
+ dialogId: dialogId2,
3065
+ dbKey: msgKey,
3066
+ content: accumulated2,
3067
+ role: "assistant",
3068
+ ...cliMessageMetadata
3069
+ }));
3070
+ }
3071
+ if (payload.type === "done") {
3072
+ totalTurnUsage2 = payload.usage;
3073
+ }
3074
+ }
3075
+ });
3076
+ if (result.outcome === "rejected") {
3077
+ return await rejectMachineStream(result.message);
3078
+ }
3079
+ if (result.outcome === "aborted") {
3080
+ return { aborted: true };
3081
+ }
3082
+ if (result.outcome === "streamEnded") {
3083
+ if (!result.sawDone) {
3084
+ dispatch(finalizeTransientMessageOnError({
3085
+ id: messageId,
3086
+ error: "\u7535\u8111\u7AEF Agent \u6D41\u5F0F\u54CD\u5E94\u88AB\u4E2D\u65AD,\u672A\u6536\u5230\u5B8C\u6210\u4FE1\u53F7"
3087
+ }));
3088
+ remoteTransientMessageFinalized = true;
3089
+ setLoopStopReason("error");
3090
+ return rejectWithValue(
3091
+ "\u7535\u8111\u7AEF Agent \u6D41\u5F0F\u54CD\u5E94\u88AB\u4E2D\u65AD,\u672A\u6536\u5230\u5B8C\u6210\u4FE1\u53F7"
3092
+ );
3093
+ }
3094
+ await persistMessageWithFixedId(dispatch, buildMachineAssistantMessage());
3095
+ remoteTransientMessageFinalized = true;
3096
+ }
3097
+ } finally {
3098
+ try {
3099
+ await reader2.cancel();
3100
+ } catch {
3101
+ }
3102
+ }
3103
+ return {
3104
+ usage: totalTurnUsage2 ?? void 0
3105
+ };
3106
+ }
3107
+ let cliSessionId = dialogConfig.cliSessionId ?? null;
3108
+ dispatch(messageStreaming({
3109
+ id: messageId,
3110
+ dialogId: dialogId2,
3111
+ dbKey: msgKey,
3112
+ content: "",
3113
+ role: "assistant",
3114
+ ...cliMessageMetadata
3115
+ }));
3116
+ remoteTransientMessageId = messageId;
3117
+ const ensureCliSession = async () => {
3118
+ if (cliSessionId) {
3119
+ const existing = await getCliChatSession(
3120
+ { getState },
3121
+ { sessionId: cliSessionId }
3122
+ ).catch(() => null);
3123
+ if (existing?.ok && existing?.session?.sessionId) {
3124
+ return cliSessionId;
3125
+ }
3126
+ }
3127
+ const started = await startCliChatSession(
3128
+ { getState },
3129
+ {
3130
+ cliProvider: agentConfig.cliProvider || "copilot",
3131
+ model: agentConfig.model || void 0,
3132
+ systemPrompt: agentConfig.prompt || void 0,
3133
+ reasoningEffort: agentConfig.reasoning_effort || agentConfig.reasoningEffort || void 0,
3134
+ temperature: agentConfig.temperature,
3135
+ topP: agentConfig.top_p,
3136
+ frequencyPenalty: agentConfig.frequency_penalty,
3137
+ presencePenalty: agentConfig.presence_penalty,
3138
+ maxTokens: agentConfig.max_tokens,
3139
+ enableThinking: agentConfig.enableThinking,
3140
+ thinkingBudget: agentConfig.thinkingBudget
3141
+ }
3142
+ );
3143
+ const newSessionId = typeof started?.sessionId === "string" ? started.sessionId : null;
3144
+ if (!newSessionId) {
3145
+ throw new Error("\u65E0\u6CD5\u521B\u5EFA CLI session\u3002");
3146
+ }
3147
+ cliSessionId = newSessionId;
3148
+ const patchResult = dispatch(
3149
+ patch({
3150
+ dbKey: dialogKey2,
3151
+ changes: {
3152
+ cliSessionId: newSessionId
3153
+ }
3154
+ })
3155
+ );
3156
+ try {
3157
+ if (typeof patchResult?.unwrap === "function") {
3158
+ await patchResult.unwrap();
3159
+ } else {
3160
+ await patchResult;
3161
+ }
3162
+ } catch {
3163
+ }
3164
+ return newSessionId;
3165
+ };
3166
+ const initialSessionId = await ensureCliSession();
3167
+ console.info("[streamAgentChatTurn] Calling CLI turn stream. Session ID:", initialSessionId);
3168
+ let resp = await createCliChatTurnStream(
3169
+ {
3170
+ getState
3171
+ },
3172
+ {
3173
+ sessionId: initialSessionId,
3174
+ prompt,
3175
+ model: agentConfig.model || void 0
3176
+ },
3177
+ loopController.signal
3178
+ );
3179
+ if (!resp.ok && resp.status === 404) {
3180
+ console.warn("[streamAgentChatTurn] CLI Session 404. Re-creating session...");
3181
+ cliSessionId = null;
3182
+ const renewedSessionId = await ensureCliSession();
3183
+ console.info("[streamAgentChatTurn] Retrying CLI turn stream. Session ID:", renewedSessionId);
3184
+ resp = await createCliChatTurnStream(
3185
+ {
3186
+ getState
3187
+ },
3188
+ {
3189
+ sessionId: renewedSessionId,
3190
+ prompt,
3191
+ model: agentConfig.model || void 0
3192
+ },
3193
+ loopController.signal
3194
+ );
3195
+ }
3196
+ if (!resp.ok) {
3197
+ const err = await resp.json().catch(() => ({ error: resp.statusText }));
3198
+ console.error("[streamAgentChatTurn] Local CLI fetch failed. Status:", resp.status, "Error details:", err);
3199
+ dispatch(removeTransientMessage(messageId));
3200
+ setLoopStopReason("error");
3201
+ remoteTransientMessageFinalized = true;
3202
+ return rejectWithValue(err.error || "CLI \u6267\u884C\u5931\u8D25");
3203
+ }
3204
+ const reader = resp.body?.getReader();
3205
+ if (!reader) {
3206
+ dispatch(removeTransientMessage(messageId));
3207
+ setLoopStopReason("error");
3208
+ remoteTransientMessageFinalized = true;
3209
+ return rejectWithValue("\u65E0\u6CD5\u8BFB\u53D6\u6D41\u5F0F\u54CD\u5E94");
3210
+ }
3211
+ let accumulated = "";
3212
+ let cliCapabilityWarnings = [];
3213
+ let cliTurnUsage = null;
3214
+ const decoder = new TextDecoder();
3215
+ const buildCliAssistantMessage = () => ({
3216
+ id: messageId,
3217
+ dbKey: msgKey,
3218
+ role: "assistant",
3219
+ content: accumulated,
3220
+ ...cliMessageMetadata,
3221
+ userId: selectIdentityUserId(getState())
3222
+ });
3223
+ const rejectCliStream = async (message) => {
3224
+ if (accumulated.length > 0) {
3225
+ await persistMessageWithFixedId(dispatch, buildCliAssistantMessage());
3226
+ } else {
3227
+ dispatch(removeTransientMessage(messageId));
3228
+ }
3229
+ setLoopStopReason("error");
3230
+ remoteTransientMessageFinalized = true;
3231
+ return rejectWithValue(message);
3232
+ };
3233
+ const abortCliStream = async () => {
3234
+ if (w2) w2.__LOOP_STOP_REASON__ = "aborted";
3235
+ if (accumulated.length <= 0) {
3236
+ return;
3237
+ }
3238
+ await persistMessageWithFixedId(dispatch, buildCliAssistantMessage());
3239
+ };
3240
+ try {
3241
+ const result = await consumeAgentRunStream({
3242
+ reader,
3243
+ decoder,
3244
+ parseChunk: (raw) => {
3245
+ const parsed = [];
3246
+ for (const line of raw.split("\n")) {
3247
+ if (!line.startsWith("data: ")) continue;
3248
+ try {
3249
+ parsed.push(JSON.parse(line.slice(6)));
3250
+ } catch {
3251
+ }
3252
+ }
3253
+ return parsed;
3254
+ },
3255
+ isAborted: () => loopController.signal.aborted || thunkApi.signal.aborted,
3256
+ signal: loopController.signal,
3257
+ onAbort: abortCliStream,
3258
+ isDoneEvent: (payload) => payload?.done === true,
3259
+ onPayload: (payload) => {
3260
+ if (payload.error) {
3261
+ return { reject: payload.error };
3262
+ }
3263
+ if (payload.chunk) {
3264
+ accumulated += payload.chunk;
3265
+ dispatch(messageStreaming({
3266
+ id: messageId,
3267
+ dialogId: dialogId2,
3268
+ dbKey: msgKey,
3269
+ content: accumulated,
3270
+ role: "assistant",
3271
+ ...cliMessageMetadata
3272
+ }));
3273
+ }
3274
+ if (payload.done && Array.isArray(payload.warnings)) {
3275
+ cliCapabilityWarnings = payload.warnings.filter(
3276
+ (warning) => typeof warning === "string" && warning.trim().length > 0
3277
+ );
3278
+ }
3279
+ if (payload.done && payload.usage) {
3280
+ cliTurnUsage = updateTotalUsage(cliTurnUsage, payload.usage);
3281
+ }
3282
+ }
3283
+ });
3284
+ if (result.outcome === "rejected") {
3285
+ return await rejectCliStream(result.message);
3286
+ }
3287
+ if (result.outcome === "aborted") {
3288
+ return { aborted: true };
3289
+ }
3290
+ if (result.outcome === "streamEnded") {
3291
+ if (!result.sawDone) {
3292
+ dispatch(finalizeTransientMessageOnError({
3293
+ id: messageId,
3294
+ error: "CLI \u6D41\u5F0F\u54CD\u5E94\u88AB\u4E2D\u65AD,\u672A\u6536\u5230\u5B8C\u6210\u4FE1\u53F7"
3295
+ }));
3296
+ remoteTransientMessageFinalized = true;
3297
+ setLoopStopReason("error");
3298
+ return rejectWithValue("CLI \u6D41\u5F0F\u54CD\u5E94\u88AB\u4E2D\u65AD,\u672A\u6536\u5230\u5B8C\u6210\u4FE1\u53F7");
3299
+ }
3300
+ if (cliCapabilityWarnings.length > 0) {
3301
+ accumulated = appendCliCapabilityWarnings(accumulated, cliCapabilityWarnings);
3302
+ dispatch(messageStreaming({
3303
+ id: messageId,
3304
+ dialogId: dialogId2,
3305
+ dbKey: msgKey,
3306
+ content: accumulated,
3307
+ role: "assistant",
3308
+ ...cliMessageMetadata
3309
+ }));
3310
+ }
3311
+ await persistMessageWithFixedId(dispatch, buildCliAssistantMessage());
3312
+ remoteTransientMessageFinalized = true;
3313
+ const cliUsageRaw = cliTurnUsage;
3314
+ const hasRealUsage = !!cliUsageRaw && (cliUsageRaw.prompt_tokens ?? cliUsageRaw.input_tokens ?? 0) + (cliUsageRaw.completion_tokens ?? cliUsageRaw.output_tokens ?? 0) + (cliUsageRaw.cache_creation_input_tokens ?? 0) + (cliUsageRaw.cache_read_input_tokens ?? 0) > 0;
3315
+ const isCliEstimated = !hasRealUsage;
3316
+ const cliUsage = hasRealUsage ? cliUsageRaw : estimateMissingUsage({ content: accumulated });
3317
+ if (dialogKey2) {
3318
+ try {
3319
+ await dispatch(updateTokens({
3320
+ dialogId: dialogId2,
3321
+ dialogKey: dialogKey2,
3322
+ usage: cliUsage,
3323
+ agentConfig: isCliEstimated ? { ...agentConfig, apiSource: "cli" } : agentConfig
3324
+ })).unwrap();
3325
+ } catch (err) {
3326
+ console.warn("[streamAgentChatTurn] CLI token stats dispatch failed", err);
3327
+ }
3328
+ }
3329
+ }
3330
+ } finally {
3331
+ try {
3332
+ await reader.cancel();
3333
+ } catch {
3334
+ }
3335
+ }
3336
+ return;
3337
+ }
3338
+ const currentDialog = selectDialogConfigByKey(state, explicitDialogKey) ?? selectCurrentDialogConfig(state);
3339
+ const activeDialogKey = currentDialog?.dbKey;
3340
+ const dialogKey = explicitDialogKey || activeDialogKey;
3341
+ if (!dialogKey) {
3342
+ return rejectWithValue("\u5F53\u524D\u5BF9\u8BDD\u4E0D\u5B58\u5728\uFF0C\u65E0\u6CD5\u53D1\u9001\u6D88\u606F\u3002");
3343
+ }
3344
+ runtimeDialogKey = dialogKey;
3345
+ const dialogId = extractCustomId(dialogKey);
3346
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-dialog-resolved", {
3347
+ dialogKey,
3348
+ dialogId
3349
+ });
3350
+ if (shouldUseDesktopLocalRuntime(agentConfig)) {
3351
+ const desktopMessageMetadata = buildMessageMetadata(agentConfig);
3352
+ const w2 = typeof globalThis !== "undefined" && globalThis.window ? globalThis.window : null;
3353
+ loopKey = `loop:${dialogId}`;
3354
+ dispatch(addActiveController({ messageId: loopKey, controller: loopController, dialogKey }));
3355
+ let currentContent = "";
3356
+ const assistantSegments = [];
3357
+ let assistantMessageKeys = null;
3358
+ let streamResult = null;
3359
+ let streamError = null;
3360
+ let reasoningBuffer = "";
3361
+ const activeToolMessages = /* @__PURE__ */ new Map();
3362
+ const ensureAssistantMessageKeys = () => {
3363
+ if (!assistantMessageKeys) {
3364
+ assistantMessageKeys = createDialogMessageKeyAndId(dialogId);
3365
+ assistantSegments.push({
3366
+ key: assistantMessageKeys.key,
3367
+ messageId: assistantMessageKeys.messageId,
3368
+ content: "",
3369
+ finalized: false,
3370
+ toolCallIds: []
3371
+ });
3372
+ remoteTransientMessageId = assistantMessageKeys.messageId;
3373
+ }
3374
+ return assistantMessageKeys;
3375
+ };
3376
+ const streamDesktopAssistantText = (text) => {
3377
+ currentContent += text;
3378
+ const { key: msgKey2, messageId: messageId2 } = ensureAssistantMessageKeys();
3379
+ const segment2 = assistantSegments[assistantSegments.length - 1];
3380
+ segment2.content = currentContent;
3381
+ dispatch(messageStreaming({
3382
+ id: messageId2,
3383
+ dialogId,
3384
+ dbKey: msgKey2,
3385
+ content: currentContent,
3386
+ role: "assistant",
3387
+ isStreaming: true,
3388
+ ...desktopMessageMetadata
3389
+ }));
3390
+ };
3391
+ const finalizeCurrentAssistantSegmentForTool = () => {
3392
+ const segment2 = assistantSegments[assistantSegments.length - 1];
3393
+ if (segment2) {
3394
+ segment2.content = currentContent;
3395
+ segment2.finalized = true;
3396
+ }
3397
+ if (assistantMessageKeys && currentContent.length > 0) {
3398
+ dispatch(messageStreaming({
3399
+ id: assistantMessageKeys.messageId,
3400
+ dialogId,
3401
+ dbKey: assistantMessageKeys.key,
3402
+ content: currentContent,
3403
+ role: "assistant",
3404
+ isStreaming: false,
3405
+ ...desktopMessageMetadata
3406
+ }));
3407
+ }
3408
+ assistantMessageKeys = null;
3409
+ currentContent = "";
3410
+ };
3411
+ try {
3412
+ const desktopAgentRef = agentConfig.dbKey || agentKey;
3413
+ const eventStream = runDesktopAgentRuntimeTurnStream({
3414
+ agentRef: desktopAgentRef,
3415
+ input: userInput,
3416
+ continueDialogId: dialogId,
3417
+ dialogKey,
3418
+ cwd: runtimeOptions?.cwd,
3419
+ restrictShellToWorkspace: runtimeOptions?.restrictShellToWorkspace === true,
3420
+ workspaceToolsHint: runtimeOptions?.workspaceToolsHint === true,
3421
+ agentConfigSnapshot: agentConfig,
3422
+ dialogMessages: selectAllMsgs(getState(), dialogId),
3423
+ signal: loopController.signal
3424
+ });
3425
+ for await (const event of eventStream) {
3426
+ if (loopController.signal.aborted || thunkApi.signal.aborted) {
3427
+ if (w2) w2.__LOOP_STOP_REASON__ = "aborted";
3428
+ break;
3429
+ }
3430
+ if (event.type === "delta") {
3431
+ streamDesktopAssistantText(event.text);
3432
+ } else if (event.type === "thinking") {
3433
+ if (typeof event.content === "string") {
3434
+ reasoningBuffer += event.content;
3435
+ }
3436
+ } else if (event.type === "tool") {
3437
+ const toolEvent = event.event;
3438
+ const callId = toolEvent.toolCallId;
3439
+ if (!callId) continue;
3440
+ if (toolEvent.type === "tool-call") {
3441
+ attachToolCallIdToSegment(assistantSegments, callId);
3442
+ finalizeCurrentAssistantSegmentForTool();
3443
+ const { key: dbKey, messageId: toolMsgId } = createDialogMessageKeyAndId(dialogId);
3444
+ const toolMsg = {
3445
+ id: toolMsgId,
3446
+ dialogId,
3447
+ dbKey,
3448
+ role: "tool",
3449
+ content: "",
3450
+ isStreaming: true,
3451
+ toolName: toolEvent.toolName,
3452
+ toolCallId: callId,
3453
+ ...toolEvent.argumentsPreview ? {
3454
+ toolPayload: {
3455
+ input: {
3456
+ command: toolEvent.argumentsPreview,
3457
+ cmd: toolEvent.argumentsPreview
3458
+ }
3459
+ },
3460
+ metadata: {
3461
+ argumentsPreview: toolEvent.argumentsPreview
3462
+ }
3463
+ } : {}
3464
+ };
3465
+ activeToolMessages.set(callId, toolMsg);
3466
+ dispatch(messageStreaming(toolMsg));
3467
+ } else if (toolEvent.type === "tool-result" || toolEvent.type === "tool-error") {
3468
+ const existing = activeToolMessages.get(callId);
3469
+ if (existing) {
3470
+ const isError = toolEvent.type === "tool-error";
3471
+ const existingMeta = asRecordOrEmpty(existing.metadata);
3472
+ const existingInput = isRecord(existing.toolPayload?.input) ? existing.toolPayload.input : {};
3473
+ const mergedMeta = {
3474
+ ...existingMeta,
3475
+ ...toolEvent.metadata,
3476
+ ...isError ? { error: true, message: toolEvent.message } : {}
3477
+ };
3478
+ const toolResultMsg = {
3479
+ ...existing,
3480
+ isStreaming: false,
3481
+ content: projectDesktopToolUiContent({
3482
+ toolName: toolEvent.toolName || existing.toolName,
3483
+ content: toolEvent.content,
3484
+ summary: toolEvent.summary,
3485
+ message: toolEvent.message,
3486
+ metadata: mergedMeta,
3487
+ argumentsPreview: asOptionalTrimmedString(mergedMeta.argumentsPreview) || asOptionalTrimmedString(existingInput.command) || asOptionalTrimmedString(existingInput.cmd) || void 0
3488
+ }),
3489
+ metadata: mergedMeta
3490
+ };
3491
+ activeToolMessages.set(callId, toolResultMsg);
3492
+ dispatch(messageStreaming(toolResultMsg));
3493
+ }
3494
+ }
3495
+ } else if (event.type === "done") {
3496
+ streamResult = event.result;
3497
+ } else if (event.type === "error") {
3498
+ streamError = event.error;
3499
+ }
3500
+ }
3501
+ } catch (err) {
3502
+ if (isAbortError(err) || loopController.signal.aborted || thunkApi.signal.aborted) {
3503
+ if (w2) w2.__LOOP_STOP_REASON__ = "aborted";
3504
+ } else {
3505
+ streamError = err?.message || "Local turn read stream error";
3506
+ }
3507
+ }
3508
+ if (loopController.signal.aborted || thunkApi.signal.aborted || typeof streamError === "string" && /operation was aborted/i.test(streamError)) {
3509
+ if (w2) w2.__LOOP_STOP_REASON__ = "aborted";
3510
+ const stopKeys = assistantMessageKeys;
3511
+ if (stopKeys) {
3512
+ const last = assistantSegments[assistantSegments.length - 1];
3513
+ if (last && last.messageId === stopKeys.messageId) {
3514
+ last.content = currentContent;
3515
+ }
3516
+ }
3517
+ const stopToolNameById = /* @__PURE__ */ new Map();
3518
+ for (const [callId, toolMsg] of activeToolMessages) {
3519
+ if (!toolMessageWillPersist(toolMsg)) continue;
3520
+ const toolName = toolMsg?.toolName;
3521
+ stopToolNameById.set(
3522
+ callId,
3523
+ typeof toolName === "string" && toolName ? toolName : "tool"
3524
+ );
3525
+ }
3526
+ for (const segment2 of assistantSegments) {
3527
+ const hasContent = segment2.content.trim().length > 0;
3528
+ const hasToolCalls = segment2.toolCallIds && segment2.toolCallIds.length > 0;
3529
+ if (hasContent || hasToolCalls) {
3530
+ const stopToolCalls = buildMinimalToolCallsFromIds(
3531
+ segment2.toolCallIds,
3532
+ stopToolNameById
3533
+ );
3534
+ await persistMessageWithFixedId(dispatch, {
3535
+ id: segment2.messageId,
3536
+ dbKey: segment2.key,
3537
+ role: "assistant",
3538
+ content: segment2.content,
3539
+ ...stopToolCalls.length > 0 ? { tool_calls: stopToolCalls } : {},
3540
+ ...desktopMessageMetadata,
3541
+ userId: selectIdentityUserId(getState())
3542
+ });
3543
+ } else {
3544
+ dispatch(removeTransientMessage(segment2.messageId));
3545
+ }
3546
+ }
3547
+ const durableTools = [];
3548
+ for (const toolMsg of activeToolMessages.values()) {
3549
+ const content = toolMsg?.content;
3550
+ const hasContent = typeof content === "string" ? content.trim().length > 0 : Array.isArray(content) && content.length > 0;
3551
+ if (!hasContent) {
3552
+ dispatch(removeTransientMessage(toolMsg.id));
3553
+ continue;
3554
+ }
3555
+ const stopped = { ...toolMsg, isStreaming: false };
3556
+ dispatch(messageStreaming(stopped));
3557
+ durableTools.push(stopped);
3558
+ }
3559
+ await persistToolMessages(dispatch, durableTools, {
3560
+ isStreaming: false,
3561
+ soft: true
3562
+ });
3563
+ remoteTransientMessageFinalized = true;
3564
+ return { aborted: true };
3565
+ }
3566
+ const finalizeDesktopTurnOnError = async (errorText) => {
3567
+ const errorToolNameById = /* @__PURE__ */ new Map();
3568
+ for (const [callId, toolMsg] of activeToolMessages) {
3569
+ if (!toolMessageWillPersist(toolMsg)) continue;
3570
+ const toolName = toolMsg?.toolName;
3571
+ errorToolNameById.set(
3572
+ callId,
3573
+ typeof toolName === "string" && toolName ? toolName : "tool"
3574
+ );
3575
+ }
3576
+ for (const segment2 of assistantSegments) {
3577
+ const hasContent = segment2.content.trim().length > 0;
3578
+ const hasToolCalls = segment2.toolCallIds && segment2.toolCallIds.length > 0;
3579
+ if (hasContent || hasToolCalls) {
3580
+ const errorToolCalls = buildMinimalToolCallsFromIds(
3581
+ segment2.toolCallIds,
3582
+ errorToolNameById
3583
+ );
3584
+ await persistMessageWithFixedId(dispatch, {
3585
+ id: segment2.messageId,
3586
+ dbKey: segment2.key,
3587
+ role: "assistant",
3588
+ content: segment2.content,
3589
+ ...errorToolCalls.length > 0 ? { tool_calls: errorToolCalls } : {},
3590
+ ...desktopMessageMetadata,
3591
+ userId: selectIdentityUserId(getState())
3592
+ });
3593
+ if (hasContent) {
3594
+ dispatch(finalizeTransientMessageOnError({
3595
+ id: segment2.messageId,
3596
+ error: errorText
3597
+ }));
3598
+ }
3599
+ } else {
3600
+ dispatch(finalizeTransientMessageOnError({
3601
+ id: segment2.messageId,
3602
+ error: errorText
3603
+ }));
3604
+ }
3605
+ }
3606
+ const durableTools = [];
3607
+ for (const toolMsg of activeToolMessages.values()) {
3608
+ const content = toolMsg?.content;
3609
+ const hasContent = typeof content === "string" ? content.trim().length > 0 : Array.isArray(content) && content.length > 0;
3610
+ if (!hasContent) {
3611
+ dispatch(removeTransientMessage(toolMsg.id));
3612
+ continue;
3613
+ }
3614
+ const stopped = { ...toolMsg, isStreaming: false };
3615
+ dispatch(messageStreaming(stopped));
3616
+ durableTools.push(stopped);
3617
+ }
3618
+ await persistToolMessages(dispatch, durableTools, {
3619
+ isStreaming: false,
3620
+ soft: true
3621
+ });
3622
+ remoteTransientMessageFinalized = true;
3623
+ setLoopStopReason("error");
3624
+ };
3625
+ if (streamError) {
3626
+ await finalizeDesktopTurnOnError(streamError);
3627
+ return rejectWithValue(streamError);
3628
+ }
3629
+ if (!streamResult) {
3630
+ const message = "Local turn stream closed unexpectedly without result";
3631
+ await finalizeDesktopTurnOnError(message);
3632
+ return rejectWithValue(message);
3633
+ }
3634
+ const desktopTurnMessages = streamResult.turnMessages || [];
3635
+ const hasSegmentWithCallIds = assistantSegments.some(
3636
+ (s) => s.toolCallIds.length > 0
3637
+ );
3638
+ if (!hasSegmentWithCallIds) {
3639
+ const doneOnlyAssistantCalls = desktopTurnMessages.filter(
3640
+ (m) => m?.role === "assistant" && Array.isArray(m.tool_calls) && m.tool_calls.length > 0
3641
+ ).flatMap((m) => m.tool_calls.map((tc) => tc?.id)).filter((id) => typeof id === "string");
3642
+ if (doneOnlyAssistantCalls.length > 0) {
3643
+ ensureAssistantMessageKeys();
3644
+ for (const callId of doneOnlyAssistantCalls) {
3645
+ attachToolCallIdToSegment(assistantSegments, callId);
3646
+ }
3647
+ if (currentContent.length === 0) {
3648
+ finalizeCurrentAssistantSegmentForTool();
3649
+ }
3650
+ }
3651
+ }
3652
+ if (activeToolMessages.size === 0) {
3653
+ for (const toolMessage of buildDesktopRuntimeToolMessagesForUi({
3654
+ dialogId,
3655
+ turnMessages: desktopTurnMessages
3656
+ })) {
3657
+ dispatch(messageStreaming(toolMessage));
3658
+ activeToolMessages.set(
3659
+ asTrimmedString(toolMessage.toolCallId) || toolMessage.id,
3660
+ toolMessage
3661
+ );
3662
+ }
3663
+ }
3664
+ await persistToolMessages(
3665
+ dispatch,
3666
+ activeToolMessages.values(),
3667
+ { isStreaming: false, soft: true }
3668
+ );
3669
+ const earlierFinalizedSegments = selectPersistableFinalizedSegments(assistantSegments);
3670
+ for (const segment2 of earlierFinalizedSegments) {
3671
+ const segmentToolCalls = resolveSegmentToolCalls(
3672
+ segment2.toolCallIds,
3673
+ desktopTurnMessages
3674
+ );
3675
+ dispatch(write({
3676
+ data: {
3677
+ id: segment2.messageId,
3678
+ dbKey: segment2.key,
3679
+ dialogId,
3680
+ content: segment2.content,
3681
+ role: "assistant",
3682
+ isStreaming: false,
3683
+ type: "msg" /* MSG */,
3684
+ ...segmentToolCalls.length > 0 ? { tool_calls: segmentToolCalls } : {},
3685
+ ...desktopMessageMetadata
3686
+ },
3687
+ customKey: segment2.key
3688
+ }));
3689
+ }
3690
+ const { key: msgKey, messageId } = ensureAssistantMessageKeys();
3691
+ const lastSegmentContent = hasInlineExecutedToolCalls(streamResult) ? currentContent || "" : streamResult.content || currentContent || "";
3692
+ const segment = assistantSegments[assistantSegments.length - 1];
3693
+ segment.content = lastSegmentContent;
3694
+ dispatch(messageStreaming({
3695
+ id: messageId,
3696
+ dialogId,
3697
+ dbKey: msgKey,
3698
+ content: lastSegmentContent,
3699
+ role: "assistant",
3700
+ isStreaming: false,
3701
+ ...desktopMessageMetadata
3702
+ }));
3703
+ const lastSegmentToolCalls = segment ? resolveSegmentToolCalls(segment.toolCallIds, desktopTurnMessages) : [];
3704
+ await dispatch(messageStreamEnd({
3705
+ finalContentBuffer: [
3706
+ {
3707
+ type: "text",
3708
+ text: lastSegmentContent
3709
+ }
3710
+ ],
3711
+ totalUsage: streamResult.usage ?? void 0,
3712
+ messageId,
3713
+ msgKey,
3714
+ agentConfig,
3715
+ dialogId,
3716
+ dialogKey,
3717
+ // 优先用本 turn 累计的 thinking SSE;为空时兜底 streamResult.reasoning_content
3718
+ // (provider 在 SSE 流内累计返回的 reasoning_content)。
3719
+ reasoningBuffer: reasoningBuffer || (typeof streamResult?.reasoning_content === "string" ? streamResult.reasoning_content : ""),
3720
+ toolCalls: lastSegmentToolCalls,
3721
+ // 把 provider 报告的 finish_reason 透传给 messageStreamEnd,
3722
+ // 由 assembleFinalAssistantMessage 决定是否写进最终 Message。
3723
+ finishReason: streamResult.finish_reason ?? void 0,
3724
+ messageMetadata: desktopMessageMetadata
3725
+ })).unwrap();
3726
+ remoteTransientMessageFinalized = true;
3727
+ return {
3728
+ usage: streamResult.usage ?? void 0
3729
+ };
3730
+ }
3731
+ const userInputText = extractAgentRunUserText(userInput);
3732
+ const explicitServerBase = asOptionalTrimmedString(args.serverBase) ?? null;
3733
+ const currentServer = selectCurrentServer(state);
3734
+ const normalizedRequestedServerBase = explicitServerBase && normalizeServerOrigin(explicitServerBase);
3735
+ const normalizedCurrentServer = normalizeServerOrigin(
3736
+ currentServer
3737
+ );
3738
+ const canProxyToExplicitServerBase = !Array.isArray(userInput) && !runtimeOptions?.extraTools?.length && !runtimeOptions?.editingTarget && !runtimeOptions?.imageConfigOverride;
3739
+ if (explicitServerBase && canProxyToExplicitServerBase) {
3740
+ if (normalizedRequestedServerBase && normalizedCurrentServer && normalizedRequestedServerBase === normalizedCurrentServer) {
3741
+ } else {
3742
+ const token = selectIdentityToken(state);
3743
+ const authHeader = token ? `Bearer ${token}` : "";
3744
+ const rawMessages = selectAllMsgs(state, dialogId);
3745
+ const visibleMessages = buildAgentViewMessages(
3746
+ rawMessages,
3747
+ agentConfig.dbKey
3748
+ );
3749
+ const cleanedMessages = filterAndCleanMessages(visibleMessages);
3750
+ const { key: msgKey, messageId } = createDialogMessageKeyAndId(dialogId);
3751
+ remoteTransientMessageId = messageId;
3752
+ const remoteMessageMetadata = buildMessageMetadata(agentConfig);
3753
+ let accumulated = "";
3754
+ let totalTurnUsage2 = void 0;
3755
+ const buildRemoteAssistantMessage = () => ({
3756
+ id: messageId,
3757
+ dbKey: msgKey,
3758
+ role: "assistant",
3759
+ content: accumulated,
3760
+ ...remoteMessageMetadata,
3761
+ userId: selectIdentityUserId(getState())
3762
+ });
3763
+ loopKey = `loop:${dialogId}`;
3764
+ dispatch(addActiveController({ messageId: loopKey, controller: loopController, dialogKey }));
3765
+ dispatch(messageStreaming({
3766
+ id: messageId,
3767
+ dialogId,
3768
+ dbKey: msgKey,
3769
+ content: "",
3770
+ role: "assistant",
3771
+ ...remoteMessageMetadata
3772
+ }));
3773
+ const rejectRemoteStream = async (message) => {
3774
+ if (accumulated.length > 0) {
3775
+ await persistMessageWithFixedId(dispatch, buildRemoteAssistantMessage());
3776
+ } else {
3777
+ dispatch(removeTransientMessage(messageId));
3778
+ }
3779
+ setLoopStopReason("error");
3780
+ remoteTransientMessageFinalized = true;
3781
+ return rejectWithValue(message);
3782
+ };
3783
+ const remoteRequestBody = JSON.stringify({
3784
+ agentKey,
3785
+ userInput: agentRunUserInput,
3786
+ messages: cleanedMessages,
3787
+ stream: true,
3788
+ persistDialog: false,
3789
+ clientDialogId: dialogId,
3790
+ runtimeContext: {
3791
+ surface: "web",
3792
+ host: "browser",
3793
+ runtime: "react",
3794
+ entrypoint: "chat-dialog",
3795
+ capabilities: ["streaming", "dialog-ui", "tool-cards"]
3796
+ },
3797
+ ...currentDialog?.spaceId ? { spaceId: currentDialog.spaceId } : {}
3798
+ });
3799
+ const remoteRunUrl = `${explicitServerBase.replace(/\/+$/, "")}/api/agent/run`;
3800
+ const remoteResponse = await performServerProxyFetchWithRetry({
3801
+ execute: () => fetch(remoteRunUrl, {
3802
+ method: "POST",
3803
+ headers: {
3804
+ "Content-Type": "application/json",
3805
+ Accept: "text/event-stream",
3806
+ ...authHeader ? { Authorization: authHeader } : {}
3807
+ },
3808
+ body: remoteRequestBody,
3809
+ signal: loopController.signal
3810
+ }),
3811
+ signal: loopController.signal,
3812
+ logPrefix: "[streamAgentChatTurn.remoteRun]"
3813
+ });
3814
+ if (!remoteResponse.ok) {
3815
+ const errorText = await remoteResponse.text();
3816
+ return await rejectRemoteStream(
3817
+ errorText || `Remote agent run failed (${remoteResponse.status})`
3818
+ );
3819
+ }
3820
+ const reader = remoteResponse.body?.getReader();
3821
+ if (!reader) {
3822
+ return await rejectRemoteStream("\u65E0\u6CD5\u8BFB\u53D6\u8FDC\u7AEF\u6D41\u5F0F\u54CD\u5E94");
3823
+ }
3824
+ const decoder = new TextDecoder();
3825
+ const parseSSE = createSSEParser();
3826
+ const abortRemoteStream = async () => {
3827
+ if (accumulated.length <= 0) return;
3828
+ await persistMessageWithFixedId(dispatch, buildRemoteAssistantMessage());
3829
+ };
3830
+ try {
3831
+ const result = await consumeAgentRunStream({
3832
+ reader,
3833
+ decoder,
3834
+ parseChunk: (raw) => parseSSE(raw),
3835
+ isAborted: () => loopController.signal.aborted || thunkApi.signal.aborted,
3836
+ signal: loopController.signal,
3837
+ onAbort: abortRemoteStream,
3838
+ isDoneEvent: (payload) => payload?.type === "done",
3839
+ onPayload: async (payload) => {
3840
+ if (payload.type === "error") {
3841
+ return { reject: payload.message || "\u8FDC\u7AEF Agent \u6267\u884C\u5931\u8D25" };
3842
+ }
3843
+ if (payload.type === "agent_handoff") {
3844
+ await patchDialogThreadMetadata(
3845
+ dispatch,
3846
+ dialogKey,
3847
+ payload.threadMetadata
3848
+ );
3849
+ await patchDialogActiveAgent(
3850
+ dispatch,
3851
+ dialogKey,
3852
+ payload.agentKey
3853
+ );
3854
+ }
3855
+ if (payload.type === "text" && typeof payload.content === "string") {
3856
+ accumulated += payload.content;
3857
+ dispatch(messageStreaming({
3858
+ id: messageId,
3859
+ dialogId,
3860
+ dbKey: msgKey,
3861
+ content: accumulated,
3862
+ role: "assistant",
3863
+ ...remoteMessageMetadata
3864
+ }));
3865
+ }
3866
+ if (payload.type === "done") {
3867
+ totalTurnUsage2 = payload.usage;
3868
+ }
3869
+ }
3870
+ });
3871
+ if (result.outcome === "rejected") {
3872
+ return await rejectRemoteStream(result.message);
3873
+ }
3874
+ if (result.outcome === "aborted") {
3875
+ return { aborted: true };
3876
+ }
3877
+ if (result.outcome === "streamEnded") {
3878
+ if (!result.sawDone) {
3879
+ dispatch(finalizeTransientMessageOnError({
3880
+ id: messageId,
3881
+ error: "\u8FDC\u7AEF Agent \u6D41\u5F0F\u54CD\u5E94\u88AB\u4E2D\u65AD,\u672A\u6536\u5230\u5B8C\u6210\u4FE1\u53F7"
3882
+ }));
3883
+ remoteTransientMessageFinalized = true;
3884
+ setLoopStopReason("error");
3885
+ return rejectWithValue(
3886
+ "\u8FDC\u7AEF Agent \u6D41\u5F0F\u54CD\u5E94\u88AB\u4E2D\u65AD,\u672A\u6536\u5230\u5B8C\u6210\u4FE1\u53F7"
3887
+ );
3888
+ }
3889
+ await persistMessageWithFixedId(dispatch, buildRemoteAssistantMessage());
3890
+ remoteTransientMessageFinalized = true;
3891
+ }
3892
+ } finally {
3893
+ try {
3894
+ await reader.cancel();
3895
+ } catch {
3896
+ }
3897
+ }
3898
+ return {
3899
+ usage: totalTurnUsage2 ?? void 0
3900
+ };
3901
+ }
3902
+ }
3903
+ let extractedMentions;
3904
+ if (Array.isArray(userInput)) {
3905
+ extractedMentions = extractCategorizedMentions(userInput);
3906
+ }
3907
+ const mentionedTools = extractedMentions?.tools ?? [];
3908
+ const {
3909
+ references: normalizedReferences,
3910
+ contentByKey: referenceContentCache,
3911
+ referencedTools: referenceTools,
3912
+ recommendedSkillTools: referenceRecommendedSkillTools,
3913
+ recommendedSkillHints: referenceRecommendedSkillHints,
3914
+ skillPromptPatches: referenceSkillPromptPatches
3915
+ } = await resolveReferenceAssets(
3916
+ mergeReferences(agentConfig.references, (selectDialogConfigByKey(getState(), explicitDialogKey) ?? selectCurrentDialogConfig(getState()))?.extraReferences),
3917
+ dispatch
3918
+ );
3919
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-references-resolved", {
3920
+ referenceCount: normalizedReferences?.length ?? 0,
3921
+ referencedToolCount: referenceTools?.length ?? 0
3922
+ });
3923
+ const agentConfigWithReferences = {
3924
+ ...agentConfig,
3925
+ references: normalizedReferences,
3926
+ referencedTools: referenceTools,
3927
+ recommendedSkillTools: referenceRecommendedSkillTools,
3928
+ recommendedSkillHints: referenceRecommendedSkillHints,
3929
+ skillPromptPatches: referenceSkillPromptPatches
3930
+ };
3931
+ const initialRawMsgs = selectAllMsgs(state, dialogId);
3932
+ const initialHistoryIds = new Set(initialRawMsgs.map((m) => m.id));
3933
+ const keySets = await getFullChatContextKeys(
3934
+ state,
3935
+ dispatch,
3936
+ agentConfigWithReferences,
3937
+ userInput,
3938
+ currentDialog ?? void 0
3939
+ );
3940
+ const finalKeys = deduplicateContextKeys(keySets);
3941
+ const allContextKeys = /* @__PURE__ */ new Set([
3942
+ ...finalKeys.botInstructionsContext,
3943
+ ...finalKeys.currentInputContext,
3944
+ ...finalKeys.historyContext,
3945
+ ...finalKeys.botKnowledgeContext
3946
+ ]);
3947
+ const {
3948
+ tools: contextTools,
3949
+ contentByKey: contextContentCache,
3950
+ recommendedSkillTools: contextRecommendedSkillTools = [],
3951
+ recommendedSkillHints: contextRecommendedSkillHints = [],
3952
+ skillPromptPatches: contextSkillPromptPatches = []
3953
+ } = await resolveToolsFromKeys(
3954
+ Array.from(allContextKeys),
3955
+ dispatch,
3956
+ referenceContentCache
3957
+ );
3958
+ const mergedContentCache = new Map([
3959
+ ...referenceContentCache,
3960
+ ...contextContentCache
3961
+ ]);
3962
+ const agentConfigWithTools = mergeAgentToolsWithRuntime(
3963
+ {
3964
+ ...agentConfigWithReferences,
3965
+ recommendedSkillTools: [
3966
+ ...agentConfigWithReferences.recommendedSkillTools ?? [],
3967
+ ...contextRecommendedSkillTools
3968
+ ],
3969
+ recommendedSkillHints: [
3970
+ ...agentConfigWithReferences.recommendedSkillHints ?? [],
3971
+ ...contextRecommendedSkillHints
3972
+ ],
3973
+ skillPromptPatches: [
3974
+ ...agentConfigWithReferences.skillPromptPatches ?? [],
3975
+ ...contextSkillPromptPatches
3976
+ ]
3977
+ },
3978
+ contextTools,
3979
+ mentionedTools,
3980
+ runtimeOptions,
3981
+ state
3982
+ );
3983
+ const agentConfigForCall = applyImageConfigRuntimeOverride(
3984
+ agentConfigWithTools,
3985
+ runtimeOptions
3986
+ );
3987
+ const effectiveAgentConfig = agentConfigForCall;
3988
+ const initialImageGenerationState = resolveImageGenerationStreamingState(
3989
+ effectiveAgentConfig
3990
+ );
3991
+ const streamingMessageMetadata = {
3992
+ ...buildMessageMetadata(agentConfigForCall),
3993
+ ...initialImageGenerationState ? { imageGenerationState: initialImageGenerationState } : {}
3994
+ };
3995
+ const isRespModel = resolveClientWire(
3996
+ resolveAgentCallPlan(agentConfigForCall, {})
3997
+ ) === "responses";
3998
+ if (isRespModel) {
3999
+ const maxExecutionTime2 = selectMaxExecutionTime(state);
4000
+ const MAX_TIME_MS2 = maxExecutionTime2 > 0 ? maxExecutionTime2 : 24e4;
4001
+ const startTime2 = Date.now();
4002
+ const staticContexts2 = await buildStaticContextsWithToolsPrewarm(
4003
+ state,
4004
+ dispatch,
4005
+ agentConfigForCall,
4006
+ currentDialog ?? void 0,
4007
+ mergedContentCache
4008
+ );
4009
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-static-context-ready", {
4010
+ model: agentConfigForCall.model,
4011
+ responseApi: true
4012
+ });
4013
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-post-static-entered", {
4014
+ responseApi: true
4015
+ });
4016
+ let appendTempUserInput2 = true;
4017
+ let currentParentMessageId2 = parentMessageId ?? void 0;
4018
+ const w2 = typeof globalThis !== "undefined" && globalThis.window ? globalThis.window : null;
4019
+ if (w2) w2.__LOOP_STOP_REASON__ = null;
4020
+ loopKey = `loop:${dialogId}`;
4021
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-active-controller-adding", {
4022
+ responseApi: true
4023
+ });
4024
+ dispatch(addActiveController({ messageId: loopKey, controller: loopController, dialogKey }));
4025
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-active-controller-added", {
4026
+ responseApi: true
4027
+ });
4028
+ for (; ; ) {
4029
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-loop-entered", {
4030
+ responseApi: true
4031
+ });
4032
+ const requestParentMessageId = currentParentMessageId2;
4033
+ if (loopController.signal.aborted || thunkApi.signal.aborted) {
4034
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-loop-aborted-before-context", {
4035
+ loopControllerAborted: loopController.signal.aborted,
4036
+ thunkSignalAborted: thunkApi.signal.aborted,
4037
+ responseApi: true
4038
+ });
4039
+ if (w2) w2.__LOOP_STOP_REASON__ = "aborted";
4040
+ return { aborted: true };
4041
+ }
4042
+ const loopState = getState();
4043
+ const now = Date.now();
4044
+ if (now - startTime2 > MAX_TIME_MS2) {
4045
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-loop-timeout-before-context", {
4046
+ maxTimeMs: MAX_TIME_MS2,
4047
+ elapsedMs: now - startTime2,
4048
+ responseApi: true
4049
+ });
4050
+ if (w2) w2.__LOOP_STOP_REASON__ = "timeout";
4051
+ break;
4052
+ }
4053
+ const accessError = validateAccessAndBalance(
4054
+ agentConfigForCall,
4055
+ loopState
4056
+ );
4057
+ if (accessError) {
4058
+ const accessErrorReason = classifyQuickChatAccessError(accessError);
4059
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-access-error-before-context", {
4060
+ hasAccessError: true,
4061
+ reason: accessErrorReason,
4062
+ responseApi: true
4063
+ });
4064
+ if (quickChatPerfStartedAt && runtimeDialogKey && !modelRequestStarted) {
4065
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-access-error-finalized", {
4066
+ reason: accessErrorReason,
4067
+ responseApi: true
4068
+ });
4069
+ await finalizeQuickChatAgentTurnFailure(
4070
+ dispatch,
4071
+ runtimeDialogKey,
4072
+ agentKey,
4073
+ new Error(accessError)
4074
+ );
4075
+ }
4076
+ setLoopStopReason("error");
4077
+ return rejectWithValue(accessError);
4078
+ }
4079
+ const willSkipDynamicContext = canUseQuickChatEmptyDynamicContexts(
4080
+ quickChatPerfStartedAt,
4081
+ userInput,
4082
+ runtimeOptions,
4083
+ currentDialog,
4084
+ agentConfigForCall
4085
+ );
4086
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-dynamic-context-decision", {
4087
+ hasRuntimeOptions: !!runtimeOptions,
4088
+ isSimpleTextInput: isSimpleTextInput(userInput),
4089
+ referenceKeyCount: currentDialog?.referenceKeys?.length ?? 0,
4090
+ willSkipDynamicContext,
4091
+ responseApi: true
4092
+ });
4093
+ const dynamicContexts = willSkipDynamicContext ? (logQuickChatPerfStage2(
4094
+ quickChatPerfStartedAt,
4095
+ "stream-agent-dynamic-context-skipped",
4096
+ {
4097
+ reason: "simple-quick-chat-first-turn",
4098
+ responseApi: true
4099
+ }
4100
+ ), EMPTY_DYNAMIC_CONTEXTS) : await buildDynamicContextsForTurn(
4101
+ loopState,
4102
+ dispatch,
4103
+ agentConfigForCall,
4104
+ userInput,
4105
+ runtimeOptions,
4106
+ mergedContentCache,
4107
+ dialogKey,
4108
+ quickChatPerfStartedAt
4109
+ );
4110
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-dynamic-context-ready", {
4111
+ responseApi: true
4112
+ });
4113
+ const contexts = mergeContexts(staticContexts2, dynamicContexts);
4114
+ const rawMessages = selectAllMsgs(loopState, dialogId);
4115
+ let visibleMessages = buildAgentViewMessages(
4116
+ rawMessages,
4117
+ agentConfigForCall.dbKey
4118
+ );
4119
+ if (appendTempUserInput2 && hasAgentRunUserInputContent(agentRunUserInput) && !isLastMessageMatchingUserInput(visibleMessages, agentRunUserInput)) {
4120
+ visibleMessages = [
4121
+ ...visibleMessages,
4122
+ {
4123
+ id: `__tmp_user_${Date.now()}`,
4124
+ dbKey: "",
4125
+ role: "user",
4126
+ content: agentRunUserInput,
4127
+ thinkContent: "",
4128
+ cybotKey: agentConfigForCall.dbKey,
4129
+ isStreaming: false
4130
+ }
4131
+ ];
4132
+ }
4133
+ const cleanedMessages = filterAndCleanMessages(visibleMessages);
4134
+ const ctxWindow = getModelContextWindow(agentConfigForCall.model) || 128e3;
4135
+ const summaryTokenCount = contexts.dialogSummary ? estimateTokenCount(contexts.dialogSummary) : 0;
4136
+ const processedMessages = trimMessagesWithSummary(
4137
+ compressOldToolResults(cleanedMessages),
4138
+ ctxWindow,
4139
+ summaryTokenCount
4140
+ );
4141
+ let firstDynamicIdx = processedMessages.findIndex(
4142
+ (m) => m.id && !initialHistoryIds.has(m.id)
4143
+ );
4144
+ if (firstDynamicIdx === -1) firstDynamicIdx = processedMessages.length;
4145
+ const stableMessages = processedMessages.slice(0, firstDynamicIdx);
4146
+ const dynamicMessages = processedMessages.slice(firstDynamicIdx);
4147
+ if (appendTempUserInput2) {
4148
+ const rejectReason = shouldRejectImageInputForAgent(
4149
+ agentConfigForCall,
4150
+ processedMessages
4151
+ );
4152
+ if (rejectReason) {
4153
+ setLoopStopReason("error");
4154
+ return rejectWithValue(rejectReason);
4155
+ }
4156
+ }
4157
+ const bodyData = generateRequestBody({
4158
+ agentConfig: effectiveAgentConfig,
4159
+ messages: dynamicMessages,
4160
+ stableMessages,
4161
+ userInput: userInputText,
4162
+ contexts
4163
+ });
4164
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-model-request-starting", {
4165
+ responseApi: true,
4166
+ dynamicMessageCount: dynamicMessages.length,
4167
+ stableMessageCount: stableMessages.length
4168
+ });
4169
+ modelRequestStarted = true;
4170
+ const meta = await sendOpenAIResponseRequest({
4171
+ bodyData,
4172
+ agentConfig: agentConfigForCall,
4173
+ thunkApi,
4174
+ dialogKey,
4175
+ parentMessageId: currentParentMessageId2,
4176
+ messageMetadata: streamingMessageMetadata,
4177
+ quickChatPerfStartedAt
4178
+ });
4179
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-model-request-finished", {
4180
+ responseApi: true,
4181
+ hasToolCalls: meta.hasToolCalls,
4182
+ hasHandedOff: meta.hasHandedOff,
4183
+ hasPendingInteraction: meta.hasPendingInteraction
4184
+ });
4185
+ appendTempUserInput2 = false;
4186
+ currentParentMessageId2 = void 0;
4187
+ totalTurnUsage = updateTotalUsage(totalTurnUsage, meta.usage);
4188
+ if (meta.hasHandedOff) {
4189
+ if (!requestParentMessageId && meta.messageId) {
4190
+ dispatch(removeTransientMessage(meta.messageId));
4191
+ }
4192
+ if (w2) w2.__LOOP_STOP_REASON__ = "handoff";
4193
+ break;
4194
+ }
4195
+ if (meta.hasPendingInteraction) {
4196
+ if (w2) w2.__LOOP_STOP_REASON__ = "pending";
4197
+ break;
4198
+ }
4199
+ const afterTurnState = getState();
4200
+ const queuedMessages = selectPendingUserInputQueue(afterTurnState, dialogKey);
4201
+ if (queuedMessages.length > 0) {
4202
+ const queuedText = queuedMessages[0];
4203
+ const currentDialogConfig = selectDialogConfigByKey(afterTurnState, dialogKey) ?? selectCurrentDialogConfig(afterTurnState);
4204
+ if (!currentDialogConfig) {
4205
+ dispatch(clearPendingUserInputQueue({ dialogKey }));
4206
+ break;
4207
+ }
4208
+ await dispatch(
4209
+ prepareAndPersistUserMessage({
4210
+ userInput: queuedText,
4211
+ dialogConfig: currentDialogConfig
4212
+ })
4213
+ ).unwrap();
4214
+ dispatch(dequeueUserInput({ dialogKey }));
4215
+ continue;
4216
+ }
4217
+ if (!meta.hasToolCalls) {
4218
+ if (w2) w2.__LOOP_STOP_REASON__ = "done";
4219
+ break;
4220
+ }
4221
+ }
4222
+ return {
4223
+ usage: totalTurnUsage ?? void 0
4224
+ };
4225
+ }
4226
+ const maxExecutionTime = selectMaxExecutionTime(state);
4227
+ const MAX_TIME_MS = maxExecutionTime > 0 ? maxExecutionTime : 24e4;
4228
+ const startTime = Date.now();
4229
+ const staticContexts = await buildStaticContextsWithToolsPrewarm(
4230
+ state,
4231
+ dispatch,
4232
+ agentConfigForCall,
4233
+ currentDialog ?? void 0,
4234
+ mergedContentCache
4235
+ );
4236
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-static-context-ready", {
4237
+ model: agentConfigForCall.model,
4238
+ responseApi: false
4239
+ });
4240
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-post-static-entered", {
4241
+ responseApi: false
4242
+ });
4243
+ let appendTempUserInput = true;
4244
+ let currentParentMessageId = parentMessageId ?? void 0;
4245
+ const w = typeof globalThis !== "undefined" && globalThis.window ? globalThis.window : null;
4246
+ if (w) w.__LOOP_STOP_REASON__ = null;
4247
+ if (!isRespModel) {
4248
+ loopKey = `loop:${dialogId}`;
4249
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-active-controller-adding", {
4250
+ responseApi: false
4251
+ });
4252
+ dispatch(addActiveController({ messageId: loopKey, controller: loopController, dialogKey }));
4253
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-active-controller-added", {
4254
+ responseApi: false
4255
+ });
4256
+ }
4257
+ for (; ; ) {
4258
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-loop-entered", {
4259
+ responseApi: false
4260
+ });
4261
+ const requestParentMessageId = currentParentMessageId;
4262
+ if (loopController.signal.aborted || thunkApi.signal.aborted) {
4263
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-loop-aborted-before-context", {
4264
+ loopControllerAborted: loopController.signal.aborted,
4265
+ thunkSignalAborted: thunkApi.signal.aborted,
4266
+ responseApi: false
4267
+ });
4268
+ if (w) w.__LOOP_STOP_REASON__ = "aborted";
4269
+ return { aborted: true };
4270
+ }
4271
+ const loopState = getState();
4272
+ const now = Date.now();
4273
+ if (now - startTime > MAX_TIME_MS) {
4274
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-loop-timeout-before-context", {
4275
+ maxTimeMs: MAX_TIME_MS,
4276
+ elapsedMs: now - startTime,
4277
+ responseApi: false
4278
+ });
4279
+ if (w) w.__LOOP_STOP_REASON__ = "timeout";
4280
+ break;
4281
+ }
4282
+ const accessError = validateAccessAndBalance(
4283
+ agentConfigForCall,
4284
+ loopState
4285
+ );
4286
+ if (accessError) {
4287
+ const accessErrorReason = classifyQuickChatAccessError(accessError);
4288
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-access-error-before-context", {
4289
+ hasAccessError: true,
4290
+ reason: accessErrorReason,
4291
+ responseApi: false
4292
+ });
4293
+ if (quickChatPerfStartedAt && runtimeDialogKey && !modelRequestStarted) {
4294
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-access-error-finalized", {
4295
+ reason: accessErrorReason,
4296
+ responseApi: false
4297
+ });
4298
+ await finalizeQuickChatAgentTurnFailure(
4299
+ dispatch,
4300
+ runtimeDialogKey,
4301
+ agentKey,
4302
+ new Error(accessError)
4303
+ );
4304
+ }
4305
+ setLoopStopReason("error");
4306
+ return rejectWithValue(accessError);
4307
+ }
4308
+ const willSkipDynamicContext = canUseQuickChatEmptyDynamicContexts(
4309
+ quickChatPerfStartedAt,
4310
+ userInput,
4311
+ runtimeOptions,
4312
+ currentDialog,
4313
+ agentConfigForCall
4314
+ );
4315
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-dynamic-context-decision", {
4316
+ hasRuntimeOptions: !!runtimeOptions,
4317
+ isSimpleTextInput: isSimpleTextInput(userInput),
4318
+ referenceKeyCount: currentDialog?.referenceKeys?.length ?? 0,
4319
+ willSkipDynamicContext,
4320
+ responseApi: false
4321
+ });
4322
+ const dynamicContexts = willSkipDynamicContext ? (logQuickChatPerfStage2(
4323
+ quickChatPerfStartedAt,
4324
+ "stream-agent-dynamic-context-skipped",
4325
+ {
4326
+ reason: "simple-quick-chat-first-turn",
4327
+ responseApi: false
4328
+ }
4329
+ ), EMPTY_DYNAMIC_CONTEXTS) : await buildDynamicContextsForTurn(
4330
+ loopState,
4331
+ dispatch,
4332
+ agentConfigForCall,
4333
+ userInput,
4334
+ runtimeOptions,
4335
+ mergedContentCache,
4336
+ dialogKey,
4337
+ quickChatPerfStartedAt
4338
+ );
4339
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-dynamic-context-ready", {
4340
+ responseApi: false
4341
+ });
4342
+ const contexts = mergeContexts(staticContexts, dynamicContexts);
4343
+ const rawMessages = selectAllMsgs(loopState, dialogId);
4344
+ let visibleMessages = buildAgentViewMessages(
4345
+ rawMessages,
4346
+ agentConfigForCall.dbKey
4347
+ );
4348
+ if (appendTempUserInput && hasAgentRunUserInputContent(agentRunUserInput) && !isLastMessageMatchingUserInput(visibleMessages, agentRunUserInput)) {
4349
+ visibleMessages = [
4350
+ ...visibleMessages,
4351
+ {
4352
+ id: `__tmp_user_${Date.now()}`,
4353
+ dbKey: "",
4354
+ role: "user",
4355
+ content: agentRunUserInput,
4356
+ thinkContent: "",
4357
+ cybotKey: agentConfigForCall.dbKey,
4358
+ isStreaming: false
4359
+ }
4360
+ ];
4361
+ }
4362
+ const cleanedMessages = filterAndCleanMessages(visibleMessages);
4363
+ const ctxWindow = getModelContextWindow(agentConfigForCall.model) || 128e3;
4364
+ const summaryTokenCount = contexts.dialogSummary ? estimateTokenCount(contexts.dialogSummary) : 0;
4365
+ const processedMessages = trimMessagesWithSummary(
4366
+ compressOldToolResults(cleanedMessages),
4367
+ ctxWindow,
4368
+ summaryTokenCount
4369
+ );
4370
+ let firstDynamicIdx = processedMessages.findIndex(
4371
+ (m) => m.id && !initialHistoryIds.has(m.id)
4372
+ );
4373
+ if (firstDynamicIdx === -1) firstDynamicIdx = processedMessages.length;
4374
+ const stableMessages = processedMessages.slice(0, firstDynamicIdx);
4375
+ const dynamicMessages = processedMessages.slice(firstDynamicIdx);
4376
+ if (appendTempUserInput) {
4377
+ const rejectReason = shouldRejectImageInputForAgent(
4378
+ agentConfigForCall,
4379
+ processedMessages
4380
+ );
4381
+ if (rejectReason) {
4382
+ setLoopStopReason("error");
4383
+ return rejectWithValue(rejectReason);
4384
+ }
4385
+ }
4386
+ const bodyData = generateRequestBody({
4387
+ agentConfig: effectiveAgentConfig,
4388
+ messages: dynamicMessages,
4389
+ stableMessages,
4390
+ userInput: userInputText,
4391
+ contexts
4392
+ });
4393
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-model-request-starting", {
4394
+ responseApi: false,
4395
+ dynamicMessageCount: dynamicMessages.length,
4396
+ stableMessageCount: stableMessages.length
4397
+ });
4398
+ modelRequestStarted = true;
4399
+ const disableToolsForThisRequest = shouldDisableQuickChatToolsForDirectAnswer(
4400
+ quickChatPerfStartedAt,
4401
+ userInput,
4402
+ runtimeOptions,
4403
+ currentDialog
4404
+ );
4405
+ if (disableToolsForThisRequest) {
4406
+ logQuickChatPerfStage2(
4407
+ quickChatPerfStartedAt,
4408
+ "stream-agent-tools-disabled-for-direct-answer",
4409
+ {
4410
+ responseApi: false,
4411
+ toolCount: Array.isArray(agentConfigForCall.tools) ? agentConfigForCall.tools.length : 0
4412
+ }
4413
+ );
4414
+ }
4415
+ const meta = await sendOpenAICompletionsRequest({
4416
+ bodyData,
4417
+ agentConfig: agentConfigForCall,
4418
+ thunkApi,
4419
+ dialogKey,
4420
+ parentMessageId: currentParentMessageId,
4421
+ messageMetadata: streamingMessageMetadata,
4422
+ disableToolsForThisRequest,
4423
+ quickChatPerfStartedAt
4424
+ });
4425
+ logQuickChatPerfStage2(quickChatPerfStartedAt, "stream-agent-model-request-finished", {
4426
+ responseApi: false,
4427
+ hasToolCalls: meta.hasToolCalls,
4428
+ hasHandedOff: meta.hasHandedOff,
4429
+ hasPendingInteraction: meta.hasPendingInteraction
4430
+ });
4431
+ appendTempUserInput = false;
4432
+ currentParentMessageId = void 0;
4433
+ totalTurnUsage = updateTotalUsage(totalTurnUsage, meta.usage);
4434
+ if (meta.hasHandedOff) {
4435
+ if (!requestParentMessageId && meta.messageId) {
4436
+ dispatch(removeTransientMessage(meta.messageId));
4437
+ }
4438
+ if (w) w.__LOOP_STOP_REASON__ = "handoff";
4439
+ break;
4440
+ }
4441
+ if (meta.hasPendingInteraction) {
4442
+ if (w) w.__LOOP_STOP_REASON__ = "pending";
4443
+ break;
4444
+ }
4445
+ const afterTurnState = getState();
4446
+ const queuedMessages = selectPendingUserInputQueue(afterTurnState, dialogKey);
4447
+ if (queuedMessages.length > 0) {
4448
+ const queuedText = queuedMessages[0];
4449
+ const currentDialogConfig = selectDialogConfigByKey(afterTurnState, dialogKey) ?? selectCurrentDialogConfig(afterTurnState);
4450
+ if (!currentDialogConfig) {
4451
+ dispatch(clearPendingUserInputQueue({ dialogKey }));
4452
+ break;
4453
+ }
4454
+ await dispatch(
4455
+ prepareAndPersistUserMessage({
4456
+ userInput: queuedText,
4457
+ dialogConfig: currentDialogConfig
4458
+ })
4459
+ ).unwrap();
4460
+ dispatch(dequeueUserInput({ dialogKey }));
4461
+ continue;
4462
+ }
4463
+ if (!meta.hasToolCalls) {
4464
+ if (w) w.__LOOP_STOP_REASON__ = "done";
4465
+ break;
4466
+ }
4467
+ }
4468
+ return {
4469
+ usage: totalTurnUsage ?? void 0
4470
+ };
4471
+ } catch (error) {
4472
+ if (isTurnAborted(error)) {
4473
+ turnAborted = true;
4474
+ if (remoteTransientMessageId && !remoteTransientMessageFinalized) {
4475
+ dispatch(removeTransientMessage(remoteTransientMessageId));
4476
+ remoteTransientMessageFinalized = true;
4477
+ }
4478
+ const w = typeof globalThis !== "undefined" && globalThis.window ? globalThis.window : null;
4479
+ if (w) w.__LOOP_STOP_REASON__ = "aborted";
4480
+ return { aborted: true };
4481
+ }
4482
+ console.error(
4483
+ `Error in streamAgentChatTurn for [${agentKey}]:`,
4484
+ error
4485
+ );
4486
+ if (remoteTransientMessageId && !remoteTransientMessageFinalized) {
4487
+ dispatch(finalizeTransientMessageOnError({
4488
+ id: remoteTransientMessageId,
4489
+ error: toErrorMessage(error)
4490
+ }));
4491
+ remoteTransientMessageFinalized = true;
4492
+ setLoopStopReason("error");
4493
+ }
4494
+ if (quickChatPerfStartedAt && runtimeDialogKey && !modelRequestStarted && !remoteTransientMessageId) {
4495
+ await finalizeQuickChatAgentTurnFailure(
4496
+ dispatch,
4497
+ runtimeDialogKey,
4498
+ agentKey,
4499
+ error
4500
+ );
4501
+ } else if (!isTurnAborted(error)) {
4502
+ setLoopStopReason("error");
4503
+ }
4504
+ return rejectWithValue(
4505
+ error?.message || "An unexpected error occurred in streamAgentChatTurn."
4506
+ );
4507
+ } finally {
4508
+ if (loopKey && runtimeDialogKey) {
4509
+ dispatch(removeActiveController({ messageId: loopKey, dialogKey: runtimeDialogKey }));
4510
+ } else if (loopKey) {
4511
+ dispatch(removeActiveController(loopKey));
4512
+ }
4513
+ if (turnAborted) {
4514
+ dispatch(clearPendingUserInputQueue(runtimeDialogKey ? { dialogKey: runtimeDialogKey } : void 0));
4515
+ }
4516
+ if (runtimeDialogKey) {
4517
+ dispatch(runChatQueueTurnEnd({
4518
+ dialogKey: runtimeDialogKey,
4519
+ ok: !turnAborted,
4520
+ aborted: turnAborted
4521
+ }));
4522
+ }
4523
+ thunkApi.signal.removeEventListener("abort", onAbort);
4524
+ }
4525
+ };
4526
+ export {
4527
+ streamAgentChatTurnHandler
4528
+ };