nolo-cli 0.95.0-alpha.6 → 0.95.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 (180) hide show
  1. package/README.md +1 -1
  2. package/{_executeModel-AUQRMRWL.js → _executeModel-4NTXSCYT.js} +67 -63
  3. package/{action-YVYQEAAV.js → action-GI44T4DR.js} +10 -10
  4. package/{addContentAction-O7R66HEX.js → addContentAction-B2DRF7P6.js} +9 -9
  5. package/{addDialogAgentAction-74OA7KYP.js → addDialogAgentAction-T3I7IXPK.js} +15 -17
  6. package/{agentDeleteCommand-4BAHJRU3.js → agentDeleteCommand-QYCCUQ35.js} +47 -43
  7. package/{agentEmailCommands-QISOY7Y6.js → agentEmailCommands-GJ7KXHA6.js} +89 -82
  8. package/{agentListCommands-U46ODMQU.js → agentListCommands-JDU7V3M5.js} +77 -82
  9. package/{agentMachineCommands-EHV2KM2C.js → agentMachineCommands-PXJG3EDI.js} +42 -38
  10. package/{agentProviderCommands-GNPTL5XR.js → agentProviderCommands-YK2BIIXZ.js} +1 -1
  11. package/{agentPullCommand-O5MPVJ5E.js → agentPullCommand-HF4A42D4.js} +1 -1
  12. package/agentRecordCommands-3ONMYU6P.js +135 -0
  13. package/{agentRunCommand-K4CLMA6B.js → agentRunCommand-L6NJGDBA.js} +88 -80
  14. package/{agentRunControl-XLGD3UZ5.js → agentRunControl-5T64LM2M.js} +2 -2
  15. package/{agentRuntimeLocal-O4HPUJA4.js → agentRuntimeLocal-SYLNOKCT.js} +44 -36
  16. package/{agentSlice-ZYT2OUR3.js → agentSlice-X63VSE6R.js} +11 -11
  17. package/{appDeleteCommands-R5BBTKQK.js → appDeleteCommands-IP22BHZE.js} +42 -38
  18. package/{appDeployCommands-ZJIXOJWD.js → appDeployCommands-5ZTQL6UL.js} +42 -38
  19. package/{appDeployStatusCommands-B3R2ZTBF.js → appDeployStatusCommands-G6EMAT75.js} +42 -38
  20. package/{appGetCommands-2AQSOV2A.js → appGetCommands-UXBDAYEM.js} +42 -38
  21. package/{appListCommands-HCIJGZFY.js → appListCommands-J274GTVP.js} +42 -38
  22. package/{authCommand-F4EFRRX6.js → authCommand-W6I6GD3F.js} +115 -23
  23. package/{authCommands-RGOGCPP6.js → authCommands-GBIFZWD3.js} +5 -5
  24. package/{builtinSkillRegistry-FUAVTRVZ.js → builtinSkillRegistry-ZMF6YGNO.js} +6 -5
  25. package/{chatQueueReduxAdapter-Q5V4YJVI.js → chatQueueReduxAdapter-KN774OKJ.js} +30 -29
  26. package/{chromeCommands-FZYAU75D.js → chromeCommands-K27J4OVZ.js} +124 -28
  27. package/{chromeOpsCommands-62P2Q2YB.js → chromeOpsCommands-IXRLN57H.js} +4 -3
  28. package/{chunk-6OZ36FXI.js → chunk-27ONFIEY.js} +22 -4
  29. package/{chunk-XOVEWFLK.js → chunk-2JCOP36I.js} +100 -100
  30. package/{chunk-JEDZAO7L.js → chunk-2SYTUTLI.js} +257 -37
  31. package/{chunk-OIVSQH2O.js → chunk-3BXNTXYI.js} +299 -5
  32. package/{chunk-EYAQT56M.js → chunk-4DPP773Q.js} +2 -2
  33. package/chunk-4LCOCOR5.js +50 -0
  34. package/{chunk-2GRGFCF6.js → chunk-4VJAC32I.js} +2 -1
  35. package/{chunk-MC4XLIJ7.js → chunk-523DITKR.js} +1 -1
  36. package/{chunk-IAO6JBYW.js → chunk-5B7XS6UO.js} +164 -14
  37. package/{chunk-E4MARS3Q.js → chunk-5GVBDNTO.js} +1 -1
  38. package/chunk-5J3PYNUP.js +255 -0
  39. package/chunk-5MMAK75Q.js +15 -0
  40. package/{chunk-JPGCXHNM.js → chunk-5OA5HMTL.js} +1 -1
  41. package/{chunk-AFDS2CVM.js → chunk-5T2W2ZZN.js} +15 -20
  42. package/{chunk-42V6BK2E.js → chunk-62IL3KQV.js} +4 -34
  43. package/{chunk-YQTQQX2H.js → chunk-67HHBCFJ.js} +1 -1
  44. package/{chunk-SNPMM7H3.js → chunk-67T7O467.js} +13 -13
  45. package/{chunk-6YTOJY35.js → chunk-6D2JFXLY.js} +35 -0
  46. package/{chunk-4MY4GLIW.js → chunk-6IHBIRPK.js} +969 -1090
  47. package/{chunk-3BMYXEUW.js → chunk-6O4IK4V2.js} +1 -1
  48. package/{chunk-DHDMC6FO.js → chunk-6TPOEJMQ.js} +9 -4
  49. package/{chunk-LLT642J4.js → chunk-6UPZ63YT.js} +24 -5
  50. package/{chunk-WADCY6G6.js → chunk-6ZWMH6TJ.js} +111 -41
  51. package/{chunk-ABQYVJBJ.js → chunk-7CHC4W22.js} +1 -1
  52. package/{chunk-GQBOR3G6.js → chunk-7KVZ5LDQ.js} +2 -2
  53. package/{chunk-MMPXJXHT.js → chunk-7VJHIB2S.js} +573 -476
  54. package/{chunk-OA6Q2A4I.js → chunk-A7RSPKU6.js} +98 -22
  55. package/{chunk-KQ4ONNQD.js → chunk-ALFH24P3.js} +56 -7
  56. package/{chunk-Q554LLSI.js → chunk-AUDNYVRC.js} +1 -1
  57. package/{chunk-GPCZ7UXG.js → chunk-AZRHIN5B.js} +1 -1
  58. package/{chunk-JRQFUXY7.js → chunk-B2XUQXQX.js} +96 -19
  59. package/chunk-BMQ2MJUK.js +153 -0
  60. package/{chunk-3IIEFNGY.js → chunk-C53ZG23R.js} +2 -2
  61. package/chunk-CHOZJMJS.js +78 -0
  62. package/{chunk-A6G32FNX.js → chunk-CJXHT3S7.js} +13 -13
  63. package/{chunk-HJUYAD4A.js → chunk-CPUFH46E.js} +8 -8
  64. package/{chunk-JOHSKZQX.js → chunk-CQMQXVFQ.js} +859 -141
  65. package/{chunk-LS2ZANRJ.js → chunk-CTUQJVQM.js} +1 -1
  66. package/{chunk-BP4XNZRM.js → chunk-CU3QB4HW.js} +3 -3
  67. package/{chunk-ACTMNVHM.js → chunk-CYSYR67N.js} +1 -1
  68. package/{chunk-ZXKVPF4K.js → chunk-DA54MHPJ.js} +236 -36
  69. package/{chunk-VLTIYV3X.js → chunk-DCLMZ5TX.js} +4 -4
  70. package/{chunk-UKZDAFYT.js → chunk-DSSTTEKI.js} +6 -10
  71. package/{chunk-HVURBGF3.js → chunk-ESRMFY7G.js} +2 -2
  72. package/{chunk-TRV2MIDW.js → chunk-EXAJ6DCR.js} +1 -0
  73. package/chunk-GMZLP5DV.js +82 -0
  74. package/{chunk-FDTR4QJ6.js → chunk-H6A6X4EK.js} +32 -1
  75. package/{chunk-DVINR3PL.js → chunk-HDLLCBRF.js} +1 -1
  76. package/{chunk-ONXOABJR.js → chunk-HNGRBWYF.js} +3 -0
  77. package/{chunk-ZLR5JN3E.js → chunk-HWRQVJGX.js} +7 -7
  78. package/{chunk-H62HCIUP.js → chunk-HYZIYH2H.js} +11 -10
  79. package/{chunk-NTW5GWDM.js → chunk-I3QNET24.js} +32 -17
  80. package/{chunk-WV42OMV7.js → chunk-IAESIMK7.js} +4 -4
  81. package/{chunk-QIAVMDHY.js → chunk-IUVCUGQR.js} +4 -4
  82. package/{chunk-EGSKXKR5.js → chunk-IX27RP45.js} +1 -1
  83. package/{chunk-IIVGDG4I.js → chunk-LNPYTNMG.js} +8 -4
  84. package/{chunk-BLJWCTRL.js → chunk-LVITW736.js} +1 -1
  85. package/{chunk-76WEAXJB.js → chunk-M3LRSBOX.js} +18 -15
  86. package/{chunk-XRWZB6CF.js → chunk-M73PVOVS.js} +23 -76
  87. package/{chunk-7S4YWN7P.js → chunk-MX574M24.js} +1 -1
  88. package/{chunk-FZGV4FGK.js → chunk-NUHHBEJC.js} +378 -187
  89. package/{chunk-53HEEOTT.js → chunk-O26PCYLS.js} +80 -13
  90. package/{chunk-3DII57IT.js → chunk-O2OWEFII.js} +1 -1
  91. package/chunk-OCZKATRC.js +129 -0
  92. package/chunk-P6GMCCAT.js +870 -0
  93. package/{chunk-CPH3W5A7.js → chunk-Q4GP72HX.js} +94 -3
  94. package/{chunk-Z77CRGTW.js → chunk-R4SQ3LGW.js} +1 -1
  95. package/chunk-RE3CDVRX.js +7600 -0
  96. package/{chunk-DEUUPHOO.js → chunk-RKGKDQGJ.js} +74 -17
  97. package/{chunk-V4MJDUSR.js → chunk-RSEEDUMS.js} +2 -2
  98. package/{chunk-BZWBEHGD.js → chunk-S3VFZW75.js} +66 -38
  99. package/{chunk-UZGQNTVW.js → chunk-S5XGT6GB.js} +5 -3
  100. package/{chunk-AFUORTY4.js → chunk-SONWNI3L.js} +21 -21
  101. package/{chunk-BYMV6QZG.js → chunk-TNIX77YM.js} +4 -0
  102. package/{chunk-OF7AQZUG.js → chunk-TU5NE4U3.js} +9 -84
  103. package/chunk-UNYJU5L6.js +780 -0
  104. package/{chunk-J4MOO56S.js → chunk-UQNS32WZ.js} +10 -2
  105. package/chunk-V2SAIXHE.js +13349 -0
  106. package/chunk-VIWDGTDA.js +8 -0
  107. package/chunk-VJVNU77E.js +83 -0
  108. package/{chunk-6D6VBVEW.js → chunk-VPFEPRME.js} +9 -9
  109. package/{chunk-JAXOVNM4.js → chunk-WILHZY7K.js} +45 -45
  110. package/{chunk-UKWGR5SS.js → chunk-WIWM4FE3.js} +187 -398
  111. package/{chunk-BGSLKVCP.js → chunk-XTDH3PGV.js} +6 -7
  112. package/{chunk-O6OSWFZQ.js → chunk-XUWRURDF.js} +6 -0
  113. package/{chunk-Q67DOFOO.js → chunk-Y3PMXGLH.js} +2 -0
  114. package/{chunk-SH43IESU.js → chunk-YUNJN43V.js} +44 -9
  115. package/{chunk-TOP2VXOR.js → chunk-Z4CSIXYP.js} +2 -2
  116. package/{chunk-2F7RJC6L.js → chunk-ZOVKKMF6.js} +1 -1
  117. package/chunk-ZRAU6T47.js +56 -0
  118. package/commandRegistry-NPS6IYBO.js +833 -0
  119. package/{contentThunks-PT23JWJX.js → contentThunks-EB4JFL4K.js} +32 -30
  120. package/{cooldownCommands-REAWYVTY.js → cooldownCommands-ZLEPIB4A.js} +2 -2
  121. package/{createAgentAutomationAction-N27SYTLU.js → createAgentAutomationAction-NZS7N4AW.js} +32 -30
  122. package/{createDialogAction-XZPLHD5G.js → createDialogAction-4Q4J7P4T.js} +36 -33
  123. package/{createPageAction-KHVJQ3CS.js → createPageAction-FPKRGV7D.js} +38 -36
  124. package/{chunk-3SJQXXGY.js → cursorProvider-YGGNMVWX.js} +2560 -9879
  125. package/{dbSlice-XVWBAGYN.js → dbSlice-DQ32LYTJ.js} +8 -8
  126. package/{deleteFile-YG6QMJLU.js → deleteFile-NX6QHCWZ.js} +3 -3
  127. package/{dialogCommands-ZUWW5UT6.js → dialogCommands-XXZH5K6U.js} +45 -41
  128. package/{dialogSlice-3YH242HS.js → dialogSlice-DXEZ3PA3.js} +36 -29
  129. package/{dist-VODFSGNG.js → dist-NJC2W7I4.js} +61 -54
  130. package/{docCreateCommands-Q6FADDSJ.js → docCreateCommands-FLNUDWG6.js} +44 -40
  131. package/{docDeleteCommands-ZKIH54PZ.js → docDeleteCommands-74OURFAB.js} +44 -40
  132. package/{docReadCommands-7BZT2QTW.js → docReadCommands-QENWDQVH.js} +43 -39
  133. package/{docStore-YSZRNUUD.js → docStore-2JTPJVFK.js} +11 -10
  134. package/{docUpdateCommands-WJXWTRL7.js → docUpdateCommands-J4HWJ5JO.js} +44 -40
  135. package/{fetchMessages-EIU7UFFK.js → fetchMessages-67MEFPZR.js} +2 -2
  136. package/{getPricing-LUSEABA6.js → getPricing-NMMFT3YI.js} +3 -3
  137. package/{handleSendMessageAction-KJO2QDBM.js → handleSendMessageAction-FGPHI364.js} +91 -83
  138. package/index.js +87 -884
  139. package/{localDialogRead-BTFJ4V2I.js → localDialogRead-EBRS242U.js} +2 -2
  140. package/{localRuntimeAuthority-6IR6BBXE.js → localRuntimeAuthority-5W6IJRAD.js} +6 -6
  141. package/{localRuntimeDb-SYQGUF4U.js → localRuntimeDb-3LRMNLCM.js} +1 -1
  142. package/{machineCommands-QC4TD7GJ.js → machineCommands-26AZP4AS.js} +84 -77
  143. package/{machineWsRunDispatch-XUOIAXO7.js → machineWsRunDispatch-GQ5XJ2DL.js} +81 -74
  144. package/{memberThunks-QGFLFVCI.js → memberThunks-5ZXPR63F.js} +9 -9
  145. package/{models-T3SG6MJ5.js → models-ZPU5EDF4.js} +2 -2
  146. package/oauthTokenStore-ITEB663N.js +23 -0
  147. package/package.json +1 -1
  148. package/pdf-U6KSUEZZ.js +26435 -0
  149. package/processSpawn-SOAV3FEV.js +11 -0
  150. package/profileConfig-ZGOFORWV.js +43 -0
  151. package/{providerPresetApply-FG6NZ57W.js → providerPresetApply-DD6NGWW6.js} +7 -7
  152. package/{providerRegistry-757OWH3O.js → providerRegistry-XDRLMYGJ.js} +7 -7
  153. package/{read-COE3ZYR6.js → read-EPTJRAEF.js} +5 -5
  154. package/{readDocTool-5USN4A6V.js → readDocTool-W4NDXNEX.js} +5 -3
  155. package/{readlineWorkspace-74TXXSLO.js → readlineWorkspace-B7NBQCX6.js} +2448 -2022
  156. package/{removeDialogAgentAction-IX3MN2ZO.js → removeDialogAgentAction-BVAWQKXE.js} +17 -19
  157. package/{runAgentClientLoop-37BXJD62.js → runAgentClientLoop-RVB5K6R2.js} +61 -58
  158. package/{runtimeDoctorCommands-X6WDBEQX.js → runtimeDoctorCommands-3USD722U.js} +3 -3
  159. package/runtimeModeArgs-2Y7BALTO.js +31 -0
  160. package/{setDialogExtraReferencesAction-X4HCPNZL.js → setDialogExtraReferencesAction-LYY45IAD.js} +12 -11
  161. package/{setPrimaryDialogAgentAction-4GMIQLOD.js → setPrimaryDialogAgentAction-73IL7DLU.js} +18 -20
  162. package/{settingSlice-ZQZVUPKK.js → settingSlice-Q6EKL7EQ.js} +9 -9
  163. package/{skillDiscovery-CYUCJMAG.js → skillDiscovery-ZBU76COE.js} +3 -3
  164. package/{spaceCommands-P3ONT6LL.js → spaceCommands-BYDGOMW7.js} +44 -40
  165. package/{streamAgentChatTurn-FGXQXALU.js → streamAgentChatTurn-HV3FSRHN.js} +183 -91
  166. package/{switchDialogAgentAction-N52LRPA3.js → switchDialogAgentAction-UUXDSQ6X.js} +15 -17
  167. package/{tableCommands-O6NWHFKV.js → tableCommands-G7RV3RU3.js} +4 -4
  168. package/{toolApiClient-QVJ6HDNN.js → toolApiClient-INIQCPGY.js} +3 -3
  169. package/{tools-R5UF2KZO.js → tools-AZR26MXC.js} +54 -51
  170. package/{tuiSummaryLlmCaller-T2SHYMDZ.js → tuiSummaryLlmCaller-74NRRLVW.js} +18 -16
  171. package/{updateCommands-2M74UL7P.js → updateCommands-4EHDLF5J.js} +3 -3
  172. package/{updateDialogTitleAction-RTADGV7A.js → updateDialogTitleAction-HEWCCXZZ.js} +81 -43
  173. package/agentRecordCommands-SIPURU2S.js +0 -128
  174. package/chunk-FOWEGIMF.js +0 -18881
  175. package/chunk-M76ECQRD.js +0 -13658
  176. package/chunk-Q5FJJ6XI.js +0 -103
  177. package/chunk-S7Z2HMCN.js +0 -25
  178. package/{chunk-VMFTFOWF.js → chunk-3AH7LNUB.js} +7 -7
  179. package/{chunk-X7HHHIOZ.js → chunk-Y6ROFCZO.js} +0 -0
  180. package/{db-WK5MDZVN.js → db-VQSAOWAO.js} +1 -1
@@ -1,3 +1,8 @@
1
+ import {
2
+ DEVIN_CONNECT_URL,
3
+ parseSseDataLineJson,
4
+ parseSseDataLineObject
5
+ } from "./chunk-P6GMCCAT.js";
1
6
  import {
2
7
  applyChatCompletionDelta,
3
8
  applyResponsesToolEvent,
@@ -5,13 +10,15 @@ import {
5
10
  finalizeResponsesToolCalls,
6
11
  flushChatCompletionStream,
7
12
  providerHttpFailure,
8
- readSseFrames,
9
- streamSseDataValues,
10
13
  throwIfChatCompletionStreamFailed
11
- } from "./chunk-OF7AQZUG.js";
14
+ } from "./chunk-TU5NE4U3.js";
12
15
  import {
13
- DEVIN_CONNECT_URL
14
- } from "./chunk-Q5FJJ6XI.js";
16
+ readSseFrames
17
+ } from "./chunk-GMZLP5DV.js";
18
+ import {
19
+ evaluateFileWritePolicy,
20
+ summarizeToolArguments
21
+ } from "./chunk-CHOZJMJS.js";
15
22
  import {
16
23
  clipToolText,
17
24
  hasImageInRuntimeMessages,
@@ -20,13 +27,16 @@ import {
20
27
  resolveHistoricalToolContentCap,
21
28
  resolveToolOutputProfile,
22
29
  stripImagePartsFromMessages
23
- } from "./chunk-3IIEFNGY.js";
30
+ } from "./chunk-C53ZG23R.js";
24
31
  import {
25
32
  downgradeUnparsableToolCalls,
26
33
  hasParsableObjectArguments,
27
34
  repairTruncatedToolArguments,
28
35
  sanitizeForOutbound
29
36
  } from "./chunk-CQ3WA2NE.js";
37
+ import {
38
+ buildDialogFallbackTitleFromUserInput
39
+ } from "./chunk-2MBTWINN.js";
30
40
  import {
31
41
  createThinkParserState,
32
42
  createToolCallAccumulator,
@@ -35,16 +45,19 @@ import {
35
45
  finalizeAccumulatedToolCalls
36
46
  } from "./chunk-N7J63Q6C.js";
37
47
  import {
48
+ DELETE_SAFETY_RED_LINE,
38
49
  TOOL_GUIDED_SECTION_ORDER,
39
50
  buildIdentityBlock,
40
51
  buildRuntimeGuidanceBlocks,
52
+ detectDispatchIntent,
53
+ detectDispatchIntentFromMessages,
41
54
  estimateContextTokens,
42
55
  hashStablePrefixContent,
43
56
  normalizeChatCompletionsBodyForProvider,
44
57
  requiresBareImageUrl,
45
58
  resolveToolGuidedSections,
46
59
  toBareImageUrlMessages
47
- } from "./chunk-OA6Q2A4I.js";
60
+ } from "./chunk-A7RSPKU6.js";
48
61
  import {
49
62
  convertMessagesToResponsesInput,
50
63
  extractReasoningFromResponseOutput,
@@ -62,25 +75,18 @@ import {
62
75
  applyToolSurfaceConstraints,
63
76
  buildDialogReadEnvelope,
64
77
  buildNoloWorkspaceCommandArgs,
78
+ buildNoloWorkspaceOpenAiTools,
65
79
  createStreamingDialogReadProjector,
66
80
  noloPositiveIntegerString,
67
81
  noloStringArg,
68
82
  parseNoloWorkspaceToolArguments,
69
83
  readTextStreamUpToChars,
70
84
  resolveNoloDialogInput
71
- } from "./chunk-IIVGDG4I.js";
72
- import {
73
- getAntigravityUserAgent,
74
- readAntigravityProjectId,
75
- resolveAntigravityCloudCodeBaseUrl
76
- } from "./chunk-UZGQNTVW.js";
85
+ } from "./chunk-LNPYTNMG.js";
77
86
  import {
78
87
  buildProviderAuthHeaders,
79
88
  buildProviderExecutionPlan
80
- } from "./chunk-6OZ36FXI.js";
81
- import {
82
- buildDialogFallbackTitleFromUserInput
83
- } from "./chunk-2MBTWINN.js";
89
+ } from "./chunk-27ONFIEY.js";
84
90
  import {
85
91
  EMPTY_ASSISTANT_REPAIR_PROMPT,
86
92
  getModelContextWindow,
@@ -91,13 +97,12 @@ import {
91
97
  resolveEmptyAssistantFallbackMessage,
92
98
  resolveEmptyAssistantOutcome,
93
99
  resolveTruncatedReasoningTailLog
94
- } from "./chunk-JAXOVNM4.js";
100
+ } from "./chunk-WILHZY7K.js";
95
101
  import {
96
102
  COMPACTION_SUMMARY_SCHEMA_VERSION,
97
103
  COMPACTION_SUMMARY_SYSTEM_PROMPT,
98
104
  buildCompactionMetricsFromPlan,
99
105
  buildCompactionUserContent,
100
- clipCompactText,
101
106
  createProviderCallTimingTracker,
102
107
  finalizeProviderCallTiming,
103
108
  formatCompactionMetricsLog,
@@ -110,26 +115,29 @@ import {
110
115
  resolveCompressionTriggerRatio,
111
116
  truncateToolOutputForContext,
112
117
  withProviderCallTimingFields
113
- } from "./chunk-WADCY6G6.js";
118
+ } from "./chunk-6ZWMH6TJ.js";
119
+ import {
120
+ clipCompactText
121
+ } from "./chunk-5MMAK75Q.js";
114
122
  import {
115
123
  estimateTokenCount
116
124
  } from "./chunk-PSCNXBYA.js";
117
- import {
118
- resolveNoloStateDir
119
- } from "./chunk-ONXOABJR.js";
120
125
  import {
121
126
  toErrorMessage
122
127
  } from "./chunk-HNMXYYJR.js";
128
+ import {
129
+ resolveNoloStateDir
130
+ } from "./chunk-HNGRBWYF.js";
123
131
  import {
124
132
  buildDialogSummaryLayer
125
- } from "./chunk-DVINR3PL.js";
133
+ } from "./chunk-HDLLCBRF.js";
126
134
  import {
127
135
  buildUserResponseLanguageContext
128
- } from "./chunk-2GRGFCF6.js";
136
+ } from "./chunk-4VJAC32I.js";
129
137
  import {
130
138
  canonicalizeToolName,
131
139
  canonicalizeToolNames
132
- } from "./chunk-O6OSWFZQ.js";
140
+ } from "./chunk-XUWRURDF.js";
133
141
  import {
134
142
  asRecordOrEmpty
135
143
  } from "./chunk-KX6YBIHG.js";
@@ -137,7 +145,7 @@ import {
137
145
  asTrimmedNonEmptyStringArray,
138
146
  dialogMessageKey,
139
147
  dialogMessageRange
140
- } from "./chunk-VMFTFOWF.js";
148
+ } from "./chunk-3AH7LNUB.js";
141
149
  import {
142
150
  asOptionalFiniteNumber
143
151
  } from "./chunk-WWC7I6TA.js";
@@ -11898,6 +11906,7 @@ var toQueue = /* @__PURE__ */ dual(2, (self, options) => toQueueArray(self.chann
11898
11906
  var runIntoQueue = /* @__PURE__ */ dual(2, (self, queue) => runIntoQueueArray(self.channel, queue));
11899
11907
 
11900
11908
  // packages/agent-runtime/abortableKernel.ts
11909
+ var IDLE_WATCHDOG_SLICES = 20;
11901
11910
  function runAbortableWithTimeout(args2) {
11902
11911
  const taskEffect = Effect_exports.callback(
11903
11912
  (resume) => {
@@ -11933,12 +11942,26 @@ function runAbortableWithTimeout(args2) {
11933
11942
  raced = Effect_exports.raceFirst(taskEffect, abortEffect);
11934
11943
  }
11935
11944
  if (typeof args2.timeoutMs === "number") {
11936
- const inner = raced;
11945
+ const outer = raced;
11937
11946
  const timeoutMs = args2.timeoutMs;
11938
- raced = Effect_exports.gen(function* () {
11939
- const outcome = yield* Effect_exports.timeoutOption(inner, Duration_exports.millis(timeoutMs));
11940
- return Option_exports.isNone(outcome) ? { kind: "timeout" } : outcome.value;
11947
+ const activityVersion = args2.activityVersion;
11948
+ const idleWatchdog = Effect_exports.gen(function* () {
11949
+ const sliceCount = activityVersion ? IDLE_WATCHDOG_SLICES : 1;
11950
+ const baseSliceMs = Math.max(1, Math.floor(timeoutMs / sliceCount));
11951
+ let idleMs = 0;
11952
+ for (; ; ) {
11953
+ const versionAtSliceStart = activityVersion?.();
11954
+ const sliceMs = Math.max(1, Math.min(timeoutMs - idleMs, baseSliceMs));
11955
+ yield* Effect_exports.sleep(Duration_exports.millis(sliceMs));
11956
+ idleMs += sliceMs;
11957
+ if (activityVersion && activityVersion() !== versionAtSliceStart) {
11958
+ idleMs = 0;
11959
+ continue;
11960
+ }
11961
+ if (idleMs >= timeoutMs) return { kind: "timeout" };
11962
+ }
11941
11963
  });
11964
+ raced = Effect_exports.raceFirst(outer, idleWatchdog);
11942
11965
  }
11943
11966
  return args2.runtime ? args2.runtime.runPromise(raced) : Effect_exports.runPromise(raced);
11944
11967
  }
@@ -12037,26 +12060,6 @@ function createLocalLoopObservationBoundary(initialCallbacks) {
12037
12060
  };
12038
12061
  }
12039
12062
 
12040
- // packages/agent-runtime/fileWritePolicy.ts
12041
- function evaluateFileWritePolicy(args2) {
12042
- if (args2.sessionApproved) return { permissionDecision: "allow" };
12043
- return {
12044
- permissionDecision: "ask",
12045
- permissionRequest: {
12046
- id: "permission-file-write-session",
12047
- tool: args2.tool,
12048
- action: "file_write",
12049
- title: "\u786E\u8BA4\u5199\u5165\u6587\u4EF6",
12050
- body: `\u672C\u4F1A\u8BDD\u9996\u6B21\u5199\u5165\u6587\u4EF6\uFF1A${args2.path}\u3002\u6279\u51C6\u540E\u672C\u4F1A\u8BDD\u540E\u7EED\u5199\u5165\u4E0D\u518D\u9010\u6B21\u786E\u8BA4\u3002`,
12051
- command: args2.path,
12052
- suggestedRule: {
12053
- scope: "session",
12054
- pattern: { capability: "file_write", target: "session" }
12055
- }
12056
- }
12057
- };
12058
- }
12059
-
12060
12063
  // packages/agent-runtime/toolCallPairing.ts
12061
12064
  function readToolCallId(message) {
12062
12065
  if (typeof message.tool_call_id === "string" && message.tool_call_id) {
@@ -12158,50 +12161,6 @@ function sanitizeToolCallPairing(messages) {
12158
12161
  return output;
12159
12162
  }
12160
12163
 
12161
- // packages/agent-runtime/parseToolArguments.ts
12162
- function parseToolArgumentsJson(raw) {
12163
- if (!raw?.trim()) return {};
12164
- try {
12165
- return asRecordOrEmpty(JSON.parse(raw));
12166
- } catch {
12167
- return {};
12168
- }
12169
- }
12170
-
12171
- // packages/agent-runtime/summarizeToolArguments.ts
12172
- function clip(value, max4 = 240) {
12173
- return clipCompactText(value, max4);
12174
- }
12175
- function summarizeToolArguments(toolName, rawArgs) {
12176
- const args2 = parseToolArgumentsJson(rawArgs);
12177
- const pick = (...keys3) => {
12178
- for (const key of keys3) {
12179
- const value = asOptionalTrimmedString(args2[key]);
12180
- if (value) return value;
12181
- }
12182
- return "";
12183
- };
12184
- const command = pick("command", "cmd", "runCommand", "executeCommand", "bash");
12185
- if (command) return clip(command);
12186
- const query = pick("query", "pattern", "search", "q");
12187
- if (query) return clip(query);
12188
- const filePath = pick("filePath", "file_path", "path", "filename", "file");
12189
- if (filePath) return clip(filePath);
12190
- const keys2 = Object.keys(args2);
12191
- if (keys2.length === 0) return "";
12192
- return clip(
12193
- keys2.slice(0, 6).map((key) => {
12194
- const value = args2[key];
12195
- if (typeof value === "string") return `${key}=${clip(value, 80)}`;
12196
- if (typeof value === "number" || typeof value === "boolean") {
12197
- return `${key}=${String(value)}`;
12198
- }
12199
- if (Array.isArray(value)) return `${key}[${value.length}]`;
12200
- return `${key}=${value === null ? "null" : typeof value}`;
12201
- }).join(" ")
12202
- );
12203
- }
12204
-
12205
12164
  // packages/agent-runtime/progressGuard.ts
12206
12165
  var DEFAULT_MAX_CONSECUTIVE_IDENTICAL_ROUNDS = 5;
12207
12166
  var DEFAULT_MAX_CONSECUTIVE_STAGNANT_TOOL_ROUNDS = 8;
@@ -12625,20 +12584,40 @@ function isColdResume(history, nowMs) {
12625
12584
  }
12626
12585
  async function maybeAutoCompactLocalHistory(args2) {
12627
12586
  const { adapter, dialogId, history } = args2;
12628
- const unchanged = () => ({
12587
+ const emitPhase = (phase) => {
12588
+ try {
12589
+ args2.onPhase?.(phase);
12590
+ } catch {
12591
+ }
12592
+ };
12593
+ emitPhase({ kind: "validating-context" });
12594
+ const unchanged = (decision) => ({
12629
12595
  history,
12630
12596
  compressed: false,
12631
- summaryGenerated: false
12597
+ summaryGenerated: false,
12598
+ decision
12632
12599
  });
12633
- if (!dialogId || history.length === 0 || typeof adapter.loadDialogSummary !== "function" || typeof adapter.saveDialogSummary !== "function") {
12634
- return unchanged();
12600
+ if (!dialogId) {
12601
+ return unchanged({ outcome: "skipped", skipReason: "no-dialog-id" });
12602
+ }
12603
+ if (history.length === 0) {
12604
+ return unchanged({ outcome: "skipped", skipReason: "empty-history" });
12605
+ }
12606
+ if (typeof adapter.loadDialogSummary !== "function" || typeof adapter.saveDialogSummary !== "function") {
12607
+ return unchanged({
12608
+ outcome: "skipped",
12609
+ skipReason: "adapter-missing-summary-methods"
12610
+ });
12635
12611
  }
12636
12612
  let stored = null;
12637
12613
  try {
12638
12614
  stored = await adapter.loadDialogSummary(dialogId);
12639
12615
  } catch (error) {
12640
12616
  console.warn("[localLoop] loadDialogSummary failed:", error);
12641
- return unchanged();
12617
+ return unchanged({
12618
+ outcome: "skipped",
12619
+ skipReason: "load-summary-failed"
12620
+ });
12642
12621
  }
12643
12622
  const bridged = toPlanCompressionMessages(history);
12644
12623
  const validation = validateStoredSummary({ history, stored: stored ?? {} });
@@ -12674,7 +12653,21 @@ async function maybeAutoCompactLocalHistory(args2) {
12674
12653
  ...args2.realContextUsagePercent !== void 0 ? { realContextUsagePercent: args2.realContextUsagePercent } : {}
12675
12654
  });
12676
12655
  const projectExisting = () => {
12677
- if (!existingSummary.trim()) return unchanged();
12656
+ const diag = plan.diagnostics;
12657
+ const diagSnapshot = diag ? {
12658
+ estimatedTokens: diag.totalUsed,
12659
+ historyBudget: diag.historyBudget,
12660
+ triggerRatio: diag.triggerRatio,
12661
+ ...diag.realUsageRatio !== void 0 ? { realUsageRatio: diag.realUsageRatio } : {}
12662
+ } : {};
12663
+ const skippedDecision = {
12664
+ outcome: "skipped",
12665
+ skipReason: diag?.emptyReason === "no-pending" ? "no-pending" : diag?.emptyReason === "below-min-compress-count" ? "below-min-compress-count" : "below-trigger",
12666
+ ...diagSnapshot,
12667
+ ...diag ? { pendingMsgCount: diag.pendingMsgCount } : {},
12668
+ ...diag?.compressCount !== void 0 ? { compressCount: diag.compressCount } : {}
12669
+ };
12670
+ if (!existingSummary.trim()) return unchanged(skippedDecision);
12678
12671
  return {
12679
12672
  history: projectHistoryWithSummary({
12680
12673
  history,
@@ -12682,14 +12675,26 @@ async function maybeAutoCompactLocalHistory(args2) {
12682
12675
  summarizedBeforeId
12683
12676
  }),
12684
12677
  compressed: true,
12685
- summaryGenerated: false
12678
+ summaryGenerated: false,
12679
+ decision: {
12680
+ outcome: "compressed",
12681
+ trigger: "existing-summary",
12682
+ ...diagSnapshot
12683
+ }
12686
12684
  };
12687
12685
  };
12688
12686
  if (!plan.shouldCompress) {
12689
12687
  return projectExisting();
12690
12688
  }
12689
+ emitPhase({ kind: "compaction-start" });
12691
12690
  try {
12691
+ if (args2.abortSignal?.aborted) {
12692
+ throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
12693
+ }
12692
12694
  const provider = await args2.resolveProvider();
12695
+ if (args2.abortSignal?.aborted) {
12696
+ throw Object.assign(new Error("auto-compaction aborted"), { compactionReason: "aborted" });
12697
+ }
12693
12698
  const msgsToCompress = plan.msgsToCompress;
12694
12699
  const messagesText = formatMessagesForSummaryWithTruncation(msgsToCompress);
12695
12700
  const fileOpsText = formatFileOperationsFromMessages(
@@ -12701,18 +12706,57 @@ async function maybeAutoCompactLocalHistory(args2) {
12701
12706
  messagesText,
12702
12707
  fileOpsText
12703
12708
  });
12704
- const result4 = await provider.complete([
12705
- { role: "system", content: COMPACTION_SUMMARY_SYSTEM_PROMPT },
12706
- { role: "user", content: promptContent }
12707
- ]);
12709
+ emitPhase({ kind: "waiting-provider" });
12710
+ const timeoutMs = typeof args2.timeoutMs === "number" && Number.isFinite(args2.timeoutMs) && args2.timeoutMs > 0 ? args2.timeoutMs : void 0;
12711
+ const requestController = new AbortController();
12712
+ let timeoutHandle;
12713
+ let abortListener;
12714
+ const request3 = provider.complete(
12715
+ [{ role: "system", content: COMPACTION_SUMMARY_SYSTEM_PROMPT }, { role: "user", content: promptContent }],
12716
+ { signal: requestController.signal, ...timeoutMs ? { timeoutMs } : {} }
12717
+ ).then(
12718
+ (value) => ({ kind: "done", value }),
12719
+ (error) => ({ kind: "provider-error", error })
12720
+ );
12721
+ const guards = [];
12722
+ if (timeoutMs) guards.push(new Promise((resolve5) => {
12723
+ timeoutHandle = setTimeout(() => {
12724
+ requestController.abort();
12725
+ resolve5({ kind: "timeout" });
12726
+ }, timeoutMs);
12727
+ }));
12728
+ if (args2.abortSignal) guards.push(new Promise((resolve5) => {
12729
+ abortListener = () => {
12730
+ requestController.abort(args2.abortSignal?.reason);
12731
+ resolve5({ kind: "aborted" });
12732
+ };
12733
+ args2.abortSignal?.addEventListener("abort", abortListener, { once: true });
12734
+ }));
12735
+ const outcome = guards.length ? await Promise.race([request3, ...guards]) : await request3;
12736
+ if (timeoutHandle) clearTimeout(timeoutHandle);
12737
+ if (abortListener) args2.abortSignal?.removeEventListener("abort", abortListener);
12738
+ if (outcome.kind !== "done") {
12739
+ const reason = outcome.kind === "timeout" ? "timeout" : outcome.kind === "aborted" ? "aborted" : "provider-error";
12740
+ const detail = outcome.kind === "provider-error" ? outcome.error instanceof Error ? outcome.error.message : String(outcome.error) : reason === "timeout" ? `auto-compaction timed out after ${timeoutMs}ms` : "auto-compaction aborted";
12741
+ throw Object.assign(new Error(detail), { compactionReason: reason });
12742
+ }
12743
+ const result4 = outcome.value;
12708
12744
  const newSummary = typeof result4.content === "string" ? result4.content.trim() : "";
12709
12745
  if (!newSummary) {
12710
12746
  console.warn(
12711
12747
  "[localLoop] auto-compaction produced empty summary; keeping prior projection"
12712
12748
  );
12749
+ const failureReason = "provider-error";
12750
+ emitPhase({ kind: "compaction-failed", reason: failureReason });
12713
12751
  return {
12714
12752
  ...projectExisting(),
12715
- failureMessage: "summary model returned empty content"
12753
+ failureMessage: "summary model returned empty content",
12754
+ failureReason,
12755
+ decision: {
12756
+ outcome: "failed",
12757
+ reason: failureReason,
12758
+ detail: "summary model returned empty content"
12759
+ }
12716
12760
  };
12717
12761
  }
12718
12762
  await adapter.saveDialogSummary({
@@ -12737,6 +12781,7 @@ async function maybeAutoCompactLocalHistory(args2) {
12737
12781
  summaryUsage: result4.usage
12738
12782
  });
12739
12783
  console.log(formatCompactionMetricsLog(metrics));
12784
+ emitPhase({ kind: "compaction-end" });
12740
12785
  return {
12741
12786
  history: projectHistoryWithSummary({
12742
12787
  history,
@@ -12749,12 +12794,29 @@ async function maybeAutoCompactLocalHistory(args2) {
12749
12794
  beforeTokens: metrics.previousSummaryTokens + metrics.compressedTokens,
12750
12795
  afterTokens: metrics.newSummaryTokens + metrics.retainedTokens,
12751
12796
  ...result4.usage ? { usage: result4.usage } : {},
12752
- metrics
12797
+ metrics,
12798
+ decision: {
12799
+ outcome: "compressed",
12800
+ trigger: invalidSummary ? "invalid-summary" : coldResume ? "cold-resume" : plan.diagnostics?.triggeredByRealUsage ? "real-usage" : "estimate",
12801
+ ...plan.diagnostics ? {
12802
+ estimatedTokens: plan.diagnostics.totalUsed,
12803
+ historyBudget: plan.diagnostics.historyBudget,
12804
+ triggerRatio: plan.diagnostics.triggerRatio,
12805
+ ...plan.diagnostics.realUsageRatio !== void 0 ? { realUsageRatio: plan.diagnostics.realUsageRatio } : {}
12806
+ } : {}
12807
+ }
12753
12808
  };
12754
12809
  } catch (error) {
12755
12810
  console.warn("[localLoop] auto-compaction failed:", error);
12756
12811
  const failureMessage = error instanceof Error && error.message ? error.message.slice(0, 200) : String(error).slice(0, 200);
12757
- return { ...projectExisting(), failureMessage };
12812
+ const failureReason = error instanceof Error && "compactionReason" in error ? error.compactionReason : "provider-error";
12813
+ emitPhase({ kind: "compaction-failed", reason: failureReason });
12814
+ return {
12815
+ ...projectExisting(),
12816
+ failureMessage,
12817
+ failureReason,
12818
+ decision: { outcome: "failed", reason: failureReason, detail: failureMessage }
12819
+ };
12758
12820
  }
12759
12821
  }
12760
12822
 
@@ -12810,6 +12872,8 @@ function emitLoopEvent(boundary, event, bridge) {
12810
12872
  boundary.emit(bridge ? { event, bridge } : { event });
12811
12873
  }
12812
12874
  var LLM_REQUEST_TIMEOUT = "LLM_REQUEST_TIMEOUT";
12875
+ var DEFAULT_LLM_REQUEST_TIMEOUT_MS = 10 * 60 * 1e3;
12876
+ var DEFAULT_COMPACTION_TIMEOUT_MS = 60 * 1e3;
12813
12877
  var LOCAL_TURN_ABORTED_CODE = "LOCAL_TURN_ABORTED";
12814
12878
  function buildAbortedError() {
12815
12879
  const error = new Error("local agent turn aborted by user");
@@ -12837,8 +12901,11 @@ async function runAbortableToolTask(input, task, pendingToolName) {
12837
12901
  }
12838
12902
  function resolveLlmRequestTimeoutMs(input) {
12839
12903
  const raw = input.llmRequestTimeoutMs ?? input.timeoutMs;
12840
- if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) return void 0;
12841
- return raw;
12904
+ return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_LLM_REQUEST_TIMEOUT_MS;
12905
+ }
12906
+ function resolveCompactionTimeoutMs(input) {
12907
+ const raw = input.compactionTimeoutMs;
12908
+ return typeof raw === "number" && Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_COMPACTION_TIMEOUT_MS;
12842
12909
  }
12843
12910
  async function runCompleteWithTimeout(args2) {
12844
12911
  const { provider, messages, options, timeoutMs, round, input, boundary, context: context3, providerName, model } = args2;
@@ -12861,6 +12928,7 @@ async function runCompleteWithTimeout(args2) {
12861
12928
  const outcome = await runAbortableWithTimeout({
12862
12929
  task: complete,
12863
12930
  timeoutMs: typeof timeoutMs === "number" ? timeoutMs : void 0,
12931
+ activityVersion: args2.activityVersion,
12864
12932
  abortSignal: input.abortSignal,
12865
12933
  runtime: input.effectRuntime
12866
12934
  });
@@ -12871,7 +12939,7 @@ async function runCompleteWithTimeout(args2) {
12871
12939
  }
12872
12940
  if (outcome.kind === "timeout") {
12873
12941
  const timeoutError = new Error(
12874
- `LLM request timed out after ${timeoutMs}ms (round ${round})`
12942
+ `LLM request timed out after ${timeoutMs}ms without new output (idle window, round ${round})`
12875
12943
  );
12876
12944
  timeoutError.code = LLM_REQUEST_TIMEOUT;
12877
12945
  throw timeoutError;
@@ -12915,16 +12983,16 @@ async function runCompleteWithTimeout(args2) {
12915
12983
  });
12916
12984
  }
12917
12985
  }
12918
- function clip2(value, max4 = 240) {
12986
+ function clip(value, max4 = 240) {
12919
12987
  return clipCompactText(value, max4);
12920
12988
  }
12921
12989
  function projectSafeToolObservationMetadata(metadata) {
12922
12990
  if (!metadata || typeof metadata !== "object") return void 0;
12923
12991
  const safe = {};
12924
12992
  if (typeof metadata.exitCode === "number") safe.exitCode = metadata.exitCode;
12925
- if (typeof metadata.actionGate === "string") safe.actionGate = clip2(metadata.actionGate, 240);
12926
- if (typeof metadata.command === "string") safe.command = clip2(metadata.command, 240);
12927
- if (typeof metadata.path === "string") safe.path = clip2(metadata.path, 240);
12993
+ if (typeof metadata.actionGate === "string") safe.actionGate = clip(metadata.actionGate, 240);
12994
+ if (typeof metadata.command === "string") safe.command = clip(metadata.command, 240);
12995
+ if (typeof metadata.path === "string") safe.path = clip(metadata.path, 240);
12928
12996
  if (typeof metadata.truncated === "boolean") safe.truncated = metadata.truncated;
12929
12997
  if (typeof metadata.byteCount === "number") safe.byteCount = metadata.byteCount;
12930
12998
  if (typeof metadata.lineCount === "number") safe.lineCount = metadata.lineCount;
@@ -12940,7 +13008,7 @@ function summarizeToolResult(content, metadata) {
12940
13008
  const lines = trimmed.split(/\r?\n/).length;
12941
13009
  parts2.push(`${lines} line${lines === 1 ? "" : "s"}`);
12942
13010
  parts2.push(`${trimmed.length} chars`);
12943
- const tail = clip2(trimmed.slice(-160), 160);
13011
+ const tail = clip(trimmed.slice(-160), 160);
12944
13012
  if (tail) parts2.push(`tail="${tail}"`);
12945
13013
  } else {
12946
13014
  parts2.push("empty");
@@ -13529,7 +13597,14 @@ async function runLocalAgentTurn(input) {
13529
13597
  agentConfig.exposedToolNames ?? agentConfig.toolNames ?? []
13530
13598
  );
13531
13599
  const guidanceBlocks = buildRuntimeGuidanceBlocks(agentTools);
13532
- const toolGuidedSections = resolveToolGuidedSections(agentTools);
13600
+ const toolGuidedSections = resolveToolGuidedSections(agentTools, {
13601
+ // 单调锁定:历史里任一 user 消息命中派发关键词、或已出现过
13602
+ // startAgentRun/controlAgentRun 的 tool_calls,后续每轮都保持 true,
13603
+ // 防止 session-scope 的 agentCollaboration 段逐轮翻转击穿前缀缓存。
13604
+ dispatchIntent: detectDispatchIntentFromMessages(history) || detectDispatchIntent(
13605
+ typeof input.input === "string" ? input.input : void 0
13606
+ )
13607
+ });
13533
13608
  const guidanceScopes = [
13534
13609
  ...input.userLanguage?.trim() ? [buildUserResponseLanguageContext({ language: input.userLanguage })] : [],
13535
13610
  guidanceBlocks.startupProtocol,
@@ -13545,6 +13620,9 @@ async function runLocalAgentTurn(input) {
13545
13620
  input.contextBlockScopes
13546
13621
  );
13547
13622
  const mergedContextBlockScopes = [
13623
+ // 删除安全红线:系统层最高优先级约束,位于所有块之前(含身份信息块),
13624
+ // owner 要求常驻「根本提示词」的最顶部(2026-09-26 批量误删事故)。
13625
+ { content: DELETE_SAFETY_RED_LINE, cacheScope: "session" },
13548
13626
  { content: identityBlock, cacheScope: "session" },
13549
13627
  ...guidanceScopes,
13550
13628
  ...callerScopes
@@ -13577,20 +13655,40 @@ async function runLocalAgentTurn(input) {
13577
13655
  }
13578
13656
  }
13579
13657
  let compactionUsage;
13658
+ const emitCompactionPhase = (phase, scope3) => {
13659
+ const atMs = Date.now();
13660
+ if (phase.kind === "validating-context") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "validating-context", atMs, compactionScope: scope3 });
13661
+ else if (phase.kind === "compaction-start") {
13662
+ emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "compacting", atMs, compactionScope: scope3 });
13663
+ emitLoopEvent(observationBoundary, { kind: "compaction-start", atMs, scope: scope3 });
13664
+ } else if (phase.kind === "waiting-provider") emitLoopEvent(observationBoundary, { kind: "turn-phase", phase: "waiting-provider", atMs, compactionScope: scope3 });
13665
+ else if (phase.kind === "compaction-end") emitLoopEvent(observationBoundary, { kind: "compaction-end", atMs, scope: scope3 });
13666
+ else emitLoopEvent(observationBoundary, { kind: "compaction-failed", atMs, scope: scope3, reason: phase.reason });
13667
+ };
13580
13668
  const emitCompactionObservation = (compacted) => {
13581
- if (compacted.compressed || compacted.summaryGenerated || compacted.failureMessage) {
13582
- emitLoopEvent(observationBoundary, {
13583
- kind: "compaction",
13584
- atMs: Date.now(),
13585
- reason: compacted.reason ?? "context_budget",
13586
- summaryGenerated: compacted.summaryGenerated,
13587
- compressed: compacted.compressed,
13588
- ...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
13589
- ...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
13590
- ...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
13591
- ...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
13592
- });
13669
+ const decision = compacted.decision;
13670
+ if (decision?.outcome === "skipped") {
13671
+ const isProtectionGap = decision.skipReason === "adapter-missing-summary-methods" || decision.skipReason === "load-summary-failed";
13672
+ const approachingBudget = decision.skipReason === "below-trigger" && typeof decision.estimatedTokens === "number" && typeof decision.historyBudget === "number" && decision.historyBudget > 0 && decision.estimatedTokens >= decision.historyBudget * 0.5;
13673
+ if (!isProtectionGap && !approachingBudget) return;
13593
13674
  }
13675
+ emitLoopEvent(observationBoundary, {
13676
+ kind: "compaction",
13677
+ atMs: Date.now(),
13678
+ ...compacted.reason ? { reason: compacted.reason } : {},
13679
+ summaryGenerated: compacted.summaryGenerated,
13680
+ compressed: compacted.compressed,
13681
+ ...compacted.failureMessage ? { failed: true, detail: compacted.failureMessage } : {},
13682
+ ...decision?.outcome === "skipped" ? { skipped: true, skipReason: decision.skipReason } : {},
13683
+ ...decision && "trigger" in decision && decision.trigger ? { trigger: decision.trigger } : {},
13684
+ ...decision && "estimatedTokens" in decision && decision.estimatedTokens !== void 0 ? { estimatedTokens: decision.estimatedTokens } : {},
13685
+ ...decision && "historyBudget" in decision && decision.historyBudget !== void 0 ? { historyBudget: decision.historyBudget } : {},
13686
+ ...decision && "realUsageRatio" in decision && decision.realUsageRatio !== void 0 ? { realUsageRatio: decision.realUsageRatio } : {},
13687
+ ...decision && "triggerRatio" in decision && decision.triggerRatio !== void 0 ? { triggerRatio: decision.triggerRatio } : {},
13688
+ ...compacted.beforeTokens !== void 0 ? { beforeTokens: compacted.beforeTokens } : {},
13689
+ ...compacted.afterTokens !== void 0 ? { afterTokens: compacted.afterTokens } : {},
13690
+ ...compacted.savedTokens !== void 0 ? { savedTokens: compacted.savedTokens } : {}
13691
+ });
13594
13692
  };
13595
13693
  try {
13596
13694
  const compacted = await maybeAutoCompactLocalHistory({
@@ -13600,7 +13698,10 @@ async function runLocalAgentTurn(input) {
13600
13698
  model: agentConfig.model,
13601
13699
  resolveProvider: resolveProviderOnce,
13602
13700
  contextWindow,
13603
- realContextUsagePercent
13701
+ realContextUsagePercent,
13702
+ abortSignal: input.abortSignal,
13703
+ timeoutMs: resolveCompactionTimeoutMs(input),
13704
+ onPhase: (phase) => emitCompactionPhase(phase, "initial")
13604
13705
  });
13605
13706
  history = compacted.history;
13606
13707
  compactionUsage = compacted.usage;
@@ -13671,17 +13772,26 @@ async function runLocalAgentTurn(input) {
13671
13772
  let skipFinalAppend = false;
13672
13773
  let partialContent = "";
13673
13774
  const progressGuard = createLocalLoopProgressGuard(input.progressGuardConfig);
13775
+ let ephemeralSummary = null;
13776
+ const ephemeralDialogId = `ephemeral-${crypto.randomUUID()}`;
13777
+ const compactionAdapter = input.continueDialogId ? input.adapter : {
13778
+ ...input.adapter,
13779
+ loadDialogSummary: async () => ephemeralSummary,
13780
+ saveDialogSummary: async (summaryInput) => {
13781
+ ephemeralSummary = summaryInput;
13782
+ }
13783
+ };
13784
+ const compactionDialogId = input.continueDialogId ?? ephemeralDialogId;
13674
13785
  const maybeCompactInLoop = async () => {
13675
- if (!input.continueDialogId) return;
13676
- if (!contextUsage) return;
13677
- const inputTokens = normalizeUsage(contextUsage).input_tokens;
13678
- if (!inputTokens || inputTokens <= 0) return;
13679
- const ratio = Math.min(1, inputTokens / contextWindow);
13680
- if (ratio < compressionTriggerRatio) return;
13786
+ const inputTokens = contextUsage ? normalizeUsage(contextUsage).input_tokens : 0;
13787
+ const ratio = inputTokens > 0 ? Math.min(1, inputTokens / contextWindow) : void 0;
13788
+ if (ratio !== void 0 && ratio < compressionTriggerRatio * 0.85) {
13789
+ return;
13790
+ }
13681
13791
  try {
13682
13792
  const compacted = await maybeAutoCompactLocalHistory({
13683
- adapter: input.adapter,
13684
- dialogId: input.continueDialogId,
13793
+ adapter: compactionAdapter,
13794
+ dialogId: compactionDialogId,
13685
13795
  // canonical 坐标:store 全量历史 + 本轮消息的「持久化形态」
13686
13796
  // (applyPersistedTurnInput 会把首条 user 消息换成 paste 展开形态)。
13687
13797
  // 锚点与 sourceHash 都必须按持久化形态计算——否则下轮从 store
@@ -13697,7 +13807,10 @@ async function runLocalAgentTurn(input) {
13697
13807
  model: agentConfig.model,
13698
13808
  resolveProvider: resolveProviderOnce,
13699
13809
  contextWindow,
13700
- realContextUsagePercent: ratio
13810
+ ...ratio !== void 0 ? { realContextUsagePercent: ratio } : {},
13811
+ abortSignal: input.abortSignal,
13812
+ timeoutMs: resolveCompactionTimeoutMs(input),
13813
+ onPhase: (phase) => emitCompactionPhase(phase, "in-loop")
13701
13814
  });
13702
13815
  if (compacted.usage) {
13703
13816
  compactionUsage = addOutOfBandUsage(compactionUsage, compacted.usage);
@@ -13767,11 +13880,12 @@ async function runLocalAgentTurn(input) {
13767
13880
  const shouldPassToolEvents = Boolean(
13768
13881
  input.onToolEvent || input.onObservationEvent || input.observationBoundary
13769
13882
  );
13883
+ let llmStreamActivity = 0;
13770
13884
  result4 = await runCompleteWithTimeout({
13771
13885
  provider,
13772
13886
  messages: requestMessages,
13773
13887
  options: {
13774
- ...typeof input.timeoutMs === "number" ? { timeoutMs: input.timeoutMs } : {},
13888
+ timeoutMs: resolveLlmRequestTimeoutMs(input),
13775
13889
  // 用户取消信号穿进 provider options:providerStreamRetry 据此在
13776
13890
  // 取消后跳过重试,provider 分支(如 antigravity/openai-compatible)
13777
13891
  // 也可把 fetch 绑定到同一信号,实现真正的传输层取消。
@@ -13780,6 +13894,7 @@ async function runLocalAgentTurn(input) {
13780
13894
  // 归到具体对话而不是 chat-proxy 兜底桶。新对话首轮 id 尚未分配。
13781
13895
  ...input.continueDialogId ? { dialogId: input.continueDialogId } : {},
13782
13896
  ...shouldStreamDeltas ? { onTextDelta: (chunk) => {
13897
+ llmStreamActivity += 1;
13783
13898
  partialContent += chunk;
13784
13899
  observationBoundary.emit({
13785
13900
  kind: "text-delta",
@@ -13789,6 +13904,7 @@ async function runLocalAgentTurn(input) {
13789
13904
  });
13790
13905
  } } : {},
13791
13906
  ...shouldStreamReasoning ? { onReasoningDelta: (chunk) => {
13907
+ llmStreamActivity += 1;
13792
13908
  observationBoundary.emit({
13793
13909
  kind: "reasoning-delta",
13794
13910
  chunk,
@@ -13797,6 +13913,7 @@ async function runLocalAgentTurn(input) {
13797
13913
  });
13798
13914
  } } : {},
13799
13915
  ...shouldPassToolEvents ? { onToolEvent: (event) => {
13916
+ llmStreamActivity += 1;
13800
13917
  observationBoundary.emit({
13801
13918
  kind: "tool-event",
13802
13919
  event,
@@ -13807,6 +13924,7 @@ async function runLocalAgentTurn(input) {
13807
13924
  ...shouldPassToolEvents ? { toolEventRound: round } : {}
13808
13925
  },
13809
13926
  timeoutMs: resolveLlmRequestTimeoutMs(input),
13927
+ activityVersion: () => llmStreamActivity,
13810
13928
  round,
13811
13929
  input,
13812
13930
  boundary: observationBoundary,
@@ -14278,33 +14396,6 @@ ${reasoningTailLog}
14278
14396
  }
14279
14397
  }
14280
14398
 
14281
- // packages/agent-runtime/kimiUserAgent.ts
14282
- var KIMI_CODE_CLI_VERSION = "0.29.2";
14283
- var KIMI_CODE_USER_AGENT = `kimi-code-cli/${KIMI_CODE_CLI_VERSION} (nolo)`;
14284
- function isKimiEndpoint(url) {
14285
- return url.includes("api.kimi.com");
14286
- }
14287
- function kimiIdentityHeaders(url) {
14288
- return isKimiEndpoint(url) ? { "User-Agent": KIMI_CODE_USER_AGENT } : {};
14289
- }
14290
-
14291
- // packages/agent-runtime/sseDataLine.ts
14292
- function parseSseDataLineJson(line) {
14293
- const trimmed = line.trim();
14294
- if (!trimmed.startsWith("data:")) return null;
14295
- const payload = trimmed.slice(5).trim();
14296
- if (!payload || payload === "[DONE]") return null;
14297
- try {
14298
- return JSON.parse(payload);
14299
- } catch {
14300
- return null;
14301
- }
14302
- }
14303
- function parseSseDataLineObject(line) {
14304
- const parsed = parseSseDataLineJson(line);
14305
- return parsed && typeof parsed === "object" ? parsed : null;
14306
- }
14307
-
14308
14399
  // packages/integrations/openai/responsesRequestBody.ts
14309
14400
  function buildResponsesRequestBody(body, model) {
14310
14401
  const tools = Array.isArray(body.tools) ? toResponsesTools(body.tools) : void 0;
@@ -14527,9 +14618,9 @@ function buildOpenAiCompatibleChatCompletionRequest(args2) {
14527
14618
  ...buildProviderAuthHeaders({
14528
14619
  endpoint,
14529
14620
  apiKey: args2.providerConfig.apiKey,
14530
- apiKeyHeader: args2.providerConfig.apiKeyHeader
14531
- }),
14532
- ...kimiIdentityHeaders(endpoint)
14621
+ apiKeyHeader: args2.providerConfig.apiKeyHeader,
14622
+ sessionId: args2.sessionId
14623
+ })
14533
14624
  };
14534
14625
  return {
14535
14626
  url: endpoint,
@@ -14632,7 +14723,8 @@ async function executeOpenAiCompatibleChatCompletion(args2) {
14632
14723
  providerConfig: apiKey2 === args2.providerConfig.apiKey ? args2.providerConfig : { ...args2.providerConfig, apiKey: apiKey2 },
14633
14724
  messages: args2.messages,
14634
14725
  tools: args2.tools,
14635
- stream: args2.stream
14726
+ stream: args2.stream,
14727
+ sessionId: args2.sessionId
14636
14728
  });
14637
14729
  return args2.fetchImpl(request3.url, {
14638
14730
  ...request3.init,
@@ -15574,132 +15666,6 @@ async function evaluateCapabilityPolicy(capability, normalizedInput, ctx) {
15574
15666
  }
15575
15667
  }
15576
15668
 
15577
- // packages/agent-runtime/localToolPolicy.ts
15578
- var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
15579
- "deleteSpaces",
15580
- "updateAgent",
15581
- "updateSelf",
15582
- "createAgent"
15583
- ]);
15584
- var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
15585
- "readFile",
15586
- "writeFile",
15587
- "editFile",
15588
- "globFiles",
15589
- "execShell",
15590
- "launchProcess",
15591
- "listProcesses",
15592
- // ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
15593
- // tasks the agent itself already spawned, so their blast radius is strictly
15594
- // narrower than launchProcess (which is default-enabled). Model-facing
15595
- // follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
15596
- // runtime-internal.
15597
- "taskWait",
15598
- "taskStop",
15599
- // Scheduling tools: forking/observing sub-agents is a declared capability
15600
- // of capable agents, and the blast radius is strictly narrower than
15601
- // execShell (already default-enabled). Requiring an env allowlist for these
15602
- // while execShell is open by default inverted the risk model and forced every
15603
- // new local user to hand-edit .env files before sub-agent tasks worked.
15604
- "startAgentRun",
15605
- "controlAgentRun"
15606
- ]);
15607
- function parseToolAllowlist(value) {
15608
- return (value ?? "").split(",").flatMap((item) => {
15609
- const trimmed = item.trim();
15610
- return trimmed ? [trimmed] : [];
15611
- });
15612
- }
15613
- function normalizeLocalToolName(toolName) {
15614
- return canonicalizeToolName(
15615
- String(toolName ?? "").replace(/^functions\./, "").trim()
15616
- );
15617
- }
15618
- function isRestrictedLocalToolMode(env) {
15619
- return env.NOLO_LOCAL_TOOL_MODE === "restricted";
15620
- }
15621
- function resolveLocalToolPolicy(args2) {
15622
- const toolName = normalizeLocalToolName(args2.toolName);
15623
- const restrictedMode = isRestrictedLocalToolMode(args2.env);
15624
- if (!toolName) {
15625
- return {
15626
- allowed: false,
15627
- toolName,
15628
- reason: "Tool name is required."
15629
- };
15630
- }
15631
- if (NEVER_LOCAL_TOOLS.has(toolName)) {
15632
- return {
15633
- allowed: false,
15634
- toolName,
15635
- reason: `${toolName} is blocked by the local runtime safety policy.`
15636
- };
15637
- }
15638
- const allowedByEnv = new Set(parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS));
15639
- const agentTools = new Set(
15640
- (args2.agentToolNames ?? []).flatMap((item) => {
15641
- const normalized = normalizeLocalToolName(item);
15642
- return normalized ? [normalized] : [];
15643
- })
15644
- );
15645
- if (!restrictedMode && agentTools.has(toolName)) {
15646
- return { allowed: true, toolName };
15647
- }
15648
- if (DEFAULT_LOCAL_TOOLS.has(toolName) && agentTools.has(toolName)) {
15649
- return { allowed: true, toolName };
15650
- }
15651
- if (allowedByEnv.has(toolName) && agentTools.has(toolName)) {
15652
- return { allowed: true, toolName };
15653
- }
15654
- return {
15655
- allowed: false,
15656
- toolName,
15657
- reason: `${toolName} is not enabled for local runtime runs. The agent must declare the tool in its manifest; in restricted mode (NOLO_LOCAL_TOOL_MODE=restricted) non-default tools also require adding to NOLO_LOCAL_ALLOWED_TOOLS (e.g. NOLO_LOCAL_ALLOWED_TOOLS=someCustomTool) and restarting the session so the env var loads.`
15658
- };
15659
- }
15660
- async function executeLocalToolWithPolicy(args2) {
15661
- if (args2.runToolNames !== void 0 && !args2.runToolNames.includes(normalizeLocalToolName(args2.call.name))) {
15662
- throw new Error(`${args2.call.name} is outside the final run tool surface.`);
15663
- }
15664
- const decision = resolveLocalToolPolicy({
15665
- env: args2.env,
15666
- agentToolNames: args2.agentToolNames,
15667
- toolName: args2.call.name
15668
- });
15669
- if (!decision.allowed) throw new Error(decision.reason);
15670
- const executor = args2.executors?.[decision.toolName];
15671
- if (!executor) {
15672
- throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
15673
- }
15674
- const opts = {
15675
- ...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
15676
- ...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
15677
- ...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
15678
- ...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
15679
- ...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
15680
- ...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
15681
- };
15682
- if (decision.toolName === "execShell") {
15683
- let parsedInput = args2.call.arguments;
15684
- if (typeof parsedInput === "string") {
15685
- try {
15686
- parsedInput = JSON.parse(parsedInput);
15687
- } catch {
15688
- parsedInput = { command: parsedInput };
15689
- }
15690
- }
15691
- await evaluateExecShellDestructiveGuard(parsedInput, opts);
15692
- opts.confirmed = true;
15693
- }
15694
- return executor(
15695
- {
15696
- ...args2.call,
15697
- name: decision.toolName
15698
- },
15699
- opts
15700
- );
15701
- }
15702
-
15703
15669
  // packages/agent-runtime/localWorkspaceTools.ts
15704
15670
  import { existsSync as existsSync3 } from "node:fs";
15705
15671
  import { createHash as createHash3 } from "node:crypto";
@@ -16498,29 +16464,6 @@ function getProcessRegistry() {
16498
16464
  return registry;
16499
16465
  }
16500
16466
 
16501
- // packages/agent-runtime/processOwnership.ts
16502
- var asNonEmptyString = (value) => {
16503
- if (typeof value !== "string") return null;
16504
- const trimmed = value.trim();
16505
- return trimmed ? trimmed : null;
16506
- };
16507
- function readProcessOwner(runtimeContext) {
16508
- if (!runtimeContext || typeof runtimeContext !== "object") return null;
16509
- const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
16510
- if (!dialogId) return null;
16511
- const turnId = asNonEmptyString(runtimeContext.turnId);
16512
- const ownerId = asNonEmptyString(runtimeContext.ownerId);
16513
- return {
16514
- dialogId,
16515
- ...turnId ? { turnId } : {},
16516
- ...ownerId ? { ownerId } : {}
16517
- };
16518
- }
16519
-
16520
- // packages/agent-runtime/workspaceShell.ts
16521
- import { resolve as resolve3 } from "node:path";
16522
- import { spawn as spawnChildProcess2 } from "node:child_process";
16523
-
16524
16467
  // packages/agent-runtime/processTaskResult.ts
16525
16468
  var PROCESS_RESULT_CAPSULE_TAIL_CHARS = 4e3;
16526
16469
  var PROCESS_RESULT_CAPSULE_SPILL_THRESHOLD_CHARS = 2e4;
@@ -16540,11 +16483,17 @@ function buildProcessTaskResultCapsule(args2) {
16540
16483
  const exitCode = args2.exitCode;
16541
16484
  const captureError = args2.captureError?.trim() || void 0;
16542
16485
  const durationMs = typeof args2.startedAt === "number" && Number.isFinite(args2.startedAt) ? Math.max(0, (args2.endedAt ?? Date.now()) - args2.startedAt) : void 0;
16543
- const stdoutTail = tailText(stdout, tailChars);
16544
- const stderrTail = tailText(stderr, tailChars);
16486
+ const stdoutProvenance = args2.streamProvenance?.stdout;
16487
+ const stderrProvenance = args2.streamProvenance?.stderr;
16488
+ const ringEvicted = Boolean(stdoutProvenance?.evicted || stderrProvenance?.evicted);
16489
+ const stdoutTailSource = typeof args2.stdoutTail === "string" ? args2.stdoutTail : stdout;
16490
+ const stderrTailSource = typeof args2.stderrTail === "string" ? args2.stderrTail : stderr;
16491
+ const stdoutTail = tailText(stdoutTailSource, tailChars);
16492
+ const stderrTail = tailText(stderrTailSource, tailChars);
16545
16493
  const inlineSize = stdout.length + stderr.length;
16546
16494
  const inlineTruncated = stdoutTail.truncated || stderrTail.truncated;
16547
- const shouldSpill = inlineTruncated || inlineSize > spillThresholdChars;
16495
+ const truncated = inlineTruncated || ringEvicted || Boolean(captureError);
16496
+ const shouldSpill = truncated || inlineSize > spillThresholdChars;
16548
16497
  let spill;
16549
16498
  if (shouldSpill) {
16550
16499
  try {
@@ -16558,8 +16507,11 @@ function buildProcessTaskResultCapsule(args2) {
16558
16507
  });
16559
16508
  spill = {
16560
16509
  displayPath: result4.displayPath,
16561
- totalChars: result4.totalChars,
16562
- totalLines: result4.totalLines
16510
+ // Prefer the caller's live provenance counters: they count every
16511
+ // byte of the original stream, while the buffered content above may
16512
+ // be a capped prefix of it.
16513
+ totalChars: (stdoutProvenance?.totalChars ?? stdout.length) + (stderrProvenance?.totalChars ?? stderr.length),
16514
+ totalLines: (stdoutProvenance?.totalLines ?? countLines(stdout)) + (stderrProvenance?.totalLines ?? countLines(stderr))
16563
16515
  };
16564
16516
  } catch {
16565
16517
  }
@@ -16570,12 +16522,33 @@ function buildProcessTaskResultCapsule(args2) {
16570
16522
  exitCode,
16571
16523
  ...durationMs !== void 0 ? { durationMs } : {},
16572
16524
  ...captureError ? { captureError } : {},
16573
- truncated: inlineTruncated || Boolean(captureError),
16525
+ truncated,
16574
16526
  ...spill ? { spill } : {}
16575
16527
  };
16576
16528
  }
16577
16529
 
16530
+ // packages/agent-runtime/processOwnership.ts
16531
+ var asNonEmptyString = (value) => {
16532
+ if (typeof value !== "string") return null;
16533
+ const trimmed = value.trim();
16534
+ return trimmed ? trimmed : null;
16535
+ };
16536
+ function readProcessOwner(runtimeContext) {
16537
+ if (!runtimeContext || typeof runtimeContext !== "object") return null;
16538
+ const dialogId = asNonEmptyString(runtimeContext.dialogId) ?? asNonEmptyString(runtimeContext.parentThreadId);
16539
+ if (!dialogId) return null;
16540
+ const turnId = asNonEmptyString(runtimeContext.turnId);
16541
+ const ownerId = asNonEmptyString(runtimeContext.ownerId);
16542
+ return {
16543
+ dialogId,
16544
+ ...turnId ? { turnId } : {},
16545
+ ...ownerId ? { ownerId } : {}
16546
+ };
16547
+ }
16548
+
16578
16549
  // packages/agent-runtime/workspaceShell.ts
16550
+ import { resolve as resolve3 } from "node:path";
16551
+ import { spawn as spawnChildProcess2 } from "node:child_process";
16579
16552
  var EXEC_SHELL_TIMEOUT_ENV = "NOLO_EXEC_SHELL_TIMEOUT_MS";
16580
16553
  var EXEC_SHELL_DETACH_ENV = "NOLO_EXEC_SHELL_DETACH_MS";
16581
16554
  var DEFAULT_EXEC_SHELL_DETACH_MS = 12e4;
@@ -17444,13 +17417,169 @@ function runTasks(args2) {
17444
17417
  return { tasks, count: tasks.length };
17445
17418
  }
17446
17419
 
17447
- // packages/agent-runtime/capabilities/execShellCapability.ts
17420
+ // packages/agent-runtime/execShellCompletionWarnings.ts
17421
+ var BG_ESCAPE_WORD_PATTERN = /(?:^|[\s;|(&/\\])(nohup|disown|setsid|start-process)(?=$|[\s;|)&])/i;
17422
+ var SHELL_SPLIT_CHARS = /* @__PURE__ */ new Set([";", "|", "&", "(", ")", "<", ">", "\n", " ", " "]);
17423
+ function maskQuotedAndEscaped(command) {
17424
+ const out = Array.from(command);
17425
+ let quote = null;
17426
+ for (let i = 0; i < out.length; i += 1) {
17427
+ const ch = out[i];
17428
+ if (quote) {
17429
+ out[i] = " ";
17430
+ if (ch === "\\" && quote !== "'") {
17431
+ if (i + 1 < out.length) out[i + 1] = " ";
17432
+ i += 1;
17433
+ } else if (ch === quote) {
17434
+ quote = null;
17435
+ }
17436
+ continue;
17437
+ }
17438
+ if (ch === "\\") {
17439
+ out[i] = " ";
17440
+ if (i + 1 < out.length) out[i + 1] = " ";
17441
+ i += 1;
17442
+ continue;
17443
+ }
17444
+ if (ch === "'" || ch === '"' || ch === "`") {
17445
+ quote = ch;
17446
+ out[i] = " ";
17447
+ continue;
17448
+ }
17449
+ if (ch === "#" && (i === 0 || /[\s;]/.test(out[i - 1] ?? " "))) {
17450
+ while (i < out.length && out[i] !== "\n") {
17451
+ out[i] = " ";
17452
+ i += 1;
17453
+ }
17454
+ }
17455
+ }
17456
+ return out.join("");
17457
+ }
17458
+ function readRedirectTarget(original, start) {
17459
+ let i = start;
17460
+ while (i < original.length && /\s/.test(original[i] ?? "")) {
17461
+ i += 1;
17462
+ }
17463
+ if (i >= original.length) return void 0;
17464
+ let text = "";
17465
+ let j = i;
17466
+ while (j < original.length) {
17467
+ const o = original[j];
17468
+ if (o === "'" || o === '"' || o === "`") {
17469
+ const quote = o;
17470
+ j += 1;
17471
+ while (j < original.length && original[j] !== quote) {
17472
+ if (original[j] === "\\" && quote !== "'" && j + 1 < original.length) {
17473
+ text += original[j + 1];
17474
+ j += 2;
17475
+ continue;
17476
+ }
17477
+ text += original[j];
17478
+ j += 1;
17479
+ }
17480
+ j += 1;
17481
+ continue;
17482
+ }
17483
+ if (/\s/.test(o) || SHELL_SPLIT_CHARS.has(o)) break;
17484
+ text += o;
17485
+ j += 1;
17486
+ }
17487
+ if (!text || text === "$") return void 0;
17488
+ return { text, end: j };
17489
+ }
17490
+ function isIgnoredRedirectTarget(target) {
17491
+ return target === "/dev/null";
17492
+ }
17493
+ function detectExecShellSynchronousWarnings(command, shell) {
17494
+ const masked = maskQuotedAndEscaped(command);
17495
+ const isPowerShell = shell?.resolvedShell === "powershell";
17496
+ const redirectTargets = [];
17497
+ let backgrounded = false;
17498
+ let i = 0;
17499
+ while (i < masked.length) {
17500
+ const ch = masked[i];
17501
+ if (ch === "&") {
17502
+ const next = masked[i + 1];
17503
+ if (next === "&") {
17504
+ i += 2;
17505
+ continue;
17506
+ }
17507
+ if (next === ">") {
17508
+ let j = i + 2;
17509
+ if (masked[j] === ">") j += 1;
17510
+ const target = readRedirectTarget(command, j);
17511
+ if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
17512
+ i = target ? target.end : j;
17513
+ continue;
17514
+ }
17515
+ const prev = masked[i - 1];
17516
+ if (prev === ">" || prev === "<") {
17517
+ i += 1;
17518
+ continue;
17519
+ }
17520
+ if (isPowerShell) {
17521
+ i += 1;
17522
+ continue;
17523
+ }
17524
+ backgrounded = true;
17525
+ i += 1;
17526
+ continue;
17527
+ }
17528
+ if (ch === ">") {
17529
+ const prev = masked[i - 1];
17530
+ if (prev === ">" || prev === "&" || prev === "<") {
17531
+ i += 1;
17532
+ continue;
17533
+ }
17534
+ let j = i + 1;
17535
+ if (masked[j] === ">") j += 1;
17536
+ if (masked[j] === "&") {
17537
+ const ampTarget = readRedirectTarget(command, j + 1);
17538
+ const isFdDuplication = ampTarget !== void 0 && (/^\d+$/.test(ampTarget.text) || ampTarget.text === "-");
17539
+ if (ampTarget && !isFdDuplication && !isIgnoredRedirectTarget(ampTarget.text)) {
17540
+ redirectTargets.push(ampTarget.text);
17541
+ }
17542
+ i = ampTarget ? ampTarget.end : j + 1;
17543
+ continue;
17544
+ }
17545
+ const target = readRedirectTarget(command, j);
17546
+ if (target && !isIgnoredRedirectTarget(target.text)) redirectTargets.push(target.text);
17547
+ i = target ? target.end : j;
17548
+ continue;
17549
+ }
17550
+ if (ch === "<") {
17551
+ i += masked[i + 1] === "<" || masked[i + 1] === "&" ? 2 : 1;
17552
+ continue;
17553
+ }
17554
+ i += 1;
17555
+ }
17556
+ const wordMatch = BG_ESCAPE_WORD_PATTERN.exec(masked);
17557
+ if (wordMatch) backgrounded = true;
17558
+ const warnings = [];
17559
+ if (redirectTargets.length > 0) {
17560
+ const target = redirectTargets[0];
17561
+ warnings.push({
17562
+ kind: "output-redirect",
17563
+ redirectTarget: target,
17564
+ message: `[wake-safety] This execShell call completed synchronously; its output was redirected to ${target}. That file is NOT delivered by any completion notification \u2014 no tracked background task was created. If you need the result, read that file in this turn.`
17565
+ });
17566
+ }
17567
+ if (backgrounded) {
17568
+ warnings.push({
17569
+ kind: "shell-backgrounding",
17570
+ message: `[wake-safety] Detected shell-internal backgrounding (lone \`&\`, nohup/disown/setsid/Start-Process or similar). Descendant processes are NOT tracked as platform tasks and will not produce completion notifications; text such as \`LAUNCHED\` printed by the command is plain stdout, not a platform receipt.`
17571
+ });
17572
+ }
17573
+ return warnings;
17574
+ }
17575
+
17576
+ // packages/agent-runtime/capabilities/execShellCapability.ts
17448
17577
  function buildExecShellToolDefinition(toolName = "execShell") {
17449
17578
  return {
17450
17579
  type: "function",
17451
17580
  function: {
17452
17581
  name: toolName,
17453
- description: `Execute a shell command from the workspace root. Prefer one compound command (e.g. 'git status && git diff --stat') to perform complete verification in one step instead of multiple small roundtrips. Do not cd into guessed paths; commands already run from the workspace root. Commands block until exit. Long-running commands (sleep over ${IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS}s, dev servers, watchers) automatically detach to background returning {detached: true, pid, label}; for persistent services, prefer launchProcess. On Windows the resolved shell may be Windows PowerShell 5.1 (metadata.shellKind="powershell5"): it does not support '&&'/'||' or $PSStyle \u2014 join commands with ';' or split into multiple calls. metadata.shellKind="pwsh" means PowerShell 7+ with full syntax. Read resolvedShell/shellKind from any execShell result before writing Windows-specific syntax.`,
17582
+ description: `Execute a shell command from the workspace root. Prefer one compound command (e.g. 'git status && git diff --stat') to perform complete verification in one step instead of multiple small roundtrips. Do not cd into guessed paths; commands already run from the workspace root. Commands block until exit. Long-running commands (sleep over ${IMMEDIATE_DETACH_SLEEP_THRESHOLD_SECONDS}s, dev servers, watchers) automatically detach to background returning {detached: true, pid, label}; for persistent services, prefer launchProcess. On Windows the resolved shell may be Windows PowerShell 5.1 (metadata.shellKind="powershell5"): it does not support '&&'/'||' or $PSStyle \u2014 join commands with ';' or split into multiple calls. metadata.shellKind="pwsh" means PowerShell 7+ with full syntax. Read resolvedShell/shellKind from any execShell result before writing Windows-specific syntax. LIFECYCLE CONTRACT (misreading this contract silenced a real dialog for 10 hours): (1) A normal command waits synchronously for at most 120 seconds; if it ends inside that window the call IS finished \u2014 a result containing exitCode means the command has already completed, never "still running". (2) Only a result with metadata.detached === true AND a taskId represents a tracked background task that may trigger completion wake-up (terminal completion turn carrying a bounded result capsule); that handle may be waited on with taskWait and will produce a completion notification. (3) Text the command itself prints (LAUNCHED, STARTED, BACKGROUND, ...) is plain stdout with zero lifecycle meaning \u2014 never read it as a platform receipt. (4) Shell-level backgrounding (\`&\`, nohup, disown, setsid, self-daemonizing scripts, PowerShell Start-Process) is NOT tracked: those descendants produce no completion notification, and the outer shell finishing tells you nothing about them. Use background: true to turn a finite job into a tracked background task immediately. When a synchronous result's core output was redirected to a file, read that file in the SAME turn \u2014 never end the turn promising a later automatic report without a taskId.`,
17454
17583
  parameters: {
17455
17584
  type: "object",
17456
17585
  properties: {
@@ -17461,6 +17590,10 @@ function buildExecShellToolDefinition(toolName = "execShell") {
17461
17590
  cmd: {
17462
17591
  type: "string",
17463
17592
  description: "Compatibility alias for command."
17593
+ },
17594
+ background: {
17595
+ type: "boolean",
17596
+ description: "Immediately detach this command into a tracked background task (no 120s synchronous wait): returns {detached: true, taskId}, and on completion the platform resumes this conversation with a bounded result capsule (exitCode, duration, stdout/stderr tail). Default false. Use for finite jobs (tests, builds, batch) whose result you need later; NOT for dev servers/watchers \u2014 use launchProcess for those."
17464
17597
  }
17465
17598
  }
17466
17599
  }
@@ -17501,11 +17634,13 @@ function normalizeExecShellInput(input) {
17501
17634
  throw new Error("execShell requires a non-empty command.");
17502
17635
  }
17503
17636
  const activity = extractActivity(record);
17637
+ const background = record.background === true || typeof record.background === "string" && record.background.trim().toLowerCase() === "true";
17504
17638
  return {
17505
17639
  command,
17506
17640
  ...record.shell !== void 0 ? { shell: record.shell } : {},
17507
17641
  ...activity ? { activity } : {},
17508
- ...record.input !== void 0 ? { input: record.input } : {}
17642
+ ...record.input !== void 0 ? { input: record.input } : {},
17643
+ ...background ? { background: true } : {}
17509
17644
  };
17510
17645
  }
17511
17646
  throw new Error("execShell requires a non-empty command.");
@@ -17543,6 +17678,7 @@ var execShellCapability = {
17543
17678
  command,
17544
17679
  shell: normalized.shell
17545
17680
  });
17681
+ const background = normalized.background === true;
17546
17682
  const result4 = await runWorkspaceCommand({
17547
17683
  workspaceRoot,
17548
17684
  command: shellPlan.argv,
@@ -17550,15 +17686,18 @@ var execShellCapability = {
17550
17686
  outputLimit: ctx.commandOutputLimit,
17551
17687
  commandPrefix: ctx.commandPrefix,
17552
17688
  abortSignal: ctx.abortSignal,
17553
- detachMs: isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
17689
+ detachMs: background ? 0 : isImmediateDetachShellCommand({ command }) ? 0 : ctx.detachMs,
17554
17690
  stdin: typeof normalized.input === "string" ? normalized.input : void 0,
17555
17691
  // Ownership of the turn that invoked this command: an auto-detached
17556
17692
  // command keeps its parent dialog so its terminal can resume that
17557
17693
  // conversation (see processOwnership.ts). Absent ctx.owner = unowned.
17558
17694
  owner: ctx.owner ?? null
17559
17695
  });
17696
+ const warnings = result4.detached || result4.spawnFailed ? [] : detectExecShellSynchronousWarnings(command, {
17697
+ resolvedShell: shellPlan.resolvedShell
17698
+ });
17560
17699
  return {
17561
- content: result4.content,
17700
+ content: warnings.length > 0 ? [result4.content, ...warnings.map((warning) => warning.message)].join("\n\n") : result4.content,
17562
17701
  metadata: {
17563
17702
  command,
17564
17703
  exitCode: result4.exitCode,
@@ -17573,8 +17712,21 @@ var execShellCapability = {
17573
17712
  // Phase 0: stable taskId from the pre-registered Execution
17574
17713
  // Envelope (additive; existing detached fields untouched).
17575
17714
  taskId: result4.taskId,
17576
- status: "running"
17577
- } : {},
17715
+ status: "running",
17716
+ // P0 machine-readable execution state: an explicit positive
17717
+ // signal instead of requiring the model to infer "not detached"
17718
+ // from absence. Mirrors the real lifecycle contract.
17719
+ executionState: "detached",
17720
+ trackedBackgroundTask: true,
17721
+ completionNotification: "terminal-resume"
17722
+ } : {
17723
+ // P0 machine-readable execution state: the command already
17724
+ // finished inside the synchronous window; no background task
17725
+ // exists, so no completion notification will ever arrive.
17726
+ executionState: "synchronous-complete",
17727
+ trackedBackgroundTask: false,
17728
+ completionNotification: "none"
17729
+ },
17578
17730
  ...normalized.activity ? { activity: normalized.activity } : {}
17579
17731
  }
17580
17732
  };
@@ -17790,7 +17942,7 @@ function buildLaunchProcessTool() {
17790
17942
  type: "function",
17791
17943
  function: {
17792
17944
  name: "launchProcess",
17793
- description: "Start a long-running background process (dev server, watcher, REPL) and return immediately with {pid, label, status}. Use listProcesses to inspect or stop it.",
17945
+ description: "Start a long-running ambient background process (dev server, watcher, REPL) and return immediately with {pid, label, taskId, status}. Real boundaries: this registers a tracked background task, but completion does NOT automatically start a new turn \u2014 the process is intentionally notice-only (an exited dev server must not silently burn a model turn). When it reaches a terminal state the bounded result (exitCode, duration, stdout/stderr tail) is recorded and surfaced as a notice injected only on your next real turn in the same conversation. Use listProcesses to inspect, taskWait to block for its terminal state, or taskStop to stop it. For a finite job (tests, builds, batch) whose result must resume the conversation automatically, use execShell with background: true instead.",
17794
17946
  parameters: {
17795
17947
  type: "object",
17796
17948
  properties: {
@@ -18576,6 +18728,87 @@ async function writeFileTool(args2) {
18576
18728
  }
18577
18729
  };
18578
18730
  }
18731
+ function extractSnippetWords(text) {
18732
+ const tokens = [];
18733
+ const latinWords = text.match(/[A-Za-z0-9_]{2,}/g);
18734
+ if (latinWords) {
18735
+ for (const w of latinWords) tokens.push(w.toLowerCase());
18736
+ }
18737
+ const cjkChars = text.match(new RegExp("\\p{Script=Han}", "gu"));
18738
+ if (cjkChars) {
18739
+ for (let i = 0; i < cjkChars.length - 1; i++) {
18740
+ tokens.push(cjkChars[i] + cjkChars[i + 1]);
18741
+ }
18742
+ if (cjkChars.length === 1) tokens.push(cjkChars[0]);
18743
+ }
18744
+ return tokens;
18745
+ }
18746
+ function calculateEditLineSimilarity(a, b) {
18747
+ if (a === b) return 1;
18748
+ if (!a || !b) return 0;
18749
+ if (a.includes(b) || b.includes(a)) return 0.8;
18750
+ const wordsA = extractSnippetWords(a);
18751
+ const wordsB = extractSnippetWords(b);
18752
+ if (wordsA.length === 0 || wordsB.length === 0) return 0;
18753
+ const setB = new Set(wordsB);
18754
+ let matches = 0;
18755
+ for (const w of wordsA) {
18756
+ if (setB.has(w)) matches++;
18757
+ }
18758
+ return 2 * matches / (wordsA.length + wordsB.length);
18759
+ }
18760
+ function findClosestEditSnippet(content, oldText) {
18761
+ const contentLines = content.split(/\r?\n/);
18762
+ const oldLinesRaw = oldText.split(/\r?\n/);
18763
+ const oldTrimmedLines = oldLinesRaw.map((l) => l.trim()).filter(Boolean);
18764
+ if (contentLines.length === 0 || oldTrimmedLines.length === 0) return null;
18765
+ if (oldTrimmedLines.length > 0 && contentLines.length >= oldTrimmedLines.length) {
18766
+ for (let i = 0; i <= contentLines.length - oldTrimmedLines.length; i++) {
18767
+ let allMatch = true;
18768
+ for (let j = 0; j < oldTrimmedLines.length; j++) {
18769
+ if (contentLines[i + j].trim() !== oldTrimmedLines[j]) {
18770
+ allMatch = false;
18771
+ break;
18772
+ }
18773
+ }
18774
+ if (allMatch) {
18775
+ const startLine2 = i + 1;
18776
+ const endLine2 = i + oldTrimmedLines.length;
18777
+ const snippetLines2 = [];
18778
+ for (let k = i; k < i + oldTrimmedLines.length; k++) {
18779
+ snippetLines2.push(`> ${k + 1}: ${contentLines[k]}`);
18780
+ }
18781
+ return `Exact match found with different indentation/whitespace (lines ${startLine2}-${endLine2}):
18782
+ ${snippetLines2.join("\n")}`;
18783
+ }
18784
+ }
18785
+ }
18786
+ const candidateTargetLines = oldTrimmedLines.filter((l) => l.length >= 4);
18787
+ const targetLine = candidateTargetLines[0] || oldTrimmedLines[0];
18788
+ if (!targetLine || targetLine.length < 3) return null;
18789
+ let bestIndex = -1;
18790
+ let bestScore = 0;
18791
+ for (let i = 0; i < contentLines.length; i++) {
18792
+ const line = contentLines[i].trim();
18793
+ if (!line || line.length < 3) continue;
18794
+ const score = calculateEditLineSimilarity(line, targetLine);
18795
+ if (score > bestScore && score >= 0.45) {
18796
+ bestScore = score;
18797
+ bestIndex = i;
18798
+ if (score === 1) break;
18799
+ }
18800
+ }
18801
+ if (bestIndex === -1) return null;
18802
+ const startLine = Math.max(0, bestIndex - 2);
18803
+ const endLine = Math.min(contentLines.length - 1, bestIndex + 2);
18804
+ const snippetLines = [];
18805
+ for (let i = startLine; i <= endLine; i++) {
18806
+ const prefix = i === bestIndex ? "> " : " ";
18807
+ snippetLines.push(`${prefix}${i + 1}: ${contentLines[i]}`);
18808
+ }
18809
+ return `Closest match near line ${bestIndex + 1}:
18810
+ ${snippetLines.join("\n")}`;
18811
+ }
18579
18812
  async function editFileTool(args2) {
18580
18813
  const parsed = parseWorkspaceToolArguments(args2.call.arguments);
18581
18814
  const requestedPath = requireWorkspaceToolPath(parsed);
@@ -18594,8 +18827,11 @@ async function editFileTool(args2) {
18594
18827
  newText
18595
18828
  });
18596
18829
  if (replacementCount !== expectedReplacements) {
18830
+ const hint = replacementCount === 0 ? findClosestEditSnippet(content, oldText) : null;
18597
18831
  throw new Error(
18598
- `editFile expected ${expectedReplacements} ${pluralizeReplacement(expectedReplacements)} but found ${replacementCount} in ${requestedPath} (matched after EOL normalization; verify the exact text).`
18832
+ `editFile expected ${expectedReplacements} ${pluralizeReplacement(expectedReplacements)} but found ${replacementCount} in ${requestedPath} (matched after EOL normalization; verify the exact text).` + (hint ? `
18833
+
18834
+ ${hint}` : "")
18599
18835
  );
18600
18836
  }
18601
18837
  await writeFile(absolutePath, nextContent, "utf8");
@@ -18931,6 +19167,55 @@ async function execShellTool(args2) {
18931
19167
  }
18932
19168
  );
18933
19169
  }
19170
+ var LAUNCH_PROCESS_STREAM_RING_CHARS = 65536;
19171
+ var LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS = 4e6;
19172
+ function createLaunchProcessStreamCapture() {
19173
+ let ring = "";
19174
+ let full = null;
19175
+ let capturedChars = 0;
19176
+ let totalChars = 0;
19177
+ let totalNewlines = 0;
19178
+ return {
19179
+ push(chunk) {
19180
+ const str = typeof chunk === "string" ? chunk : chunk.toString("utf8");
19181
+ if (!str) return;
19182
+ totalChars += str.length;
19183
+ for (let i = 0; i < str.length; i += 1) {
19184
+ if (str.charCodeAt(i) === 10) totalNewlines += 1;
19185
+ }
19186
+ const combined = ring + str;
19187
+ if (combined.length <= LAUNCH_PROCESS_STREAM_RING_CHARS) {
19188
+ ring = combined;
19189
+ return;
19190
+ }
19191
+ if (full === null) {
19192
+ full = [combined];
19193
+ capturedChars = combined.length;
19194
+ } else if (capturedChars < LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS) {
19195
+ const room = LAUNCH_PROCESS_STREAM_CAPTURE_MAX_CHARS - capturedChars;
19196
+ const slice = str.length <= room ? str : str.slice(0, room);
19197
+ full.push(slice);
19198
+ capturedChars += slice.length;
19199
+ }
19200
+ ring = combined.slice(-LAUNCH_PROCESS_STREAM_RING_CHARS);
19201
+ },
19202
+ text() {
19203
+ return full === null ? ring : full.join("");
19204
+ },
19205
+ tailText() {
19206
+ return ring;
19207
+ },
19208
+ evicted() {
19209
+ return full !== null;
19210
+ },
19211
+ totalChars() {
19212
+ return totalChars;
19213
+ },
19214
+ totalLines() {
19215
+ return totalChars > 0 ? totalNewlines + 1 : 0;
19216
+ }
19217
+ };
19218
+ }
18934
19219
  async function launchProcessTool(args2) {
18935
19220
  const parsed = parseWorkspaceToolArguments(args2.call.arguments);
18936
19221
  const command = requireShellCommand(parsed, args2.call.name);
@@ -18958,6 +19243,14 @@ async function launchProcessTool(args2) {
18958
19243
  stdio: ["ignore", "pipe", "pipe"],
18959
19244
  detached
18960
19245
  });
19246
+ const stdoutCapture = createLaunchProcessStreamCapture();
19247
+ const stderrCapture = createLaunchProcessStreamCapture();
19248
+ proc.stdout?.on("data", (chunk) => stdoutCapture.push(chunk));
19249
+ proc.stderr?.on("data", (chunk) => stderrCapture.push(chunk));
19250
+ proc.stdout?.on("error", () => {
19251
+ });
19252
+ proc.stderr?.on("error", () => {
19253
+ });
18961
19254
  const pid = proc.pid;
18962
19255
  if (typeof pid !== "number") {
18963
19256
  return {
@@ -18998,7 +19291,38 @@ async function launchProcessTool(args2) {
18998
19291
  process.removeListener("SIGTERM", cleanupChildOnHostSignal);
18999
19292
  process.removeListener("SIGINT", cleanupChildOnHostSignal);
19000
19293
  }
19001
- registry2.markExited(pid, code ?? 1);
19294
+ const exitCode = code ?? 1;
19295
+ let capsule;
19296
+ try {
19297
+ capsule = buildProcessTaskResultCapsule({
19298
+ // The full captured output (bounded prefix when the process was
19299
+ // extremely chatty): the module tails it for the inline capsule and
19300
+ // spills it for recovery. Provenance carries the live original-stream
19301
+ // counters so truncated/spill metadata never derives from the ring.
19302
+ stdout: stdoutCapture.text(),
19303
+ stderr: stderrCapture.text(),
19304
+ stdoutTail: stdoutCapture.tailText(),
19305
+ stderrTail: stderrCapture.tailText(),
19306
+ exitCode,
19307
+ // Duration measured from the registry envelope's startedAt (spawn).
19308
+ startedAt: envelope.startedAt,
19309
+ workspaceRoot: args2.workspaceRoot,
19310
+ streamProvenance: {
19311
+ stdout: {
19312
+ evicted: stdoutCapture.evicted(),
19313
+ totalChars: stdoutCapture.totalChars(),
19314
+ totalLines: stdoutCapture.totalLines()
19315
+ },
19316
+ stderr: {
19317
+ evicted: stderrCapture.evicted(),
19318
+ totalChars: stderrCapture.totalChars(),
19319
+ totalLines: stderrCapture.totalLines()
19320
+ }
19321
+ }
19322
+ });
19323
+ } catch {
19324
+ }
19325
+ registry2.markExited(pid, exitCode, capsule);
19002
19326
  });
19003
19327
  const activity = extractActivity(parsed);
19004
19328
  const resultData = { pid, label, taskId: envelope.taskId, status: "running" };
@@ -19010,6 +19334,13 @@ async function launchProcessTool(args2) {
19010
19334
  label,
19011
19335
  status: "running",
19012
19336
  taskId: envelope.taskId,
19337
+ // P0 machine-readable execution state (consistent with the real wake
19338
+ // contract): a real background task from birth, but ambient — its
19339
+ // terminal result rides the next real turn's notice, not an automatic
19340
+ // completion turn.
19341
+ executionState: "background",
19342
+ trackedBackgroundTask: true,
19343
+ completionNotification: "next-turn-notice",
19013
19344
  processLaunch: resultData,
19014
19345
  ...activity ? { activity } : {}
19015
19346
  }
@@ -19112,7 +19443,7 @@ async function tasksTool(_args) {
19112
19443
  }
19113
19444
  async function openDesktopPreviewTool(args2) {
19114
19445
  const parsed = parseWorkspaceToolArguments(args2.call.arguments);
19115
- const url = typeof parsed.url === "string" ? parsed.url.trim() : "";
19446
+ const url = asTrimmedString(parsed.url);
19116
19447
  if (!url) {
19117
19448
  return {
19118
19449
  content: JSON.stringify({ error: "openDesktopPreview requires a non-empty url." }),
@@ -19234,6 +19565,292 @@ function createLocalWorkspaceToolExecutors(args2) {
19234
19565
  };
19235
19566
  }
19236
19567
 
19568
+ // packages/agent-runtime/toolArgumentGate.ts
19569
+ var FIELD_ALIAS_GROUPS = [
19570
+ // localWorkspaceTools.ts:336 导出常量(readFile/writeFile/editFile/globFiles)
19571
+ PATH_FIELD_ALIASES,
19572
+ // localWorkspaceTools.ts:339-340 导出常量(editFile)
19573
+ OLD_TEXT_FIELD_ALIASES,
19574
+ NEW_TEXT_FIELD_ALIASES,
19575
+ // localWorkspaceTools.ts:733 `args.cmd || args.command`(launchProcess);
19576
+ // launchProcess 的 required ["command"] 见 localWorkspaceToolDefs.ts:283。
19577
+ // 注:execShell 的 schema 无 required(command 在 executor 层强制,
19578
+ // capabilities/execShellCapability.ts:42 声明 cmd 兼容字段),本组对它不产生拦截。
19579
+ ["command", "cmd"],
19580
+ // localWorkspaceTools.ts:698-699 `args.pattern ?? args.glob`(globFiles)
19581
+ ["pattern", "glob"],
19582
+ // noloWorkspaceTools.ts:492 `args.dialog ?? args.dialogId ?? args.id`(readDialog)
19583
+ ["dialog", "dialogId", "id"],
19584
+ // noloWorkspaceTools.ts:545 `args.agent ?? args.agentKey ?? args.id`(readAgent)
19585
+ ["agent", "agentKey", "id"],
19586
+ // noloWorkspaceTools.ts:552 `args.space ?? args.spaceId ?? args.id`(readSpace)
19587
+ ["space", "spaceId", "id"],
19588
+ // noloWorkspaceTools.ts:561/567 `args.doc ?? args.docKey ?? args.pageKey ?? args.key`
19589
+ // (readDoc / readSkillDoc)
19590
+ ["doc", "docKey", "pageKey", "key"],
19591
+ // noloWorkspaceTools.node.ts:238 `parsed.name ?? parsed.skillName ?? parsed.skill`(loadSkill)
19592
+ ["name", "skillName", "skill"],
19593
+ // noloWorkspaceTools.ts:593 `args.table ?? args.tableId ?? args.metaKey`(queryTableRows)
19594
+ ["table", "tableId", "metaKey"]
19595
+ ];
19596
+ var TYPE_MATCHERS = {
19597
+ string: (value) => typeof value === "string",
19598
+ // 数字字符串视为可接受:executor 普遍 Number()/clamp 宽松处理,拦截会误报。
19599
+ number: (value) => typeof value === "number" || typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)),
19600
+ integer: (value) => typeof value === "number" || typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)),
19601
+ boolean: (value) => typeof value === "boolean" || value === "true" || value === "false",
19602
+ object: (value) => typeof value === "object" && value !== null && !Array.isArray(value),
19603
+ array: (value) => Array.isArray(value)
19604
+ };
19605
+ function describeValueType(value) {
19606
+ if (value === null) return "null";
19607
+ if (Array.isArray(value)) return "array";
19608
+ return typeof value;
19609
+ }
19610
+ function isAliasSatisfied(args2, field) {
19611
+ for (const group of FIELD_ALIAS_GROUPS) {
19612
+ if (!group.includes(field)) continue;
19613
+ if (group.some((alias) => args2[alias] !== void 0)) return true;
19614
+ }
19615
+ return false;
19616
+ }
19617
+ function readRequiredFields(parameters) {
19618
+ const required = parameters.required;
19619
+ if (!Array.isArray(required)) return [];
19620
+ return required.filter((field) => typeof field === "string");
19621
+ }
19622
+ function readProperties(parameters) {
19623
+ const properties = parameters.properties;
19624
+ if (!properties || typeof properties !== "object" || Array.isArray(properties)) {
19625
+ return {};
19626
+ }
19627
+ return properties;
19628
+ }
19629
+ function validateToolArguments(args2) {
19630
+ const { toolName, rawArguments, parameters } = args2;
19631
+ if (!parameters || typeof parameters !== "object" || Array.isArray(parameters)) {
19632
+ return { ok: true, args: {} };
19633
+ }
19634
+ const schema = parameters;
19635
+ const requiredFields = readRequiredFields(schema);
19636
+ const properties = readProperties(schema);
19637
+ if (requiredFields.length === 0 && Object.keys(properties).length === 0) {
19638
+ return { ok: true, args: {} };
19639
+ }
19640
+ const raw = typeof rawArguments === "string" ? rawArguments.trim() : "";
19641
+ let record = {};
19642
+ if (raw !== "") {
19643
+ let parsed;
19644
+ try {
19645
+ parsed = JSON.parse(raw);
19646
+ } catch {
19647
+ return { ok: true, args: {} };
19648
+ }
19649
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
19650
+ return { ok: true, args: {} };
19651
+ }
19652
+ record = parsed;
19653
+ }
19654
+ for (const field of requiredFields) {
19655
+ if (record[field] !== void 0) continue;
19656
+ if (isAliasSatisfied(record, field)) continue;
19657
+ return {
19658
+ ok: false,
19659
+ message: `${toolName} \u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF1A\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570 "${field}"\u3002\u8BF7\u8865\u4E0A\u540E\u91CD\u65B0\u8C03\u7528 ${toolName}\u3002`
19660
+ };
19661
+ }
19662
+ for (const [field, spec] of Object.entries(properties)) {
19663
+ const value = record[field];
19664
+ if (value === void 0 || value === null) continue;
19665
+ if (!spec || typeof spec !== "object" || Array.isArray(spec)) continue;
19666
+ const declared = spec.type;
19667
+ if (typeof declared !== "string") continue;
19668
+ const matcher = TYPE_MATCHERS[declared];
19669
+ if (!matcher) continue;
19670
+ if (!matcher(value)) {
19671
+ return {
19672
+ ok: false,
19673
+ message: `${toolName} \u53C2\u6570\u6821\u9A8C\u5931\u8D25\uFF1A\u53C2\u6570 "${field}" \u5E94\u4E3A ${declared}\uFF0C\u5B9E\u9645\u6536\u5230 ${describeValueType(value)}\u3002\u8BF7\u4FEE\u6B63\u540E\u91CD\u65B0\u8C03\u7528 ${toolName}\u3002`
19674
+ };
19675
+ }
19676
+ }
19677
+ return { ok: true, args: record };
19678
+ }
19679
+ function buildToolParametersIndex(tools) {
19680
+ const index = /* @__PURE__ */ new Map();
19681
+ for (const tool of tools) {
19682
+ if (!tool || typeof tool !== "object") continue;
19683
+ const fn3 = tool.function;
19684
+ if (!fn3 || typeof fn3 !== "object") continue;
19685
+ const name = fn3.name;
19686
+ const parameters = fn3.parameters;
19687
+ if (typeof name === "string" && name && parameters !== void 0) {
19688
+ index.set(name, parameters);
19689
+ }
19690
+ }
19691
+ return index;
19692
+ }
19693
+ var cachedAgentRuntimeIndex = null;
19694
+ function getAgentRuntimeToolParametersIndex() {
19695
+ if (cachedAgentRuntimeIndex) return cachedAgentRuntimeIndex;
19696
+ const index = /* @__PURE__ */ new Map();
19697
+ try {
19698
+ const workspaceTools = buildLocalWorkspaceOpenAiTools({
19699
+ toolNames: [...WORKSPACE_TOOL_NAMES],
19700
+ exposeShellTools: true
19701
+ });
19702
+ for (const [name, parameters] of buildToolParametersIndex(workspaceTools)) {
19703
+ index.set(name, parameters);
19704
+ }
19705
+ const noloTools = buildNoloWorkspaceOpenAiTools({
19706
+ toolNames: [...NOLO_WORKSPACE_TOOL_NAMES]
19707
+ });
19708
+ for (const [name, parameters] of buildToolParametersIndex(noloTools)) {
19709
+ index.set(name, parameters);
19710
+ }
19711
+ } catch {
19712
+ }
19713
+ cachedAgentRuntimeIndex = index;
19714
+ return index;
19715
+ }
19716
+
19717
+ // packages/agent-runtime/localToolPolicy.ts
19718
+ var NEVER_LOCAL_TOOLS = /* @__PURE__ */ new Set([
19719
+ "deleteSpaces",
19720
+ "updateAgent",
19721
+ "updateSelf",
19722
+ "createAgent"
19723
+ ]);
19724
+ var DEFAULT_LOCAL_TOOLS = /* @__PURE__ */ new Set([
19725
+ "readFile",
19726
+ "writeFile",
19727
+ "editFile",
19728
+ "globFiles",
19729
+ "execShell",
19730
+ "launchProcess",
19731
+ "listProcesses",
19732
+ // ProcessTask follow-up tools. Same tier as listProcesses: they observe/stop
19733
+ // tasks the agent itself already spawned, so their blast radius is strictly
19734
+ // narrower than launchProcess (which is default-enabled). Model-facing
19735
+ // follow-ups are taskWait/taskStop only — lifecycle history (taskLogs) stays
19736
+ // runtime-internal.
19737
+ "taskWait",
19738
+ "taskStop",
19739
+ // Scheduling tools: forking/observing sub-agents is a declared capability
19740
+ // of capable agents, and the blast radius is strictly narrower than
19741
+ // execShell (already default-enabled). Requiring an env allowlist for these
19742
+ // while execShell is open by default inverted the risk model and forced every
19743
+ // new local user to hand-edit .env files before sub-agent tasks worked.
19744
+ "startAgentRun",
19745
+ "controlAgentRun"
19746
+ ]);
19747
+ function parseToolAllowlist(value) {
19748
+ return (value ?? "").split(",").flatMap((item) => {
19749
+ const trimmed = item.trim();
19750
+ return trimmed ? [trimmed] : [];
19751
+ });
19752
+ }
19753
+ function normalizeLocalToolName(toolName) {
19754
+ return canonicalizeToolName(
19755
+ String(toolName ?? "").replace(/^functions\./, "").trim()
19756
+ );
19757
+ }
19758
+ function isRestrictedLocalToolMode(env) {
19759
+ return env.NOLO_LOCAL_TOOL_MODE === "restricted";
19760
+ }
19761
+ function resolveLocalToolPolicy(args2) {
19762
+ const toolName = normalizeLocalToolName(args2.toolName);
19763
+ const restrictedMode = isRestrictedLocalToolMode(args2.env);
19764
+ if (!toolName) {
19765
+ return {
19766
+ allowed: false,
19767
+ toolName,
19768
+ reason: "Tool name is required."
19769
+ };
19770
+ }
19771
+ if (NEVER_LOCAL_TOOLS.has(toolName)) {
19772
+ return {
19773
+ allowed: false,
19774
+ toolName,
19775
+ reason: `${toolName} is blocked by the local runtime safety policy.`
19776
+ };
19777
+ }
19778
+ const allowedByEnv = new Set(
19779
+ parseToolAllowlist(args2.env.NOLO_LOCAL_ALLOWED_TOOLS).map(normalizeLocalToolName)
19780
+ );
19781
+ const agentTools = new Set(
19782
+ (args2.agentToolNames ?? []).flatMap((item) => {
19783
+ const normalized = normalizeLocalToolName(item);
19784
+ return normalized ? [normalized] : [];
19785
+ })
19786
+ );
19787
+ if (!restrictedMode && agentTools.has(toolName)) {
19788
+ return { allowed: true, toolName };
19789
+ }
19790
+ if (DEFAULT_LOCAL_TOOLS.has(toolName) && agentTools.has(toolName)) {
19791
+ return { allowed: true, toolName };
19792
+ }
19793
+ if (allowedByEnv.has(toolName) && agentTools.has(toolName)) {
19794
+ return { allowed: true, toolName };
19795
+ }
19796
+ return {
19797
+ allowed: false,
19798
+ toolName,
19799
+ reason: `${toolName} is not enabled for local runtime runs. The agent must declare the tool in its manifest; in restricted mode (NOLO_LOCAL_TOOL_MODE=restricted) non-default tools also require adding to NOLO_LOCAL_ALLOWED_TOOLS (e.g. NOLO_LOCAL_ALLOWED_TOOLS=someCustomTool) and restarting the session so the env var loads.`
19800
+ };
19801
+ }
19802
+ async function executeLocalToolWithPolicy(args2) {
19803
+ if (args2.runToolNames !== void 0 && !args2.runToolNames.map(normalizeLocalToolName).includes(normalizeLocalToolName(args2.call.name))) {
19804
+ throw new Error(`${args2.call.name} is outside the final run tool surface.`);
19805
+ }
19806
+ const decision = resolveLocalToolPolicy({
19807
+ env: args2.env,
19808
+ agentToolNames: args2.agentToolNames,
19809
+ toolName: args2.call.name
19810
+ });
19811
+ if (!decision.allowed) throw new Error(decision.reason);
19812
+ const executor = args2.executors?.[decision.toolName];
19813
+ if (!executor) {
19814
+ throw new Error(`${decision.toolName} is allowed by policy but no local executor is registered.`);
19815
+ }
19816
+ const parametersSchema = args2.toolParametersIndex?.get(decision.toolName);
19817
+ if (parametersSchema !== void 0) {
19818
+ const gate = validateToolArguments({
19819
+ toolName: decision.toolName,
19820
+ rawArguments: args2.call.arguments,
19821
+ parameters: parametersSchema
19822
+ });
19823
+ if (!gate.ok) throw new Error(gate.message);
19824
+ }
19825
+ const opts = {
19826
+ ...args2.abortSignal ? { abortSignal: args2.abortSignal } : {},
19827
+ ...args2.detachMs !== void 0 ? { detachMs: args2.detachMs } : {},
19828
+ ...args2.confirmed !== void 0 ? { confirmed: args2.confirmed } : {},
19829
+ ...args2.enableDestructiveShellGuard !== void 0 ? { enableDestructiveShellGuard: args2.enableDestructiveShellGuard } : {},
19830
+ ...args2.confirmDestructiveAction ? { confirmDestructiveAction: args2.confirmDestructiveAction } : {},
19831
+ ...args2.blockDestructiveWithoutConfirmation !== void 0 ? { blockDestructiveWithoutConfirmation: args2.blockDestructiveWithoutConfirmation } : {}
19832
+ };
19833
+ if (decision.toolName === "execShell") {
19834
+ let parsedInput = args2.call.arguments;
19835
+ if (typeof parsedInput === "string") {
19836
+ try {
19837
+ parsedInput = JSON.parse(parsedInput);
19838
+ } catch {
19839
+ parsedInput = { command: parsedInput };
19840
+ }
19841
+ }
19842
+ await evaluateExecShellDestructiveGuard(parsedInput, opts);
19843
+ opts.confirmed = true;
19844
+ }
19845
+ return executor(
19846
+ {
19847
+ ...args2.call,
19848
+ name: decision.toolName
19849
+ },
19850
+ opts
19851
+ );
19852
+ }
19853
+
19237
19854
  // packages/cli/client/localDialogRecords.ts
19238
19855
  var localDialogMessageRecordToRuntimeMessage = dialogMessageRecordToAgentRuntimeMessage;
19239
19856
  function buildLocalDialogWritePlan(args2) {
@@ -19370,10 +19987,10 @@ function buildLoadSkillExecutor(args2) {
19370
19987
  metadata: { loadSkill: true, resolved: false }
19371
19988
  };
19372
19989
  }
19373
- const { resolveSkillByName } = await import("./skillDiscovery-CYUCJMAG.js");
19990
+ const { resolveSkillByName } = await import("./skillDiscovery-ZBU76COE.js");
19374
19991
  const resolved = resolveSkillByName(args2.cwd, name);
19375
19992
  if (!resolved) {
19376
- const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-FUAVTRVZ.js");
19993
+ const { resolveBuiltinSkillByName } = await import("./builtinSkillRegistry-ZMF6YGNO.js");
19377
19994
  const builtin = resolveBuiltinSkillByName(name);
19378
19995
  if (builtin) {
19379
19996
  return {
@@ -19416,7 +20033,7 @@ ${body}`,
19416
20033
  };
19417
20034
  }
19418
20035
  async function formatUnknownSkillMessage(cwd, requestedName) {
19419
- const { discoverSkills } = await import("./skillDiscovery-CYUCJMAG.js");
20036
+ const { discoverSkills } = await import("./skillDiscovery-ZBU76COE.js");
19420
20037
  let available = [];
19421
20038
  try {
19422
20039
  available = discoverSkills(cwd).map((s) => s.name);
@@ -19431,739 +20048,10 @@ No skills were discovered in this workspace.`;
19431
20048
  Available skills: ${available.join(", ")}`;
19432
20049
  }
19433
20050
 
19434
- // packages/core/chat/upstreamErrorBody.ts
19435
- function parseUpstreamErrorBody(errorText, statusText) {
19436
- if (errorText) {
19437
- try {
19438
- const parsed = JSON.parse(errorText);
19439
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
19440
- const error = parsed.error;
19441
- if (error && typeof error === "object" && !Array.isArray(error)) {
19442
- return parsed;
19443
- }
19444
- }
19445
- } catch {
19446
- }
19447
- }
19448
- return { error: { message: errorText || statusText } };
19449
- }
19450
-
19451
- // packages/agent-runtime/antigravityCloudCodeProvider.ts
19452
- import { randomUUID } from "node:crypto";
19453
-
19454
- // packages/agent-runtime/antigravityWireModel.ts
19455
- var WIRE_PROFILES = {
19456
- // Antigravity discovery exposes 3.7 Flash as one tiered wire model.
19457
- // The UI labels its effort variants (Low/Medium/High), but the literal
19458
- // -medium/-high ids return 404 from streamGenerateContent.
19459
- "gemini-3.7-flash-tiered": { modelEnum: "MODEL_PLACEHOLDER_M301", maxOutputTokens: 65536 },
19460
- // Gemini 3.8 Flash 沿用 3.7 的 tiered 兼容策略:仓库内暂无 Antigravity discovery
19461
- // 证据确认 3.8 的 wire modelEnum,禁止虚构,先只声明同档输出上限;enum 待
19462
- // discovery 证据到位后补齐。
19463
- "gemini-3.8-flash-tiered": { maxOutputTokens: 65536 },
19464
- "gemini-3.6-flash-low": { maxOutputTokens: 65536 },
19465
- "gemini-3.6-flash-medium": { maxOutputTokens: 65536 },
19466
- "gemini-3.6-flash-high": { maxOutputTokens: 65536 },
19467
- // 旧模型 wire 映射保留:存量自定义 agent 仍可能引用(注册表已下线不影响此处)。
19468
- "gemini-3.5-flash-extra-low": { modelEnum: "MODEL_PLACEHOLDER_M187", maxOutputTokens: 65536 },
19469
- "gemini-3.5-flash-low": { modelEnum: "MODEL_PLACEHOLDER_M20", maxOutputTokens: 65536 },
19470
- "gemini-3-flash-agent": { modelEnum: "MODEL_PLACEHOLDER_M132", maxOutputTokens: 65536 },
19471
- "gemini-3.1-pro-low": { modelEnum: "MODEL_PLACEHOLDER_M36", maxOutputTokens: 65535 },
19472
- "gemini-pro-agent": { modelEnum: "MODEL_PLACEHOLDER_M16", maxOutputTokens: 65535 },
19473
- "claude-sonnet-5": { maxOutputTokens: 64e3 },
19474
- "claude-sonnet-4-6": { maxOutputTokens: 64e3 },
19475
- "claude-opus-4-6-thinking": { maxOutputTokens: 64e3 },
19476
- "gemini-2.5-flash": { maxOutputTokens: 65536 },
19477
- "gemini-2.5-pro": { maxOutputTokens: 65536 }
19478
- };
19479
- function resolveAntigravityWireModel(logicalModelId) {
19480
- const id = logicalModelId.trim();
19481
- const lower = id.toLowerCase();
19482
- if (lower === "gemini-3.5-flash") {
19483
- const wireModelId = "gemini-3.5-flash-low";
19484
- return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
19485
- }
19486
- if (lower === "gemini-3.7-flash" || ["gemini-3.7-flash-low", "gemini-3.7-flash-medium", "gemini-3.7-flash-high"].includes(lower)) {
19487
- const wireModelId = "gemini-3.7-flash-tiered";
19488
- return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
19489
- }
19490
- if (lower === "gemini-3.8-flash" || ["gemini-3.8-flash-low", "gemini-3.8-flash-medium", "gemini-3.8-flash-high"].includes(lower)) {
19491
- const wireModelId = "gemini-3.8-flash-tiered";
19492
- return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
19493
- }
19494
- if (lower === "gemini-3.6-flash") {
19495
- const wireModelId = "gemini-3.6-flash-low";
19496
- return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
19497
- }
19498
- if (lower === "gemini-3.1-pro" || lower === "gemini-3.1-pro-preview") {
19499
- const wireModelId = "gemini-3.1-pro-low";
19500
- return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
19501
- }
19502
- if (WIRE_PROFILES[id]) {
19503
- return { wireModelId: id, profile: WIRE_PROFILES[id] };
19504
- }
19505
- return { wireModelId: id };
19506
- }
19507
-
19508
- // packages/agent-runtime/geminiNativeShared.ts
19509
- var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
19510
- function resolveGeminiModelQuirks(modelId) {
19511
- const lower = modelId.toLowerCase();
19512
- const isGemini3 = lower.includes("gemini-3");
19513
- const isStrictSignatureModel = lower.includes("gemini-3.5") || lower.includes("flash-preview");
19514
- const isClaude = lower.includes("claude");
19515
- return {
19516
- requiresThoughtSignature: isGemini3,
19517
- allowsThoughtSignatureSentinel: isGemini3 && !isStrictSignatureModel,
19518
- isClaudeCrossModel: isClaude
19519
- };
19520
- }
19521
- function isGemini3Model(modelId) {
19522
- return resolveGeminiModelQuirks(modelId).requiresThoughtSignature;
19523
- }
19524
- function messageText(content) {
19525
- if (typeof content === "string") return content;
19526
- if (!Array.isArray(content)) return "";
19527
- return content.filter(
19528
- (part) => part?.type === "text"
19529
- ).map((part) => part.text).join("\n").trim();
19530
- }
19531
- function parseDataUrlToInlineData(url) {
19532
- const match7 = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
19533
- url
19534
- );
19535
- if (!match7) return null;
19536
- return { mimeType: match7[1], data: match7[2] };
19537
- }
19538
- function extractInlineDataParts(content) {
19539
- if (!Array.isArray(content)) return [];
19540
- const parts2 = [];
19541
- for (const part of content) {
19542
- if (!part || typeof part !== "object") continue;
19543
- if (part.type !== "image_url") continue;
19544
- const url = part.image_url?.url;
19545
- if (typeof url !== "string" || !url.trim()) continue;
19546
- const inline = parseDataUrlToInlineData(url);
19547
- if (inline) parts2.push({ inlineData: inline });
19548
- }
19549
- return parts2;
19550
- }
19551
- function convertOpenAiMessagesToGemini(messages, options) {
19552
- const contents = [];
19553
- const systemTexts = [];
19554
- let toolCallIndex = 0;
19555
- let pendingFunctionCalls = [];
19556
- const pushOrMergeContent = (role, parts2) => {
19557
- if (parts2.length === 0) return;
19558
- const last = contents[contents.length - 1];
19559
- if (last && last.role === role) {
19560
- last.parts.push(...parts2);
19561
- } else {
19562
- contents.push({ role, parts: parts2 });
19563
- }
19564
- };
19565
- const flushPendingFunctionCalls = () => {
19566
- if (pendingFunctionCalls.length === 0) return;
19567
- const dummyResponses = pendingFunctionCalls.map(
19568
- ({ name, id }) => ({
19569
- functionResponse: {
19570
- name,
19571
- response: { output: "{}" },
19572
- ...id ? { id } : {}
19573
- }
19574
- })
19575
- );
19576
- pendingFunctionCalls = [];
19577
- pushOrMergeContent("user", dummyResponses);
19578
- };
19579
- for (const raw of messages) {
19580
- if (!raw || typeof raw !== "object" || !("role" in raw)) continue;
19581
- const role = String(raw.role);
19582
- const content = "content" in raw ? raw.content : null;
19583
- if (role === "system") {
19584
- const text = messageText(
19585
- content
19586
- );
19587
- if (text) systemTexts.push(text);
19588
- continue;
19589
- }
19590
- if (role === "user") {
19591
- flushPendingFunctionCalls();
19592
- const text = messageText(
19593
- content
19594
- );
19595
- const imageParts = extractInlineDataParts(
19596
- content
19597
- );
19598
- if (!text && imageParts.length === 0) continue;
19599
- const parts2 = [];
19600
- if (text) parts2.push({ text });
19601
- for (const img of imageParts) parts2.push(img);
19602
- pushOrMergeContent("user", parts2);
19603
- continue;
19604
- }
19605
- if (role === "assistant") {
19606
- flushPendingFunctionCalls();
19607
- const text = messageText(
19608
- content
19609
- );
19610
- const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
19611
- const parts2 = [];
19612
- if (text) {
19613
- parts2.push({ text });
19614
- }
19615
- for (const call of toolCalls) {
19616
- const name = call?.function?.name?.trim();
19617
- if (!name) continue;
19618
- const id = call.id?.trim() || `${name}_${toolCallIndex++}`;
19619
- pendingFunctionCalls.push({ name, id });
19620
- const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
19621
- const isFirstFunctionCallPart = !parts2.some(
19622
- (p) => "functionCall" in p
19623
- );
19624
- const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
19625
- const part = {
19626
- functionCall: {
19627
- name,
19628
- args: parseToolArgs(call.function?.arguments),
19629
- ...id ? { id } : {}
19630
- },
19631
- ...signature ? { thoughtSignature: signature } : {}
19632
- };
19633
- parts2.push(part);
19634
- }
19635
- pushOrMergeContent("model", parts2);
19636
- continue;
19637
- }
19638
- if (role === "tool") {
19639
- const toolCallId = "tool_call_id" in raw && typeof raw.tool_call_id === "string" ? raw.tool_call_id : "";
19640
- const rawName = "name" in raw && typeof raw.name === "string" ? raw.name.trim() : "";
19641
- const pendingIndex = pendingFunctionCalls.findIndex(
19642
- (p) => toolCallId ? p.id === toolCallId : rawName ? p.name === rawName : true
19643
- );
19644
- if (pendingIndex === -1) continue;
19645
- const [{ name, id }] = pendingFunctionCalls.splice(pendingIndex, 1);
19646
- const output = messageText(content) || "{}";
19647
- pushOrMergeContent("user", [
19648
- {
19649
- functionResponse: {
19650
- name,
19651
- response: { output },
19652
- // 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
19653
- // Gemini contents 转成 Claude messages 时需要 functionResponse →
19654
- // tool_result 的 tool_use_id;缺 id 时网关报
19655
- // "tool_result.tool_use_id: Field required"(HTTP 400)。
19656
- ...id ? { id } : {}
19657
- }
19658
- }
19659
- ]);
19660
- }
19661
- }
19662
- flushPendingFunctionCalls();
19663
- if (contents.length > 0 && contents[0]?.role === "model") {
19664
- contents.unshift({
19665
- role: "user",
19666
- parts: [{ text: "Continue the conversation." }]
19667
- });
19668
- }
19669
- return { contents, systemTexts };
19670
- }
19671
- function parseToolArgs(raw) {
19672
- if (typeof raw === "string") {
19673
- try {
19674
- const parsed = JSON.parse(raw);
19675
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
19676
- return parsed;
19677
- }
19678
- } catch {
19679
- }
19680
- }
19681
- if (raw && typeof raw === "object" && !Array.isArray(raw)) {
19682
- return raw;
19683
- }
19684
- return {};
19685
- }
19686
- function sanitizeGeminiSchemaNode(node, active) {
19687
- const out = {};
19688
- if (!node || typeof node !== "object" || Array.isArray(node)) {
19689
- return { type: "string" };
19690
- }
19691
- if (active?.has(node)) {
19692
- return { type: "object", description: "(circular schema reference)" };
19693
- }
19694
- const seen = active ?? /* @__PURE__ */ new WeakSet();
19695
- seen.add(node);
19696
- try {
19697
- return sanitizeGeminiSchemaNodeInner(node, out, seen);
19698
- } finally {
19699
- seen.delete(node);
19700
- }
19701
- }
19702
- function sanitizeGeminiSchemaNodeInner(src, out, seen) {
19703
- if (Array.isArray(src.type)) {
19704
- const firstNonNull = src.type.find((t) => t !== "null");
19705
- if (typeof firstNonNull === "string") out.type = firstNonNull;
19706
- out.nullable = true;
19707
- } else if (typeof src.type === "string") {
19708
- out.type = src.type;
19709
- }
19710
- if (typeof src.description === "string") out.description = src.description;
19711
- if (typeof src.minimum === "number") out.minimum = src.minimum;
19712
- if (typeof src.maximum === "number") out.maximum = src.maximum;
19713
- if (Array.isArray(src.enum) && src.enum.length > 0) out.enum = src.enum;
19714
- if (src.nullable === true) out.nullable = true;
19715
- if ("const" in src && src.const !== void 0 && !out.enum) {
19716
- out.enum = [src.const];
19717
- }
19718
- const variantBranches = [
19719
- ...Array.isArray(src.oneOf) ? src.oneOf : [],
19720
- ...Array.isArray(src.anyOf) ? src.anyOf : []
19721
- ];
19722
- if (variantBranches.length > 0) {
19723
- const mergedProperties = {};
19724
- let requiredIntersection;
19725
- for (const branch of variantBranches) {
19726
- const sanitized = sanitizeGeminiSchemaNode(branch, seen);
19727
- const branchProperties = sanitized.properties ?? {};
19728
- for (const [key, value] of Object.entries(branchProperties)) {
19729
- const previous = mergedProperties[key];
19730
- const prevEnum = previous?.enum;
19731
- const nextEnum = value?.enum;
19732
- if (prevEnum && nextEnum) {
19733
- mergedProperties[key] = {
19734
- ...value,
19735
- enum: [.../* @__PURE__ */ new Set([...prevEnum, ...nextEnum])]
19736
- };
19737
- } else {
19738
- mergedProperties[key] = value;
19739
- }
19740
- }
19741
- const branchRequired = Array.isArray(sanitized.required) ? sanitized.required : [];
19742
- requiredIntersection = requiredIntersection === void 0 ? [...branchRequired] : requiredIntersection.filter((r) => branchRequired.includes(r));
19743
- }
19744
- out.properties = {
19745
- ...out.properties ?? {},
19746
- ...mergedProperties
19747
- };
19748
- if (requiredIntersection !== void 0 && requiredIntersection.length > 0) {
19749
- out.required = requiredIntersection;
19750
- }
19751
- if (typeof out.type !== "string") out.type = "object";
19752
- }
19753
- if (Array.isArray(src.allOf)) {
19754
- for (const branch of src.allOf) {
19755
- const sanitized = sanitizeGeminiSchemaNode(branch, seen);
19756
- out.properties = {
19757
- ...out.properties ?? {},
19758
- ...sanitized.properties ?? {}
19759
- };
19760
- if (Array.isArray(sanitized.required)) {
19761
- out.required = [
19762
- .../* @__PURE__ */ new Set([
19763
- ...out.required ?? [],
19764
- ...sanitized.required ?? []
19765
- ])
19766
- ];
19767
- }
19768
- }
19769
- if (typeof out.type !== "string") out.type = "object";
19770
- }
19771
- if (src.properties && typeof src.properties === "object") {
19772
- const properties = {};
19773
- for (const [key, value] of Object.entries(
19774
- src.properties
19775
- )) {
19776
- properties[key] = sanitizeGeminiSchemaNode(value, seen);
19777
- }
19778
- out.properties = properties;
19779
- if (typeof out.type !== "string") out.type = "object";
19780
- }
19781
- if (Array.isArray(src.required)) {
19782
- const properties = out.properties ?? {};
19783
- const required = [...new Set(src.required)].filter(
19784
- (r) => typeof r === "string" && r in properties
19785
- );
19786
- if (required.length > 0) out.required = required;
19787
- }
19788
- if (src.items !== void 0) {
19789
- out.items = sanitizeGeminiSchemaNode(src.items, seen);
19790
- if (typeof out.type !== "string") out.type = "array";
19791
- }
19792
- if (typeof out.type !== "string") out.type = "object";
19793
- return out;
19794
- }
19795
- function convertOpenAiToolsToGemini(tools) {
19796
- if (!Array.isArray(tools) || tools.length === 0) return void 0;
19797
- const declarations = [];
19798
- for (const tool of tools) {
19799
- if (!tool || typeof tool !== "object" || !("function" in tool)) continue;
19800
- const fn3 = tool.function;
19801
- const name = typeof fn3.name === "string" ? fn3.name : "";
19802
- if (!name) continue;
19803
- declarations.push({
19804
- name,
19805
- description: typeof fn3.description === "string" ? fn3.description : "",
19806
- parameters: sanitizeGeminiSchemaNode(
19807
- fn3.parameters ?? { type: "object", properties: {} }
19808
- )
19809
- });
19810
- }
19811
- if (declarations.length === 0) return void 0;
19812
- return [{ functionDeclarations: declarations }];
19813
- }
19814
- function createGeminiAccumulatorState() {
19815
- return {
19816
- text: "",
19817
- toolCalls: [],
19818
- reasoning: "",
19819
- events: []
19820
- };
19821
- }
19822
- function applyGeminiChunk(chunk, state, options) {
19823
- if (!chunk || typeof chunk !== "object") return;
19824
- const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
19825
- if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
19826
- const meta = response.usageMetadata;
19827
- const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
19828
- const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
19829
- const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
19830
- const cached3 = typeof meta.cachedContentTokenCount === "number" && Number.isFinite(meta.cachedContentTokenCount) ? (
19831
- // cached ⊆ prompt;对畸形上游防御性钳位,避免 cache_read > input 破坏归一化与计费
19832
- Math.min(Math.max(0, Math.floor(meta.cachedContentTokenCount)), prompt)
19833
- ) : 0;
19834
- state.usage = {
19835
- prompt_tokens: prompt,
19836
- completion_tokens: candidates2,
19837
- total_tokens: total,
19838
- ...cached3 > 0 ? { cache_read_input_tokens: cached3 } : {}
19839
- };
19840
- state.events.push({ kind: "usage", usage: state.usage });
19841
- }
19842
- const candidates = Array.isArray(response.candidates) ? response.candidates : [];
19843
- for (const candidate of candidates) {
19844
- if (!candidate || typeof candidate !== "object") continue;
19845
- const candidateFinishReason = candidate.finishReason;
19846
- if (typeof candidateFinishReason === "string" && candidateFinishReason.trim()) {
19847
- state.finishReason = candidateFinishReason.trim();
19848
- state.events.push({ kind: "finish", reason: state.finishReason });
19849
- }
19850
- const parts2 = Array.isArray(
19851
- candidate.content?.parts
19852
- ) ? candidate.content.parts : [];
19853
- for (const part of parts2) {
19854
- if (!part || typeof part !== "object") continue;
19855
- const partSignature = part.thoughtSignature;
19856
- const isThought = Boolean(part.thought);
19857
- if ("text" in part && typeof part.text === "string") {
19858
- const piece = part.text;
19859
- if (!isThought) {
19860
- state.text += piece;
19861
- if (piece) {
19862
- state.events.push({ kind: "text", text: piece });
19863
- if (options?.onTextDelta) options.onTextDelta(piece);
19864
- }
19865
- } else {
19866
- state.reasoning += piece;
19867
- if (piece) {
19868
- state.events.push({ kind: "reasoning", text: piece });
19869
- if (options?.onReasoningDelta) options.onReasoningDelta(piece);
19870
- }
19871
- }
19872
- }
19873
- if (isThought && typeof partSignature === "string" && partSignature) {
19874
- state.pendingThoughtSignature = partSignature;
19875
- }
19876
- if ("functionCall" in part && part.functionCall) {
19877
- const call = part.functionCall;
19878
- const name = typeof call.name === "string" ? call.name : "tool";
19879
- const id = typeof call.id === "string" ? call.id : `${name}_${state.toolCalls.length}`;
19880
- const argsObj = call.args && typeof call.args === "object" ? call.args : {};
19881
- const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : state.pendingThoughtSignature;
19882
- state.pendingThoughtSignature = void 0;
19883
- const toolCall = {
19884
- id,
19885
- type: "function",
19886
- function: { name, arguments: JSON.stringify(argsObj) },
19887
- ...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
19888
- };
19889
- state.toolCalls.push(toolCall);
19890
- state.events.push({ kind: "tool_call", toolCall });
19891
- }
19892
- }
19893
- }
19894
- }
19895
- function accumulateGeminiChunks(chunks2, options) {
19896
- const state = createGeminiAccumulatorState();
19897
- for (const chunk of chunks2) {
19898
- applyGeminiChunk(chunk, state, options);
19899
- }
19900
- return {
19901
- text: state.text,
19902
- toolCalls: state.toolCalls,
19903
- usage: state.usage,
19904
- finishReason: state.finishReason,
19905
- reasoningContent: state.reasoning,
19906
- events: state.events
19907
- };
19908
- }
19909
- async function accumulateGeminiStream(stream, options) {
19910
- const state = createGeminiAccumulatorState();
19911
- for await (const chunk of stream) {
19912
- applyGeminiChunk(chunk, state, options);
19913
- }
19914
- return {
19915
- text: state.text,
19916
- toolCalls: state.toolCalls,
19917
- usage: state.usage,
19918
- finishReason: state.finishReason,
19919
- reasoningContent: state.reasoning,
19920
- events: state.events
19921
- };
19922
- }
19923
- function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
19924
- return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
19925
- }
19926
- function buildGeminiGenerateContentRequest(args2) {
19927
- const { contents, systemTexts } = convertOpenAiMessagesToGemini(
19928
- args2.messages,
19929
- { attachSkipThoughtSignature: args2.attachSkipThoughtSignature }
19930
- );
19931
- const request3 = { contents };
19932
- if (systemTexts.length > 0) {
19933
- request3.systemInstruction = {
19934
- role: "user",
19935
- parts: systemTexts.map((text) => ({ text }))
19936
- };
19937
- }
19938
- const toolsResult = convertOpenAiToolsToGemini(args2.tools);
19939
- if (toolsResult) {
19940
- request3.tools = toolsResult;
19941
- request3.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
19942
- }
19943
- const generationConfig = {};
19944
- if (typeof args2.maxTokens === "number" && args2.maxTokens > 0) {
19945
- generationConfig.maxOutputTokens = args2.maxTokens;
19946
- }
19947
- if (typeof args2.temperature === "number") {
19948
- generationConfig.temperature = args2.temperature;
19949
- }
19950
- if (Object.keys(generationConfig).length > 0) {
19951
- request3.generationConfig = generationConfig;
19952
- }
19953
- return request3;
19954
- }
19955
-
19956
- // packages/agent-runtime/antigravityCloudCodeProvider.ts
19957
- var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
19958
- function buildCloudCodeAssistPayload(args2) {
19959
- const projectId = readAntigravityProjectId(args2.metadata);
19960
- if (!projectId) {
19961
- throw new Error(
19962
- "Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
19963
- );
19964
- }
19965
- const logicalModel = asOptionalTrimmedString(args2.openAiBody.model) ?? asOptionalTrimmedString(args2.agentConfig.model) ?? "gemini-3.1-pro";
19966
- const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
19967
- const rawMessages = Array.isArray(args2.openAiBody.messages) ? args2.openAiBody.messages : [];
19968
- const quirks = resolveGeminiModelQuirks(model);
19969
- const isClaude = quirks.isClaudeCrossModel;
19970
- const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
19971
- attachSkipThoughtSignature: quirks.allowsThoughtSignatureSentinel
19972
- });
19973
- if (contents.length === 0) {
19974
- throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
19975
- }
19976
- const prompt = args2.agentConfig.prompt?.trim();
19977
- if (prompt) systemTexts.unshift(prompt);
19978
- const request3 = { contents };
19979
- if (systemTexts.length > 0) {
19980
- request3.systemInstruction = {
19981
- role: "user",
19982
- parts: systemTexts.map((text) => ({ text }))
19983
- };
19984
- }
19985
- const tools = convertOpenAiToolsToGemini(
19986
- Array.isArray(args2.openAiBody.tools) ? args2.openAiBody.tools : void 0
19987
- );
19988
- if (tools) {
19989
- request3.tools = tools;
19990
- request3.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
19991
- }
19992
- const generationConfig = {};
19993
- if (profile?.maxOutputTokens) {
19994
- generationConfig.maxOutputTokens = profile.maxOutputTokens;
19995
- } else if (typeof args2.agentConfig.max_tokens === "number" && args2.agentConfig.max_tokens > 0) {
19996
- generationConfig.maxOutputTokens = args2.agentConfig.max_tokens;
19997
- }
19998
- if (typeof args2.agentConfig.temperature === "number") {
19999
- generationConfig.temperature = args2.agentConfig.temperature;
20000
- }
20001
- if (Object.keys(generationConfig).length > 0) {
20002
- request3.generationConfig = generationConfig;
20003
- }
20004
- const agentId = randomUUID();
20005
- const trajectoryId = randomUUID();
20006
- const step = 2;
20007
- const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
20008
- const labels = {
20009
- trajectory_id: trajectoryId,
20010
- last_step_index: String(step - 1),
20011
- used_claude: String(isClaude),
20012
- used_claude_conservative: String(isClaude)
20013
- };
20014
- if (profile?.modelEnum) {
20015
- labels.model_enum = profile.modelEnum;
20016
- }
20017
- request3.labels = labels;
20018
- request3.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
20019
- return {
20020
- url: `${resolveAntigravityCloudCodeBaseUrl(args2.agentConfig.customProviderUrl)}${STREAM_PATH}`,
20021
- envelope: {
20022
- project: projectId,
20023
- model,
20024
- request: request3,
20025
- requestId,
20026
- requestType: "agent",
20027
- userAgent: "antigravity"
20028
- }
20029
- };
20030
- }
20031
- function resolveAntigravityFinishReason(upstream) {
20032
- const normalized = (upstream ?? "").trim().toUpperCase();
20033
- if (normalized === "MAX_TOKENS") return "length";
20034
- if (normalized === "SAFETY" || normalized === "RECITATION" || normalized === "PROHIBITED_CONTENT" || normalized === "BLOCKLIST") {
20035
- return "content_filter";
20036
- }
20037
- return "stop";
20038
- }
20039
- function normalizeAntigravityCompletion(decoded) {
20040
- const { text, toolCalls, usage, finishReason, reasoningContent, events } = decoded;
20041
- const normalizedFinishReason = (finishReason ?? "").trim().toUpperCase();
20042
- if (!text && !reasoningContent && toolCalls.length === 0 && !finishReason && !usage) {
20043
- const body = {
20044
- error: {
20045
- message: "antigravity upstream returned an empty stream (no content, finishReason or usage); channel degradation, not model emptiness"
20046
- },
20047
- provider_events: events
20048
- };
20049
- return {
20050
- status: 502,
20051
- text: "",
20052
- toolCalls: [],
20053
- providerEvents: events,
20054
- body
20055
- };
20056
- }
20057
- if (normalizedFinishReason === "MALFORMED_FUNCTION_CALL") {
20058
- const message2 = "antigravity upstream returned MALFORMED_FUNCTION_CALL (model generated an invalid function call or tool arguments were rejected by upstream)";
20059
- const providerFailure = {
20060
- kind: "provider_failure",
20061
- provider: "antigravity",
20062
- code: "MALFORMED_FUNCTION_CALL",
20063
- message: message2,
20064
- providerReason: "MALFORMED_FUNCTION_CALL",
20065
- retryable: false,
20066
- status: 502
20067
- };
20068
- return {
20069
- status: 502,
20070
- text: "",
20071
- toolCalls: [],
20072
- finishReason,
20073
- providerEvents: events,
20074
- providerFailure,
20075
- runtimeProviderFailure: {
20076
- message: providerFailure.message,
20077
- retryable: providerFailure.retryable
20078
- },
20079
- body: {
20080
- error: {
20081
- message: message2,
20082
- code: "MALFORMED_FUNCTION_CALL",
20083
- category: "malformed_function_call",
20084
- providerReason: "MALFORMED_FUNCTION_CALL",
20085
- retryable: false
20086
- },
20087
- provider_failure: providerFailure,
20088
- provider_events: events
20089
- }
20090
- };
20091
- }
20092
- const message = {
20093
- role: "assistant",
20094
- content: text || null
20095
- };
20096
- if (toolCalls.length > 0) message.tool_calls = toolCalls;
20097
- if (reasoningContent) message.reasoning_content = reasoningContent;
20098
- return {
20099
- status: 200,
20100
- text,
20101
- ...reasoningContent ? { reasoningContent } : {},
20102
- toolCalls,
20103
- ...usage ? { usage } : {},
20104
- ...finishReason ? { finishReason } : {},
20105
- providerEvents: events,
20106
- body: {
20107
- choices: [{
20108
- index: 0,
20109
- message,
20110
- finish_reason: toolCalls.length > 0 ? "tool_calls" : resolveAntigravityFinishReason(finishReason)
20111
- }],
20112
- ...usage ? { usage } : {},
20113
- provider_events: events
20114
- }
20115
- };
20116
- }
20117
- async function fetchAntigravityCloudCodeCompletion(args2) {
20118
- const fetchImpl = args2.fetchImpl ?? fetch;
20119
- const { url, envelope } = buildCloudCodeAssistPayload(args2);
20120
- const response = await fetchImpl(url, {
20121
- method: "POST",
20122
- headers: {
20123
- Authorization: `Bearer ${args2.accessToken}`,
20124
- "Content-Type": "application/json",
20125
- "User-Agent": getAntigravityUserAgent()
20126
- },
20127
- body: JSON.stringify(envelope),
20128
- signal: args2.signal
20129
- });
20130
- if (!response.ok) {
20131
- const errorText = await response.text();
20132
- return {
20133
- status: response.status,
20134
- text: "",
20135
- toolCalls: [],
20136
- providerEvents: [],
20137
- // 保留上游结构:Antigravity 的限流 body 同样携带结构化的重置信息,
20138
- // 压成字符串会让冷却退化成 5 分钟默认值。
20139
- body: parseUpstreamErrorBody(errorText, response.statusText)
20140
- };
20141
- }
20142
- const chunkStream = streamSseDataValues(response, parseSseDataLineJson);
20143
- const { text, toolCalls, usage, finishReason, reasoningContent, events } = await accumulateGeminiStream(chunkStream, {
20144
- onTextDelta: args2.onTextDelta,
20145
- onReasoningDelta: args2.onReasoningDelta
20146
- });
20147
- const normalized = normalizeAntigravityCompletion({
20148
- text,
20149
- toolCalls,
20150
- usage,
20151
- finishReason,
20152
- reasoningContent,
20153
- events
20154
- });
20155
- if (normalized.status !== 200 || !text && toolCalls.length === 0) {
20156
- console.warn(
20157
- `[antigravity] empty completion: finishReason=${JSON.stringify(finishReason)} reasoningLen=${reasoningContent?.length ?? 0} usage=${JSON.stringify(usage) ?? "none"} model=${String(envelope.model)} base=${new URL(url).host}`
20158
- );
20159
- }
20160
- return normalized;
20161
- }
20162
-
20163
20051
  // packages/agent-runtime/devin/devinProvider.ts
20164
- import { randomBytes, randomUUID as randomUUID2 } from "node:crypto";
20052
+ import { randomBytes, randomUUID } from "node:crypto";
20165
20053
  var CLIENT_NAME = "chisel";
20166
- var CLIENT_VERSION = "2026.8.18";
20054
+ var CLIENT_VERSION = "3000.11.3";
20167
20055
  function writeVarint(fieldNum, value) {
20168
20056
  const tag = fieldNum << 3 | 0;
20169
20057
  const bytes = [];
@@ -20223,7 +20111,7 @@ function encodeDevinClientMetadata(token) {
20223
20111
  function encodeDevinChatMessage(msg) {
20224
20112
  const source = msg.role === "assistant" ? 2 : msg.role === "tool" ? 4 : 1;
20225
20113
  return Buffer.concat([
20226
- writeStringField(1, randomUUID2()),
20114
+ writeStringField(1, randomUUID()),
20227
20115
  writeVarint(2, source),
20228
20116
  writeStringField(3, msg.text),
20229
20117
  ...(msg.toolCalls ?? []).map(
@@ -20311,7 +20199,7 @@ ${item.text}`;
20311
20199
  const chatMessageBuffers = coalesced.map((m) => encodeDevinChatMessage(m));
20312
20200
  const completionConfig = buildCompletionConfig({ temperature });
20313
20201
  const modelConfig = Buffer.concat([
20314
- writeStringField(1, randomUUID2()),
20202
+ writeStringField(1, randomUUID()),
20315
20203
  writeVarint(2, 1),
20316
20204
  writeVarint(3, 4)
20317
20205
  ]);
@@ -20323,7 +20211,7 @@ ${item.text}`;
20323
20211
  writeMessageField(8, completionConfig),
20324
20212
  ...tools.map((tool) => writeMessageField(10, encodeDevinToolDefinition(tool))),
20325
20213
  writeMessageField(15, modelConfig),
20326
- writeStringField(16, randomUUID2()),
20214
+ writeStringField(16, randomUUID()),
20327
20215
  writeVarint(20, 1),
20328
20216
  writeStringField(21, model)
20329
20217
  ]);
@@ -20685,20 +20573,16 @@ function createDevinProvider(options) {
20685
20573
  }
20686
20574
 
20687
20575
  export {
20576
+ readCommandActionGatePayload,
20577
+ readActionGate,
20688
20578
  Option_exports,
20689
20579
  Duration_exports,
20690
20580
  Exit_exports,
20691
20581
  Effect_exports,
20692
- readCommandActionGatePayload,
20693
- readActionGate,
20694
- evaluateFileWritePolicy,
20695
- summarizeToolArguments,
20696
20582
  formatToolOverflowMarker,
20697
20583
  LOCAL_AGENT_CONFIG_MISSING_CODE,
20698
20584
  LOCAL_TURN_ABORTED_CODE,
20699
20585
  runLocalAgentTurn,
20700
- parseSseDataLineJson,
20701
- parseSseDataLineObject,
20702
20586
  codexStreamFailureStatus,
20703
20587
  aggregateResponsesStream,
20704
20588
  buildOpenAiCompatibleChatCompletionRequest,
@@ -20714,8 +20598,6 @@ export {
20714
20598
  createHybridRecordStore,
20715
20599
  isDestructiveShellCommand,
20716
20600
  evaluateShellCommandPolicy,
20717
- resolveLocalToolPolicy,
20718
- executeLocalToolWithPolicy,
20719
20601
  filterRetainedLedgerRecords,
20720
20602
  isLineRangeCovered,
20721
20603
  getProcessRegistry,
@@ -20726,17 +20608,14 @@ export {
20726
20608
  internalSearchWorkspace,
20727
20609
  internalListWorkspaceEntries,
20728
20610
  createLocalWorkspaceToolExecutors,
20611
+ buildToolParametersIndex,
20612
+ getAgentRuntimeToolParametersIndex,
20613
+ resolveLocalToolPolicy,
20614
+ executeLocalToolWithPolicy,
20729
20615
  localDialogMessageRecordToRuntimeMessage,
20730
20616
  buildLocalDialogWritePlan,
20731
20617
  buildNoloWorkspaceCliToolExecutors,
20732
20618
  buildLoadSkillExecutor,
20733
- parseUpstreamErrorBody,
20734
- isGemini3Model,
20735
- accumulateGeminiChunks,
20736
- shouldUseGeminiNativeToolRoute,
20737
- buildGeminiGenerateContentRequest,
20738
- resolveAntigravityFinishReason,
20739
- fetchAntigravityCloudCodeCompletion,
20740
20619
  readDevinUpstreamFailure,
20741
20620
  createDevinProvider
20742
20621
  };