nolo-cli 0.32.0 → 0.33.0-alpha.3

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 (170) hide show
  1. package/README.md +6 -12
  2. package/{_executeModel-LTMSIBS4.js → _executeModel-RWPVI3YV.js} +76 -67
  3. package/{action-HI3VRQLP.js → action-SMLG6OTB.js} +17 -15
  4. package/{addContentAction-NCURJ6PK.js → addContentAction-SFO244QN.js} +14 -13
  5. package/{addDialogAgentAction-RCY4ECF4.js → addDialogAgentAction-W44ZCEHB.js} +14 -13
  6. package/{agentDeleteCommand-D3MYZK6E.js → agentDeleteCommand-KU2RXQPP.js} +42 -59
  7. package/{agentEmailCommands-6BXS574I.js → agentEmailCommands-MPCMDENS.js} +89 -80
  8. package/{agentGrantCommands-E7ZZFRHK.js → agentGrantCommands-2LEZDADN.js} +2 -2
  9. package/{agentListCommands-SF3HEUTT.js → agentListCommands-EPD4N6FX.js} +73 -78
  10. package/{agentMachineCommands-YARVXRR6.js → agentMachineCommands-AF7C3YRT.js} +40 -57
  11. package/{agentPullCommand-ARSIDNVC.js → agentPullCommand-YH5GEBK4.js} +5 -5
  12. package/agentRecordCommands-EYE6MZZG.js +112 -0
  13. package/agentRunCommand-LL22SGTN.js +130 -0
  14. package/{agentRuntimeLocal-ATGJY6WC.js → agentRuntimeLocal-JX34G47Z.js} +35 -50
  15. package/{agentSlice-4XWW344Y.js → agentSlice-TNMFQQOV.js} +15 -13
  16. package/{appDeleteCommands-63JO7RXS.js → appDeleteCommands-43K5VXQB.js} +38 -55
  17. package/{appDeployCommands-Y7EWYUGM.js → appDeployCommands-FEEJSVDZ.js} +38 -55
  18. package/{appDeployStatusCommands-ZBEY3DWB.js → appDeployStatusCommands-H76CG45R.js} +38 -55
  19. package/{appGetCommands-QSSOSEYL.js → appGetCommands-MDZYFTYZ.js} +38 -55
  20. package/{appListCommands-PH3XWNDX.js → appListCommands-TUJJXPWG.js} +38 -55
  21. package/{authCommand-BBDHMSO6.js → authCommand-T7UK4CWS.js} +18 -18
  22. package/{authCommands-4UDEKRE6.js → authCommands-EAPFGNHN.js} +8 -8
  23. package/chatQueueReduxAdapter-LVQXC4ZY.js +180 -0
  24. package/chunk-2H3XIBY4.js +239 -0
  25. package/{chunk-TEYN42N3.js → chunk-2IVEXF7P.js} +11 -4
  26. package/{chunk-WTGCTVJG.js → chunk-2QTEYCR7.js} +3 -6
  27. package/{chunk-DOISARTV.js → chunk-2UECQ7RE.js} +1 -1
  28. package/{chunk-SWYMCHM7.js → chunk-37V5LNEQ.js} +69 -1
  29. package/{chunk-E3APEOIM.js → chunk-3GZXL6FM.js} +4 -19
  30. package/{chunk-O3JR45Q2.js → chunk-3VAQHAXT.js} +44 -44
  31. package/{chunk-O5OMJPPF.js → chunk-3WXRAHCG.js} +6 -5
  32. package/{chunk-LAXMH7JY.js → chunk-57QJXIB6.js} +18 -15
  33. package/chunk-5CS33IBL.js +301 -0
  34. package/{chunk-3UGKATZQ.js → chunk-5SBK2MTI.js} +8 -369
  35. package/chunk-6PO2SYCS.js +1800 -0
  36. package/{chunk-TA6EA2A3.js → chunk-6SXC35F4.js} +182 -20
  37. package/{chunk-MXFQHRSS.js → chunk-6XIE5ZGI.js} +1 -1
  38. package/{chunk-3GZT3L6F.js → chunk-73GINUCW.js} +326 -481
  39. package/{chunk-VMWR7VNI.js → chunk-7E72JMBB.js} +7 -7
  40. package/{chunk-4PNU7W7K.js → chunk-AAGCMVFT.js} +106 -124
  41. package/chunk-ADLYMQB6.js +642 -0
  42. package/{chunk-ZWJOGMKH.js → chunk-AETZ7AD6.js} +1 -1
  43. package/{chunk-UDA3ZYLW.js → chunk-AFV4FOT2.js} +70 -24
  44. package/{chunk-BGTUGS3T.js → chunk-AOXVOC6D.js} +4 -30
  45. package/{chunk-2ZRP5RUG.js → chunk-B2BSG6QQ.js} +12 -11
  46. package/{chunk-44HACRCK.js → chunk-BANYWEYY.js} +4 -4
  47. package/{chunk-TOW4E763.js → chunk-BJIRLHJR.js} +2 -0
  48. package/{chunk-ZJ2WITOO.js → chunk-BQXOGBFN.js} +2 -2
  49. package/{chunk-G5GVZAXF.js → chunk-CLP2K7U4.js} +15 -19
  50. package/{chunk-2K4NDPT5.js → chunk-DFUPZE6V.js} +20 -12
  51. package/{chunk-YHGHADBQ.js → chunk-DPMBNHOJ.js} +4 -4
  52. package/chunk-EGRJC4ZN.js +91 -0
  53. package/{chunk-K6QEHQZ3.js → chunk-EKLRRZIN.js} +1 -1
  54. package/{chunk-XFG3BAKN.js → chunk-FMEVI5TG.js} +65 -0
  55. package/{chunk-RH53LMEJ.js → chunk-FSSX3XRY.js} +2 -4
  56. package/{chunk-VP4WJWKW.js → chunk-GM6PU7B6.js} +431 -345
  57. package/{chunk-EEF23OOK.js → chunk-GMXWYXAF.js} +7 -7
  58. package/{chunk-SFWZUTCI.js → chunk-GTYM4HKV.js} +1 -1
  59. package/{chunk-MITD7CON.js → chunk-HDKRSRYU.js} +1461 -301
  60. package/chunk-HS7MLR74.js +38 -0
  61. package/{chunk-3AUWC6EM.js → chunk-HUCT7HID.js} +5 -84
  62. package/{chunk-PTHDLIRB.js → chunk-I6N2UVVY.js} +1 -1
  63. package/chunk-IDAU4UFS.js +437 -0
  64. package/{chunk-Q76I4SXI.js → chunk-IHEC7VBF.js} +1 -1
  65. package/{chunk-OWHNFZNW.js → chunk-IL545V3E.js} +4 -4
  66. package/{chunk-3LY4F7SV.js → chunk-INZZJSQF.js} +348 -331
  67. package/{chunk-CF2WZF4N.js → chunk-J6WH4PYZ.js} +0 -8
  68. package/{chunk-2HXKAPH7.js → chunk-JMPYDFHY.js} +6 -6
  69. package/{chunk-V54H24CQ.js → chunk-JTSGWTYZ.js} +3 -3
  70. package/{chunk-ATK5WJOA.js → chunk-JZ5AMMXU.js} +4 -4
  71. package/chunk-KHCLMKZZ.js +3062 -0
  72. package/{chunk-WHLVPK32.js → chunk-KMSZPTM6.js} +27 -3
  73. package/{chunk-L3GCUVOH.js → chunk-KSRFVP36.js} +1 -1
  74. package/{chunk-DLWCWUNW.js → chunk-LOD75GOS.js} +336 -32
  75. package/{chunk-UOJRKY5J.js → chunk-M2YMQOLC.js} +44 -53
  76. package/chunk-M3JEW6N6.js +193 -0
  77. package/{chunk-XDHHF73Q.js → chunk-M4NC7NF6.js} +95 -95
  78. package/{chunk-3FCNXC2J.js → chunk-MPZJVZDC.js} +3735 -1394
  79. package/{chunk-IXZX5CJK.js → chunk-MQRZ5QUH.js} +1 -1
  80. package/{chunk-3ASDTTEI.js → chunk-MRWGHF56.js} +2 -0
  81. package/{chunk-D34RI6NI.js → chunk-NNWHHCVP.js} +75 -1
  82. package/{chunk-6YABCOFU.js → chunk-NUO3QFWD.js} +1 -1
  83. package/{chunk-GAF5X6B7.js → chunk-O6GEBMIY.js} +269 -309
  84. package/{chunk-CAENRKNJ.js → chunk-OR2HNLVO.js} +126 -88
  85. package/chunk-OW765XBU.js +10 -0
  86. package/chunk-PREQU5QV.js +231 -0
  87. package/{chunk-Q3CSL43H.js → chunk-Q5ITEGIN.js} +1 -1
  88. package/{chunk-7S54ZGF6.js → chunk-RAZOLMJR.js} +256 -12
  89. package/chunk-RCFIB45Q.js +28 -0
  90. package/chunk-RY57GLGW.js +188 -0
  91. package/{chunk-KGEVMUMI.js → chunk-TFPUAELY.js} +11 -11
  92. package/{chunk-ZJH3LKEW.js → chunk-UK5JGQVU.js} +94 -15
  93. package/chunk-URMS4XY2.js +10 -0
  94. package/{chunk-RXVX5LFR.js → chunk-VH2F7ZB6.js} +1 -1
  95. package/chunk-VIDPVFP3.js +20 -0
  96. package/{chunk-W367V5CH.js → chunk-WHD6BG7M.js} +400 -115
  97. package/{chunk-5RDLGLAP.js → chunk-WJSW43QZ.js} +4 -7
  98. package/{chunk-CF7S2RYZ.js → chunk-WLH5BAKX.js} +6 -6
  99. package/{chunk-VVEH6XUE.js → chunk-X2DAEZ3X.js} +1 -1
  100. package/{chunk-2IJAKBK2.js → chunk-X664KVEV.js} +426 -246
  101. package/{chunk-43EPBPZ2.js → chunk-XCCGU6QB.js} +2 -2
  102. package/chunk-Y5GCAMGP.js +9 -0
  103. package/{chunk-V42OE5HT.js → chunk-YDTYDA5W.js} +3 -3
  104. package/chunk-YYLHWIW6.js +48 -0
  105. package/{chunk-AOS5IN2I.js → chunk-ZHYK3N56.js} +1 -1
  106. package/{chunk-ODS2MVMU.js → chunk-ZJMME4DS.js} +19 -303
  107. package/{chunk-PJ2DDQQM.js → chunk-ZURFOV5J.js} +2 -2
  108. package/chunk-ZZ2MH7LE.js +84 -0
  109. package/{cliExecutor-BBUVQU4L.js → cliExecutor-DW3PHGEL.js} +2 -2
  110. package/{clipboardy-BVE3LVEH.js → clipboardy-MMBYVRLF.js} +166 -372
  111. package/{codingSkills-V35TRR4Y.js → codingSkills-DY5MINPG.js} +5 -4
  112. package/{createAgentAutomationAction-WLRNE7C4.js → createAgentAutomationAction-INQT23LX.js} +40 -31
  113. package/createDialogAction-LDCPDI73.js +60 -0
  114. package/{createPageAction-7YROVZ3W.js → createPageAction-5YXOG2M4.js} +56 -47
  115. package/{db-6DPSJ6WT.js → db-3H3JECGY.js} +45 -5
  116. package/{dbSlice-BBL3PEVW.js → dbSlice-3SD5L5H2.js} +13 -12
  117. package/{deleteFile-RJTEPOT4.js → deleteFile-XQXPBFFB.js} +7 -6
  118. package/dialogCommands-CHJO47AX.js +81 -0
  119. package/{dialogSlice-N4HPG6HM.js → dialogSlice-DOWKOILN.js} +36 -29
  120. package/{docCreateCommands-GRA5BHSA.js → docCreateCommands-OVZARUFX.js} +40 -55
  121. package/{docDeleteCommands-ONIJM5MD.js → docDeleteCommands-E2XJ62LD.js} +42 -57
  122. package/{docReadCommands-H55VQ2US.js → docReadCommands-I7OSREPJ.js} +40 -55
  123. package/{docStore-B5AHDNW5.js → docStore-UAWSKZ2Y.js} +39 -30
  124. package/{docUpdateCommands-ZQIQVGC2.js → docUpdateCommands-X4Z26VJM.js} +43 -58
  125. package/{fetchMessages-VPPQDDZ4.js → fetchMessages-7QRCCRYK.js} +3 -3
  126. package/{getPricing-QO5TYNCK.js → getPricing-L2ENXWHV.js} +7 -6
  127. package/{handleSendMessageAction-IN5XX5U7.js → handleSendMessageAction-C3TSDWKH.js} +38 -31
  128. package/index.js +67 -67
  129. package/{lib-FYYBQIXS.js → lib-2ZTNRXR4.js} +432 -183
  130. package/{localDialogRead-3DBXVYXS.js → localDialogRead-SLMPV5SK.js} +2 -2
  131. package/{localRuntimeAuthority-NDUA2D7Y.js → localRuntimeAuthority-E3R24J4T.js} +4 -2
  132. package/{localRuntimeDb-GKYRBWLQ.js → localRuntimeDb-DDZCJFQZ.js} +1 -1
  133. package/{machineCommands-H3UMKE76.js → machineCommands-BUOIYJAD.js} +93 -84
  134. package/{machineWsRunDispatch-HONRUK3R.js → machineWsRunDispatch-7CRWAA6O.js} +83 -74
  135. package/{models-WDUTTYFS.js → models-OX2S5C6Q.js} +2 -2
  136. package/{offlineMarxistsAgentCommand-E6LUG63A.js → offlineMarxistsAgentCommand-GEH6SNNA.js} +1 -1
  137. package/package.json +1 -4
  138. package/{read-64OQDO3I.js → read-6G73BMEY.js} +8 -7
  139. package/{readDocTool-MXM3T6PE.js → readDocTool-DK4EI2GA.js} +1 -2
  140. package/{readlineWorkspace-XVJZDCSC.js → readlineWorkspace-ZDWEASJV.js} +265 -428
  141. package/{removeDialogAgentAction-NEKVAMSH.js → removeDialogAgentAction-E7H557UO.js} +19 -17
  142. package/{runAgentClientLoop-H7U53QB6.js → runAgentClientLoop-U7HYA3O5.js} +72 -64
  143. package/{runtimeDoctorCommands-WI2YZUSJ.js → runtimeDoctorCommands-KIKM6BIO.js} +5 -5
  144. package/{setDialogExtraReferencesAction-WTOHQDIV.js → setDialogExtraReferencesAction-RMMGBR5F.js} +15 -14
  145. package/{setPrimaryDialogAgentAction-LDJOYC4F.js → setPrimaryDialogAgentAction-FWBKKLVA.js} +19 -17
  146. package/{settingSlice-4M37TN7V.js → settingSlice-73PV4KG4.js} +16 -14
  147. package/{skillDiscovery-5U6RYAHN.js → skillDiscovery-KLLKXPUO.js} +4 -4
  148. package/{slateUtils-2M7MUTWX.js → slateUtils-VO2FU36K.js} +1 -1
  149. package/{spaceCommands-7VVKJBDV.js → spaceCommands-GEWZXGHM.js} +43 -240
  150. package/{spaceSlice-T6YK6D34.js → spaceSlice-B6MOVY4N.js} +38 -61
  151. package/{streamAgentChatTurn-RQ63QFQ7.js → streamAgentChatTurn-T527EQTT.js} +1261 -150
  152. package/{switchDialogAgentAction-XVWGKR2Z.js → switchDialogAgentAction-US6QNL3N.js} +14 -13
  153. package/syncMapping-RK2MANUX.js +43 -0
  154. package/{tableCommands-RJZ3V4TF.js → tableCommands-QE47K72R.js} +8 -7
  155. package/{toolApiClient-ARGFDJAG.js → toolApiClient-B2MFXMEG.js} +3 -3
  156. package/tools-XMWCVMPM.js +98 -0
  157. package/{tuiSummaryLlmCaller-SRZ4QQUP.js → tuiSummaryLlmCaller-NCAJSVSD.js} +24 -21
  158. package/{updateDialogTitleAction-BBDSWHNG.js → updateDialogTitleAction-XPJZRJEL.js} +48 -38
  159. package/agentRecordCommands-JFZRQJQ4.js +0 -103
  160. package/agentRunCommand-NOX5FLKO.js +0 -121
  161. package/chunk-AYMOSAHE.js +0 -3158
  162. package/chunk-D2BPX6DQ.js +0 -1707
  163. package/chunk-DCDL3GC4.js +0 -171
  164. package/chunk-F3MP7CP6.js +0 -73
  165. package/chunk-WZSRQNQG.js +0 -2587
  166. package/createDialogAction-Y6YV64QB.js +0 -52
  167. package/dialogCommands-XLO5CAHZ.js +0 -95
  168. package/tools-KYZX3BGO.js +0 -90
  169. package/{chunk-Z5MXSEOJ.js → chunk-RQSOAMPJ.js} +2 -2
  170. package/{chunk-JDSUTNYY.js → chunk-SAQQLJZ5.js} +3 -3
package/chunk-AYMOSAHE.js DELETED
@@ -1,3158 +0,0 @@
1
- import {
2
- buildDialogSummaryLayer,
3
- buildLinkedSpacesSection,
4
- buildSpaceContextLayer
5
- } from "./chunk-DOISARTV.js";
6
- import {
7
- buildCurrentTimeBlock,
8
- buildIdentityBlock,
9
- buildRuntimeGuidanceBlocks,
10
- fetchReferenceContents,
11
- resolveToolGuidedSections
12
- } from "./chunk-3UGKATZQ.js";
13
- import {
14
- getAllToolRuns,
15
- resolveAgentRecommendedSkillNames,
16
- resolveAgentRequiredPackIds
17
- } from "./chunk-D2BPX6DQ.js";
18
- import {
19
- getDocState
20
- } from "./chunk-EEF23OOK.js";
21
- import {
22
- resolveToolBaseUrl
23
- } from "./chunk-44HACRCK.js";
24
- import {
25
- getFinalPrice,
26
- getModelPricing,
27
- getPrices,
28
- hasExplicitAgentPricing
29
- } from "./chunk-E3APEOIM.js";
30
- import {
31
- selectCurrentTable,
32
- selectTableRows,
33
- selectViewMode
34
- } from "./chunk-3FCNXC2J.js";
35
- import {
36
- PERSONALIZATION_DIALOG_CATEGORY,
37
- buildPersonalizationDialogPolicyContext,
38
- extractReferenceKeysFromMessage,
39
- getModelContextWindow,
40
- resolveBuiltinPlatformAgentConfig,
41
- selectAllMsgs
42
- } from "./chunk-3GZT3L6F.js";
43
- import {
44
- COMPACTION_SUMMARY_SYSTEM_PROMPT,
45
- buildCompactionMetricsFromPlan,
46
- buildCompactionUserContent,
47
- clipCompactText,
48
- estimateTokenCount,
49
- formatCompactionMetricsLog,
50
- formatFileOperationsFromMessages,
51
- formatMessagesForSummaryWithTruncation,
52
- planCompression,
53
- planContextUsage
54
- } from "./chunk-BGTUGS3T.js";
55
- import {
56
- toErrorMessage
57
- } from "./chunk-HNMXYYJR.js";
58
- import {
59
- selectPendingFiles
60
- } from "./chunk-3ASDTTEI.js";
61
- import {
62
- findModelConfig,
63
- getModelConfig,
64
- getProviderByModelName
65
- } from "./chunk-2K4NDPT5.js";
66
- import {
67
- PLATFORM_HOSTED_QWEN_37_FLASH_MODEL
68
- } from "./chunk-CAENRKNJ.js";
69
- import {
70
- DEFAULT_AGENT_BASE_POLICY,
71
- DEFAULT_USER_PREFERENCE_PROFILE,
72
- selectAiRecentContentLimit,
73
- selectGlobalPrompt,
74
- selectKnowledgeCaptureLevel,
75
- selectSpaceContextLevel,
76
- selectUserTonePreset
77
- } from "./chunk-G5GVZAXF.js";
78
- import {
79
- asRecordOrEmpty
80
- } from "./chunk-KX6YBIHG.js";
81
- import {
82
- read,
83
- selectById
84
- } from "./chunk-LAXMH7JY.js";
85
- import {
86
- asTrimmedLowercaseString
87
- } from "./chunk-QSJ3HFEF.js";
88
- import {
89
- PUBLIC_QWEN_37_FLASH_AGENT_KEY
90
- } from "./chunk-ZJH3LKEW.js";
91
- import {
92
- extractCustomId
93
- } from "./chunk-TOW4E763.js";
94
- import {
95
- selectIdentityUserBalance,
96
- selectIdentityUserId
97
- } from "./chunk-2IJAKBK2.js";
98
- import {
99
- isRecord
100
- } from "./chunk-KUG52IAP.js";
101
- import {
102
- canonicalizeToolName,
103
- canonicalizeToolNames,
104
- prioritizeToolNames
105
- } from "./chunk-3AUWC6EM.js";
106
- import {
107
- TOOL_PACKS,
108
- addDefaultSystemCapabilityTools,
109
- applyDefaultWebToolPacks,
110
- applyDisabledTools,
111
- applySystemBuiltinSkillFilter,
112
- expandEnabledPackPromptPatches,
113
- expandEnabledPacks,
114
- resolveEffectiveEnabledPacks
115
- } from "./chunk-CF7S2RYZ.js";
116
- import {
117
- asNonEmptyStringArray
118
- } from "./chunk-I42VC5KR.js";
119
- import {
120
- asOptionalTrimmedString
121
- } from "./chunk-G3SUCT4W.js";
122
-
123
- // packages/agent-runtime/actionGate.ts
124
- function readCommandActionGatePayload(payload) {
125
- if (!isRecord(payload)) return null;
126
- if (!Array.isArray(payload.command)) return null;
127
- const command = payload.command.flatMap((item) => {
128
- const value = asOptionalTrimmedString(item);
129
- return value ? [value] : [];
130
- });
131
- if (command.length === 0) return null;
132
- const displayCommand = asOptionalTrimmedString(payload.displayCommand);
133
- return {
134
- command,
135
- ...displayCommand ? { displayCommand } : {}
136
- };
137
- }
138
- function readActionGate(value) {
139
- if (!isRecord(value)) return null;
140
- if (typeof value.id !== "string" || !value.id.trim()) return null;
141
- if (value.kind !== "confirm" && value.kind !== "handoff" && value.kind !== "input") return null;
142
- if (typeof value.title !== "string" || !value.title.trim()) return null;
143
- const titleParams = readTitleParams(value.titleParams);
144
- return {
145
- id: value.id.trim(),
146
- kind: value.kind,
147
- title: value.title.trim(),
148
- ...titleParams ? { titleParams } : {},
149
- ...asOptionalTrimmedString(value.body) ? { body: asOptionalTrimmedString(value.body) } : {},
150
- ...Object.prototype.hasOwnProperty.call(value, "payload") ? { payload: value.payload } : {}
151
- };
152
- }
153
- function readTitleParams(value) {
154
- if (!isRecord(value)) return void 0;
155
- const entries = Object.entries(value).flatMap(([key, raw]) => {
156
- if (typeof raw === "string" || typeof raw === "number") {
157
- return [[key, raw]];
158
- }
159
- return [];
160
- });
161
- if (entries.length === 0) return void 0;
162
- return Object.fromEntries(entries);
163
- }
164
-
165
- // packages/ai/agent/getFullChatContextKeys.ts
166
- var difference = (arrA, arrB) => {
167
- if (!arrA.length) return [];
168
- if (!arrB.length) return [...arrA];
169
- const exclude = new Set(arrB);
170
- return arrA.filter((item) => !exclude.has(item));
171
- };
172
- var getFullChatContextKeys = async (state, dispatch, agentConfig, userInput, dialogConfig) => {
173
- const msgs = selectAllMsgs(
174
- state,
175
- dialogConfig?.dbKey ? extractCustomId(dialogConfig.dbKey) : dialogConfig?.id
176
- );
177
- const botInstructionKeys = /* @__PURE__ */ new Set();
178
- const botKnowledgeKeys = /* @__PURE__ */ new Set();
179
- if (Array.isArray(agentConfig.references)) {
180
- for (const ref of agentConfig.references) {
181
- if (!ref?.dbKey) continue;
182
- if (ref.type === "instruction") {
183
- botInstructionKeys.add(ref.dbKey);
184
- } else {
185
- botKnowledgeKeys.add(ref.dbKey);
186
- }
187
- }
188
- }
189
- const currentInputKeys = /* @__PURE__ */ new Set();
190
- if (Array.isArray(userInput)) {
191
- for (const part of userInput) {
192
- if (part?.pageKey) currentInputKeys.add(part.pageKey);
193
- if (part?.dialogKey) currentInputKeys.add(part.dialogKey);
194
- }
195
- }
196
- const historyKeys = /* @__PURE__ */ new Set();
197
- const savedKeys = dialogConfig?.referenceKeys;
198
- if (Array.isArray(savedKeys)) {
199
- savedKeys.forEach((k) => historyKeys.add(k));
200
- }
201
- const scanContentParts = (msg) => {
202
- if (!msg) return;
203
- for (const key of extractReferenceKeysFromMessage(msg)) {
204
- historyKeys.add(key);
205
- }
206
- };
207
- if (msgs && msgs.length > 0) {
208
- const summarizedBeforeId = dialogConfig?.summarizedBeforeId;
209
- if (!summarizedBeforeId) {
210
- for (const msg of msgs) scanContentParts(msg);
211
- } else {
212
- let foundMarker = false;
213
- let startScan = false;
214
- for (const msg of msgs) {
215
- if (!startScan) {
216
- if (msg.id === summarizedBeforeId) {
217
- foundMarker = true;
218
- startScan = true;
219
- }
220
- continue;
221
- }
222
- scanContentParts(msg);
223
- }
224
- if (!foundMarker) {
225
- console.warn(`[getFullChatContextKeys] marker ${summarizedBeforeId} not found, scanning all`);
226
- for (const msg of msgs) scanContentParts(msg);
227
- }
228
- }
229
- }
230
- return {
231
- botInstructionKeys,
232
- currentInputKeys,
233
- historyKeys,
234
- botKnowledgeKeys
235
- };
236
- };
237
- var deduplicateContextKeys = (keys) => {
238
- const {
239
- botInstructionKeys,
240
- currentInputKeys,
241
- historyKeys,
242
- botKnowledgeKeys
243
- } = keys;
244
- const finalBotInstructionKeys = Array.from(botInstructionKeys);
245
- const finalCurrentInputKeys = difference(
246
- Array.from(currentInputKeys),
247
- finalBotInstructionKeys
248
- );
249
- const finalHistoryKeys = difference(Array.from(historyKeys), [
250
- ...finalBotInstructionKeys,
251
- ...finalCurrentInputKeys
252
- ]);
253
- const finalBotKnowledgeKeys = difference(Array.from(botKnowledgeKeys), [
254
- ...finalBotInstructionKeys,
255
- ...finalCurrentInputKeys,
256
- ...finalHistoryKeys
257
- ]);
258
- return {
259
- botInstructionsContext: finalBotInstructionKeys,
260
- currentInputContext: finalCurrentInputKeys,
261
- historyContext: finalHistoryKeys,
262
- botKnowledgeContext: finalBotKnowledgeKeys
263
- };
264
- };
265
-
266
- // packages/ai/agent/toolOutputPolicy.ts
267
- var MAX_HISTORICAL_TOOL_CONTENT_CHARS = 1600;
268
- var MAX_IN_TURN_TOOL_CONTENT_CHARS = 4e3;
269
- var FRESH_TOOL_OUTPUT_MAX_CHARS = 32e3;
270
- var DEFAULT_TOOL_OUTPUT_PROFILE = {
271
- maxChars: MAX_IN_TURN_TOOL_CONTENT_CHARS,
272
- headRatio: 0.5
273
- };
274
- var TOOL_OUTPUT_PROFILES = {
275
- readFile: { maxChars: 4800, headRatio: 0.68, historicalMaxChars: 4800 },
276
- read_file: { maxChars: 4800, headRatio: 0.68, historicalMaxChars: 4800 },
277
- readWorkspaceFile: { maxChars: 4800, headRatio: 0.68, historicalMaxChars: 4800 },
278
- searchFiles: { maxChars: 3600, headRatio: 0.78 },
279
- search_files: { maxChars: 3600, headRatio: 0.78 },
280
- listFiles: { maxChars: 2800, headRatio: 0.85 },
281
- globFiles: { maxChars: 2800, headRatio: 0.85 },
282
- execShell: { maxChars: 4e3, headRatio: 0.35 },
283
- runCommand: { maxChars: 4e3, headRatio: 0.35 },
284
- launchProcess: { maxChars: 2800, headRatio: 0.35 },
285
- editFile: { maxChars: 2800, headRatio: 0.62 },
286
- writeFile: { maxChars: 2400, headRatio: 0.62 },
287
- readPastedText: { maxChars: 4800, headRatio: 0.5, historicalMaxChars: 4800 }
288
- };
289
- function resolveToolOutputProfile(toolName) {
290
- return (toolName ? TOOL_OUTPUT_PROFILES[toolName] : void 0) ?? DEFAULT_TOOL_OUTPUT_PROFILE;
291
- }
292
- function resolveHistoricalToolContentCap(toolName, historicalMaxChars) {
293
- const profile = toolName ? TOOL_OUTPUT_PROFILES[toolName] : void 0;
294
- return profile?.historicalMaxChars !== void 0 ? Math.max(historicalMaxChars, profile.historicalMaxChars) : historicalMaxChars;
295
- }
296
- function projectToolMessageContent(input) {
297
- const { content, isFresh, toolName, historicalMaxChars } = input;
298
- if (isFresh) {
299
- if (content.length <= FRESH_TOOL_OUTPUT_MAX_CHARS) return content;
300
- return clipToolText(
301
- content,
302
- FRESH_TOOL_OUTPUT_MAX_CHARS,
303
- resolveToolOutputProfile(toolName).headRatio,
304
- `
305
- \u2026[\u622A\u65AD\uFF0C\u539F\u59CB\u957F\u5EA6 ${content.length} \u5B57\u7B26]`
306
- );
307
- }
308
- const cap = resolveHistoricalToolContentCap(toolName, historicalMaxChars);
309
- if (content.length <= cap) return content;
310
- return content.slice(0, cap) + `
311
- \u2026[\u622A\u65AD\uFF0C\u539F\u59CB\u957F\u5EA6 ${content.length} \u5B57\u7B26]`;
312
- }
313
- function clipToolText(content, maxChars, headRatio, marker = "\n\n[... tool output middle omitted; head/tail preserved ...]\n\n") {
314
- const normalized = content.replace(/\r\n/g, "\n").trim();
315
- if (normalized.length <= maxChars) return normalized;
316
- if (maxChars <= marker.length + 2) return normalized.slice(0, maxChars);
317
- const available = maxChars - marker.length;
318
- const headChars = Math.max(1, Math.floor(available * headRatio));
319
- const tailChars = Math.max(1, available - headChars);
320
- return `${normalized.slice(0, headChars)}${marker}${normalized.slice(-tailChars)}`;
321
- }
322
-
323
- // packages/ai/policy/runtimePolicy.ts
324
- var clampLevel = (value, fallback) => {
325
- const n = Number(value);
326
- if (n === 1 || n === 2 || n === 3 || n === 4) {
327
- return n;
328
- }
329
- return fallback;
330
- };
331
- var normalizeTonePreset = (value, fallback) => {
332
- switch (value) {
333
- case "professional":
334
- case "friendly":
335
- case "direct":
336
- case "pragmatic":
337
- case "default":
338
- return value;
339
- default:
340
- return fallback;
341
- }
342
- };
343
- var normalizeToneResolutionMode = (value, fallback) => {
344
- switch (value) {
345
- case "agent_first":
346
- case "user_first":
347
- case "blend":
348
- return value;
349
- default:
350
- return fallback;
351
- }
352
- };
353
- var normalizeSelfEvolutionMode = (value, fallback) => {
354
- switch (value) {
355
- case "none":
356
- case "knowledge_only":
357
- case "prompt_and_refs":
358
- case "full":
359
- return value;
360
- default:
361
- return fallback;
362
- }
363
- };
364
- var resolveAgentBasePolicy = (agentConfig) => {
365
- const raw = agentConfig?.basePolicy ?? {};
366
- return {
367
- version: 1,
368
- tone: {
369
- preset: normalizeTonePreset(
370
- raw?.tone?.preset,
371
- DEFAULT_AGENT_BASE_POLICY.tone?.preset ?? "default"
372
- ),
373
- resolutionMode: normalizeToneResolutionMode(
374
- raw?.tone?.resolutionMode,
375
- DEFAULT_AGENT_BASE_POLICY.tone?.resolutionMode ?? "blend"
376
- )
377
- },
378
- knowledgeCaptureMaxLevel: clampLevel(
379
- raw?.knowledgeCaptureMaxLevel,
380
- DEFAULT_AGENT_BASE_POLICY.knowledgeCaptureMaxLevel
381
- ),
382
- spaceContextMaxLevel: clampLevel(
383
- raw?.spaceContextMaxLevel,
384
- DEFAULT_AGENT_BASE_POLICY.spaceContextMaxLevel
385
- ),
386
- selfEvolutionMode: normalizeSelfEvolutionMode(
387
- raw?.selfEvolutionMode,
388
- DEFAULT_AGENT_BASE_POLICY.selfEvolutionMode
389
- )
390
- };
391
- };
392
- var resolveUserPreferenceProfile = (settingsRecord) => {
393
- const fallbackSpaceLevel = settingsRecord?.enableReadCurrentSpace === false ? 1 : DEFAULT_USER_PREFERENCE_PROFILE.spaceContextLevel;
394
- return {
395
- version: 1,
396
- tone: {
397
- preset: normalizeTonePreset(
398
- settingsRecord?.userTonePreset,
399
- DEFAULT_USER_PREFERENCE_PROFILE.tone?.preset ?? "default"
400
- )
401
- },
402
- knowledgeCaptureLevel: clampLevel(
403
- settingsRecord?.knowledgeCaptureLevel,
404
- DEFAULT_USER_PREFERENCE_PROFILE.knowledgeCaptureLevel
405
- ),
406
- spaceContextLevel: clampLevel(
407
- settingsRecord?.spaceContextLevel,
408
- fallbackSpaceLevel
409
- )
410
- };
411
- };
412
- var containsAny = (text, patterns) => patterns.some((pattern) => text.includes(pattern));
413
- var inferCaptureIntent = (userInput) => {
414
- const normalized = userInput.toLowerCase();
415
- if (containsAny(normalized, [
416
- "\u4FDD\u5B58",
417
- "\u5B58\u4E00\u4E0B",
418
- "\u6C89\u6DC0",
419
- "\u8BB0\u4F4F",
420
- "\u5199\u5165\u6587\u6863",
421
- "\u5EFA\u6587\u6863",
422
- "\u521B\u5EFA\u6587\u6863",
423
- "\u5BFC\u5165 skill",
424
- "\u5BFC\u5165\u8FD9\u4E2A skill",
425
- "\u786E\u8BA4\u5BFC\u5165",
426
- "\u786E\u8BA4\u5BFC\u5165\u8FD9\u4E2A skill",
427
- "\u5BFC\u5165\u8FD9\u4E2A\u6280\u80FD",
428
- "\u786E\u8BA4\u5BFC\u5165\u8FD9\u4E2A\u6280\u80FD",
429
- "\u521B\u5EFA skill",
430
- "\u521B\u5EFA\u8FD9\u4E2A skill",
431
- "skill \u6587\u6863",
432
- "\u521B\u5EFA\u8868\u683C",
433
- "createtable",
434
- "addtablerow",
435
- "addtablerows",
436
- "\u5EFA\u8868",
437
- "\u5EFA\u4E2A\u8868",
438
- "\u505A\u4E2A\u8868",
439
- "\u505A\u4E00\u5F20\u8868",
440
- "\u5199\u8868",
441
- "\u5199\u5165\u8868",
442
- "\u5199\u5165\u4E00\u884C",
443
- "\u5199\u5165 table",
444
- "\u653E\u5230 table",
445
- "\u5B58\u5230 table",
446
- "\u4FDD\u5B58\u5230 table",
447
- "\u8BB0\u5F55\u4E0B\u6765",
448
- "\u91C7\u96C6",
449
- "\u505A\u6570\u636E\u96C6",
450
- "\u505A\u6210\u6570\u636E\u96C6",
451
- "\u6574\u7406\u6210\u6570\u636E\u96C6",
452
- "\u6574\u7406\u6210\u8868",
453
- "\u6574\u7406\u6210\u4E00\u5F20\u8868",
454
- "\u5EFA\u7ACB\u4E00\u4E2A\u8868",
455
- "\u5EFA\u7ACB\u4E00\u5F20\u8868",
456
- "\u5EFA\u7ACB\u6210\u8868",
457
- "\u5EFA\u7ACB\u6210\u4E00\u5F20\u8868",
458
- "\u521B\u5EFA\u8FD9\u4E2A\u8868\u683C",
459
- "\u786E\u8BA4\u521B\u5EFA",
460
- "\u786E\u8BA4\u521B\u5EFA\u8FD9\u5F20\u8868\u683C",
461
- "create doc",
462
- "import skill",
463
- "confirm import",
464
- "create skill",
465
- "create table",
466
- "write table",
467
- "save to table",
468
- "dataset",
469
- "save this",
470
- "remember this",
471
- "document this"
472
- ])) {
473
- return "strong";
474
- }
475
- if (containsAny(normalized, [
476
- "\u603B\u7ED3",
477
- "\u65B9\u6848",
478
- "\u8C03\u7814",
479
- "\u89C4\u8303",
480
- "\u4F1A\u8BAE\u7EAA\u8981",
481
- "\u603B\u7ED3\u4E00\u4E0B",
482
- "research",
483
- "proposal",
484
- "spec",
485
- "summary"
486
- ])) {
487
- return "possible";
488
- }
489
- return "none";
490
- };
491
- var resolveTonePreset = (agentTone, userTone, mode) => {
492
- if (mode === "agent_first") {
493
- return agentTone === "default" ? userTone : agentTone;
494
- }
495
- if (mode === "user_first") {
496
- return userTone === "default" ? agentTone : userTone;
497
- }
498
- if (userTone !== "default") return userTone;
499
- return agentTone;
500
- };
501
- var preloadSummaryCountByLevel = (level) => ({ 1: 0, 2: 0, 3: 8, 4: 16 })[level];
502
- var preloadBudgetRatioByLevel = (level) => ({ 1: 0, 2: 0.01, 3: 0.04, 4: 0.08 })[level];
503
- var knowledgeCaptureLevelLabel = (level) => ({
504
- 1: "\u4E0D\u4E3B\u52A8\u521B\u5EFA",
505
- 2: "\u5148\u95EE\u518D\u521B\u5EFA",
506
- 3: "\u56DE\u7B54\u540E\u5EFA\u8BAE\u521B\u5EFA",
507
- 4: "\u9AD8\u4EF7\u503C\u7ED3\u679C\u53EF\u81EA\u52A8\u521B\u5EFA"
508
- })[level] ?? "\u672A\u77E5\u7EA7\u522B";
509
- var spaceContextLevelLabel = (level) => ({
510
- 1: "\u4E0D\u81EA\u52A8\u8BFB\u53D6",
511
- 2: "\u53EA\u770B\u7ED3\u6784\u548C\u6807\u9898",
512
- 3: "\u8F7B\u91CF\u8BFB\u53D6",
513
- 4: "\u81EA\u9002\u5E94\u8BFB\u53D6"
514
- })[level] ?? "\u672A\u77E5\u7EA7\u522B";
515
- var buildStaticUserPolicyContext = (params) => {
516
- const agentBasePolicy = resolveAgentBasePolicy(params.agentConfig);
517
- const userPreferenceProfile = resolveUserPreferenceProfile(params.settingsRecord);
518
- const tonePreset = resolveTonePreset(
519
- agentBasePolicy.tone?.preset ?? "default",
520
- userPreferenceProfile.tone?.preset ?? "default",
521
- agentBasePolicy.tone?.resolutionMode ?? "blend"
522
- );
523
- const knowledgeLevel = Math.min(
524
- agentBasePolicy.knowledgeCaptureMaxLevel,
525
- userPreferenceProfile.knowledgeCaptureLevel
526
- );
527
- const spaceLevel = Math.min(
528
- agentBasePolicy.spaceContextMaxLevel,
529
- userPreferenceProfile.spaceContextLevel
530
- );
531
- return [
532
- `\u7528\u6237\u8BED\u6C14\u504F\u597D\uFF1A${tonePreset}`,
533
- `\u77E5\u8BC6\u6C89\u6DC0\u7EA7\u522B\uFF1A${knowledgeLevel}\uFF08${knowledgeCaptureLevelLabel(knowledgeLevel)}\uFF09`,
534
- `\u7A7A\u95F4\u4E0A\u4E0B\u6587\u7EA7\u522B\uFF1A${spaceLevel}\uFF08${spaceContextLevelLabel(spaceLevel)}\uFF09`,
535
- "\u8BF7\u5C3D\u91CF\u4FDD\u7559 agent \u81EA\u8EAB\u89D2\u8272\u8BBE\u5B9A\uFF0C\u540C\u65F6\u6309\u7528\u6237\u504F\u597D\u8C03\u6574\u8868\u8FBE\u548C\u81EA\u52A8\u5316\u7A0B\u5EA6\u3002"
536
- ].join("\n");
537
- };
538
- var resolveSpaceContextPreloadPlan = (level) => ({
539
- preloadSummaryCount: preloadSummaryCountByLevel(level),
540
- preloadBudgetRatio: preloadBudgetRatioByLevel(level),
541
- includeRecentContent: level >= 3
542
- });
543
-
544
- // packages/ai/agent/canvasEditingContext.ts
545
- function buildCanvasNodeEditingContextSummary(runtimeOptions) {
546
- if (runtimeOptions?.editingTarget?.kind !== "canvas_node") return null;
547
- const editingTarget = runtimeOptions.editingTarget;
548
- const metadata = editingTarget.metadata ?? {};
549
- const selectedNodeId = typeof metadata.selectedNodeId === "string" ? metadata.selectedNodeId : editingTarget.key ?? "(\u672A\u77E5\u8282\u70B9)";
550
- const part = typeof metadata.part === "string" ? metadata.part : editingTarget.title ?? selectedNodeId;
551
- const nodeType = typeof metadata.type === "string" ? metadata.type : "(\u672A\u77E5\u7C7B\u578B)";
552
- const path = Array.isArray(metadata.path) ? metadata.path.filter((item) => typeof item === "string") : [];
553
- const props = asRecordOrEmpty(metadata.props);
554
- const style = asRecordOrEmpty(metadata.style);
555
- return [
556
- "\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1ACanvas Tree \u4E2D\u7684\u4E00\u4E2A\u9009\u4E2D\u8282\u70B9\u3002",
557
- `- \u8282\u70B9 ID: ${selectedNodeId}`,
558
- `- part: ${part}`,
559
- `- \u8282\u70B9\u7C7B\u578B: ${nodeType}`,
560
- ...path.length ? [`- \u8282\u70B9\u8DEF\u5F84: ${path.join(" > ")}`] : [],
561
- "",
562
- "\u5F53\u524D\u8282\u70B9 props:",
563
- JSON.stringify(props, null, 2),
564
- "",
565
- "\u5F53\u524D\u8282\u70B9 style:",
566
- JSON.stringify(style, null, 2),
567
- "",
568
- "\u3010\u7ED9 AI \u7684\u64CD\u4F5C\u6307\u5357 / \u975E\u7528\u6237\u539F\u8BDD\u3011",
569
- `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`,
570
- "2. \u4E0D\u8981\u91CD\u5EFA root/shell\uFF0C\u4E0D\u8981\u91CD\u65B0 append \u5DF2\u5B58\u5728\u7684\u5927\u5757\u5185\u5BB9\u3002",
571
- "3. \u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u65B0\u589E\u5B50\u6A21\u5757\uFF0C\u5426\u5219\u4E0D\u8981 appendNode\u3002",
572
- "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"
573
- ].join("\n");
574
- }
575
-
576
- // packages/ai/agent/buildEditingContext.ts
577
- var buildAppConstraintPacks = (args) => {
578
- const imports = new Set(args.externalImports);
579
- const fileSet = new Set(args.fileNames);
580
- const packs = [
581
- {
582
- id: "repair-loop",
583
- title: "\u9884\u68C0\u4E0E\u5B9A\u70B9\u4FEE\u590D",
584
- rules: [
585
- "\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",
586
- "\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",
587
- "\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",
588
- "\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"
589
- ]
590
- },
591
- {
592
- id: "design-system",
593
- title: "\u8BBE\u8BA1\u7CFB\u7EDF\u4E0E\u5C0F\u6539\u52A8\u7EA6\u675F",
594
- rules: [
595
- "\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",
596
- "\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",
597
- "\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",
598
- "\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",
599
- "\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",
600
- "\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"
601
- ]
602
- }
603
- ];
604
- if (args.framework === "react-spa" || fileSet.has("main.tsx") || fileSet.has("App.tsx")) {
605
- packs.push({
606
- id: "react-spa-core",
607
- title: "React SPA \u5F62\u6001\u4FDD\u6301",
608
- rules: [
609
- '\u7EE7\u7EED\u6CBF\u7528 framework: "react-spa" + files\uFF0C\u4E0D\u8981\u9000\u56DE\u5355\u6587\u4EF6 Worker\u3002',
610
- "\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"
611
- ]
612
- });
613
- }
614
- if (imports.has("react-icons/lu")) {
615
- packs.push({
616
- id: "react-icons-lu",
617
- title: "Lucide \u56FE\u6807\u5B89\u5168\u89C4\u5219",
618
- rules: [
619
- "\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",
620
- "\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"
621
- ]
622
- });
623
- }
624
- if (imports.has("leaflet") || imports.has("react-leaflet")) {
625
- packs.push({
626
- id: "leaflet",
627
- title: "Leaflet \u5730\u56FE\u7EA6\u675F",
628
- rules: [
629
- "\u4E0D\u8981\u624B\u52A8 import leaflet.css\uFF1B\u5E73\u53F0\u4F1A\u81EA\u52A8\u6CE8\u5165 Leaflet \u6837\u5F0F\u3002",
630
- "\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"
631
- ]
632
- });
633
- }
634
- if (imports.has("@xyflow/react")) {
635
- packs.push({
636
- id: "xyflow",
637
- title: "Flow \u56FE\u7F16\u8F91\u7EA6\u675F",
638
- rules: [
639
- "\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",
640
- "\u4F18\u5148\u590D\u7528\u73B0\u6709\u8282\u70B9/\u8FB9\u6570\u636E\u7ED3\u6784\uFF0C\u907F\u514D\u91CD\u5199\u6574\u5957 flow \u753B\u5E03\u3002"
641
- ]
642
- });
643
- }
644
- if (imports.has("echarts") || imports.has("echarts-for-react")) {
645
- packs.push({
646
- id: "echarts",
647
- title: "\u56FE\u8868\u6539\u52A8\u7EA6\u675F",
648
- rules: [
649
- "\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",
650
- "\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"
651
- ]
652
- });
653
- }
654
- if (imports.has("docx") || imports.has("xlsx")) {
655
- packs.push({
656
- id: "file-processing",
657
- title: "\u6587\u6863/\u8868\u683C\u5904\u7406\u7EA6\u675F",
658
- rules: [
659
- "\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",
660
- "\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"
661
- ]
662
- });
663
- }
664
- return packs;
665
- };
666
- var formatAppConstraintPacks = (packs) => {
667
- if (packs.length === 0) return [];
668
- return [
669
- "",
670
- "\u5F53\u524D\u6FC0\u6D3B\u7EA6\u675F\u5305\uFF08\u6309\u5F53\u524D\u5E94\u7528\u4F9D\u8D56/\u5F62\u6001\u52A8\u6001\u6CE8\u5165\uFF09\uFF1A",
671
- ...packs.flatMap((pack) => [
672
- `- ${pack.title}\uFF08${pack.id}\uFF09`,
673
- ...pack.rules.map((rule) => ` - ${rule}`)
674
- ])
675
- ];
676
- };
677
- var buildEditingContextSummary = (state, runtimeOptions) => {
678
- const targetKind = runtimeOptions?.editingTarget?.kind;
679
- if (targetKind === "table") {
680
- const table = selectCurrentTable(state);
681
- const rows = selectTableRows(state);
682
- const metadata = runtimeOptions?.editingTarget?.metadata;
683
- const focusContext = metadata && typeof metadata === "object" ? metadata.focusContext : null;
684
- if (!table) return null;
685
- const columns = Array.isArray(table.columns) ? table.columns : [];
686
- const columnSummaries = columns.length ? columns.map((c) => {
687
- const displayName = c.label || c.name;
688
- const type = c.type || "text";
689
- const requiredFlag = c.required ? "\u5FC5\u586B" : "\u53EF\u9009";
690
- const primaryFlag = c.isPrimary ? "\uFF0C\u4E3B\u5B57\u6BB5" : "";
691
- const optionsStr = Array.isArray(c.options) && c.options.length ? `\uFF0C\u53EF\u9009\u503C\uFF1A${c.options.join(" | ")}` : "";
692
- const descStr = c.description ? `\u3002\u8BF4\u660E\uFF1A${c.description}` : "";
693
- return `- ${c.name}\uFF08\u663E\u793A\u540D\uFF1A${displayName}\uFF0C\u7C7B\u578B\uFF1A${type}\uFF0C${requiredFlag}${primaryFlag}${optionsStr}${descStr}\uFF09`;
694
- }) : ["- (\u5F53\u524D\u8868\u5C1A\u672A\u5B9A\u4E49\u5B57\u6BB5)"];
695
- const sampleRows = Array.isArray(rows) ? rows.slice(0, 20) : [];
696
- const rowsPreview = sampleRows.length ? JSON.stringify(sampleRows, null, 2) : "(\u5F53\u524D\u8868\u6682\u65E0\u884C\u6570\u636E)";
697
- const tableTitle = table.displayName ?? table.tableId ?? "(\u672A\u547D\u540D\u8868)";
698
- const tableDesc = table.description ? `\u7528\u9014\u8BF4\u660E\uFF1A${table.description}` : "(\u6682\u65E0\u7528\u9014\u8BF4\u660E)";
699
- const tableTagsLine = Array.isArray(table.tags) && table.tags.length ? `- \u5173\u952E\u8BCD\u6807\u7B7E: ${table.tags.join(", ")}` : null;
700
- return [
701
- "\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1A\u4E00\u5F20\u6570\u636E\u8868\uFF08Editing Table\uFF09\u3002",
702
- `- \u8868 ID: ${table.tableId}`,
703
- `- \u663E\u793A\u540D\u79F0: ${tableTitle}`,
704
- `- ${tableDesc}`,
705
- ...tableTagsLine ? [tableTagsLine] : [],
706
- ...focusContext && typeof focusContext === "object" && "columnName" in focusContext ? [
707
- "",
708
- "\u5F53\u524D\u7126\u70B9\uFF08Focus Context\uFF09\uFF1A",
709
- `- \u5F53\u524D\u5355\u5143\u683C\u5217: ${String(focusContext.columnName ?? "(\u672A\u77E5\u5217)")}`,
710
- ...focusContext.rowTitle ? [`- \u5F53\u524D\u884C\u6807\u9898: ${String(focusContext.rowTitle)}`] : [],
711
- ...focusContext.rowIndex !== null && focusContext.rowIndex !== void 0 ? [`- \u5F53\u524D\u884C\u53F7: ${Number(focusContext.rowIndex) + 1}`] : [],
712
- ...focusContext.cellPreview ? [`- \u5F53\u524D\u5355\u5143\u683C\u5185\u5BB9\u9884\u89C8: ${String(focusContext.cellPreview)}`] : []
713
- ] : [],
714
- "",
715
- "\u5B57\u6BB5\u5B9A\u4E49\uFF08Field Schema\uFF09\uFF1A",
716
- ...columnSummaries,
717
- "",
718
- "\u3010\u7ED9 AI \u7684\u64CD\u4F5C\u6307\u5357 / \u975E\u7528\u6237\u539F\u8BDD\u3011",
719
- "\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",
720
- "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",
721
- "2. \u8C03\u7528 addTableRow \u65F6\uFF1A",
722
- " - \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",
723
- ' - \u4F8B\u5982\uFF1A{"values":{"title":"\u4FEE Bug #123","status":"todo","note":"\u9AD8\u4F18\u5148\u7EA7"}}\u3002',
724
- " - \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",
725
- ' - \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',
726
- " - \u7EDD\u4E0D\u8981\u4F20\u5165\u7A7A\u5BF9\u8C61 {} \u4F5C\u4E3A values\u3002",
727
- "",
728
- "\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",
729
- rowsPreview
730
- ].join("\n");
731
- }
732
- if (targetKind === "page" || targetKind === "article") {
733
- const page = getDocState();
734
- const metadata = runtimeOptions?.editingTarget?.metadata;
735
- const focusContext = metadata && typeof metadata === "object" ? metadata.focusContext : null;
736
- if (!page) return null;
737
- const title = page.title ?? "(\u672A\u547D\u540D\u9875\u9762)";
738
- return [
739
- "\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1A\u4E00\u4E2A\u9875\u9762 / \u6587\u7AE0\uFF08Editing Document\uFF09\u3002",
740
- `- \u6807\u9898: ${title}`,
741
- ...focusContext && typeof focusContext === "object" && "anchorPath" in focusContext ? [
742
- "",
743
- "\u5F53\u524D\u7126\u70B9\uFF08Focus Context\uFF09\uFF1A",
744
- `- \u5149\u6807\u662F\u5426\u6298\u53E0: ${Boolean(focusContext.isCollapsed) ? "\u662F" : "\u5426"}`,
745
- ...focusContext.blockType ? [`- \u5F53\u524D\u5757\u7C7B\u578B: ${String(focusContext.blockType)}`] : [],
746
- ...focusContext.selectedText ? [`- \u5F53\u524D\u9009\u4E2D\u6587\u672C: ${String(focusContext.selectedText)}`] : [],
747
- ...focusContext.anchorPath?.length ? [`- \u5F53\u524D\u951A\u70B9\u8DEF\u5F84: ${focusContext.anchorPath.join(" > ")}`] : []
748
- ] : [],
749
- "",
750
- "\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",
751
- "\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"
752
- ].join("\n");
753
- }
754
- if (targetKind === "app") {
755
- const editingTarget = runtimeOptions?.editingTarget;
756
- const metadata = editingTarget?.metadata;
757
- const appId = editingTarget?.key ?? "(\u672A\u77E5 appId)";
758
- const title = editingTarget?.title ?? "(\u672A\u547D\u540D\u5E94\u7528)";
759
- const framework = typeof metadata?.framework === "string" ? metadata.framework : "worker";
760
- const appUrl = typeof metadata?.appUrl === "string" ? metadata.appUrl : null;
761
- const fileNames = Array.isArray(metadata?.fileNames) ? metadata.fileNames.filter((name) => typeof name === "string") : [];
762
- const externalImports = Array.isArray(metadata?.externalImports) ? metadata.externalImports.filter(
763
- (name) => typeof name === "string"
764
- ) : [];
765
- const sourceSummary = asOptionalTrimmedString(editingTarget?.summary) ?? null;
766
- const selectedNode = metadata && typeof metadata === "object" && metadata.selectedNode && typeof metadata.selectedNode === "object" ? metadata.selectedNode : null;
767
- const constraintPacks = buildAppConstraintPacks({
768
- framework,
769
- fileNames,
770
- externalImports
771
- });
772
- if (selectedNode && typeof selectedNode.cssPath === "string") {
773
- const tagName = typeof selectedNode.tagName === "string" && selectedNode.tagName ? selectedNode.tagName : "\u5143\u7D20";
774
- const cssPath = String(selectedNode.cssPath);
775
- const outerHTMLSnippet = typeof selectedNode.outerHTMLSnippet === "string" ? selectedNode.outerHTMLSnippet : "";
776
- const textSnippet = typeof selectedNode.textSnippet === "string" ? selectedNode.textSnippet : "";
777
- const noloLoc = typeof selectedNode.noloLoc === "string" ? selectedNode.noloLoc : "";
778
- constraintPacks.push({
779
- id: "selected-node",
780
- title: "\u7528\u6237\u9009\u4E2D\u8282\u70B9\uFF08\u5B9A\u70B9\u4FEE\u6539\uFF09",
781
- rules: [
782
- `\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`,
783
- `\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`,
784
- "\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",
785
- "\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",
786
- "\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"
787
- ]
788
- });
789
- }
790
- return [
791
- "\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1A\u4E00\u4E2A Web \u5E94\u7528\uFF08Editing App\uFF09\u3002",
792
- `- \u5E94\u7528 ID: ${appId}`,
793
- `- \u540D\u79F0: ${title}`,
794
- `- \u6280\u672F\u5F62\u6001: ${framework}`,
795
- ...appUrl ? [`- \u5F53\u524D\u8BBF\u95EE\u5730\u5740: ${appUrl}`] : [],
796
- ...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)"],
797
- ...externalImports.length ? [`- \u5F53\u524D\u4F9D\u8D56\u767D\u540D\u5355\u547D\u4E2D: ${externalImports.join(", ")}`] : [],
798
- ...sourceSummary ? ["", sourceSummary] : [],
799
- "",
800
- "\u3010\u7ED9 AI \u7684\u64CD\u4F5C\u6307\u5357 / \u975E\u7528\u6237\u539F\u8BDD\u3011",
801
- "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",
802
- "1b. \u5982\u679C appFileList / appFileSearch / appFileRead \u8FD4\u56DE 409\uFF08APP_WORKSPACE_MISSING / \u6E90\u7801\u5DE5\u4F5C\u533A\u7F3A\u5931\uFF09\u6216 400\uFF08UNSUPPORTED_APP_FRAMEWORK / \u4E0D\u662F Nolo React SSR\uFF09\uFF0C**\u7ACB\u5373\u505C\u6B62\u4FEE\u6539\uFF0C\u4E0D\u8981\u81EA\u5DF1\u7F16\u5360\u4F4D\u4EE3\u7801\u6216\u964D\u7EA7 framework \u53BB appDeploy**\u3002\u5148\u8C03\u7528 appVersionList(appId) \u67E5\u770B\u5386\u53F2\u7248\u672C\uFF0C\u9009\u4E00\u4E2A\u6700\u8FD1\u7684\u5B8C\u6574\u7248\u672C\u7528 appVersionRestore(appId, versionId) \u6062\u590D\uFF0C\u6062\u590D\u540E\u6E90\u7801\u5DE5\u4F5C\u533A\u4F1A\u91CD\u5EFA\uFF0C\u518D\u7EE7\u7EED\u4FEE\u6539\u3002\u5982\u679C\u6CA1\u6709\u5386\u53F2\u7248\u672C\uFF0C\u518D\u5411\u7528\u6237\u8BF4\u660E\u60C5\u51B5\u3002\u7EDD\u4E0D\u53EF\u4EE5\u7528 `fetch(appUrl)`\u3001\u7A7A\u4EE3\u7801\u3001\u5360\u4F4D\u4EE3\u7801\u53BB appDeploy\u2014\u2014\u90A3\u4F1A\u8986\u76D6\u73B0\u6709\u5E94\u7528\u5BFC\u81F4\u6570\u636E\u4E22\u5931\u3002",
803
- "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",
804
- "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",
805
- "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",
806
- `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`,
807
- 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",
808
- ...fileNames.length ? [] : [
809
- "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",
810
- "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"
811
- ],
812
- "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",
813
- "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",
814
- "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",
815
- ...formatAppConstraintPacks(constraintPacks)
816
- ].join("\n");
817
- }
818
- if (targetKind === "local_preview") {
819
- const metadata = runtimeOptions?.editingTarget?.metadata;
820
- const selectedNode = metadata && typeof metadata === "object" && metadata.selectedNode && typeof metadata.selectedNode === "object" ? metadata.selectedNode : null;
821
- if (!selectedNode) return null;
822
- const readString = (key) => typeof selectedNode[key] === "string" ? selectedNode[key] : "";
823
- const tagName = readString("tagName") || "\u5143\u7D20";
824
- const cssPath = readString("cssPath");
825
- const noloLoc = readString("noloLoc");
826
- const textSnippet = readString("textSnippet");
827
- const outerHTMLSnippet = readString("outerHTMLSnippet");
828
- return [
829
- "\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1A\u672C\u5730\u5DE5\u4F5C\u533A\u91CC\u6B63\u5728\u9884\u89C8\u7684\u7F51\u9875\uFF08Local Preview\uFF09\u3002",
830
- `\u7528\u6237\u5728\u9884\u89C8\u4E2D\u9009\u4E2D\u4E86\u4E00\u4E2A\u5143\u7D20\uFF1A<${tagName}>\uFF0CCSS \u8DEF\u5F84\uFF1A${cssPath}${noloLoc ? `\uFF0C\u6E90\u7801\u4F4D\u7F6E\uFF1A${noloLoc}` : ""}\u3002`,
831
- `\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`,
832
- "",
833
- "\u3010\u7ED9 AI \u7684\u64CD\u4F5C\u6307\u5357 / \u975E\u7528\u6237\u539F\u8BDD\u3011",
834
- "1. \u672C\u8F6E\u4FEE\u6539\u5FC5\u987B\u4EE5\u8FD9\u4E2A\u5143\u7D20\u4E3A\u4E2D\u5FC3\uFF1B\u5148\u5728\u672C\u5730\u5DE5\u4F5C\u533A\u6E90\u7801\u4E2D\u5B9A\u4F4D\u5230\u751F\u6210\u8FD9\u6BB5 HTML \u7684\u4EE3\u7801\uFF0C\u518D\u52A8\u624B\u3002",
835
- noloLoc ? "2. \u5DF2\u7ED9\u51FA\u6E90\u7801\u4F4D\u7F6E\uFF0C\u76F4\u63A5\u8BFB\u8BE5\u6587\u4EF6\u7684\u5BF9\u5E94\u884C\u8303\u56F4\u786E\u8BA4\uFF0C\u4E0D\u8981\u5168\u5C40\u641C\u7D22\u3002" : "2. \u6CA1\u6709\u6E90\u7801\u4F4D\u7F6E\u65F6\uFF0C\u7528 CSS \u8DEF\u5F84\u91CC\u7684\u7C7B\u540D\u3001\u53EF\u89C1\u6587\u672C\u6216 HTML \u7247\u6BB5\u641C\u7D22\u5DE5\u4F5C\u533A\u5B9A\u4F4D\uFF0C\u4E0D\u8981\u51ED\u731C\u6D4B\u6539\u52A8\u3002",
836
- "3. \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\u4FDD\u6301\u672A\u547D\u4E2D\u7684\u6587\u4EF6\u4E0D\u53D8\u3002",
837
- "4. \u5982\u679C\u5B9A\u4F4D\u7ED3\u679C\u843D\u5728 node_modules \u6216\u6765\u81EA\u63A5\u53E3\u6570\u636E\uFF0C\u5148\u544A\u8BC9\u7528\u6237\u5B9E\u9645\u60C5\u51B5\uFF0C\u518D\u63D0\u51FA\u53EF\u884C\u7684\u6539\u6CD5\uFF0C\u4E0D\u8981\u786C\u6539\u3002",
838
- "5. \u5982\u679C\u6309 CSS \u8DEF\u5F84\u548C HTML \u7247\u6BB5\u627E\u4E0D\u5230\u5BF9\u5E94\u4F4D\u7F6E\uFF0C\u5148\u5411\u7528\u6237\u8BF4\u660E\u5E76\u8BF7\u5176\u91CD\u65B0\u9009\u62E9\u3002"
839
- ].join("\n");
840
- }
841
- if (targetKind === "image" || targetKind === "file") {
842
- const editingTarget = runtimeOptions?.editingTarget;
843
- const metadata = editingTarget?.metadata;
844
- const title = editingTarget?.title ?? "(\u672A\u547D\u540D\u5BF9\u8C61)";
845
- const objectKey = editingTarget?.key ?? "(\u672A\u77E5 key)";
846
- const fileId = typeof metadata?.fileId === "string" ? metadata.fileId : null;
847
- const url = typeof metadata?.url === "string" ? metadata.url : null;
848
- const size = typeof metadata?.size === "number" ? metadata.size : null;
849
- return [
850
- `\u5F53\u524D\u7F16\u8F91\u76EE\u6807\uFF1A\u4E00\u4E2A${targetKind === "image" ? "\u56FE\u7247" : "\u6587\u4EF6"}\u5BF9\u8C61\uFF08Editing ${targetKind === "image" ? "Image" : "File"}\uFF09\u3002`,
851
- `- \u5BF9\u8C61 key: ${objectKey}`,
852
- `- \u6807\u9898: ${title}`,
853
- ...fileId ? [`- fileId: ${fileId}`] : [],
854
- ...url ? [`- \u8D44\u6E90\u5730\u5740: ${url}`] : [],
855
- ...size !== null ? [`- \u6587\u4EF6\u5927\u5C0F: ${size} bytes`] : [],
856
- "",
857
- "\u3010\u7ED9 AI \u7684\u64CD\u4F5C\u6307\u5357 / \u975E\u7528\u6237\u539F\u8BDD\u3011",
858
- 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"
859
- ].join("\n");
860
- }
861
- if (targetKind === "canvas_node") {
862
- return buildCanvasNodeEditingContextSummary(runtimeOptions);
863
- }
864
- return null;
865
- };
866
-
867
- // packages/ai/llm/agentCapabilities.ts
868
- var ANTIGRAVITY_EFFORT_SUFFIXES = [
869
- "-tiered",
870
- "-extra-low",
871
- "-low",
872
- "-medium",
873
- "-high"
874
- ];
875
- function stripEffortSuffix(model) {
876
- for (const suffix of ANTIGRAVITY_EFFORT_SUFFIXES) {
877
- if (model.endsWith(suffix) && model.length > suffix.length) {
878
- return model.slice(0, -suffix.length);
879
- }
880
- }
881
- return model;
882
- }
883
- function stripPreviewSuffix(model) {
884
- const suffix = "-preview";
885
- if (model.endsWith(suffix) && model.length > suffix.length) {
886
- return model.slice(0, -suffix.length);
887
- }
888
- return model;
889
- }
890
- var lookupKnownModelVision = (provider, model) => {
891
- if (!model) return void 0;
892
- const candidates = [model];
893
- const strippedEffort = stripEffortSuffix(model);
894
- if (strippedEffort !== model) candidates.push(strippedEffort);
895
- const strippedPreview = stripPreviewSuffix(model);
896
- if (strippedPreview !== model) candidates.push(strippedPreview);
897
- for (const candidate of candidates) {
898
- if (provider && provider !== "custom") {
899
- const direct = findModelConfig(provider, candidate);
900
- if (direct && typeof direct.hasVision === "boolean") return direct.hasVision;
901
- }
902
- const detected = getProviderByModelName(candidate);
903
- if (detected) {
904
- const found = findModelConfig(detected, candidate)?.hasVision;
905
- if (found !== void 0) return found;
906
- }
907
- if (candidate.includes("/")) {
908
- const slash = candidate.indexOf("/");
909
- const modelProvider = candidate.slice(0, slash).toLowerCase();
910
- const modelName = candidate.slice(slash + 1);
911
- const nested = findModelConfig(modelProvider, modelName);
912
- if (nested && typeof nested.hasVision === "boolean") return nested.hasVision;
913
- }
914
- }
915
- return void 0;
916
- };
917
- var resolveAgentImageInputSupport = (agent) => {
918
- if (!agent) return true;
919
- const provider = asTrimmedLowercaseString(agent.provider) || null;
920
- const model = asOptionalTrimmedString(agent.model) ?? "";
921
- const catalogHasVision = lookupKnownModelVision(
922
- provider,
923
- model
924
- );
925
- if (catalogHasVision !== void 0) {
926
- return catalogHasVision;
927
- }
928
- if (typeof agent.hasVision === "boolean") {
929
- return agent.hasVision;
930
- }
931
- return true;
932
- };
933
-
934
- // packages/ai/agent/appWorkingMemory.ts
935
- var APP_TOOL_NAMES = /* @__PURE__ */ new Set([
936
- "appList",
937
- "appRead",
938
- "appDeploy",
939
- "appPreflight",
940
- "appDelete"
941
- ]);
942
- var contentToText = (content) => {
943
- if (!content) return "";
944
- if (typeof content === "string") return content;
945
- if (Array.isArray(content)) {
946
- return content.map((part) => "text" in part ? part.text ?? "" : "").join("\n");
947
- }
948
- return "";
949
- };
950
- var parseAppListEntries = (text) => text.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("- **") && line.includes("(appId:"));
951
- var buildRecentAppToolMemory = (messages, toolRuns) => {
952
- const messageById = new Map(messages.map((msg) => [msg.id, msg]));
953
- const recentRuns = [...toolRuns].filter((run) => APP_TOOL_NAMES.has(run.toolName)).sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0)).slice(0, 8);
954
- if (recentRuns.length === 0) return null;
955
- const lines = [
956
- "\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"
957
- ];
958
- const latestDeployLike = recentRuns.find(
959
- (run) => ["appDeploy", "appRead", "appPreflight"].includes(run.toolName)
960
- );
961
- if (latestDeployLike) {
962
- const input = latestDeployLike.input ?? {};
963
- const parts = [
964
- `- \u6700\u8FD1\u4E00\u6B21\u5173\u952E app \u64CD\u4F5C: ${latestDeployLike.toolName}`,
965
- typeof input.appId === "string" ? `appId=${input.appId}` : null,
966
- typeof input.name === "string" ? `name=${input.name}` : null,
967
- typeof input.framework === "string" ? `framework=${input.framework}` : null
968
- ].filter(Boolean);
969
- lines.push(parts.join("\uFF0C"));
970
- }
971
- const relatedMessages = recentRuns.map((run) => messageById.get(run.messageId)).filter((msg) => !!msg);
972
- const appListMessage = relatedMessages.find((msg) => msg.toolName === "appList");
973
- if (appListMessage) {
974
- const entries = parseAppListEntries(contentToText(appListMessage.content)).slice(0, 5);
975
- if (entries.length > 0) {
976
- lines.push("- \u6700\u8FD1\u4E00\u6B21 appList \u7ED3\u679C\uFF1A");
977
- lines.push(...entries.map((entry) => ` ${entry}`));
978
- }
979
- }
980
- const latestReadMessage = relatedMessages.find((msg) => msg.toolName === "appRead");
981
- if (latestReadMessage) {
982
- const text = contentToText(latestReadMessage.content);
983
- const appId = text.match(/- appId:\s*(.+)/)?.[1]?.trim();
984
- const url = text.match(/- 访问地址:\s*(.+)/)?.[1]?.trim();
985
- if (appId || url) {
986
- lines.push(
987
- [
988
- "- \u6700\u8FD1\u4E00\u6B21 appRead \u771F\u503C:",
989
- appId ? `appId=${appId}` : null,
990
- url ? `url=${url}` : null
991
- ].filter(Boolean).join("\uFF0C")
992
- );
993
- }
994
- }
995
- const latestPreflightRun = recentRuns.find((run) => run.toolName === "appPreflight");
996
- if (latestPreflightRun) {
997
- lines.push(
998
- [
999
- "- \u6700\u8FD1\u4E00\u6B21 appPreflight:",
1000
- latestPreflightRun.status === "failed" ? "\u5931\u8D25" : "\u5DF2\u6267\u884C",
1001
- latestPreflightRun.outputSummary ? `\u6458\u8981=${latestPreflightRun.outputSummary}` : null
1002
- ].filter(Boolean).join("\uFF0C")
1003
- );
1004
- }
1005
- const latestDeployMessage = relatedMessages.find((msg) => msg.toolName === "appDeploy");
1006
- if (latestDeployMessage) {
1007
- const text = contentToText(latestDeployMessage.content);
1008
- const appId = text.match(/- appId:\s*(.+)/)?.[1]?.trim();
1009
- const url = text.match(/- 访问地址:\s*(.+)/)?.[1]?.trim();
1010
- if (appId || url) {
1011
- lines.push(
1012
- [
1013
- "- \u6700\u8FD1\u4E00\u6B21 appDeploy \u7ED3\u679C:",
1014
- appId ? `appId=${appId}` : null,
1015
- url ? `url=${url}` : null
1016
- ].filter(Boolean).join("\uFF0C")
1017
- );
1018
- }
1019
- }
1020
- lines.push(
1021
- "- \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"
1022
- );
1023
- return lines.join("\n");
1024
- };
1025
-
1026
- // packages/ai/agent/streamAgentChatTurnUtils.ts
1027
- var BROWSER_UNAVAILABLE_CORE_TOOLS = {
1028
- queryModelUsage: true,
1029
- createAgentAutomation: true,
1030
- notifyUser: true
1031
- };
1032
- var getRuntimeCoreTools = () => {
1033
- if (typeof window === "undefined") {
1034
- return [...TOOL_PACKS.CORE];
1035
- }
1036
- return TOOL_PACKS.CORE.filter(
1037
- (toolName) => !BROWSER_UNAVAILABLE_CORE_TOOLS[toolName]
1038
- );
1039
- };
1040
- var isInlineVisualArtifactAgent = (agentConfig) => {
1041
- const tags = Array.isArray(agentConfig.tags) ? agentConfig.tags : [];
1042
- return tags.some(
1043
- (tag) => typeof tag === "string" && ["inline-artifact", "streaming-ui"].includes(tag)
1044
- );
1045
- };
1046
- var estimateTokensOfMessage = (msg) => {
1047
- let content = "";
1048
- if (typeof msg.content === "string") {
1049
- content = msg.content;
1050
- } else if (Array.isArray(msg.content)) {
1051
- content = msg.content.map((p) => {
1052
- if (p.type === "text") return p.text || "";
1053
- if (p.type === "image_url") return "[image]";
1054
- return "[non-text]";
1055
- }).join("");
1056
- } else if (msg.content && typeof msg.content === "object") {
1057
- content = JSON.stringify(msg.content);
1058
- }
1059
- let extraTokens = 0;
1060
- if (Array.isArray(msg.tool_calls)) {
1061
- const toolsStr = JSON.stringify(msg.tool_calls);
1062
- extraTokens = estimateTokenCount(toolsStr);
1063
- }
1064
- return estimateTokenCount(content) + extraTokens;
1065
- };
1066
- var classifyConversationLoad = (messages) => {
1067
- const N = 20;
1068
- if (!Array.isArray(messages) || messages.length === 0) return "light";
1069
- const tail = messages.slice(-N);
1070
- const tokenSamples = tail.map(estimateTokensOfMessage);
1071
- if (tokenSamples.length === 0) return "light";
1072
- const sum = tokenSamples.reduce((acc, v) => acc + v, 0);
1073
- const avg = sum / tokenSamples.length;
1074
- const sorted = [...tokenSamples].sort((a, b) => a - b);
1075
- const p95 = sorted[Math.floor((sorted.length - 1) * 0.95)];
1076
- if (p95 < 200 && avg < 120) {
1077
- return "light";
1078
- }
1079
- if (p95 > 2e3 || avg > 1200) {
1080
- return "heavy";
1081
- }
1082
- return "medium";
1083
- };
1084
- var compressOldToolResults = (messages, maxChars = 800) => {
1085
- let lastToolCallAssistantIdx = -1;
1086
- for (let i = messages.length - 1; i >= 0; i--) {
1087
- if (messages[i].role === "assistant" && Array.isArray(messages[i].tool_calls) && messages[i].tool_calls.length > 0) {
1088
- lastToolCallAssistantIdx = i;
1089
- break;
1090
- }
1091
- }
1092
- return messages.map((msg, idx) => {
1093
- if (msg.role !== "tool") return msg;
1094
- const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
1095
- const projected = projectToolMessageContent({
1096
- content,
1097
- isFresh: idx > lastToolCallAssistantIdx,
1098
- toolName: msg.name,
1099
- historicalMaxChars: maxChars
1100
- });
1101
- if (projected === content) return msg;
1102
- return { ...msg, content: projected };
1103
- });
1104
- };
1105
- var trimMessagesWithSummary = (messages, contextWindow, summaryTokenCount) => {
1106
- const recentLoad = classifyConversationLoad(messages);
1107
- const { rawMessageBudget, minTailTokens } = planContextUsage({
1108
- contextWindow,
1109
- summaryTokens: summaryTokenCount,
1110
- recentLoad
1111
- });
1112
- if (!Array.isArray(messages) || messages.length === 0) return messages;
1113
- let totalTokens = 0;
1114
- let keepCount = 0;
1115
- for (let i = messages.length - 1; i >= 0; i--) {
1116
- const t = estimateTokensOfMessage(messages[i]);
1117
- if (totalTokens + t > rawMessageBudget) break;
1118
- totalTokens += t;
1119
- keepCount++;
1120
- }
1121
- if (keepCount >= messages.length) {
1122
- return messages;
1123
- }
1124
- if (totalTokens < minTailTokens) {
1125
- const maxBudgetWithSlack = rawMessageBudget * 1.2;
1126
- for (let i = messages.length - 1 - keepCount; i >= 0; i--) {
1127
- const t = estimateTokensOfMessage(messages[i]);
1128
- if (totalTokens + t > maxBudgetWithSlack) break;
1129
- totalTokens += t;
1130
- keepCount++;
1131
- if (totalTokens >= minTailTokens) break;
1132
- }
1133
- }
1134
- if (keepCount === 0 && messages.length > 0) {
1135
- keepCount = Math.min(2, messages.length);
1136
- }
1137
- let cutIndex = messages.length - keepCount;
1138
- if (cutIndex < 0) cutIndex = 0;
1139
- while (cutIndex > 0 && messages[cutIndex]?.role === "tool") {
1140
- cutIndex--;
1141
- }
1142
- return messages.slice(cutIndex);
1143
- };
1144
- var createDbSliceTurnContextSource = (dispatch) => ({
1145
- readRecord: async (dbKey) => {
1146
- const result = await dispatch(read({ dbKey })).unwrap();
1147
- return result ?? null;
1148
- }
1149
- });
1150
- var joinMapValues = (map) => Array.from(map.values()).join("");
1151
- var hasImageInMessages = (messages) => {
1152
- if (!Array.isArray(messages)) return false;
1153
- return messages.some((msg) => {
1154
- const content = msg.content;
1155
- if (!Array.isArray(content)) return false;
1156
- return content.some(
1157
- (part) => part && typeof part === "object" && part.type === "image_url" && part.image_url && typeof part.image_url.url === "string" && part.image_url.url.trim() !== ""
1158
- );
1159
- });
1160
- };
1161
- 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";
1162
- function shouldRejectImageInputForAgent(agentConfig, messages) {
1163
- const agentHasVision = resolveAgentImageInputSupport(agentConfig);
1164
- if (!agentHasVision && hasImageInMessages(messages)) {
1165
- return REJECT_NO_VISION_MESSAGE;
1166
- }
1167
- return null;
1168
- }
1169
- var formatCurrentInputContext = (pendingFiles, currentInputMap) => {
1170
- if (pendingFiles.length === 0 || currentInputMap.size === 0) {
1171
- return joinMapValues(currentInputMap);
1172
- }
1173
- const relevantPendingFiles = pendingFiles.filter((file) => {
1174
- const key = file.sourceDialogKey || file.dialogKey || file.pageKey;
1175
- return key && currentInputMap.has(key);
1176
- });
1177
- if (relevantPendingFiles.length === 0) {
1178
- return joinMapValues(currentInputMap);
1179
- }
1180
- const filesByGroup = /* @__PURE__ */ new Map();
1181
- for (const file of relevantPendingFiles) {
1182
- const groupKey = file.groupId || file.id;
1183
- const group = filesByGroup.get(groupKey);
1184
- if (group) {
1185
- group.push(file);
1186
- } else {
1187
- filesByGroup.set(groupKey, [file]);
1188
- }
1189
- }
1190
- let sourceCounter = 1;
1191
- let output = "";
1192
- filesByGroup.forEach((filesInGroup) => {
1193
- const isGroup = filesInGroup.length > 1;
1194
- const sourceName = isGroup ? filesInGroup[0].name.split(" (")[0] : filesInGroup[0].name;
1195
- output += `--- Source ${sourceCounter}: "${sourceName}" ---
1196
- `;
1197
- filesInGroup.forEach((file) => {
1198
- const key = file.sourceDialogKey || file.dialogKey || file.pageKey;
1199
- if (!key) return;
1200
- const content = currentInputMap.get(key);
1201
- if (!content) return;
1202
- if (isGroup) {
1203
- output += `### Document: "${file.name}"
1204
- ${content}
1205
- `;
1206
- } else {
1207
- output += `${content}
1208
- `;
1209
- }
1210
- });
1211
- output += `--- End of Source ${sourceCounter} ---
1212
-
1213
- `;
1214
- sourceCounter++;
1215
- });
1216
- return output;
1217
- };
1218
- var validateAccessAndBalance = (agentConfig, state) => {
1219
- const userBalance = selectIdentityUserBalance(state);
1220
- const currentUserId = selectIdentityUserId(state);
1221
- const isCustomApi = agentConfig.apiSource === "custom";
1222
- const isCliApi = agentConfig.apiSource === "cli";
1223
- const isDeviceLocalOwner = agentConfig.userId === "local" && !currentUserId;
1224
- const isOwner = isDeviceLocalOwner || Boolean(currentUserId) && agentConfig.userId === currentUserId;
1225
- if (!isOwner) {
1226
- const hasWhitelist = Array.isArray(agentConfig.whitelist) && agentConfig.whitelist.length > 0;
1227
- if (hasWhitelist) {
1228
- const isUserInWhitelist = !!currentUserId && agentConfig.whitelist?.includes(currentUserId);
1229
- if (!isUserInWhitelist) {
1230
- return "\u60A8\u4E0D\u5728\u8BE5\u5E94\u7528\u7684\u767D\u540D\u5355\u4E2D\uFF0C\u65E0\u6CD5\u4F7F\u7528\u3002";
1231
- }
1232
- }
1233
- }
1234
- if (isCustomApi || isCliApi) {
1235
- return null;
1236
- }
1237
- const SUBSCRIPTION_OAUTH_REFS = /* @__PURE__ */ new Set([
1238
- "cursor",
1239
- "chatgpt",
1240
- "xai",
1241
- "antigravity",
1242
- "claude"
1243
- ]);
1244
- if (SUBSCRIPTION_OAUTH_REFS.has((agentConfig.apiKeyRef ?? "").trim().toLowerCase())) {
1245
- return null;
1246
- }
1247
- const isPlatformApi = agentConfig.apiSource === "platform" || agentConfig.useServerProxy === true;
1248
- if (isDeviceLocalOwner && !isPlatformApi) {
1249
- return null;
1250
- }
1251
- if (typeof userBalance !== "number") {
1252
- const hasSessionUser = Boolean(
1253
- state?.auth?.currentUser?.userId
1254
- );
1255
- if (!currentUserId || !hasSessionUser) {
1256
- return "\u8BF7\u767B\u5F55\u540E\u4F7F\u7528\u5E73\u53F0\u6A21\u578B\uFF0C\u6216\u6539\u7528\u672C\u5730\u81EA\u5B9A\u4E49/API/CLI Agent\u3002";
1257
- }
1258
- return "\u6B63\u5728\u83B7\u53D6\u7528\u6237\u4F59\u989D\uFF0C\u8BF7\u7A0D\u5019...";
1259
- }
1260
- const serverPrices = getModelPricing(agentConfig.provider || "", agentConfig.model);
1261
- if (!serverPrices && !hasExplicitAgentPricing(agentConfig)) {
1262
- return "\u65E0\u6CD5\u83B7\u53D6\u6A21\u578B\u5B9A\u4EF7\u4FE1\u606F\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
1263
- }
1264
- const prices = getPrices(agentConfig, serverPrices ?? null);
1265
- const maxPrice = getFinalPrice(prices);
1266
- if (userBalance < maxPrice) {
1267
- return "\u4F59\u989D\u4E0D\u8DB3\uFF0C\u8BF7\u5145\u503C\u540E\u518D\u8BD5\u3002";
1268
- }
1269
- return null;
1270
- };
1271
- var fetchMemoryOverlayContext = async (state, agentConfig, userInput, dialogConfig) => {
1272
- const token = typeof state?.auth?.currentToken === "string" ? state.auth.currentToken : null;
1273
- const currentServer = typeof state?.settings?.currentServer === "string" ? state.settings.currentServer : null;
1274
- const agentKey = asOptionalTrimmedString(agentConfig.dbKey) ?? "";
1275
- if (!token || !currentServer || !agentKey) return null;
1276
- const baseUrl = resolveToolBaseUrl(currentServer);
1277
- if (!baseUrl) return null;
1278
- const inputText = typeof userInput === "string" ? userInput : JSON.stringify(userInput ?? "");
1279
- const spaceId = asOptionalTrimmedString(dialogConfig?.spaceId) ?? (state?.space?.viewMode === "all" ? void 0 : asOptionalTrimmedString(state?.space?.currentSpaceId));
1280
- try {
1281
- const response = await fetch(`${baseUrl}/api/memory/query`, {
1282
- method: "POST",
1283
- headers: {
1284
- "Content-Type": "application/json",
1285
- Authorization: `Bearer ${token}`
1286
- },
1287
- body: JSON.stringify({
1288
- agentKey,
1289
- userInput: inputText,
1290
- ...spaceId ? { spaceId } : {}
1291
- })
1292
- });
1293
- if (!response.ok) return null;
1294
- const payload = await response.json().catch(() => null);
1295
- return asOptionalTrimmedString(payload?.promptBlock) ?? null;
1296
- } catch {
1297
- return null;
1298
- }
1299
- };
1300
- var buildStaticContexts = async (state, dispatch, agentConfig, dialogConfig, referenceContentCache) => {
1301
- const keySets = await getFullChatContextKeys(
1302
- state,
1303
- dispatch,
1304
- agentConfig,
1305
- "",
1306
- // 静态上下文不需要 userInput
1307
- void 0
1308
- // 静态上下文不需要 dialogConfig
1309
- );
1310
- const finalKeys = deduplicateContextKeys(keySets);
1311
- const fetchReferences = (keys) => fetchReferenceContents(keys, dispatch, {
1312
- format: "simplified_markdown",
1313
- inlineMentionMeta: true,
1314
- preloaded: referenceContentCache
1315
- });
1316
- const [botInstructionsMap, botKnowledgeMap] = await Promise.all([
1317
- fetchReferences(finalKeys.botInstructionsContext),
1318
- fetchReferences(finalKeys.botKnowledgeContext)
1319
- ]);
1320
- const globalPrompt = selectGlobalPrompt(state);
1321
- const userTonePreset = selectUserTonePreset(state);
1322
- const knowledgeCaptureLevel = selectKnowledgeCaptureLevel(state);
1323
- const spaceContextLevel = selectSpaceContextLevel(state);
1324
- const userRecentLimit = selectAiRecentContentLimit(state);
1325
- const contextWindow = getModelContextWindow(agentConfig.model) || 128e3;
1326
- const preloadPlan = resolveSpaceContextPreloadPlan(spaceContextLevel);
1327
- const dynamicLimit = Math.floor(contextWindow * preloadPlan.preloadBudgetRatio / 150);
1328
- const recentLimit = preloadPlan.includeRecentContent ? Math.max(3, Math.min(userRecentLimit, Math.max(3, dynamicLimit))) : 0;
1329
- const turnContextSource = createDbSliceTurnContextSource(dispatch);
1330
- let spaceContext = null;
1331
- if (spaceContextLevel > 1) {
1332
- const spaceLayer = await buildSpaceContextLayer({
1333
- source: turnContextSource,
1334
- spaceId: dialogConfig?.spaceId,
1335
- recentContentLimit: recentLimit
1336
- });
1337
- spaceContext = spaceLayer ? spaceLayer.content.trim() : null;
1338
- }
1339
- const linkedSpaceIds = agentConfig.linkedSpaces || [];
1340
- if (linkedSpaceIds.length > 0 && spaceContextLevel > 1) {
1341
- const linkedSection = await buildLinkedSpacesSection({
1342
- source: turnContextSource,
1343
- linkedSpaceIds
1344
- });
1345
- if (linkedSection) {
1346
- spaceContext = (spaceContext ?? "") + `
1347
-
1348
- ${linkedSection}`;
1349
- }
1350
- }
1351
- const dialogPolicyContext = dialogConfig?.category === PERSONALIZATION_DIALOG_CATEGORY ? buildPersonalizationDialogPolicyContext() : null;
1352
- return {
1353
- botInstructionsContext: joinMapValues(botInstructionsMap),
1354
- botKnowledgeContext: joinMapValues(botKnowledgeMap),
1355
- spaceContext,
1356
- userGlobalPrompt: globalPrompt,
1357
- userPolicyContext: [
1358
- buildStaticUserPolicyContext({
1359
- agentConfig,
1360
- settingsRecord: {
1361
- userTonePreset,
1362
- knowledgeCaptureLevel,
1363
- spaceContextLevel,
1364
- enableReadCurrentSpace: spaceContextLevel > 1
1365
- }
1366
- }),
1367
- dialogPolicyContext
1368
- ].filter(Boolean).join("\n")
1369
- };
1370
- };
1371
- var buildDynamicContexts = async (state, dispatch, agentConfig, userInput, runtimeOptions, referenceContentCache, dialogKey) => {
1372
- let dialogSummary = null;
1373
- let dialogConfig;
1374
- if (dialogKey) {
1375
- dialogConfig = selectById(state, dialogKey);
1376
- if (dialogConfig?.summary) {
1377
- dialogSummary = dialogConfig.summary;
1378
- }
1379
- }
1380
- const keySets = await getFullChatContextKeys(
1381
- state,
1382
- dispatch,
1383
- agentConfig,
1384
- userInput,
1385
- dialogConfig
1386
- );
1387
- const finalKeys = deduplicateContextKeys(keySets);
1388
- const fetchReferences = (keys) => fetchReferenceContents(keys, dispatch, {
1389
- format: "simplified_markdown",
1390
- inlineMentionMeta: true,
1391
- preloaded: referenceContentCache
1392
- });
1393
- const [currentInputMap, historyMap] = await Promise.all([
1394
- fetchReferences(finalKeys.currentInputContext),
1395
- fetchReferences(finalKeys.historyContext)
1396
- ]);
1397
- const pendingFiles = selectPendingFiles(state);
1398
- const formattedCurrentInputContext = formatCurrentInputContext(
1399
- pendingFiles,
1400
- currentInputMap
1401
- );
1402
- const dialogId = dialogConfig?.id ?? null;
1403
- const currentDialogMessages = selectAllMsgs(state, dialogId);
1404
- const currentDialogMessageIds = new Set(currentDialogMessages.map((msg) => msg.id));
1405
- const currentDialogToolRuns = getAllToolRuns().filter(
1406
- (run) => currentDialogMessageIds.has(run.messageId)
1407
- );
1408
- const editingContext = buildEditingContextSummary(state, runtimeOptions);
1409
- const appWorkingMemory = buildRecentAppToolMemory(
1410
- currentDialogMessages,
1411
- currentDialogToolRuns
1412
- );
1413
- const memoryOverlay = await fetchMemoryOverlayContext(
1414
- state,
1415
- agentConfig,
1416
- userInput,
1417
- dialogConfig
1418
- );
1419
- return {
1420
- currentInputContext: formattedCurrentInputContext.trim() || null,
1421
- historyContext: joinMapValues(historyMap),
1422
- editingContext,
1423
- appWorkingMemory,
1424
- memoryOverlay,
1425
- dialogSummary,
1426
- referenceKeys: dialogConfig?.referenceKeys || []
1427
- };
1428
- };
1429
- var mergeContexts = (staticCtx, dynamicCtx) => ({
1430
- botInstructionsContext: staticCtx.botInstructionsContext || void 0,
1431
- botKnowledgeContext: staticCtx.botKnowledgeContext || void 0,
1432
- spaceContext: staticCtx.spaceContext || void 0,
1433
- userGlobalPrompt: staticCtx.userGlobalPrompt || void 0,
1434
- userPolicyContext: staticCtx.userPolicyContext || void 0,
1435
- currentInputContext: dynamicCtx.currentInputContext,
1436
- historyContext: dynamicCtx.historyContext || void 0,
1437
- editingContext: dynamicCtx.editingContext,
1438
- appWorkingMemory: dynamicCtx.appWorkingMemory,
1439
- memoryOverlay: dynamicCtx.memoryOverlay,
1440
- dialogSummary: dynamicCtx.dialogSummary,
1441
- referenceKeys: dynamicCtx.referenceKeys
1442
- });
1443
- var mergeAgentToolsWithRuntime = (agentConfig, referencedTools, mentionedTools, runtimeOptions, state) => {
1444
- const rawBaseTools = Array.isArray(agentConfig.tools) ? agentConfig.tools : [];
1445
- const agentEnabledPacks = resolveAgentRequiredPackIds(agentConfig);
1446
- const isInlineArtifact = isInlineVisualArtifactAgent(agentConfig);
1447
- const effectiveEnabledPacks = resolveEffectiveEnabledPacks({
1448
- enabledPacks: agentEnabledPacks,
1449
- declaredOnly: isInlineArtifact
1450
- });
1451
- const expandedPackTools = expandEnabledPacks(
1452
- effectiveEnabledPacks,
1453
- rawBaseTools
1454
- );
1455
- const baseTools = canonicalizeToolNames(expandedPackTools);
1456
- const requiredSkillTools = canonicalizeToolNames(
1457
- agentConfig.referencedTools ?? []
1458
- );
1459
- const recommendedSkillTools = canonicalizeToolNames(
1460
- agentConfig.recommendedSkillTools ?? []
1461
- );
1462
- const recommendedSkillHints = [
1463
- .../* @__PURE__ */ new Set([
1464
- ...asNonEmptyStringArray(agentConfig.recommendedSkillHints),
1465
- ...resolveAgentRecommendedSkillNames(agentConfig)
1466
- ])
1467
- ];
1468
- const skillPromptPatches = [
1469
- .../* @__PURE__ */ new Set([
1470
- ...asNonEmptyStringArray(agentConfig.skillPromptPatches),
1471
- // 能力包的 promptPatch(方法论文档)与 skill reference 的 patch 走同一条
1472
- // 注入链(buildSkillGuidanceBlock → buildSkillGuidancePromptBlock),
1473
- // 让「工具 + 配套纪律」作为一个能力包整体注入 system prompt。
1474
- ...expandEnabledPackPromptPatches(effectiveEnabledPacks)
1475
- ])
1476
- ];
1477
- const webPadded = applyDefaultWebToolPacks({
1478
- toolNames: baseTools,
1479
- skipWeb: isInlineVisualArtifactAgent(agentConfig)
1480
- });
1481
- const enhancedTools = /* @__PURE__ */ new Set([
1482
- ...webPadded,
1483
- ...isInlineVisualArtifactAgent(agentConfig) ? [] : getRuntimeCoreTools(),
1484
- ...isInlineVisualArtifactAgent(agentConfig) ? [] : requiredSkillTools,
1485
- ...isInlineVisualArtifactAgent(agentConfig) ? [] : canonicalizeToolNames(referencedTools),
1486
- ...isInlineVisualArtifactAgent(agentConfig) ? [] : canonicalizeToolNames(mentionedTools)
1487
- ]);
1488
- const extraTools = isInlineVisualArtifactAgent(agentConfig) ? [] : canonicalizeToolNames(runtimeOptions?.extraTools ?? []);
1489
- for (const t of extraTools) {
1490
- enhancedTools.add(t);
1491
- }
1492
- if (!isInlineVisualArtifactAgent(agentConfig)) {
1493
- const viewMode = state ? selectViewMode(state) : "categories";
1494
- if (viewMode === "all") {
1495
- enhancedTools.delete("search_workspace");
1496
- if (!recommendedSkillHints.includes("search-all-spaces")) {
1497
- recommendedSkillHints.push("search-all-spaces");
1498
- }
1499
- } else {
1500
- enhancedTools.add("search_workspace");
1501
- }
1502
- }
1503
- const systemBuiltinSkills = state?.settings?.systemBuiltinSkills;
1504
- const mountedTools = isInlineVisualArtifactAgent(agentConfig) ? Array.from(enhancedTools) : addDefaultSystemCapabilityTools(Array.from(enhancedTools));
1505
- const filteredTools = applySystemBuiltinSkillFilter(
1506
- mountedTools,
1507
- systemBuiltinSkills
1508
- );
1509
- return {
1510
- ...agentConfig,
1511
- tools: applyDisabledTools(
1512
- prioritizeToolNames(
1513
- filteredTools,
1514
- recommendedSkillTools
1515
- ),
1516
- agentConfig?.disabledTools
1517
- ),
1518
- recommendedSkillTools,
1519
- recommendedSkillHints,
1520
- skillPromptPatches
1521
- };
1522
- };
1523
- var applyImageConfigRuntimeOverride = (agentConfig, runtimeOptions) => {
1524
- const override = runtimeOptions?.imageConfigOverride;
1525
- if (!override) {
1526
- return agentConfig;
1527
- }
1528
- const baseImageConfig = agentConfig.imageConfig ?? {};
1529
- return {
1530
- ...agentConfig,
1531
- ...override.imageModelOverride ? { model: override.imageModelOverride } : {},
1532
- imageConfig: {
1533
- ...baseImageConfig,
1534
- ...override
1535
- }
1536
- };
1537
- };
1538
- var formatImageWaitHint = (range) => {
1539
- if (!range || typeof range.min !== "number" || typeof range.max !== "number") {
1540
- return void 0;
1541
- }
1542
- return `\u901A\u5E38\u9700\u8981 ${range.min}-${range.max} \u79D2`;
1543
- };
1544
- var resolveAgentImageModelIdentity = (agentConfig) => {
1545
- let providerKey = (agentConfig.provider || "").toLowerCase();
1546
- let modelName = agentConfig.model ?? "";
1547
- if (modelName.includes("/")) {
1548
- const slash = modelName.indexOf("/");
1549
- if (!providerKey) providerKey = modelName.slice(0, slash);
1550
- modelName = modelName.slice(slash + 1);
1551
- }
1552
- try {
1553
- return {
1554
- providerKey,
1555
- modelConfig: getModelConfig(providerKey, modelName)
1556
- };
1557
- } catch {
1558
- try {
1559
- const detected = getProviderByModelName(modelName);
1560
- if (!detected) {
1561
- return { providerKey, modelConfig: null };
1562
- }
1563
- return {
1564
- providerKey: detected,
1565
- modelConfig: getModelConfig(detected, modelName)
1566
- };
1567
- } catch {
1568
- return { providerKey, modelConfig: null };
1569
- }
1570
- }
1571
- };
1572
- var EXPLICIT_IMAGE_GENERATION_TOOL_NAMES = /* @__PURE__ */ new Set([
1573
- "openAIGptImage",
1574
- "openAIGptImageGenerate",
1575
- "openAIGptImageEdit",
1576
- "chatgptWebImageGenerate",
1577
- "geminiFlashImage",
1578
- "geminiProImagePreview"
1579
- ]);
1580
- var agentUsesExplicitImageGenerationTool = (agentConfig) => {
1581
- const toolNames = Array.isArray(agentConfig.tools) ? agentConfig.tools : Array.isArray(agentConfig.toolNames) ? agentConfig.toolNames : [];
1582
- return toolNames.some(
1583
- (name) => typeof name === "string" && EXPLICIT_IMAGE_GENERATION_TOOL_NAMES.has(name.trim())
1584
- );
1585
- };
1586
- var resolveImageGenerationStreamingState = (agentConfig, args) => {
1587
- const { modelConfig } = resolveAgentImageModelIdentity(agentConfig);
1588
- const hasImageOutput = !!(modelConfig?.hasImageOutput ?? modelConfig?.supportsImageOutput) || agentConfig.imageConfig?.enabled === true || agentUsesExplicitImageGenerationTool(agentConfig);
1589
- if (!hasImageOutput) {
1590
- return void 0;
1591
- }
1592
- const currentProfile = modelConfig?.imageGenerationProfiles?.find(
1593
- (profile) => profile.imageModel === modelConfig.name
1594
- );
1595
- const usesWebImageTool = agentUsesExplicitImageGenerationTool(agentConfig) && (Array.isArray(agentConfig.tools) ? agentConfig.tools : []).includes("chatgptWebImageGenerate");
1596
- return {
1597
- kind: "image_generation",
1598
- stage: args?.stage ?? args?.previous?.stage ?? "submitted",
1599
- startedAt: args?.previous?.startedAt ?? Date.now(),
1600
- 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"),
1601
- profileLabel: currentProfile?.label
1602
- };
1603
- };
1604
-
1605
- // packages/ai/agent/imagePreprocessing.ts
1606
- var DEFAULT_IMAGE_PREPROCESSOR_AGENT_KEY = PUBLIC_QWEN_37_FLASH_AGENT_KEY;
1607
- var DESCRIBE_IMAGE_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u56FE\u7247\u63CF\u8FF0\u52A9\u624B\u3002\u8BF7\u6781\u5176\u8BE6\u7EC6\u5730\u63CF\u8FF0\u8FD9\u5F20\u56FE\u7247\uFF0C\u76EE\u6807\u662F\u8BA9\u4E00\u4E2A\u770B\u4E0D\u5230\u56FE\u7247\u7684 AI \u52A9\u624B\u80FD\u5B8C\u5168\u7406\u89E3\u56FE\u7247\u5185\u5BB9\u3002
1608
-
1609
- \u8BF7\u6309\u4EE5\u4E0B\u7ED3\u6784\u63CF\u8FF0\uFF1A
1610
-
1611
- 1. **\u56FE\u7247\u7C7B\u578B**\uFF1A\u8FD9\u662F\u754C\u9762\u622A\u56FE\u3001\u7167\u7247\u3001\u56FE\u8868\u3001\u6587\u6863\u3001\u8FD8\u662F\u5176\u4ED6\u7C7B\u578B\uFF1F
1612
-
1613
- 2. **\u5982\u679C\u662F\u754C\u9762\u622A\u56FE**\uFF1A
1614
- - \u5217\u51FA\u6240\u6709\u53EF\u89C1\u7684 UI \u5143\u7D20\uFF1A\u6807\u9898\u680F\u3001\u5BFC\u822A\u83DC\u5355\u3001\u6309\u94AE\u3001\u8F93\u5165\u6846\u3001\u5217\u8868\u9879\u7B49
1615
- - \u9010\u4E2A\u63CF\u8FF0\u6BCF\u4E2A\u5143\u7D20\u7684\u6587\u5B57\u5185\u5BB9\u548C\u4F4D\u7F6E\uFF08\u5982"\u5DE6\u4E0A\u89D2"\u3001"\u53F3\u4FA7\u680F"\uFF09
1616
- - \u63CF\u8FF0\u989C\u8272\u4E3B\u9898\u3001\u5E03\u5C40\u7ED3\u6784\u3001\u5F53\u524D\u72B6\u6001\uFF08\u5982\u9009\u4E2D\u3001hover\u3001loading\uFF09
1617
- - \u5982\u679C\u6709\u5F39\u7A97/\u5BF9\u8BDD\u6846/\u901A\u77E5\uFF0C\u5B8C\u6574\u8BB0\u5F55\u5176\u6587\u5B57\u5185\u5BB9
1618
-
1619
- 3. **\u5982\u679C\u662F\u751F\u6D3B\u7167\u7247**\uFF1A
1620
- - \u573A\u666F/\u73AF\u5883\uFF1A\u5BA4\u5185/\u5BA4\u5916\u3001\u5730\u70B9\u7C7B\u578B\u3001\u65F6\u95F4\u611F\uFF08\u767D\u5929/\u591C\u665A\uFF09
1621
- - \u4EBA\u7269\uFF1A\u4EBA\u6570\u3001\u59FF\u52BF\u3001\u8868\u60C5\u3001\u7A7F\u7740\u3001\u52A8\u4F5C
1622
- - \u7269\u4F53\uFF1A\u524D\u666F/\u80CC\u666F\u4E2D\u7684\u6240\u6709\u663E\u8457\u7269\u4F53
1623
- - \u5149\u7EBF\u3001\u5929\u6C14\u3001\u6C1B\u56F4
1624
-
1625
- 4. **\u5982\u679C\u662F\u56FE\u8868/\u6570\u636E\u56FE**\uFF1A
1626
- - \u56FE\u8868\u7C7B\u578B\uFF08\u67F1\u72B6\u56FE/\u6298\u7EBF\u56FE/\u997C\u56FE\u7B49\uFF09
1627
- - \u5750\u6807\u8F74\u6807\u7B7E\u3001\u6570\u503C\u8303\u56F4\u3001\u5355\u4F4D
1628
- - \u5173\u952E\u6570\u636E\u70B9\u548C\u8D8B\u52BF
1629
- - \u56FE\u4F8B\u3001\u6807\u9898
1630
-
1631
- 5. **\u6240\u6709\u53EF\u89C1\u6587\u5B57**\uFF1A\u9010\u5B57\u8BB0\u5F55\u56FE\u7247\u4E2D\u51FA\u73B0\u7684\u6240\u6709\u6587\u5B57\uFF08UI \u6587\u5B57\u3001\u8DEF\u724C\u3001\u6807\u7B7E\u3001\u6C34\u5370\u7B49\uFF09\uFF0C\u4FDD\u7559\u539F\u6587\u3002
1632
-
1633
- 6. **\u989C\u8272\u548C\u5E03\u5C40**\uFF1A\u4E3B\u8272\u8C03\u3001\u5E03\u5C40\u7ED3\u6784\u3001\u7A7A\u95F4\u5173\u7CFB\u3002
1634
-
1635
- \u8BF7\u5C3D\u53EF\u80FD\u8BE6\u7EC6\uFF0C\u4E0D\u8981\u9057\u6F0F\u4EFB\u4F55\u53EF\u89C1\u4FE1\u606F\u3002`;
1636
- function extractImageUrlsFromMessages(messages) {
1637
- const urls = [];
1638
- for (const msg of messages) {
1639
- if (!Array.isArray(msg.content)) continue;
1640
- for (const part of msg.content) {
1641
- if (part && typeof part === "object" && part.type === "image_url" && part.image_url && typeof part.image_url.url === "string" && part.image_url.url.trim()) {
1642
- urls.push(part.image_url.url);
1643
- }
1644
- }
1645
- }
1646
- return urls;
1647
- }
1648
- function hasImageInRuntimeMessages(messages) {
1649
- return extractImageUrlsFromMessages(messages).length > 0;
1650
- }
1651
- async function preprocessImagesForTextOnlyAgent(messages, describeImage) {
1652
- const imageUrls = extractImageUrlsFromMessages(messages);
1653
- if (imageUrls.length === 0) return messages;
1654
- const description = await describeImage(imageUrls);
1655
- if (description === null || !description.trim()) return messages;
1656
- const descriptionText = `[\u56FE\u7247\u63CF\u8FF0] ${description.trim()}`;
1657
- return messages.map((msg) => {
1658
- if (!Array.isArray(msg.content)) return msg;
1659
- const hasImage = msg.content.some((p) => p?.type === "image_url");
1660
- if (!hasImage) return msg;
1661
- const newContent = msg.content.map((part) => {
1662
- if (part && typeof part === "object" && part.type === "image_url") {
1663
- return { type: "text", text: descriptionText };
1664
- }
1665
- return part;
1666
- }).filter((p) => p !== null && p !== void 0);
1667
- return { ...msg, content: newContent };
1668
- });
1669
- }
1670
- async function describeImageWithLocalProvider(adapter, imageUrls, visionAgentConfig) {
1671
- if (imageUrls.length === 0) return null;
1672
- try {
1673
- const config = visionAgentConfig ?? resolveBuiltinPlatformAgentConfig(DEFAULT_IMAGE_PREPROCESSOR_AGENT_KEY);
1674
- if (!config) {
1675
- console.warn("[imagePreprocessing] vision agent config not found, skipping");
1676
- return null;
1677
- }
1678
- const visionProvider = await adapter.resolveProvider(config);
1679
- const result = await visionProvider.complete(
1680
- [{ role: "user", content: buildDescribeContentParts(imageUrls) }],
1681
- { timeoutMs: 3e4 }
1682
- );
1683
- const text = result.content?.trim();
1684
- if (!text) return null;
1685
- return text;
1686
- } catch (error) {
1687
- console.warn("[imagePreprocessing] vision describe failed, will fallback:", error);
1688
- return null;
1689
- }
1690
- }
1691
- async function describeImageViaServerProxy(serverUrl, authToken, imageUrls, visionAgentKey) {
1692
- if (imageUrls.length === 0) return null;
1693
- const agentKey = visionAgentKey ?? DEFAULT_IMAGE_PREPROCESSOR_AGENT_KEY;
1694
- const { model: visionModel, provider: visionProvider } = resolveDefaultVisionModelConfig(agentKey);
1695
- try {
1696
- const payload = {
1697
- model: visionModel,
1698
- messages: [{ role: "user", content: buildDescribeContentParts(imageUrls) }],
1699
- stream: false,
1700
- provider: visionProvider,
1701
- agentKey,
1702
- // server proxy 需要 url 字段,但 nolo 平台 agent 的上游由 server 端路由,
1703
- // 这里放一个占位 url,server 端会根据 provider/model 覆盖。
1704
- url: "https://api.ollama.com/v1/chat/completions"
1705
- };
1706
- const response = await fetch(`${serverUrl}/api/chat`, {
1707
- method: "POST",
1708
- headers: {
1709
- "Content-Type": "application/json",
1710
- Authorization: `Bearer ${authToken}`
1711
- },
1712
- body: JSON.stringify(payload),
1713
- signal: AbortSignal.timeout(3e4)
1714
- });
1715
- if (!response.ok) {
1716
- console.warn(`[imagePreprocessing] server proxy vision call failed: ${response.status}`);
1717
- return null;
1718
- }
1719
- const data = await response.json();
1720
- const text = data?.choices?.[0]?.message?.content;
1721
- if (typeof text === "string" && text.trim()) {
1722
- return text.trim();
1723
- }
1724
- return null;
1725
- } catch (error) {
1726
- console.warn("[imagePreprocessing] server proxy vision describe failed:", error);
1727
- return null;
1728
- }
1729
- }
1730
- function buildDescribeContentParts(imageUrls) {
1731
- const parts = [{ type: "text", text: DESCRIBE_IMAGE_PROMPT }];
1732
- for (const url of imageUrls) {
1733
- parts.push({ type: "image_url", image_url: { url } });
1734
- }
1735
- return parts;
1736
- }
1737
- function resolveDefaultVisionModelConfig(agentKey) {
1738
- const key = agentKey ?? DEFAULT_IMAGE_PREPROCESSOR_AGENT_KEY;
1739
- const config = resolveBuiltinPlatformAgentConfig(key);
1740
- return {
1741
- model: config?.model ?? PLATFORM_HOSTED_QWEN_37_FLASH_MODEL,
1742
- provider: config?.provider ?? "nolo",
1743
- config
1744
- };
1745
- }
1746
- async function tryPreprocessWebImageOrReject(messages, agentConfig, initialHistoryIds, serverUrl, authToken) {
1747
- const rejectReason = shouldRejectImageInputForAgent(
1748
- agentConfig,
1749
- messages
1750
- );
1751
- if (!rejectReason) {
1752
- const firstDynamicIdx = messages.findIndex((m) => m.id && !initialHistoryIds.has(m.id));
1753
- const splitIdx2 = firstDynamicIdx === -1 ? messages.length : firstDynamicIdx;
1754
- return {
1755
- kind: "ok",
1756
- messages,
1757
- stableMessages: messages.slice(0, splitIdx2),
1758
- dynamicMessages: messages.slice(splitIdx2)
1759
- };
1760
- }
1761
- if (!serverUrl || !authToken) {
1762
- return { kind: "reject", reason: rejectReason };
1763
- }
1764
- const preprocessed = await preprocessImagesForTextOnlyAgent(
1765
- messages,
1766
- (urls) => describeImageViaServerProxy(serverUrl, authToken, urls)
1767
- );
1768
- if (preprocessed === messages) {
1769
- return { kind: "reject", reason: rejectReason };
1770
- }
1771
- const newMessages = preprocessed;
1772
- const newFirstDynamicIdx = newMessages.findIndex((m) => m.id && !initialHistoryIds.has(m.id));
1773
- const splitIdx = newFirstDynamicIdx === -1 ? newMessages.length : newFirstDynamicIdx;
1774
- return {
1775
- kind: "ok",
1776
- messages: newMessages,
1777
- stableMessages: newMessages.slice(0, splitIdx),
1778
- dynamicMessages: newMessages.slice(splitIdx)
1779
- };
1780
- }
1781
-
1782
- // packages/agent-runtime/toolCallPairing.ts
1783
- function readToolCallId(message) {
1784
- if (typeof message.tool_call_id === "string" && message.tool_call_id) {
1785
- return message.tool_call_id;
1786
- }
1787
- if (typeof message.toolCallId === "string" && message.toolCallId) {
1788
- return message.toolCallId;
1789
- }
1790
- return void 0;
1791
- }
1792
- function isContentBlank(content) {
1793
- if (content == null) return true;
1794
- if (typeof content === "string") return content.trim().length === 0;
1795
- if (Array.isArray(content)) {
1796
- if (content.length === 0) return true;
1797
- return !content.some((part) => {
1798
- if (part == null || typeof part !== "object") return false;
1799
- const p = part;
1800
- if (p.type === "text") return typeof p.text === "string" && p.text.trim().length > 0;
1801
- if (p.type === "image_url") {
1802
- const url = p.image_url?.url;
1803
- return typeof url === "string" && url.trim().length > 0;
1804
- }
1805
- return true;
1806
- });
1807
- }
1808
- return false;
1809
- }
1810
- function sanitizeToolCallPairing(messages) {
1811
- const assistantIndexByCallId = /* @__PURE__ */ new Map();
1812
- for (let i = 0; i < messages.length; i += 1) {
1813
- const m = messages[i];
1814
- if (m == null) continue;
1815
- if (m.role !== "assistant") continue;
1816
- const toolCalls = m.tool_calls;
1817
- if (!Array.isArray(toolCalls)) continue;
1818
- for (const call of toolCalls) {
1819
- const id = call?.id;
1820
- if (typeof id !== "string" || !id) continue;
1821
- if (!assistantIndexByCallId.has(id)) {
1822
- assistantIndexByCallId.set(id, i);
1823
- }
1824
- }
1825
- }
1826
- const toolByCallId = /* @__PURE__ */ new Map();
1827
- for (let i = 0; i < messages.length; i += 1) {
1828
- const m = messages[i];
1829
- if (m == null) continue;
1830
- if (m.role !== "tool") continue;
1831
- const id = readToolCallId(m);
1832
- if (typeof id !== "string" || !id) continue;
1833
- if (!toolByCallId.has(id)) {
1834
- toolByCallId.set(id, m);
1835
- }
1836
- }
1837
- const output = [];
1838
- const consumedToolCallIds = /* @__PURE__ */ new Set();
1839
- for (let i = 0; i < messages.length; i += 1) {
1840
- const m = messages[i];
1841
- if (m == null) continue;
1842
- if (m.role === "tool") continue;
1843
- if (m.role !== "assistant") {
1844
- output.push(m);
1845
- continue;
1846
- }
1847
- const toolCalls = m.tool_calls;
1848
- if (!Array.isArray(toolCalls) || toolCalls.length === 0) {
1849
- output.push(m);
1850
- continue;
1851
- }
1852
- const matchedToolCalls = [];
1853
- const matchedToolMessages = [];
1854
- for (const call of toolCalls) {
1855
- const id = call?.id;
1856
- if (typeof id !== "string" || !id) continue;
1857
- const toolMessage = toolByCallId.get(id);
1858
- if (!toolMessage) continue;
1859
- if (assistantIndexByCallId.get(id) !== i) continue;
1860
- if (consumedToolCallIds.has(id)) continue;
1861
- matchedToolCalls.push(call);
1862
- matchedToolMessages.push(toolMessage);
1863
- consumedToolCallIds.add(id);
1864
- }
1865
- if (matchedToolCalls.length === 0) {
1866
- const { tool_calls: _drop, ...rest } = m;
1867
- const stripped = rest;
1868
- if (isContentBlank(stripped.content)) {
1869
- continue;
1870
- }
1871
- output.push(stripped);
1872
- continue;
1873
- }
1874
- const normalizedAssistant = { ...m, tool_calls: matchedToolCalls };
1875
- output.push(normalizedAssistant);
1876
- for (const toolMessage of matchedToolMessages) {
1877
- output.push(toolMessage);
1878
- }
1879
- }
1880
- return output;
1881
- }
1882
-
1883
- // packages/agent-runtime/parseToolArguments.ts
1884
- function parseToolArgumentsJson(raw) {
1885
- if (!raw?.trim()) return {};
1886
- try {
1887
- return asRecordOrEmpty(JSON.parse(raw));
1888
- } catch {
1889
- return {};
1890
- }
1891
- }
1892
-
1893
- // packages/agent-runtime/summarizeToolArguments.ts
1894
- function clip(value, max = 240) {
1895
- return clipCompactText(value, max);
1896
- }
1897
- function summarizeToolArguments(toolName, rawArgs) {
1898
- const args = parseToolArgumentsJson(rawArgs);
1899
- const pick = (...keys2) => {
1900
- for (const key of keys2) {
1901
- const value = asOptionalTrimmedString(args[key]);
1902
- if (value) return value;
1903
- }
1904
- return "";
1905
- };
1906
- const command = pick("command", "cmd", "runCommand", "executeCommand", "bash");
1907
- if (command) return clip(command);
1908
- const query = pick("query", "pattern", "search", "q");
1909
- if (query) return clip(query);
1910
- const filePath = pick("filePath", "file_path", "path", "filename", "file");
1911
- if (filePath) return clip(filePath);
1912
- const keys = Object.keys(args);
1913
- if (keys.length === 0) return "";
1914
- return clip(
1915
- keys.slice(0, 6).map((key) => {
1916
- const value = args[key];
1917
- if (typeof value === "string") return `${key}=${clip(value, 80)}`;
1918
- if (typeof value === "number" || typeof value === "boolean") {
1919
- return `${key}=${String(value)}`;
1920
- }
1921
- if (Array.isArray(value)) return `${key}[${value.length}]`;
1922
- return `${key}=${value === null ? "null" : typeof value}`;
1923
- }).join(" ")
1924
- );
1925
- }
1926
-
1927
- // packages/agent-runtime/contextBlockScope.ts
1928
- var isContextBlockScope = (value) => {
1929
- if (typeof value !== "object" || value === null) return false;
1930
- const candidate = value;
1931
- return typeof candidate.content === "string" && (candidate.cacheScope === "session" || candidate.cacheScope === "turn");
1932
- };
1933
- var normalizeContextBlockScopes = (legacyBlocks = void 0, scopes = void 0) => {
1934
- const trimmedScopes = (Array.isArray(scopes) ? scopes : []).filter(isContextBlockScope).map((scope) => ({ content: scope.content.trim(), cacheScope: scope.cacheScope })).filter((scope) => scope.content.length > 0);
1935
- if (trimmedScopes.length > 0) {
1936
- return trimmedScopes;
1937
- }
1938
- return (Array.isArray(legacyBlocks) ? legacyBlocks : []).filter((block) => typeof block === "string").map((block) => block.trim()).filter((block) => block.length > 0).map((block) => ({ content: block, cacheScope: "turn" }));
1939
- };
1940
-
1941
- // packages/agent-runtime/localAutoCompaction.ts
1942
- function toPlanCompressionMessages(history) {
1943
- return history.map((message, index) => ({
1944
- id: `local-${index}`,
1945
- role: message.role,
1946
- content: message.content,
1947
- ...Array.isArray(message.tool_calls) ? { tool_calls: message.tool_calls } : {}
1948
- }));
1949
- }
1950
- function buildLocalSummaryHistoryMessage(summary) {
1951
- const layer = buildDialogSummaryLayer({ summary });
1952
- return {
1953
- role: "user",
1954
- content: layer?.content ?? `--- \u5386\u53F2\u5BF9\u8BDD\u6458\u8981 ---
1955
- ${summary.trim()}`
1956
- };
1957
- }
1958
- function projectHistoryWithSummary(args) {
1959
- const bridged = toPlanCompressionMessages(args.history);
1960
- let startIndex = 0;
1961
- if (args.summarizedBeforeId) {
1962
- const found = bridged.findIndex((m) => m.id === args.summarizedBeforeId);
1963
- if (found !== -1) startIndex = found + 1;
1964
- }
1965
- return [
1966
- buildLocalSummaryHistoryMessage(args.summary),
1967
- ...args.history.slice(startIndex)
1968
- ];
1969
- }
1970
- var COLD_RESUME_IDLE_MS = 60 * 60 * 1e3;
1971
- function isColdResume(history, nowMs) {
1972
- for (let i = history.length - 1; i >= 0; i -= 1) {
1973
- const at = history[i]?.createdAt;
1974
- if (typeof at === "number" && Number.isFinite(at)) {
1975
- return nowMs - at > COLD_RESUME_IDLE_MS;
1976
- }
1977
- }
1978
- return false;
1979
- }
1980
- async function maybeAutoCompactLocalHistory(args) {
1981
- const { adapter, dialogId, history } = args;
1982
- const unchanged = () => ({
1983
- history,
1984
- compressed: false,
1985
- summaryGenerated: false
1986
- });
1987
- if (!dialogId || history.length === 0 || typeof adapter.loadDialogSummary !== "function" || typeof adapter.saveDialogSummary !== "function") {
1988
- return unchanged();
1989
- }
1990
- let stored = null;
1991
- try {
1992
- stored = await adapter.loadDialogSummary(dialogId);
1993
- } catch (error) {
1994
- console.warn("[localLoop] loadDialogSummary failed:", error);
1995
- return unchanged();
1996
- }
1997
- const existingSummary = typeof stored?.summary === "string" ? stored.summary : "";
1998
- const summarizedBeforeId = typeof stored?.summarizedBeforeId === "string" ? stored.summarizedBeforeId : void 0;
1999
- const contextWindow = typeof args.contextWindow === "number" && Number.isFinite(args.contextWindow) && args.contextWindow > 0 ? args.contextWindow : getModelContextWindow(args.model ?? "");
2000
- const allMsgs = toPlanCompressionMessages(history);
2001
- const coldResume = isColdResume(history, args.now?.() ?? Date.now());
2002
- const plan = planCompression({
2003
- allMsgs,
2004
- summarizedBeforeId,
2005
- summary: existingSummary,
2006
- contextWindow,
2007
- // 防死亡螺旋:用 summary 长度作为上次压缩后的基线。如果新内容没让
2008
- // totalUsed 比 summary 本身增长超过 minNewTokens,不重复触发。
2009
- lastCompactedTokenCount: existingSummary ? estimateTokenCount(existingSummary) : void 0,
2010
- ...coldResume ? { force: true, reason: "context_budget" } : {}
2011
- });
2012
- const projectExisting = () => {
2013
- if (!existingSummary.trim()) return unchanged();
2014
- return {
2015
- history: projectHistoryWithSummary({
2016
- history,
2017
- summary: existingSummary,
2018
- summarizedBeforeId
2019
- }),
2020
- compressed: true,
2021
- summaryGenerated: false
2022
- };
2023
- };
2024
- if (!plan.shouldCompress) {
2025
- return projectExisting();
2026
- }
2027
- try {
2028
- const provider = await args.resolveProvider();
2029
- const msgsToCompress = plan.msgsToCompress;
2030
- const messagesText = formatMessagesForSummaryWithTruncation(msgsToCompress);
2031
- const fileOpsText = formatFileOperationsFromMessages(
2032
- msgsToCompress,
2033
- canonicalizeToolName
2034
- );
2035
- const promptContent = buildCompactionUserContent({
2036
- previousSummary: existingSummary,
2037
- messagesText,
2038
- fileOpsText
2039
- });
2040
- const result = await provider.complete([
2041
- { role: "system", content: COMPACTION_SUMMARY_SYSTEM_PROMPT },
2042
- { role: "user", content: promptContent }
2043
- ]);
2044
- const newSummary = typeof result.content === "string" ? result.content.trim() : "";
2045
- if (!newSummary) {
2046
- console.warn(
2047
- "[localLoop] auto-compaction produced empty summary; keeping prior projection"
2048
- );
2049
- return projectExisting();
2050
- }
2051
- await adapter.saveDialogSummary({
2052
- dialogId,
2053
- summary: newSummary,
2054
- summarizedBeforeId: plan.newSummarizedBeforeId
2055
- });
2056
- const metrics = buildCompactionMetricsFromPlan({
2057
- reason: coldResume ? "cold_resume" : "context_budget",
2058
- previousSummary: existingSummary,
2059
- plan,
2060
- newSummary,
2061
- summaryUsage: result.usage
2062
- });
2063
- console.log(formatCompactionMetricsLog(metrics));
2064
- return {
2065
- history: projectHistoryWithSummary({
2066
- history,
2067
- summary: newSummary,
2068
- summarizedBeforeId: plan.newSummarizedBeforeId
2069
- }),
2070
- compressed: true,
2071
- summaryGenerated: true,
2072
- ...result.usage ? { usage: result.usage } : {},
2073
- metrics
2074
- };
2075
- } catch (error) {
2076
- console.warn("[localLoop] auto-compaction failed:", error);
2077
- return projectExisting();
2078
- }
2079
- }
2080
-
2081
- // packages/agent-runtime/localLoop.ts
2082
- var LOCAL_AGENT_CONFIG_MISSING_CODE = "LOCAL_AGENT_CONFIG_MISSING";
2083
- 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";
2084
- 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";
2085
- 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";
2086
- 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";
2087
- function resolveEmptyAssistantOutcome(args) {
2088
- if (args.hasToolCalls || args.hasVisibleOutput) return { kind: "ok" };
2089
- if (args.finishReason === "length") return { kind: "fallback", reason: "length_truncated" };
2090
- if (!args.repairUsed) return { kind: "repair" };
2091
- if (!args.finishReason && !args.streamComplete) {
2092
- return { kind: "fallback", reason: "stream_truncated" };
2093
- }
2094
- return { kind: "fallback", reason: "empty_completion" };
2095
- }
2096
- function resolveEmptyAssistantFallbackMessage(reason) {
2097
- if (reason === "length_truncated") return LENGTH_TRUNCATED_FALLBACK_MESSAGE;
2098
- if (reason === "stream_truncated") return STREAM_TRUNCATED_FALLBACK_MESSAGE;
2099
- return EMPTY_ASSISTANT_FALLBACK_MESSAGE;
2100
- }
2101
- function hasAssistantVisibleOutput(content) {
2102
- if (typeof content === "string") return content.trim().length > 0;
2103
- if (!Array.isArray(content)) return false;
2104
- return content.some((part) => {
2105
- if (part?.type === "text" && String(part.text ?? "").trim()) return true;
2106
- if (part?.type === "image_url") {
2107
- const url = part?.image_url?.url;
2108
- return typeof url === "string" && url.trim().length > 0;
2109
- }
2110
- return false;
2111
- });
2112
- }
2113
- function formatToolExecutionError(args) {
2114
- const message = toErrorMessage(args.error);
2115
- return `${args.toolName} failed: ${message}`;
2116
- }
2117
- function formatStructuredToolExecutionError(args) {
2118
- if (!args.error || typeof args.error !== "object") return null;
2119
- const error = args.error;
2120
- if (typeof error.code !== "string") return null;
2121
- return JSON.stringify({
2122
- error: error.code,
2123
- message: typeof error.message === "string" ? error.message : formatToolExecutionError(args),
2124
- ...error.policy && typeof error.policy === "object" ? { policy: error.policy } : {},
2125
- ...error.permissionRequest && typeof error.permissionRequest === "object" ? { permissionRequest: error.permissionRequest } : {}
2126
- });
2127
- }
2128
- function shouldReturnToolExecutionErrors(adapter) {
2129
- return adapter.capabilities.includes("local-tools");
2130
- }
2131
- function emitToolEvent(input, event) {
2132
- input.onToolEvent?.(event);
2133
- }
2134
- function emitLoopEvent(input, event) {
2135
- if (!input.onLoopEvent) return;
2136
- try {
2137
- input.onLoopEvent(event);
2138
- } catch {
2139
- }
2140
- }
2141
- var LLM_REQUEST_TIMEOUT = "LLM_REQUEST_TIMEOUT";
2142
- var LOCAL_TURN_ABORTED_CODE = "LOCAL_TURN_ABORTED";
2143
- function buildAbortedError() {
2144
- const error = new Error("local agent turn aborted by user");
2145
- error.code = LOCAL_TURN_ABORTED_CODE;
2146
- return error;
2147
- }
2148
- function throwIfAborted(input) {
2149
- if (input.abortSignal?.aborted) throw buildAbortedError();
2150
- }
2151
- async function raceWithAbort(input, promise, pendingToolName) {
2152
- const signal = input.abortSignal;
2153
- if (!signal) return promise;
2154
- let abortListener;
2155
- const abortPromise = new Promise((_resolve, reject) => {
2156
- abortListener = () => {
2157
- const error = buildAbortedError();
2158
- if (pendingToolName) error.pendingToolName = pendingToolName;
2159
- promise.catch(() => {
2160
- });
2161
- reject(error);
2162
- };
2163
- if (signal.aborted) {
2164
- abortListener();
2165
- return;
2166
- }
2167
- signal.addEventListener("abort", abortListener, { once: true });
2168
- });
2169
- try {
2170
- return await Promise.race([promise, abortPromise]);
2171
- } finally {
2172
- if (signal && abortListener) signal.removeEventListener("abort", abortListener);
2173
- }
2174
- }
2175
- function resolveLlmRequestTimeoutMs(input) {
2176
- const raw = input.llmRequestTimeoutMs ?? input.timeoutMs;
2177
- if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) return void 0;
2178
- return raw;
2179
- }
2180
- async function runCompleteWithTimeout(args) {
2181
- const { provider, messages, options, timeoutMs, round, input, context } = args;
2182
- emitLoopEvent(input, {
2183
- kind: "llm-start",
2184
- round,
2185
- atMs: Date.now(),
2186
- ...context ? { context } : {}
2187
- });
2188
- const complete = provider.complete(messages, options);
2189
- let ok = false;
2190
- const signal = input.abortSignal;
2191
- let abortListener;
2192
- const racers = [];
2193
- if (signal) {
2194
- racers.push(
2195
- new Promise((_resolve, reject) => {
2196
- abortListener = () => reject(buildAbortedError());
2197
- if (signal.aborted) {
2198
- abortListener();
2199
- return;
2200
- }
2201
- signal.addEventListener("abort", abortListener, { once: true });
2202
- })
2203
- );
2204
- }
2205
- let timer;
2206
- if (typeof timeoutMs === "number") {
2207
- racers.push(
2208
- new Promise((_resolve, reject) => {
2209
- timer = setTimeout(() => {
2210
- reject(new Error(`__llm_timeout__:${timeoutMs}`));
2211
- }, timeoutMs);
2212
- })
2213
- );
2214
- }
2215
- let result;
2216
- try {
2217
- result = racers.length === 0 ? await complete : await Promise.race([complete, ...racers]);
2218
- ok = true;
2219
- return result;
2220
- } catch (error) {
2221
- const isTimeout = error instanceof Error && error.message.startsWith("__llm_timeout__:");
2222
- if (!isTimeout) throw error;
2223
- const timeoutError = new Error(
2224
- `LLM request timed out after ${timeoutMs}ms (round ${round})`
2225
- );
2226
- timeoutError.code = LLM_REQUEST_TIMEOUT;
2227
- throw timeoutError;
2228
- } finally {
2229
- if (timer) clearTimeout(timer);
2230
- if (signal && abortListener) signal.removeEventListener("abort", abortListener);
2231
- const usage = result?.usage;
2232
- const cacheHit = Number(usage?.cache_read_input_tokens ?? usage?.prompt_cache_hit_tokens ?? 0);
2233
- const cacheMiss = Number(usage?.cache_creation_input_tokens ?? usage?.prompt_cache_miss_tokens ?? 0);
2234
- const inputTokens = Number(usage?.input_tokens ?? usage?.prompt_tokens ?? 0);
2235
- const outputTokens = Number(usage?.output_tokens ?? usage?.completion_tokens ?? 0);
2236
- emitLoopEvent(input, {
2237
- kind: "llm-end",
2238
- round,
2239
- atMs: Date.now(),
2240
- ok,
2241
- ...inputTokens > 0 || cacheHit > 0 || cacheMiss > 0 ? {
2242
- cache: {
2243
- inputTokens,
2244
- outputTokens,
2245
- cacheHitTokens: cacheHit,
2246
- cacheMissTokens: cacheMiss,
2247
- hitRatio: inputTokens > 0 ? Math.round(cacheHit / inputTokens * 1e4) / 1e4 : 0
2248
- }
2249
- } : {}
2250
- });
2251
- }
2252
- }
2253
- function clip2(value, max = 240) {
2254
- return clipCompactText(value, max);
2255
- }
2256
- function summarizeToolResult(content, metadata) {
2257
- const parts = [];
2258
- const exitCode = metadata?.exitCode;
2259
- if (typeof exitCode === "number") parts.push(`exit=${exitCode}`);
2260
- if (typeof content === "string") {
2261
- const trimmed = content.trim();
2262
- if (trimmed) {
2263
- const lines = trimmed.split(/\r?\n/).length;
2264
- parts.push(`${lines} line${lines === 1 ? "" : "s"}`);
2265
- parts.push(`${trimmed.length} chars`);
2266
- const tail = clip2(trimmed.slice(-160), 160);
2267
- if (tail) parts.push(`tail="${tail}"`);
2268
- } else {
2269
- parts.push("empty");
2270
- }
2271
- }
2272
- return parts.join(" ");
2273
- }
2274
- function formatToolMessageContent(args) {
2275
- if (args.toolName !== "listFiles" && args.toolName !== "globFiles" && args.toolName !== "searchFiles" && args.toolName !== "readFile" || !args.metadata || Object.keys(args.metadata).length === 0) {
2276
- return args.content;
2277
- }
2278
- return `${args.content}
2279
-
2280
- [tool metadata]
2281
- ${JSON.stringify(args.metadata)}`;
2282
- }
2283
- function blocksToOpenAiMessages(blocks) {
2284
- const out = [];
2285
- let text = "";
2286
- let reasoning = "";
2287
- let pendingToolCalls = [];
2288
- let pendingToolResults = [];
2289
- const flushSegment = () => {
2290
- if (text === "" && pendingToolCalls.length === 0 && reasoning === "") return;
2291
- out.push({
2292
- role: "assistant",
2293
- content: text || null,
2294
- ...reasoning ? { reasoning_content: reasoning } : {},
2295
- ...pendingToolCalls.length > 0 ? { tool_calls: pendingToolCalls } : {}
2296
- });
2297
- for (let i = 0; i < pendingToolCalls.length; i += 1) {
2298
- const tc = pendingToolCalls[i];
2299
- const res = pendingToolResults[i];
2300
- out.push({
2301
- role: "tool",
2302
- content: formatToolMessageContent({
2303
- toolName: tc.function.name,
2304
- content: res?.content ?? "",
2305
- ...res?.metadata ? { metadata: res.metadata } : {}
2306
- }),
2307
- tool_call_id: tc.id,
2308
- toolName: tc.function.name,
2309
- ...res?.metadata ? { tool_result_metadata: res.metadata } : {}
2310
- });
2311
- }
2312
- text = "";
2313
- reasoning = "";
2314
- pendingToolCalls = [];
2315
- pendingToolResults = [];
2316
- };
2317
- for (const block of blocks) {
2318
- if (block.type === "text") {
2319
- if (pendingToolCalls.length > 0) {
2320
- flushSegment();
2321
- }
2322
- text += block.text;
2323
- continue;
2324
- }
2325
- if (block.type === "thinking") {
2326
- reasoning += block.thinking;
2327
- continue;
2328
- }
2329
- if (block.type === "toolCall") {
2330
- pendingToolCalls.push(block.toolCall);
2331
- pendingToolResults.push({
2332
- content: block.result?.content ?? "",
2333
- ...block.result?.metadata ? { metadata: block.result.metadata } : {}
2334
- });
2335
- }
2336
- }
2337
- flushSegment();
2338
- return out;
2339
- }
2340
- function buildActionGate(args) {
2341
- const gate = readActionGate(args.metadata?.actionGate);
2342
- if (!gate) return null;
2343
- if (gate.kind === "handoff" && !readCommandActionGatePayload(gate.payload)) return null;
2344
- return {
2345
- ...gate,
2346
- toolName: args.toolName,
2347
- toolCallId: args.toolCallId
2348
- };
2349
- }
2350
- var TOOL_METADATA_KEYS = [
2351
- "path",
2352
- "query",
2353
- "effectivePattern",
2354
- "startLine",
2355
- "endLine",
2356
- "totalLines",
2357
- "totalBytes",
2358
- "bytes",
2359
- "totalChars",
2360
- "count",
2361
- "matchCount",
2362
- "matchedFiles",
2363
- "truncated",
2364
- "limitedByMaxResults",
2365
- "limitedByMaxDepth",
2366
- "visitedEntries",
2367
- "maxResults",
2368
- "exitCode",
2369
- "status",
2370
- "timedOut",
2371
- "aborted",
2372
- "replacements",
2373
- "code",
2374
- "error",
2375
- "message",
2376
- "warnings",
2377
- "pasteId",
2378
- "source"
2379
- ];
2380
- function trimHistoryToContextBudget(history, model) {
2381
- if (history.length === 0) return { history, droppedCount: 0 };
2382
- const { rawMessageBudget } = planContextUsage({
2383
- contextWindow: getModelContextWindow(model ?? ""),
2384
- summaryTokens: 0,
2385
- // localLoop 没有 web 端的负载分档器;medium 是中性默认值,
2386
- // 不为了省几个 token 在这里复制一份分类逻辑。
2387
- recentLoad: "medium"
2388
- });
2389
- const messageTokens = (message) => {
2390
- const toolCalls = message.tool_calls;
2391
- return estimateTokenCount(contentAsText(message.content)) + (Array.isArray(toolCalls) ? estimateTokenCount(JSON.stringify(toolCalls)) : 0);
2392
- };
2393
- let used = 0;
2394
- let start = history.length;
2395
- for (let i = history.length - 1; i >= 0; i -= 1) {
2396
- const cost = messageTokens(history[i]);
2397
- if (used + cost > rawMessageBudget && start < history.length) break;
2398
- used += cost;
2399
- start = i;
2400
- }
2401
- if (start === 0) return { history, droppedCount: 0 };
2402
- return {
2403
- history: sanitizeToolCallPairing(history.slice(start)),
2404
- droppedCount: start
2405
- };
2406
- }
2407
- function contentAsText(content) {
2408
- if (typeof content === "string") return content;
2409
- if (!Array.isArray(content)) return "";
2410
- return content.map((part) => {
2411
- if (part?.type === "text") return part.text;
2412
- if (part?.type === "image_url") return part.image_url.url;
2413
- return "";
2414
- }).join("\n");
2415
- }
2416
- function contentCharCount(content) {
2417
- if (typeof content === "string") return content.length;
2418
- if (!Array.isArray(content)) return 0;
2419
- return content.reduce((total, part) => {
2420
- if (part?.type === "text") return total + part.text.length;
2421
- if (part?.type === "image_url") return total + part.image_url.url.length;
2422
- return total;
2423
- }, 0);
2424
- }
2425
- function compactToolMetadata(metadata) {
2426
- if (!metadata) return "";
2427
- const selected = {};
2428
- for (const key of TOOL_METADATA_KEYS) {
2429
- const value = metadata[key];
2430
- if (value === void 0) continue;
2431
- if (typeof value === "string") {
2432
- selected[key] = clipCompactText(value, 240);
2433
- continue;
2434
- }
2435
- if (Array.isArray(value)) {
2436
- selected[key] = value.slice(0, 20).map(
2437
- (item) => typeof item === "string" ? clipCompactText(item, 180) : clipCompactText(JSON.stringify(item), 180)
2438
- );
2439
- continue;
2440
- }
2441
- selected[key] = value;
2442
- }
2443
- return Object.keys(selected).length > 0 ? clipCompactText(JSON.stringify(selected), 1200) : "";
2444
- }
2445
- function projectToolContentForProvider(args) {
2446
- const content = args.content;
2447
- if (typeof content !== "string") return content;
2448
- const metadataText = compactToolMetadata(args.metadata);
2449
- const embeddedMetadataIndex = metadataText ? content.indexOf("\n\n[tool metadata]\n") : -1;
2450
- const contentForProjection = embeddedMetadataIndex >= 0 ? content.slice(0, embeddedMetadataIndex) : content;
2451
- const metadataSuffix = metadataText ? `
2452
-
2453
- [tool metadata]
2454
- ${metadataText}` : "";
2455
- if (embeddedMetadataIndex >= 0 && content.length <= args.maxChars) {
2456
- return content;
2457
- }
2458
- const headRatio = resolveToolOutputProfile(args.toolName).headRatio;
2459
- const diagnostic = (clippedLength) => `[${args.label}; originalChars=${content.length}; omittedChars=${Math.max(
2460
- 0,
2461
- content.length - clippedLength
2462
- )}]`;
2463
- const suffix = (clippedLength) => [diagnostic(clippedLength), metadataSuffix.trimStart()].filter(Boolean).join("\n\n");
2464
- const initialBudget = Math.max(
2465
- 1,
2466
- args.maxChars - suffix(contentForProjection.length).length - 2
2467
- );
2468
- let clipped = clipToolText(contentForProjection, initialBudget, headRatio);
2469
- const wasClipped = clipped.length < contentForProjection.trim().length;
2470
- const needsProjection = wasClipped || Boolean(metadataSuffix) || embeddedMetadataIndex >= 0;
2471
- if (!needsProjection) return args.content;
2472
- let projected = wasClipped || metadataSuffix ? `${clipped}
2473
-
2474
- ${suffix(clipped.length)}` : clipped;
2475
- if (projected.length > args.maxChars) {
2476
- const boundedBudget = Math.max(
2477
- 1,
2478
- args.maxChars - suffix(clipped.length).length - 2
2479
- );
2480
- clipped = clipToolText(contentForProjection, boundedBudget, headRatio);
2481
- projected = `${clipped}
2482
-
2483
- ${suffix(clipped.length)}`;
2484
- }
2485
- return projected.length <= args.maxChars ? projected : projected.slice(0, args.maxChars);
2486
- }
2487
- function summarizeHistoricalToolContent(content, toolName, metadata) {
2488
- return projectToolContentForProvider({
2489
- content,
2490
- toolName,
2491
- metadata,
2492
- // Same single source of truth as the server path and the read ledgers:
2493
- // read-family tools keep their profile historical cap (4800) cross-turn,
2494
- // unprofiled tools fall back to the flat historical budget.
2495
- maxChars: resolveHistoricalToolContentCap(toolName, MAX_HISTORICAL_TOOL_CONTENT_CHARS),
2496
- label: "historical tool result truncated for the next turn"
2497
- });
2498
- }
2499
- function prepareMessagesForProviderCall(messages) {
2500
- const paired = sanitizeToolCallPairing(messages);
2501
- let freshRunStart = paired.length;
2502
- while (freshRunStart > 0 && paired[freshRunStart - 1].role === "tool") {
2503
- freshRunStart -= 1;
2504
- }
2505
- let toolMessageCount = 0;
2506
- let rawToolContentChars = 0;
2507
- let projectedToolContentChars = 0;
2508
- let truncatedToolResults = 0;
2509
- const projected = paired.map((message, index) => {
2510
- const { context_reference: _contextReference, ...providerMessage } = message;
2511
- const sanitizedContent = providerMessage.content == null ? "" : typeof providerMessage.content === "string" ? providerMessage.content : providerMessage.content;
2512
- if (providerMessage.role !== "tool") {
2513
- return {
2514
- ...providerMessage,
2515
- content: sanitizedContent
2516
- };
2517
- }
2518
- toolMessageCount += 1;
2519
- rawToolContentChars += contentCharCount(sanitizedContent);
2520
- const isFresh = index >= freshRunStart;
2521
- const maxChars = isFresh ? FRESH_TOOL_OUTPUT_MAX_CHARS : resolveToolOutputProfile(providerMessage.toolName).maxChars;
2522
- const projectedContent = projectToolContentForProvider({
2523
- content: sanitizedContent,
2524
- toolName: providerMessage.toolName,
2525
- metadata: providerMessage.tool_result_metadata,
2526
- maxChars,
2527
- label: "in-turn tool result truncated/projected before next provider call"
2528
- });
2529
- projectedToolContentChars += contentCharCount(projectedContent);
2530
- if (contentCharCount(projectedContent) < contentCharCount(sanitizedContent)) {
2531
- truncatedToolResults += 1;
2532
- }
2533
- return {
2534
- ...providerMessage,
2535
- content: projectedContent
2536
- };
2537
- });
2538
- return {
2539
- messages: projected,
2540
- metrics: {
2541
- messageCount: projected.length,
2542
- contentChars: projected.reduce((total, message) => total + contentCharCount(message.content), 0),
2543
- toolMessageCount,
2544
- rawToolContentChars,
2545
- projectedToolContentChars,
2546
- truncatedToolResults,
2547
- stableContextChars: 0,
2548
- dynamicContextChars: 0
2549
- }
2550
- };
2551
- }
2552
- function prepareHistoryForNextTurn(history, contextReferenceResolver) {
2553
- return history.map((message) => {
2554
- if (message.role === "user" && message.context_reference !== void 0 && contextReferenceResolver?.(message.context_reference)) {
2555
- return { ...message, content: message.context_reference };
2556
- }
2557
- if (message.role !== "tool") return message;
2558
- return {
2559
- ...message,
2560
- content: summarizeHistoricalToolContent(
2561
- message.content,
2562
- message.toolName,
2563
- message.tool_result_metadata
2564
- )
2565
- };
2566
- });
2567
- }
2568
- var IMAGE_OMITTED_PLACEHOLDER = "[Image content omitted: model does not support image input]";
2569
- function stripImagePartsFromContent(content) {
2570
- if (!Array.isArray(content)) return content;
2571
- const filtered = content.filter((part) => part?.type !== "image_url");
2572
- if (filtered.length === 0) return IMAGE_OMITTED_PLACEHOLDER;
2573
- return filtered;
2574
- }
2575
- function filterImagePartsFromMessages(messages, supportsImages) {
2576
- if (supportsImages) return messages;
2577
- return messages.map((msg) => ({
2578
- ...msg,
2579
- content: stripImagePartsFromContent(msg.content)
2580
- }));
2581
- }
2582
- function buildMessages(args) {
2583
- if (args.contextBlockScopes?.length) {
2584
- const blocks2 = args.contextBlockScopes.filter((b) => b.content.trim());
2585
- const stableParts = [args.prompt?.trim(), ...blocks2.filter((b) => b.cacheScope === "session").map((b) => b.content)].filter(Boolean);
2586
- const dynamicParts = blocks2.filter((b) => b.cacheScope === "turn").map((b) => b.content).map((block) => block.trim()).filter(Boolean);
2587
- const stableContent = stableParts.join("\n\n");
2588
- const dynamicContent = dynamicParts.join("\n\n");
2589
- const systemContent2 = dynamicContent ? `${stableContent}
2590
-
2591
- ${dynamicContent}` : stableContent;
2592
- return {
2593
- messages: [
2594
- ...systemContent2 ? [{
2595
- role: "system",
2596
- content: systemContent2,
2597
- ...stableContent ? { stable_prefix_chars: stableContent.length } : {}
2598
- }] : [],
2599
- ...prepareHistoryForNextTurn(args.history, args.contextReferenceResolver),
2600
- { role: "user", content: args.input }
2601
- ],
2602
- stableContextChars: stableContent.length,
2603
- dynamicContextChars: dynamicContent.length
2604
- };
2605
- }
2606
- const blocks = (args.contextBlocks ?? []).map((block) => block.trim()).filter(Boolean);
2607
- const systemContent = [args.prompt?.trim(), ...blocks].filter(Boolean).join("\n\n");
2608
- return {
2609
- messages: [
2610
- ...systemContent ? [{ role: "system", content: systemContent }] : [],
2611
- ...prepareHistoryForNextTurn(args.history, args.contextReferenceResolver),
2612
- { role: "user", content: args.input }
2613
- ],
2614
- stableContextChars: (args.prompt?.trim() ?? "").length,
2615
- dynamicContextChars: blocks.join("\n\n").length
2616
- };
2617
- }
2618
- function mergeTurnUsage(current, next) {
2619
- if (!next) return current;
2620
- const read2 = (usage) => ({
2621
- input: Number(usage.input_tokens ?? usage.prompt_tokens ?? 0),
2622
- output: Number(usage.output_tokens ?? usage.completion_tokens ?? 0),
2623
- cacheHit: Number(
2624
- usage.cache_read_input_tokens ?? usage.prompt_cache_hit_tokens ?? 0
2625
- ),
2626
- cacheMiss: Number(
2627
- usage.cache_creation_input_tokens ?? usage.prompt_cache_miss_tokens ?? 0
2628
- )
2629
- });
2630
- const right = read2(next);
2631
- const left = current ? read2(current) : { input: 0, output: 0, cacheHit: 0, cacheMiss: 0 };
2632
- return {
2633
- input_tokens: left.input + right.input,
2634
- output_tokens: left.output + right.output,
2635
- cache_read_input_tokens: left.cacheHit + right.cacheHit,
2636
- cache_creation_input_tokens: left.cacheMiss + right.cacheMiss
2637
- };
2638
- }
2639
- function addOutOfBandUsage(turn, extra) {
2640
- if (!extra) return turn;
2641
- const num = (u, ...keys) => {
2642
- if (!u) return 0;
2643
- for (const k of keys) {
2644
- const v = Number(u[k]);
2645
- if (Number.isFinite(v) && v !== 0) return v;
2646
- }
2647
- return 0;
2648
- };
2649
- return {
2650
- ...turn ?? {},
2651
- input_tokens: num(turn, "input_tokens", "prompt_tokens") + num(extra, "input_tokens", "prompt_tokens"),
2652
- output_tokens: num(turn, "output_tokens", "completion_tokens") + num(extra, "output_tokens", "completion_tokens"),
2653
- cache_read_input_tokens: num(turn, "cache_read_input_tokens", "prompt_cache_hit_tokens") + num(extra, "cache_read_input_tokens", "prompt_cache_hit_tokens"),
2654
- cache_creation_input_tokens: num(turn, "cache_creation_input_tokens", "prompt_cache_miss_tokens") + num(extra, "cache_creation_input_tokens", "prompt_cache_miss_tokens")
2655
- };
2656
- }
2657
- function extractUserInputText(content) {
2658
- if (typeof content === "string") return content;
2659
- if (!Array.isArray(content)) return "";
2660
- return content.flatMap((part) => part?.type === "text" && part.text ? [part.text] : []).join("\n").trim();
2661
- }
2662
- function attachDialogIdToError(error, dialogId) {
2663
- if (!dialogId) return;
2664
- if (typeof error === "object" && error !== null) {
2665
- error.dialogId = dialogId;
2666
- }
2667
- }
2668
- async function persistFailedLocalTurn(args) {
2669
- const errorMessage = toErrorMessage(args.error);
2670
- try {
2671
- const saved = await args.adapter.saveTurn({
2672
- agentKey: args.agentKey,
2673
- messages: args.messages,
2674
- result: {
2675
- content: args.partialContent || `[nolo] Agent run failed: ${errorMessage}`,
2676
- model: args.model ?? "unknown",
2677
- toolCallCount: args.toolCallCount ?? 0,
2678
- error: true,
2679
- errorMessage,
2680
- ...args.usage ? { usage: args.usage } : {}
2681
- },
2682
- ...args.accountingUsage ? { accountingUsage: args.accountingUsage } : {},
2683
- ...args.usageRecords?.length ? { usageRecords: args.usageRecords } : {},
2684
- ...args.billingConfig ? { billingConfig: args.billingConfig } : {},
2685
- ...args.input.runtimeContext ? { runtimeContext: args.input.runtimeContext } : {},
2686
- ...args.input.continueDialogId ? { continueDialogId: args.input.continueDialogId } : {},
2687
- ...args.input.spaceId ? { spaceId: args.input.spaceId } : {},
2688
- ...args.input.category ? { category: args.input.category } : {},
2689
- ...args.input.inheritedFromDialogKey ? { inheritedFromDialogKey: args.input.inheritedFromDialogKey } : {},
2690
- ...args.input.parentDialogId ? { parentDialogId: args.input.parentDialogId } : {}
2691
- });
2692
- return saved?.dialogId;
2693
- } catch {
2694
- return args.input.continueDialogId;
2695
- }
2696
- }
2697
- function applyPersistedTurnInput(messages, persistedInput, persistedInputReference) {
2698
- if (persistedInput === void 0 && persistedInputReference === void 0) {
2699
- return messages;
2700
- }
2701
- let replaced = false;
2702
- return messages.map((message) => {
2703
- if (replaced || message.role !== "user") return message;
2704
- replaced = true;
2705
- return {
2706
- ...message,
2707
- ...persistedInput !== void 0 ? { content: persistedInput } : {},
2708
- ...persistedInputReference !== void 0 ? { context_reference: persistedInputReference } : {}
2709
- };
2710
- });
2711
- }
2712
- async function runLocalAgentTurn(input) {
2713
- const agentConfig = await input.adapter.loadAgentConfig(input.agentRef);
2714
- if (!agentConfig) {
2715
- const error = new Error(
2716
- `agentRef "${input.agentRef}" \u672A\u5339\u914D\u5230\u672C\u5730 agent\u3002\u8FD9\u4E0D\u662F\u914D\u7F6E\u7F3A\u5931\uFF0C\u8BF7\u7528 listAgents \u67E5\u770B\u53EF\u7528 agent\uFF0C\u518D\u7528 readAgent \u89E3\u6790 agentKey\uFF0C\u52FF\u624B\u5DE5\u62FC key\u3002`
2717
- );
2718
- error.code = LOCAL_AGENT_CONFIG_MISSING_CODE;
2719
- error.agentRef = input.agentRef;
2720
- throw error;
2721
- }
2722
- const rawBillingConfig = agentConfig.rawRecord ?? {};
2723
- const billingConfig = {
2724
- model: agentConfig.model || "unknown",
2725
- ...agentConfig.provider ? { provider: agentConfig.provider } : {},
2726
- ...agentConfig.apiSource ? { apiSource: agentConfig.apiSource } : {},
2727
- ...agentConfig.apiKeyRef !== void 0 ? { apiKeyRef: agentConfig.apiKeyRef } : {},
2728
- ...typeof rawBillingConfig.inputPrice === "number" ? { inputPrice: rawBillingConfig.inputPrice } : {},
2729
- ...typeof rawBillingConfig.outputPrice === "number" ? { outputPrice: rawBillingConfig.outputPrice } : {},
2730
- ...rawBillingConfig.sharingLevel ? { sharingLevel: rawBillingConfig.sharingLevel } : {},
2731
- id: agentConfig.key,
2732
- ...typeof rawBillingConfig.userId === "string" ? { userId: rawBillingConfig.userId } : {}
2733
- };
2734
- let history = [];
2735
- try {
2736
- history = input.continueDialogId ? await input.adapter.loadDialogHistory(input.continueDialogId) : [];
2737
- } catch (error) {
2738
- const dialogId = await persistFailedLocalTurn({
2739
- adapter: input.adapter,
2740
- agentKey: agentConfig.key,
2741
- messages: [{ role: "user", content: input.input }],
2742
- error,
2743
- model: agentConfig.model,
2744
- input
2745
- });
2746
- attachDialogIdToError(error, dialogId);
2747
- throw error;
2748
- }
2749
- const identityBlock = buildIdentityBlock({
2750
- agentName: agentConfig.name,
2751
- agentId: agentConfig.key,
2752
- model: agentConfig.model
2753
- });
2754
- const agentTools = canonicalizeToolNames(
2755
- agentConfig.exposedToolNames ?? agentConfig.toolNames ?? []
2756
- );
2757
- const guidanceBlocks = buildRuntimeGuidanceBlocks(agentTools);
2758
- const toolGuidedSections = resolveToolGuidedSections(agentTools);
2759
- const guidanceScopes = [
2760
- guidanceBlocks.startupProtocol,
2761
- guidanceBlocks.contextLayerContract,
2762
- guidanceBlocks.emailRegistrationWorkflow,
2763
- guidanceBlocks.webResearchToolPolicy,
2764
- ...Object.values(toolGuidedSections)
2765
- ].map((content) => content.trim()).filter((content) => content.length > 0).map((content) => ({ content, cacheScope: "session" }));
2766
- const currentTimeScope = [
2767
- { content: buildCurrentTimeBlock(/* @__PURE__ */ new Date(), void 0), cacheScope: "turn" }
2768
- ];
2769
- const callerScopes = normalizeContextBlockScopes(
2770
- input.contextBlocks,
2771
- input.contextBlockScopes
2772
- );
2773
- const mergedContextBlockScopes = [
2774
- { content: identityBlock, cacheScope: "session" },
2775
- ...guidanceScopes,
2776
- ...currentTimeScope,
2777
- ...callerScopes
2778
- ];
2779
- let resolvedProvider;
2780
- const resolveProviderOnce = async () => {
2781
- if (!resolvedProvider) {
2782
- resolvedProvider = await input.adapter.resolveProvider(agentConfig);
2783
- }
2784
- return resolvedProvider;
2785
- };
2786
- let compactionUsage;
2787
- try {
2788
- const compacted = await maybeAutoCompactLocalHistory({
2789
- adapter: input.adapter,
2790
- dialogId: input.continueDialogId,
2791
- history,
2792
- model: agentConfig.model,
2793
- resolveProvider: resolveProviderOnce
2794
- });
2795
- history = compacted.history;
2796
- compactionUsage = compacted.usage;
2797
- } catch (error) {
2798
- console.warn("[localLoop] auto-compaction unexpected error:", error);
2799
- }
2800
- const trimmedHistory = trimHistoryToContextBudget(history, agentConfig.model);
2801
- if (trimmedHistory.droppedCount > 0) {
2802
- history = trimmedHistory.history;
2803
- }
2804
- const hasContextBlocks = callerScopes.some((block) => block.content.trim()) || mergedContextBlockScopes.some((block) => block.content.trim());
2805
- const promptMessageCount = agentConfig.prompt?.trim() || hasContextBlocks ? 1 : 0;
2806
- const turnStartIndex = promptMessageCount + history.length;
2807
- const builtMessages = buildMessages({
2808
- prompt: agentConfig.prompt,
2809
- contextBlockScopes: mergedContextBlockScopes,
2810
- history,
2811
- input: input.input,
2812
- contextReferenceResolver: input.adapter.host === "cli" ? input.contextReferenceResolver : void 0
2813
- });
2814
- let messages = builtMessages.messages;
2815
- const supportsImages = resolveAgentImageInputSupport({
2816
- apiSource: agentConfig.apiSource,
2817
- provider: agentConfig.provider,
2818
- model: agentConfig.model,
2819
- hasVision: agentConfig.hasVision
2820
- });
2821
- if (!supportsImages && hasImageInRuntimeMessages(messages)) {
2822
- const imageUrls = extractImageUrlsFromMessages(messages);
2823
- const preprocessed = await preprocessImagesForTextOnlyAgent(
2824
- messages,
2825
- (urls) => describeImageWithLocalProvider(input.adapter, urls)
2826
- );
2827
- if (preprocessed !== messages) {
2828
- messages = preprocessed;
2829
- emitLoopEvent(input, {
2830
- kind: "image-preprocessed",
2831
- atMs: Date.now(),
2832
- imageCount: imageUrls.length
2833
- });
2834
- } else {
2835
- messages = filterImagePartsFromMessages(messages, false);
2836
- emitLoopEvent(input, {
2837
- kind: "image-downgraded",
2838
- reason: "no-vision",
2839
- atMs: Date.now()
2840
- });
2841
- }
2842
- }
2843
- const userInputText = extractUserInputText(input.input);
2844
- let toolCallCount = 0;
2845
- let result;
2846
- let turnUsage;
2847
- let contextUsage;
2848
- const usageRecords = [];
2849
- let loopError;
2850
- let round = 0;
2851
- let emptyAssistantRepairPending = false;
2852
- let emptyAssistantRepairUsed = false;
2853
- let skipFinalAppend = false;
2854
- let partialContent = "";
2855
- try {
2856
- const provider = await resolveProviderOnce();
2857
- while (true) {
2858
- partialContent = "";
2859
- throwIfAborted(input);
2860
- const preparedMessages = prepareMessagesForProviderCall(messages);
2861
- const baseRequestMessages = filterImagePartsFromMessages(
2862
- preparedMessages.messages,
2863
- supportsImages
2864
- );
2865
- const requestMessages = emptyAssistantRepairPending ? [...baseRequestMessages, { role: "user", content: EMPTY_ASSISTANT_REPAIR_PROMPT }] : baseRequestMessages;
2866
- const contextMetrics = {
2867
- ...preparedMessages.metrics,
2868
- messageCount: requestMessages.length,
2869
- contentChars: requestMessages.reduce(
2870
- (total, message) => total + contentCharCount(message.content),
2871
- 0
2872
- ),
2873
- stableContextChars: builtMessages.stableContextChars,
2874
- dynamicContextChars: builtMessages.dynamicContextChars
2875
- };
2876
- emptyAssistantRepairPending = false;
2877
- result = await runCompleteWithTimeout({
2878
- provider,
2879
- messages: requestMessages,
2880
- options: {
2881
- ...typeof input.timeoutMs === "number" ? { timeoutMs: input.timeoutMs } : {},
2882
- ...input.onTextDelta ? { onTextDelta: (chunk) => {
2883
- partialContent += chunk;
2884
- input.onTextDelta(chunk);
2885
- } } : {},
2886
- ...input.onReasoningDelta ? { onReasoningDelta: input.onReasoningDelta } : {},
2887
- ...input.onToolEvent ? { onToolEvent: input.onToolEvent } : {},
2888
- ...input.onToolEvent ? { toolEventRound: round } : {}
2889
- },
2890
- timeoutMs: resolveLlmRequestTimeoutMs(input),
2891
- round,
2892
- input,
2893
- context: contextMetrics
2894
- });
2895
- turnUsage = mergeTurnUsage(turnUsage, result.usage);
2896
- contextUsage = result.usage;
2897
- if (result.usage && Object.keys(result.usage).length > 0) {
2898
- usageRecords.push({
2899
- callId: typeof result.usage.provider_call_id === "string" && result.usage.provider_call_id.trim() ? result.usage.provider_call_id.trim() : crypto.randomUUID(),
2900
- usage: result.usage,
2901
- model: result.model || agentConfig.model || "unknown",
2902
- ...result.provider || agentConfig.provider ? { provider: result.provider || agentConfig.provider } : {}
2903
- });
2904
- }
2905
- const toolCalls = result.tool_calls ?? [];
2906
- const rawToolCallsCount = (result.tool_calls?.length ?? 0) || (Array.isArray(result.raw_tool_calls) ? result.raw_tool_calls.length : 0);
2907
- if (toolCalls.length === 0 && rawToolCallsCount === 0) {
2908
- const outcome = resolveEmptyAssistantOutcome({
2909
- hasToolCalls: rawToolCallsCount > 0,
2910
- hasVisibleOutput: hasAssistantVisibleOutput(result.content),
2911
- repairUsed: emptyAssistantRepairUsed,
2912
- finishReason: result.finish_reason,
2913
- streamComplete: result.stream_complete
2914
- });
2915
- if (outcome.kind === "repair") {
2916
- emptyAssistantRepairPending = true;
2917
- emptyAssistantRepairUsed = true;
2918
- continue;
2919
- }
2920
- if (outcome.kind === "fallback") {
2921
- result = {
2922
- ...result,
2923
- content: resolveEmptyAssistantFallbackMessage(outcome.reason)
2924
- };
2925
- break;
2926
- }
2927
- break;
2928
- }
2929
- const outputBlocks = result.output ?? [];
2930
- if (outputBlocks.length > 0) {
2931
- let hasInlineExecutedTools = false;
2932
- for (const block of outputBlocks) {
2933
- if (block.type !== "toolCall") continue;
2934
- toolCallCount += 1;
2935
- const toolName = block.toolCall.function.name;
2936
- if (block.result) {
2937
- hasInlineExecutedTools = true;
2938
- } else {
2939
- throw new Error(
2940
- `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.`
2941
- );
2942
- }
2943
- }
2944
- if (hasInlineExecutedTools) {
2945
- messages.push(...blocksToOpenAiMessages(outputBlocks));
2946
- skipFinalAppend = true;
2947
- break;
2948
- }
2949
- round += 1;
2950
- continue;
2951
- }
2952
- toolCallCount += toolCalls.length;
2953
- messages.push({
2954
- role: "assistant",
2955
- content: result.content || null,
2956
- ...result.reasoning_content ? { reasoning_content: result.reasoning_content } : {},
2957
- tool_calls: toolCalls
2958
- });
2959
- for (const toolCall of toolCalls) {
2960
- throwIfAborted(input);
2961
- const toolName = toolCall.function.name;
2962
- let toolResult;
2963
- const startedAt = Date.now();
2964
- emitLoopEvent(input, { kind: "tool-start", name: toolName, atMs: Date.now() });
2965
- emitToolEvent(input, {
2966
- type: "tool-call",
2967
- round,
2968
- toolCallId: toolCall.id,
2969
- toolName,
2970
- argumentsPreview: summarizeToolArguments(toolName, toolCall.function.arguments)
2971
- });
2972
- try {
2973
- const executePromise = input.adapter.executeTool({
2974
- id: toolCall.id,
2975
- name: toolName,
2976
- arguments: toolCall.function.arguments,
2977
- ...userInputText ? { userInput: userInputText } : {},
2978
- ...input.runtimeContext ? { runtimeContext: input.runtimeContext } : {},
2979
- ...input.abortSignal ? { abortSignal: input.abortSignal } : {}
2980
- }, {
2981
- ...input.abortSignal ? { abortSignal: input.abortSignal } : {},
2982
- ...input.runtimeContext ? { runtimeContext: input.runtimeContext } : {}
2983
- });
2984
- toolResult = await raceWithAbort(input, executePromise, toolName);
2985
- const actionGate = buildActionGate({
2986
- toolName,
2987
- toolCallId: toolCall.id,
2988
- metadata: toolResult.metadata
2989
- });
2990
- if (actionGate && input.onActionGate) {
2991
- const replacement = await input.onActionGate(actionGate);
2992
- if (replacement) {
2993
- toolResult = replacement;
2994
- }
2995
- }
2996
- emitLoopEvent(input, { kind: "tool-end", name: toolName, atMs: Date.now(), ok: true });
2997
- emitToolEvent(input, {
2998
- type: "tool-result",
2999
- round,
3000
- toolCallId: toolCall.id,
3001
- toolName,
3002
- elapsedMs: Math.max(0, Date.now() - startedAt),
3003
- summary: summarizeToolResult(toolResult.content, toolResult.metadata),
3004
- ...typeof toolResult.content === "string" ? { content: toolResult.content } : {},
3005
- metadata: toolResult.metadata
3006
- });
3007
- } catch (error) {
3008
- emitLoopEvent(input, { kind: "tool-end", name: toolName, atMs: Date.now(), ok: false });
3009
- if (error && typeof error === "object" && error.code === LOCAL_TURN_ABORTED_CODE) {
3010
- throw error;
3011
- }
3012
- if (!shouldReturnToolExecutionErrors(input.adapter)) throw error;
3013
- emitToolEvent(input, {
3014
- type: "tool-error",
3015
- round,
3016
- toolCallId: toolCall.id,
3017
- toolName,
3018
- elapsedMs: Math.max(0, Date.now() - startedAt),
3019
- message: toErrorMessage(error)
3020
- });
3021
- toolResult = {
3022
- content: formatStructuredToolExecutionError({ toolName, error }) ?? formatToolExecutionError({ toolName, error }),
3023
- metadata: {
3024
- error: true,
3025
- toolName,
3026
- message: toErrorMessage(error),
3027
- ...error && typeof error === "object" && typeof error.code === "string" ? { code: error.code } : {}
3028
- }
3029
- };
3030
- }
3031
- messages.push({
3032
- role: "tool",
3033
- content: formatToolMessageContent({
3034
- toolName,
3035
- content: toolResult.content,
3036
- metadata: toolResult.metadata
3037
- }),
3038
- tool_call_id: toolCall.id,
3039
- toolName,
3040
- ...toolResult.metadata ? { tool_result_metadata: toolResult.metadata } : {}
3041
- });
3042
- }
3043
- round += 1;
3044
- }
3045
- } catch (error) {
3046
- loopError = error;
3047
- }
3048
- if (loopError) {
3049
- const turnMessages2 = applyPersistedTurnInput(
3050
- messages.slice(turnStartIndex),
3051
- input.persistedInput,
3052
- input.persistedInputReference
3053
- );
3054
- const dialogId = await persistFailedLocalTurn({
3055
- adapter: input.adapter,
3056
- agentKey: agentConfig.key,
3057
- messages: turnMessages2,
3058
- error: loopError,
3059
- model: agentConfig.model,
3060
- toolCallCount,
3061
- partialContent,
3062
- usage: contextUsage,
3063
- accountingUsage: addOutOfBandUsage(turnUsage, compactionUsage),
3064
- usageRecords: [
3065
- ...compactionUsage ? [{
3066
- callId: typeof compactionUsage.provider_call_id === "string" && compactionUsage.provider_call_id.trim() ? compactionUsage.provider_call_id.trim() : crypto.randomUUID(),
3067
- usage: compactionUsage,
3068
- model: agentConfig.model || "unknown",
3069
- ...agentConfig.provider ? { provider: agentConfig.provider } : {}
3070
- }] : [],
3071
- ...usageRecords
3072
- ],
3073
- billingConfig,
3074
- input
3075
- });
3076
- attachDialogIdToError(loopError, dialogId);
3077
- throw loopError;
3078
- }
3079
- result = result;
3080
- if (!skipFinalAppend) {
3081
- messages.push({
3082
- role: "assistant",
3083
- content: result.content,
3084
- // 与中间轮(:561)一致带上 reasoning_content,让 saveTurn 持久化思维链,
3085
- // 空轮/异常排查时能回看模型实际想了什么。
3086
- ...result.reasoning_content ? { reasoning_content: result.reasoning_content } : {}
3087
- });
3088
- }
3089
- const turnMessages = applyPersistedTurnInput(
3090
- messages.slice(turnStartIndex),
3091
- input.persistedInput,
3092
- input.persistedInputReference
3093
- );
3094
- if (compactionUsage && Object.keys(compactionUsage).length > 0) {
3095
- usageRecords.unshift({
3096
- callId: typeof compactionUsage.provider_call_id === "string" && compactionUsage.provider_call_id.trim() ? compactionUsage.provider_call_id.trim() : crypto.randomUUID(),
3097
- usage: compactionUsage,
3098
- model: agentConfig.model || result.model || "unknown",
3099
- ...agentConfig.provider ? { provider: agentConfig.provider } : {}
3100
- });
3101
- }
3102
- const accountingUsage = addOutOfBandUsage(turnUsage, compactionUsage);
3103
- const saved = await input.adapter.saveTurn({
3104
- agentKey: agentConfig.key,
3105
- messages: turnMessages,
3106
- result: {
3107
- ...result,
3108
- ...toolCallCount > 0 ? { toolCallCount } : {},
3109
- ...agentConfig.toolSurface ? { runtimeToolSurface: agentConfig.toolSurface } : {}
3110
- },
3111
- ...usageRecords.length > 0 ? { usageRecords } : {},
3112
- ...accountingUsage ? { accountingUsage } : {},
3113
- billingConfig,
3114
- ...input.runtimeContext ? { runtimeContext: input.runtimeContext } : {},
3115
- ...input.continueDialogId ? { continueDialogId: input.continueDialogId } : {},
3116
- ...input.spaceId ? { spaceId: input.spaceId } : {},
3117
- ...input.category ? { category: input.category } : {},
3118
- ...input.inheritedFromDialogKey ? { inheritedFromDialogKey: input.inheritedFromDialogKey } : {},
3119
- ...input.parentDialogId ? { parentDialogId: input.parentDialogId } : {}
3120
- });
3121
- return {
3122
- ...result,
3123
- ...usageRecords.length > 0 ? { usageRecords } : {},
3124
- ...accountingUsage ? { accountingUsage } : {},
3125
- ...toolCallCount > 0 ? { toolCallCount } : {},
3126
- ...agentConfig.toolSurface ? { runtimeToolSurface: agentConfig.toolSurface } : {},
3127
- // 透出最后一轮 provider 调用的 finish_reason;多轮工具循环里只有最后一轮收尾状态有意义。
3128
- ...result.finish_reason ? { finish_reason: result.finish_reason } : {},
3129
- dialogId: saved.dialogId,
3130
- title: saved.title,
3131
- turnMessages
3132
- };
3133
- }
3134
-
3135
- export {
3136
- readCommandActionGatePayload,
3137
- readActionGate,
3138
- parseToolArgumentsJson,
3139
- summarizeToolArguments,
3140
- getFullChatContextKeys,
3141
- deduplicateContextKeys,
3142
- resolveHistoricalToolContentCap,
3143
- inferCaptureIntent,
3144
- compressOldToolResults,
3145
- trimMessagesWithSummary,
3146
- validateAccessAndBalance,
3147
- buildStaticContexts,
3148
- buildDynamicContexts,
3149
- mergeContexts,
3150
- mergeAgentToolsWithRuntime,
3151
- applyImageConfigRuntimeOverride,
3152
- resolveImageGenerationStreamingState,
3153
- tryPreprocessWebImageOrReject,
3154
- LOCAL_AGENT_CONFIG_MISSING_CODE,
3155
- EMPTY_ASSISTANT_REPAIR_PROMPT,
3156
- LOCAL_TURN_ABORTED_CODE,
3157
- runLocalAgentTurn
3158
- };