nolo-cli 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,933 @@
1
+ import {
2
+ buildCurrentTimeBlock,
3
+ buildIdentityBlock,
4
+ buildRuntimeGuidanceBlocks
5
+ } from "./chunk-PAKN26FP.js";
6
+ import {
7
+ canonicalizeToolNames
8
+ } from "./chunk-AUQ747NZ.js";
9
+ import {
10
+ clipCompactText
11
+ } from "./chunk-5MMAK75Q.js";
12
+ import {
13
+ findModelConfig,
14
+ getProviderByModelName
15
+ } from "./chunk-BBYVOSU2.js";
16
+ import {
17
+ compactWhitespace
18
+ } from "./chunk-DWLEOOGR.js";
19
+ import {
20
+ toErrorMessage
21
+ } from "./chunk-HNMXYYJR.js";
22
+ import {
23
+ asRecordOrEmpty
24
+ } from "./chunk-KX6YBIHG.js";
25
+ import {
26
+ asTrimmedLowercaseString
27
+ } from "./chunk-QSJ3HFEF.js";
28
+ import {
29
+ asOptionalTrimmedString
30
+ } from "./chunk-G3SUCT4W.js";
31
+ import {
32
+ isRecord
33
+ } from "./chunk-KUG52IAP.js";
34
+
35
+ // packages/agent-runtime/actionGate.ts
36
+ function readCommandActionGatePayload(payload) {
37
+ if (!isRecord(payload)) return null;
38
+ if (!Array.isArray(payload.command)) return null;
39
+ const command = payload.command.flatMap((item) => {
40
+ const value = asOptionalTrimmedString(item);
41
+ return value ? [value] : [];
42
+ });
43
+ if (command.length === 0) return null;
44
+ const displayCommand = asOptionalTrimmedString(payload.displayCommand);
45
+ return {
46
+ command,
47
+ ...displayCommand ? { displayCommand } : {}
48
+ };
49
+ }
50
+ function readActionGate(value) {
51
+ if (!isRecord(value)) return null;
52
+ if (typeof value.id !== "string" || !value.id.trim()) return null;
53
+ if (value.kind !== "confirm" && value.kind !== "handoff" && value.kind !== "input") return null;
54
+ if (typeof value.title !== "string" || !value.title.trim()) return null;
55
+ return {
56
+ id: value.id.trim(),
57
+ kind: value.kind,
58
+ title: value.title.trim(),
59
+ ...asOptionalTrimmedString(value.body) ? { body: asOptionalTrimmedString(value.body) } : {},
60
+ ...Object.prototype.hasOwnProperty.call(value, "payload") ? { payload: value.payload } : {}
61
+ };
62
+ }
63
+
64
+ // packages/ai/llm/agentCapabilities.ts
65
+ var isCustomAgent = (agent) => {
66
+ const apiSource = agent.apiSource?.toLowerCase();
67
+ const provider = agent.provider?.toLowerCase();
68
+ return apiSource === "custom" || provider === "custom";
69
+ };
70
+ var ANTIGRAVITY_EFFORT_SUFFIXES = [
71
+ "-extra-low",
72
+ "-low",
73
+ "-medium",
74
+ "-high"
75
+ ];
76
+ function stripEffortSuffix(model) {
77
+ for (const suffix of ANTIGRAVITY_EFFORT_SUFFIXES) {
78
+ if (model.endsWith(suffix) && model.length > suffix.length) {
79
+ return model.slice(0, -suffix.length);
80
+ }
81
+ }
82
+ return model;
83
+ }
84
+ var lookupKnownModelVision = (provider, model) => {
85
+ if (!model) return void 0;
86
+ const candidates = [model];
87
+ const stripped = stripEffortSuffix(model);
88
+ if (stripped !== model) candidates.push(stripped);
89
+ for (const candidate of candidates) {
90
+ if (provider) {
91
+ const direct = findModelConfig(provider, candidate);
92
+ if (direct) return direct.hasVision;
93
+ }
94
+ const detected = getProviderByModelName(candidate);
95
+ if (detected) {
96
+ const found = findModelConfig(detected, candidate)?.hasVision;
97
+ if (found !== void 0) return found;
98
+ }
99
+ if (!provider && candidate.includes("/")) {
100
+ const slash = candidate.indexOf("/");
101
+ const modelProvider = candidate.slice(0, slash).toLowerCase();
102
+ const modelName = candidate.slice(slash + 1);
103
+ const nested = findModelConfig(modelProvider, modelName);
104
+ if (nested) return nested.hasVision;
105
+ }
106
+ }
107
+ return void 0;
108
+ };
109
+ var resolveAgentImageInputSupport = (agent) => {
110
+ if (!agent) return true;
111
+ const provider = asTrimmedLowercaseString(agent.provider) || null;
112
+ const model = asOptionalTrimmedString(agent.model) ?? "";
113
+ const custom = isCustomAgent(agent);
114
+ const catalogHasVision = lookupKnownModelVision(
115
+ custom ? null : provider,
116
+ model
117
+ );
118
+ if (!custom && catalogHasVision !== void 0) {
119
+ return catalogHasVision;
120
+ }
121
+ if (custom) {
122
+ if (catalogHasVision === true) return true;
123
+ return true;
124
+ }
125
+ if (typeof agent.hasVision === "boolean") {
126
+ return agent.hasVision;
127
+ }
128
+ return true;
129
+ };
130
+
131
+ // packages/agent-runtime/toolCallPairing.ts
132
+ function readToolCallId(message) {
133
+ if (typeof message.tool_call_id === "string" && message.tool_call_id) {
134
+ return message.tool_call_id;
135
+ }
136
+ if (typeof message.toolCallId === "string" && message.toolCallId) {
137
+ return message.toolCallId;
138
+ }
139
+ return void 0;
140
+ }
141
+ function isContentBlank(content) {
142
+ if (content == null) return true;
143
+ if (typeof content === "string") return content.trim().length === 0;
144
+ if (Array.isArray(content)) {
145
+ if (content.length === 0) return true;
146
+ return !content.some((part) => {
147
+ if (part == null || typeof part !== "object") return false;
148
+ const p = part;
149
+ if (p.type === "text") return typeof p.text === "string" && p.text.trim().length > 0;
150
+ if (p.type === "image_url") {
151
+ const url = p.image_url?.url;
152
+ return typeof url === "string" && url.trim().length > 0;
153
+ }
154
+ return true;
155
+ });
156
+ }
157
+ return false;
158
+ }
159
+ function sanitizeToolCallPairing(messages) {
160
+ const assistantIndexByCallId = /* @__PURE__ */ new Map();
161
+ for (let i = 0; i < messages.length; i += 1) {
162
+ const m = messages[i];
163
+ if (m == null) continue;
164
+ if (m.role !== "assistant") continue;
165
+ const toolCalls = m.tool_calls;
166
+ if (!Array.isArray(toolCalls)) continue;
167
+ for (const call of toolCalls) {
168
+ const id = call?.id;
169
+ if (typeof id !== "string" || !id) continue;
170
+ if (!assistantIndexByCallId.has(id)) {
171
+ assistantIndexByCallId.set(id, i);
172
+ }
173
+ }
174
+ }
175
+ const toolByCallId = /* @__PURE__ */ new Map();
176
+ for (let i = 0; i < messages.length; i += 1) {
177
+ const m = messages[i];
178
+ if (m == null) continue;
179
+ if (m.role !== "tool") continue;
180
+ const id = readToolCallId(m);
181
+ if (typeof id !== "string" || !id) continue;
182
+ if (!toolByCallId.has(id)) {
183
+ toolByCallId.set(id, m);
184
+ }
185
+ }
186
+ const output = [];
187
+ const consumedToolCallIds = /* @__PURE__ */ new Set();
188
+ for (let i = 0; i < messages.length; i += 1) {
189
+ const m = messages[i];
190
+ if (m == null) continue;
191
+ if (m.role === "tool") continue;
192
+ if (m.role !== "assistant") {
193
+ output.push(m);
194
+ continue;
195
+ }
196
+ const toolCalls = m.tool_calls;
197
+ if (!Array.isArray(toolCalls) || toolCalls.length === 0) {
198
+ output.push(m);
199
+ continue;
200
+ }
201
+ const matchedToolCalls = [];
202
+ const matchedToolMessages = [];
203
+ for (const call of toolCalls) {
204
+ const id = call?.id;
205
+ if (typeof id !== "string" || !id) continue;
206
+ const toolMessage = toolByCallId.get(id);
207
+ if (!toolMessage) continue;
208
+ if (assistantIndexByCallId.get(id) !== i) continue;
209
+ if (consumedToolCallIds.has(id)) continue;
210
+ matchedToolCalls.push(call);
211
+ matchedToolMessages.push(toolMessage);
212
+ consumedToolCallIds.add(id);
213
+ }
214
+ if (matchedToolCalls.length === 0) {
215
+ const { tool_calls: _drop, ...rest } = m;
216
+ const stripped = rest;
217
+ if (isContentBlank(stripped.content)) {
218
+ continue;
219
+ }
220
+ output.push(stripped);
221
+ continue;
222
+ }
223
+ const normalizedAssistant = { ...m, tool_calls: matchedToolCalls };
224
+ output.push(normalizedAssistant);
225
+ for (const toolMessage of matchedToolMessages) {
226
+ output.push(toolMessage);
227
+ }
228
+ }
229
+ return output;
230
+ }
231
+
232
+ // packages/agent-runtime/parseToolArguments.ts
233
+ function parseToolArgumentsJson(raw) {
234
+ if (!raw?.trim()) return {};
235
+ try {
236
+ return asRecordOrEmpty(JSON.parse(raw));
237
+ } catch {
238
+ return {};
239
+ }
240
+ }
241
+
242
+ // packages/agent-runtime/summarizeToolArguments.ts
243
+ function clip(value, max = 240) {
244
+ return clipCompactText(value, max);
245
+ }
246
+ function summarizeToolArguments(toolName, rawArgs) {
247
+ const args = parseToolArgumentsJson(rawArgs);
248
+ const pick = (...keys2) => {
249
+ for (const key of keys2) {
250
+ const value = asOptionalTrimmedString(args[key]);
251
+ if (value) return value;
252
+ }
253
+ return "";
254
+ };
255
+ const command = pick("command", "cmd", "runCommand", "executeCommand", "bash");
256
+ if (command) return clip(command);
257
+ const query = pick("query", "pattern", "search", "q");
258
+ if (query) return clip(query);
259
+ const filePath = pick("filePath", "file_path", "path", "filename", "file");
260
+ if (filePath) return clip(filePath);
261
+ const keys = Object.keys(args);
262
+ if (keys.length === 0) return "";
263
+ return clip(
264
+ keys.slice(0, 6).map((key) => {
265
+ const value = args[key];
266
+ if (typeof value === "string") return `${key}=${clip(value, 80)}`;
267
+ if (typeof value === "number" || typeof value === "boolean") {
268
+ return `${key}=${String(value)}`;
269
+ }
270
+ if (Array.isArray(value)) return `${key}[${value.length}]`;
271
+ return `${key}=${value === null ? "null" : typeof value}`;
272
+ }).join(" ")
273
+ );
274
+ }
275
+
276
+ // packages/agent-runtime/localLoop.ts
277
+ var LOCAL_AGENT_CONFIG_MISSING_CODE = "LOCAL_AGENT_CONFIG_MISSING";
278
+ var EMPTY_ASSISTANT_REPAIR_PROMPT = "\u8BF7\u7ED9\u51FA\u660E\u786E\u7684\u6587\u5B57\u56DE\u7B54\u6216\u6267\u884C\u4E0B\u4E00\u6B65\uFF1A\u5982\u679C\u4EFB\u52A1\u5DF2\u5B8C\u6210\uFF0C\u8BF7\u76F4\u63A5\u603B\u7ED3\u7ED3\u679C\uFF1B\u5982\u679C\u9700\u8981\u8C03\u7528\u5DE5\u5177\uFF0C\u8BF7\u76F4\u63A5\u8F93\u51FA tool_calls\u3002\u8BF7\u5207\u52FF\u8FD4\u56DE\u7A7A\u5185\u5BB9\u3002";
279
+ var EMPTY_ASSISTANT_FALLBACK_MESSAGE = "\u6A21\u578B\u8FDE\u7EED\u8FD4\u56DE\u7A7A\u6D88\u606F\uFF0C\u5F53\u524D\u4EFB\u52A1\u672A\u5B8C\u6210\u3002\u8BF7\u91CD\u8BD5\u5F53\u524D\u6B65\u9AA4\uFF0C\u6216\u7ED9\u51FA\u66F4\u5177\u4F53\u7684\u4FEE\u6539\u8303\u56F4\u3002";
280
+ var LENGTH_TRUNCATED_FALLBACK_MESSAGE = "\u8F93\u51FA\u8FBE\u5230\u957F\u5EA6\u4E0A\u9650\u88AB\u622A\u65AD\uFF0C\u5EFA\u8BAE\u7F29\u77ED\u4EFB\u52A1\u6216\u63D0\u9AD8\u8F93\u51FA\u4E0A\u9650\u3002";
281
+ var STREAM_TRUNCATED_FALLBACK_MESSAGE = "\u4E0A\u6E38\u54CD\u5E94\u6D41\u5728\u6536\u5C3E\u524D\u88AB\u4E2D\u65AD\uFF08\u672A\u6536\u5230\u7ED3\u675F\u6807\u8BB0\uFF09\uFF0C\u672C\u8F6E\u8F93\u51FA\u4E0D\u5B8C\u6574\u3002\u8BF7\u91CD\u8BD5\u5F53\u524D\u6B65\u9AA4\u3002";
282
+ function resolveEmptyAssistantOutcome(args) {
283
+ if (args.hasToolCalls || args.hasVisibleOutput) return { kind: "ok" };
284
+ if (args.finishReason === "length") return { kind: "fallback", reason: "length_truncated" };
285
+ if (!args.repairUsed) return { kind: "repair" };
286
+ if (!args.finishReason) return { kind: "fallback", reason: "stream_truncated" };
287
+ return { kind: "fallback", reason: "empty_completion" };
288
+ }
289
+ function resolveEmptyAssistantFallbackMessage(reason) {
290
+ if (reason === "length_truncated") return LENGTH_TRUNCATED_FALLBACK_MESSAGE;
291
+ if (reason === "stream_truncated") return STREAM_TRUNCATED_FALLBACK_MESSAGE;
292
+ return EMPTY_ASSISTANT_FALLBACK_MESSAGE;
293
+ }
294
+ function hasAssistantVisibleOutput(content) {
295
+ if (typeof content === "string") return content.trim().length > 0;
296
+ if (!Array.isArray(content)) return false;
297
+ return content.some((part) => {
298
+ if (part?.type === "text" && String(part.text ?? "").trim()) return true;
299
+ if (part?.type === "image_url") {
300
+ const url = part?.image_url?.url;
301
+ return typeof url === "string" && url.trim().length > 0;
302
+ }
303
+ return false;
304
+ });
305
+ }
306
+ function formatToolExecutionError(args) {
307
+ const message = toErrorMessage(args.error);
308
+ return `${args.toolName} failed: ${message}`;
309
+ }
310
+ function formatStructuredToolExecutionError(args) {
311
+ if (!args.error || typeof args.error !== "object") return null;
312
+ const error = args.error;
313
+ if (typeof error.code !== "string") return null;
314
+ return JSON.stringify({
315
+ error: error.code,
316
+ message: typeof error.message === "string" ? error.message : formatToolExecutionError(args),
317
+ ...error.policy && typeof error.policy === "object" ? { policy: error.policy } : {},
318
+ ...error.permissionRequest && typeof error.permissionRequest === "object" ? { permissionRequest: error.permissionRequest } : {}
319
+ });
320
+ }
321
+ function shouldReturnToolExecutionErrors(adapter) {
322
+ return adapter.capabilities.includes("local-tools");
323
+ }
324
+ function emitToolEvent(input, event) {
325
+ input.onToolEvent?.(event);
326
+ }
327
+ function emitLoopEvent(input, event) {
328
+ if (!input.onLoopEvent) return;
329
+ try {
330
+ input.onLoopEvent(event);
331
+ } catch {
332
+ }
333
+ }
334
+ var LLM_REQUEST_TIMEOUT = "LLM_REQUEST_TIMEOUT";
335
+ var LOCAL_TURN_ABORTED_CODE = "LOCAL_TURN_ABORTED";
336
+ function buildAbortedError() {
337
+ const error = new Error("local agent turn aborted by user");
338
+ error.code = LOCAL_TURN_ABORTED_CODE;
339
+ return error;
340
+ }
341
+ function throwIfAborted(input) {
342
+ if (input.abortSignal?.aborted) throw buildAbortedError();
343
+ }
344
+ function resolveLlmRequestTimeoutMs(input) {
345
+ const raw = input.llmRequestTimeoutMs ?? input.timeoutMs;
346
+ if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) return void 0;
347
+ return raw;
348
+ }
349
+ async function runCompleteWithTimeout(args) {
350
+ const { provider, messages, options, timeoutMs, round, input } = args;
351
+ emitLoopEvent(input, { kind: "llm-start", round, atMs: Date.now() });
352
+ const complete = provider.complete(messages, options);
353
+ let ok = false;
354
+ const signal = input.abortSignal;
355
+ let abortListener;
356
+ const racers = [];
357
+ if (signal) {
358
+ racers.push(
359
+ new Promise((_resolve, reject) => {
360
+ abortListener = () => reject(buildAbortedError());
361
+ if (signal.aborted) {
362
+ abortListener();
363
+ return;
364
+ }
365
+ signal.addEventListener("abort", abortListener, { once: true });
366
+ })
367
+ );
368
+ }
369
+ let timer;
370
+ if (typeof timeoutMs === "number") {
371
+ racers.push(
372
+ new Promise((_resolve, reject) => {
373
+ timer = setTimeout(() => {
374
+ reject(new Error(`__llm_timeout__:${timeoutMs}`));
375
+ }, timeoutMs);
376
+ })
377
+ );
378
+ }
379
+ let result;
380
+ try {
381
+ result = racers.length === 0 ? await complete : await Promise.race([complete, ...racers]);
382
+ ok = true;
383
+ return result;
384
+ } catch (error) {
385
+ const isTimeout = error instanceof Error && error.message.startsWith("__llm_timeout__:");
386
+ if (!isTimeout) throw error;
387
+ const timeoutError = new Error(
388
+ `LLM request timed out after ${timeoutMs}ms (round ${round})`
389
+ );
390
+ timeoutError.code = LLM_REQUEST_TIMEOUT;
391
+ throw timeoutError;
392
+ } finally {
393
+ if (timer) clearTimeout(timer);
394
+ if (signal && abortListener) signal.removeEventListener("abort", abortListener);
395
+ const usage = result?.usage;
396
+ const cacheHit = Number(usage?.cache_read_input_tokens ?? usage?.prompt_cache_hit_tokens ?? 0);
397
+ const cacheMiss = Number(usage?.cache_creation_input_tokens ?? usage?.prompt_cache_miss_tokens ?? 0);
398
+ const inputTokens = Number(usage?.input_tokens ?? usage?.prompt_tokens ?? 0);
399
+ const outputTokens = Number(usage?.output_tokens ?? usage?.completion_tokens ?? 0);
400
+ emitLoopEvent(input, {
401
+ kind: "llm-end",
402
+ round,
403
+ atMs: Date.now(),
404
+ ok,
405
+ ...inputTokens > 0 || cacheHit > 0 || cacheMiss > 0 ? {
406
+ cache: {
407
+ inputTokens,
408
+ outputTokens,
409
+ cacheHitTokens: cacheHit,
410
+ cacheMissTokens: cacheMiss,
411
+ hitRatio: inputTokens > 0 ? Math.round(cacheHit / inputTokens * 1e4) / 1e4 : 0
412
+ }
413
+ } : {}
414
+ });
415
+ }
416
+ }
417
+ function clip2(value, max = 240) {
418
+ return clipCompactText(value, max);
419
+ }
420
+ function summarizeToolResult(content, metadata) {
421
+ const parts = [];
422
+ const exitCode = metadata?.exitCode;
423
+ if (typeof exitCode === "number") parts.push(`exit=${exitCode}`);
424
+ if (typeof content === "string") {
425
+ const trimmed = content.trim();
426
+ if (trimmed) {
427
+ const lines = trimmed.split(/\r?\n/).length;
428
+ parts.push(`${lines} line${lines === 1 ? "" : "s"}`);
429
+ parts.push(`${trimmed.length} chars`);
430
+ const tail = clip2(trimmed.slice(-160), 160);
431
+ if (tail) parts.push(`tail="${tail}"`);
432
+ } else {
433
+ parts.push("empty");
434
+ }
435
+ }
436
+ return parts.join(" ");
437
+ }
438
+ function formatToolMessageContent(args) {
439
+ if (args.toolName !== "listFiles" && args.toolName !== "globFiles" && args.toolName !== "searchFiles" && args.toolName !== "readFile" || !args.metadata || Object.keys(args.metadata).length === 0) {
440
+ return args.content;
441
+ }
442
+ return `${args.content}
443
+
444
+ [tool metadata]
445
+ ${JSON.stringify(args.metadata)}`;
446
+ }
447
+ function blocksToOpenAiMessages(blocks) {
448
+ const out = [];
449
+ let text = "";
450
+ let reasoning = "";
451
+ let pendingToolCalls = [];
452
+ let pendingToolResults = [];
453
+ const flushSegment = () => {
454
+ if (text === "" && pendingToolCalls.length === 0 && reasoning === "") return;
455
+ out.push({
456
+ role: "assistant",
457
+ content: text || null,
458
+ ...reasoning ? { reasoning_content: reasoning } : {},
459
+ ...pendingToolCalls.length > 0 ? { tool_calls: pendingToolCalls } : {}
460
+ });
461
+ for (let i = 0; i < pendingToolCalls.length; i += 1) {
462
+ const tc = pendingToolCalls[i];
463
+ const res = pendingToolResults[i];
464
+ out.push({
465
+ role: "tool",
466
+ content: formatToolMessageContent({
467
+ toolName: tc.function.name,
468
+ content: res?.content ?? "",
469
+ ...res?.metadata ? { metadata: res.metadata } : {}
470
+ }),
471
+ tool_call_id: tc.id,
472
+ toolName: tc.function.name,
473
+ ...res?.metadata ? { tool_result_metadata: res.metadata } : {}
474
+ });
475
+ }
476
+ text = "";
477
+ reasoning = "";
478
+ pendingToolCalls = [];
479
+ pendingToolResults = [];
480
+ };
481
+ for (const block of blocks) {
482
+ if (block.type === "text") {
483
+ if (pendingToolCalls.length > 0) {
484
+ flushSegment();
485
+ }
486
+ text += block.text;
487
+ continue;
488
+ }
489
+ if (block.type === "thinking") {
490
+ reasoning += block.thinking;
491
+ continue;
492
+ }
493
+ if (block.type === "toolCall") {
494
+ pendingToolCalls.push(block.toolCall);
495
+ pendingToolResults.push({
496
+ content: block.result?.content ?? "",
497
+ ...block.result?.metadata ? { metadata: block.result.metadata } : {}
498
+ });
499
+ }
500
+ }
501
+ flushSegment();
502
+ return out;
503
+ }
504
+ function buildActionGate(args) {
505
+ const gate = readActionGate(args.metadata?.actionGate);
506
+ if (!gate) return null;
507
+ if (gate.kind === "handoff" && !readCommandActionGatePayload(gate.payload)) return null;
508
+ return {
509
+ ...gate,
510
+ toolName: args.toolName,
511
+ toolCallId: args.toolCallId
512
+ };
513
+ }
514
+ var MAX_HISTORICAL_TOOL_CONTENT_CHARS = 1600;
515
+ var MAX_IN_TURN_TOOL_CONTENT_CHARS = 4e3;
516
+ function summarizeToolContentForProvider(content, maxChars, label) {
517
+ if (typeof content !== "string") return content;
518
+ if (content.length <= maxChars) return content;
519
+ const compact = compactWhitespace(content);
520
+ const clipped = compact.length > maxChars ? compact.slice(0, maxChars - 160) : compact;
521
+ return [
522
+ `[${label}]`,
523
+ `originalChars=${content.length}`,
524
+ clipped
525
+ ].join("\n");
526
+ }
527
+ function summarizeHistoricalToolContent(content) {
528
+ return summarizeToolContentForProvider(
529
+ content,
530
+ MAX_HISTORICAL_TOOL_CONTENT_CHARS,
531
+ "historical tool result truncated for the next turn"
532
+ );
533
+ }
534
+ function prepareMessagesForProviderCall(messages) {
535
+ const paired = sanitizeToolCallPairing(messages);
536
+ return paired.map((message) => {
537
+ const sanitizedContent = message.content == null ? "" : typeof message.content === "string" ? message.content : message.content;
538
+ if (message.role !== "tool") {
539
+ return {
540
+ ...message,
541
+ content: sanitizedContent
542
+ };
543
+ }
544
+ return {
545
+ ...message,
546
+ content: summarizeToolContentForProvider(
547
+ sanitizedContent,
548
+ MAX_IN_TURN_TOOL_CONTENT_CHARS,
549
+ "in-turn tool result truncated before next provider call"
550
+ )
551
+ };
552
+ });
553
+ }
554
+ function prepareHistoryForNextTurn(history) {
555
+ return history.map((message) => {
556
+ if (message.role !== "tool") return message;
557
+ return {
558
+ ...message,
559
+ content: summarizeHistoricalToolContent(message.content)
560
+ };
561
+ });
562
+ }
563
+ var IMAGE_OMITTED_PLACEHOLDER = "[Image content omitted: model does not support image input]";
564
+ function stripImagePartsFromContent(content) {
565
+ if (!Array.isArray(content)) return content;
566
+ const filtered = content.filter((part) => part?.type !== "image_url");
567
+ if (filtered.length === 0) return IMAGE_OMITTED_PLACEHOLDER;
568
+ return filtered;
569
+ }
570
+ function filterImagePartsFromMessages(messages, supportsImages) {
571
+ if (supportsImages) return messages;
572
+ return messages.map((msg) => ({
573
+ ...msg,
574
+ content: stripImagePartsFromContent(msg.content)
575
+ }));
576
+ }
577
+ function buildMessages(args) {
578
+ if (args.contextBlockScopes?.length) {
579
+ const blocks2 = args.contextBlockScopes.filter((b) => b.content.trim());
580
+ const stableParts = [args.prompt?.trim(), ...blocks2.filter((b) => b.cacheScope === "session").map((b) => b.content)].filter(Boolean);
581
+ const dynamicParts = blocks2.filter((b) => b.cacheScope === "turn").map((b) => b.content).filter(Boolean);
582
+ const stableContent = stableParts.join("\n\n");
583
+ const dynamicContent = dynamicParts.join("\n\n");
584
+ const systemContent2 = dynamicContent ? `${stableContent}
585
+
586
+ ${dynamicContent}` : stableContent;
587
+ return [
588
+ ...systemContent2 ? [{ role: "system", content: systemContent2 }] : [],
589
+ ...prepareHistoryForNextTurn(args.history),
590
+ { role: "user", content: args.input }
591
+ ];
592
+ }
593
+ const blocks = (args.contextBlocks ?? []).map((block) => block.trim()).filter(Boolean);
594
+ const systemContent = [args.prompt?.trim(), ...blocks].filter(Boolean).join("\n\n");
595
+ return [
596
+ ...systemContent ? [{ role: "system", content: systemContent }] : [],
597
+ ...prepareHistoryForNextTurn(args.history),
598
+ { role: "user", content: args.input }
599
+ ];
600
+ }
601
+ function mergeTurnUsage(current, next) {
602
+ if (!next) return current;
603
+ const read = (usage) => ({
604
+ input: Number(usage.input_tokens ?? usage.prompt_tokens ?? 0),
605
+ output: Number(usage.output_tokens ?? usage.completion_tokens ?? 0),
606
+ cacheHit: Number(
607
+ usage.cache_read_input_tokens ?? usage.prompt_cache_hit_tokens ?? 0
608
+ ),
609
+ cacheMiss: Number(
610
+ usage.cache_creation_input_tokens ?? usage.prompt_cache_miss_tokens ?? 0
611
+ )
612
+ });
613
+ const right = read(next);
614
+ const left = current ? read(current) : { input: 0, output: 0, cacheHit: 0, cacheMiss: 0 };
615
+ return {
616
+ input_tokens: right.input || left.input,
617
+ output_tokens: left.output + right.output,
618
+ cache_read_input_tokens: left.cacheHit + right.cacheHit,
619
+ cache_creation_input_tokens: left.cacheMiss + right.cacheMiss
620
+ };
621
+ }
622
+ function extractUserInputText(content) {
623
+ if (typeof content === "string") return content;
624
+ if (!Array.isArray(content)) return "";
625
+ return content.flatMap((part) => part?.type === "text" && part.text ? [part.text] : []).join("\n").trim();
626
+ }
627
+ async function runLocalAgentTurn(input) {
628
+ const agentConfig = await input.adapter.loadAgentConfig(input.agentRef);
629
+ if (!agentConfig) {
630
+ const error = new Error(`Local agent config not found: ${input.agentRef}`);
631
+ error.code = LOCAL_AGENT_CONFIG_MISSING_CODE;
632
+ error.agentRef = input.agentRef;
633
+ throw error;
634
+ }
635
+ const history = input.continueDialogId ? await input.adapter.loadDialogHistory(input.continueDialogId) : [];
636
+ const identityBlock = buildIdentityBlock({
637
+ agentName: agentConfig.name,
638
+ agentId: agentConfig.key,
639
+ model: agentConfig.model
640
+ });
641
+ const agentTools = canonicalizeToolNames(agentConfig.toolNames ?? []);
642
+ const guidanceBlocks = buildRuntimeGuidanceBlocks(agentTools);
643
+ const guidanceScopes = [
644
+ guidanceBlocks.startupProtocol,
645
+ guidanceBlocks.contextLayerContract,
646
+ guidanceBlocks.emailRegistrationWorkflow,
647
+ guidanceBlocks.webResearchToolPolicy
648
+ ].map((content) => content.trim()).filter((content) => content.length > 0).map((content) => ({ content, cacheScope: "session" }));
649
+ const currentTimeScope = [
650
+ { content: buildCurrentTimeBlock(/* @__PURE__ */ new Date(), void 0), cacheScope: "turn" }
651
+ ];
652
+ const mergedContextBlockScopes = [
653
+ { content: identityBlock, cacheScope: "session" },
654
+ ...guidanceScopes,
655
+ ...currentTimeScope,
656
+ ...input.contextBlockScopes ?? []
657
+ ];
658
+ const hasContextBlocks = (input.contextBlocks ?? []).some(
659
+ (block) => block.trim()
660
+ ) || mergedContextBlockScopes.some(
661
+ (block) => block.content.trim()
662
+ );
663
+ const promptMessageCount = agentConfig.prompt?.trim() || hasContextBlocks ? 1 : 0;
664
+ const turnStartIndex = promptMessageCount + history.length;
665
+ const messages = buildMessages({
666
+ prompt: agentConfig.prompt,
667
+ contextBlocks: input.contextBlocks,
668
+ contextBlockScopes: mergedContextBlockScopes,
669
+ history,
670
+ input: input.input
671
+ });
672
+ const provider = await input.adapter.resolveProvider(agentConfig);
673
+ const supportsImages = resolveAgentImageInputSupport({
674
+ apiSource: agentConfig.apiSource,
675
+ provider: agentConfig.provider,
676
+ model: agentConfig.model,
677
+ hasVision: agentConfig.hasVision
678
+ });
679
+ const userInputText = extractUserInputText(input.input);
680
+ let toolCallCount = 0;
681
+ let result;
682
+ let turnUsage;
683
+ let loopError;
684
+ let round = 0;
685
+ let emptyAssistantRepairPending = false;
686
+ let emptyAssistantRepairUsed = false;
687
+ let imageDowngradeNotified = false;
688
+ let skipFinalAppend = false;
689
+ let partialContent = "";
690
+ try {
691
+ while (true) {
692
+ partialContent = "";
693
+ throwIfAborted(input);
694
+ const baseRequestMessages = filterImagePartsFromMessages(
695
+ prepareMessagesForProviderCall(messages),
696
+ supportsImages
697
+ );
698
+ if (!supportsImages && !imageDowngradeNotified && messages.some((m) => Array.isArray(m.content) && m.content.some((p) => p?.type === "image_url"))) {
699
+ imageDowngradeNotified = true;
700
+ emitLoopEvent(input, {
701
+ kind: "image-downgraded",
702
+ reason: "no-vision",
703
+ atMs: Date.now()
704
+ });
705
+ }
706
+ const requestMessages = emptyAssistantRepairPending ? [...baseRequestMessages, { role: "user", content: EMPTY_ASSISTANT_REPAIR_PROMPT }] : baseRequestMessages;
707
+ emptyAssistantRepairPending = false;
708
+ result = await runCompleteWithTimeout({
709
+ provider,
710
+ messages: requestMessages,
711
+ options: {
712
+ ...typeof input.timeoutMs === "number" ? { timeoutMs: input.timeoutMs } : {},
713
+ ...input.onTextDelta ? { onTextDelta: (chunk) => {
714
+ partialContent += chunk;
715
+ input.onTextDelta(chunk);
716
+ } } : {},
717
+ ...input.onReasoningDelta ? { onReasoningDelta: input.onReasoningDelta } : {},
718
+ ...input.onToolEvent ? { onToolEvent: input.onToolEvent } : {},
719
+ ...input.onToolEvent ? { toolEventRound: round } : {}
720
+ },
721
+ timeoutMs: resolveLlmRequestTimeoutMs(input),
722
+ round,
723
+ input
724
+ });
725
+ turnUsage = mergeTurnUsage(turnUsage, result.usage);
726
+ const toolCalls = result.tool_calls ?? [];
727
+ const rawToolCallsCount = (result.tool_calls?.length ?? 0) || (Array.isArray(result.raw_tool_calls) ? result.raw_tool_calls.length : 0);
728
+ if (toolCalls.length === 0 && rawToolCallsCount === 0) {
729
+ const outcome = resolveEmptyAssistantOutcome({
730
+ hasToolCalls: rawToolCallsCount > 0,
731
+ hasVisibleOutput: hasAssistantVisibleOutput(result.content),
732
+ repairUsed: emptyAssistantRepairUsed,
733
+ finishReason: result.finish_reason
734
+ });
735
+ if (outcome.kind === "repair") {
736
+ emptyAssistantRepairPending = true;
737
+ emptyAssistantRepairUsed = true;
738
+ continue;
739
+ }
740
+ if (outcome.kind === "fallback") {
741
+ result = {
742
+ ...result,
743
+ content: resolveEmptyAssistantFallbackMessage(outcome.reason)
744
+ };
745
+ break;
746
+ }
747
+ break;
748
+ }
749
+ const outputBlocks = result.output ?? [];
750
+ if (outputBlocks.length > 0) {
751
+ let hasInlineExecutedTools = false;
752
+ for (const block of outputBlocks) {
753
+ if (block.type !== "toolCall") continue;
754
+ toolCallCount += 1;
755
+ const toolName = block.toolCall.function.name;
756
+ if (block.result) {
757
+ hasInlineExecutedTools = true;
758
+ } else {
759
+ throw new Error(
760
+ `provider returned output block with unexecuted toolCall "${toolName}" (id=${block.toolCall.id}); no provider currently emits this shape. Either the provider must fill block.result (like Cursor's exec channel) or it must not set result.output at all.`
761
+ );
762
+ }
763
+ }
764
+ if (hasInlineExecutedTools) {
765
+ messages.push(...blocksToOpenAiMessages(outputBlocks));
766
+ skipFinalAppend = true;
767
+ break;
768
+ }
769
+ round += 1;
770
+ continue;
771
+ }
772
+ toolCallCount += toolCalls.length;
773
+ messages.push({
774
+ role: "assistant",
775
+ content: result.content || null,
776
+ ...result.reasoning_content ? { reasoning_content: result.reasoning_content } : {},
777
+ tool_calls: toolCalls
778
+ });
779
+ for (const toolCall of toolCalls) {
780
+ throwIfAborted(input);
781
+ const toolName = toolCall.function.name;
782
+ let toolResult;
783
+ const startedAt = Date.now();
784
+ emitLoopEvent(input, { kind: "tool-start", name: toolName, atMs: Date.now() });
785
+ emitToolEvent(input, {
786
+ type: "tool-call",
787
+ round,
788
+ toolCallId: toolCall.id,
789
+ toolName,
790
+ argumentsPreview: summarizeToolArguments(toolName, toolCall.function.arguments)
791
+ });
792
+ try {
793
+ toolResult = await input.adapter.executeTool({
794
+ id: toolCall.id,
795
+ name: toolName,
796
+ arguments: toolCall.function.arguments,
797
+ ...userInputText ? { userInput: userInputText } : {},
798
+ ...input.abortSignal ? { abortSignal: input.abortSignal } : {}
799
+ });
800
+ const actionGate = buildActionGate({
801
+ toolName,
802
+ toolCallId: toolCall.id,
803
+ metadata: toolResult.metadata
804
+ });
805
+ if (actionGate && input.onActionGate) {
806
+ const replacement = await input.onActionGate(actionGate);
807
+ if (replacement) {
808
+ toolResult = replacement;
809
+ }
810
+ }
811
+ emitLoopEvent(input, { kind: "tool-end", name: toolName, atMs: Date.now(), ok: true });
812
+ emitToolEvent(input, {
813
+ type: "tool-result",
814
+ round,
815
+ toolCallId: toolCall.id,
816
+ toolName,
817
+ elapsedMs: Math.max(0, Date.now() - startedAt),
818
+ summary: summarizeToolResult(toolResult.content, toolResult.metadata),
819
+ ...typeof toolResult.content === "string" ? { content: toolResult.content } : {},
820
+ metadata: toolResult.metadata
821
+ });
822
+ } catch (error) {
823
+ emitLoopEvent(input, { kind: "tool-end", name: toolName, atMs: Date.now(), ok: false });
824
+ if (!shouldReturnToolExecutionErrors(input.adapter)) throw error;
825
+ emitToolEvent(input, {
826
+ type: "tool-error",
827
+ round,
828
+ toolCallId: toolCall.id,
829
+ toolName,
830
+ elapsedMs: Math.max(0, Date.now() - startedAt),
831
+ message: toErrorMessage(error)
832
+ });
833
+ toolResult = {
834
+ content: formatStructuredToolExecutionError({ toolName, error }) ?? formatToolExecutionError({ toolName, error }),
835
+ metadata: {
836
+ error: true,
837
+ toolName,
838
+ message: toErrorMessage(error),
839
+ ...error && typeof error === "object" && typeof error.code === "string" ? { code: error.code } : {}
840
+ }
841
+ };
842
+ }
843
+ messages.push({
844
+ role: "tool",
845
+ content: formatToolMessageContent({
846
+ toolName,
847
+ content: toolResult.content,
848
+ metadata: toolResult.metadata
849
+ }),
850
+ tool_call_id: toolCall.id,
851
+ toolName,
852
+ ...toolResult.metadata ? { tool_result_metadata: toolResult.metadata } : {}
853
+ });
854
+ }
855
+ round += 1;
856
+ }
857
+ } catch (error) {
858
+ loopError = error;
859
+ }
860
+ if (loopError) {
861
+ const errorMessage = toErrorMessage(loopError);
862
+ const turnMessages2 = messages.slice(turnStartIndex);
863
+ const saved2 = await input.adapter.saveTurn({
864
+ agentKey: agentConfig.key,
865
+ messages: turnMessages2,
866
+ result: {
867
+ content: partialContent || `[nolo] Agent run failed: ${errorMessage}`,
868
+ model: agentConfig.model ?? "unknown",
869
+ toolCallCount,
870
+ error: true,
871
+ errorMessage
872
+ },
873
+ ...input.runtimeContext ? { runtimeContext: input.runtimeContext } : {},
874
+ ...input.continueDialogId ? { continueDialogId: input.continueDialogId } : {},
875
+ ...input.spaceId ? { spaceId: input.spaceId } : {},
876
+ ...input.category ? { category: input.category } : {},
877
+ ...input.inheritedFromDialogKey ? { inheritedFromDialogKey: input.inheritedFromDialogKey } : {},
878
+ ...input.parentDialogId ? { parentDialogId: input.parentDialogId } : {}
879
+ });
880
+ if (saved2?.dialogId && typeof loopError === "object" && loopError !== null) {
881
+ loopError.dialogId = saved2.dialogId;
882
+ }
883
+ throw loopError;
884
+ }
885
+ result = result;
886
+ if (!skipFinalAppend) {
887
+ messages.push({
888
+ role: "assistant",
889
+ content: result.content,
890
+ // 与中间轮(:561)一致带上 reasoning_content,让 saveTurn 持久化思维链,
891
+ // 空轮/异常排查时能回看模型实际想了什么。
892
+ ...result.reasoning_content ? { reasoning_content: result.reasoning_content } : {}
893
+ });
894
+ }
895
+ const turnMessages = messages.slice(turnStartIndex);
896
+ const saved = await input.adapter.saveTurn({
897
+ agentKey: agentConfig.key,
898
+ messages: turnMessages,
899
+ result: {
900
+ ...result,
901
+ ...toolCallCount > 0 ? { toolCallCount } : {},
902
+ ...agentConfig.toolSurface ? { runtimeToolSurface: agentConfig.toolSurface } : {}
903
+ },
904
+ ...input.runtimeContext ? { runtimeContext: input.runtimeContext } : {},
905
+ ...input.continueDialogId ? { continueDialogId: input.continueDialogId } : {},
906
+ ...input.spaceId ? { spaceId: input.spaceId } : {},
907
+ ...input.category ? { category: input.category } : {},
908
+ ...input.inheritedFromDialogKey ? { inheritedFromDialogKey: input.inheritedFromDialogKey } : {},
909
+ ...input.parentDialogId ? { parentDialogId: input.parentDialogId } : {}
910
+ });
911
+ return {
912
+ ...result,
913
+ ...turnUsage ? { usage: turnUsage } : {},
914
+ ...toolCallCount > 0 ? { toolCallCount } : {},
915
+ ...agentConfig.toolSurface ? { runtimeToolSurface: agentConfig.toolSurface } : {},
916
+ // 透出最后一轮 provider 调用的 finish_reason;多轮工具循环里只有最后一轮收尾状态有意义。
917
+ ...result.finish_reason ? { finish_reason: result.finish_reason } : {},
918
+ dialogId: saved.dialogId,
919
+ turnMessages
920
+ };
921
+ }
922
+
923
+ export {
924
+ readCommandActionGatePayload,
925
+ readActionGate,
926
+ parseToolArgumentsJson,
927
+ summarizeToolArguments,
928
+ resolveAgentImageInputSupport,
929
+ LOCAL_AGENT_CONFIG_MISSING_CODE,
930
+ EMPTY_ASSISTANT_REPAIR_PROMPT,
931
+ LOCAL_TURN_ABORTED_CODE,
932
+ runLocalAgentTurn
933
+ };