nolo-cli 0.16.0-alpha.2 → 0.16.0-alpha.21

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 (136) hide show
  1. package/{_executeModel-QAUS6B7J.js → _executeModel-GRCQXT5R.js} +51 -45
  2. package/{action-GUOZYYGN.js → action-LT7BRFLK.js} +10 -9
  3. package/{addContentAction-QDGHGUBH.js → addContentAction-PL3KKBDH.js} +9 -8
  4. package/{addDialogAgentAction-Z4YCYZIV.js → addDialogAgentAction-FCMSKYAF.js} +8 -7
  5. package/{agentDeleteCommand-365DMKHW.js → agentDeleteCommand-WNL3CNQX.js} +32 -29
  6. package/{agentEmailCommands-TQMXL36I.js → agentEmailCommands-MPEUMRAS.js} +63 -57
  7. package/{agentListCommands-6B5X4RC6.js → agentListCommands-YO4AOQMS.js} +31 -28
  8. package/{agentMachineCommands-LOEARB6V.js → agentMachineCommands-WYM6YRYJ.js} +30 -27
  9. package/{agentPullCommand-6HWUT3SW.js → agentPullCommand-ZZGU5KOY.js} +4 -4
  10. package/agentRecordCommands-BVWSHMIY.js +105 -0
  11. package/{agentRunCommand-SGMH67WT.js → agentRunCommand-E3ZI6RSF.js} +64 -55
  12. package/{agentRunControl-6ADXVYMR.js → agentRunControl-Y5AFH5PQ.js} +24 -1
  13. package/{agentRuntimeLocal-YSYZ33ER.js → agentRuntimeLocal-P4VGX6H6.js} +26 -25
  14. package/{agentSlice-IVE735EV.js → agentSlice-D33GU3JL.js} +9 -8
  15. package/{appDeleteCommands-6QYOO3JB.js → appDeleteCommands-VA4R2SWX.js} +29 -26
  16. package/{appDeployCommands-WTCT6XO6.js → appDeployCommands-JWMWQNG6.js} +29 -26
  17. package/{appDeployStatusCommands-CGWGZJKB.js → appDeployStatusCommands-KYXGLZSQ.js} +29 -26
  18. package/{appGetCommands-O4OCAMRW.js → appGetCommands-ELOO3JG6.js} +29 -26
  19. package/{appListCommands-UENFP4XY.js → appListCommands-SJUW4RLW.js} +29 -26
  20. package/{authCommand-YFTR3347.js → authCommand-WJZPOLSS.js} +16 -9
  21. package/{authCommands-YXGOXNBZ.js → authCommands-XTBV7OFZ.js} +6 -5
  22. package/{chunk-RKM3K52F.js → chunk-34WPV75U.js} +23 -2
  23. package/{chunk-VPTJB4HM.js → chunk-3ND52WIL.js} +2 -5
  24. package/{chunk-SOTZ6RDN.js → chunk-3Q7WHGCB.js} +1 -1
  25. package/{chunk-KKY4B2Q2.js → chunk-4PWB7JRR.js} +4 -1
  26. package/{chunk-U7LEGLEB.js → chunk-4T5F7YZQ.js} +1 -1
  27. package/{chunk-OQMPU2ML.js → chunk-5PGGCJGV.js} +6 -6
  28. package/chunk-7BUYEZ6U.js +671 -0
  29. package/{chunk-AS3ZQ3O2.js → chunk-7OBMZCRD.js} +1 -1
  30. package/{chunk-WA6KZL5V.js → chunk-AAODAAUQ.js} +23 -20
  31. package/{chunk-GRTFNYLR.js → chunk-AKVLLMOU.js} +3 -3
  32. package/{chunk-QLUFR47U.js → chunk-AL2V7U3E.js} +1 -1
  33. package/{chunk-MTU75CZ2.js → chunk-B5TOXZAK.js} +1 -1
  34. package/{chunk-QZVGMD5F.js → chunk-BE2GNT5E.js} +2 -8
  35. package/{chunk-JKWWVF2I.js → chunk-D3HVJJIA.js} +1 -1
  36. package/{chunk-B4KT7RN2.js → chunk-DKZFOK24.js} +18 -89
  37. package/chunk-DL6EPNIK.js +50 -0
  38. package/{chunk-YYIRR6QC.js → chunk-E5KQTMMJ.js} +212 -250
  39. package/{chunk-4QQFLN5C.js → chunk-EGPCU42M.js} +58 -8
  40. package/{chunk-XVP3C2KY.js → chunk-ELT65PZW.js} +2 -2
  41. package/{chunk-EMXI3N3Z.js → chunk-ENP2ELIL.js} +5 -5
  42. package/{chunk-6565R2TI.js → chunk-EXAEHRLI.js} +112 -191
  43. package/chunk-FQZZLA3C.js +223 -0
  44. package/{chunk-WPN6RMDF.js → chunk-GMZZ5EKJ.js} +3 -3
  45. package/{chunk-RSYUDGGZ.js → chunk-HQNPCMWL.js} +3 -3
  46. package/{chunk-OGGHETUE.js → chunk-HQPG2PIV.js} +62 -19
  47. package/{chunk-4NLUNENX.js → chunk-IQZ6TGVW.js} +10 -3
  48. package/{chunk-VE6XMVKG.js → chunk-J67FKTTY.js} +330 -213
  49. package/{chunk-G2MKOQCB.js → chunk-JFE7XW4D.js} +1 -1
  50. package/{setDialogExtraReferencesAction-2VLGWQKG.js → chunk-JLA4FXYC.js} +2 -17
  51. package/{chunk-OOIN7HSO.js → chunk-JP7REMYP.js} +19 -1
  52. package/chunk-KFEVY3ST.js +255 -0
  53. package/{chunk-I66RU7P7.js → chunk-KKWJ5VPZ.js} +1 -1
  54. package/{chunk-WRN5EQT7.js → chunk-L2RRMXNJ.js} +13 -4
  55. package/{chunk-ISYE6GZB.js → chunk-L6NVTGI7.js} +1 -1
  56. package/{chunk-HRQCKQA5.js → chunk-MUCU6ATG.js} +8 -257
  57. package/{chunk-BFRVXJJJ.js → chunk-MUIT5AAM.js} +112 -27
  58. package/{chunk-WNLPAOIT.js → chunk-MVQ4TBSD.js} +1 -1
  59. package/{chunk-O53CP2QR.js → chunk-N2HYIBLH.js} +6 -6
  60. package/{chunk-524BDL33.js → chunk-O6W2O2DA.js} +1 -15
  61. package/{chunk-YC3DJILJ.js → chunk-PUSK7HXJ.js} +64 -22
  62. package/{chunk-OOSFSFMA.js → chunk-R5V5G73M.js} +2 -0
  63. package/{chunk-4IJYA27C.js → chunk-RG2U2MTJ.js} +1 -1
  64. package/{chunk-Z24FGIU2.js → chunk-RIDWN7AP.js} +34 -15
  65. package/{chunk-IKXL2HZ3.js → chunk-RK5NYQEL.js} +1 -1
  66. package/{chunk-QLFCNUVQ.js → chunk-RUTSBLDM.js} +1629 -261
  67. package/{chunk-TTGAVETO.js → chunk-RVOUXDFU.js} +5 -5
  68. package/{chunk-JTINRTBT.js → chunk-SKDNBYZK.js} +2 -2
  69. package/{chunk-KMQPSTMJ.js → chunk-TRT4I4UD.js} +2 -2
  70. package/{chunk-EHLHSX7R.js → chunk-UB4RYYNQ.js} +9 -2
  71. package/{chunk-N5424GSW.js → chunk-UGUW3FHG.js} +4 -4
  72. package/{chunk-YNHQIXX5.js → chunk-UIOYWBU7.js} +395 -326
  73. package/chunk-V5R4NZP2.js +78 -0
  74. package/{chunk-MYMMNKYL.js → chunk-VNAEBGDK.js} +156 -6
  75. package/{chunk-J55UHASN.js → chunk-VST53WEL.js} +1 -1
  76. package/{chunk-6MHDWKOT.js → chunk-VVKQFITN.js} +25 -12
  77. package/{chunk-W4NVOSFF.js → chunk-WFHXMLHZ.js} +1 -1
  78. package/{chunk-H33743XH.js → chunk-WJRJDX2W.js} +1 -1
  79. package/chunk-X4Q4UZEY.js +26 -0
  80. package/{chunk-E237VE6U.js → chunk-XFYDGBXL.js} +4 -4
  81. package/{chunk-JS33TCQ3.js → chunk-XHG22OEX.js} +4 -4
  82. package/{chunk-DVRHHFEA.js → chunk-XMLRJUU5.js} +1 -1
  83. package/{chunk-V2J635L5.js → chunk-XOIF2TNF.js} +2 -2
  84. package/{chunk-SFXYKGK2.js → chunk-XRZJGPFI.js} +7 -7
  85. package/chunk-ZHXJ6M7T.js +27 -0
  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-TS6NNZ4X.js → createAgentAutomationAction-ONKZ46XE.js} +22 -21
  90. package/{createDialogAction-5HVQ33EX.js → createDialogAction-7QWJEBKU.js} +24 -23
  91. package/{createPageAction-4F3ZGQJD.js → createPageAction-PB3KXZIA.js} +28 -27
  92. package/{dbSlice-OP6UPXKA.js → dbSlice-CGSRFJN3.js} +8 -7
  93. package/{deleteFile-WPWVZE4B.js → deleteFile-WDZ3VM7B.js} +3 -3
  94. package/{dialogCommands-ZL6L24BS.js → dialogCommands-YZFU4Q26.js} +30 -27
  95. package/{dialogSlice-FAWUQDJW.js → dialogSlice-53B5ISGQ.js} +22 -21
  96. package/{docCreateCommands-LYROQTFH.js → docCreateCommands-LOUC5PFB.js} +28 -25
  97. package/{docDeleteCommands-6TWGTZNR.js → docDeleteCommands-HHPGT4BR.js} +29 -26
  98. package/{docReadCommands-PRULNF26.js → docReadCommands-YPSN4HEF.js} +28 -25
  99. package/{docStore-2UHVWLTV.js → docStore-LJXXRB5W.js} +23 -22
  100. package/{docUpdateCommands-NNYYWJBI.js → docUpdateCommands-CJCZO54M.js} +28 -25
  101. package/{fetchMessages-KTNM7QAR.js → fetchMessages-BMGVZVSE.js} +4 -3
  102. package/{getPricing-UGDJHI7M.js → getPricing-RYY6OBA4.js} +4 -4
  103. package/handleSendMessageAction-ICGX4QCM.js +402 -0
  104. package/index.js +68 -68
  105. package/{localDialogRead-2VRI24F4.js → localDialogRead-HQZPVIE3.js} +1 -1
  106. package/{localRuntimeDb-LGDF6FQP.js → localRuntimeDb-THJZGAOJ.js} +1 -1
  107. package/{machineCommands-JQPEQFSE.js → machineCommands-YLDZXK4D.js} +64 -58
  108. package/{machineWsRunDispatch-FFFNWVEW.js → machineWsRunDispatch-LTQL3DRE.js} +56 -50
  109. package/{models-LSCRJJ6P.js → models-5K5G2CZI.js} +2 -2
  110. package/package.json +1 -1
  111. package/queryRunOverlay-O4LOMMPO.js +161 -0
  112. package/{read-HXHAZBKH.js → read-3FMPZPER.js} +3 -3
  113. package/{readDocTool-VPBDTO4G.js → readDocTool-VSYHKK3V.js} +1 -1
  114. package/{readlineWorkspace-QSXHSBHA.js → readlineWorkspace-OSPVWNAT.js} +699 -168
  115. package/{removeDialogAgentAction-HUFVN35S.js → removeDialogAgentAction-OAGA2G3U.js} +11 -10
  116. package/{runAgentClientLoop-A75BUU6D.js → runAgentClientLoop-76SUKKPX.js} +46 -40
  117. package/runOverlayPresentation-ZO4VCWEU.js +11 -0
  118. package/{runtimeDoctorCommands-THIHX2SY.js → runtimeDoctorCommands-E2OUORHK.js} +6 -6
  119. package/setDialogExtraReferencesAction-JZEXA5SL.js +27 -0
  120. package/{setPrimaryDialogAgentAction-VB4UV2CC.js → setPrimaryDialogAgentAction-4ZUQQKDG.js} +27 -18
  121. package/{settingSlice-7JYPQNAC.js → settingSlice-7MNKHZ6R.js} +9 -8
  122. package/{skillDiscovery-6M2BZUFN.js → skillDiscovery-KJWT7JBU.js} +3 -3
  123. package/{spaceCommands-4LE45GB7.js → spaceCommands-GIF7MKVD.js} +31 -28
  124. package/{spaceSlice-444MFUP6.js → spaceSlice-M4PVN5PO.js} +22 -21
  125. package/{streamAgentChatTurn-DJAE7USZ.js → streamAgentChatTurn-GCKTFSHQ.js} +96 -55
  126. package/{tableCommands-3P7MJ3PF.js → tableCommands-BEQAGE4I.js} +1 -1
  127. package/{tools-YB6LXSVN.js → tools-RJVFXOLR.js} +35 -30
  128. package/{tuiSummaryLlmCaller-QQL3JA5I.js → tuiSummaryLlmCaller-VUNVBRX3.js} +7 -6
  129. package/types-ZSTJ7MPR.js +7 -0
  130. package/{updateDialogTitleAction-6HGFBM64.js → updateDialogTitleAction-PSR67DLV.js} +25 -24
  131. package/agentRecordCommands-DCH2WBL2.js +0 -99
  132. package/chunk-BYXBJQAS.js +0 -0
  133. package/handleSendMessageAction-LJPUYNOH.js +0 -215
  134. package/{chunk-O4BU24WZ.js → chunk-6Y7A3OQQ.js} +3 -3
  135. package/{chunk-CMKUBIGW.js → chunk-X7W4TNB4.js} +3 -3
  136. 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-UB4RYYNQ.js";
7
7
  import {
8
8
  buildLocalAgentLookupKeys,
9
- normalizeAgentHandle,
10
9
  shouldReadAgentKeyRemotely
11
- } from "./chunk-QZVGMD5F.js";
10
+ } from "./chunk-BE2GNT5E.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-WNLPAOIT.js";
19
+ } from "./chunk-MVQ4TBSD.js";
21
20
  import {
22
21
  inlineImageUrlsForCustomProvider,
23
22
  prepareTools
24
- } from "./chunk-WRN5EQT7.js";
23
+ } from "./chunk-L2RRMXNJ.js";
25
24
  import {
26
25
  getAntigravityUserAgent,
27
26
  isAntigravityOAuthAgent,
28
27
  readAntigravityProjectId,
29
28
  resolveAntigravityCloudCodeBaseUrl
30
- } from "./chunk-ISYE6GZB.js";
29
+ } from "./chunk-L6NVTGI7.js";
31
30
  import {
32
31
  FORCED_TOOLS,
33
32
  addDefaultLightWebToolsForConfiguredAgents,
@@ -36,18 +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
43
  resolveEffectiveEnabledPacks
50
- } from "./chunk-VE6XMVKG.js";
44
+ } from "./chunk-J67FKTTY.js";
51
45
  import {
52
46
  createDrainExhaustedResponse,
53
47
  isCoreDrainingBody,
@@ -57,15 +51,18 @@ import {
57
51
  import {
58
52
  normalizeDialogTitle
59
53
  } from "./chunk-OWOHNGCN.js";
54
+ import {
55
+ getDefaultCliLocalRuntimeDb
56
+ } from "./chunk-WJRJDX2W.js";
60
57
  import {
61
58
  prepareTokenUsageData
62
- } from "./chunk-YNHQIXX5.js";
59
+ } from "./chunk-UIOYWBU7.js";
63
60
  import {
64
61
  BUILTIN_TITLE_LLM_CONFIG
65
- } from "./chunk-V2J635L5.js";
62
+ } from "./chunk-XOIF2TNF.js";
66
63
  import {
67
64
  fetchServerSyncedCredential
68
- } from "./chunk-OQMPU2ML.js";
65
+ } from "./chunk-5PGGCJGV.js";
69
66
  import {
70
67
  buildAgentRuntimeDialogWritePlan,
71
68
  buildLocalWorkspaceOpenAiTools,
@@ -76,37 +73,39 @@ import {
76
73
  executeLocalToolWithPolicy,
77
74
  executeOpenAiCompatibleChatCompletion,
78
75
  parseSseDataLineJson,
76
+ parseSseDataLineObject,
79
77
  readOpenAiCompatibleSseCompletion,
80
78
  resolveOpenAiCompatibleProviderConfig
81
- } from "./chunk-YC3DJILJ.js";
79
+ } from "./chunk-PUSK7HXJ.js";
82
80
  import {
83
81
  buildPlatformChatCompletionRequest,
84
82
  canUsePlatformChatProvider,
85
83
  parsePlatformChatCompletionData,
86
84
  parsePlatformChatCompletionResponse,
87
85
  readSseDataValues,
88
- resolveLegacyDeepSeekProxyChatFallback,
89
86
  resolvePlatformChatProviderConfig,
90
87
  shouldUsePlatformChatProvider
91
- } from "./chunk-WA6KZL5V.js";
88
+ } from "./chunk-AAODAAUQ.js";
92
89
  import {
93
90
  resolveAgentRuntimeConfigFromRecord
94
91
  } from "./chunk-OIQPORYI.js";
95
92
  import {
96
- parseToolArgumentsJson,
97
93
  summarizeToolArguments
98
- } from "./chunk-6MHDWKOT.js";
94
+ } from "./chunk-VVKQFITN.js";
95
+ import {
96
+ convertMessagesToResponsesInput,
97
+ toResponsesTools
98
+ } from "./chunk-KFEVY3ST.js";
99
99
  import {
100
100
  resolvePlatformAuthToken
101
- } from "./chunk-HRQCKQA5.js";
101
+ } from "./chunk-MUCU6ATG.js";
102
102
  import {
103
103
  buildLoadSkillExecutor,
104
104
  buildNoloWorkspaceCliToolExecutors,
105
105
  buildNoloWorkspaceOpenAiTools,
106
- canonicalizeToolNames,
107
106
  parseNoloWorkspaceToolArguments,
108
107
  resolveRuntimeToolSurfaceForAgent
109
- } from "./chunk-B4KT7RN2.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-HQPG2PIV.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,28 +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
- PUBLIC_KIMI_K26_IMAGE_AGENT_KEY,
175
- PUBLIC_KIMI_K27_CODING_AGENT_KEY
176
- } from "./chunk-VPTJB4HM.js";
189
+ PUBLIC_KIMI_K26_IMAGE_AGENT_KEY
190
+ } from "./chunk-3ND52WIL.js";
177
191
  import {
178
192
  asTrimmedString
179
193
  } from "./chunk-3EUW3WEO.js";
@@ -263,6 +277,10 @@ var STRINGS = {
263
277
  en: "Cleared current dialog messages.",
264
278
  zh: "\u5DF2\u6E05\u9664\u5F53\u524D\u5BF9\u8BDD\u6D88\u606F\u3002"
265
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
+ },
266
284
  clearNoDialog: {
267
285
  en: "No current dialog messages to clear.",
268
286
  zh: "\u5F53\u524D\u6CA1\u6709\u53EF\u6E05\u9664\u7684\u5BF9\u8BDD\u6D88\u606F\u3002"
@@ -463,6 +481,10 @@ var STRINGS = {
463
481
  en: "Run stopped",
464
482
  zh: "\u8FD0\u884C\u5DF2\u505C\u6B62"
465
483
  },
484
+ runFinishedLabel: {
485
+ en: "Run finished",
486
+ zh: "\u8FD0\u884C\u5DF2\u7ED3\u675F"
487
+ },
466
488
  runLogTailLabel: {
467
489
  en: "Log tail:",
468
490
  zh: "\u65E5\u5FD7\u5C3E\u90E8\uFF1A"
@@ -497,6 +519,10 @@ var STRINGS = {
497
519
  en: "selected",
498
520
  zh: "\u5DF2\u9009"
499
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
+ },
500
526
  dialogConfirmHint: {
501
527
  en: "(\u2191\u2193 move \xB7 Enter choose \xB7 Esc cancel)",
502
528
  zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
@@ -537,7 +563,7 @@ var STRINGS = {
537
563
  en: "abort the operation",
538
564
  zh: "\u4E2D\u6B62\u64CD\u4F5C"
539
565
  },
540
- // --- Ask choice (ui_ask_choice) ------------------------------------------
566
+ // --- Ask choice (ask_user) ------------------------------------------
541
567
  askChoiceTitle: {
542
568
  en: "question",
543
569
  zh: "\u95EE\u9898"
@@ -928,11 +954,191 @@ function agentRunCardLabels() {
928
954
  runStatus: t("runStatusLabel"),
929
955
  runStarted: t("runStartedLabel"),
930
956
  runStopped: t("runStoppedLabel"),
957
+ runFinished: t("runFinishedLabel"),
931
958
  logTail: t("runLogTailLabel"),
932
959
  runs: (count) => t("runsListLabel", String(count))
933
960
  };
934
961
  }
935
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
+
936
1142
  // packages/cli/client/localRuntimeDiagnostics.ts
937
1143
  import { ulid } from "ulid";
938
1144
  var preparedAgentRuntimeCache = /* @__PURE__ */ new Map();
@@ -972,7 +1178,7 @@ function summarizeOpenAiToolNames(tools) {
972
1178
  }
973
1179
 
974
1180
  // packages/cli/client/localRuntimeAdapter.ts
975
- import { dirname, extname, join } from "node:path";
1181
+ import { dirname as dirname2, extname, join as join2 } from "node:path";
976
1182
  import { fileURLToPath } from "node:url";
977
1183
 
978
1184
  // packages/core/summarizeEndpoint.ts
@@ -1123,6 +1329,11 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
1123
1329
  const attemptBudget = coreDraining ? coreDrainingMaxAttempts : maxAttempts;
1124
1330
  if (attempt < attemptBudget) {
1125
1331
  const delayMs = await resolveRetryAfterMs(response, attempt);
1332
+ options.onRetry?.({
1333
+ attempt: attempt + 1,
1334
+ maxAttempts: attemptBudget,
1335
+ delayMs
1336
+ });
1126
1337
  await (options.sleep ?? defaultSleep)(delayMs);
1127
1338
  continue;
1128
1339
  }
@@ -1136,7 +1347,13 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
1136
1347
  if (!isTransientFetchError(error)) throw error;
1137
1348
  lastError = error;
1138
1349
  if (attempt < maxAttempts) {
1139
- 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);
1140
1357
  }
1141
1358
  }
1142
1359
  }
@@ -1466,14 +1683,14 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
1466
1683
  [PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY]: {
1467
1684
  key: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
1468
1685
  name: "DeepSeek V4 Pro",
1469
- provider: "deepseek",
1686
+ provider: "nolo",
1470
1687
  model: "deepseek-v4-pro",
1471
1688
  apiSource: "platform",
1472
1689
  useServerProxy: true,
1473
1690
  rawRecord: {
1474
1691
  dbKey: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
1475
1692
  isPublic: true,
1476
- provider: "deepseek",
1693
+ provider: "nolo",
1477
1694
  model: "deepseek-v4-pro",
1478
1695
  apiSource: "platform",
1479
1696
  useServerProxy: true
@@ -1511,22 +1728,6 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
1511
1728
  useServerProxy: true
1512
1729
  }
1513
1730
  },
1514
- [PUBLIC_KIMI_K27_CODING_AGENT_KEY]: {
1515
- key: PUBLIC_KIMI_K27_CODING_AGENT_KEY,
1516
- name: "Kimi K2.7 Coding",
1517
- provider: "nolo",
1518
- model: "kimi-k2.7-code",
1519
- apiSource: "platform",
1520
- useServerProxy: true,
1521
- rawRecord: {
1522
- dbKey: PUBLIC_KIMI_K27_CODING_AGENT_KEY,
1523
- isPublic: true,
1524
- provider: "nolo",
1525
- model: "kimi-k2.7-code",
1526
- apiSource: "platform",
1527
- useServerProxy: true
1528
- }
1529
- },
1530
1731
  [BUILTIN_NOLO_AGENT_KEY]: {
1531
1732
  key: BUILTIN_NOLO_AGENT_KEY,
1532
1733
  name: "Nolo",
@@ -1599,23 +1800,6 @@ async function readAgentFromStore(args) {
1599
1800
  if (!record || typeof record !== "object") continue;
1600
1801
  return resolveAgentRuntimeConfigFromRecord(key, record);
1601
1802
  }
1602
- const normalizedRef = normalizeAgentHandle(args.agentRef);
1603
- if (!normalizedRef) {
1604
- return resolveBuiltinPlatformAgentConfig(args.agentRef);
1605
- }
1606
- try {
1607
- const iterator = args.store.iterator({
1608
- gte: "agent-",
1609
- lte: "agent-\uFFFF"
1610
- });
1611
- for await (const [key, record] of iterator) {
1612
- if (!record || typeof record !== "object") continue;
1613
- const handle = normalizeAgentHandle(record.handle);
1614
- if (handle !== normalizedRef) continue;
1615
- return resolveAgentRuntimeConfigFromRecord(key, record);
1616
- }
1617
- } catch {
1618
- }
1619
1803
  return resolveBuiltinPlatformAgentConfig(args.agentRef);
1620
1804
  }
1621
1805
  async function readDialogMessages(args) {
@@ -1774,7 +1958,10 @@ var LOCAL_SERVER_WEB_TOOL_NAMES = ["fetchWebpage", "exa_search"];
1774
1958
  var LOCAL_SERVER_WEB_TOOL_NAME_SET = new Set(
1775
1959
  LOCAL_SERVER_WEB_TOOL_NAMES
1776
1960
  );
1777
- var LOCAL_SERVER_MEMORY_TOOL_NAMES = ["rememberMemory"];
1961
+ var LOCAL_SERVER_MEMORY_TOOL_NAMES = [
1962
+ "queryMemory",
1963
+ "rememberMemory"
1964
+ ];
1778
1965
  var LOCAL_SERVER_MEMORY_TOOL_NAME_SET = new Set(
1779
1966
  LOCAL_SERVER_MEMORY_TOOL_NAMES
1780
1967
  );
@@ -2006,6 +2193,25 @@ function buildServerPlatformToolExecutors(args) {
2006
2193
  }
2007
2194
  ])
2008
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
+ };
2009
2215
  const rememberMemory = async (call) => {
2010
2216
  const parsed = parseNoloWorkspaceToolArguments(call.arguments);
2011
2217
  const content = typeof parsed.content === "string" ? parsed.content.trim() : "";
@@ -2032,11 +2238,368 @@ function buildServerPlatformToolExecutors(args) {
2032
2238
  metadata: { serverPlatformTool: true, memoryWrite: true }
2033
2239
  };
2034
2240
  };
2035
- 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
+ };
2036
2600
  }
2037
2601
 
2038
2602
  // packages/cli/client/cliAgentRunToolExecutors.ts
2039
- import { existsSync, readFileSync } from "node:fs";
2040
2603
  var noopOutput = { write: () => {
2041
2604
  } };
2042
2605
  var parseCallArgs = (call) => {
@@ -2046,7 +2609,7 @@ var parseCallArgs = (call) => {
2046
2609
  return {};
2047
2610
  }
2048
2611
  };
2049
- var resolveFs = (deps) => deps.fs ?? { existsSync, readFileSync };
2612
+ var resolveFs = (deps) => deps.fs ?? { existsSync: existsSync2, readFileSync: readFileSync2 };
2050
2613
  var tailFile = (logPath, tailLines, fs) => {
2051
2614
  if (!fs.existsSync(logPath)) return void 0;
2052
2615
  try {
@@ -2058,6 +2621,27 @@ var tailFile = (logPath, tailLines, fs) => {
2058
2621
  return void 0;
2059
2622
  }
2060
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
+ }
2061
2645
  function createCliStartAgentRunExecutor(deps = {}) {
2062
2646
  return async (call) => {
2063
2647
  const args = parseCallArgs(call);
@@ -2065,35 +2649,105 @@ function createCliStartAgentRunExecutor(deps = {}) {
2065
2649
  const task = typeof args.task === "string" ? args.task.trim() : "";
2066
2650
  if (!agentKey) throw new Error("startAgentRun: \u7F3A\u5C11 agentKey \u53C2\u6570\u3002");
2067
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
+ }
2068
2675
  const message = typeof args.input === "undefined" ? task : `${task}
2069
2676
 
2070
2677
  --- \u9644\u52A0\u8F93\u5165 ---
2071
2678
  ${JSON.stringify(args.input)}`;
2072
- const rawArgs = ["--agent", agentKey, "--msg-file", "PLACEHOLDER", "--bg"];
2679
+ const rawArgs = [
2680
+ "--agent",
2681
+ agentKey,
2682
+ "--msg-file",
2683
+ "PLACEHOLDER",
2684
+ "--bg",
2685
+ // 非持久化派发(review 等一次性任务):透传 --ephemeral,run 完成后不留
2686
+ // dialog 记录。与 web 端 runAgentBackground 的 ephemeral: true 对齐。
2687
+ ...args.ephemeral === true ? ["--ephemeral"] : []
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
2084
2703
  },
2085
2704
  deps
2086
2705
  );
2087
- const displayName = agentName ?? "agent";
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
  }
@@ -2139,9 +2870,28 @@ function createCliControlAgentRunExecutor(deps = {}) {
2139
2870
  if (action === "status") {
2140
2871
  const reconciled = checkStaleRun(record.runId, deps) ?? record;
2141
2872
  const logTail = tailLines > 0 ? tailFile(record.logPath, tailLines, resolveFs(deps)) : void 0;
2142
- const name = reconciled.agentName || "agent";
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,6 +3390,97 @@ function convertOpenAiTools(tools) {
2586
3390
  if (declarations.length === 0) return void 0;
2587
3391
  return [{ functionDeclarations: declarations }];
2588
3392
  }
3393
+ function accumulateGeminiChunks(chunks) {
3394
+ let text = "";
3395
+ const toolCalls = [];
3396
+ let usage;
3397
+ let pendingThoughtSignature;
3398
+ for (const chunk of chunks) {
3399
+ if (!chunk || typeof chunk !== "object") continue;
3400
+ const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
3401
+ if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
3402
+ const meta = response.usageMetadata;
3403
+ const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
3404
+ const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
3405
+ const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
3406
+ usage = {
3407
+ prompt_tokens: prompt,
3408
+ completion_tokens: candidates2,
3409
+ total_tokens: total
3410
+ };
3411
+ }
3412
+ const candidates = Array.isArray(response.candidates) ? response.candidates : [];
3413
+ for (const candidate of candidates) {
3414
+ if (!candidate || typeof candidate !== "object") continue;
3415
+ const parts = Array.isArray(
3416
+ candidate.content?.parts
3417
+ ) ? candidate.content.parts : [];
3418
+ for (const part of parts) {
3419
+ if (!part || typeof part !== "object") continue;
3420
+ const partSignature = part.thoughtSignature;
3421
+ if ("text" in part && typeof part.text === "string") {
3422
+ const piece = part.text;
3423
+ if (!part.thought) {
3424
+ text += piece;
3425
+ }
3426
+ }
3427
+ if (part.thought && typeof partSignature === "string" && partSignature) {
3428
+ pendingThoughtSignature = partSignature;
3429
+ }
3430
+ if ("functionCall" in part && part.functionCall) {
3431
+ const call = part.functionCall;
3432
+ const name = typeof call.name === "string" ? call.name : "tool";
3433
+ const id = typeof call.id === "string" ? call.id : `${name}_${toolCalls.length}`;
3434
+ const argsObj = call.args && typeof call.args === "object" ? call.args : {};
3435
+ const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : pendingThoughtSignature;
3436
+ pendingThoughtSignature = void 0;
3437
+ toolCalls.push({
3438
+ id,
3439
+ type: "function",
3440
+ function: { name, arguments: JSON.stringify(argsObj) },
3441
+ ...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
3442
+ });
3443
+ }
3444
+ }
3445
+ }
3446
+ }
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";
2589
3484
  function buildCloudCodeAssistPayload(args) {
2590
3485
  const projectId = readAntigravityProjectId(args.metadata);
2591
3486
  if (!projectId) {
@@ -2596,8 +3491,9 @@ function buildCloudCodeAssistPayload(args) {
2596
3491
  const logicalModel = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gemini-3.1-pro";
2597
3492
  const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
2598
3493
  const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
2599
- const { contents, systemTexts } = convertOpenAiMessagesToCca(rawMessages, {
2600
- attachSkipThoughtSignature: isGemini3WireModel(model)
3494
+ const isClaude = model.toLowerCase().includes("claude");
3495
+ const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
3496
+ attachSkipThoughtSignature: isGemini3Model(model)
2601
3497
  });
2602
3498
  if (contents.length === 0) {
2603
3499
  throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
@@ -2611,7 +3507,7 @@ function buildCloudCodeAssistPayload(args) {
2611
3507
  parts: systemTexts.map((text) => ({ text }))
2612
3508
  };
2613
3509
  }
2614
- const tools = convertOpenAiTools(
3510
+ const tools = convertOpenAiToolsToGemini(
2615
3511
  Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
2616
3512
  );
2617
3513
  if (tools) {
@@ -2631,83 +3527,31 @@ function buildCloudCodeAssistPayload(args) {
2631
3527
  request.generationConfig = generationConfig;
2632
3528
  }
2633
3529
  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) {
2662
- let text = "";
2663
- const toolCalls = [];
2664
- let usage;
2665
- for (const chunk of chunks) {
2666
- if (!chunk || typeof chunk !== "object") continue;
2667
- const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
2668
- if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
2669
- const meta = response.usageMetadata;
2670
- const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
2671
- const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
2672
- const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
2673
- usage = {
2674
- prompt_tokens: prompt,
2675
- completion_tokens: candidates2,
2676
- total_tokens: total
2677
- };
2678
- }
2679
- const candidates = Array.isArray(response.candidates) ? response.candidates : [];
2680
- for (const candidate of candidates) {
2681
- if (!candidate || typeof candidate !== "object" || !("content" in candidate)) continue;
2682
- const content = candidate.content;
2683
- if (!content || typeof content !== "object" || !("parts" in content)) continue;
2684
- const parts = content.parts;
2685
- if (!Array.isArray(parts)) continue;
2686
- for (const part of parts) {
2687
- if (!part || typeof part !== "object") continue;
2688
- const partSignature = part.thoughtSignature;
2689
- if ("text" in part && typeof part.text === "string") {
2690
- const piece = part.text;
2691
- if (!part.thought) {
2692
- text += piece;
2693
- }
2694
- }
2695
- if ("functionCall" in part && part.functionCall) {
2696
- const call = part.functionCall;
2697
- const name = typeof call.name === "string" ? call.name : "tool";
2698
- const id = typeof call.id === "string" ? call.id : `${name}_${toolCalls.length}`;
2699
- const argsObj = asRecordOrEmpty(call.args);
2700
- toolCalls.push({
2701
- id,
2702
- type: "function",
2703
- function: { name, arguments: JSON.stringify(argsObj) },
2704
- ...typeof partSignature === "string" && partSignature ? { thought_signature: partSignature } : {}
2705
- });
2706
- }
2707
- }
2708
- }
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;
2709
3541
  }
2710
- return { text, toolCalls, usage };
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
+ };
2711
3555
  }
2712
3556
  async function readSseJsonChunks(response) {
2713
3557
  return readSseDataValues(response, parseSseDataLineJson);
@@ -2733,7 +3577,7 @@ async function fetchAntigravityCloudCodeCompletion(args) {
2733
3577
  };
2734
3578
  }
2735
3579
  const chunks = await readSseJsonChunks(response);
2736
- const { text, toolCalls, usage } = accumulateCcaChunks(chunks);
3580
+ const { text, toolCalls, usage } = accumulateGeminiChunks(chunks);
2737
3581
  const message = {
2738
3582
  role: "assistant",
2739
3583
  content: text || null
@@ -2769,28 +3613,94 @@ var CLAUDE_CODE_IDENTITY_PATTERNS = [
2769
3613
  CLAUDE_CODE_SYSTEM_INSTRUCTION,
2770
3614
  "You are Claude Code"
2771
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
+ }
2772
3669
  function stringValue(value) {
2773
3670
  return typeof value === "string" && value.length > 0 ? value : void 0;
2774
3671
  }
3672
+ function isCacheControl(value) {
3673
+ return Boolean(
3674
+ value && typeof value === "object" && !Array.isArray(value) && typeof value.type === "string"
3675
+ );
3676
+ }
2775
3677
  function toAnthropicContent(content) {
2776
- if (typeof content === "string") return [{ type: "text", text: content }];
3678
+ if (typeof content === "string") {
3679
+ return content.length > 0 ? [{ type: "text", text: content }] : [];
3680
+ }
2777
3681
  if (!Array.isArray(content)) return [];
2778
3682
  const blocks = [];
2779
3683
  for (const raw of content) {
2780
3684
  if (!raw || typeof raw !== "object") continue;
2781
3685
  const part = raw;
2782
3686
  if ((part.type === "text" || part.type === "input_text") && typeof part.text === "string") {
2783
- 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
+ }
2784
3692
  continue;
2785
3693
  }
2786
3694
  if (part.type !== "image_url") continue;
2787
3695
  const imageUrl = typeof part.image_url === "string" ? part.image_url : stringValue(part.image_url?.url);
2788
3696
  if (!imageUrl) continue;
2789
3697
  const dataMatch = imageUrl.match(/^data:([^;,]+);base64,(.+)$/s);
2790
- blocks.push({
3698
+ const block = {
2791
3699
  type: "image",
2792
3700
  source: dataMatch ? { type: "base64", media_type: dataMatch[1], data: dataMatch[2] } : { type: "url", url: imageUrl }
2793
- });
3701
+ };
3702
+ if (isCacheControl(part.cache_control)) block.cache_control = part.cache_control;
3703
+ blocks.push(block);
2794
3704
  }
2795
3705
  return blocks;
2796
3706
  }
@@ -2824,7 +3734,15 @@ function buildAnthropicMessagesBody(args) {
2824
3734
  const message = raw;
2825
3735
  const role = String(message.role ?? "");
2826
3736
  if (role === "system" || role === "developer") {
2827
- 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
+ }
2828
3746
  continue;
2829
3747
  }
2830
3748
  if (role === "tool") {
@@ -2866,6 +3784,9 @@ function buildAnthropicMessagesBody(args) {
2866
3784
  if (!hasClaudeCodeIdentity(system)) {
2867
3785
  system.unshift({ type: "text", text: CLAUDE_CODE_SYSTEM_INSTRUCTION });
2868
3786
  }
3787
+ if (system.length > 0 && !system.some((block) => isCacheControl(block.cache_control))) {
3788
+ system[system.length - 1].cache_control = { type: "ephemeral" };
3789
+ }
2869
3790
  const tools = Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools.flatMap((raw) => {
2870
3791
  if (!raw || typeof raw !== "object") return [];
2871
3792
  const fn = raw.function;
@@ -2880,14 +3801,39 @@ function buildAnthropicMessagesBody(args) {
2880
3801
  const model = stringValue(args.openAiBody.model) ?? args.agentConfig.model ?? "claude-sonnet-5";
2881
3802
  const maxTokensRaw = args.openAiBody.max_completion_tokens ?? args.openAiBody.max_tokens ?? args.agentConfig.max_tokens;
2882
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
+ }
2883
3827
  return {
2884
3828
  model,
2885
3829
  messages,
2886
- max_tokens: maxTokens,
3830
+ max_tokens: finalMaxTokens,
2887
3831
  stream: false,
3832
+ ...thinkingBlock ? { thinking: thinkingBlock } : {},
3833
+ ...outputConfig ? { output_config: outputConfig } : {},
2888
3834
  ...system.length > 0 ? { system } : {},
2889
3835
  ...tools.length > 0 ? { tools } : {},
2890
- ...typeof args.openAiBody.temperature === "number" ? { temperature: args.openAiBody.temperature } : typeof args.agentConfig.temperature === "number" ? { temperature: args.agentConfig.temperature } : {},
3836
+ ...typeof finalTemperature === "number" ? { temperature: finalTemperature } : {},
2891
3837
  ...typeof args.openAiBody.top_p === "number" ? { top_p: args.openAiBody.top_p } : {}
2892
3838
  };
2893
3839
  }
@@ -2911,6 +3857,8 @@ function mapAnthropicMessageToOpenAi(payload) {
2911
3857
  }
2912
3858
  const usage = payload.usage ?? {};
2913
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;
2914
3862
  const outputTokens = typeof usage.output_tokens === "number" ? usage.output_tokens : 0;
2915
3863
  const stopReason = String(payload.stop_reason ?? "");
2916
3864
  const message = { role: "assistant", content: text || null };
@@ -2926,9 +3874,16 @@ function mapAnthropicMessageToOpenAi(payload) {
2926
3874
  finish_reason: toolCalls.length > 0 || stopReason === "tool_use" ? "tool_calls" : stopReason === "max_tokens" ? "length" : "stop"
2927
3875
  }],
2928
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.
2929
3880
  prompt_tokens: inputTokens,
3881
+ input_tokens: inputTokens,
2930
3882
  completion_tokens: outputTokens,
2931
- 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
2932
3887
  }
2933
3888
  };
2934
3889
  }
@@ -9003,6 +9958,262 @@ function isCursorOAuthAgent(agent) {
9003
9958
  return agent.apiKeyRef?.trim().toLowerCase() === "cursor";
9004
9959
  }
9005
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
+
9006
10217
  // packages/agent-runtime/oauthProviders.ts
9007
10218
  var XAI_ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1e3;
9008
10219
  var decodeBase64 = (s) => Buffer.from(s, "base64").toString("utf8");
@@ -9496,7 +10707,7 @@ function buildOpenAiTools(args) {
9496
10707
  const toolset = buildLocalWorkspaceToolsetForEnv(args);
9497
10708
  const toolNameSet = new Set(args.toolNames ?? []);
9498
10709
  const callAgentTools = toolNameSet.has("callAgent") ? prepareTools(["callAgent"]) : [];
9499
- const uiAskChoiceTools = toolNameSet.has("ui_ask_choice") ? prepareTools(["ui_ask_choice"]) : [];
10710
+ const uiAskChoiceTools = toolNameSet.has("ask_user") ? prepareTools(["ask_user"]) : [];
9500
10711
  const readPastedTextTools = toolNameSet.has("readPastedText") ? [
9501
10712
  {
9502
10713
  type: "function",
@@ -9556,10 +10767,10 @@ function buildOpenAiTools(args) {
9556
10767
  var CLI_DEFAULT_TOOLS = ["exa_search", "fetchWebpage"];
9557
10768
  function addDefaultCliCoreTools(toolNames, env, options) {
9558
10769
  const declaredOnly = env && shouldUseDeclaredOnlyLocalWorkspaceTools(env);
9559
- 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");
9560
10771
  const injected = declaredOnly ? [...forcedTools] : [...forcedTools, ...CLI_DEFAULT_TOOLS];
9561
10772
  const combined = [...toolNames, ...injected];
9562
- 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");
9563
10774
  return [...new Set(filtered)];
9564
10775
  }
9565
10776
  function resolveCliEffectiveEnabledPacks(args) {
@@ -9852,9 +11063,9 @@ function createCliCallAgentToolExecutor(deps, ctx) {
9852
11063
  // packages/cli/client/localRuntimeAdapter.ts
9853
11064
  var currentMetaFile = fileURLToPath(import.meta.url);
9854
11065
  var isJsBundle = extname(currentMetaFile) === ".js";
9855
- var SOURCE_CLI_DIR = isJsBundle ? dirname(currentMetaFile) : dirname(dirname(currentMetaFile));
9856
- var CLI_DIR = isCompiledBinary() ? dirname(process.execPath) : SOURCE_CLI_DIR;
9857
- 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");
9858
11069
  function createCliLocalRuntimeAdapter(deps) {
9859
11070
  const now = deps.now ?? Date.now;
9860
11071
  const createId = deps.createId ?? createFallbackId;
@@ -10200,6 +11411,74 @@ function createCliLocalRuntimeAdapter(deps) {
10200
11411
  }
10201
11412
  };
10202
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
+ }
10203
11482
  if (isCursorOAuthAgent(agentConfig)) {
10204
11483
  const accessToken = await apiKeyRefResolver("cursor");
10205
11484
  if (!accessToken) {
@@ -10269,6 +11548,101 @@ function createCliLocalRuntimeAdapter(deps) {
10269
11548
  }
10270
11549
  };
10271
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
+ }
10272
11646
  if (shouldUsePlatformChatProvider(deps.env, agentConfig)) {
10273
11647
  const providerConfig2 = await resolvePlatformChatProviderConfig({
10274
11648
  agentConfig,
@@ -10329,47 +11703,20 @@ function createCliLocalRuntimeAdapter(deps) {
10329
11703
  },
10330
11704
  {
10331
11705
  sleep: deps.sleep,
10332
- 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
10333
11716
  }
10334
11717
  );
10335
- let responseProviderConfig = providerConfig2;
10336
- let firstErrorRaw;
10337
11718
  if (!res.ok) {
10338
- firstErrorRaw = await res.text().catch(() => "");
10339
- const fallbackProviderConfig = resolveLegacyDeepSeekProxyChatFallback({
10340
- providerConfig: providerConfig2,
10341
- status: res.status,
10342
- raw: firstErrorRaw
10343
- });
10344
- if (fallbackProviderConfig) {
10345
- responseProviderConfig = fallbackProviderConfig;
10346
- const fallbackRequest = buildPlatformChatCompletionRequest({
10347
- providerConfig: fallbackProviderConfig,
10348
- messages,
10349
- tools: tools2,
10350
- stream: false
10351
- });
10352
- logLocalRuntimeDiagnostic("provider.request.compatibility-fallback", {
10353
- agentKey: agentConfig.key,
10354
- provider: providerConfig2.provider,
10355
- fromEndpoint: summarizeEndpoint(providerConfig2.endpoint) ?? null,
10356
- toEndpoint: summarizeEndpoint(fallbackProviderConfig.endpoint) ?? null,
10357
- reason: "legacy-proxy-responses-schema"
10358
- });
10359
- res = await fetchWithTransientRetry(
10360
- fetchImpl,
10361
- fallbackRequest.url,
10362
- { ...fallbackRequest.init },
10363
- {
10364
- sleep: deps.sleep,
10365
- loopbackRequest
10366
- }
10367
- );
10368
- firstErrorRaw = void 0;
10369
- }
10370
- }
10371
- if (!res.ok) {
10372
- const raw2 = firstErrorRaw ?? await res.text().catch(() => "");
11719
+ const raw2 = await res.text().catch(() => "");
10373
11720
  const data2 = parsePlatformChatCompletionData(raw2);
10374
11721
  const rawPreview = raw2.length > 200 ? `${raw2.slice(0, 200)}\u2026(${raw2.length}b)` : raw2;
10375
11722
  const gatewayHeaders = [
@@ -10420,7 +11767,7 @@ function createCliLocalRuntimeAdapter(deps) {
10420
11767
  });
10421
11768
  const data = parsePlatformChatCompletionData(raw);
10422
11769
  return parsePlatformChatCompletionResponse({
10423
- providerConfig: responseProviderConfig,
11770
+ providerConfig: providerConfig2,
10424
11771
  data,
10425
11772
  trace: messages
10426
11773
  });
@@ -10521,6 +11868,23 @@ function createCliLocalRuntimeAdapter(deps) {
10521
11868
  };
10522
11869
  },
10523
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
+ }
10524
11888
  assertWithinLocalToolBudget({
10525
11889
  toolName: call.name,
10526
11890
  budgets: localToolBudgets,
@@ -10529,7 +11893,7 @@ function createCliLocalRuntimeAdapter(deps) {
10529
11893
  const result = await executeLocalToolWithPolicy({
10530
11894
  env: deps.env,
10531
11895
  agentToolNames: activeAgentToolNames,
10532
- call,
11896
+ call: injectedCall,
10533
11897
  executors: localToolExecutors,
10534
11898
  abortSignal: opts?.abortSignal,
10535
11899
  detachMs: resolveExecShellDetachMs(deps.env),
@@ -10550,6 +11914,8 @@ function createCliLocalRuntimeAdapter(deps) {
10550
11914
  export {
10551
11915
  summarizeEndpoint,
10552
11916
  isBuiltinNoloAgentRef,
11917
+ readTimestamp,
11918
+ parseAgentRunEvent,
10553
11919
  parseCliLocale,
10554
11920
  getCliLocale,
10555
11921
  setCliLocale,
@@ -10557,6 +11923,8 @@ export {
10557
11923
  t,
10558
11924
  toolLabel,
10559
11925
  agentRunCardLabels,
11926
+ QUOTA_ERROR_PATTERNS,
11927
+ isQuotaExhaustedError,
10560
11928
  clearCliLocalRuntimePreparedAgentCache,
10561
11929
  createCliCallAgentToolExecutor,
10562
11930
  createCliLocalRuntimeAdapter