nolo-cli 0.82.0-alpha.6 → 0.82.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +2 -2
  2. package/{_executeModel-225YRU52.js → _executeModel-FHVQOYWX.js} +48 -48
  3. package/{action-D22U6CTH.js → action-YVYQEAAV.js} +11 -11
  4. package/{addContentAction-XAPUTGL4.js → addContentAction-O7R66HEX.js} +9 -9
  5. package/{addDialogAgentAction-M7VLLBZM.js → addDialogAgentAction-74OA7KYP.js} +8 -8
  6. package/{agentDeleteCommand-ZJNQGVR2.js → agentDeleteCommand-4427YKQF.js} +31 -29
  7. package/{agentEmailCommands-VLVWFWX2.js → agentEmailCommands-LYDIAUOP.js} +67 -63
  8. package/{agentGrantCommands-R3VQEZJR.js → agentGrantCommands-M3XFO6EN.js} +2 -2
  9. package/{agentListCommands-GHQGLAUU.js → agentListCommands-O4AEMQVV.js} +40 -32
  10. package/{agentMachineCommands-QDXYENZJ.js → agentMachineCommands-F6IHXMPD.js} +31 -29
  11. package/{agentProviderCommands-65ZC2WB4.js → agentProviderCommands-GNPTL5XR.js} +87 -0
  12. package/{agentPullCommand-N7L2CT7L.js → agentPullCommand-O5MPVJ5E.js} +3 -3
  13. package/agentRecordCommands-BDLFOU7E.js +128 -0
  14. package/{agentRunCommand-YSCD65HH.js → agentRunCommand-HSSYFGMC.js} +65 -61
  15. package/{agentRunControl-T44MESII.js → agentRunControl-WCTKX5VL.js} +2 -2
  16. package/{agentRuntimeLocal-ZOHB7OOO.js → agentRuntimeLocal-IW3IM5P6.js} +27 -25
  17. package/{agentSlice-O2SBU5TK.js → agentSlice-G54NT6PX.js} +10 -10
  18. package/{appDeleteCommands-PRT6K5N2.js → appDeleteCommands-ZXLXNRHF.js} +31 -29
  19. package/{appDeployCommands-63ZONFAN.js → appDeployCommands-PWB4YERK.js} +31 -29
  20. package/{appDeployStatusCommands-AFAYCVR3.js → appDeployStatusCommands-2EZKZP7Y.js} +31 -29
  21. package/{appGetCommands-TNZDZE36.js → appGetCommands-JNUKOWHO.js} +31 -29
  22. package/{appListCommands-IA4SPG2X.js → appListCommands-6X3H67SS.js} +31 -29
  23. package/{authCommand-EVGFLAHO.js → authCommand-F4EFRRX6.js} +164 -24
  24. package/{authCommands-ILTBI6JV.js → authCommands-RGOGCPP6.js} +4 -5
  25. package/builtinSkillRegistry-FUAVTRVZ.js +33 -0
  26. package/{chatQueueReduxAdapter-4SM3DAWX.js → chatQueueReduxAdapter-VJXYSZ2D.js} +24 -24
  27. package/{chromeCommands-VOIRNJBL.js → chromeCommands-FZYAU75D.js} +1 -1
  28. package/{chromeOpsCommands-M7DPCX2T.js → chromeOpsCommands-62P2Q2YB.js} +31 -1
  29. package/{chunk-C3FZR5EC.js → chunk-2F7RJC6L.js} +1 -1
  30. package/{chunk-QC5LGHYP.js → chunk-2YMRWISD.js} +10 -5
  31. package/{chunk-HQUORJTM.js → chunk-3BMYXEUW.js} +1 -1
  32. package/{chunk-3QPYFHAH.js → chunk-3DII57IT.js} +1 -1
  33. package/{chunk-NTW5GWDM.js → chunk-3VNWWVKB.js} +2 -0
  34. package/{chunk-DWUCB2A3.js → chunk-42V6BK2E.js} +1 -1
  35. package/{chunk-KIS76A2P.js → chunk-4EZHSKTB.js} +38 -4
  36. package/{chunk-GBPZKFYK.js → chunk-53HEEOTT.js} +4 -4
  37. package/{chunk-5XTOKQLW.js → chunk-5UTFL4QJ.js} +6 -2
  38. package/chunk-5ZUL4CUO.js +10 -0
  39. package/{chunk-E6RGHPDR.js → chunk-6D6VBVEW.js} +4 -6
  40. package/{chunk-CMH2SYHX.js → chunk-6OZ36FXI.js} +2 -2
  41. package/{chunk-NRALD3CC.js → chunk-76WEAXJB.js} +49 -10
  42. package/{chunk-3W2JJOH3.js → chunk-7REEVK4I.js} +3 -3
  43. package/{chunk-BYEJ7K2Z.js → chunk-7S4YWN7P.js} +1 -1
  44. package/{chunk-SREASRV5.js → chunk-ABQYVJBJ.js} +1 -1
  45. package/chunk-ACTMNVHM.js +93 -0
  46. package/{chunk-XWNRAIUL.js → chunk-AFUORTY4.js} +6 -16
  47. package/{chunk-E36HZARC.js → chunk-ASQYTZTR.js} +46 -9
  48. package/{chunk-73IOJLK2.js → chunk-AVV3M6CX.js} +10 -10
  49. package/{chunk-WL2RKIBF.js → chunk-BLJWCTRL.js} +1 -1
  50. package/chunk-BNGW5ASC.js +344 -0
  51. package/{chunk-SZLVDREM.js → chunk-BP4XNZRM.js} +3 -3
  52. package/{chunk-2KDR4CWE.js → chunk-BYMV6QZG.js} +24 -1
  53. package/{chunk-MYU3MJCF.js → chunk-DHDMC6FO.js} +175 -7
  54. package/{chunk-FP27MNSX.js → chunk-DL2LVM5E.js} +3 -3
  55. package/{chunk-EXMHJN7C.js → chunk-EYAQT56M.js} +4 -3
  56. package/{chunk-5LSS6MFZ.js → chunk-F5OE5KSJ.js} +13 -15
  57. package/{chunk-CJCJF5XB.js → chunk-FDTR4QJ6.js} +4 -2
  58. package/{chunk-NJ6WLAPS.js → chunk-FEEHCOBD.js} +1 -1
  59. package/{chunk-YSKEOTPH.js → chunk-GGMVRZRO.js} +155 -795
  60. package/{chunk-PYXL2CJL.js → chunk-GPCZ7UXG.js} +1 -1
  61. package/{chunk-K7AG465Q.js → chunk-GQBOR3G6.js} +4 -2
  62. package/{chunk-YFADVSZE.js → chunk-H62HCIUP.js} +6 -6
  63. package/{chunk-PZM3EENV.js → chunk-HJUYAD4A.js} +1 -1
  64. package/{chunk-A3NNC2LA.js → chunk-HOBJGHLD.js} +1235 -59
  65. package/{chunk-3JQ2NRYU.js → chunk-HVURBGF3.js} +4 -4
  66. package/{chunk-6SD5OPQ4.js → chunk-IIBAPOTQ.js} +11 -173
  67. package/{chunk-ZVN6I33J.js → chunk-IIVGDG4I.js} +6 -5
  68. package/{chunk-UDQWGU7F.js → chunk-J4MOO56S.js} +1 -1
  69. package/{chunk-KC5FAHVS.js → chunk-JEDZAO7L.js} +1 -1
  70. package/{chunk-6XIE5ZGI.js → chunk-JPGCXHNM.js} +1 -1
  71. package/chunk-JRQFUXY7.js +1625 -0
  72. package/chunk-KQ4ONNQD.js +677 -0
  73. package/{chunk-CPSZJBLK.js → chunk-L7I247DF.js} +105 -26
  74. package/{chunk-RXX4GDIH.js → chunk-LS2ZANRJ.js} +1 -1
  75. package/{chunk-BJIRLHJR.js → chunk-M2EJHDJP.js} +4 -0
  76. package/{chunk-EVBFYPDC.js → chunk-MC4XLIJ7.js} +6 -2
  77. package/{chunk-DSRXPQWA.js → chunk-NEDZDG3M.js} +43 -43
  78. package/{chunk-UJ63UXGE.js → chunk-OIVSQH2O.js} +1006 -801
  79. package/{chunk-AETZ7AD6.js → chunk-Q554LLSI.js} +1 -1
  80. package/chunk-Q5FJJ6XI.js +103 -0
  81. package/{chunk-AJHEFRGJ.js → chunk-Q67DOFOO.js} +214 -5
  82. package/{chunk-UZ6XXCVR.js → chunk-QDSINZM3.js} +15 -2
  83. package/{chunk-D6XYLSOS.js → chunk-QIAVMDHY.js} +1 -1
  84. package/{chunk-YWG6EMH3.js → chunk-RG6JBBX5.js} +10 -6
  85. package/{chunk-YXLXHIT2.js → chunk-RTUYRRBM.js} +6 -6
  86. package/{chunk-HHLTFENG.js → chunk-SDTTBMBU.js} +907 -317
  87. package/{chunk-QCZX4FTW.js → chunk-SH43IESU.js} +173 -15
  88. package/{chunk-LSZXYE64.js → chunk-SL4QHSPQ.js} +756 -80
  89. package/{chunk-FNGAF7C4.js → chunk-SNPMM7H3.js} +137 -12
  90. package/{chunk-EM6MPSEI.js → chunk-SPUTJ4DW.js} +52 -30
  91. package/{chunk-SO7B7NW3.js → chunk-STHU4Y5X.js} +413 -62
  92. package/{chunk-SPAQ4PVV.js → chunk-SV5IJK6K.js} +1 -1
  93. package/{chunk-KVDUCO4Q.js → chunk-TDRTS7QW.js} +16 -12
  94. package/{chunk-BJCWNHVU.js → chunk-TOP2VXOR.js} +2 -2
  95. package/{chunk-4EJ5QYB5.js → chunk-UKZDAFYT.js} +1 -1
  96. package/{chunk-PGSKWZCB.js → chunk-UZGQNTVW.js} +1 -1
  97. package/{chunk-ZZCJUXUI.js → chunk-V4MJDUSR.js} +2 -2
  98. package/{chunk-JYYZCK2Z.js → chunk-V7E4PXQD.js} +1 -1
  99. package/{chunk-OZX2IPKM.js → chunk-VLTIYV3X.js} +1 -1
  100. package/{chunk-NHRQCXIQ.js → chunk-VMFTFOWF.js} +13 -3
  101. package/{chunk-4UW2LDVA.js → chunk-VQW3EKYS.js} +15 -15
  102. package/{chunk-HH65VA5U.js → chunk-WGR3J4Q6.js} +101 -4
  103. package/{chunk-5J7W2VWW.js → chunk-WV42OMV7.js} +6 -265
  104. package/{chunk-Q46HQOW3.js → chunk-XTAZCQUT.js} +7 -7
  105. package/{chunk-DUJWWUGV.js → chunk-YQTQQX2H.js} +1 -1
  106. package/{chunk-BOYUESO7.js → chunk-Z77CRGTW.js} +1 -1
  107. package/{contentThunks-ENAVF2YU.js → contentThunks-D6QQKIPF.js} +25 -25
  108. package/{cooldownCommands-BSCH2W7P.js → cooldownCommands-REAWYVTY.js} +2 -2
  109. package/{createAgentAutomationAction-CH6BYC7K.js → createAgentAutomationAction-UIPWW4DG.js} +25 -25
  110. package/{createDialogAction-23UDOXSO.js → createDialogAction-573VVP3X.js} +28 -28
  111. package/{createPageAction-J6AEMLHK.js → createPageAction-LRFSS6TD.js} +26 -26
  112. package/{dbSlice-GKGGFNOB.js → dbSlice-XVWBAGYN.js} +8 -8
  113. package/{deleteFile-LWSR674W.js → deleteFile-YG6QMJLU.js} +3 -3
  114. package/{dialogCommands-BJJGCCQR.js → dialogCommands-KFK2FF5B.js} +35 -31
  115. package/{dialogSlice-F7RD6PUY.js → dialogSlice-EXLC5XTD.js} +24 -24
  116. package/{docCreateCommands-53GB2FU3.js → docCreateCommands-V777WOZ7.js} +32 -30
  117. package/{docDeleteCommands-TAW5JEBU.js → docDeleteCommands-5KHT7Z5Q.js} +33 -31
  118. package/{docReadCommands-F5N7N5E3.js → docReadCommands-BLROGWP3.js} +32 -30
  119. package/{docStore-WX4YBGXC.js → docStore-DZNGJXX7.js} +9 -9
  120. package/{docUpdateCommands-YQ7TRT35.js → docUpdateCommands-QXOZHQ5H.js} +32 -30
  121. package/{fetchMessages-DRABNDPZ.js → fetchMessages-EIU7UFFK.js} +3 -4
  122. package/{getPricing-HRMSOF3E.js → getPricing-LUSEABA6.js} +4 -4
  123. package/{handleSendMessageAction-CW4LULIR.js → handleSendMessageAction-OROTZBPO.js} +24 -24
  124. package/index.js +102 -85
  125. package/{localDialogRead-PUQKFI73.js → localDialogRead-BTFJ4V2I.js} +2 -2
  126. package/{localRuntimeDb-P37ZTX55.js → localRuntimeDb-SYQGUF4U.js} +1 -1
  127. package/{machineCommands-FIYWY5EU.js → machineCommands-IJWERHRH.js} +64 -60
  128. package/{machineWsRunDispatch-KQ4OFFNR.js → machineWsRunDispatch-XQ36M4L7.js} +62 -58
  129. package/{memberThunks-KATHH3F4.js → memberThunks-QGFLFVCI.js} +9 -9
  130. package/{models-GS72DVJS.js → models-T3SG6MJ5.js} +2 -2
  131. package/{offlineMarxistsAgentCommand-GEH6SNNA.js → offlineMarxistsAgentCommand-HGXZV4XJ.js} +1 -1
  132. package/package.json +1 -1
  133. package/providerPresetApply-FG6NZ57W.js +214 -0
  134. package/providerRegistry-757OWH3O.js +31 -0
  135. package/{read-LC6HVYBN.js → read-COE3ZYR6.js} +5 -4
  136. package/{readDocTool-N3ERJHHF.js → readDocTool-5USN4A6V.js} +1 -1
  137. package/{readlineWorkspace-QYI6BRNA.js → readlineWorkspace-EB3362L3.js} +144 -108
  138. package/{removeDialogAgentAction-F5GPTALR.js → removeDialogAgentAction-IX3MN2ZO.js} +11 -11
  139. package/{runAgentClientLoop-GZ5VUGAW.js → runAgentClientLoop-3MR2NPWR.js} +47 -47
  140. package/{runtimeDoctorCommands-CROTMULY.js → runtimeDoctorCommands-X6WDBEQX.js} +2 -2
  141. package/{setDialogExtraReferencesAction-AY4ZCF3A.js → setDialogExtraReferencesAction-X4HCPNZL.js} +9 -9
  142. package/{setPrimaryDialogAgentAction-HPMG7V3R.js → setPrimaryDialogAgentAction-4GMIQLOD.js} +11 -11
  143. package/{settingSlice-OEJA4NQO.js → settingSlice-ZQZVUPKK.js} +10 -10
  144. package/{spaceCommands-IYMIXCMC.js → spaceCommands-TIDVUPDV.js} +30 -28
  145. package/{streamAgentChatTurn-EAXIUJTK.js → streamAgentChatTurn-CLP2JWCQ.js} +59 -58
  146. package/{switchDialogAgentAction-HMDZTZ4I.js → switchDialogAgentAction-N52LRPA3.js} +8 -8
  147. package/{tableCommands-SUNTHAYX.js → tableCommands-O6NWHFKV.js} +1 -1
  148. package/{toolApiClient-VGYUB4P5.js → toolApiClient-QVJ6HDNN.js} +2 -2
  149. package/{tools-QWQOW6J4.js → tools-OXEEBABR.js} +43 -43
  150. package/tuiSummaryLlmCaller-VJY3YD2Q.js +127 -0
  151. package/{updateCommands-Y363MC3L.js → updateCommands-2M74UL7P.js} +2 -2
  152. package/{updateDialogTitleAction-2HCE2M7S.js → updateDialogTitleAction-4YWKF2OE.js} +45 -28
  153. package/agentRecordCommands-AQFYM5HS.js +0 -124
  154. package/chunk-3IT2PFHL.js +0 -611
  155. package/chunk-I42VC5KR.js +0 -15
  156. package/chunk-NG4UT4K4.js +0 -79
  157. package/codingSkills-E6KSDNSJ.js +0 -48
  158. package/tuiSummaryLlmCaller-3Z24VUWM.js +0 -116
  159. package/{chunk-3RAG2NAD.js → chunk-UKWGR5SS.js} +3 -3
  160. package/{db-VQSAOWAO.js → db-WK5MDZVN.js} +1 -1
  161. package/{localRuntimeAuthority-R5UBODT3.js → localRuntimeAuthority-6IR6BBXE.js} +3 -3
@@ -8,15 +8,19 @@ import {
8
8
  readSseFrames,
9
9
  streamSseDataValues,
10
10
  throwIfChatCompletionStreamFailed
11
- } from "./chunk-QC5LGHYP.js";
11
+ } from "./chunk-2YMRWISD.js";
12
+ import {
13
+ DEVIN_CONNECT_URL
14
+ } from "./chunk-Q5FJJ6XI.js";
12
15
  import {
13
16
  clipToolText,
14
17
  hasImageInRuntimeMessages,
18
+ resolveAgentContextWindow,
15
19
  resolveAgentImageInputSupport,
16
20
  resolveHistoricalToolContentCap,
17
21
  resolveToolOutputProfile,
18
22
  stripImagePartsFromMessages
19
- } from "./chunk-KIS76A2P.js";
23
+ } from "./chunk-4EZHSKTB.js";
20
24
  import {
21
25
  downgradeUnparsableToolCalls,
22
26
  hasParsableObjectArguments,
@@ -34,13 +38,15 @@ import {
34
38
  TOOL_GUIDED_SECTION_ORDER,
35
39
  buildIdentityBlock,
36
40
  buildRuntimeGuidanceBlocks,
41
+ detectDispatchIntent,
42
+ detectDispatchIntentFromMessages,
37
43
  estimateContextTokens,
38
44
  hashStablePrefixContent,
39
45
  normalizeChatCompletionsBodyForProvider,
40
46
  requiresBareImageUrl,
41
47
  resolveToolGuidedSections,
42
48
  toBareImageUrlMessages
43
- } from "./chunk-CPSZJBLK.js";
49
+ } from "./chunk-L7I247DF.js";
44
50
  import {
45
51
  convertMessagesToResponsesInput,
46
52
  extractReasoningFromResponseOutput,
@@ -64,16 +70,16 @@ import {
64
70
  parseNoloWorkspaceToolArguments,
65
71
  readTextStreamUpToChars,
66
72
  resolveNoloDialogInput
67
- } from "./chunk-ZVN6I33J.js";
73
+ } from "./chunk-IIVGDG4I.js";
68
74
  import {
69
75
  getAntigravityUserAgent,
70
76
  readAntigravityProjectId,
71
77
  resolveAntigravityCloudCodeBaseUrl
72
- } from "./chunk-PGSKWZCB.js";
78
+ } from "./chunk-UZGQNTVW.js";
73
79
  import {
74
80
  buildProviderAuthHeaders,
75
81
  buildProviderExecutionPlan
76
- } from "./chunk-CMH2SYHX.js";
82
+ } from "./chunk-6OZ36FXI.js";
77
83
  import {
78
84
  buildDialogFallbackTitleFromUserInput
79
85
  } from "./chunk-2MBTWINN.js";
@@ -87,7 +93,7 @@ import {
87
93
  resolveEmptyAssistantFallbackMessage,
88
94
  resolveEmptyAssistantOutcome,
89
95
  resolveTruncatedReasoningTailLog
90
- } from "./chunk-DSRXPQWA.js";
96
+ } from "./chunk-NEDZDG3M.js";
91
97
  import {
92
98
  COMPACTION_SUMMARY_SCHEMA_VERSION,
93
99
  COMPACTION_SUMMARY_SYSTEM_PROMPT,
@@ -106,7 +112,7 @@ import {
106
112
  resolveCompressionTriggerRatio,
107
113
  truncateToolOutputForContext,
108
114
  withProviderCallTimingFields
109
- } from "./chunk-E36HZARC.js";
115
+ } from "./chunk-ASQYTZTR.js";
110
116
  import {
111
117
  estimateTokenCount
112
118
  } from "./chunk-PSCNXBYA.js";
@@ -130,27 +136,25 @@ import {
130
136
  asRecordOrEmpty
131
137
  } from "./chunk-KX6YBIHG.js";
132
138
  import {
139
+ asTrimmedNonEmptyStringArray,
133
140
  dialogMessageKey,
134
141
  dialogMessageRange
135
- } from "./chunk-NHRQCXIQ.js";
142
+ } from "./chunk-VMFTFOWF.js";
136
143
  import {
137
144
  asOptionalFiniteNumber
138
145
  } from "./chunk-WWC7I6TA.js";
139
- import {
140
- asTrimmedNonEmptyStringArray
141
- } from "./chunk-I42VC5KR.js";
142
146
  import {
143
147
  asTrimmedLowercaseString
144
148
  } from "./chunk-QSJ3HFEF.js";
149
+ import {
150
+ isRecord
151
+ } from "./chunk-KUG52IAP.js";
145
152
  import {
146
153
  asTrimmedString
147
154
  } from "./chunk-3EUW3WEO.js";
148
155
  import {
149
156
  asOptionalPositiveFiniteNumber
150
157
  } from "./chunk-U6VC4MU4.js";
151
- import {
152
- isRecord
153
- } from "./chunk-KUG52IAP.js";
154
158
  import {
155
159
  normalizeServerOrigin
156
160
  } from "./chunk-CF7PE763.js";
@@ -12200,8 +12204,208 @@ function summarizeToolArguments(toolName, rawArgs) {
12200
12204
  );
12201
12205
  }
12202
12206
 
12207
+ // packages/agent-runtime/progressGuard.ts
12208
+ var DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS = 5;
12209
+ var DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS = 8;
12210
+ function sortJsonKeys(obj) {
12211
+ if (obj === null || typeof obj !== "object") return obj;
12212
+ if (Array.isArray(obj)) return obj.map(sortJsonKeys);
12213
+ const sorted = {};
12214
+ for (const key of Object.keys(obj).sort()) {
12215
+ sorted[key] = sortJsonKeys(obj[key]);
12216
+ }
12217
+ return sorted;
12218
+ }
12219
+ function normalizeToolArguments(rawArgs) {
12220
+ if (typeof rawArgs !== "string") {
12221
+ try {
12222
+ return JSON.stringify(sortJsonKeys(rawArgs ?? ""));
12223
+ } catch {
12224
+ return String(rawArgs ?? "");
12225
+ }
12226
+ }
12227
+ const trimmed = rawArgs.trim();
12228
+ if (!trimmed) return "";
12229
+ try {
12230
+ const parsed = JSON.parse(trimmed);
12231
+ return JSON.stringify(sortJsonKeys(parsed));
12232
+ } catch {
12233
+ return trimmed;
12234
+ }
12235
+ }
12236
+ function extractNormalizedContentText(content) {
12237
+ if (typeof content === "string") return content.trim();
12238
+ if (!Array.isArray(content)) return "";
12239
+ return content.map((part) => {
12240
+ if (part?.type === "text") return String(part.text ?? "").trim();
12241
+ if (part?.type === "image_url") return `[img:${part.image_url?.url ?? ""}]`;
12242
+ return "";
12243
+ }).filter(Boolean).join("\n");
12244
+ }
12245
+ function buildToolCallsSignature(toolCalls) {
12246
+ if (!toolCalls || toolCalls.length === 0) return "";
12247
+ return toolCalls.map(
12248
+ (tc) => `${tc.function?.name ?? ""}:${normalizeToolArguments(tc.function?.arguments)}`
12249
+ ).join(";;");
12250
+ }
12251
+ function buildAssistantActionFingerprint(result4) {
12252
+ const content = extractNormalizedContentText(result4.content);
12253
+ const reasoning = typeof result4.reasoning_content === "string" ? result4.reasoning_content.trim() : "";
12254
+ let toolCallsSig = buildToolCallsSignature(result4.tool_calls);
12255
+ let hasToolCalls = Array.isArray(result4.tool_calls) && result4.tool_calls.length > 0;
12256
+ if (!toolCallsSig && Array.isArray(result4.output) && result4.output.length > 0) {
12257
+ const blocksToolCalls = result4.output.filter(
12258
+ (b) => b.type === "toolCall"
12259
+ ).map((b) => b.toolCall);
12260
+ if (blocksToolCalls.length > 0) {
12261
+ toolCallsSig = buildToolCallsSignature(blocksToolCalls);
12262
+ hasToolCalls = true;
12263
+ }
12264
+ }
12265
+ const hasNonEmptyText = content.length > 0 || reasoning.length > 0;
12266
+ const fingerprint = `${content}##${reasoning}##${toolCallsSig}`;
12267
+ return {
12268
+ fingerprint,
12269
+ hasNonEmptyText,
12270
+ hasToolCalls,
12271
+ toolCallsSignature: toolCallsSig
12272
+ };
12273
+ }
12274
+ function buildToolResultsSignature(toolExecutions) {
12275
+ if (toolExecutions.length === 0) return "";
12276
+ return toolExecutions.map((exec) => {
12277
+ const contentStr = typeof exec.content === "string" ? exec.content.trim() : "";
12278
+ const metaStr = exec.metadata ? JSON.stringify(sortJsonKeys(exec.metadata)) : "";
12279
+ return `${exec.toolName}:${contentStr}:${metaStr}`;
12280
+ }).join(";;");
12281
+ }
12282
+ function resolveProgressGuardConfig(options, env = typeof process !== "undefined" ? process.env : {}) {
12283
+ const envDisabled = env.NOLO_LOOP_PROGRESS_GUARD_DISABLED === "true" || env.NOLO_LOOP_PROGRESS_GUARD_DISABLED === "1";
12284
+ const disabled = options?.disabled ?? envDisabled ?? false;
12285
+ const parsePositiveInt = (val, fallback) => {
12286
+ if (typeof val === "number" && Number.isFinite(val) && val >= 1) {
12287
+ return Math.floor(val);
12288
+ }
12289
+ if (typeof val === "string") {
12290
+ const parsed = parseInt(val, 10);
12291
+ if (Number.isFinite(parsed) && parsed >= 1) {
12292
+ return parsed;
12293
+ }
12294
+ }
12295
+ return fallback;
12296
+ };
12297
+ const maxConsecutiveIdenticalRounds = parsePositiveInt(
12298
+ options?.maxConsecutiveIdenticalRounds ?? env.NOLO_LOOP_MAX_IDENTICAL_ROUNDS,
12299
+ DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS
12300
+ );
12301
+ const maxConsecutiveStagnantToolRounds = parsePositiveInt(
12302
+ options?.maxConsecutiveStagnantToolRounds ?? env.NOLO_LOOP_MAX_STAGNANT_TOOL_ROUNDS,
12303
+ DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS
12304
+ );
12305
+ return {
12306
+ disabled,
12307
+ maxConsecutiveIdenticalRounds,
12308
+ maxConsecutiveStagnantToolRounds
12309
+ };
12310
+ }
12311
+ var LocalLoopProgressGuard = class {
12312
+ config;
12313
+ lastAssistantFingerprint = null;
12314
+ lastAssistantHasNonEmptyText = false;
12315
+ consecutiveIdenticalCount = 0;
12316
+ lastToolCallsSignature = null;
12317
+ lastToolResultsSignature = null;
12318
+ consecutiveStagnantToolCount = 0;
12319
+ constructor(config, env) {
12320
+ this.config = resolveProgressGuardConfig(config, env);
12321
+ }
12322
+ /**
12323
+ * 在 LLM 返回 assistant 响应后调用。
12324
+ * 仅在纯文本/无工具调用且实质文本相同达到阈值时直接熔断;
12325
+ * 若存在工具调用,则不在此处熔断,留待工具执行后结合工具结果综合判定。
12326
+ */
12327
+ observeAssistantResponse(result4) {
12328
+ if (this.config.disabled) return { action: "continue" };
12329
+ const { fingerprint, hasNonEmptyText, hasToolCalls } = buildAssistantActionFingerprint(result4);
12330
+ if (this.lastAssistantFingerprint !== null && this.lastAssistantFingerprint === fingerprint) {
12331
+ this.consecutiveIdenticalCount += 1;
12332
+ if (!hasToolCalls && hasNonEmptyText && this.consecutiveIdenticalCount >= this.config.maxConsecutiveIdenticalRounds) {
12333
+ return {
12334
+ action: "stall",
12335
+ reason: "repetition_loop",
12336
+ detail: `Consecutive identical text-only assistant response for ${this.consecutiveIdenticalCount} rounds.`,
12337
+ consecutiveRounds: this.consecutiveIdenticalCount
12338
+ };
12339
+ }
12340
+ } else {
12341
+ this.lastAssistantFingerprint = fingerprint;
12342
+ this.lastAssistantHasNonEmptyText = hasNonEmptyText;
12343
+ this.consecutiveIdenticalCount = 1;
12344
+ }
12345
+ return { action: "continue" };
12346
+ }
12347
+ /**
12348
+ * 在本轮所有工具执行完毕后调用,检查是否陷入停滞死循环。
12349
+ * 只有当工具返回内容与元数据完全无变化时才计入无进展 streak;
12350
+ * 一旦工具结果发生变化(如合法轮询状态推进),立即重置 identical streak,确保绝不误杀正常长任务。
12351
+ */
12352
+ observeToolExecution(toolCalls, toolResults) {
12353
+ if (this.config.disabled) return { action: "continue" };
12354
+ if (!toolCalls || toolCalls.length === 0) return { action: "continue" };
12355
+ const toolCallsSig = buildToolCallsSignature(toolCalls);
12356
+ const toolResultsSig = buildToolResultsSignature(toolResults);
12357
+ const toolCallsUnchanged = this.lastToolCallsSignature !== null && this.lastToolCallsSignature === toolCallsSig;
12358
+ const toolResultsUnchanged = this.lastToolResultsSignature !== null && this.lastToolResultsSignature === toolResultsSig;
12359
+ if (toolCallsUnchanged && toolResultsUnchanged) {
12360
+ this.consecutiveStagnantToolCount += 1;
12361
+ if (this.consecutiveIdenticalCount >= this.config.maxConsecutiveIdenticalRounds) {
12362
+ return {
12363
+ action: "stall",
12364
+ reason: "repetition_loop",
12365
+ detail: `Consecutive identical assistant response with unchanged tool results for ${this.consecutiveIdenticalCount} rounds.`,
12366
+ consecutiveRounds: this.consecutiveIdenticalCount
12367
+ };
12368
+ }
12369
+ if (this.consecutiveStagnantToolCount >= this.config.maxConsecutiveStagnantToolRounds) {
12370
+ return {
12371
+ action: "stall",
12372
+ reason: "stagnant_tool_calls",
12373
+ detail: `Consecutive stagnant tool calls with unchanged results for ${this.consecutiveStagnantToolCount} rounds.`,
12374
+ consecutiveRounds: this.consecutiveStagnantToolCount
12375
+ };
12376
+ }
12377
+ } else {
12378
+ this.lastToolCallsSignature = toolCallsSig;
12379
+ this.lastToolResultsSignature = toolResultsSig;
12380
+ this.consecutiveStagnantToolCount = 1;
12381
+ if (!toolResultsUnchanged) {
12382
+ this.consecutiveIdenticalCount = 1;
12383
+ }
12384
+ }
12385
+ return { action: "continue" };
12386
+ }
12387
+ };
12388
+ function createLocalLoopProgressGuard(config, env) {
12389
+ return new LocalLoopProgressGuard(config, env);
12390
+ }
12391
+
12392
+ // packages/agent-runtime/toolArgumentsFingerprint.ts
12393
+ var hashFingerprintInput = (value) => {
12394
+ let hash2 = 2166136261;
12395
+ for (let index = 0; index < value.length; index += 1) {
12396
+ hash2 ^= value.charCodeAt(index);
12397
+ hash2 = Math.imul(hash2, 16777619);
12398
+ }
12399
+ return (hash2 >>> 0).toString(16).padStart(8, "0");
12400
+ };
12401
+ function buildToolArgumentsFingerprint(rawArguments) {
12402
+ if (rawArguments === void 0 || rawArguments === null) return void 0;
12403
+ const normalized = normalizeToolArguments(rawArguments);
12404
+ return hashFingerprintInput(normalized);
12405
+ }
12406
+
12203
12407
  // packages/agent-runtime/leafFinalHandoff.ts
12204
- var LEAF_FINAL_HANDOFF_INSTRUCTIONS = `Leaf subtask final: return only the result, blockers/findings, and minimal evidence the parent needs. Do not narrate your process or restate the task. Keep success minimal (a one-line result is enough); on failure include the blocker, severity when relevant, and an evidence reference (file:line, test command, commit, artifact, or run/dialog). If the task explicitly requires a long-form deliverable (document, translation, dataset, code, or other artifact), provide that deliverable in full and keep only the handoff around it concise.`;
12408
+ var LEAF_FINAL_HANDOFF_INSTRUCTIONS = `Leaf subtask final: return only the result, blockers/findings, and minimal evidence the parent needs. Do not narrate your process or restate the task. Keep success minimal (a one-line result is enough); on failure include the blocker, severity when relevant, and an evidence reference (file:line, test command, commit, artifact, or run/dialog). If the task explicitly requires a long-form deliverable (document, translation, dataset, code, or other artifact), provide that deliverable in full and keep only the handoff around it concise. During execution, follow the brief as given: only when new evidence would materially change the goal, risk, irreversibility, or DoD should you surface it as a blocker/finding in the handoff \u2014 do not silently expand scope or re-litigate the settled direction.`;
12205
12409
 
12206
12410
  // packages/agent-runtime/contextBlockScope.ts
12207
12411
  var isContextBlockScope = (value) => {
@@ -12423,20 +12627,33 @@ function isColdResume(history, nowMs) {
12423
12627
  }
12424
12628
  async function maybeAutoCompactLocalHistory(args2) {
12425
12629
  const { adapter, dialogId, history } = args2;
12426
- const unchanged = () => ({
12630
+ const unchanged = (decision) => ({
12427
12631
  history,
12428
12632
  compressed: false,
12429
- summaryGenerated: false
12633
+ summaryGenerated: false,
12634
+ decision
12430
12635
  });
12431
- if (!dialogId || history.length === 0 || typeof adapter.loadDialogSummary !== "function" || typeof adapter.saveDialogSummary !== "function") {
12432
- return unchanged();
12636
+ if (!dialogId) {
12637
+ return unchanged({ outcome: "skipped", skipReason: "no-dialog-id" });
12638
+ }
12639
+ if (history.length === 0) {
12640
+ return unchanged({ outcome: "skipped", skipReason: "empty-history" });
12641
+ }
12642
+ if (typeof adapter.loadDialogSummary !== "function" || typeof adapter.saveDialogSummary !== "function") {
12643
+ return unchanged({
12644
+ outcome: "skipped",
12645
+ skipReason: "adapter-missing-summary-methods"
12646
+ });
12433
12647
  }
12434
12648
  let stored = null;
12435
12649
  try {
12436
12650
  stored = await adapter.loadDialogSummary(dialogId);
12437
12651
  } catch (error) {
12438
12652
  console.warn("[localLoop] loadDialogSummary failed:", error);
12439
- return unchanged();
12653
+ return unchanged({
12654
+ outcome: "skipped",
12655
+ skipReason: "load-summary-failed"
12656
+ });
12440
12657
  }
12441
12658
  const bridged = toPlanCompressionMessages(history);
12442
12659
  const validation = validateStoredSummary({ history, stored: stored ?? {} });
@@ -12472,7 +12689,21 @@ async function maybeAutoCompactLocalHistory(args2) {
12472
12689
  ...args2.realContextUsagePercent !== void 0 ? { realContextUsagePercent: args2.realContextUsagePercent } : {}
12473
12690
  });
12474
12691
  const projectExisting = () => {
12475
- if (!existingSummary.trim()) return unchanged();
12692
+ const diag = plan.diagnostics;
12693
+ const diagSnapshot = diag ? {
12694
+ estimatedTokens: diag.totalUsed,
12695
+ historyBudget: diag.historyBudget,
12696
+ triggerRatio: diag.triggerRatio,
12697
+ ...diag.realUsageRatio !== void 0 ? { realUsageRatio: diag.realUsageRatio } : {}
12698
+ } : {};
12699
+ const skippedDecision = {
12700
+ outcome: "skipped",
12701
+ skipReason: diag?.emptyReason === "no-pending" ? "no-pending" : diag?.emptyReason === "below-min-compress-count" ? "below-min-compress-count" : "below-trigger",
12702
+ ...diagSnapshot,
12703
+ ...diag ? { pendingMsgCount: diag.pendingMsgCount } : {},
12704
+ ...diag?.compressCount !== void 0 ? { compressCount: diag.compressCount } : {}
12705
+ };
12706
+ if (!existingSummary.trim()) return unchanged(skippedDecision);
12476
12707
  return {
12477
12708
  history: projectHistoryWithSummary({
12478
12709
  history,
@@ -12480,7 +12711,12 @@ async function maybeAutoCompactLocalHistory(args2) {
12480
12711
  summarizedBeforeId
12481
12712
  }),
12482
12713
  compressed: true,
12483
- summaryGenerated: false
12714
+ summaryGenerated: false,
12715
+ decision: {
12716
+ outcome: "compressed",
12717
+ trigger: "existing-summary",
12718
+ ...diagSnapshot
12719
+ }
12484
12720
  };
12485
12721
  };
12486
12722
  if (!plan.shouldCompress) {
@@ -12510,7 +12746,11 @@ async function maybeAutoCompactLocalHistory(args2) {
12510
12746
  );
12511
12747
  return {
12512
12748
  ...projectExisting(),
12513
- failureMessage: "summary model returned empty content"
12749
+ failureMessage: "summary model returned empty content",
12750
+ decision: {
12751
+ outcome: "failed",
12752
+ detail: "summary model returned empty content"
12753
+ }
12514
12754
  };
12515
12755
  }
12516
12756
  await adapter.saveDialogSummary({
@@ -12547,227 +12787,56 @@ async function maybeAutoCompactLocalHistory(args2) {
12547
12787
  beforeTokens: metrics.previousSummaryTokens + metrics.compressedTokens,
12548
12788
  afterTokens: metrics.newSummaryTokens + metrics.retainedTokens,
12549
12789
  ...result4.usage ? { usage: result4.usage } : {},
12550
- metrics
12790
+ metrics,
12791
+ decision: {
12792
+ outcome: "compressed",
12793
+ trigger: invalidSummary ? "invalid-summary" : coldResume ? "cold-resume" : plan.diagnostics?.triggeredByRealUsage ? "real-usage" : "estimate",
12794
+ ...plan.diagnostics ? {
12795
+ estimatedTokens: plan.diagnostics.totalUsed,
12796
+ historyBudget: plan.diagnostics.historyBudget,
12797
+ triggerRatio: plan.diagnostics.triggerRatio,
12798
+ ...plan.diagnostics.realUsageRatio !== void 0 ? { realUsageRatio: plan.diagnostics.realUsageRatio } : {}
12799
+ } : {}
12800
+ }
12551
12801
  };
12552
12802
  } catch (error) {
12553
12803
  console.warn("[localLoop] auto-compaction failed:", error);
12554
12804
  const failureMessage = error instanceof Error && error.message ? error.message.slice(0, 200) : String(error).slice(0, 200);
12555
- return { ...projectExisting(), failureMessage };
12805
+ return {
12806
+ ...projectExisting(),
12807
+ failureMessage,
12808
+ decision: { outcome: "failed", detail: failureMessage }
12809
+ };
12556
12810
  }
12557
12811
  }
12558
12812
 
12559
- // packages/agent-runtime/progressGuard.ts
12560
- var DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS = 5;
12561
- var DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS = 8;
12562
- function sortJsonKeys(obj) {
12563
- if (obj === null || typeof obj !== "object") return obj;
12564
- if (Array.isArray(obj)) return obj.map(sortJsonKeys);
12565
- const sorted = {};
12566
- for (const key of Object.keys(obj).sort()) {
12567
- sorted[key] = sortJsonKeys(obj[key]);
12813
+ // packages/agent-runtime/localLoop.ts
12814
+ var LOOP_TIMING_ENABLED = typeof process !== "undefined" && process.env?.NOLO_LOOP_TIMING === "1";
12815
+ var LOOP_TIMING_FILE = typeof process !== "undefined" ? process.env?.NOLO_LOOP_TIMING_FILE : void 0;
12816
+ var loopTimingRows = [];
12817
+ var loopTimingLastMark;
12818
+ function loopTimingMark(phase, round) {
12819
+ if (!LOOP_TIMING_ENABLED) return;
12820
+ const now = performance.now();
12821
+ if (loopTimingLastMark !== void 0) {
12822
+ loopTimingRows.push({ phase, round, durationMs: now - loopTimingLastMark });
12568
12823
  }
12569
- return sorted;
12824
+ loopTimingLastMark = now;
12570
12825
  }
12571
- function normalizeToolArguments(rawArgs) {
12572
- if (typeof rawArgs !== "string") {
12826
+ async function loopTimingFlush() {
12827
+ if (!LOOP_TIMING_ENABLED) return;
12828
+ const lines = loopTimingRows.map((row) => JSON.stringify(row)).join("\n");
12829
+ loopTimingRows = [];
12830
+ loopTimingLastMark = void 0;
12831
+ if (!lines) return;
12832
+ if (LOOP_TIMING_FILE) {
12573
12833
  try {
12574
- return JSON.stringify(sortJsonKeys(rawArgs ?? ""));
12834
+ const { appendFileSync } = await import("node:fs");
12835
+ appendFileSync(LOOP_TIMING_FILE, lines + "\n");
12575
12836
  } catch {
12576
- return String(rawArgs ?? "");
12577
12837
  }
12578
- }
12579
- const trimmed = rawArgs.trim();
12580
- if (!trimmed) return "";
12581
- try {
12582
- const parsed = JSON.parse(trimmed);
12583
- return JSON.stringify(sortJsonKeys(parsed));
12584
- } catch {
12585
- return trimmed;
12586
- }
12587
- }
12588
- function extractNormalizedContentText(content) {
12589
- if (typeof content === "string") return content.trim();
12590
- if (!Array.isArray(content)) return "";
12591
- return content.map((part) => {
12592
- if (part?.type === "text") return String(part.text ?? "").trim();
12593
- if (part?.type === "image_url") return `[img:${part.image_url?.url ?? ""}]`;
12594
- return "";
12595
- }).filter(Boolean).join("\n");
12596
- }
12597
- function buildToolCallsSignature(toolCalls) {
12598
- if (!toolCalls || toolCalls.length === 0) return "";
12599
- return toolCalls.map(
12600
- (tc) => `${tc.function?.name ?? ""}:${normalizeToolArguments(tc.function?.arguments)}`
12601
- ).join(";;");
12602
- }
12603
- function buildAssistantActionFingerprint(result4) {
12604
- const content = extractNormalizedContentText(result4.content);
12605
- const reasoning = typeof result4.reasoning_content === "string" ? result4.reasoning_content.trim() : "";
12606
- let toolCallsSig = buildToolCallsSignature(result4.tool_calls);
12607
- let hasToolCalls = Array.isArray(result4.tool_calls) && result4.tool_calls.length > 0;
12608
- if (!toolCallsSig && Array.isArray(result4.output) && result4.output.length > 0) {
12609
- const blocksToolCalls = result4.output.filter(
12610
- (b) => b.type === "toolCall"
12611
- ).map((b) => b.toolCall);
12612
- if (blocksToolCalls.length > 0) {
12613
- toolCallsSig = buildToolCallsSignature(blocksToolCalls);
12614
- hasToolCalls = true;
12615
- }
12616
- }
12617
- const hasNonEmptyText = content.length > 0 || reasoning.length > 0;
12618
- const fingerprint = `${content}##${reasoning}##${toolCallsSig}`;
12619
- return {
12620
- fingerprint,
12621
- hasNonEmptyText,
12622
- hasToolCalls,
12623
- toolCallsSignature: toolCallsSig
12624
- };
12625
- }
12626
- function buildToolResultsSignature(toolExecutions) {
12627
- if (toolExecutions.length === 0) return "";
12628
- return toolExecutions.map((exec) => {
12629
- const contentStr = typeof exec.content === "string" ? exec.content.trim() : "";
12630
- const metaStr = exec.metadata ? JSON.stringify(sortJsonKeys(exec.metadata)) : "";
12631
- return `${exec.toolName}:${contentStr}:${metaStr}`;
12632
- }).join(";;");
12633
- }
12634
- function resolveProgressGuardConfig(options, env = typeof process !== "undefined" ? process.env : {}) {
12635
- const envDisabled = env.NOLO_LOOP_PROGRESS_GUARD_DISABLED === "true" || env.NOLO_LOOP_PROGRESS_GUARD_DISABLED === "1";
12636
- const disabled = options?.disabled ?? envDisabled ?? false;
12637
- const parsePositiveInt = (val, fallback) => {
12638
- if (typeof val === "number" && Number.isFinite(val) && val >= 1) {
12639
- return Math.floor(val);
12640
- }
12641
- if (typeof val === "string") {
12642
- const parsed = parseInt(val, 10);
12643
- if (Number.isFinite(parsed) && parsed >= 1) {
12644
- return parsed;
12645
- }
12646
- }
12647
- return fallback;
12648
- };
12649
- const maxConsecutiveIdenticalRounds = parsePositiveInt(
12650
- options?.maxConsecutiveIdenticalRounds ?? env.NOLO_LOOP_MAX_IDENTICAL_ROUNDS,
12651
- DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS
12652
- );
12653
- const maxConsecutiveStagnantToolRounds = parsePositiveInt(
12654
- options?.maxConsecutiveStagnantToolRounds ?? env.NOLO_LOOP_MAX_STAGNANT_TOOL_ROUNDS,
12655
- DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS
12656
- );
12657
- return {
12658
- disabled,
12659
- maxConsecutiveIdenticalRounds,
12660
- maxConsecutiveStagnantToolRounds
12661
- };
12662
- }
12663
- var LocalLoopProgressGuard = class {
12664
- config;
12665
- lastAssistantFingerprint = null;
12666
- lastAssistantHasNonEmptyText = false;
12667
- consecutiveIdenticalCount = 0;
12668
- lastToolCallsSignature = null;
12669
- lastToolResultsSignature = null;
12670
- consecutiveStagnantToolCount = 0;
12671
- constructor(config, env) {
12672
- this.config = resolveProgressGuardConfig(config, env);
12673
- }
12674
- /**
12675
- * 在 LLM 返回 assistant 响应后调用。
12676
- * 仅在纯文本/无工具调用且实质文本相同达到阈值时直接熔断;
12677
- * 若存在工具调用,则不在此处熔断,留待工具执行后结合工具结果综合判定。
12678
- */
12679
- observeAssistantResponse(result4) {
12680
- if (this.config.disabled) return { action: "continue" };
12681
- const { fingerprint, hasNonEmptyText, hasToolCalls } = buildAssistantActionFingerprint(result4);
12682
- if (this.lastAssistantFingerprint !== null && this.lastAssistantFingerprint === fingerprint) {
12683
- this.consecutiveIdenticalCount += 1;
12684
- if (!hasToolCalls && hasNonEmptyText && this.consecutiveIdenticalCount >= this.config.maxConsecutiveIdenticalRounds) {
12685
- return {
12686
- action: "stall",
12687
- reason: "repetition_loop",
12688
- detail: `Consecutive identical text-only assistant response for ${this.consecutiveIdenticalCount} rounds.`,
12689
- consecutiveRounds: this.consecutiveIdenticalCount
12690
- };
12691
- }
12692
- } else {
12693
- this.lastAssistantFingerprint = fingerprint;
12694
- this.lastAssistantHasNonEmptyText = hasNonEmptyText;
12695
- this.consecutiveIdenticalCount = 1;
12696
- }
12697
- return { action: "continue" };
12698
- }
12699
- /**
12700
- * 在本轮所有工具执行完毕后调用,检查是否陷入停滞死循环。
12701
- * 只有当工具返回内容与元数据完全无变化时才计入无进展 streak;
12702
- * 一旦工具结果发生变化(如合法轮询状态推进),立即重置 identical streak,确保绝不误杀正常长任务。
12703
- */
12704
- observeToolExecution(toolCalls, toolResults) {
12705
- if (this.config.disabled) return { action: "continue" };
12706
- if (!toolCalls || toolCalls.length === 0) return { action: "continue" };
12707
- const toolCallsSig = buildToolCallsSignature(toolCalls);
12708
- const toolResultsSig = buildToolResultsSignature(toolResults);
12709
- const toolCallsUnchanged = this.lastToolCallsSignature !== null && this.lastToolCallsSignature === toolCallsSig;
12710
- const toolResultsUnchanged = this.lastToolResultsSignature !== null && this.lastToolResultsSignature === toolResultsSig;
12711
- if (toolCallsUnchanged && toolResultsUnchanged) {
12712
- this.consecutiveStagnantToolCount += 1;
12713
- if (this.consecutiveIdenticalCount >= this.config.maxConsecutiveIdenticalRounds) {
12714
- return {
12715
- action: "stall",
12716
- reason: "repetition_loop",
12717
- detail: `Consecutive identical assistant response with unchanged tool results for ${this.consecutiveIdenticalCount} rounds.`,
12718
- consecutiveRounds: this.consecutiveIdenticalCount
12719
- };
12720
- }
12721
- if (this.consecutiveStagnantToolCount >= this.config.maxConsecutiveStagnantToolRounds) {
12722
- return {
12723
- action: "stall",
12724
- reason: "stagnant_tool_calls",
12725
- detail: `Consecutive stagnant tool calls with unchanged results for ${this.consecutiveStagnantToolCount} rounds.`,
12726
- consecutiveRounds: this.consecutiveStagnantToolCount
12727
- };
12728
- }
12729
- } else {
12730
- this.lastToolCallsSignature = toolCallsSig;
12731
- this.lastToolResultsSignature = toolResultsSig;
12732
- this.consecutiveStagnantToolCount = 1;
12733
- if (!toolResultsUnchanged) {
12734
- this.consecutiveIdenticalCount = 1;
12735
- }
12736
- }
12737
- return { action: "continue" };
12738
- }
12739
- };
12740
- function createLocalLoopProgressGuard(config, env) {
12741
- return new LocalLoopProgressGuard(config, env);
12742
- }
12743
-
12744
- // packages/agent-runtime/localLoop.ts
12745
- var LOOP_TIMING_ENABLED = typeof process !== "undefined" && process.env?.NOLO_LOOP_TIMING === "1";
12746
- var LOOP_TIMING_FILE = typeof process !== "undefined" ? process.env?.NOLO_LOOP_TIMING_FILE : void 0;
12747
- var loopTimingRows = [];
12748
- var loopTimingLastMark;
12749
- function loopTimingMark(phase, round) {
12750
- if (!LOOP_TIMING_ENABLED) return;
12751
- const now = performance.now();
12752
- if (loopTimingLastMark !== void 0) {
12753
- loopTimingRows.push({ phase, round, durationMs: now - loopTimingLastMark });
12754
- }
12755
- loopTimingLastMark = now;
12756
- }
12757
- async function loopTimingFlush() {
12758
- if (!LOOP_TIMING_ENABLED) return;
12759
- const lines = loopTimingRows.map((row) => JSON.stringify(row)).join("\n");
12760
- loopTimingRows = [];
12761
- loopTimingLastMark = void 0;
12762
- if (!lines) return;
12763
- if (LOOP_TIMING_FILE) {
12764
- try {
12765
- const { appendFileSync } = await import("node:fs");
12766
- appendFileSync(LOOP_TIMING_FILE, lines + "\n");
12767
- } catch {
12768
- }
12769
- } else {
12770
- process.stderr.write(lines + "\n");
12838
+ } else {
12839
+ process.stderr.write(lines + "\n");
12771
12840
  }
12772
12841
  }
12773
12842
  var LOCAL_AGENT_CONFIG_MISSING_CODE = "LOCAL_AGENT_CONFIG_MISSING";
@@ -13046,10 +13115,10 @@ var TOOL_METADATA_KEYS = [
13046
13115
  "pasteId",
13047
13116
  "source"
13048
13117
  ];
13049
- function trimHistoryToContextBudget(history, model) {
13118
+ function trimHistoryToContextBudget(history, model, contextWindowOverride) {
13050
13119
  if (history.length === 0) return { history, droppedCount: 0 };
13051
13120
  const { rawMessageBudget } = planContextUsage({
13052
- contextWindow: getModelContextWindow(model ?? ""),
13121
+ contextWindow: contextWindowOverride ?? getModelContextWindow(model ?? ""),
13053
13122
  summaryTokens: 0,
13054
13123
  // localLoop 没有 web 端的负载分档器;medium 是中性默认值,
13055
13124
  // 不为了省几个 token 在这里复制一份分类逻辑。
@@ -13512,7 +13581,14 @@ async function runLocalAgentTurn(input) {
13512
13581
  agentConfig.exposedToolNames ?? agentConfig.toolNames ?? []
13513
13582
  );
13514
13583
  const guidanceBlocks = buildRuntimeGuidanceBlocks(agentTools);
13515
- const toolGuidedSections = resolveToolGuidedSections(agentTools);
13584
+ const toolGuidedSections = resolveToolGuidedSections(agentTools, {
13585
+ // 单调锁定:历史里任一 user 消息命中派发关键词、或已出现过
13586
+ // startAgentRun/controlAgentRun 的 tool_calls,后续每轮都保持 true,
13587
+ // 防止 session-scope 的 agentCollaboration 段逐轮翻转击穿前缀缓存。
13588
+ dispatchIntent: detectDispatchIntentFromMessages(history) || detectDispatchIntent(
13589
+ typeof input.input === "string" ? input.input : void 0
13590
+ )
13591
+ });
13516
13592
  const guidanceScopes = [
13517
13593
  ...input.userLanguage?.trim() ? [buildUserResponseLanguageContext({ language: input.userLanguage })] : [],
13518
13594
  guidanceBlocks.startupProtocol,
@@ -13540,7 +13616,7 @@ async function runLocalAgentTurn(input) {
13540
13616
  }
13541
13617
  return resolvedProvider;
13542
13618
  };
13543
- const contextWindow = getModelContextWindow(agentConfig.model ?? "");
13619
+ const contextWindow = resolveAgentContextWindow(agentConfig);
13544
13620
  const compressionTriggerRatio = resolveCompressionTriggerRatio(contextWindow);
13545
13621
  let realContextUsagePercent;
13546
13622
  if (input.continueDialogId && typeof input.adapter.loadLastContextUsage === "function") {
@@ -13561,19 +13637,29 @@ async function runLocalAgentTurn(input) {
13561
13637
  }
13562
13638
  let compactionUsage;
13563
13639
  const emitCompactionObservation = (compacted) => {
13564
- if (compacted.compressed || compacted.summaryGenerated || compacted.failureMessage) {
13565
- emitLoopEvent(observationBoundary, {
13566
- kind: "compaction",
13567
- atMs: Date.now(),
13568
- reason: compacted.reason ?? "context_budget",
13569
- summaryGenerated: compacted.summaryGenerated,
13570
- compressed: compacted.compressed,
13571
- ...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
13572
- ...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
13573
- ...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
13574
- ...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
13575
- });
13640
+ const decision = compacted.decision;
13641
+ if (decision?.outcome === "skipped") {
13642
+ const isProtectionGap = decision.skipReason === "adapter-missing-summary-methods" || decision.skipReason === "load-summary-failed";
13643
+ const approachingBudget = decision.skipReason === "below-trigger" && typeof decision.estimatedTokens === "number" && typeof decision.historyBudget === "number" && decision.historyBudget > 0 && decision.estimatedTokens >= decision.historyBudget * 0.5;
13644
+ if (!isProtectionGap && !approachingBudget) return;
13576
13645
  }
13646
+ emitLoopEvent(observationBoundary, {
13647
+ kind: "compaction",
13648
+ atMs: Date.now(),
13649
+ ...compacted.reason ? { reason: compacted.reason } : {},
13650
+ summaryGenerated: compacted.summaryGenerated,
13651
+ compressed: compacted.compressed,
13652
+ ...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
13653
+ ...decision?.outcome === "skipped" ? { skipped: true, skipReason: decision.skipReason } : {},
13654
+ ...decision && "trigger" in decision && decision.trigger ? { trigger: decision.trigger } : {},
13655
+ ...decision && "estimatedTokens" in decision && decision.estimatedTokens !== void 0 ? { estimatedTokens: decision.estimatedTokens } : {},
13656
+ ...decision && "historyBudget" in decision && decision.historyBudget !== void 0 ? { historyBudget: decision.historyBudget } : {},
13657
+ ...decision && "realUsageRatio" in decision && decision.realUsageRatio !== void 0 ? { realUsageRatio: decision.realUsageRatio } : {},
13658
+ ...decision && "triggerRatio" in decision && decision.triggerRatio !== void 0 ? { triggerRatio: decision.triggerRatio } : {},
13659
+ ...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
13660
+ ...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
13661
+ ...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
13662
+ });
13577
13663
  };
13578
13664
  try {
13579
13665
  const compacted = await maybeAutoCompactLocalHistory({
@@ -13582,6 +13668,7 @@ async function runLocalAgentTurn(input) {
13582
13668
  history,
13583
13669
  model: agentConfig.model,
13584
13670
  resolveProvider: resolveProviderOnce,
13671
+ contextWindow,
13585
13672
  realContextUsagePercent
13586
13673
  });
13587
13674
  history = compacted.history;
@@ -13591,7 +13678,7 @@ async function runLocalAgentTurn(input) {
13591
13678
  console.warn("[localLoop] auto-compaction unexpected error:", error);
13592
13679
  }
13593
13680
  loopTimingMark("maybeAutoCompactLocalHistory", 0);
13594
- const trimmedHistory = trimHistoryToContextBudget(history, agentConfig.model);
13681
+ const trimmedHistory = trimHistoryToContextBudget(history, agentConfig.model, contextWindow);
13595
13682
  if (trimmedHistory.droppedCount > 0) {
13596
13683
  history = trimmedHistory.history;
13597
13684
  }
@@ -13653,17 +13740,26 @@ async function runLocalAgentTurn(input) {
13653
13740
  let skipFinalAppend = false;
13654
13741
  let partialContent = "";
13655
13742
  const progressGuard = createLocalLoopProgressGuard(input.progressGuardConfig);
13743
+ let ephemeralSummary = null;
13744
+ const ephemeralDialogId = `ephemeral-${crypto.randomUUID()}`;
13745
+ const compactionAdapter = input.continueDialogId ? input.adapter : {
13746
+ ...input.adapter,
13747
+ loadDialogSummary: async () => ephemeralSummary,
13748
+ saveDialogSummary: async (summaryInput) => {
13749
+ ephemeralSummary = summaryInput;
13750
+ }
13751
+ };
13752
+ const compactionDialogId = input.continueDialogId ?? ephemeralDialogId;
13656
13753
  const maybeCompactInLoop = async () => {
13657
- if (!input.continueDialogId) return;
13658
- if (!contextUsage) return;
13659
- const inputTokens = normalizeUsage(contextUsage).input_tokens;
13660
- if (!inputTokens || inputTokens <= 0) return;
13661
- const ratio = Math.min(1, inputTokens / contextWindow);
13662
- if (ratio < compressionTriggerRatio) return;
13754
+ const inputTokens = contextUsage ? normalizeUsage(contextUsage).input_tokens : 0;
13755
+ const ratio = inputTokens > 0 ? Math.min(1, inputTokens / contextWindow) : void 0;
13756
+ if (ratio !== void 0 && ratio < compressionTriggerRatio * 0.85) {
13757
+ return;
13758
+ }
13663
13759
  try {
13664
13760
  const compacted = await maybeAutoCompactLocalHistory({
13665
- adapter: input.adapter,
13666
- dialogId: input.continueDialogId,
13761
+ adapter: compactionAdapter,
13762
+ dialogId: compactionDialogId,
13667
13763
  // canonical 坐标:store 全量历史 + 本轮消息的「持久化形态」
13668
13764
  // (applyPersistedTurnInput 会把首条 user 消息换成 paste 展开形态)。
13669
13765
  // 锚点与 sourceHash 都必须按持久化形态计算——否则下轮从 store
@@ -13678,7 +13774,8 @@ async function runLocalAgentTurn(input) {
13678
13774
  ],
13679
13775
  model: agentConfig.model,
13680
13776
  resolveProvider: resolveProviderOnce,
13681
- realContextUsagePercent: ratio
13777
+ contextWindow,
13778
+ ...ratio !== void 0 ? { realContextUsagePercent: ratio } : {}
13682
13779
  });
13683
13780
  if (compacted.usage) {
13684
13781
  compactionUsage = addOutOfBandUsage(compactionUsage, compacted.usage);
@@ -13946,6 +14043,7 @@ ${reasoningTailLog}
13946
14043
  const startedAt = Date.now();
13947
14044
  loopTimingMark("toolCallStart", round);
13948
14045
  const argumentsPreview = summarizeToolArguments(toolName, toolCall.function.arguments);
14046
+ const argumentsFingerprint = buildToolArgumentsFingerprint(toolCall.function.arguments);
13949
14047
  emitLoopEvent(
13950
14048
  observationBoundary,
13951
14049
  {
@@ -13954,7 +14052,8 @@ ${reasoningTailLog}
13954
14052
  toolCallId: toolCall.id,
13955
14053
  toolName,
13956
14054
  atMs: startedAt,
13957
- ...argumentsPreview ? { argumentsPreview } : {}
14055
+ ...argumentsPreview ? { argumentsPreview } : {},
14056
+ ...argumentsFingerprint ? { argumentsFingerprint } : {}
13958
14057
  },
13959
14058
  {
13960
14059
  type: "tool-call",
@@ -15568,13 +15667,13 @@ var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
15568
15667
  "execShell",
15569
15668
  "launchProcess",
15570
15669
  "listProcesses",
15571
- // ProcessTask follow-up tools (Phase 1). Same tier as listProcesses: they
15572
- // observe/stop tasks the agent itself already spawned, so their blast radius
15573
- // is strictly narrower than launchProcess (which is default-enabled).
15670
+ // ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
15671
+ // tasks the agent itself already spawned, so their blast radius is strictly
15672
+ // narrower than launchProcess (which is default-enabled). Model-facing
15673
+ // follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
15674
+ // runtime-internal.
15574
15675
  "taskWait",
15575
- "taskLogs",
15576
15676
  "taskStop",
15577
- "tasks",
15578
15677
  // Scheduling tools: forking/observing sub-agents is a declared capability
15579
15678
  // of capable agents, and the blast radius is strictly narrower than
15580
15679
  // execShell (already default-enabled). Requiring an env allowlist for these
@@ -17571,9 +17670,7 @@ var WORKSPACE_TOOL_NAMES = [
17571
17670
  "launchProcess",
17572
17671
  "listProcesses",
17573
17672
  "taskWait",
17574
- "taskLogs",
17575
17673
  "taskStop",
17576
- "tasks",
17577
17674
  "openDesktopPreview"
17578
17675
  ];
17579
17676
  var SHELL_TOOL_NAMES = [
@@ -17581,9 +17678,7 @@ var SHELL_TOOL_NAMES = [
17581
17678
  "launchProcess",
17582
17679
  "listProcesses",
17583
17680
  "taskWait",
17584
- "taskLogs",
17585
- "taskStop",
17586
- "tasks"
17681
+ "taskStop"
17587
17682
  ];
17588
17683
  var WORKSPACE_TOOL_NAME_SET = new Set(WORKSPACE_TOOL_NAMES);
17589
17684
  function buildWorkspacePathProperty() {
@@ -17832,7 +17927,7 @@ function buildTaskWaitTool() {
17832
17927
  type: "function",
17833
17928
  function: {
17834
17929
  name: "taskWait",
17835
- description: 'Block until a background task (from launchProcess, or an execShell command that detached) reaches a terminal state, or until timeoutMs elapses. Returns {outcome, status, exitCode?, cursor, events}: outcome "terminal" with status exited|failed|stopped when it finished, outcome "timeout" with status "running" when it outlived the whole budget, outcome "not-found" for an unknown taskId, or outcome "evicted" when the event trail aged out (never wait again in that case). One call already waits the maximum budget and returns the moment the task ends, so a "timeout" means the task is genuinely longer than that \u2014 go do other work and come back, rather than re-waiting in a loop (each re-wait costs a full model round-trip). For a cheap liveness peek use taskLogs (non-blocking) or pass a small timeoutMs. `cursor` is the highest event seq covered by this response \u2014 pass it to taskLogs to read only newer events.',
17930
+ description: 'Block until a background task (from launchProcess, or an execShell command that detached) reaches a terminal state, or until timeoutMs elapses. Returns {outcome, status, exitCode?, cursor, events}: outcome "terminal" with status exited|failed|stopped when it finished, outcome "timeout" with status "running" when it outlived the whole budget, outcome "not-found" for an unknown taskId, or outcome "evicted" when the event trail aged out (never wait again in that case). One call already waits the maximum budget and returns the moment the task ends, so a "timeout" means the task is genuinely longer than that \u2014 go do other work and come back, rather than re-waiting in a loop (each re-wait costs a full model round-trip). Pass a small timeoutMs for a cheap liveness peek instead of the full result. `cursor` is the highest event seq covered by this response.',
17836
17931
  parameters: {
17837
17932
  type: "object",
17838
17933
  properties: {
@@ -17851,30 +17946,6 @@ function buildTaskWaitTool() {
17851
17946
  }
17852
17947
  };
17853
17948
  }
17854
- function buildTaskLogsTool() {
17855
- return {
17856
- type: "function",
17857
- function: {
17858
- name: "taskLogs",
17859
- description: "Read a background task's lifecycle events incrementally. Returns {outcome, status, cursor, events} where events are the started|promoted|exited|killed records with seq greater than the cursor you passed, and the returned `cursor` is the new high-water mark to pass next time (omit cursor to read from the beginning; repeating the same cursor is idempotent). Oversized output is spilled to a file and reported as `logRef`, which you can open with readFile.",
17860
- parameters: {
17861
- type: "object",
17862
- properties: {
17863
- taskId: {
17864
- type: "string",
17865
- minLength: 1,
17866
- description: "Task id returned by launchProcess or by a detached execShell result."
17867
- },
17868
- cursor: {
17869
- type: "number",
17870
- description: "Last event seq you already consumed; only events with a higher seq are returned. Defaults to 0 (all retained events)."
17871
- }
17872
- },
17873
- required: ["taskId"]
17874
- }
17875
- }
17876
- };
17877
- }
17878
17949
  function buildTaskStopTool() {
17879
17950
  return {
17880
17951
  type: "function",
@@ -17895,19 +17966,6 @@ function buildTaskStopTool() {
17895
17966
  }
17896
17967
  };
17897
17968
  }
17898
- function buildTasksTool() {
17899
- return {
17900
- type: "function",
17901
- function: {
17902
- name: "tasks",
17903
- description: "List background tasks you can still wait on, read logs from, or stop. Returns {count, tasks: {taskId, pid, label, status, startedAt, persist}[]}. Use it to recover a taskId you lost track of; foreground commands still running inside execShell are not listed.",
17904
- parameters: {
17905
- type: "object",
17906
- properties: {}
17907
- }
17908
- }
17909
- };
17910
- }
17911
17969
  function buildWorkspaceToolDefinition(toolName) {
17912
17970
  if (toolName === "readFile") {
17913
17971
  return buildReadWorkspaceFileTool();
@@ -17927,9 +17985,7 @@ function buildWorkspaceToolDefinition(toolName) {
17927
17985
  if (toolName === "openDesktopPreview") return buildOpenDesktopPreviewTool();
17928
17986
  if (toolName === "listProcesses") return buildListProcessesTool();
17929
17987
  if (toolName === "taskWait") return buildTaskWaitTool();
17930
- if (toolName === "taskLogs") return buildTaskLogsTool();
17931
17988
  if (toolName === "taskStop") return buildTaskStopTool();
17932
- if (toolName === "tasks") return buildTasksTool();
17933
17989
  return null;
17934
17990
  }
17935
17991
  function filterDeclaredWorkspaceToolNames(args2) {
@@ -19395,15 +19451,23 @@ function buildLoadSkillExecutor(args2) {
19395
19451
  const { resolveSkillByName } = await import("./skillDiscovery-CYUCJMAG.js");
19396
19452
  const resolved = resolveSkillByName(args2.cwd, name);
19397
19453
  if (!resolved) {
19398
- const { resolveCodingBuiltinSlug, buildCodingSkillContentBySlug } = await import("./codingSkills-E6KSDNSJ.js");
19399
- const builtinSlug = resolveCodingBuiltinSlug(name);
19400
- if (builtinSlug) {
19401
- const body = buildCodingSkillContentBySlug(builtinSlug);
19454
+ const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-FUAVTRVZ.js");
19455
+ const builtin = resolveBuiltinSkillByName(name);
19456
+ if (builtin) {
19402
19457
  return {
19403
19458
  content: `Skill "${name}" loaded inline. Follow its instructions.
19404
19459
 
19405
- ${body}`,
19406
- metadata: { loadSkill: true, resolved: true, name, requestedName: name, builtin: true }
19460
+ ${builtin.content}`,
19461
+ // toolNames 进 metadata:回退面已扩到全注册表,其中授工具型 skill
19462
+ // (search-* 等)的工具在本宿主未必接线,宿主可据此降级提示。
19463
+ metadata: {
19464
+ loadSkill: true,
19465
+ resolved: true,
19466
+ name,
19467
+ requestedName: name,
19468
+ builtin: true,
19469
+ ...builtin.config.toolNames?.length ? { toolNames: [...builtin.config.toolNames] } : {}
19470
+ }
19407
19471
  };
19408
19472
  }
19409
19473
  return {
@@ -20174,6 +20238,530 @@ async function fetchAntigravityCloudCodeCompletion(args2) {
20174
20238
  return normalized;
20175
20239
  }
20176
20240
 
20241
+ // packages/agent-runtime/devin/devinProvider.ts
20242
+ import { randomBytes, randomUUID as randomUUID2 } from "node:crypto";
20243
+ var CLIENT_NAME = "chisel";
20244
+ var CLIENT_VERSION = "2026.8.18";
20245
+ function writeVarint(fieldNum, value) {
20246
+ const tag = fieldNum << 3 | 0;
20247
+ const bytes = [];
20248
+ let t = tag;
20249
+ while (t >= 128) {
20250
+ bytes.push(t & 127 | 128);
20251
+ t >>>= 7;
20252
+ }
20253
+ bytes.push(t);
20254
+ let v = value;
20255
+ while (v >= 128) {
20256
+ bytes.push(v & 127 | 128);
20257
+ v >>>= 7;
20258
+ }
20259
+ bytes.push(v);
20260
+ return Buffer.from(bytes);
20261
+ }
20262
+ function writeLengthDelimited(fieldNum, content) {
20263
+ const tag = fieldNum << 3 | 2;
20264
+ const tagBytes = [];
20265
+ let t = tag;
20266
+ while (t >= 128) {
20267
+ tagBytes.push(t & 127 | 128);
20268
+ t >>>= 7;
20269
+ }
20270
+ tagBytes.push(t);
20271
+ const lenBytes = [];
20272
+ let len = content.length;
20273
+ while (len >= 128) {
20274
+ lenBytes.push(len & 127 | 128);
20275
+ len >>>= 7;
20276
+ }
20277
+ lenBytes.push(len);
20278
+ return Buffer.concat([Buffer.from(tagBytes), Buffer.from(lenBytes), content]);
20279
+ }
20280
+ function writeStringField(fieldNum, str) {
20281
+ return writeLengthDelimited(fieldNum, Buffer.from(str, "utf8"));
20282
+ }
20283
+ function writeMessageField(fieldNum, message) {
20284
+ return writeLengthDelimited(fieldNum, message);
20285
+ }
20286
+ function generateFingerprint() {
20287
+ return randomBytes(366).toString("hex");
20288
+ }
20289
+ function encodeDevinClientMetadata(token) {
20290
+ return Buffer.concat([
20291
+ writeStringField(1, CLIENT_NAME),
20292
+ writeStringField(2, CLIENT_VERSION),
20293
+ writeStringField(3, token),
20294
+ writeStringField(4, "en"),
20295
+ writeStringField(5, process.platform === "win32" ? "windows" : "linux"),
20296
+ writeStringField(7, CLIENT_VERSION),
20297
+ writeStringField(12, CLIENT_NAME),
20298
+ writeStringField(31, generateFingerprint())
20299
+ ]);
20300
+ }
20301
+ function encodeDevinChatMessage(msg) {
20302
+ const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
20303
+ return Buffer.concat([
20304
+ writeStringField(1, randomUUID2()),
20305
+ writeVarint(2, source),
20306
+ writeStringField(3, msg.text),
20307
+ ...(msg.toolCalls ?? []).map(
20308
+ (toolCall) => writeMessageField(
20309
+ 6,
20310
+ Buffer.concat([
20311
+ writeStringField(1, toolCall.id),
20312
+ writeStringField(2, toolCall.function.name),
20313
+ writeStringField(3, toolCall.function.arguments)
20314
+ ])
20315
+ )
20316
+ ),
20317
+ ...msg.toolCallId ? [writeStringField(7, msg.toolCallId)] : []
20318
+ ]);
20319
+ }
20320
+ function encodeDevinToolDefinition(tool) {
20321
+ const fn3 = tool.function ?? {};
20322
+ const name = typeof fn3.name === "string" ? fn3.name : "";
20323
+ const description = typeof fn3.description === "string" ? fn3.description : "";
20324
+ const parameters = fn3.parameters ?? {};
20325
+ return Buffer.concat([
20326
+ writeStringField(1, name),
20327
+ writeStringField(2, description.length > 6998 ? `${description.slice(0, 6995)}...` : description),
20328
+ writeStringField(3, JSON.stringify(parameters))
20329
+ ]);
20330
+ }
20331
+ function writeFixed64Field(fieldNum, val) {
20332
+ const b = Buffer.alloc(8);
20333
+ b.writeDoubleLE(val, 0);
20334
+ const tag = fieldNum << 3 | 1;
20335
+ const tagBytes = [];
20336
+ let t = tag;
20337
+ while (t >= 128) {
20338
+ tagBytes.push(t & 127 | 128);
20339
+ t >>>= 7;
20340
+ }
20341
+ tagBytes.push(t);
20342
+ return Buffer.concat([Buffer.from(tagBytes), b]);
20343
+ }
20344
+ function buildCompletionConfig(params) {
20345
+ const maxTokens = params?.maxTokens ?? 128e3;
20346
+ const maxNewlines = params?.maxNewlines ?? 400;
20347
+ const temp = params?.temperature ?? 1;
20348
+ const topP = params?.topP ?? 0.95;
20349
+ return Buffer.concat([
20350
+ writeVarint(1, 1),
20351
+ writeVarint(2, maxTokens),
20352
+ writeVarint(3, maxNewlines),
20353
+ writeFixed64Field(5, temp),
20354
+ writeVarint(7, 40),
20355
+ writeFixed64Field(8, topP)
20356
+ ]);
20357
+ }
20358
+ function buildGetChatMessageRequest(params) {
20359
+ const { token, messages, model, tools = [], temperature } = params;
20360
+ const metadata = encodeDevinClientMetadata(token);
20361
+ let systemPrompt = "";
20362
+ const filteredMessages = [];
20363
+ for (const m of messages) {
20364
+ const text = typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.filter((p) => p?.type === "text").map((p) => p.text).join("\n") : "";
20365
+ if (m.role === "system") {
20366
+ systemPrompt = systemPrompt ? `${systemPrompt}
20367
+
20368
+ ${text}` : text;
20369
+ } else if (m.role === "user" || m.role === "assistant" || m.role === "tool") {
20370
+ filteredMessages.push({
20371
+ role: m.role,
20372
+ text,
20373
+ ...m.tool_call_id ? { toolCallId: m.tool_call_id } : {},
20374
+ ...m.tool_calls?.length ? { toolCalls: m.tool_calls } : {}
20375
+ });
20376
+ }
20377
+ }
20378
+ const coalesced = [];
20379
+ for (const item of filteredMessages) {
20380
+ const last = coalesced[coalesced.length - 1];
20381
+ if (last && last.role === item.role && item.role !== "tool" && !last.toolCalls?.length && !item.toolCalls?.length) {
20382
+ last.text = `${last.text}
20383
+
20384
+ ${item.text}`;
20385
+ } else {
20386
+ coalesced.push({ ...item });
20387
+ }
20388
+ }
20389
+ const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
20390
+ const completionConfig = buildCompletionConfig({ temperature });
20391
+ const modelConfig = Buffer.concat([
20392
+ writeStringField(1, randomUUID2()),
20393
+ writeVarint(2, 1),
20394
+ writeVarint(3, 4)
20395
+ ]);
20396
+ return Buffer.concat([
20397
+ writeMessageField(1, metadata),
20398
+ writeStringField(2, systemPrompt),
20399
+ ...chatMessageBuffers.map((b) => writeMessageField(3, b)),
20400
+ writeVarint(7, 5),
20401
+ writeMessageField(8, completionConfig),
20402
+ ...tools.map((tool) => writeMessageField(10, encodeDevinToolDefinition(tool))),
20403
+ writeMessageField(15, modelConfig),
20404
+ writeStringField(16, randomUUID2()),
20405
+ writeVarint(20, 1),
20406
+ writeStringField(21, model)
20407
+ ]);
20408
+ }
20409
+ function buildDevinConnectFrame(payload, flags = 0) {
20410
+ const header = Buffer.alloc(5);
20411
+ header[0] = flags & 255;
20412
+ header.writeUInt32BE(payload.length, 1);
20413
+ return Buffer.concat([header, payload]);
20414
+ }
20415
+ function parseDevinConnectFrames(buffer3) {
20416
+ const frames = [];
20417
+ let offset = 0;
20418
+ while (offset + 5 <= buffer3.length) {
20419
+ const flags = buffer3[offset];
20420
+ const length = buffer3.readUInt32BE(offset + 1);
20421
+ if (offset + 5 + length > buffer3.length) {
20422
+ break;
20423
+ }
20424
+ const payload = buffer3.subarray(offset + 5, offset + 5 + length);
20425
+ frames.push({ flags, payload });
20426
+ offset += 5 + length;
20427
+ }
20428
+ return {
20429
+ frames,
20430
+ remainder: buffer3.subarray(offset)
20431
+ };
20432
+ }
20433
+ function parseDevinMetadataUsage(metaBytes) {
20434
+ let prompt = 0;
20435
+ let completion;
20436
+ let cacheRead = 0;
20437
+ let cacheWrite = 0;
20438
+ let sawAny = false;
20439
+ let offset = 0;
20440
+ while (offset < metaBytes.length) {
20441
+ let tag = 0;
20442
+ let shift = 0;
20443
+ while (offset < metaBytes.length) {
20444
+ const b = metaBytes[offset++];
20445
+ tag |= (b & 127) << shift;
20446
+ if (!(b & 128)) break;
20447
+ shift += 7;
20448
+ }
20449
+ const fieldNum = tag >>> 3;
20450
+ const wireType = tag & 7;
20451
+ if (wireType === 0) {
20452
+ let val = 0;
20453
+ let s = 0;
20454
+ while (offset < metaBytes.length) {
20455
+ const b = metaBytes[offset++];
20456
+ val |= (b & 127) << s;
20457
+ if (!(b & 128)) break;
20458
+ s += 7;
20459
+ }
20460
+ if (fieldNum === 2) {
20461
+ prompt = val;
20462
+ sawAny = true;
20463
+ } else if (fieldNum === 3) {
20464
+ completion = val;
20465
+ sawAny = true;
20466
+ } else if (fieldNum === 4) {
20467
+ cacheWrite = val;
20468
+ sawAny = true;
20469
+ } else if (fieldNum === 5) {
20470
+ cacheRead = val;
20471
+ sawAny = true;
20472
+ }
20473
+ } else if (wireType === 2) {
20474
+ let len = 0;
20475
+ let s = 0;
20476
+ while (offset < metaBytes.length) {
20477
+ const b = metaBytes[offset++];
20478
+ len |= (b & 127) << s;
20479
+ if (!(b & 128)) break;
20480
+ s += 7;
20481
+ }
20482
+ offset += len;
20483
+ } else {
20484
+ break;
20485
+ }
20486
+ }
20487
+ return sawAny ? { prompt, completion, cacheRead, cacheWrite } : null;
20488
+ }
20489
+ function attachDevinUpstreamFailure(error, failure) {
20490
+ if (failure) {
20491
+ error.devinUpstreamFailure = failure;
20492
+ }
20493
+ return error;
20494
+ }
20495
+ function readDevinUpstreamFailure(error) {
20496
+ if (!error || typeof error !== "object") return void 0;
20497
+ const failure = error.devinUpstreamFailure;
20498
+ if (!failure || typeof failure !== "object") return void 0;
20499
+ if (typeof failure.status !== "number" || !Number.isFinite(failure.status)) {
20500
+ return void 0;
20501
+ }
20502
+ return failure;
20503
+ }
20504
+ function parseDevinConnectTrailer(payload) {
20505
+ const text = payload.toString("utf8").trim();
20506
+ if (!text || text === "{}") return null;
20507
+ try {
20508
+ const parsed = JSON.parse(text);
20509
+ if (!parsed.error) {
20510
+ return new Error(`Devin Connect invalid terminal trailer: ${text}`);
20511
+ }
20512
+ const code = typeof parsed.error.code === "string" ? parsed.error.code : "unknown";
20513
+ const message = typeof parsed.error.message === "string" ? parsed.error.message : "Unknown error";
20514
+ return attachDevinUpstreamFailure(
20515
+ new Error(`Devin Connect upstream error ${code}: ${message}`),
20516
+ // Connect/gRPC 的 resource_exhausted 与 HTTP 429 同义(限流/配额耗尽)。
20517
+ code === "resource_exhausted" ? { status: 429, body: parsed.error } : void 0
20518
+ );
20519
+ } catch {
20520
+ return new Error(`Devin Connect invalid terminal trailer: ${text}`);
20521
+ }
20522
+ }
20523
+ function decodeDevinResponsePayload(payload) {
20524
+ let offset = 0;
20525
+ let content = "";
20526
+ let reasoning = "";
20527
+ let finishReason = null;
20528
+ let usage = null;
20529
+ const events = [];
20530
+ while (offset < payload.length) {
20531
+ let tag = 0;
20532
+ let shift = 0;
20533
+ while (offset < payload.length) {
20534
+ const b = payload[offset++];
20535
+ tag |= (b & 127) << shift;
20536
+ if (!(b & 128)) break;
20537
+ shift += 7;
20538
+ }
20539
+ const fieldNum = tag >>> 3;
20540
+ const wireType = tag & 7;
20541
+ if (wireType === 0) {
20542
+ let val = 0;
20543
+ let s = 0;
20544
+ while (offset < payload.length) {
20545
+ const b = payload[offset++];
20546
+ val |= (b & 127) << s;
20547
+ if (!(b & 128)) break;
20548
+ s += 7;
20549
+ }
20550
+ if (fieldNum === 5) {
20551
+ finishReason = val === 10 ? "tool_calls" : val === 1 || val === 3 ? "length" : "stop";
20552
+ }
20553
+ } else if (wireType === 2) {
20554
+ let len = 0;
20555
+ let s = 0;
20556
+ while (offset < payload.length) {
20557
+ const b = payload[offset++];
20558
+ len |= (b & 127) << s;
20559
+ if (!(b & 128)) break;
20560
+ s += 7;
20561
+ }
20562
+ const valBytes = payload.subarray(offset, offset + len);
20563
+ offset += len;
20564
+ if (fieldNum === 3) {
20565
+ const text = valBytes.toString("utf8");
20566
+ content += text;
20567
+ events.push({ type: "content", text });
20568
+ } else if (fieldNum === 9) {
20569
+ const text = valBytes.toString("utf8");
20570
+ reasoning += text;
20571
+ events.push({ type: "reasoning", text });
20572
+ } else if (fieldNum === 6) {
20573
+ let nestedOffset = 0;
20574
+ let id;
20575
+ let name;
20576
+ let argsDelta;
20577
+ while (nestedOffset < valBytes.length) {
20578
+ let nestedTag = 0;
20579
+ let nestedShift = 0;
20580
+ while (nestedOffset < valBytes.length) {
20581
+ const b = valBytes[nestedOffset++];
20582
+ nestedTag |= (b & 127) << nestedShift;
20583
+ if (!(b & 128)) break;
20584
+ nestedShift += 7;
20585
+ }
20586
+ const nestedField = nestedTag >>> 3;
20587
+ const nestedWire = nestedTag & 7;
20588
+ if (nestedWire !== 2) break;
20589
+ let nestedLength = 0;
20590
+ let lengthShift = 0;
20591
+ while (nestedOffset < valBytes.length) {
20592
+ const b = valBytes[nestedOffset++];
20593
+ nestedLength |= (b & 127) << lengthShift;
20594
+ if (!(b & 128)) break;
20595
+ lengthShift += 7;
20596
+ }
20597
+ const nestedValue = valBytes.subarray(nestedOffset, nestedOffset + nestedLength);
20598
+ nestedOffset += nestedLength;
20599
+ const text = nestedValue.toString("utf8");
20600
+ if (nestedField === 1) id = text;
20601
+ else if (nestedField === 2) name = text;
20602
+ else if (nestedField === 3) argsDelta = (argsDelta ?? "") + text;
20603
+ }
20604
+ if (id !== void 0 && name !== void 0) {
20605
+ events.push({ type: "tool-call-start", id, name });
20606
+ }
20607
+ if (argsDelta !== void 0) {
20608
+ events.push({ type: "tool-call-args", argsDelta, ...id ? { id } : {} });
20609
+ }
20610
+ } else if (fieldNum === 7) {
20611
+ usage = parseDevinMetadataUsage(valBytes);
20612
+ }
20613
+ } else {
20614
+ break;
20615
+ }
20616
+ }
20617
+ return { content, reasoning, finishReason, events, usage };
20618
+ }
20619
+ function createDevinProvider(options) {
20620
+ const { token, model = "swe-2-max", fetchImpl = fetch, tools = [], temperature } = options;
20621
+ return {
20622
+ model,
20623
+ async complete(messages, opts) {
20624
+ const selectedModel = model;
20625
+ const requestPayload = buildGetChatMessageRequest({
20626
+ token,
20627
+ messages,
20628
+ model: selectedModel,
20629
+ tools,
20630
+ temperature
20631
+ });
20632
+ const frame = buildDevinConnectFrame(requestPayload);
20633
+ const response = await fetchImpl(DEVIN_CONNECT_URL, {
20634
+ method: "POST",
20635
+ headers: {
20636
+ "authorization": `Basic ${token}-${token}`,
20637
+ "content-type": "application/connect+proto",
20638
+ "connect-protocol-version": "1"
20639
+ },
20640
+ body: new Uint8Array(frame),
20641
+ signal: opts?.signal
20642
+ });
20643
+ if (!response.ok) {
20644
+ const errText = await response.text().catch(() => "");
20645
+ throw attachDevinUpstreamFailure(
20646
+ new Error(
20647
+ `Devin Connect upstream returned error ${response.status}: ${errText}`
20648
+ ),
20649
+ { status: response.status, body: errText }
20650
+ );
20651
+ }
20652
+ if (!response.body) {
20653
+ throw new Error("Devin Connect response body is null");
20654
+ }
20655
+ let text = "";
20656
+ let reasoning = "";
20657
+ let finishReason = null;
20658
+ let frameUsage = null;
20659
+ const toolCallOrder = [];
20660
+ const toolCallById = /* @__PURE__ */ new Map();
20661
+ let currentToolCallId = null;
20662
+ let buffer3 = Buffer.alloc(0);
20663
+ let sawTrailer = false;
20664
+ const reader = response.body.getReader();
20665
+ try {
20666
+ while (true) {
20667
+ const { done: done4, value } = await reader.read();
20668
+ if (done4) break;
20669
+ buffer3 = Buffer.concat([buffer3, Buffer.from(value)]);
20670
+ const { frames, remainder } = parseDevinConnectFrames(buffer3);
20671
+ buffer3 = Buffer.from(remainder);
20672
+ for (const f of frames) {
20673
+ if (sawTrailer) {
20674
+ throw new Error("Devin Connect received a frame after the terminal trailer");
20675
+ }
20676
+ if (f.flags & 2) {
20677
+ sawTrailer = true;
20678
+ const trailerError = parseDevinConnectTrailer(f.payload);
20679
+ if (trailerError) throw trailerError;
20680
+ continue;
20681
+ }
20682
+ const delta = decodeDevinResponsePayload(f.payload);
20683
+ if (delta.usage?.completion !== void 0) {
20684
+ frameUsage = delta.usage;
20685
+ }
20686
+ text += delta.content;
20687
+ reasoning += delta.reasoning;
20688
+ if (delta.finishReason) finishReason = delta.finishReason;
20689
+ for (const event of delta.events) {
20690
+ if (event.type === "reasoning") {
20691
+ opts?.onReasoningDelta?.(event.text);
20692
+ } else if (event.type === "content") {
20693
+ opts?.onTextDelta?.(event.text);
20694
+ } else if (event.type === "tool-call-start") {
20695
+ const existing = toolCallById.get(event.id);
20696
+ if (existing) {
20697
+ existing.name = event.name;
20698
+ } else {
20699
+ toolCallOrder.push(event.id);
20700
+ toolCallById.set(event.id, {
20701
+ id: event.id,
20702
+ name: event.name,
20703
+ argumentsText: ""
20704
+ });
20705
+ }
20706
+ currentToolCallId = event.id;
20707
+ } else {
20708
+ const targetId = event.id ?? currentToolCallId;
20709
+ const target = targetId ? toolCallById.get(targetId) : void 0;
20710
+ if (target) target.argumentsText += event.argsDelta;
20711
+ }
20712
+ }
20713
+ }
20714
+ }
20715
+ } finally {
20716
+ reader.releaseLock();
20717
+ }
20718
+ if (buffer3.length > 0) {
20719
+ throw new Error("Devin Connect upstream ended with an incomplete frame");
20720
+ }
20721
+ if (!sawTrailer) {
20722
+ throw new Error("Devin Connect upstream ended before the terminal trailer");
20723
+ }
20724
+ const toolCalls = toolCallOrder.map((id) => {
20725
+ const call = toolCallById.get(id);
20726
+ return {
20727
+ id: call.id,
20728
+ type: "function",
20729
+ function: {
20730
+ name: call.name,
20731
+ arguments: call.argumentsText || "{}"
20732
+ }
20733
+ };
20734
+ });
20735
+ if (!text && !reasoning && toolCalls.length === 0) {
20736
+ throw new Error("Devin Connect upstream completed without content or tool calls");
20737
+ }
20738
+ const usage = frameUsage ? {
20739
+ prompt_tokens: frameUsage.prompt + frameUsage.cacheRead,
20740
+ completion_tokens: frameUsage.completion ?? 0,
20741
+ total_tokens: frameUsage.prompt + frameUsage.cacheRead + (frameUsage.completion ?? 0) + frameUsage.cacheWrite,
20742
+ ...frameUsage.cacheRead > 0 ? { prompt_tokens_details: { cached_tokens: frameUsage.cacheRead } } : {},
20743
+ ...frameUsage.cacheWrite > 0 ? { cache_creation_input_tokens: frameUsage.cacheWrite } : {}
20744
+ } : void 0;
20745
+ return {
20746
+ content: text,
20747
+ model: selectedModel,
20748
+ provider: "devin",
20749
+ ...usage ? { usage } : {},
20750
+ ...reasoning ? { reasoning_content: reasoning } : {},
20751
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {},
20752
+ // The upstream finish event wins whenever it is present. A tool call
20753
+ // cut off by the length limit has to stay "length" instead of being
20754
+ // relabelled "tool_calls", so probes/telemetry and any downstream
20755
+ // consumer of the final finish_reason no longer see a truncated turn
20756
+ // mislabelled as a normal one. localLoop keeps its own truncation
20757
+ // gates and excludes tool-bearing turns from them.
20758
+ finish_reason: finishReason ?? (toolCalls.length > 0 ? "tool_calls" : "stop"),
20759
+ stream_complete: true
20760
+ };
20761
+ }
20762
+ };
20763
+ }
20764
+
20177
20765
  export {
20178
20766
  Option_exports,
20179
20767
  Duration_exports,
@@ -20226,5 +20814,7 @@ export {
20226
20814
  shouldUseGeminiNativeToolRoute,
20227
20815
  buildGeminiGenerateContentRequest,
20228
20816
  resolveAntigravityFinishReason,
20229
- fetchAntigravityCloudCodeCompletion
20817
+ fetchAntigravityCloudCodeCompletion,
20818
+ readDevinUpstreamFailure,
20819
+ createDevinProvider
20230
20820
  };