nolo-cli 0.16.0 → 0.18.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 (134) hide show
  1. package/{_executeModel-AVCA2NAV.js → _executeModel-X5PCIZN6.js} +50 -44
  2. package/{action-F5JACQBG.js → action-LT7BRFLK.js} +10 -9
  3. package/{addContentAction-AQXEYRBE.js → addContentAction-PL3KKBDH.js} +9 -8
  4. package/{addDialogAgentAction-EJHHJZWW.js → addDialogAgentAction-FCMSKYAF.js} +8 -7
  5. package/{agentDeleteCommand-QW5PUMDQ.js → agentDeleteCommand-2BZDQV36.js} +32 -29
  6. package/{agentEmailCommands-4ORVLGVQ.js → agentEmailCommands-2QJDGRMB.js} +62 -56
  7. package/{agentListCommands-YWBYRTYC.js → agentListCommands-6VEPTKBI.js} +31 -28
  8. package/{agentMachineCommands-JSQW4FOA.js → agentMachineCommands-NVVHNWYI.js} +30 -27
  9. package/{agentPullCommand-6HWUT3SW.js → agentPullCommand-ZZGU5KOY.js} +4 -4
  10. package/{agentRecordCommands-AASIWOBT.js → agentRecordCommands-4GGRDMD4.js} +57 -51
  11. package/{agentRunCommand-TB5BHXUH.js → agentRunCommand-XOLQNKBZ.js} +63 -54
  12. package/{agentRunControl-6ADXVYMR.js → agentRunControl-Y5AFH5PQ.js} +24 -1
  13. package/{agentRuntimeLocal-QNPNJRVH.js → agentRuntimeLocal-7WYWCGL4.js} +25 -22
  14. package/{agentSlice-RUNXC62Y.js → agentSlice-EAXPGEYV.js} +9 -8
  15. package/appDeleteCommands-77KR2RJ4.js +127 -0
  16. package/appDeployCommands-K7CAHGBI.js +166 -0
  17. package/appDeployStatusCommands-4OEKLTBT.js +147 -0
  18. package/appGetCommands-VM2WDLAZ.js +122 -0
  19. package/appListCommands-GX6BBA6U.js +125 -0
  20. package/{authCommand-YFTR3347.js → authCommand-DY6UUL6O.js} +16 -9
  21. package/{authCommands-YXGOXNBZ.js → authCommands-XTBV7OFZ.js} +6 -5
  22. package/{chunk-DPAB4FQ7.js → chunk-23FZYPLC.js} +1608 -212
  23. package/{chunk-LPEUV5RE.js → chunk-34WPV75U.js} +23 -2
  24. package/{chunk-XPC5C7BK.js → chunk-3ND52WIL.js} +2 -2
  25. package/{chunk-SOTZ6RDN.js → chunk-3Q7WHGCB.js} +1 -1
  26. package/{chunk-3OIRVWXA.js → chunk-3ZX7PERL.js} +10 -1
  27. package/{chunk-KKY4B2Q2.js → chunk-4PWB7JRR.js} +4 -1
  28. package/{chunk-6N4KODMN.js → chunk-4T5F7YZQ.js} +1 -1
  29. package/chunk-7BUYEZ6U.js +671 -0
  30. package/{chunk-AS3ZQ3O2.js → chunk-7OBMZCRD.js} +1 -1
  31. package/{chunk-IGXREZW2.js → chunk-AHCY2S2I.js} +1 -1
  32. package/{chunk-QLUFR47U.js → chunk-AL2V7U3E.js} +1 -1
  33. package/{chunk-MTU75CZ2.js → chunk-B5TOXZAK.js} +1 -1
  34. package/{chunk-AUURUT6L.js → chunk-BV4VEE3W.js} +264 -424
  35. package/{chunk-FRV6A633.js → chunk-CZ6NYQTV.js} +13 -4
  36. package/{chunk-PCTUYVUM.js → chunk-DFCFMCY6.js} +10 -3
  37. package/{chunk-JTMNCCWF.js → chunk-DKZFOK24.js} +16 -87
  38. package/chunk-DL6EPNIK.js +50 -0
  39. package/{chunk-ZQBL7LIC.js → chunk-EDV7EBOI.js} +317 -216
  40. package/{chunk-IWLUTMYX.js → chunk-ELT65PZW.js} +2 -2
  41. package/chunk-FQZZLA3C.js +223 -0
  42. package/{chunk-55NSNCFM.js → chunk-FXUSIQC2.js} +1 -1
  43. package/{chunk-MR6ISAGB.js → chunk-G5U6LDLG.js} +6 -6
  44. package/chunk-GFUIQ4RY.js +136 -0
  45. package/{chunk-NVEWUJVX.js → chunk-HEGV7BH3.js} +1 -1
  46. package/{chunk-BEBNFWDU.js → chunk-HWW2M4SN.js} +3 -3
  47. package/{chunk-4L2OJPCU.js → chunk-I2ZJKTG5.js} +58 -8
  48. package/{chunk-Z5JQNBNY.js → chunk-IYEXFJPC.js} +34 -15
  49. package/{setDialogExtraReferencesAction-LR6MSIXO.js → chunk-JLA4FXYC.js} +2 -17
  50. package/chunk-KFEVY3ST.js +255 -0
  51. package/{chunk-4FX6NVDW.js → chunk-L4F3I4SR.js} +3 -136
  52. package/{chunk-XBS2WYJ2.js → chunk-LLWKHDG4.js} +1 -1
  53. package/{chunk-3WGLLTK4.js → chunk-LSFAWXKC.js} +100 -3
  54. package/{chunk-6EVITP2G.js → chunk-MHSGJW4Z.js} +2 -251
  55. package/{chunk-O6W2O2DA.js → chunk-MKA6QE5E.js} +6 -2
  56. package/{chunk-DGEYDWEZ.js → chunk-MPVYDS7I.js} +3 -3
  57. package/{chunk-KFHN5NGJ.js → chunk-MVQ4TBSD.js} +1 -1
  58. package/{chunk-AVVZUXXC.js → chunk-N54HIJVJ.js} +34 -13
  59. package/{chunk-EHLHSX7R.js → chunk-OK6YSWLH.js} +9 -2
  60. package/{chunk-33BJUVK4.js → chunk-PIZYJVHQ.js} +5 -5
  61. package/{chunk-RLCXU7A5.js → chunk-PJSV3IZ5.js} +1 -1
  62. package/{chunk-7UKFVQ5W.js → chunk-R35XMF6F.js} +126 -41
  63. package/{chunk-OOSFSFMA.js → chunk-R5V5G73M.js} +2 -0
  64. package/{chunk-S2LXHNHG.js → chunk-REA4JLBH.js} +6 -6
  65. package/chunk-RQN4SEKL.js +107 -0
  66. package/{chunk-EABWT43X.js → chunk-RVOUXDFU.js} +5 -5
  67. package/{chunk-NSCHQQPU.js → chunk-SCTYAHYK.js} +470 -325
  68. package/{chunk-JTINRTBT.js → chunk-SKDNBYZK.js} +2 -2
  69. package/{chunk-M43KDE25.js → chunk-SWDPIPOY.js} +2 -8
  70. package/{chunk-KMQPSTMJ.js → chunk-TRT4I4UD.js} +2 -2
  71. package/{chunk-66X4VSRC.js → chunk-UAIVG4J6.js} +42 -2
  72. package/{chunk-3663CXZN.js → chunk-UBHAWFQ6.js} +143 -31
  73. package/{chunk-YJKXGHJ6.js → chunk-UGUW3FHG.js} +4 -4
  74. package/{chunk-P3RIAYGG.js → chunk-V3ED5AWK.js} +3 -3
  75. package/chunk-V5R4NZP2.js +78 -0
  76. package/{chunk-4IJYA27C.js → chunk-VDXCXCXH.js} +1 -1
  77. package/{chunk-MYMMNKYL.js → chunk-VNAEBGDK.js} +156 -6
  78. package/{chunk-FY233ZFU.js → chunk-VYHDJEQD.js} +110 -192
  79. package/{chunk-W4NVOSFF.js → chunk-WFHXMLHZ.js} +1 -1
  80. package/{chunk-H33743XH.js → chunk-WJRJDX2W.js} +1 -1
  81. package/chunk-X4Q4UZEY.js +26 -0
  82. package/{chunk-RPDGJO4D.js → chunk-XHG22OEX.js} +4 -4
  83. package/{chunk-DVRHHFEA.js → chunk-XMLRJUU5.js} +1 -1
  84. package/{chunk-3S2VOMIF.js → chunk-XRZJGPFI.js} +7 -7
  85. package/{chunk-GSINCD4P.js → chunk-YGW4G5W5.js} +25 -12
  86. package/chunk-ZZ2MH7LE.js +84 -0
  87. package/{cliExecutor-K3F7DMRO.js → cliExecutor-DNE7TCC4.js} +2 -2
  88. package/codingSkills-36KN5NQT.js +48 -0
  89. package/{createAgentAutomationAction-FNHPSKKO.js → createAgentAutomationAction-GNFF524X.js} +20 -19
  90. package/{createDialogAction-TZCVQ3NU.js → createDialogAction-RB55KCLO.js} +22 -21
  91. package/{createPageAction-EIGZ3BKT.js → createPageAction-Y7343GLU.js} +26 -25
  92. package/{db-HCJ5PRB5.js → db-W3O47YGF.js} +38 -12
  93. package/{dbSlice-7KQH6GOU.js → dbSlice-CGSRFJN3.js} +8 -7
  94. package/{deleteFile-WPWVZE4B.js → deleteFile-WDZ3VM7B.js} +3 -3
  95. package/{dialogCommands-FO77J5DQ.js → dialogCommands-IAZK6YHQ.js} +30 -27
  96. package/{dialogSlice-MM5U4KE2.js → dialogSlice-UQAXF23P.js} +20 -19
  97. package/{docCreateCommands-I3BS3AZI.js → docCreateCommands-I2EWZGCI.js} +33 -28
  98. package/{docDeleteCommands-Q2OPV52P.js → docDeleteCommands-IZ45UZKG.js} +32 -27
  99. package/{docReadCommands-YOOFACYZ.js → docReadCommands-R6Z4QJYU.js} +31 -26
  100. package/{docStore-NGYQ2JTR.js → docStore-5HOJ4D7D.js} +21 -20
  101. package/{docUpdateCommands-2B32ITHN.js → docUpdateCommands-2LRBKQPY.js} +32 -27
  102. package/{fetchMessages-KTNM7QAR.js → fetchMessages-BMGVZVSE.js} +4 -3
  103. package/{getPricing-P4XRJRZB.js → getPricing-G7DLAST6.js} +3 -3
  104. package/{handleSendMessageAction-JRZWWBKP.js → handleSendMessageAction-Q4HY35WX.js} +21 -20
  105. package/index.js +95 -64
  106. package/{localDialogRead-2VRI24F4.js → localDialogRead-4H3QJFLW.js} +2 -2
  107. package/{localRuntimeDb-LGDF6FQP.js → localRuntimeDb-THJZGAOJ.js} +1 -1
  108. package/{machineCommands-WRWF2ICZ.js → machineCommands-PKBPQKTY.js} +63 -57
  109. package/{machineWsRunDispatch-ZX7Q3TWZ.js → machineWsRunDispatch-UZAW4OXJ.js} +55 -49
  110. package/{models-WQ5N4OJM.js → models-DJFSJ7SW.js} +2 -2
  111. package/package.json +1 -1
  112. package/queryRunOverlay-O4LOMMPO.js +161 -0
  113. package/{read-CN3TNXIP.js → read-3FMPZPER.js} +3 -3
  114. package/{readDocTool-WF3675ED.js → readDocTool-VSYHKK3V.js} +1 -1
  115. package/{readlineWorkspace-ZTGRGW46.js → readlineWorkspace-Y2RDOFZG.js} +762 -218
  116. package/{removeDialogAgentAction-YDHBFEGI.js → removeDialogAgentAction-OAGA2G3U.js} +10 -9
  117. package/{runAgentClientLoop-JZCOP7LG.js → runAgentClientLoop-NBPIKJ6J.js} +44 -38
  118. package/runOverlayPresentation-ZO4VCWEU.js +11 -0
  119. package/{runtimeDoctorCommands-THIHX2SY.js → runtimeDoctorCommands-E2OUORHK.js} +6 -6
  120. package/setDialogExtraReferencesAction-JZEXA5SL.js +27 -0
  121. package/{setPrimaryDialogAgentAction-IIVDCY5C.js → setPrimaryDialogAgentAction-4ZUQQKDG.js} +26 -17
  122. package/{settingSlice-O23YDK2O.js → settingSlice-7MNKHZ6R.js} +9 -8
  123. package/{skillDiscovery-6M2BZUFN.js → skillDiscovery-KJWT7JBU.js} +3 -3
  124. package/{spaceCommands-VV4GTPQK.js → spaceCommands-DHCZ7J5I.js} +31 -28
  125. package/{spaceSlice-DRWWZJP7.js → spaceSlice-ZXLLG3CR.js} +20 -19
  126. package/{streamAgentChatTurn-Y6WGATQR.js → streamAgentChatTurn-L3YW6LSB.js} +98 -57
  127. package/{tableCommands-3P7MJ3PF.js → tableCommands-BEQAGE4I.js} +1 -1
  128. package/{tools-PUNBY3AH.js → tools-ECGXR5QF.js} +33 -28
  129. package/{tuiSummaryLlmCaller-F64WLSAF.js → tuiSummaryLlmCaller-OMSCNHXA.js} +6 -5
  130. package/types-ZSTJ7MPR.js +7 -0
  131. package/{updateDialogTitleAction-YSR4TCMB.js → updateDialogTitleAction-HQ2EUDFT.js} +23 -22
  132. package/{chunk-O4BU24WZ.js → chunk-6Y7A3OQQ.js} +3 -3
  133. package/{chunk-CMKUBIGW.js → chunk-X7W4TNB4.js} +3 -3
  134. package/{localRuntimeAuthority-TEGCOWX4.js → localRuntimeAuthority-4IXJCHZ7.js} +3 -3
@@ -3,12 +3,11 @@ import {
3
3
  refreshAntigravityOAuthToken,
4
4
  refreshOpenAiCodexToken,
5
5
  refreshXaiOAuthToken
6
- } from "./chunk-EHLHSX7R.js";
6
+ } from "./chunk-OK6YSWLH.js";
7
7
  import {
8
8
  buildLocalAgentLookupKeys,
9
- normalizeAgentHandle,
10
9
  shouldReadAgentKeyRemotely
11
- } from "./chunk-M43KDE25.js";
10
+ } from "./chunk-SWDPIPOY.js";
12
11
  import {
13
12
  LOCAL_CODEX_AGENT_ID,
14
13
  LOCAL_CODEX_AGENT_KEY,
@@ -17,17 +16,17 @@ import {
17
16
  } from "./chunk-VHBWHNVT.js";
18
17
  import {
19
18
  inferCaptureIntent
20
- } from "./chunk-KFHN5NGJ.js";
19
+ } from "./chunk-MVQ4TBSD.js";
21
20
  import {
22
21
  inlineImageUrlsForCustomProvider,
23
22
  prepareTools
24
- } from "./chunk-FRV6A633.js";
23
+ } from "./chunk-CZ6NYQTV.js";
25
24
  import {
26
25
  getAntigravityUserAgent,
27
26
  isAntigravityOAuthAgent,
28
27
  readAntigravityProjectId,
29
28
  resolveAntigravityCloudCodeBaseUrl
30
- } from "./chunk-55NSNCFM.js";
29
+ } from "./chunk-FXUSIQC2.js";
31
30
  import {
32
31
  FORCED_TOOLS,
33
32
  addDefaultLightWebToolsForConfiguredAgents,
@@ -36,19 +35,13 @@ import {
36
35
  applyDisabledTools,
37
36
  applySystemBuiltinSkillFilter,
38
37
  expandEnabledPacks,
39
- formatListRunsCard,
40
- formatNotFoundRunCard,
41
- formatStartRunCard,
42
- formatStatusRunCard,
43
- formatStopRunCard,
44
38
  readXPostFunc,
45
39
  readXPostFunctionSchema,
46
40
  readXhsProfileFunc,
47
41
  readXhsProfileFunctionSchema,
48
42
  rememberMemoryFunctionSchema,
49
- resolveEffectiveEnabledPacks,
50
- resolveRunLabel
51
- } from "./chunk-ZQBL7LIC.js";
43
+ resolveEffectiveEnabledPacks
44
+ } from "./chunk-EDV7EBOI.js";
52
45
  import {
53
46
  createDrainExhaustedResponse,
54
47
  isCoreDrainingBody,
@@ -58,15 +51,18 @@ import {
58
51
  import {
59
52
  normalizeDialogTitle
60
53
  } from "./chunk-OWOHNGCN.js";
54
+ import {
55
+ getDefaultCliLocalRuntimeDb
56
+ } from "./chunk-WJRJDX2W.js";
61
57
  import {
62
58
  prepareTokenUsageData
63
- } from "./chunk-NSCHQQPU.js";
59
+ } from "./chunk-SCTYAHYK.js";
64
60
  import {
65
61
  BUILTIN_TITLE_LLM_CONFIG
66
62
  } from "./chunk-XOIF2TNF.js";
67
63
  import {
68
64
  fetchServerSyncedCredential
69
- } from "./chunk-S2LXHNHG.js";
65
+ } from "./chunk-REA4JLBH.js";
70
66
  import {
71
67
  buildAgentRuntimeDialogWritePlan,
72
68
  buildLocalWorkspaceOpenAiTools,
@@ -77,9 +73,10 @@ import {
77
73
  executeLocalToolWithPolicy,
78
74
  executeOpenAiCompatibleChatCompletion,
79
75
  parseSseDataLineJson,
76
+ parseSseDataLineObject,
80
77
  readOpenAiCompatibleSseCompletion,
81
78
  resolveOpenAiCompatibleProviderConfig
82
- } from "./chunk-7UKFVQ5W.js";
79
+ } from "./chunk-R35XMF6F.js";
83
80
  import {
84
81
  buildPlatformChatCompletionRequest,
85
82
  canUsePlatformChatProvider,
@@ -88,25 +85,27 @@ import {
88
85
  readSseDataValues,
89
86
  resolvePlatformChatProviderConfig,
90
87
  shouldUsePlatformChatProvider
91
- } from "./chunk-AVVZUXXC.js";
88
+ } from "./chunk-N54HIJVJ.js";
92
89
  import {
93
90
  resolveAgentRuntimeConfigFromRecord
94
91
  } from "./chunk-OIQPORYI.js";
95
92
  import {
96
- parseToolArgumentsJson,
97
93
  summarizeToolArguments
98
- } from "./chunk-GSINCD4P.js";
94
+ } from "./chunk-YGW4G5W5.js";
95
+ import {
96
+ convertMessagesToResponsesInput,
97
+ toResponsesTools
98
+ } from "./chunk-KFEVY3ST.js";
99
99
  import {
100
100
  resolvePlatformAuthToken
101
- } from "./chunk-6EVITP2G.js";
101
+ } from "./chunk-MHSGJW4Z.js";
102
102
  import {
103
103
  buildLoadSkillExecutor,
104
104
  buildNoloWorkspaceCliToolExecutors,
105
105
  buildNoloWorkspaceOpenAiTools,
106
- canonicalizeToolNames,
107
106
  parseNoloWorkspaceToolArguments,
108
107
  resolveRuntimeToolSurfaceForAgent
109
- } from "./chunk-JTMNCCWF.js";
108
+ } from "./chunk-DKZFOK24.js";
110
109
  import {
111
110
  clipCompactText
112
111
  } from "./chunk-5MMAK75Q.js";
@@ -122,6 +121,15 @@ import {
122
121
  readOAuthCredential,
123
122
  resolveFreshAccessToken
124
123
  } from "./chunk-JZPBVBIY.js";
124
+ import {
125
+ isAdaptiveThinkingModelId
126
+ } from "./chunk-UAIVG4J6.js";
127
+ import {
128
+ toErrorMessage
129
+ } from "./chunk-HNMXYYJR.js";
130
+ import {
131
+ canonicalizeToolNames
132
+ } from "./chunk-ZZ2MH7LE.js";
125
133
  import {
126
134
  compactWhitespace
127
135
  } from "./chunk-DWLEOOGR.js";
@@ -129,22 +137,29 @@ import {
129
137
  checkStaleRun,
130
138
  finalizeRunRecord,
131
139
  findRunRecord,
132
- listRunRecords,
140
+ gcRunRecords,
141
+ queryRunRecords,
133
142
  spawnLocalBackgroundRun
134
- } from "./chunk-MYMMNKYL.js";
143
+ } from "./chunk-VNAEBGDK.js";
144
+ import {
145
+ TASK_PREVIEW_MAX,
146
+ formatListRunsCard,
147
+ formatNotFoundRunCard,
148
+ formatStartRunCard,
149
+ formatStatusRunCard,
150
+ formatStopRunCard,
151
+ isAgentNameFallback,
152
+ isAgentRunTerminalStatus,
153
+ resolveRunLabel,
154
+ shortRunId
155
+ } from "./chunk-FQZZLA3C.js";
135
156
  import {
136
157
  CliProviderQuotaError,
137
158
  executeCli
138
- } from "./chunk-CMKUBIGW.js";
159
+ } from "./chunk-X7W4TNB4.js";
139
160
  import {
140
161
  buildCliPrompt
141
162
  } from "./chunk-ATNTHIZI.js";
142
- import {
143
- toErrorMessage
144
- } from "./chunk-HNMXYYJR.js";
145
- import {
146
- getDefaultCliLocalRuntimeDb
147
- } from "./chunk-H33743XH.js";
148
163
  import {
149
164
  isCompiledBinary,
150
165
  parseUserIdFromAuthToken
@@ -152,27 +167,27 @@ import {
152
167
  import {
153
168
  DEFAULT_NOLO_SERVER_URL
154
169
  } from "./chunk-OLZBQWZU.js";
155
- import {
156
- asRecordOrEmpty
157
- } from "./chunk-KX6YBIHG.js";
158
170
  import {
159
171
  createTokenKey,
160
172
  createUserKey,
161
173
  dialogMessageRange
162
- } from "./chunk-O4BU24WZ.js";
174
+ } from "./chunk-6Y7A3OQQ.js";
175
+ import {
176
+ asOptionalFiniteNumber
177
+ } from "./chunk-WWC7I6TA.js";
163
178
  import {
164
179
  asTrimmedNonEmptyStringArray
165
180
  } from "./chunk-I42VC5KR.js";
166
181
  import {
167
- asOptionalFiniteNumber
168
- } from "./chunk-WWC7I6TA.js";
182
+ asTrimmedLowercaseString
183
+ } from "./chunk-QSJ3HFEF.js";
169
184
  import {
170
185
  BUILTIN_NOLO_AGENT_KEY,
171
186
  PUBLIC_DEEPSEEK_V4_FLASH_AGENT_KEY,
172
187
  PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
173
188
  PUBLIC_GLM_52_AGENT_KEY,
174
189
  PUBLIC_KIMI_K26_IMAGE_AGENT_KEY
175
- } from "./chunk-XPC5C7BK.js";
190
+ } from "./chunk-3ND52WIL.js";
176
191
  import {
177
192
  asTrimmedString
178
193
  } from "./chunk-3EUW3WEO.js";
@@ -262,6 +277,10 @@ var STRINGS = {
262
277
  en: "Cleared current dialog messages.",
263
278
  zh: "\u5DF2\u6E05\u9664\u5F53\u524D\u5BF9\u8BDD\u6D88\u606F\u3002"
264
279
  },
280
+ persistentProcessesLeft: {
281
+ en: "{0} persistent process(es) left running in the background.",
282
+ zh: "\u4ECD\u6709 {0} \u4E2A\u5E38\u9A7B\u540E\u53F0\u8FDB\u7A0B\u5728\u540E\u53F0\u7EE7\u7EED\u8FD0\u884C\u3002"
283
+ },
265
284
  clearNoDialog: {
266
285
  en: "No current dialog messages to clear.",
267
286
  zh: "\u5F53\u524D\u6CA1\u6709\u53EF\u6E05\u9664\u7684\u5BF9\u8BDD\u6D88\u606F\u3002"
@@ -294,6 +313,10 @@ var STRINGS = {
294
313
  en: "Agent switch cancelled.",
295
314
  zh: "\u5DF2\u53D6\u6D88\u5207\u6362 agent\u3002"
296
315
  },
316
+ agentPickerLoading: {
317
+ en: "Loading agents\u2026",
318
+ zh: "\u6B63\u5728\u52A0\u8F7D agent \u5217\u8868\u2026"
319
+ },
297
320
  historyPickerTitle: {
298
321
  en: "Resume dialog (\u2191\u2193 Enter Esc)",
299
322
  zh: "\u6062\u590D\u5BF9\u8BDD\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
@@ -458,6 +481,10 @@ var STRINGS = {
458
481
  en: "Run stopped",
459
482
  zh: "\u8FD0\u884C\u5DF2\u505C\u6B62"
460
483
  },
484
+ runFinishedLabel: {
485
+ en: "Run finished",
486
+ zh: "\u8FD0\u884C\u5DF2\u7ED3\u675F"
487
+ },
461
488
  runLogTailLabel: {
462
489
  en: "Log tail:",
463
490
  zh: "\u65E5\u5FD7\u5C3E\u90E8\uFF1A"
@@ -492,6 +519,10 @@ var STRINGS = {
492
519
  en: "selected",
493
520
  zh: "\u5DF2\u9009"
494
521
  },
522
+ dialogMultiSelectRequired: {
523
+ en: "Pick at least one option to submit",
524
+ zh: "\u81F3\u5C11\u9009\u62E9\u4E00\u9879\u624D\u80FD\u63D0\u4EA4"
525
+ },
495
526
  dialogConfirmHint: {
496
527
  en: "(\u2191\u2193 move \xB7 Enter choose \xB7 Esc cancel)",
497
528
  zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
@@ -532,7 +563,7 @@ var STRINGS = {
532
563
  en: "abort the operation",
533
564
  zh: "\u4E2D\u6B62\u64CD\u4F5C"
534
565
  },
535
- // --- Ask choice (ui_ask_choice) ------------------------------------------
566
+ // --- Ask choice (ask_user) ------------------------------------------
536
567
  askChoiceTitle: {
537
568
  en: "question",
538
569
  zh: "\u95EE\u9898"
@@ -613,10 +644,6 @@ var STRINGS = {
613
644
  en: "tools",
614
645
  zh: "\u5DE5\u5177"
615
646
  },
616
- contextFieldThinking: {
617
- en: "thinking",
618
- zh: "\u601D\u8003"
619
- },
620
647
  contextFieldServer: {
621
648
  en: "server",
622
649
  zh: "\u670D\u52A1\u7AEF"
@@ -654,7 +681,6 @@ var STRINGS = {
654
681
  " /context Show workspace context and next actions",
655
682
  " /runtime <mode> Use auto, local, or server runtime",
656
683
  " /tools <mode> Control tool trace: hide, compact, verbose",
657
- " /thinking <mode> Control thinking output: hide, marker, show",
658
684
  " /switch Pick an agent interactively (\u2191\u2193, Enter)",
659
685
  " /switch list List agents as text",
660
686
  " /switch <name> Switch directly by name, alias, or key (alias: /agent)",
@@ -691,7 +717,6 @@ var STRINGS = {
691
717
  " /context \u67E5\u770B\u5DE5\u4F5C\u533A\u4E0A\u4E0B\u6587\u4E0E\u540E\u7EED\u64CD\u4F5C",
692
718
  " /runtime <mode> \u5207\u6362 runtime\uFF1Aauto\u3001local\u3001server",
693
719
  " /tools <mode> \u5DE5\u5177\u8F68\u8FF9\u663E\u793A\uFF1Ahide\u3001compact\u3001verbose",
694
- " /thinking <mode> \u601D\u8003\u8FC7\u7A0B\u663E\u793A\uFF1Ahide\u3001marker\u3001show",
695
720
  " /switch \u4EA4\u4E92\u5F0F\u9009\u62E9 agent\uFF08\u2191\u2193 \u79FB\u52A8\uFF0CEnter \u786E\u8BA4\uFF09",
696
721
  " /switch list \u4EE5\u6587\u672C\u5217\u51FA\u5168\u90E8 agent",
697
722
  " /switch <name> \u6309\u540D\u79F0\u3001\u522B\u540D\u6216 key \u76F4\u63A5\u5207\u6362\uFF08\u522B\u540D\uFF1A/agent\uFF09",
@@ -736,12 +761,6 @@ var STRINGS = {
736
761
  },
737
762
  toolsUsage: { en: "Usage: /tools <hide|compact|verbose>", zh: "\u7528\u6CD5\uFF1A/tools <hide|compact|verbose>" },
738
763
  toolsSet: { en: "Tool display: {0}", zh: "\u5DE5\u5177\u663E\u793A\uFF1A{0}" },
739
- thinkingCurrent: {
740
- en: "Thinking display: {0} (hide | marker | show)",
741
- zh: "\u601D\u8003\u663E\u793A\uFF1A{0}\uFF08hide | marker | show\uFF09"
742
- },
743
- thinkingUsage: { en: "Usage: /thinking <hide|marker|show>", zh: "\u7528\u6CD5\uFF1A/thinking <hide|marker|show>" },
744
- thinkingSet: { en: "Thinking display: {0}", zh: "\u601D\u8003\u663E\u793A\uFF1A{0}" },
745
764
  tasksRunning: { en: "Running processes ({0}):", zh: "\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\uFF08{0}\uFF09\uFF1A" },
746
765
  tasksStopped: { en: "Stopped/exited ({0}):", zh: "\u5DF2\u505C\u6B62/\u5DF2\u9000\u51FA\uFF08{0}\uFF09\uFF1A" },
747
766
  tasksNone: { en: "No processes.", zh: "\u6CA1\u6709\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\u3002" },
@@ -935,11 +954,191 @@ function agentRunCardLabels() {
935
954
  runStatus: t("runStatusLabel"),
936
955
  runStarted: t("runStartedLabel"),
937
956
  runStopped: t("runStoppedLabel"),
957
+ runFinished: t("runFinishedLabel"),
938
958
  logTail: t("runLogTailLabel"),
939
959
  runs: (count) => t("runsListLabel", String(count))
940
960
  };
941
961
  }
942
962
 
963
+ // packages/ai/tools/agent/quotaCircuitBreaker.ts
964
+ var QUOTA_ERROR_PATTERNS = [
965
+ /429/,
966
+ /quota/i,
967
+ /rate\s*limit/i,
968
+ /too\s*many\s*requests/i,
969
+ /额度/,
970
+ /上限/,
971
+ /用尽/,
972
+ /CliProviderQuotaError/i
973
+ ];
974
+ var AGENT_NOT_FOUND_PATTERNS = [
975
+ /agent[^\n]{0,80}not\s+found/i,
976
+ /agent[^\n]{0,80}not\s+exist/i,
977
+ /agent[^\n]{0,80}不存在/i,
978
+ /agent[^\n]{0,80}未找到/i,
979
+ /AGENT_NOT_FOUND/
980
+ ];
981
+ var AUTH_ERROR_PATTERNS = [
982
+ /401/,
983
+ /403/,
984
+ /unauthori[sz]ed/i,
985
+ /authentication\s+failed/i,
986
+ /invalid\s+(api[-\s]?key|token|credential)/i,
987
+ /api[-\s]?key\s+(invalid|missing|not\s+found)/i,
988
+ /token\s*(invalid|expired|失效|过期)/i,
989
+ /未授权/,
990
+ /认证失败/,
991
+ /凭证/
992
+ ];
993
+ var NETWORK_ERROR_PATTERNS = [
994
+ /ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND|EHOSTUNREACH|EPIPE/i,
995
+ /getaddrinfo|DNS\s+(error|fail)/i,
996
+ /fetch\s+failed/i,
997
+ /network\s+(error|unreachable|down|disconnected)/i,
998
+ /socket\s+(hang|closed|error)/i,
999
+ /连接失败/,
1000
+ /网络错误|网络异常|无法连接/
1001
+ ];
1002
+ function findActiveBreaker(now, table, target) {
1003
+ if (!Number.isFinite(now)) return void 0;
1004
+ for (const entry of table) {
1005
+ if (entry.target !== target) continue;
1006
+ if (typeof entry.until === "number" && entry.until > now) return entry;
1007
+ }
1008
+ return void 0;
1009
+ }
1010
+ function isCliProviderQuotaErrorShape(error) {
1011
+ if (!error || typeof error !== "object") return false;
1012
+ const e = error;
1013
+ return e.name === "CliProviderQuotaError" || typeof e.message === "string" && e.message.startsWith("[QUOTA_LIMITED:");
1014
+ }
1015
+ function isQuotaExhaustedError(error) {
1016
+ if (!error) return false;
1017
+ if (isCliProviderQuotaErrorShape(error)) return true;
1018
+ if (error instanceof Error) {
1019
+ return QUOTA_ERROR_PATTERNS.some((pattern) => pattern.test(error.message));
1020
+ }
1021
+ if (typeof error === "string") {
1022
+ return QUOTA_ERROR_PATTERNS.some((pattern) => pattern.test(error));
1023
+ }
1024
+ const maybeStatus = error.status;
1025
+ if (typeof maybeStatus === "number" && maybeStatus === 429) return true;
1026
+ const maybeStatusCode = error.statusCode;
1027
+ if (typeof maybeStatusCode === "number" && maybeStatusCode === 429) return true;
1028
+ return false;
1029
+ }
1030
+ function isAgentNotFoundError(error) {
1031
+ if (!error) return false;
1032
+ const e = error;
1033
+ if (e.code === "AGENT_NOT_FOUND") return true;
1034
+ const message = typeof e.message === "string" ? e.message : typeof error === "string" ? error : "";
1035
+ if (AGENT_NOT_FOUND_PATTERNS.some((pattern) => pattern.test(message))) return true;
1036
+ if ((e.status === 404 || e.statusCode === 404) && /agent|不存在|未找到/i.test(message)) {
1037
+ return true;
1038
+ }
1039
+ return false;
1040
+ }
1041
+ function extractMessage(error) {
1042
+ if (typeof error === "string") return error;
1043
+ if (error instanceof Error) return error.message;
1044
+ if (error && typeof error === "object") {
1045
+ const m = error.message;
1046
+ return typeof m === "string" ? m : "";
1047
+ }
1048
+ return "";
1049
+ }
1050
+ function extractStatus(error) {
1051
+ if (!error || typeof error !== "object") return void 0;
1052
+ const e = error;
1053
+ const s = typeof e.status === "number" ? e.status : void 0;
1054
+ const sc = typeof e.statusCode === "number" ? e.statusCode : void 0;
1055
+ return s ?? sc;
1056
+ }
1057
+ function parseResetsInMs(text) {
1058
+ if (!text) return void 0;
1059
+ const unitMs = (n, unit) => {
1060
+ if (/^d/.test(unit)) return n * 24 * 3600 * 1e3;
1061
+ if (/^h/.test(unit)) return n * 3600 * 1e3;
1062
+ if (/^m/.test(unit)) return n * 60 * 1e3;
1063
+ if (/^s/.test(unit)) return n * 1e3;
1064
+ return NaN;
1065
+ };
1066
+ const re = /(\d+)\s*(d(?:ay|ays)?|h(?:r|rs|our|ours)?|m(?:in|ins|inute|inutes)?|s(?:ec|ecs|econd|econds)?)/gi;
1067
+ let totalMs = 0;
1068
+ let matched = false;
1069
+ let m;
1070
+ while ((m = re.exec(text)) !== null) {
1071
+ const ms = unitMs(Number(m[1]), m[2]);
1072
+ if (!Number.isFinite(ms)) continue;
1073
+ totalMs += ms;
1074
+ matched = true;
1075
+ }
1076
+ return matched ? totalMs : void 0;
1077
+ }
1078
+ function extractProvider(error) {
1079
+ if (!error || typeof error !== "object") return void 0;
1080
+ const p = error.provider;
1081
+ if (typeof p === "string" && p.length > 0) return p;
1082
+ const message = extractMessage(error);
1083
+ const tag = /\[QUOTA_LIMITED:([^\]]+)\]/i.exec(message);
1084
+ if (tag?.[1]) return tag[1];
1085
+ return void 0;
1086
+ }
1087
+ function extractRetryAfterHeader(error) {
1088
+ if (!error || typeof error !== "object") return void 0;
1089
+ const headers = error.headers;
1090
+ if (!headers || typeof headers !== "object") return void 0;
1091
+ const raw = headers["retry-after"];
1092
+ if (typeof raw !== "string" && typeof raw !== "number") return void 0;
1093
+ const secs = Number(raw);
1094
+ return Number.isFinite(secs) && secs > 0 ? secs * 1e3 : void 0;
1095
+ }
1096
+ function classifyRunFailure(error) {
1097
+ const message = extractMessage(error);
1098
+ const status = extractStatus(error);
1099
+ const retryAfterMs = extractRetryAfterHeader(error) ?? parseResetsInMs(message);
1100
+ if (isQuotaExhaustedError(error)) {
1101
+ return {
1102
+ reason: "quota",
1103
+ provider: extractProvider(error),
1104
+ // 纯函数不取时钟:resetsAt 由调用方用 now + retryAfterMs 计算后补齐
1105
+ retryAfterMs,
1106
+ message
1107
+ };
1108
+ }
1109
+ if (isAgentNotFoundError(error)) {
1110
+ return { reason: "agent-not-found", message };
1111
+ }
1112
+ if (isAuthError(error)) {
1113
+ return { reason: "auth", message };
1114
+ }
1115
+ if (isNetworkError(error)) {
1116
+ return { reason: "network", message };
1117
+ }
1118
+ return { reason: "other", message };
1119
+ }
1120
+ function isAuthError(error) {
1121
+ const message = extractMessage(error);
1122
+ const status = extractStatus(error);
1123
+ if (status === 401 || status === 403) return true;
1124
+ return AUTH_ERROR_PATTERNS.some((pattern) => pattern.test(message));
1125
+ }
1126
+ function isNetworkError(error) {
1127
+ const message = extractMessage(error);
1128
+ return NETWORK_ERROR_PATTERNS.some((pattern) => pattern.test(message));
1129
+ }
1130
+ var DEFAULT_QUOTA_BREAKER_MS = 6 * 3600 * 1e3;
1131
+ var DEFAULT_AGENT_NOT_FOUND_BREAKER_MS = 15 * 60 * 1e3;
1132
+ function buildBreakerEntry(now, target, kind, retryAfterMs) {
1133
+ const ttl = kind === "quota" ? typeof retryAfterMs === "number" && retryAfterMs > 0 ? retryAfterMs : DEFAULT_QUOTA_BREAKER_MS : DEFAULT_AGENT_NOT_FOUND_BREAKER_MS;
1134
+ return {
1135
+ target,
1136
+ kind,
1137
+ until: now + ttl,
1138
+ ...kind === "quota" && typeof retryAfterMs === "number" ? { resetsAt: now + retryAfterMs } : {}
1139
+ };
1140
+ }
1141
+
943
1142
  // packages/cli/client/localRuntimeDiagnostics.ts
944
1143
  import { ulid } from "ulid";
945
1144
  var preparedAgentRuntimeCache = /* @__PURE__ */ new Map();
@@ -979,7 +1178,7 @@ function summarizeOpenAiToolNames(tools) {
979
1178
  }
980
1179
 
981
1180
  // packages/cli/client/localRuntimeAdapter.ts
982
- import { dirname, extname, join } from "node:path";
1181
+ import { dirname as dirname2, extname, join as join2 } from "node:path";
983
1182
  import { fileURLToPath } from "node:url";
984
1183
 
985
1184
  // packages/core/summarizeEndpoint.ts
@@ -1130,6 +1329,11 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
1130
1329
  const attemptBudget = coreDraining ? coreDrainingMaxAttempts : maxAttempts;
1131
1330
  if (attempt < attemptBudget) {
1132
1331
  const delayMs = await resolveRetryAfterMs(response, attempt);
1332
+ options.onRetry?.({
1333
+ attempt: attempt + 1,
1334
+ maxAttempts: attemptBudget,
1335
+ delayMs
1336
+ });
1133
1337
  await (options.sleep ?? defaultSleep)(delayMs);
1134
1338
  continue;
1135
1339
  }
@@ -1143,7 +1347,13 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
1143
1347
  if (!isTransientFetchError(error)) throw error;
1144
1348
  lastError = error;
1145
1349
  if (attempt < maxAttempts) {
1146
- await (options.sleep ?? defaultSleep)(transientFetchRetryDelayMs(attempt));
1350
+ const delayMs = transientFetchRetryDelayMs(attempt);
1351
+ options.onRetry?.({
1352
+ attempt: attempt + 1,
1353
+ maxAttempts,
1354
+ delayMs
1355
+ });
1356
+ await (options.sleep ?? defaultSleep)(delayMs);
1147
1357
  }
1148
1358
  }
1149
1359
  }
@@ -1590,23 +1800,6 @@ async function readAgentFromStore(args) {
1590
1800
  if (!record || typeof record !== "object") continue;
1591
1801
  return resolveAgentRuntimeConfigFromRecord(key, record);
1592
1802
  }
1593
- const normalizedRef = normalizeAgentHandle(args.agentRef);
1594
- if (!normalizedRef) {
1595
- return resolveBuiltinPlatformAgentConfig(args.agentRef);
1596
- }
1597
- try {
1598
- const iterator = args.store.iterator({
1599
- gte: "agent-",
1600
- lte: "agent-\uFFFF"
1601
- });
1602
- for await (const [key, record] of iterator) {
1603
- if (!record || typeof record !== "object") continue;
1604
- const handle = normalizeAgentHandle(record.handle);
1605
- if (handle !== normalizedRef) continue;
1606
- return resolveAgentRuntimeConfigFromRecord(key, record);
1607
- }
1608
- } catch {
1609
- }
1610
1803
  return resolveBuiltinPlatformAgentConfig(args.agentRef);
1611
1804
  }
1612
1805
  async function readDialogMessages(args) {
@@ -1765,7 +1958,10 @@ var LOCAL_SERVER_WEB_TOOL_NAMES = ["fetchWebpage", "exa_search"];
1765
1958
  var LOCAL_SERVER_WEB_TOOL_NAME_SET = new Set(
1766
1959
  LOCAL_SERVER_WEB_TOOL_NAMES
1767
1960
  );
1768
- var LOCAL_SERVER_MEMORY_TOOL_NAMES = ["rememberMemory"];
1961
+ var LOCAL_SERVER_MEMORY_TOOL_NAMES = [
1962
+ "queryMemory",
1963
+ "rememberMemory"
1964
+ ];
1769
1965
  var LOCAL_SERVER_MEMORY_TOOL_NAME_SET = new Set(
1770
1966
  LOCAL_SERVER_MEMORY_TOOL_NAMES
1771
1967
  );
@@ -1997,6 +2193,25 @@ function buildServerPlatformToolExecutors(args) {
1997
2193
  }
1998
2194
  ])
1999
2195
  );
2196
+ const queryMemory = async (call) => {
2197
+ const parsed = parseNoloWorkspaceToolArguments(call.arguments);
2198
+ const query = typeof parsed.query === "string" ? parsed.query.trim() : "";
2199
+ if (!query) {
2200
+ return {
2201
+ content: JSON.stringify({ error: "queryMemory \u9700\u8981\u975E\u7A7A query\u3002" }),
2202
+ metadata: { serverPlatformTool: true, memoryRead: false }
2203
+ };
2204
+ }
2205
+ const body = { userInput: query };
2206
+ if (args.agentKey) body.agentKey = args.agentKey;
2207
+ const raw = await postServer("/api/memory/query", body, {
2208
+ retryTransient: true
2209
+ });
2210
+ return {
2211
+ content: raw,
2212
+ metadata: { serverPlatformTool: true, memoryRead: true }
2213
+ };
2214
+ };
2000
2215
  const rememberMemory = async (call) => {
2001
2216
  const parsed = parseNoloWorkspaceToolArguments(call.arguments);
2002
2217
  const content = typeof parsed.content === "string" ? parsed.content.trim() : "";
@@ -2023,11 +2238,368 @@ function buildServerPlatformToolExecutors(args) {
2023
2238
  metadata: { serverPlatformTool: true, memoryWrite: true }
2024
2239
  };
2025
2240
  };
2026
- return { ...tableExecutors, ...webExecutors, rememberMemory };
2241
+ return { ...tableExecutors, ...webExecutors, queryMemory, rememberMemory };
2242
+ }
2243
+
2244
+ // packages/cli/client/cliAgentRunToolExecutors.ts
2245
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
2246
+
2247
+ // packages/cli/client/agentRunSnapshot.ts
2248
+ function readString(value) {
2249
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2250
+ }
2251
+ function readLogLines(parsed) {
2252
+ if (Array.isArray(parsed.logLines)) return parsed.logLines;
2253
+ const tail = readString(parsed.logTail);
2254
+ return tail ? tail.split("\n") : void 0;
2255
+ }
2256
+ function readTimestamp(value) {
2257
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
2258
+ if (typeof value === "string" && value.trim()) {
2259
+ const parsed = Date.parse(value);
2260
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
2261
+ }
2262
+ return void 0;
2263
+ }
2264
+ function readToolNames(value) {
2265
+ if (!Array.isArray(value)) return void 0;
2266
+ const names = value.filter((n) => typeof n === "string" && Boolean(n.trim()));
2267
+ return names.length > 0 ? names : void 0;
2268
+ }
2269
+ function buildSnapshot(parsed, event) {
2270
+ const runId = readString(parsed.runId) ?? readString(event.metadata?.runId) ?? "";
2271
+ const label = resolveRunLabel({
2272
+ agentName: parsed.agentName,
2273
+ name: parsed.name,
2274
+ agentKey: parsed.agentKey
2275
+ });
2276
+ const logLines = readLogLines(parsed);
2277
+ const taskPreview = readString(parsed.taskPreview);
2278
+ const lastToolNames = readToolNames(parsed.lastToolNames);
2279
+ const lastAssistantText = readString(parsed.lastAssistantText);
2280
+ const errorMessage = readString(parsed.errorMessage);
2281
+ const startedAt = readTimestamp(parsed.startedAt);
2282
+ const finishedAt = readTimestamp(parsed.finishedAt) ?? readTimestamp(parsed.endedAt);
2283
+ return {
2284
+ runId,
2285
+ status: readString(parsed.status) ?? "running",
2286
+ // The literal `agent` fallback is dropped here rather than at each render
2287
+ // site: an unnamed run should render no name row, not the word "agent".
2288
+ ...isAgentNameFallback(label) ? {} : { agentName: label },
2289
+ ...taskPreview ? { taskPreview } : {},
2290
+ ...typeof parsed.toolCallCount === "number" && Number.isFinite(parsed.toolCallCount) ? { toolCallCount: parsed.toolCallCount } : {},
2291
+ ...lastToolNames ? { lastToolNames } : {},
2292
+ ...lastAssistantText ? { lastAssistantText } : {},
2293
+ ...errorMessage ? { errorMessage } : {},
2294
+ ...startedAt !== void 0 ? { startedAt } : {},
2295
+ ...finishedAt !== void 0 ? { finishedAt } : {},
2296
+ ...logLines ? { logLines } : {},
2297
+ logKey: logLines && logLines.length > 0 ? logLines.join("\n") : ""
2298
+ };
2299
+ }
2300
+ var STOP_STATUSES = /* @__PURE__ */ new Set(["killed", "cancelled", "cancelling"]);
2301
+ function parseAgentRunEvent(event) {
2302
+ if (event.type !== "tool-result") return null;
2303
+ if (event.toolName !== "startAgentRun" && event.toolName !== "controlAgentRun") {
2304
+ return null;
2305
+ }
2306
+ const raw = typeof event.content === "string" ? event.content.trim() : "";
2307
+ if (!raw.startsWith("{")) return null;
2308
+ let parsed;
2309
+ try {
2310
+ parsed = JSON.parse(raw);
2311
+ } catch {
2312
+ return null;
2313
+ }
2314
+ if (Array.isArray(parsed.runs)) return null;
2315
+ const snapshot = buildSnapshot(parsed, event);
2316
+ const status = readString(parsed.status);
2317
+ if (event.toolName === "startAgentRun") {
2318
+ if (!snapshot.runId) return null;
2319
+ return { kind: "start", snapshot };
2320
+ }
2321
+ if (parsed.found === false || status === "not_found") {
2322
+ return { kind: "gone", snapshot: { ...snapshot, status: "not_found" } };
2323
+ }
2324
+ if (status && STOP_STATUSES.has(status)) {
2325
+ return { kind: "stop", snapshot };
2326
+ }
2327
+ if (!status) return null;
2328
+ if (!snapshot.runId) return null;
2329
+ return { kind: "status", snapshot };
2330
+ }
2331
+
2332
+ // packages/ai/tools/agent/batchAggregation.ts
2333
+ var DEFAULT_BATCH_TIMEOUT_MS = 30 * 60 * 1e3;
2334
+ var MAX_ERROR_SUMMARY_CHARS = 120;
2335
+ var MAX_FAILURE_LINES = 10;
2336
+ function isFailureStatus(status) {
2337
+ return isAgentRunTerminalStatus(status) && status !== "done";
2338
+ }
2339
+ function isOrphanedStatus(status) {
2340
+ return status === "orphaned";
2341
+ }
2342
+ function toEpochMs(iso) {
2343
+ if (!iso) return void 0;
2344
+ const ms = Date.parse(iso);
2345
+ return Number.isFinite(ms) ? ms : void 0;
2346
+ }
2347
+ function isOverTimeout(run, nowMs, timeoutMs) {
2348
+ const startedMs = toEpochMs(run.startedAt);
2349
+ if (startedMs === void 0) return false;
2350
+ return nowMs - startedMs >= timeoutMs;
2351
+ }
2352
+ function truncateErrorSummary(text, max = MAX_ERROR_SUMMARY_CHARS) {
2353
+ if (!text) return "";
2354
+ const collapsed = text.replace(/\s+/g, " ").trim();
2355
+ if (collapsed.length <= max) return collapsed;
2356
+ return `${collapsed.slice(0, max - 1)}\u2026`;
2357
+ }
2358
+ function formatFailureLine(run) {
2359
+ const label = shortRunId(run.runId);
2360
+ const agent = run.agentName ? ` (${run.agentName})` : "";
2361
+ const error = truncateErrorSummary(run.errorSummary);
2362
+ return error ? `\u5931\u8D25: ${label}${agent} \u2014 ${error}` : `\u5931\u8D25: ${label}${agent}`;
2363
+ }
2364
+ function formatBatchSummary(batchId, counts, runs, reason) {
2365
+ const failures = runs.filter((r) => isFailureStatus(r.status));
2366
+ const unfinished = runs.filter((r) => !isAgentRunTerminalStatus(r.status));
2367
+ if (reason === "timeout") {
2368
+ const lines2 = [
2369
+ `\u6279\u6B21 ${batchId}: \u8D85\u65F6\u672A\u6536\u655B \u2014 ${counts.running} \u4E2A\u672A\u5B8C\u6210`
2370
+ ];
2371
+ for (const run of unfinished.slice(0, MAX_FAILURE_LINES)) {
2372
+ const agent = run.agentName ? ` (${run.agentName})` : "";
2373
+ lines2.push(`\u672A\u5B8C\u6210: ${shortRunId(run.runId)}${agent}`);
2374
+ }
2375
+ const rest2 = unfinished.length - MAX_FAILURE_LINES;
2376
+ if (rest2 > 0) lines2.push(`\u2026 \u53CA\u53E6\u5916 ${rest2} \u4E2A\u672A\u5B8C\u6210`);
2377
+ return lines2.join("\n");
2378
+ }
2379
+ const tail = counts.running > 0 ? `, ${counts.running} \u4ECD\u5728\u8DD1` : "";
2380
+ const lines = [
2381
+ `\u6279\u6B21 ${batchId}: ${counts.success + counts.failed}/${counts.total} \u5B8C\u6210 \u2014 ${counts.success} \u6210\u529F, ${counts.failed} \u5931\u8D25${tail}`
2382
+ ];
2383
+ for (const run of failures.slice(0, MAX_FAILURE_LINES)) {
2384
+ lines.push(formatFailureLine(run));
2385
+ }
2386
+ const rest = failures.length - MAX_FAILURE_LINES;
2387
+ if (rest > 0) lines.push(`\u2026 \u53CA\u53E6\u5916 ${rest} \u4E2A\u5931\u8D25`);
2388
+ return lines.join("\n");
2389
+ }
2390
+ function aggregateBatch(input) {
2391
+ const { batchId, runs, now } = input;
2392
+ const timeoutMs = input.timeoutMs ?? DEFAULT_BATCH_TIMEOUT_MS;
2393
+ const notified = new Set(input.notifiedReasons ?? []);
2394
+ const nowMs = toEpochMs(now) ?? 0;
2395
+ let success = 0;
2396
+ let failed = 0;
2397
+ let orphaned = 0;
2398
+ let running = 0;
2399
+ const unfinished = [];
2400
+ let timedOut = false;
2401
+ for (const run of runs) {
2402
+ if (isAgentRunTerminalStatus(run.status)) {
2403
+ if (run.status === "done") success += 1;
2404
+ else {
2405
+ failed += 1;
2406
+ if (isOrphanedStatus(run.status)) orphaned += 1;
2407
+ }
2408
+ } else {
2409
+ running += 1;
2410
+ unfinished.push(run.runId);
2411
+ if (isOverTimeout(run, nowMs, timeoutMs)) timedOut = true;
2412
+ }
2413
+ }
2414
+ const converged = running === 0;
2415
+ let newWakeReasons = [];
2416
+ if (failed > 0 && !notified.has("failure")) {
2417
+ newWakeReasons = ["failure"];
2418
+ } else if (converged && !notified.has("converged")) {
2419
+ newWakeReasons = ["converged"];
2420
+ } else if (timedOut && !notified.has("timeout")) {
2421
+ newWakeReasons = ["timeout"];
2422
+ }
2423
+ const counts = {
2424
+ total: runs.length,
2425
+ success,
2426
+ failed,
2427
+ orphaned,
2428
+ running
2429
+ };
2430
+ const summary = newWakeReasons.length > 0 ? formatBatchSummary(batchId, counts, runs, newWakeReasons[0]) : "";
2431
+ return {
2432
+ batchId,
2433
+ converged,
2434
+ timedOut,
2435
+ counts,
2436
+ newWakeReasons,
2437
+ unfinished,
2438
+ summary
2439
+ };
2440
+ }
2441
+
2442
+ // packages/ai/tools/agent/runtimeTodo.ts
2443
+ var TODO_REVIEW_BLOCK = "BLOCK";
2444
+ function deriveTodoStatus(input) {
2445
+ const { todo, runs } = input;
2446
+ if (todo.status === "abandoned") {
2447
+ return { status: "abandoned" };
2448
+ }
2449
+ if (runs.length === 0) {
2450
+ return { status: todo.status };
2451
+ }
2452
+ if (runs.some((r) => !isAgentRunTerminalStatus(r.status))) {
2453
+ return { status: "running", latestRun: latestRun(runs) };
2454
+ }
2455
+ const latest = latestRun(runs);
2456
+ if (latest?.reviewVerdict === TODO_REVIEW_BLOCK) {
2457
+ return {
2458
+ status: "blocked",
2459
+ latestRun: latest,
2460
+ blockedReason: clipSummary(latest.reviewReason, MAX_ERROR_SUMMARY_CHARS)
2461
+ };
2462
+ }
2463
+ if (latest?.status === "done") {
2464
+ return { status: "done", latestRun: latest };
2465
+ }
2466
+ return { status: "pending", latestRun: latest };
2467
+ }
2468
+ function toEpochMs2(iso) {
2469
+ if (!iso) return void 0;
2470
+ const ms = Date.parse(iso);
2471
+ return Number.isFinite(ms) ? ms : void 0;
2472
+ }
2473
+ function latestRun(runs) {
2474
+ let latest;
2475
+ let latestScore = -1;
2476
+ for (const run of runs) {
2477
+ const score = toEpochMs2(run.finishedAt) ?? toEpochMs2(run.startedAt) ?? -1;
2478
+ if (latest === void 0 || score >= latestScore) {
2479
+ latest = run;
2480
+ latestScore = score;
2481
+ }
2482
+ }
2483
+ return latest;
2484
+ }
2485
+ function clipSummary(text, max) {
2486
+ if (!text) return void 0;
2487
+ const folded = text.replace(/\s+/g, " ").trim();
2488
+ if (folded.length === 0) return void 0;
2489
+ return folded.length > max ? `${folded.slice(0, max - 1)}\u2026` : folded;
2490
+ }
2491
+
2492
+ // packages/cli/client/fileSystemStores.ts
2493
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2494
+ import { homedir as nodeHomedir } from "node:os";
2495
+ import { dirname, join } from "node:path";
2496
+ var nodeFs = {
2497
+ mkdirSync,
2498
+ writeFileSync,
2499
+ readFileSync,
2500
+ existsSync
2501
+ };
2502
+ function resolveNoloHome(env, homedir) {
2503
+ const custom = env?.NOLO_HOME;
2504
+ if (custom && custom.trim()) return custom.trim();
2505
+ return join(homedir(), ".nolo");
2506
+ }
2507
+ function ensureDir(dir, fs) {
2508
+ fs.mkdirSync(dir, { recursive: true });
2509
+ }
2510
+ function readJson(path, fs) {
2511
+ if (!fs.existsSync(path)) return void 0;
2512
+ try {
2513
+ const raw = fs.readFileSync(path, "utf8");
2514
+ return JSON.parse(String(raw));
2515
+ } catch {
2516
+ return void 0;
2517
+ }
2518
+ }
2519
+ function writeJson(path, data, fs) {
2520
+ fs.writeFileSync(path, JSON.stringify(data, null, 2));
2521
+ }
2522
+ function createFileSystemCircuitBreakerStore(opts = {}) {
2523
+ const env = opts.env ?? process.env;
2524
+ const homedir = opts.homedir ?? nodeHomedir;
2525
+ const fs = opts.fs ?? nodeFs;
2526
+ const filePath = opts.filePath ?? join(resolveNoloHome(env, homedir), "breakers.json");
2527
+ const loadMap = () => {
2528
+ const data = readJson(filePath, fs);
2529
+ const map = /* @__PURE__ */ new Map();
2530
+ if (data?.entries) {
2531
+ for (const entry of data.entries) {
2532
+ if (entry && typeof entry.target === "string") map.set(entry.target, entry);
2533
+ }
2534
+ }
2535
+ return map;
2536
+ };
2537
+ const persist = (map) => {
2538
+ ensureDir(dirname(filePath), fs);
2539
+ writeJson(filePath, { entries: [...map.values()] }, fs);
2540
+ };
2541
+ return {
2542
+ get(target) {
2543
+ return loadMap().get(target);
2544
+ },
2545
+ set(entry) {
2546
+ const map = loadMap();
2547
+ map.set(entry.target, entry);
2548
+ persist(map);
2549
+ },
2550
+ clear(target) {
2551
+ const map = loadMap();
2552
+ map.delete(target);
2553
+ persist(map);
2554
+ },
2555
+ clearAll() {
2556
+ persist(/* @__PURE__ */ new Map());
2557
+ }
2558
+ };
2559
+ }
2560
+ function createFileSystemTodoStore(opts = {}) {
2561
+ const env = opts.env ?? process.env;
2562
+ const homedir = opts.homedir ?? nodeHomedir;
2563
+ const fs = opts.fs ?? nodeFs;
2564
+ const filePath = opts.filePath ?? join(resolveNoloHome(env, homedir), "todos.json");
2565
+ const loadMap = () => {
2566
+ const data = readJson(filePath, fs);
2567
+ const map = /* @__PURE__ */ new Map();
2568
+ if (data?.todos) {
2569
+ for (const todo of data.todos) {
2570
+ if (todo && typeof todo.id === "string") map.set(todo.id, todo);
2571
+ }
2572
+ }
2573
+ return map;
2574
+ };
2575
+ const persist = (map) => {
2576
+ ensureDir(dirname(filePath), fs);
2577
+ writeJson(filePath, { todos: [...map.values()] }, fs);
2578
+ };
2579
+ return {
2580
+ async getTodo(id) {
2581
+ return loadMap().get(id);
2582
+ },
2583
+ async listTodos(filter) {
2584
+ const all = [...loadMap().values()];
2585
+ if (!filter?.statuses || filter.statuses.length === 0) return all;
2586
+ const wanted = new Set(filter.statuses);
2587
+ return all.filter((t2) => wanted.has(t2.status));
2588
+ },
2589
+ async putTodo(todo) {
2590
+ const map = loadMap();
2591
+ map.set(todo.id, todo);
2592
+ persist(map);
2593
+ },
2594
+ async deleteTodo(id) {
2595
+ const map = loadMap();
2596
+ map.delete(id);
2597
+ persist(map);
2598
+ }
2599
+ };
2027
2600
  }
2028
2601
 
2029
2602
  // packages/cli/client/cliAgentRunToolExecutors.ts
2030
- import { existsSync, readFileSync } from "node:fs";
2031
2603
  var noopOutput = { write: () => {
2032
2604
  } };
2033
2605
  var parseCallArgs = (call) => {
@@ -2037,7 +2609,7 @@ var parseCallArgs = (call) => {
2037
2609
  return {};
2038
2610
  }
2039
2611
  };
2040
- var resolveFs = (deps) => deps.fs ?? { existsSync, readFileSync };
2612
+ var resolveFs = (deps) => deps.fs ?? { existsSync: existsSync2, readFileSync: readFileSync2 };
2041
2613
  var tailFile = (logPath, tailLines, fs) => {
2042
2614
  if (!fs.existsSync(logPath)) return void 0;
2043
2615
  try {
@@ -2049,6 +2621,27 @@ var tailFile = (logPath, tailLines, fs) => {
2049
2621
  return void 0;
2050
2622
  }
2051
2623
  };
2624
+ var resolveBreakerStore = (deps) => deps.breakerStore ?? createFileSystemCircuitBreakerStore({ env: deps.env, homedir: deps.homedir, fs: deps.fs });
2625
+ var resolveTodoStore = (deps) => deps.todoStore ?? createFileSystemTodoStore({ env: deps.env, homedir: deps.homedir, fs: deps.fs });
2626
+ var resolveNowMs = (deps) => typeof deps.nowMs === "function" ? deps.nowMs() : Date.now();
2627
+ var resolveTarget = (deps, agentKey) => typeof deps.resolveProviderTarget === "function" ? deps.resolveProviderTarget(agentKey) : agentKey;
2628
+ function buildProgressField(record, nowMs) {
2629
+ const activity = record.activity;
2630
+ if (!activity || isAgentRunTerminalStatus(record.status)) return {};
2631
+ const lastEventAt = Date.parse(activity.lastEventAt ?? "");
2632
+ const inFlight = activity.inFlight;
2633
+ const progress = {
2634
+ toolCalls: activity.counters?.toolCalls ?? 0,
2635
+ llmCalls: activity.counters?.llmCalls ?? 0,
2636
+ fileEdits: activity.counters?.fileEdits ?? 0,
2637
+ ...Number.isFinite(lastEventAt) ? { idleMs: Math.max(0, nowMs - lastEventAt) } : {}
2638
+ };
2639
+ if (inFlight) {
2640
+ progress.inFlight = inFlight.name ? `${inFlight.kind}:${inFlight.name}` : inFlight.kind;
2641
+ if (Number.isFinite(inFlight.sinceMs)) progress.inFlightMs = Math.max(0, inFlight.sinceMs);
2642
+ }
2643
+ return { progress };
2644
+ }
2052
2645
  function createCliStartAgentRunExecutor(deps = {}) {
2053
2646
  return async (call) => {
2054
2647
  const args = parseCallArgs(call);
@@ -2056,6 +2649,29 @@ function createCliStartAgentRunExecutor(deps = {}) {
2056
2649
  const task = typeof args.task === "string" ? args.task.trim() : "";
2057
2650
  if (!agentKey) throw new Error("startAgentRun: \u7F3A\u5C11 agentKey \u53C2\u6570\u3002");
2058
2651
  if (!task) throw new Error("startAgentRun: \u7F3A\u5C11\u6709\u6548\u7684 task \u6587\u672C\u63CF\u8FF0\u3002");
2652
+ const breakerStore = resolveBreakerStore(deps);
2653
+ const target = resolveTarget(deps, agentKey);
2654
+ const nowMs = resolveNowMs(deps);
2655
+ const activeBreaker = findActiveBreaker(
2656
+ nowMs,
2657
+ [breakerStore.get(target)].filter(Boolean),
2658
+ target
2659
+ );
2660
+ if (activeBreaker) {
2661
+ const resetsAt = activeBreaker.resetsAt;
2662
+ return {
2663
+ content: JSON.stringify({
2664
+ rejected: true,
2665
+ reason: "quota",
2666
+ provider: target,
2667
+ ...resetsAt !== void 0 ? { resetsAt } : {},
2668
+ message: `provider ${target} \u5904\u4E8E\u7194\u65AD\u671F\uFF08\u914D\u989D\u8017\u5C3D\uFF09\uFF0C\u5EFA\u8BAE\u6539\u6D3E\u5176\u5B83 provider\u3002`
2669
+ }),
2670
+ metadata: {
2671
+ displayData: `Run rejected \xB7 quota breaker active on ${target}`
2672
+ }
2673
+ };
2674
+ }
2059
2675
  const message = typeof args.input === "undefined" ? task : `${task}
2060
2676
 
2061
2677
  --- \u9644\u52A0\u8F93\u5165 ---
@@ -2071,13 +2687,16 @@ ${JSON.stringify(args.input)}`;
2071
2687
  ...args.ephemeral === true ? ["--ephemeral"] : []
2072
2688
  ];
2073
2689
  const agentName = typeof args.agentName === "string" && args.agentName.trim() ? args.agentName.trim() : typeof args.name === "string" && args.name.trim() ? args.name.trim() : void 0;
2074
- const { runId } = await spawnLocalBackgroundRun(
2690
+ const batchId = typeof args.batchId === "string" && args.batchId.trim() ? args.batchId.trim() : void 0;
2691
+ const { runId, batchId: resolvedBatchId } = await spawnLocalBackgroundRun(
2075
2692
  {
2076
2693
  rawArgs,
2077
2694
  commandPath: ["agent", "run"],
2078
2695
  cliEntrypointPath: deps.cliEntrypoint,
2079
2696
  agentKey,
2080
2697
  ...agentName ? { agentName } : {},
2698
+ ...batchId ? { batchId } : {},
2699
+ ...typeof args.parentDialogId === "string" && args.parentDialogId.trim() ? { parentDialogId: args.parentDialogId.trim() } : {},
2081
2700
  cwd: deps.cwd ?? process.cwd(),
2082
2701
  message,
2083
2702
  output: noopOutput
@@ -2086,14 +2705,49 @@ ${JSON.stringify(args.input)}`;
2086
2705
  );
2087
2706
  const displayName = resolveRunLabel({ agentName, agentKey, runId });
2088
2707
  const labels = agentRunCardLabels();
2708
+ const taskPreview = typeof args.task === "string" ? args.task.replace(/\s+/g, " ").trim().slice(0, TASK_PREVIEW_MAX) : "";
2709
+ const trackTodo = typeof args.trackTodo === "boolean" ? args.trackTodo : Boolean(resolvedBatchId);
2710
+ if (trackTodo) {
2711
+ try {
2712
+ const todoStore = resolveTodoStore(deps);
2713
+ const todoId = `todo-${resolvedBatchId}`;
2714
+ const existing = await todoStore.getTodo(todoId);
2715
+ const nowIso = new Date(nowMs).toISOString();
2716
+ const runIds = existing?.runIds ?? [];
2717
+ if (!runIds.includes(runId)) runIds.push(runId);
2718
+ const todo = {
2719
+ id: todoId,
2720
+ title: taskPreview || task.slice(0, 100),
2721
+ status: existing?.status ?? "pending",
2722
+ ...existing?.specPath ? { specPath: existing.specPath } : {},
2723
+ ...existing?.worktree ? { worktree: existing.worktree } : {},
2724
+ ...existing?.branch ? { branch: existing.branch } : {},
2725
+ ...deps.cwd ? { worktree: deps.cwd } : {},
2726
+ runIds,
2727
+ deps: existing?.deps ?? [],
2728
+ createdAt: existing?.createdAt ?? nowIso,
2729
+ updatedAt: nowIso
2730
+ };
2731
+ await todoStore.putTodo(todo);
2732
+ } catch {
2733
+ }
2734
+ }
2089
2735
  return {
2090
2736
  content: JSON.stringify({
2091
2737
  runId,
2092
2738
  status: "running",
2093
- ...agentName ? { agentName } : {}
2739
+ // batchId is always returned so the caller can later filter by it —
2740
+ // even when the caller didn't supply one, a fresh id was generated.
2741
+ batchId: resolvedBatchId,
2742
+ ...agentName ? { agentName } : {},
2743
+ ...taskPreview ? { taskPreview } : {}
2094
2744
  }),
2095
2745
  metadata: {
2096
- displayData: formatStartRunCard(displayName, "running", labels)
2746
+ displayData: formatStartRunCard(displayName, "running", {
2747
+ task: taskPreview,
2748
+ runId,
2749
+ labels
2750
+ })
2097
2751
  }
2098
2752
  };
2099
2753
  };
@@ -2104,26 +2758,103 @@ function createCliControlAgentRunExecutor(deps = {}) {
2104
2758
  const action = typeof args.action === "string" ? args.action : "";
2105
2759
  const tailLines = typeof args.tailLines === "number" ? args.tailLines : 0;
2106
2760
  if (action === "list") {
2107
- const records = listRunRecords(deps);
2761
+ gcRunRecords(deps);
2762
+ const { runs: records, total, hasMore } = queryRunRecords(
2763
+ {
2764
+ ...typeof args.batchId === "string" && args.batchId.trim() ? { batchId: args.batchId.trim() } : {},
2765
+ ...typeof args.status === "string" && args.status.trim() ? { status: args.status.trim() } : typeof args.statusFilter === "string" && args.statusFilter.trim() ? { status: args.statusFilter.trim() } : {},
2766
+ ...typeof args.limit === "number" ? { limit: args.limit } : {},
2767
+ ...typeof args.offset === "number" ? { offset: args.offset } : {}
2768
+ },
2769
+ deps
2770
+ );
2108
2771
  const runs = records.map((record2) => {
2109
- const reconciled = checkStaleRun(record2.runId, deps) ?? record2;
2110
2772
  return {
2111
- runId: reconciled.runId,
2112
- status: reconciled.status,
2113
- agentKey: reconciled.agentKey,
2114
- ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
2115
- pid: reconciled.pid ?? null,
2116
- startedAt: reconciled.startedAt
2773
+ runId: record2.runId,
2774
+ status: record2.status,
2775
+ agentKey: record2.agentKey,
2776
+ ...record2.agentName ? { agentName: record2.agentName } : {},
2777
+ ...record2.batchId ? { batchId: record2.batchId } : {},
2778
+ pid: record2.pid ?? null,
2779
+ startedAt: record2.startedAt
2117
2780
  };
2118
2781
  });
2119
2782
  const labels2 = agentRunCardLabels();
2783
+ const batchIdArg = typeof args.batchId === "string" && args.batchId.trim() ? args.batchId.trim() : void 0;
2784
+ let batchSummary;
2785
+ if (batchIdArg && records.length > 0) {
2786
+ const batchRuns = records.map((r) => ({
2787
+ runId: r.runId,
2788
+ status: r.status,
2789
+ startedAt: r.startedAt,
2790
+ ...r.agentName ? { agentName: r.agentName } : {}
2791
+ }));
2792
+ batchSummary = aggregateBatch({
2793
+ batchId: batchIdArg,
2794
+ runs: batchRuns,
2795
+ now: new Date(resolveNowMs(deps)).toISOString()
2796
+ });
2797
+ }
2120
2798
  return {
2121
- content: JSON.stringify({ runs, count: runs.length }),
2799
+ content: JSON.stringify({
2800
+ runs,
2801
+ count: runs.length,
2802
+ total,
2803
+ hasMore,
2804
+ ...batchSummary?.summary ? { batchSummary: batchSummary.summary } : {}
2805
+ }),
2122
2806
  metadata: {
2123
2807
  displayData: formatListRunsCard(runs, labels2)
2124
2808
  }
2125
2809
  };
2126
2810
  }
2811
+ if (action === "todo") {
2812
+ const todoStore = resolveTodoStore(deps);
2813
+ const statusesRaw = typeof args.status === "string" ? args.status.trim() : void 0;
2814
+ const filter = statusesRaw && statusesRaw !== "all" ? { statuses: statusesRaw.split(",").map((s) => s.trim()).filter(Boolean) } : void 0;
2815
+ const todos = await todoStore.listTodos(filter);
2816
+ const enriched = await Promise.all(
2817
+ todos.map(async (todo) => {
2818
+ const runSummaries = [];
2819
+ for (const rid of todo.runIds) {
2820
+ const rec = findRunRecord(rid, deps);
2821
+ if (!rec) continue;
2822
+ runSummaries.push({
2823
+ runId: rec.runId,
2824
+ status: rec.status,
2825
+ startedAt: rec.startedAt,
2826
+ ...rec.agentName ? { agentName: rec.agentName } : {}
2827
+ });
2828
+ }
2829
+ const derived = deriveTodoStatus({
2830
+ todo: { id: todo.id, status: todo.status },
2831
+ runs: runSummaries,
2832
+ now: new Date(resolveNowMs(deps)).toISOString()
2833
+ });
2834
+ return {
2835
+ id: todo.id,
2836
+ title: todo.title,
2837
+ status: derived.status,
2838
+ runIds: todo.runIds,
2839
+ ...derived.blockedReason ? { blockedReason: derived.blockedReason } : {},
2840
+ ...derived.latestRun ? { latestRunId: derived.latestRun.runId, latestRunStatus: derived.latestRun.status } : {},
2841
+ updatedAt: todo.updatedAt
2842
+ };
2843
+ })
2844
+ );
2845
+ return {
2846
+ content: JSON.stringify({ todos: enriched, count: enriched.length }),
2847
+ metadata: {
2848
+ displayData: formatListRunsCard(
2849
+ enriched.map((t2) => ({
2850
+ agentName: t2.title,
2851
+ status: t2.status
2852
+ })),
2853
+ agentRunCardLabels()
2854
+ )
2855
+ }
2856
+ };
2857
+ }
2127
2858
  if (action !== "status" && action !== "stop") {
2128
2859
  throw new Error(`controlAgentRun: \u672A\u77E5 action "${action}"\u3002`);
2129
2860
  }
@@ -2142,6 +2873,25 @@ function createCliControlAgentRunExecutor(deps = {}) {
2142
2873
  const name = resolveRunLabel(reconciled);
2143
2874
  const logLines = logTail ? logTail.split("\n") : void 0;
2144
2875
  const labels2 = agentRunCardLabels();
2876
+ if (reconciled.status === "failed" || reconciled.status === "orphaned") {
2877
+ try {
2878
+ const failureSource = logTail ?? reconciled.note ?? "";
2879
+ const failureInfo = classifyRunFailure(
2880
+ failureSource || reconciled.status
2881
+ );
2882
+ if (failureInfo.reason === "quota") {
2883
+ const t2 = resolveTarget(deps, reconciled.agentKey);
2884
+ const entry = buildBreakerEntry(
2885
+ resolveNowMs(deps),
2886
+ t2,
2887
+ "quota",
2888
+ failureInfo.retryAfterMs
2889
+ );
2890
+ resolveBreakerStore(deps).set(entry);
2891
+ }
2892
+ } catch {
2893
+ }
2894
+ }
2145
2895
  return {
2146
2896
  content: JSON.stringify({
2147
2897
  runId: reconciled.runId,
@@ -2162,11 +2912,26 @@ function createCliControlAgentRunExecutor(deps = {}) {
2162
2912
  // indistinguishable from a hung run without this field. Surfacing
2163
2913
  // dialogId gives the caller a reliable way to fetch the result.
2164
2914
  ...reconciled.dialogId ? { dialogId: reconciled.dialogId } : {},
2915
+ // Progress is what makes tailLines:0 an actual answer to "is it
2916
+ // stuck?". Without it a poll returns `running` and a pid, so the only
2917
+ // way to tell a working run from a wedged one was to pull 30 lines of
2918
+ // log — the exact thing the orchestration prompt tells the model not
2919
+ // to do. The registry has been recording this all along and `nolo
2920
+ // agent status` has been printing it; only the tool was blind.
2921
+ ...buildProgressField(reconciled, resolveNowMs(deps)),
2165
2922
  ...logTail !== void 0 ? { logTail } : {},
2166
2923
  ...logLines ? { logLines } : {}
2167
2924
  }),
2168
2925
  metadata: {
2169
- displayData: formatStatusRunCard(name, reconciled.status, { logLines, labels: labels2 })
2926
+ displayData: formatStatusRunCard(name, reconciled.status, {
2927
+ runId: reconciled.runId,
2928
+ timing: {
2929
+ startedAt: readTimestamp(reconciled.startedAt),
2930
+ finishedAt: readTimestamp(reconciled.endedAt)
2931
+ },
2932
+ logLines,
2933
+ labels: labels2
2934
+ })
2170
2935
  }
2171
2936
  };
2172
2937
  }
@@ -2304,7 +3069,7 @@ function buildLocalToolExecutors(args) {
2304
3069
  }
2305
3070
  };
2306
3071
  },
2307
- ui_ask_choice: async (call) => {
3072
+ ask_user: async (call) => {
2308
3073
  const parsedArgs = (() => {
2309
3074
  try {
2310
3075
  return JSON.parse(call.arguments || "{}");
@@ -2320,8 +3085,8 @@ function buildLocalToolExecutors(args) {
2320
3085
  if (!hasQuestions && (!question || choices.length === 0)) {
2321
3086
  return {
2322
3087
  content: JSON.stringify({
2323
- error: "ui_ask_choice",
2324
- detail: "ui_ask_choice \u9700\u8981 question+choices \u6216 questions\u3002"
3088
+ error: "ask_user",
3089
+ detail: "ask_user \u9700\u8981 question+choices \u6216 questions\u3002"
2325
3090
  }),
2326
3091
  metadata: { uiAskChoice: true, error: true }
2327
3092
  };
@@ -2337,7 +3102,7 @@ function buildLocalToolExecutors(args) {
2337
3102
  if (result.kind === "multi-submitted") {
2338
3103
  return {
2339
3104
  content: JSON.stringify({
2340
- type: "ui_ask_choice",
3105
+ type: "ask_user",
2341
3106
  question,
2342
3107
  choices,
2343
3108
  blocking,
@@ -2354,7 +3119,7 @@ function buildLocalToolExecutors(args) {
2354
3119
  if (result.kind === "selected") {
2355
3120
  return {
2356
3121
  content: JSON.stringify({
2357
- type: "ui_ask_choice",
3122
+ type: "ask_user",
2358
3123
  question,
2359
3124
  choices,
2360
3125
  blocking,
@@ -2369,7 +3134,7 @@ function buildLocalToolExecutors(args) {
2369
3134
  }
2370
3135
  return {
2371
3136
  content: JSON.stringify({
2372
- type: "ui_ask_choice",
3137
+ type: "ask_user",
2373
3138
  question,
2374
3139
  choices,
2375
3140
  blocking,
@@ -2384,7 +3149,7 @@ function buildLocalToolExecutors(args) {
2384
3149
  }
2385
3150
  return {
2386
3151
  content: JSON.stringify({
2387
- type: "ui_ask_choice",
3152
+ type: "ask_user",
2388
3153
  question,
2389
3154
  choices,
2390
3155
  blocking,
@@ -2448,19 +3213,22 @@ function resolveAntigravityWireModel(logicalModelId) {
2448
3213
  return { wireModelId: id };
2449
3214
  }
2450
3215
 
2451
- // packages/agent-runtime/antigravityCloudCodeProvider.ts
2452
- var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
3216
+ // packages/agent-runtime/geminiNativeShared.ts
2453
3217
  var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
2454
- function isGemini3WireModel(modelId) {
3218
+ function isGemini3Model(modelId) {
2455
3219
  return modelId.includes("gemini-3");
2456
3220
  }
2457
3221
  function messageText(content) {
2458
3222
  if (typeof content === "string") return content;
2459
3223
  if (!Array.isArray(content)) return "";
2460
- return content.filter((part) => part?.type === "text").map((part) => part.text).join("\n").trim();
3224
+ return content.filter(
3225
+ (part) => part?.type === "text"
3226
+ ).map((part) => part.text).join("\n").trim();
2461
3227
  }
2462
3228
  function parseDataUrlToInlineData(url) {
2463
- const match = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(url);
3229
+ const match = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
3230
+ url
3231
+ );
2464
3232
  if (!match) return null;
2465
3233
  return { mimeType: match[1], data: match[2] };
2466
3234
  }
@@ -2477,7 +3245,7 @@ function extractInlineDataParts(content) {
2477
3245
  }
2478
3246
  return parts;
2479
3247
  }
2480
- function convertOpenAiMessagesToCca(messages, options) {
3248
+ function convertOpenAiMessagesToGemini(messages, options) {
2481
3249
  const contents = [];
2482
3250
  const systemTexts = [];
2483
3251
  const toolNamesById = /* @__PURE__ */ new Map();
@@ -2493,9 +3261,11 @@ function convertOpenAiMessagesToCca(messages, options) {
2493
3261
  };
2494
3262
  const flushPendingFunctionCalls = () => {
2495
3263
  if (pendingFunctionCalls.length === 0) return;
2496
- const dummyResponses = pendingFunctionCalls.map(({ name }) => ({
2497
- functionResponse: { name, response: { output: "{}" } }
2498
- }));
3264
+ const dummyResponses = pendingFunctionCalls.map(
3265
+ ({ name }) => ({
3266
+ functionResponse: { name, response: { output: "{}" } }
3267
+ })
3268
+ );
2499
3269
  pendingFunctionCalls = [];
2500
3270
  pushOrMergeContent("user", dummyResponses);
2501
3271
  };
@@ -2504,13 +3274,17 @@ function convertOpenAiMessagesToCca(messages, options) {
2504
3274
  const role = String(raw.role);
2505
3275
  const content = "content" in raw ? raw.content : null;
2506
3276
  if (role === "system") {
2507
- const text = messageText(content);
3277
+ const text = messageText(
3278
+ content
3279
+ );
2508
3280
  if (text) systemTexts.push(text);
2509
3281
  continue;
2510
3282
  }
2511
3283
  if (role === "user") {
2512
3284
  flushPendingFunctionCalls();
2513
- const text = messageText(content);
3285
+ const text = messageText(
3286
+ content
3287
+ );
2514
3288
  const imageParts = extractInlineDataParts(
2515
3289
  content
2516
3290
  );
@@ -2524,7 +3298,9 @@ function convertOpenAiMessagesToCca(messages, options) {
2524
3298
  if (role === "assistant") {
2525
3299
  flushPendingFunctionCalls();
2526
3300
  const parts = [];
2527
- const text = messageText(content);
3301
+ const text = messageText(
3302
+ content
3303
+ );
2528
3304
  if (text) parts.push({ text });
2529
3305
  const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
2530
3306
  for (const call of toolCalls) {
@@ -2534,17 +3310,20 @@ function convertOpenAiMessagesToCca(messages, options) {
2534
3310
  toolNamesById.set(id, name);
2535
3311
  pendingFunctionCalls.push({ name, id });
2536
3312
  const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
2537
- const isFirstFunctionCallPart = !parts.some((p) => "functionCall" in p);
2538
- parts.push({
3313
+ const isFirstFunctionCallPart = !parts.some(
3314
+ (p) => "functionCall" in p
3315
+ );
3316
+ const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
3317
+ const part = {
2539
3318
  functionCall: {
2540
3319
  name,
2541
- args: parseToolArgumentsJson(call.function?.arguments),
2542
- id
3320
+ args: parseToolArgs(call.function?.arguments),
3321
+ ...id ? { id } : {}
2543
3322
  },
2544
- ...realSignature ? { thoughtSignature: realSignature } : options.attachSkipThoughtSignature && isFirstFunctionCallPart ? { thoughtSignature: SKIP_THOUGHT_SIGNATURE } : {}
2545
- });
3323
+ ...signature ? { thoughtSignature: signature } : {}
3324
+ };
3325
+ parts.push(part);
2546
3326
  }
2547
- if (parts.length === 0) continue;
2548
3327
  pushOrMergeContent("model", parts);
2549
3328
  continue;
2550
3329
  }
@@ -2562,14 +3341,39 @@ function convertOpenAiMessagesToCca(messages, options) {
2562
3341
  }
2563
3342
  const output = messageText(content) || "{}";
2564
3343
  pushOrMergeContent("user", [
2565
- { functionResponse: { name, response: { output } } }
3344
+ {
3345
+ functionResponse: {
3346
+ name,
3347
+ response: { output },
3348
+ // 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
3349
+ // Gemini contents 转成 Claude messages 时需要 functionResponse →
3350
+ // tool_result 的 tool_use_id;缺 id 时网关报
3351
+ // "tool_result.tool_use_id: Field required"(HTTP 400)。
3352
+ ...toolCallId ? { id: toolCallId } : {}
3353
+ }
3354
+ }
2566
3355
  ]);
2567
3356
  }
2568
3357
  }
2569
3358
  flushPendingFunctionCalls();
2570
3359
  return { contents, systemTexts };
2571
3360
  }
2572
- function convertOpenAiTools(tools) {
3361
+ function parseToolArgs(raw) {
3362
+ if (typeof raw === "string") {
3363
+ try {
3364
+ const parsed = JSON.parse(raw);
3365
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
3366
+ return parsed;
3367
+ }
3368
+ } catch {
3369
+ }
3370
+ }
3371
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
3372
+ return raw;
3373
+ }
3374
+ return {};
3375
+ }
3376
+ function convertOpenAiToolsToGemini(tools) {
2573
3377
  if (!Array.isArray(tools) || tools.length === 0) return void 0;
2574
3378
  const declarations = [];
2575
3379
  for (const tool of tools) {
@@ -2586,79 +3390,7 @@ function convertOpenAiTools(tools) {
2586
3390
  if (declarations.length === 0) return void 0;
2587
3391
  return [{ functionDeclarations: declarations }];
2588
3392
  }
2589
- function buildCloudCodeAssistPayload(args) {
2590
- const projectId = readAntigravityProjectId(args.metadata);
2591
- if (!projectId) {
2592
- throw new Error(
2593
- "Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
2594
- );
2595
- }
2596
- const logicalModel = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gemini-3.1-pro";
2597
- const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
2598
- const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
2599
- const { contents, systemTexts } = convertOpenAiMessagesToCca(rawMessages, {
2600
- attachSkipThoughtSignature: isGemini3WireModel(model)
2601
- });
2602
- if (contents.length === 0) {
2603
- throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
2604
- }
2605
- const prompt = args.agentConfig.prompt?.trim();
2606
- if (prompt) systemTexts.unshift(prompt);
2607
- const request = { contents };
2608
- if (systemTexts.length > 0) {
2609
- request.systemInstruction = {
2610
- role: "user",
2611
- parts: systemTexts.map((text) => ({ text }))
2612
- };
2613
- }
2614
- const tools = convertOpenAiTools(
2615
- Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
2616
- );
2617
- if (tools) {
2618
- request.tools = tools;
2619
- request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
2620
- }
2621
- const generationConfig = {};
2622
- if (profile?.maxOutputTokens) {
2623
- generationConfig.maxOutputTokens = profile.maxOutputTokens;
2624
- } else if (typeof args.agentConfig.max_tokens === "number" && args.agentConfig.max_tokens > 0) {
2625
- generationConfig.maxOutputTokens = args.agentConfig.max_tokens;
2626
- }
2627
- if (typeof args.agentConfig.temperature === "number") {
2628
- generationConfig.temperature = args.agentConfig.temperature;
2629
- }
2630
- if (Object.keys(generationConfig).length > 0) {
2631
- request.generationConfig = generationConfig;
2632
- }
2633
- const agentId = randomUUID();
2634
- const trajectoryId = randomUUID();
2635
- const step = 2;
2636
- const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
2637
- const isClaude = model.toLowerCase().includes("claude");
2638
- const labels = {
2639
- trajectory_id: trajectoryId,
2640
- last_step_index: String(step - 1),
2641
- used_claude: String(isClaude),
2642
- used_claude_conservative: String(isClaude)
2643
- };
2644
- if (profile?.modelEnum) {
2645
- labels.model_enum = profile.modelEnum;
2646
- }
2647
- request.labels = labels;
2648
- request.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
2649
- return {
2650
- url: `${resolveAntigravityCloudCodeBaseUrl(args.agentConfig.customProviderUrl)}${STREAM_PATH}`,
2651
- envelope: {
2652
- project: projectId,
2653
- model,
2654
- request,
2655
- requestId,
2656
- requestType: "agent",
2657
- userAgent: "antigravity"
2658
- }
2659
- };
2660
- }
2661
- function accumulateCcaChunks(chunks) {
3393
+ function accumulateGeminiChunks(chunks) {
2662
3394
  let text = "";
2663
3395
  const toolCalls = [];
2664
3396
  let usage;
@@ -2679,11 +3411,10 @@ function accumulateCcaChunks(chunks) {
2679
3411
  }
2680
3412
  const candidates = Array.isArray(response.candidates) ? response.candidates : [];
2681
3413
  for (const candidate of candidates) {
2682
- if (!candidate || typeof candidate !== "object" || !("content" in candidate)) continue;
2683
- const content = candidate.content;
2684
- if (!content || typeof content !== "object" || !("parts" in content)) continue;
2685
- const parts = content.parts;
2686
- if (!Array.isArray(parts)) continue;
3414
+ if (!candidate || typeof candidate !== "object") continue;
3415
+ const parts = Array.isArray(
3416
+ candidate.content?.parts
3417
+ ) ? candidate.content.parts : [];
2687
3418
  for (const part of parts) {
2688
3419
  if (!part || typeof part !== "object") continue;
2689
3420
  const partSignature = part.thoughtSignature;
@@ -2700,7 +3431,7 @@ function accumulateCcaChunks(chunks) {
2700
3431
  const call = part.functionCall;
2701
3432
  const name = typeof call.name === "string" ? call.name : "tool";
2702
3433
  const id = typeof call.id === "string" ? call.id : `${name}_${toolCalls.length}`;
2703
- const argsObj = asRecordOrEmpty(call.args);
3434
+ const argsObj = call.args && typeof call.args === "object" ? call.args : {};
2704
3435
  const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : pendingThoughtSignature;
2705
3436
  pendingThoughtSignature = void 0;
2706
3437
  toolCalls.push({
@@ -2713,7 +3444,114 @@ function accumulateCcaChunks(chunks) {
2713
3444
  }
2714
3445
  }
2715
3446
  }
2716
- return { text, toolCalls, usage };
3447
+ return { text, toolCalls, usage };
3448
+ }
3449
+ function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
3450
+ return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
3451
+ }
3452
+ function buildGeminiGenerateContentRequest(args) {
3453
+ const { contents, systemTexts } = convertOpenAiMessagesToGemini(
3454
+ args.messages,
3455
+ { attachSkipThoughtSignature: args.attachSkipThoughtSignature }
3456
+ );
3457
+ const request = { contents };
3458
+ if (systemTexts.length > 0) {
3459
+ request.systemInstruction = {
3460
+ role: "user",
3461
+ parts: systemTexts.map((text) => ({ text }))
3462
+ };
3463
+ }
3464
+ const toolsResult = convertOpenAiToolsToGemini(args.tools);
3465
+ if (toolsResult) {
3466
+ request.tools = toolsResult;
3467
+ request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
3468
+ }
3469
+ const generationConfig = {};
3470
+ if (typeof args.maxTokens === "number" && args.maxTokens > 0) {
3471
+ generationConfig.maxOutputTokens = args.maxTokens;
3472
+ }
3473
+ if (typeof args.temperature === "number") {
3474
+ generationConfig.temperature = args.temperature;
3475
+ }
3476
+ if (Object.keys(generationConfig).length > 0) {
3477
+ request.generationConfig = generationConfig;
3478
+ }
3479
+ return request;
3480
+ }
3481
+
3482
+ // packages/agent-runtime/antigravityCloudCodeProvider.ts
3483
+ var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
3484
+ function buildCloudCodeAssistPayload(args) {
3485
+ const projectId = readAntigravityProjectId(args.metadata);
3486
+ if (!projectId) {
3487
+ throw new Error(
3488
+ "Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
3489
+ );
3490
+ }
3491
+ const logicalModel = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gemini-3.1-pro";
3492
+ const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
3493
+ const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
3494
+ const isClaude = model.toLowerCase().includes("claude");
3495
+ const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
3496
+ attachSkipThoughtSignature: isGemini3Model(model)
3497
+ });
3498
+ if (contents.length === 0) {
3499
+ throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
3500
+ }
3501
+ const prompt = args.agentConfig.prompt?.trim();
3502
+ if (prompt) systemTexts.unshift(prompt);
3503
+ const request = { contents };
3504
+ if (systemTexts.length > 0) {
3505
+ request.systemInstruction = {
3506
+ role: "user",
3507
+ parts: systemTexts.map((text) => ({ text }))
3508
+ };
3509
+ }
3510
+ const tools = convertOpenAiToolsToGemini(
3511
+ Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
3512
+ );
3513
+ if (tools) {
3514
+ request.tools = tools;
3515
+ request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
3516
+ }
3517
+ const generationConfig = {};
3518
+ if (profile?.maxOutputTokens) {
3519
+ generationConfig.maxOutputTokens = profile.maxOutputTokens;
3520
+ } else if (typeof args.agentConfig.max_tokens === "number" && args.agentConfig.max_tokens > 0) {
3521
+ generationConfig.maxOutputTokens = args.agentConfig.max_tokens;
3522
+ }
3523
+ if (typeof args.agentConfig.temperature === "number") {
3524
+ generationConfig.temperature = args.agentConfig.temperature;
3525
+ }
3526
+ if (Object.keys(generationConfig).length > 0) {
3527
+ request.generationConfig = generationConfig;
3528
+ }
3529
+ const agentId = randomUUID();
3530
+ const trajectoryId = randomUUID();
3531
+ const step = 2;
3532
+ const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
3533
+ const labels = {
3534
+ trajectory_id: trajectoryId,
3535
+ last_step_index: String(step - 1),
3536
+ used_claude: String(isClaude),
3537
+ used_claude_conservative: String(isClaude)
3538
+ };
3539
+ if (profile?.modelEnum) {
3540
+ labels.model_enum = profile.modelEnum;
3541
+ }
3542
+ request.labels = labels;
3543
+ request.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
3544
+ return {
3545
+ url: `${resolveAntigravityCloudCodeBaseUrl(args.agentConfig.customProviderUrl)}${STREAM_PATH}`,
3546
+ envelope: {
3547
+ project: projectId,
3548
+ model,
3549
+ request,
3550
+ requestId,
3551
+ requestType: "agent",
3552
+ userAgent: "antigravity"
3553
+ }
3554
+ };
2717
3555
  }
2718
3556
  async function readSseJsonChunks(response) {
2719
3557
  return readSseDataValues(response, parseSseDataLineJson);
@@ -2739,7 +3577,7 @@ async function fetchAntigravityCloudCodeCompletion(args) {
2739
3577
  };
2740
3578
  }
2741
3579
  const chunks = await readSseJsonChunks(response);
2742
- const { text, toolCalls, usage } = accumulateCcaChunks(chunks);
3580
+ const { text, toolCalls, usage } = accumulateGeminiChunks(chunks);
2743
3581
  const message = {
2744
3582
  role: "assistant",
2745
3583
  content: text || null
@@ -2775,9 +3613,67 @@ var CLAUDE_CODE_IDENTITY_PATTERNS = [
2775
3613
  CLAUDE_CODE_SYSTEM_INSTRUCTION,
2776
3614
  "You are Claude Code"
2777
3615
  ];
3616
+ var REASONING_EFFORT_TO_BUDGET = {
3617
+ minimal: 2048,
3618
+ low: 4096,
3619
+ medium: 8192,
3620
+ high: 16384,
3621
+ xhigh: 32e3,
3622
+ max: 32e3
3623
+ };
3624
+ function resolveThinkingBudget(effort) {
3625
+ if (!effort) return void 0;
3626
+ const normalized = effort.toLowerCase();
3627
+ if (normalized === "none" || normalized === "off") return void 0;
3628
+ return REASONING_EFFORT_TO_BUDGET[normalized];
3629
+ }
3630
+ var DEFAULT_THINKING_EFFORT = "medium";
3631
+ var DEFAULT_ENABLED_BUDGET = 8192;
3632
+ var DEFAULT_ENABLE_THINKING_BUDGET = 8e3;
3633
+ var ANTHROPIC_EFFORT_ALIASES = { minimal: "low" };
3634
+ function resolveThinkingSpec(input) {
3635
+ const { model, maxTokens } = input;
3636
+ const normalizedEffort = input.reasoningEffort?.toLowerCase();
3637
+ const effortDisabled = normalizedEffort === "none" || normalizedEffort === "off";
3638
+ const effectiveEffort = normalizedEffort !== void 0 && !effortDisabled ? ANTHROPIC_EFFORT_ALIASES[normalizedEffort] ?? normalizedEffort : DEFAULT_THINKING_EFFORT;
3639
+ let thinkingBlock;
3640
+ let outputConfig;
3641
+ let finalMaxTokens = maxTokens;
3642
+ let finalTemperature = input.temperature;
3643
+ if (isAdaptiveThinkingModelId(model)) {
3644
+ if (effortDisabled) {
3645
+ thinkingBlock = { type: "disabled" };
3646
+ } else {
3647
+ thinkingBlock = { type: "adaptive", display: "summarized" };
3648
+ outputConfig = { effort: effectiveEffort };
3649
+ }
3650
+ } else {
3651
+ const injected = input.injectedThinking;
3652
+ const injectedBudget = injected?.type === "enabled" && typeof injected.budget_tokens === "number" ? injected.budget_tokens : void 0;
3653
+ const effortBudget = resolveThinkingBudget(input.reasoningEffort);
3654
+ const fallbackBudget = input.reasoningEffort === void 0 ? injectedBudget ?? (input.enableThinking === true ? typeof input.thinkingBudget === "number" ? input.thinkingBudget : DEFAULT_ENABLE_THINKING_BUDGET : DEFAULT_ENABLED_BUDGET) : void 0;
3655
+ const thinkingBudget = effortBudget ?? fallbackBudget;
3656
+ if (thinkingBudget !== void 0) {
3657
+ thinkingBlock = { type: "enabled", budget_tokens: thinkingBudget };
3658
+ finalMaxTokens = Math.max(maxTokens, thinkingBudget + 1);
3659
+ finalTemperature = 1;
3660
+ }
3661
+ }
3662
+ return {
3663
+ thinkingBlock,
3664
+ outputConfig,
3665
+ maxTokens: finalMaxTokens,
3666
+ temperature: finalTemperature
3667
+ };
3668
+ }
2778
3669
  function stringValue(value) {
2779
3670
  return typeof value === "string" && value.length > 0 ? value : void 0;
2780
3671
  }
3672
+ function isCacheControl(value) {
3673
+ return Boolean(
3674
+ value && typeof value === "object" && !Array.isArray(value) && typeof value.type === "string"
3675
+ );
3676
+ }
2781
3677
  function toAnthropicContent(content) {
2782
3678
  if (typeof content === "string") {
2783
3679
  return content.length > 0 ? [{ type: "text", text: content }] : [];
@@ -2788,17 +3684,23 @@ function toAnthropicContent(content) {
2788
3684
  if (!raw || typeof raw !== "object") continue;
2789
3685
  const part = raw;
2790
3686
  if ((part.type === "text" || part.type === "input_text") && typeof part.text === "string") {
2791
- if (part.text.length > 0) blocks.push({ type: "text", text: part.text });
3687
+ if (part.text.length > 0) {
3688
+ const block2 = { type: "text", text: part.text };
3689
+ if (isCacheControl(part.cache_control)) block2.cache_control = part.cache_control;
3690
+ blocks.push(block2);
3691
+ }
2792
3692
  continue;
2793
3693
  }
2794
3694
  if (part.type !== "image_url") continue;
2795
3695
  const imageUrl = typeof part.image_url === "string" ? part.image_url : stringValue(part.image_url?.url);
2796
3696
  if (!imageUrl) continue;
2797
3697
  const dataMatch = imageUrl.match(/^data:([^;,]+);base64,(.+)$/s);
2798
- blocks.push({
3698
+ const block = {
2799
3699
  type: "image",
2800
3700
  source: dataMatch ? { type: "base64", media_type: dataMatch[1], data: dataMatch[2] } : { type: "url", url: imageUrl }
2801
- });
3701
+ };
3702
+ if (isCacheControl(part.cache_control)) block.cache_control = part.cache_control;
3703
+ blocks.push(block);
2802
3704
  }
2803
3705
  return blocks;
2804
3706
  }
@@ -2832,7 +3734,15 @@ function buildAnthropicMessagesBody(args) {
2832
3734
  const message = raw;
2833
3735
  const role = String(message.role ?? "");
2834
3736
  if (role === "system" || role === "developer") {
2835
- system.push(...toAnthropicContent(message.content));
3737
+ const stablePrefixChars = Number(message.stable_prefix_chars);
3738
+ if (typeof message.content === "string" && Number.isFinite(stablePrefixChars) && stablePrefixChars > 0 && stablePrefixChars <= message.content.length) {
3739
+ const stable = message.content.slice(0, stablePrefixChars);
3740
+ const dynamic = message.content.slice(stablePrefixChars);
3741
+ system.push({ type: "text", text: stable, cache_control: { type: "ephemeral" } });
3742
+ if (dynamic) system.push({ type: "text", text: dynamic });
3743
+ } else {
3744
+ system.push(...toAnthropicContent(message.content));
3745
+ }
2836
3746
  continue;
2837
3747
  }
2838
3748
  if (role === "tool") {
@@ -2874,6 +3784,9 @@ function buildAnthropicMessagesBody(args) {
2874
3784
  if (!hasClaudeCodeIdentity(system)) {
2875
3785
  system.unshift({ type: "text", text: CLAUDE_CODE_SYSTEM_INSTRUCTION });
2876
3786
  }
3787
+ if (system.length > 0 && !system.some((block) => isCacheControl(block.cache_control))) {
3788
+ system[system.length - 1].cache_control = { type: "ephemeral" };
3789
+ }
2877
3790
  const tools = Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools.flatMap((raw) => {
2878
3791
  if (!raw || typeof raw !== "object") return [];
2879
3792
  const fn = raw.function;
@@ -2888,14 +3801,39 @@ function buildAnthropicMessagesBody(args) {
2888
3801
  const model = stringValue(args.openAiBody.model) ?? args.agentConfig.model ?? "claude-sonnet-5";
2889
3802
  const maxTokensRaw = args.openAiBody.max_completion_tokens ?? args.openAiBody.max_tokens ?? args.agentConfig.max_tokens;
2890
3803
  const maxTokens = typeof maxTokensRaw === "number" && Number.isFinite(maxTokensRaw) ? Math.max(1, Math.floor(maxTokensRaw)) : 8192;
3804
+ const reasoningEffort = stringValue(args.openAiBody.reasoning_effort) ?? stringValue(args.agentConfig.reasoning_effort);
3805
+ const spec = resolveThinkingSpec({
3806
+ model,
3807
+ reasoningEffort,
3808
+ maxTokens,
3809
+ temperature: typeof args.openAiBody.temperature === "number" ? args.openAiBody.temperature : args.agentConfig.temperature,
3810
+ injectedThinking: args.openAiBody.thinking,
3811
+ enableThinking: args.agentConfig.enableThinking,
3812
+ thinkingBudget: args.agentConfig.thinkingBudget
3813
+ });
3814
+ const { thinkingBlock, outputConfig } = spec;
3815
+ const finalMaxTokens = spec.maxTokens;
3816
+ const finalTemperature = spec.temperature;
3817
+ if (messages.length > 0) {
3818
+ const lastMessage = messages[messages.length - 1];
3819
+ const content = Array.isArray(lastMessage.content) ? lastMessage.content : [];
3820
+ if (content.length > 0) {
3821
+ const lastBlock = content[content.length - 1];
3822
+ if (!isCacheControl(lastBlock.cache_control)) {
3823
+ lastBlock.cache_control = { type: "ephemeral" };
3824
+ }
3825
+ }
3826
+ }
2891
3827
  return {
2892
3828
  model,
2893
3829
  messages,
2894
- max_tokens: maxTokens,
3830
+ max_tokens: finalMaxTokens,
2895
3831
  stream: false,
3832
+ ...thinkingBlock ? { thinking: thinkingBlock } : {},
3833
+ ...outputConfig ? { output_config: outputConfig } : {},
2896
3834
  ...system.length > 0 ? { system } : {},
2897
3835
  ...tools.length > 0 ? { tools } : {},
2898
- ...typeof args.openAiBody.temperature === "number" ? { temperature: args.openAiBody.temperature } : typeof args.agentConfig.temperature === "number" ? { temperature: args.agentConfig.temperature } : {},
3836
+ ...typeof finalTemperature === "number" ? { temperature: finalTemperature } : {},
2899
3837
  ...typeof args.openAiBody.top_p === "number" ? { top_p: args.openAiBody.top_p } : {}
2900
3838
  };
2901
3839
  }
@@ -2919,6 +3857,8 @@ function mapAnthropicMessageToOpenAi(payload) {
2919
3857
  }
2920
3858
  const usage = payload.usage ?? {};
2921
3859
  const inputTokens = (typeof usage.input_tokens === "number" ? usage.input_tokens : 0) + (typeof usage.cache_creation_input_tokens === "number" ? usage.cache_creation_input_tokens : 0) + (typeof usage.cache_read_input_tokens === "number" ? usage.cache_read_input_tokens : 0);
3860
+ const cacheCreationInputTokens = typeof usage.cache_creation_input_tokens === "number" ? usage.cache_creation_input_tokens : 0;
3861
+ const cacheReadInputTokens = typeof usage.cache_read_input_tokens === "number" ? usage.cache_read_input_tokens : 0;
2922
3862
  const outputTokens = typeof usage.output_tokens === "number" ? usage.output_tokens : 0;
2923
3863
  const stopReason = String(payload.stop_reason ?? "");
2924
3864
  const message = { role: "assistant", content: text || null };
@@ -2934,9 +3874,16 @@ function mapAnthropicMessageToOpenAi(payload) {
2934
3874
  finish_reason: toolCalls.length > 0 || stopReason === "tool_use" ? "tool_calls" : stopReason === "max_tokens" ? "length" : "stop"
2935
3875
  }],
2936
3876
  usage: {
3877
+ // prompt_tokens/input_tokens are total input, including cache read/write.
3878
+ // Preserve Anthropic's components so normalization and billing can apply
3879
+ // the correct cache prices without double-counting them.
2937
3880
  prompt_tokens: inputTokens,
3881
+ input_tokens: inputTokens,
2938
3882
  completion_tokens: outputTokens,
2939
- total_tokens: inputTokens + outputTokens
3883
+ output_tokens: outputTokens,
3884
+ total_tokens: inputTokens + outputTokens,
3885
+ cache_creation_input_tokens: cacheCreationInputTokens,
3886
+ cache_read_input_tokens: cacheReadInputTokens
2940
3887
  }
2941
3888
  };
2942
3889
  }
@@ -9011,6 +9958,262 @@ function isCursorOAuthAgent(agent) {
9011
9958
  return agent.apiKeyRef?.trim().toLowerCase() === "cursor";
9012
9959
  }
9013
9960
 
9961
+ // packages/agent-runtime/codexResponsesProvider.ts
9962
+ import { randomUUID as randomUUID4 } from "node:crypto";
9963
+ var CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
9964
+ var CODEX_CLIENT_VERSION = "0.144.1";
9965
+ var CODEX_ORIGINATOR = "codex_cli_rs";
9966
+ var CODEX_OPENAI_BETA = "responses=experimental";
9967
+ var OPENAI_AUTH_CLAIM = "https://api.openai.com/auth";
9968
+ var CODEX_INSTALLATION_ID = randomUUID4();
9969
+ function decodeCodexAccountId(accessToken) {
9970
+ const parts = accessToken.split(".");
9971
+ if (parts.length < 2) return void 0;
9972
+ try {
9973
+ const payload = JSON.parse(
9974
+ Buffer.from(parts[1], "base64").toString("utf8")
9975
+ );
9976
+ const claim = payload[OPENAI_AUTH_CLAIM];
9977
+ const value = claim && typeof claim === "object" ? claim.chatgpt_account_id : void 0;
9978
+ return typeof value === "string" && value ? value : void 0;
9979
+ } catch {
9980
+ return void 0;
9981
+ }
9982
+ }
9983
+ function createCodexRequestIdentity(installationId = CODEX_INSTALLATION_ID) {
9984
+ const sessionId = randomUUID4();
9985
+ const threadId = randomUUID4();
9986
+ const windowId = randomUUID4();
9987
+ const turnId = randomUUID4();
9988
+ const turnMetadata = {
9989
+ installation_id: installationId,
9990
+ session_id: sessionId,
9991
+ thread_id: threadId,
9992
+ turn_id: turnId,
9993
+ window_id: windowId,
9994
+ request_kind: "turn",
9995
+ turn_started_at_unix_ms: Date.now()
9996
+ };
9997
+ const turnMetadataJson = JSON.stringify(turnMetadata);
9998
+ return {
9999
+ sessionId,
10000
+ threadId,
10001
+ windowId,
10002
+ turnId,
10003
+ turnMetadataJson,
10004
+ clientMetadata: {
10005
+ "x-codex-installation-id": installationId,
10006
+ session_id: sessionId,
10007
+ thread_id: threadId,
10008
+ "x-codex-window-id": windowId,
10009
+ turn_id: turnId,
10010
+ "x-codex-turn-metadata": turnMetadataJson
10011
+ }
10012
+ };
10013
+ }
10014
+ function buildCodexCompatibilityHeaders(identity, accountId) {
10015
+ return {
10016
+ Authorization: "",
10017
+ // filled by caller with bearer token
10018
+ "Content-Type": "application/json",
10019
+ Accept: "text/event-stream",
10020
+ "chatgpt-account-id": accountId,
10021
+ "OpenAI-Beta": CODEX_OPENAI_BETA,
10022
+ originator: CODEX_ORIGINATOR,
10023
+ version: CODEX_CLIENT_VERSION,
10024
+ session_id: identity.sessionId,
10025
+ conversation_id: identity.sessionId,
10026
+ "x-client-request-id": identity.sessionId,
10027
+ "session-id": identity.sessionId,
10028
+ "thread-id": identity.threadId,
10029
+ "x-codex-window-id": identity.windowId,
10030
+ "x-codex-turn-metadata": identity.turnMetadataJson
10031
+ };
10032
+ }
10033
+ function collectInstructions(messages, agentPrompt) {
10034
+ const systemTexts = [];
10035
+ const prompt = agentPrompt?.trim();
10036
+ if (prompt) systemTexts.push(prompt);
10037
+ for (const raw of messages) {
10038
+ if (!raw || typeof raw !== "object") continue;
10039
+ const role = String(raw.role ?? "");
10040
+ if (role !== "system" && role !== "developer") continue;
10041
+ const content = raw.content;
10042
+ const stringContent = asOptionalTrimmedString(content);
10043
+ if (stringContent) {
10044
+ systemTexts.push(stringContent);
10045
+ } else if (Array.isArray(content)) {
10046
+ const text = content.filter(
10047
+ (p) => !!p && p.type === "text"
10048
+ ).map((p) => p.text).join("\n").trim();
10049
+ if (text) systemTexts.push(text);
10050
+ }
10051
+ }
10052
+ return systemTexts.join("\n\n");
10053
+ }
10054
+ function collectStableInstructions(messages, fallbackPrompt) {
10055
+ const systemTexts = [];
10056
+ if (fallbackPrompt?.trim()) systemTexts.push(fallbackPrompt.trim());
10057
+ for (const raw of messages) {
10058
+ if (!raw || typeof raw !== "object") continue;
10059
+ const message = raw;
10060
+ const role = String(message.role ?? "");
10061
+ if (role !== "system" && role !== "developer") continue;
10062
+ if (typeof message.content === "string") {
10063
+ const boundary = Number(message.stable_prefix_chars);
10064
+ const text = Number.isFinite(boundary) && boundary > 0 ? message.content.slice(0, boundary) : message.content;
10065
+ if (text.trim()) systemTexts.push(text.trim());
10066
+ }
10067
+ }
10068
+ return systemTexts.join("\n\n");
10069
+ }
10070
+ function stablePromptCacheKey(parts) {
10071
+ const value = JSON.stringify(parts);
10072
+ let hash = 2166136261;
10073
+ for (let index = 0; index < value.length; index += 1) {
10074
+ hash ^= value.charCodeAt(index);
10075
+ hash = Math.imul(hash, 16777619) >>> 0;
10076
+ }
10077
+ return `nolo-codex-${hash.toString(16).padStart(8, "0")}`;
10078
+ }
10079
+ function buildCodexRequestBody(args, identity = createCodexRequestIdentity()) {
10080
+ const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
10081
+ const nonSystem = rawMessages.filter((m) => {
10082
+ const role = m && typeof m === "object" ? String(m.role) : "";
10083
+ return role !== "system" && role !== "developer";
10084
+ });
10085
+ const input = convertMessagesToResponsesInput(nonSystem);
10086
+ const instructions = collectInstructions(rawMessages, args.agentConfig.prompt);
10087
+ const stableInstructions = collectStableInstructions(rawMessages, args.agentConfig.prompt);
10088
+ const model = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gpt-5.5";
10089
+ const tools = toResponsesTools(
10090
+ Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
10091
+ );
10092
+ const body = {
10093
+ model,
10094
+ input,
10095
+ stream: true,
10096
+ store: false,
10097
+ // Keep routing stable across turns and request UUIDs. Growing input/history
10098
+ // is intentionally excluded; only stable request-prefix material belongs.
10099
+ prompt_cache_key: stablePromptCacheKey([model, stableInstructions, tools ?? []]),
10100
+ client_metadata: identity.clientMetadata
10101
+ };
10102
+ if (instructions) body.instructions = instructions;
10103
+ if (tools && tools.length > 0) {
10104
+ body.tools = tools;
10105
+ body.tool_choice = "auto";
10106
+ body.parallel_tool_calls = true;
10107
+ }
10108
+ return body;
10109
+ }
10110
+ function aggregateResponsesStream(events) {
10111
+ let text = "";
10112
+ const toolCalls = [];
10113
+ let usage;
10114
+ for (const ev of events) {
10115
+ const type = String(ev.type ?? "");
10116
+ if (type === "response.output_text.delta" && typeof ev.delta === "string") {
10117
+ text += ev.delta;
10118
+ continue;
10119
+ }
10120
+ if (type === "response.output_item.done") {
10121
+ const item = ev.item;
10122
+ if (item && item.type === "function_call") {
10123
+ const name = typeof item.name === "string" ? item.name : "";
10124
+ if (name) {
10125
+ toolCalls.push({
10126
+ id: typeof item.call_id === "string" && item.call_id ? item.call_id : `${name}_${toolCalls.length}`,
10127
+ type: "function",
10128
+ function: {
10129
+ name,
10130
+ arguments: typeof item.arguments === "string" ? item.arguments : "{}"
10131
+ }
10132
+ });
10133
+ }
10134
+ }
10135
+ continue;
10136
+ }
10137
+ if (type === "response.completed") {
10138
+ const response = ev.response;
10139
+ const u = response?.usage;
10140
+ if (u) {
10141
+ const prompt = typeof u.input_tokens === "number" ? u.input_tokens : 0;
10142
+ const completion = typeof u.output_tokens === "number" ? u.output_tokens : 0;
10143
+ const total = typeof u.total_tokens === "number" ? u.total_tokens : prompt + completion;
10144
+ usage = {
10145
+ prompt_tokens: prompt,
10146
+ completion_tokens: completion,
10147
+ total_tokens: total
10148
+ };
10149
+ }
10150
+ }
10151
+ }
10152
+ return { text, toolCalls, usage };
10153
+ }
10154
+ async function readSseEvents(response) {
10155
+ return readSseDataValues(response, (line) => {
10156
+ const ev = parseSseDataLineObject(line);
10157
+ return ev && !Array.isArray(ev) ? ev : null;
10158
+ });
10159
+ }
10160
+ async function fetchCodexResponsesCompletion(args) {
10161
+ const fetchImpl = args.fetchImpl ?? fetch;
10162
+ const accountId = args.accountId?.trim() || decodeCodexAccountId(args.accessToken);
10163
+ if (!accountId) {
10164
+ return {
10165
+ status: 401,
10166
+ body: {
10167
+ error: {
10168
+ message: "ChatGPT Codex credential is missing chatgpt_account_id. Re-run `nolo auth chatgpt`."
10169
+ }
10170
+ }
10171
+ };
10172
+ }
10173
+ const identity = createCodexRequestIdentity();
10174
+ const body = buildCodexRequestBody(args, identity);
10175
+ const headers = buildCodexCompatibilityHeaders(identity, accountId);
10176
+ headers.Authorization = `Bearer ${args.accessToken}`;
10177
+ const response = await fetchImpl(CODEX_RESPONSES_URL, {
10178
+ method: "POST",
10179
+ headers,
10180
+ body: JSON.stringify(body),
10181
+ signal: args.signal
10182
+ });
10183
+ if (!response.ok) {
10184
+ const errorText = await response.text();
10185
+ return {
10186
+ status: response.status,
10187
+ body: { error: { message: errorText || response.statusText } }
10188
+ };
10189
+ }
10190
+ const events = await readSseEvents(response);
10191
+ const { text, toolCalls, usage } = aggregateResponsesStream(events);
10192
+ const message = {
10193
+ role: "assistant",
10194
+ content: text || null
10195
+ };
10196
+ if (toolCalls.length > 0) message.tool_calls = toolCalls;
10197
+ return {
10198
+ status: 200,
10199
+ body: {
10200
+ choices: [
10201
+ {
10202
+ index: 0,
10203
+ message,
10204
+ finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop"
10205
+ }
10206
+ ],
10207
+ ...usage ? { usage } : {}
10208
+ }
10209
+ };
10210
+ }
10211
+ function isCodexOAuthAgent(agentConfig) {
10212
+ if (!agentConfig) return false;
10213
+ const apiKeyRef = asTrimmedLowercaseString(agentConfig.apiKeyRef);
10214
+ return apiKeyRef === "chatgpt";
10215
+ }
10216
+
9014
10217
  // packages/agent-runtime/oauthProviders.ts
9015
10218
  var XAI_ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1e3;
9016
10219
  var decodeBase64 = (s) => Buffer.from(s, "base64").toString("utf8");
@@ -9504,7 +10707,7 @@ function buildOpenAiTools(args) {
9504
10707
  const toolset = buildLocalWorkspaceToolsetForEnv(args);
9505
10708
  const toolNameSet = new Set(args.toolNames ?? []);
9506
10709
  const callAgentTools = toolNameSet.has("callAgent") ? prepareTools(["callAgent"]) : [];
9507
- const uiAskChoiceTools = toolNameSet.has("ui_ask_choice") ? prepareTools(["ui_ask_choice"]) : [];
10710
+ const uiAskChoiceTools = toolNameSet.has("ask_user") ? prepareTools(["ask_user"]) : [];
9508
10711
  const readPastedTextTools = toolNameSet.has("readPastedText") ? [
9509
10712
  {
9510
10713
  type: "function",
@@ -9564,10 +10767,10 @@ function buildOpenAiTools(args) {
9564
10767
  var CLI_DEFAULT_TOOLS = ["exa_search", "fetchWebpage"];
9565
10768
  function addDefaultCliCoreTools(toolNames, env, options) {
9566
10769
  const declaredOnly = env && shouldUseDeclaredOnlyLocalWorkspaceTools(env);
9567
- const forcedTools = options?.hasUserChoice === true ? FORCED_TOOLS : FORCED_TOOLS.filter((name) => name !== "ui_ask_choice");
10770
+ const forcedTools = options?.hasUserChoice === true ? FORCED_TOOLS : FORCED_TOOLS.filter((name) => name !== "ask_user");
9568
10771
  const injected = declaredOnly ? [...forcedTools] : [...forcedTools, ...CLI_DEFAULT_TOOLS];
9569
10772
  const combined = [...toolNames, ...injected];
9570
- const filtered = options?.hasUserChoice === true ? combined : combined.filter((name) => name !== "ui_ask_choice");
10773
+ const filtered = options?.hasUserChoice === true ? combined : combined.filter((name) => name !== "ask_user");
9571
10774
  return [...new Set(filtered)];
9572
10775
  }
9573
10776
  function resolveCliEffectiveEnabledPacks(args) {
@@ -9860,9 +11063,9 @@ function createCliCallAgentToolExecutor(deps, ctx) {
9860
11063
  // packages/cli/client/localRuntimeAdapter.ts
9861
11064
  var currentMetaFile = fileURLToPath(import.meta.url);
9862
11065
  var isJsBundle = extname(currentMetaFile) === ".js";
9863
- var SOURCE_CLI_DIR = isJsBundle ? dirname(currentMetaFile) : dirname(dirname(currentMetaFile));
9864
- var CLI_DIR = isCompiledBinary() ? dirname(process.execPath) : SOURCE_CLI_DIR;
9865
- var CLI_ENTRYPOINT = isCompiledBinary() ? process.execPath : isJsBundle ? currentMetaFile : join(SOURCE_CLI_DIR, "index.ts");
11066
+ var SOURCE_CLI_DIR = isJsBundle ? dirname2(currentMetaFile) : dirname2(dirname2(currentMetaFile));
11067
+ var CLI_DIR = isCompiledBinary() ? dirname2(process.execPath) : SOURCE_CLI_DIR;
11068
+ var CLI_ENTRYPOINT = isCompiledBinary() ? process.execPath : isJsBundle ? currentMetaFile : join2(SOURCE_CLI_DIR, "index.ts");
9866
11069
  function createCliLocalRuntimeAdapter(deps) {
9867
11070
  const now = deps.now ?? Date.now;
9868
11071
  const createId = deps.createId ?? createFallbackId;
@@ -10208,6 +11411,74 @@ function createCliLocalRuntimeAdapter(deps) {
10208
11411
  }
10209
11412
  };
10210
11413
  }
11414
+ if (isCodexOAuthAgent(agentConfig)) {
11415
+ const accessToken = await apiKeyRefResolver("chatgpt");
11416
+ if (!accessToken) {
11417
+ throw new Error(
11418
+ 'OAuth credential for "chatgpt" not found locally. Run `nolo auth chatgpt`.'
11419
+ );
11420
+ }
11421
+ const credential = readOAuthCredential("chatgpt");
11422
+ const accountId = credential?.accountId;
11423
+ const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
11424
+ agentConfig,
11425
+ deps.env,
11426
+ buildProviderOpenAiTools,
11427
+ additionalToolNames,
11428
+ { hasUserChoice: Boolean(deps.requestUserChoice) }
11429
+ );
11430
+ logLocalRuntimeDiagnostic("provider.selected", {
11431
+ agentKey: agentConfig.key,
11432
+ transport: "codex-responses",
11433
+ provider: "openai",
11434
+ model: agentConfig.model ?? "gpt-5.6-sol",
11435
+ hasApiKey: true
11436
+ });
11437
+ return {
11438
+ model: agentConfig.model || "gpt-5.6-sol",
11439
+ complete: async (messages, options) => {
11440
+ const result = await fetchCodexResponsesCompletion({
11441
+ agentConfig,
11442
+ accessToken,
11443
+ ...accountId ? { accountId } : {},
11444
+ openAiBody: {
11445
+ model: agentConfig.model || "gpt-5.6-sol",
11446
+ messages,
11447
+ stream: false,
11448
+ ...tools2.length > 0 ? { tools: tools2 } : {}
11449
+ },
11450
+ fetchImpl: (url, init) => fetchWithTransientRetry(fetchImpl, url, init, {
11451
+ sleep: deps.sleep,
11452
+ loopbackRequest
11453
+ })
11454
+ });
11455
+ if (result.status < 200 || result.status >= 300) {
11456
+ const errMsg = result.body?.error && typeof result.body.error === "object" && typeof result.body.error.message === "string" ? result.body.error.message : JSON.stringify(result.body);
11457
+ throw new Error(
11458
+ `local Codex OAuth provider failed: HTTP ${result.status} ${errMsg}`
11459
+ );
11460
+ }
11461
+ const choice = Array.isArray(result.body.choices) ? result.body.choices[0] : void 0;
11462
+ const message = choice?.message ?? {};
11463
+ const content = typeof message.content === "string" ? message.content : "";
11464
+ const tool_calls = Array.isArray(message.tool_calls) ? message.tool_calls : void 0;
11465
+ if (content && options?.onTextDelta) options.onTextDelta(content);
11466
+ logLocalRuntimeDiagnostic("provider.request.result", {
11467
+ agentKey: agentConfig.key,
11468
+ transport: "codex-responses",
11469
+ ok: true,
11470
+ contentChars: content.length,
11471
+ toolCallCount: tool_calls?.length ?? 0,
11472
+ requestedToolNames: requestedToolNames2
11473
+ });
11474
+ return {
11475
+ content,
11476
+ ...tool_calls ? { tool_calls } : {},
11477
+ trace: messages
11478
+ };
11479
+ }
11480
+ };
11481
+ }
10211
11482
  if (isCursorOAuthAgent(agentConfig)) {
10212
11483
  const accessToken = await apiKeyRefResolver("cursor");
10213
11484
  if (!accessToken) {
@@ -10277,6 +11548,101 @@ function createCliLocalRuntimeAdapter(deps) {
10277
11548
  }
10278
11549
  };
10279
11550
  }
11551
+ if (shouldUsePlatformChatProvider(deps.env, agentConfig) && isGemini3Model(agentConfig.model ?? "") && agentConfig.provider === "google") {
11552
+ const providerConfig2 = await resolvePlatformChatProviderConfig({
11553
+ agentConfig,
11554
+ env: deps.env,
11555
+ apiKeyRefResolver,
11556
+ credentialBroker,
11557
+ syncFetcher
11558
+ });
11559
+ const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
11560
+ agentConfig,
11561
+ deps.env,
11562
+ buildProviderOpenAiTools,
11563
+ additionalToolNames,
11564
+ { hasUserChoice: Boolean(deps.requestUserChoice) }
11565
+ );
11566
+ if (tools2.length > 0 && providerConfig2.apiKey && shouldUseGeminiNativeToolRoute(
11567
+ agentConfig.provider ?? "",
11568
+ agentConfig.model ?? "",
11569
+ tools2,
11570
+ () => false
11571
+ // CLI 端不区分 image 模型
11572
+ )) {
11573
+ logLocalRuntimeDiagnostic("provider.selected", {
11574
+ agentKey: agentConfig.key,
11575
+ transport: "gemini-native-tool",
11576
+ apiSource: agentConfig.apiSource ?? null,
11577
+ provider: providerConfig2.provider,
11578
+ model: providerConfig2.model,
11579
+ hasApiKey: Boolean(providerConfig2.apiKey)
11580
+ });
11581
+ return {
11582
+ model: providerConfig2.model,
11583
+ complete: async (messages, options) => {
11584
+ const requestBody = buildGeminiGenerateContentRequest({
11585
+ messages,
11586
+ tools: tools2,
11587
+ maxTokens: typeof agentConfig.max_tokens === "number" ? agentConfig.max_tokens : void 0,
11588
+ temperature: typeof agentConfig.temperature === "number" ? agentConfig.temperature : void 0,
11589
+ attachSkipThoughtSignature: true
11590
+ });
11591
+ const model = providerConfig2.model;
11592
+ const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:streamGenerateContent?alt=sse`;
11593
+ logLocalRuntimeDiagnostic("provider.request.start", {
11594
+ agentKey: agentConfig.key,
11595
+ transport: "gemini-native-tool",
11596
+ model,
11597
+ messageCount: messages.length,
11598
+ toolCount: tools2.length,
11599
+ requestedToolNames: requestedToolNames2
11600
+ });
11601
+ const res = await fetchImpl(url, {
11602
+ method: "POST",
11603
+ headers: {
11604
+ "Content-Type": "application/json",
11605
+ "x-goog-api-key": providerConfig2.apiKey ?? ""
11606
+ },
11607
+ body: JSON.stringify(requestBody),
11608
+ signal: AbortSignal.timeout(12e4)
11609
+ });
11610
+ if (!res.ok) {
11611
+ const errText = await res.text();
11612
+ logLocalRuntimeDiagnostic("provider.request.failed", {
11613
+ agentKey: agentConfig.key,
11614
+ transport: "gemini-native-tool",
11615
+ status: res.status,
11616
+ error: errText.slice(0, 200)
11617
+ });
11618
+ throw new Error(
11619
+ `gemini native tool provider failed: HTTP ${res.status} ${errText.slice(0, 500)}`
11620
+ );
11621
+ }
11622
+ const chunks = await readSseDataValues(res, parseSseDataLineJson);
11623
+ const { text, toolCalls, usage } = accumulateGeminiChunks(chunks);
11624
+ if (text && options?.onTextDelta) {
11625
+ options.onTextDelta(text);
11626
+ }
11627
+ const result = {
11628
+ content: text,
11629
+ model,
11630
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
11631
+ ...usage ? { usage } : {},
11632
+ trace: messages
11633
+ };
11634
+ logLocalRuntimeDiagnostic("provider.request.result", {
11635
+ agentKey: agentConfig.key,
11636
+ transport: "gemini-native-tool",
11637
+ ok: true,
11638
+ contentChars: text.length,
11639
+ toolCallCount: toolCalls.length
11640
+ });
11641
+ return result;
11642
+ }
11643
+ };
11644
+ }
11645
+ }
10280
11646
  if (shouldUsePlatformChatProvider(deps.env, agentConfig)) {
10281
11647
  const providerConfig2 = await resolvePlatformChatProviderConfig({
10282
11648
  agentConfig,
@@ -10337,7 +11703,16 @@ function createCliLocalRuntimeAdapter(deps) {
10337
11703
  },
10338
11704
  {
10339
11705
  sleep: deps.sleep,
10340
- loopbackRequest
11706
+ loopbackRequest,
11707
+ // auto 档位转发 nolo.chat 时,网关层 502(server: Caddy、空 body)
11708
+ // 意味着请求根本没到 Bun 上游,provider 未受理,重试安全。
11709
+ // 与 429/503 同口径:不会重复计费/重复生成。
11710
+ retryableStatuses: /* @__PURE__ */ new Set([429, 502, 503]),
11711
+ onRetry: deps.activityReporter ? ({ attempt, maxAttempts, delayMs }) => {
11712
+ deps.activityReporter(
11713
+ `\u81EA\u52A8\u91CD\u8BD5 ${attempt}/${maxAttempts} \xB7 ${Math.ceil(delayMs / 1e3)}s`
11714
+ );
11715
+ } : void 0
10341
11716
  }
10342
11717
  );
10343
11718
  if (!res.ok) {
@@ -10493,6 +11868,23 @@ function createCliLocalRuntimeAdapter(deps) {
10493
11868
  };
10494
11869
  },
10495
11870
  executeTool: async (call, opts) => {
11871
+ const contextualCall = opts?.runtimeContext ? { ...call, runtimeContext: opts.runtimeContext } : call;
11872
+ let injectedCall = contextualCall;
11873
+ if (contextualCall.name === "startAgentRun" && deps.parentDialogId && typeof contextualCall.arguments === "string") {
11874
+ try {
11875
+ const args = JSON.parse(contextualCall.arguments);
11876
+ if (!args.parentDialogId) {
11877
+ injectedCall = {
11878
+ ...contextualCall,
11879
+ arguments: JSON.stringify({
11880
+ ...args,
11881
+ parentDialogId: deps.parentDialogId
11882
+ })
11883
+ };
11884
+ }
11885
+ } catch {
11886
+ }
11887
+ }
10496
11888
  assertWithinLocalToolBudget({
10497
11889
  toolName: call.name,
10498
11890
  budgets: localToolBudgets,
@@ -10501,7 +11893,7 @@ function createCliLocalRuntimeAdapter(deps) {
10501
11893
  const result = await executeLocalToolWithPolicy({
10502
11894
  env: deps.env,
10503
11895
  agentToolNames: activeAgentToolNames,
10504
- call,
11896
+ call: injectedCall,
10505
11897
  executors: localToolExecutors,
10506
11898
  abortSignal: opts?.abortSignal,
10507
11899
  detachMs: resolveExecShellDetachMs(deps.env),
@@ -10522,6 +11914,8 @@ function createCliLocalRuntimeAdapter(deps) {
10522
11914
  export {
10523
11915
  summarizeEndpoint,
10524
11916
  isBuiltinNoloAgentRef,
11917
+ readTimestamp,
11918
+ parseAgentRunEvent,
10525
11919
  parseCliLocale,
10526
11920
  getCliLocale,
10527
11921
  setCliLocale,
@@ -10529,6 +11923,8 @@ export {
10529
11923
  t,
10530
11924
  toolLabel,
10531
11925
  agentRunCardLabels,
11926
+ QUOTA_ERROR_PATTERNS,
11927
+ isQuotaExhaustedError,
10532
11928
  clearCliLocalRuntimePreparedAgentCache,
10533
11929
  createCliCallAgentToolExecutor,
10534
11930
  createCliLocalRuntimeAdapter