nolo-cli 0.54.0 → 0.61.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/README.md +3 -3
  2. package/{_executeModel-OPTKYHJA.js → _executeModel-R26QYY66.js} +50 -46
  3. package/{action-ORXWW2ZG.js → action-76JX3JX3.js} +7 -6
  4. package/{addContentAction-53BZ34AE.js → addContentAction-V3NAZRTJ.js} +6 -5
  5. package/{addDialogAgentAction-JRYUS54Y.js → addDialogAgentAction-RZOAF46K.js} +5 -4
  6. package/{agentDeleteCommand-FJIWU2BS.js → agentDeleteCommand-6GNQA4J4.js} +30 -27
  7. package/{agentEmailCommands-CE32L43B.js → agentEmailCommands-HH67CYKD.js} +61 -57
  8. package/{agentGrantCommands-2LEZDADN.js → agentGrantCommands-R3VQEZJR.js} +1 -1
  9. package/{agentListCommands-VJNKULIK.js → agentListCommands-23XW3OPZ.js} +61 -31
  10. package/{agentMachineCommands-HCJ3WQXL.js → agentMachineCommands-HXHASEWO.js} +31 -28
  11. package/{agentPullCommand-M552CYSI.js → agentPullCommand-N7L2CT7L.js} +2 -2
  12. package/{agentRecordCommands-QFWERED4.js → agentRecordCommands-UHTQJVGC.js} +59 -55
  13. package/{agentRunCommand-G3GQMUNN.js → agentRunCommand-OAMT77EX.js} +63 -59
  14. package/{agentRunControl-INKFDXDA.js → agentRunControl-WECMOO6O.js} +11 -6
  15. package/{agentRuntimeLocal-K327ELSL.js → agentRuntimeLocal-QBK4H3T2.js} +26 -23
  16. package/{agentSlice-ODKF4J6M.js → agentSlice-7XJH5WQF.js} +8 -7
  17. package/{appDeleteCommands-XUXMFDI4.js → appDeleteCommands-AX2O6VDV.js} +30 -27
  18. package/{appDeployCommands-37F4GPCU.js → appDeployCommands-L5ZR26CB.js} +30 -27
  19. package/{appDeployStatusCommands-WSPU7TUK.js → appDeployStatusCommands-5HQHELRA.js} +30 -27
  20. package/{appGetCommands-YLOBA3EM.js → appGetCommands-HVSYOS57.js} +30 -27
  21. package/{appListCommands-UD62R5ME.js → appListCommands-XV2FPTWX.js} +30 -27
  22. package/{authCommand-OK6HLHGS.js → authCommand-WOTWLJNF.js} +35 -29
  23. package/{authCommands-2DUIUEMT.js → authCommands-ILTBI6JV.js} +7 -5
  24. package/{chatQueueReduxAdapter-TV2TUOQS.js → chatQueueReduxAdapter-F3R253JE.js} +20 -18
  25. package/{chunk-HPW5MNDQ.js → chunk-22BTGNSP.js} +113 -57
  26. package/{chunk-UNZDCI3O.js → chunk-2KDR4CWE.js} +35 -4
  27. package/{chunk-3ZTR7ZO4.js → chunk-2PGGC63K.js} +1 -1
  28. package/{chunk-EA5OYZVD.js → chunk-37XDGCY7.js} +1 -1
  29. package/chunk-3BLB7QKO.js +433 -0
  30. package/{chunk-CS6TCJ7E.js → chunk-3JQ2NRYU.js} +30 -7
  31. package/{chunk-3LKZRP7E.js → chunk-3QGUVVX5.js} +2 -2
  32. package/{chunk-SSXTSPSG.js → chunk-45YO6H7P.js} +71 -30
  33. package/{chunk-YLCUU3WM.js → chunk-4NJEIGBQ.js} +5 -5
  34. package/{chunk-K4NISKOR.js → chunk-5ZYA4JJ3.js} +47 -17
  35. package/{chunk-6HIGYUBQ.js → chunk-6XIE5ZGI.js} +1 -1
  36. package/{chunk-3Y2K5O2R.js → chunk-7A3RRUCQ.js} +125 -40
  37. package/{chunk-6COJEAYH.js → chunk-7KELZLC2.js} +44 -37
  38. package/chunk-AETZ7AD6.js +274 -0
  39. package/chunk-BFU6C242.js +66 -0
  40. package/{chunk-IA3A5373.js → chunk-C3FZR5EC.js} +1 -1
  41. package/{chunk-IWUMSAQF.js → chunk-CJCJF5XB.js} +26 -3
  42. package/{chunk-UGBHDMHI.js → chunk-CP7VIDZ7.js} +1 -1
  43. package/{chunk-TR4DXUYX.js → chunk-CQ2OZMLQ.js} +1181 -737
  44. package/{chunk-JON2PHYT.js → chunk-CTCW7U7N.js} +1 -1
  45. package/{chunk-7NYDJAQ7.js → chunk-DNNSCSA2.js} +5 -5
  46. package/{chunk-NI2BS6UD.js → chunk-DWUCB2A3.js} +1 -1
  47. package/{chunk-FJHMLRDQ.js → chunk-DWYSDNOH.js} +22 -28
  48. package/{chunk-AA564GBL.js → chunk-E3YVTQWT.js} +2 -2
  49. package/chunk-E4MARS3Q.js +114 -0
  50. package/{chunk-75MSWWUE.js → chunk-E6RGHPDR.js} +5 -3
  51. package/chunk-EDKF7RX4.js +30 -0
  52. package/{chunk-TC6P4NDR.js → chunk-F44FAXP2.js} +6 -6
  53. package/{chunk-SYYUU7EV.js → chunk-FHAGENAS.js} +2 -3
  54. package/{chunk-NJUQBYFJ.js → chunk-FKFMIBTT.js} +3 -1
  55. package/{chunk-INZZJSQF.js → chunk-FZGV4FGK.js} +24 -12
  56. package/{chunk-6HDYSFLO.js → chunk-GSXDRMDO.js} +3 -3
  57. package/{chunk-AUVFJGPC.js → chunk-JX5PJCWS.js} +7 -5
  58. package/{chunk-LYGNQHUW.js → chunk-JYYZCK2Z.js} +2 -4
  59. package/{chunk-EY7V7REW.js → chunk-KHCLMKZZ.js} +6 -280
  60. package/{chunk-EJE33XNR.js → chunk-KSCXMC6U.js} +1521 -565
  61. package/{chunk-XOJRZUPF.js → chunk-KWSQR2KK.js} +14 -29
  62. package/{chunk-2WBFJHQA.js → chunk-L7B47JXR.js} +34 -39
  63. package/{chunk-EICIFHVS.js → chunk-LAFC3B2I.js} +1 -1
  64. package/{chunk-N4JKMCY3.js → chunk-LJKICKVC.js} +2 -2
  65. package/chunk-M3JEW6N6.js +193 -0
  66. package/{chunk-LRGKOI5Y.js → chunk-MBOEV4L2.js} +7 -3
  67. package/{chunk-SVDMVX4G.js → chunk-MMZ6ZTVO.js} +112 -73
  68. package/{chunk-JDSUTNYY.js → chunk-MP64VFGD.js} +2 -2
  69. package/{chunk-NFLA6GSU.js → chunk-MXUDQZXQ.js} +44 -5
  70. package/chunk-N4G4PKQ6.js +23 -0
  71. package/{chunk-WQHGJHAL.js → chunk-N6HLMLKE.js} +732 -726
  72. package/{chunk-YQBXOHE6.js → chunk-NO42UD73.js} +1 -1
  73. package/{chunk-MLEZPE3U.js → chunk-NRRPKMM7.js} +4 -4
  74. package/{chunk-KXKQO4Q6.js → chunk-NTW5GWDM.js} +58 -1
  75. package/chunk-ONXOABJR.js +215 -0
  76. package/{chunk-TY3ADTX5.js → chunk-OZX2IPKM.js} +7 -2
  77. package/{chunk-Q4XZVZPN.js → chunk-P7OOB7QP.js} +1 -1
  78. package/{chunk-XIJZOCSP.js → chunk-PEZJEQAO.js} +1 -1
  79. package/{chunk-SWJGJMTW.js → chunk-PQDIDWGX.js} +1 -1
  80. package/chunk-PSCNXBYA.js +11 -0
  81. package/{chunk-BY2FF2C4.js → chunk-QEFJJS2I.js} +55 -73
  82. package/{chunk-BG7J6Y5X.js → chunk-QEW2MFDQ.js} +1 -1
  83. package/{chunk-KLIBF3BY.js → chunk-RDBARW6T.js} +8 -3
  84. package/{chunk-ZVOHVJI3.js → chunk-RJ2SAFB5.js} +82 -35
  85. package/{chunk-MYMBBB6Q.js → chunk-RVWRKFUB.js} +5 -3
  86. package/{chunk-43CXXVJD.js → chunk-RXX4GDIH.js} +1 -1
  87. package/chunk-SEJ5OS6F.js +49 -0
  88. package/{chunk-JXIP6ZWH.js → chunk-SKIRVYEI.js} +18 -5
  89. package/{chunk-SAJSBPI2.js → chunk-SOJM57FX.js} +5 -2
  90. package/{chunk-EKLRRZIN.js → chunk-SPAQ4PVV.js} +0 -5
  91. package/{chunk-RHMDMTDK.js → chunk-SYNKICCB.js} +2 -2
  92. package/{chunk-YBFJQC2M.js → chunk-TBHAHL33.js} +65 -42
  93. package/{chunk-L7NG2M6H.js → chunk-TRV2MIDW.js} +89 -74
  94. package/{chunk-5UAYZEXO.js → chunk-UZPQSVM6.js} +1 -1
  95. package/{chunk-7FAS3NEF.js → chunk-VAKVNHK5.js} +19 -15
  96. package/{chunk-UOWXD4VN.js → chunk-VHO3TMQZ.js} +336 -244
  97. package/{chunk-SVC3GGUA.js → chunk-VMWYBIXG.js} +7 -5
  98. package/{chunk-ZHXJ6M7T.js → chunk-W7XHHYWM.js} +4 -0
  99. package/{chunk-UR66XPVF.js → chunk-XAVSS3KE.js} +21 -3
  100. package/{chunk-A65UV3M5.js → chunk-XOKOSO35.js} +10 -19
  101. package/{chunk-VZMUOPYG.js → chunk-XTJTN3RW.js} +46 -3
  102. package/{chunk-T5HJEUQN.js → chunk-YCDWJX45.js} +1 -1
  103. package/{chunk-BBTN4NQD.js → chunk-Z4QSJILV.js} +85 -13
  104. package/{chunk-5FCIPEKT.js → chunk-Z5MHFBJZ.js} +1051 -926
  105. package/{chunk-O5FLGN2L.js → chunk-ZRSJ3JEH.js} +6 -2
  106. package/{cliExecutor-BBUVQU4L.js → cliExecutor-HG3S345O.js} +1 -1
  107. package/{codingSkills-BCQXRZOI.js → codingSkills-TKROLCBA.js} +4 -3
  108. package/{contentThunks-KNI6VXLT.js → contentThunks-OZPK5B4Z.js} +21 -19
  109. package/{cooldownCommands-GI5NNWGL.js → cooldownCommands-BSCH2W7P.js} +2 -2
  110. package/{createAgentAutomationAction-OK4L33KF.js → createAgentAutomationAction-LCIBGE5T.js} +23 -21
  111. package/{createDialogAction-JDSMY4AY.js → createDialogAction-JPJZMHJE.js} +25 -22
  112. package/{createPageAction-T7RA3HCG.js → createPageAction-6P2WLNHO.js} +26 -23
  113. package/{dbSlice-TVX6SN2T.js → dbSlice-IBVOBVMS.js} +5 -4
  114. package/{deleteFile-JYKRT7C3.js → deleteFile-FWP2PSBG.js} +3 -2
  115. package/{dialogCommands-UQZYWOOV.js → dialogCommands-WAFKC3KK.js} +30 -27
  116. package/{dialogSlice-TYW2G7IL.js → dialogSlice-R5RZHFTU.js} +20 -18
  117. package/{docCreateCommands-OA6HZBWO.js → docCreateCommands-GHGB42S7.js} +32 -28
  118. package/{docDeleteCommands-KBB3YQI2.js → docDeleteCommands-Y5I7ZEX4.js} +33 -29
  119. package/{docReadCommands-ZLMFVC67.js → docReadCommands-BMXM6J7T.js} +32 -28
  120. package/{docStore-2URPBVCS.js → docStore-DKWZ6XJ5.js} +6 -5
  121. package/{docUpdateCommands-HMH5KUON.js → docUpdateCommands-QNABH3M2.js} +32 -28
  122. package/{getPricing-RFOPUWHY.js → getPricing-NM3NUTAS.js} +4 -4
  123. package/handleSendMessageAction-UQGKM4UX.js +675 -0
  124. package/index.js +79 -88
  125. package/{lib-2ZTNRXR4.js → lib-FRRS27KN.js} +63 -28
  126. package/{localRuntimeAuthority-KQDAE64E.js → localRuntimeAuthority-R5UBODT3.js} +6 -4
  127. package/{localRuntimeDb-PF7CFKDL.js → localRuntimeDb-P37ZTX55.js} +1 -1
  128. package/{machineCommands-RK6L7ZWL.js → machineCommands-YDAIPYU5.js} +298 -80
  129. package/{machineWsRunDispatch-3X64DW2Z.js → machineWsRunDispatch-O6RM2ECT.js} +57 -53
  130. package/{memberThunks-THZYZFSN.js → memberThunks-VZI6G7YZ.js} +10 -8
  131. package/{models-JVKUEER5.js → models-FAMINFZ7.js} +2 -2
  132. package/package.json +3 -2
  133. package/{read-K4JU4MQC.js → read-2BYWW7AA.js} +3 -2
  134. package/{readDocTool-LQGR6FUN.js → readDocTool-LC3A7QTB.js} +1 -1
  135. package/{readlineWorkspace-XUFJV3RS.js → readlineWorkspace-5DP3AJWN.js} +4367 -2796
  136. package/{removeDialogAgentAction-ECHCFB7N.js → removeDialogAgentAction-SFYZXHNK.js} +8 -7
  137. package/{runAgentClientLoop-24GQ2AW6.js → runAgentClientLoop-Y6HWP2PT.js} +51 -46
  138. package/{runtimeDoctorCommands-JKTTN723.js → runtimeDoctorCommands-CROTMULY.js} +7 -5
  139. package/{setDialogExtraReferencesAction-KCVJNGMB.js → setDialogExtraReferencesAction-Q32RGFTA.js} +6 -5
  140. package/{setPrimaryDialogAgentAction-VDOBOMKC.js → setPrimaryDialogAgentAction-BFYJHUJS.js} +8 -7
  141. package/{settingSlice-VR2IJSXC.js → settingSlice-IRUU4VFB.js} +6 -5
  142. package/{skillDiscovery-2QTZINON.js → skillDiscovery-CYUCJMAG.js} +2 -1
  143. package/{spaceCommands-S5YJJXL7.js → spaceCommands-CLN45IE3.js} +33 -215
  144. package/{streamAgentChatTurn-QHKP3ABO.js → streamAgentChatTurn-6WFQJ4DY.js} +107 -74
  145. package/{switchDialogAgentAction-5L4UP7VI.js → switchDialogAgentAction-L2KOKCGG.js} +5 -4
  146. package/{tableCommands-R6WFRDYF.js → tableCommands-SUNTHAYX.js} +1 -1
  147. package/{toolApiClient-53U4UDFF.js → toolApiClient-VGYUB4P5.js} +2 -1
  148. package/{tools-SSXSTC3O.js → tools-RR53D65Q.js} +39 -35
  149. package/{tuiSummaryLlmCaller-URFJHFC5.js → tuiSummaryLlmCaller-F3DPFFZM.js} +15 -13
  150. package/{updateCommands-IYKLF3JX.js → updateCommands-AJYSD73Y.js} +2 -2
  151. package/{updateDialogTitleAction-YFYAEW3T.js → updateDialogTitleAction-WXS3AKOL.js} +23 -21
  152. package/agentSuperviseCommands-5AR3DKNN.js +0 -640
  153. package/chunk-6IGD47IC.js +0 -19
  154. package/chunk-FD36SCCD.js +0 -105
  155. package/chunk-GRFK2XP4.js +0 -230
  156. package/chunk-HJTAGT3W.js +0 -370
  157. package/chunk-SUEIAK5N.js +0 -2574
  158. package/handleSendMessageAction-GO53TY7U.js +0 -409
@@ -4,10 +4,27 @@ import {
4
4
  refreshAntigravityOAuthToken,
5
5
  refreshOpenAiCodexToken,
6
6
  xaiRefresh
7
- } from "./chunk-NFLA6GSU.js";
7
+ } from "./chunk-MXUDQZXQ.js";
8
8
  import {
9
9
  defaultLoopbackRequest
10
10
  } from "./chunk-EADNWBAZ.js";
11
+ import {
12
+ ackRunRecord,
13
+ appendRunQueue,
14
+ checkStaleRun,
15
+ claimRunRecord,
16
+ commitRunRecordClaim,
17
+ findRunRecord,
18
+ gcRunRecords,
19
+ popAllQueueEntries,
20
+ queryRunRecords,
21
+ releaseRunRecordAck,
22
+ serializeQueueEntries,
23
+ spawnLocalBackgroundRun,
24
+ terminateRunProcess,
25
+ transitionRunToTerminal,
26
+ withQueueLock
27
+ } from "./chunk-45YO6H7P.js";
11
28
  import {
12
29
  clearCredentialAvailability,
13
30
  markCredentialUnavailable,
@@ -15,57 +32,33 @@ import {
15
32
  readCredentialEntry,
16
33
  recordCredentialProbe,
17
34
  resolveCredentialKeyWithFallback
18
- } from "./chunk-NI2BS6UD.js";
35
+ } from "./chunk-DWUCB2A3.js";
19
36
  import {
20
37
  buildLocalAgentLookupKeys
21
- } from "./chunk-JON2PHYT.js";
38
+ } from "./chunk-CTCW7U7N.js";
22
39
  import {
23
40
  LOCAL_CODEX_AGENT_ID,
24
41
  LOCAL_CODEX_AGENT_KEY,
25
42
  NOLO_DEFAULT_AGENT_ID,
26
43
  NOLO_DEFAULT_AGENT_KEY
27
- } from "./chunk-EKLRRZIN.js";
44
+ } from "./chunk-SPAQ4PVV.js";
28
45
  import {
29
46
  CliProviderQuotaError,
30
47
  executeCli
31
- } from "./chunk-JDSUTNYY.js";
32
- import {
33
- ackRunRecord,
34
- appendRunQueue,
35
- checkStaleRun,
36
- claimRunRecord,
37
- commitRunRecordClaim,
38
- finalizeRunRecord,
39
- findRunRecord,
40
- gcRunRecords,
41
- popAllQueueEntries,
42
- queryRunRecords,
43
- releaseRunRecordAck,
44
- resolveRunReportPath,
45
- serializeQueueEntries,
46
- spawnLocalBackgroundRun,
47
- terminateRunProcess,
48
- withQueueLock
49
- } from "./chunk-SSXTSPSG.js";
48
+ } from "./chunk-MP64VFGD.js";
50
49
  import {
51
50
  inferCaptureIntent
52
- } from "./chunk-EICIFHVS.js";
51
+ } from "./chunk-LAFC3B2I.js";
53
52
  import {
54
53
  buildCliPrompt
55
54
  } from "./chunk-ATNTHIZI.js";
56
55
  import {
57
56
  inlineImageUrlsForCustomProvider,
58
57
  prepareTools
59
- } from "./chunk-RHMDMTDK.js";
58
+ } from "./chunk-SYNKICCB.js";
60
59
  import {
61
60
  getServerProviderSecret
62
61
  } from "./chunk-HS7MLR74.js";
63
- import {
64
- getAntigravityUserAgent,
65
- isAntigravityOAuthAgent,
66
- readAntigravityProjectId,
67
- resolveAntigravityCloudCodeBaseUrl
68
- } from "./chunk-BG7J6Y5X.js";
69
62
  import {
70
63
  CONTROL_AGENT_RUN_ACTIONS,
71
64
  buildControlAgentRunFunctionSchema,
@@ -79,7 +72,7 @@ import {
79
72
  rememberMemoryFunctionSchema,
80
73
  resolveAgentRequiredPackIds,
81
74
  setTodoListFunc
82
- } from "./chunk-TR4DXUYX.js";
75
+ } from "./chunk-CQ2OZMLQ.js";
83
76
  import {
84
77
  fetchWithTransientRetry,
85
78
  isTransientFetchError
@@ -95,26 +88,26 @@ import {
95
88
  isAgentRunTerminalStatus,
96
89
  resolveRunLabel,
97
90
  shortRunId
98
- } from "./chunk-KXKQO4Q6.js";
91
+ } from "./chunk-NTW5GWDM.js";
99
92
  import {
100
93
  applyBuiltinAgentRuntimeOverride,
101
94
  applyTokenUsageToDayStats,
102
95
  prepareTokenUsageData,
103
96
  resolveBuiltinPlatformAgentConfig,
104
97
  runKeyed
105
- } from "./chunk-YBFJQC2M.js";
98
+ } from "./chunk-TBHAHL33.js";
106
99
  import {
107
100
  BUILTIN_TITLE_LLM_CONFIG
108
101
  } from "./chunk-EVBFYPDC.js";
109
102
  import {
110
103
  fetchServerSyncedCredential
111
- } from "./chunk-TC6P4NDR.js";
104
+ } from "./chunk-F44FAXP2.js";
112
105
  import {
113
106
  require_date_fns
114
107
  } from "./chunk-M76ECQRD.js";
115
108
  import {
116
109
  getDefaultCliLocalRuntimeDb
117
- } from "./chunk-IA3A5373.js";
110
+ } from "./chunk-C3FZR5EC.js";
118
111
  import {
119
112
  FORCED_TOOLS,
120
113
  addDefaultLightWebToolsForConfiguredAgents,
@@ -124,10 +117,16 @@ import {
124
117
  applySystemBuiltinSkillFilter,
125
118
  expandEnabledPacks,
126
119
  resolveEffectiveEnabledPacks
127
- } from "./chunk-O5FLGN2L.js";
120
+ } from "./chunk-ZRSJ3JEH.js";
128
121
  import {
129
122
  DEFAULT_HYBRID_READ_TIMEOUT_MS,
123
+ Duration_exports,
124
+ Effect_exports,
125
+ Exit_exports,
126
+ Option_exports,
127
+ accumulateGeminiChunks,
130
128
  aggregateResponsesStream,
129
+ buildGeminiGenerateContentRequest,
131
130
  buildLoadSkillExecutor,
132
131
  buildLocalDialogWritePlan,
133
132
  buildLocalWorkspaceOpenAiTools,
@@ -139,62 +138,77 @@ import {
139
138
  evaluateFileWritePolicy,
140
139
  executeLocalToolWithPolicy,
141
140
  executeOpenAiCompatibleChatCompletion,
141
+ fetchAntigravityCloudCodeCompletion,
142
142
  filterRetainedLedgerRecords,
143
143
  internalListWorkspaceEntries,
144
144
  internalSearchWorkspace,
145
+ isGemini3Model,
145
146
  isLineRangeCovered,
146
147
  localDialogMessageRecordToRuntimeMessage,
147
148
  parseSseDataLineJson,
148
149
  parseSseDataLineObject,
149
150
  parseSyncServersEnv,
151
+ parseUpstreamErrorBody,
152
+ resolveAntigravityFinishReason,
150
153
  resolveOpenAiCompatibleProviderConfig,
154
+ shouldUseGeminiNativeToolRoute,
151
155
  summarizeToolArguments
152
- } from "./chunk-EJE33XNR.js";
156
+ } from "./chunk-KSCXMC6U.js";
153
157
  import {
158
+ PlatformStreamInterruptedError,
154
159
  buildPlatformChatCompletionRequest,
155
160
  canUsePlatformChatProvider,
156
- collectStablePromptPrefix,
157
161
  hasDirectOpenAiCompatibleProvider,
158
162
  parsePlatformChatCompletionData,
159
163
  parsePlatformChatCompletionResponse,
160
164
  readPlatformChatSseCompletion,
161
165
  readSseDataValues,
162
166
  resolvePlatformChatProviderConfig,
163
- shouldUsePlatformChatProvider,
164
- stablePromptCacheKey,
165
- streamSseDataValues
166
- } from "./chunk-3Y2K5O2R.js";
167
+ shouldUsePlatformChatProvider
168
+ } from "./chunk-7A3RRUCQ.js";
167
169
  import {
168
170
  resolveAgentRuntimeConfigFromRecord,
169
171
  resolveHistoricalToolContentCap
170
- } from "./chunk-A65UV3M5.js";
172
+ } from "./chunk-XOKOSO35.js";
171
173
  import {
174
+ collectStablePromptPrefix,
172
175
  convertMessagesToResponsesInput,
176
+ stablePromptCacheKey,
173
177
  toResponsesTools
174
- } from "./chunk-VZMUOPYG.js";
178
+ } from "./chunk-XTJTN3RW.js";
179
+ import {
180
+ isAntigravityOAuthAgent
181
+ } from "./chunk-QEW2MFDQ.js";
175
182
  import {
176
183
  resolvePlatformAuthToken
177
- } from "./chunk-KLIBF3BY.js";
184
+ } from "./chunk-RDBARW6T.js";
178
185
  import {
179
186
  buildNoloWorkspaceOpenAiTools,
180
187
  parseNoloWorkspaceToolArguments,
181
188
  resolveRuntimeToolSurfaceForAgent
182
- } from "./chunk-ZVOHVJI3.js";
189
+ } from "./chunk-RJ2SAFB5.js";
183
190
  import {
184
191
  mergeAvailabilityDeadline,
185
192
  resolveAvailabilityAction,
186
193
  resolveCooldownGate
187
- } from "./chunk-IWUMSAQF.js";
194
+ } from "./chunk-CJCJF5XB.js";
188
195
  import {
189
196
  buildDialogFallbackTitleFromUserInput,
190
197
  normalizeDialogTitle
191
198
  } from "./chunk-2MBTWINN.js";
192
199
  import {
193
- clipCompactText
194
- } from "./chunk-BBTN4NQD.js";
200
+ clipCompactText,
201
+ createProviderCallTimingTracker,
202
+ finalizeProviderCallTiming,
203
+ observeMeaningfulProviderResponseAt,
204
+ withProviderCallTimingFields
205
+ } from "./chunk-Z4QSJILV.js";
206
+ import {
207
+ estimateTokenCount
208
+ } from "./chunk-PSCNXBYA.js";
195
209
  import {
196
210
  isAdaptiveThinkingModelId
197
- } from "./chunk-SVDMVX4G.js";
211
+ } from "./chunk-MMZ6ZTVO.js";
198
212
  import {
199
213
  compactWhitespace
200
214
  } from "./chunk-DWLEOOGR.js";
@@ -203,13 +217,13 @@ import {
203
217
  resolveCurrentRunRuntimeToolPolicy,
204
218
  resolveLocalWorkspaceExecutorOptionsFromPolicy,
205
219
  resolveRequestedRuntimeToolNames
206
- } from "./chunk-CS6TCJ7E.js";
220
+ } from "./chunk-3JQ2NRYU.js";
207
221
  import {
208
222
  createOAuthTokenStore,
209
223
  isTokenExpired,
210
224
  readOAuthCredential,
211
225
  resolveFreshAccessToken
212
- } from "./chunk-FD36SCCD.js";
226
+ } from "./chunk-ONXOABJR.js";
213
227
  import {
214
228
  toErrorMessage
215
229
  } from "./chunk-HNMXYYJR.js";
@@ -229,21 +243,24 @@ import {
229
243
  createUserKey,
230
244
  dialogMessageRange
231
245
  } from "./chunk-NHRQCXIQ.js";
232
- import {
233
- asTrimmedNonEmptyStringArray
234
- } from "./chunk-I42VC5KR.js";
235
246
  import {
236
247
  asTrimmedLowercaseString
237
248
  } from "./chunk-QSJ3HFEF.js";
238
249
  import {
239
250
  isSystemBuiltinTrustedAgentKey
240
- } from "./chunk-2WBFJHQA.js";
251
+ } from "./chunk-L7B47JXR.js";
252
+ import {
253
+ asTrimmedString
254
+ } from "./chunk-3EUW3WEO.js";
241
255
  import {
242
256
  isRecord
243
257
  } from "./chunk-KUG52IAP.js";
244
258
  import {
245
259
  NOLO_CLUSTER_SERVERS
246
260
  } from "./chunk-LCBAMY2M.js";
261
+ import {
262
+ isLoopbackUrl
263
+ } from "./chunk-4SN6J65J.js";
247
264
  import {
248
265
  normalizeServerOrigin
249
266
  } from "./chunk-CF7PE763.js";
@@ -360,11 +377,30 @@ function initCliLocale(env = process.env) {
360
377
  function newlineHint(platform = process.platform) {
361
378
  return platform === "win32" ? "Ctrl+J" : "Shift+Enter";
362
379
  }
380
+ var WELCOME_TIPS = {
381
+ en: [
382
+ `Tip: ${newlineHint()} for a newline; /help lists all commands.`,
383
+ "Tip: paste a screenshot or drag an image into the terminal \u2014 nolo can see it.",
384
+ "Tip: /doc attach <doc> brings a doc into this conversation's context.",
385
+ "Tip: /theme switches colors; terminal mode follows your terminal's day/night.",
386
+ "Tip: /history resumes a recent dialog; /agents lists your agents."
387
+ ],
388
+ zh: [
389
+ `\u63D0\u793A\uFF1A${newlineHint()} \u6362\u884C\uFF1B/help \u5217\u51FA\u5168\u90E8\u547D\u4EE4\u3002`,
390
+ "\u63D0\u793A\uFF1A\u76F4\u63A5\u7C98\u8D34\u622A\u56FE\u6216\u628A\u56FE\u7247\u62D6\u8FDB\u7EC8\u7AEF\uFF0Cnolo \u770B\u5F97\u61C2\u3002",
391
+ "\u63D0\u793A\uFF1A/doc attach <doc> \u628A\u6587\u6863\u6302\u8FDB\u5F53\u524D\u5BF9\u8BDD\u7684\u4E0A\u4E0B\u6587\u3002",
392
+ "\u63D0\u793A\uFF1A/theme \u5207\u6362\u914D\u8272\uFF1Bterminal \u6A21\u5F0F\u8DDF\u968F\u7EC8\u7AEF\u7684\u65E5\u591C\u4E3B\u9898\u3002",
393
+ "\u63D0\u793A\uFF1A/history \u56DE\u5230\u6700\u8FD1\u5BF9\u8BDD\uFF1B/agents \u67E5\u770B\u53EF\u7528 Agent\u3002"
394
+ ]
395
+ };
396
+ function dailyWelcomeTip(now = Date.now()) {
397
+ const tips = WELCOME_TIPS[currentLocale];
398
+ const day = Math.floor(now / 864e5);
399
+ return tips[day % tips.length];
400
+ }
363
401
  var STRINGS = {
364
- welcomeHint: {
365
- en: `Tell nolo what you want. Use /help for commands. ${newlineHint()} for newline.`,
366
- zh: `\u544A\u8BC9 nolo \u4F60\u60F3\u8981\u4EC0\u4E48\u3002\u8F93\u5165 /help \u67E5\u770B\u547D\u4EE4\u3002${newlineHint()} \u6362\u884C\u3002`
367
- },
402
+ // Welcome hint lives in WELCOME_TIPS + dailyWelcomeTip() (rotating daily
403
+ // tips); the composer placeholder already covers "type / for commands".
368
404
  promptLabel: {
369
405
  en: "\u276F ",
370
406
  zh: "\u276F "
@@ -617,6 +653,14 @@ var STRINGS = {
617
653
  // --- Tool trace copy ------------------------------------------------------
618
654
  // The compact trace shows only status, never timing or output size: a line
619
655
  // count told the user nothing actionable and the ms figure read as noise.
656
+ thinkingActive: {
657
+ en: "Thinking\u2026",
658
+ zh: "\u601D\u8003\u4E2D\u2026"
659
+ },
660
+ thinkingActivePreview: {
661
+ en: "Thinking: {0}",
662
+ zh: "\u601D\u8003\u4E2D\uFF1A{0}"
663
+ },
620
664
  thinkingTraceLine: {
621
665
  en: "\u273B Thought for {0}",
622
666
  zh: "\u273B \u601D\u8003 {0}"
@@ -878,7 +922,7 @@ var STRINGS = {
878
922
  " /customize Describe how you want to tune nolo",
879
923
  " /tasks List background process tasks (aliases: /jobs, /procs)",
880
924
  " /stop <pid|all> Stop background process tasks",
881
- " /login Show login/profile hint",
925
+ " /login Show login/profile hint (/login --server <url> to log in here)",
882
926
  " /profile Show active profile",
883
927
  " /update Update the nolo CLI install",
884
928
  " /version Show version/update hint",
@@ -916,7 +960,7 @@ var STRINGS = {
916
960
  " /customize \u63CF\u8FF0\u4F60\u60F3\u600E\u4E48\u8C03\u6559 nolo",
917
961
  " /tasks \u5217\u51FA\u540E\u53F0\u5B50\u8FDB\u7A0B\u4EFB\u52A1\uFF08\u522B\u540D\uFF1A/jobs, /procs\uFF09",
918
962
  " /stop <pid|all> \u505C\u6B62\u6307\u5B9A\u7684\u540E\u53F0\u4EFB\u52A1",
919
- " /login \u67E5\u770B\u767B\u5F55 / \u914D\u7F6E\u63D0\u793A",
963
+ " /login \u67E5\u770B\u767B\u5F55 / \u914D\u7F6E\u63D0\u793A\uFF08/login --server <url> \u53EF\u5728\u672C\u4F1A\u8BDD\u5185\u767B\u5F55\uFF09",
920
964
  " /profile \u67E5\u770B\u5F53\u524D\u914D\u7F6E\u73AF\u5883",
921
965
  " /update \u66F4\u65B0 nolo CLI",
922
966
  " /version \u67E5\u770B\u7248\u672C\u4E0E\u66F4\u65B0\u63D0\u793A",
@@ -1049,14 +1093,56 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`,
1049
1093
  en: "MVP login uses profile/env auth. Set AUTH_TOKEN, NOLO_SERVER, or NOLO_PROFILE before starting nolo.",
1050
1094
  zh: "MVP \u767B\u5F55\u8D70 profile/\u73AF\u5883\u53D8\u91CF\u8BA4\u8BC1\u3002\u542F\u52A8 nolo \u524D\u8BF7\u8BBE\u7F6E AUTH_TOKEN\u3001NOLO_SERVER \u6216 NOLO_PROFILE\u3002"
1051
1095
  },
1096
+ loginTuiStart: {
1097
+ en: "Or run `/login --server <url>` to log in right here (opens a browser authorization URL).",
1098
+ zh: "\u4E5F\u53EF\u4EE5\u6267\u884C /login --server <url> \u76F4\u63A5\u5728\u8FD9\u91CC\u767B\u5F55\uFF08\u4F1A\u7ED9\u51FA\u6D4F\u89C8\u5668\u6388\u6743\u94FE\u63A5\uFF09\u3002"
1099
+ },
1100
+ loginUsage: {
1101
+ en: "Usage: /login [--server <url>]. Unsupported flags: {0}",
1102
+ zh: "\u7528\u6CD5\uFF1A/login [--server <url>]\u3002\u4E0D\u652F\u6301\u7684\u53C2\u6570\uFF1A{0}"
1103
+ },
1104
+ loginStarted: {
1105
+ en: "Open this URL to authorize nolo-cli:\n{0}\nCode: {1}",
1106
+ zh: "\u6253\u5F00\u8FD9\u4E2A\u94FE\u63A5\u6388\u6743 nolo-cli\uFF1A\n{0}\n\u6388\u6743\u7801\uFF1A{1}"
1107
+ },
1108
+ loginBrowserFailed: {
1109
+ en: "Could not open a browser automatically. Paste the URL above into a browser.",
1110
+ zh: "\u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u628A\u4E0A\u9762\u7684\u94FE\u63A5\u7C98\u8D34\u5230\u6D4F\u89C8\u5668\u91CC\u3002"
1111
+ },
1112
+ loginWaiting: {
1113
+ en: "[nolo] Waiting for browser authorization ({0} remaining)... (Ctrl+C to cancel)",
1114
+ zh: "[nolo] \u7B49\u5F85\u6D4F\u89C8\u5668\u6388\u6743\uFF08\u5269\u4F59 {0}\uFF09\u2026\u2026\u6309 Ctrl+C \u53D6\u6D88"
1115
+ },
1116
+ loginStillWaiting: {
1117
+ en: "[nolo] Still waiting... ({0} remaining)",
1118
+ zh: "[nolo] \u4ECD\u5728\u7B49\u5F85\u2026\u2026\uFF08\u5269\u4F59 {0}\uFF09"
1119
+ },
1120
+ loginSuccess: {
1121
+ en: "Logged in. Token saved to profile; this session now uses it immediately.",
1122
+ zh: "\u767B\u5F55\u6210\u529F\u3002Token \u5DF2\u5199\u5165 profile\uFF0C\u5F53\u524D\u4F1A\u8BDD\u7ACB\u5373\u751F\u6548\u3002"
1123
+ },
1124
+ loginFailed: {
1125
+ en: "Login failed: {0}",
1126
+ zh: "\u767B\u5F55\u5931\u8D25\uFF1A{0}"
1127
+ },
1128
+ loginTimeout: {
1129
+ en: "Login timed out. Run /login again, or use `nolo login --token <jwt>` in a shell.",
1130
+ zh: "\u767B\u5F55\u8D85\u65F6\u3002\u8BF7\u91CD\u65B0\u6267\u884C /login\uFF0C\u6216\u5728 shell \u91CC\u7528 nolo login --token <jwt>\u3002"
1131
+ },
1132
+ loginCancelled: {
1133
+ en: "Login cancelled.",
1134
+ zh: "\u5DF2\u53D6\u6D88\u767B\u5F55\u3002"
1135
+ },
1052
1136
  versionInfo: {
1053
1137
  en: "nolo {0}\nUpdate this install with: nolo update\nIf repo-local output differs, publish/install the latest npm package first.",
1054
1138
  zh: "nolo {0}\n\u7528 nolo update \u66F4\u65B0\u5F53\u524D\u5B89\u88C5\u3002\n\u5982\u679C\u672C\u5730\u4ED3\u5E93\u8F93\u51FA\u7684\u7248\u672C\u4E0D\u540C\uFF0C\u8BF7\u5148\u53D1\u5E03/\u5B89\u88C5\u6700\u65B0\u7684 npm \u5305\u3002"
1055
1139
  },
1056
1140
  versionUnknown: { en: "unknown version", zh: "\u672A\u77E5\u7248\u672C" },
1057
1141
  updateAvailable: {
1058
- en: "New nolo {0} available (you have {1}) \u2014 run /update to upgrade",
1059
- zh: "\u65B0\u7248\u672C nolo {0} \u53EF\u7528\uFF08\u5F53\u524D {1}\uFF09\u2014 \u8FD0\u884C /update \u5347\u7EA7"
1142
+ // 保持短:这行在窄终端物理换行会破坏 banner 重绘的行数计算。当前版本
1143
+ // 号上一行 version line 已有,不重复。
1144
+ en: "\u2191 nolo {0} available \u2014 /update to upgrade",
1145
+ zh: "\u2191 nolo {0} \u53EF\u7528 \u2014 /update \u5347\u7EA7"
1060
1146
  },
1061
1147
  // --- Dialog list / timestamps -----------------------------------------
1062
1148
  recentDialogs: { en: "Recent dialogs:", zh: "\u6700\u8FD1\u5BF9\u8BDD\uFF1A" },
@@ -1466,6 +1552,7 @@ function mapAnthropicMessageToOpenAi(payload) {
1466
1552
  };
1467
1553
  }
1468
1554
  async function fetchAnthropicMessagesCompletion(args) {
1555
+ const timingTracker = createProviderCallTimingTracker();
1469
1556
  const response = await (args.fetchImpl ?? fetch)(ANTHROPIC_MESSAGES_URL, {
1470
1557
  method: "POST",
1471
1558
  headers: {
@@ -1484,7 +1571,16 @@ async function fetchAnthropicMessagesCompletion(args) {
1484
1571
  error: { message: await response.text().catch(() => response.statusText) }
1485
1572
  }));
1486
1573
  if (!response.ok) return { status: response.status, body: payload, headers: response.headers };
1487
- return { status: 200, body: mapAnthropicMessageToOpenAi(payload) };
1574
+ const mapped = mapAnthropicMessageToOpenAi(payload);
1575
+ const timing = finalizeProviderCallTiming(timingTracker);
1576
+ const usage = mapped.usage;
1577
+ if (usage && typeof usage === "object" && timing.callDurationMs !== void 0) {
1578
+ mapped.usage = {
1579
+ ...usage,
1580
+ callDurationMs: timing.callDurationMs
1581
+ };
1582
+ }
1583
+ return { status: 200, body: mapped };
1488
1584
  }
1489
1585
  function isAnthropicOAuthAgent(agent) {
1490
1586
  return agent.apiKeyRef?.trim().toLowerCase() === "claude";
@@ -1523,6 +1619,7 @@ var LOCAL_SERVER_MEMORY_TOOL_NAME_SET = new Set(
1523
1619
  // packages/cli/client/localRuntimeTools.ts
1524
1620
  function buildOpenAiTools(args) {
1525
1621
  const toolset = buildLocalWorkspaceToolsetForEnv(args);
1622
+ const workspaceToolNames = toolset.toolNames;
1526
1623
  const toolNameSet = new Set(args.toolNames ?? []);
1527
1624
  const uiAskChoiceTools = toolNameSet.has("ask_user") ? prepareTools(["ask_user"]) : [];
1528
1625
  const readPastedTextTools = toolNameSet.has("readPastedText") ? [
@@ -1564,7 +1661,7 @@ function buildOpenAiTools(args) {
1564
1661
  ...uiAskChoiceTools,
1565
1662
  ...readPastedTextTools,
1566
1663
  ...buildLocalWorkspaceOpenAiTools({
1567
- toolNames: toolset.toolNames,
1664
+ toolNames: args.effectiveToolNames ?? workspaceToolNames,
1568
1665
  exposeShellTools: toolset.exposeShellTools
1569
1666
  }),
1570
1667
  ...buildServerPlatformOpenAiTools({ toolNames: args.toolNames }),
@@ -1583,8 +1680,15 @@ function buildOrchestrationOpenAiTools(args) {
1583
1680
  const waitCapableActions = CONTROL_AGENT_RUN_ACTIONS.filter(
1584
1681
  (action) => action !== "wait"
1585
1682
  );
1586
- const controlSchema = hasRunWakeChannel(args.env) ? buildControlAgentRunFunctionSchema({ actions: waitCapableActions }) : buildControlAgentRunFunctionSchema();
1587
- const startSchema = buildStartAgentRunFunctionSchema({ supportsWait: false });
1683
+ const wakeChannel = hasRunWakeChannel(args.env);
1684
+ const controlSchema = buildControlAgentRunFunctionSchema({
1685
+ ...wakeChannel ? { actions: waitCapableActions } : {},
1686
+ wakeEnabled: wakeChannel
1687
+ });
1688
+ const startSchema = buildStartAgentRunFunctionSchema({
1689
+ supportsWait: false,
1690
+ wakeEnabled: wakeChannel
1691
+ });
1588
1692
  return prepareTools(names).map((tool) => {
1589
1693
  if (tool?.function?.name === "controlAgentRun") {
1590
1694
  return { ...tool, function: controlSchema };
@@ -1596,8 +1700,8 @@ function buildOrchestrationOpenAiTools(args) {
1596
1700
  });
1597
1701
  }
1598
1702
  var CLI_DEFAULT_TOOLS = ["exa_search", "fetchWebpage", "ask_user"];
1599
- function addDefaultCliCoreTools(toolNames, env) {
1600
- const declaredOnly = env && shouldUseDeclaredOnlyLocalWorkspaceTools(env);
1703
+ function addDefaultCliCoreTools(toolNames, env, args) {
1704
+ const declaredOnly = args?.skipHostDefaults === true || (env ? shouldUseDeclaredOnlyLocalWorkspaceTools(env) : false);
1601
1705
  const injected = declaredOnly ? [...FORCED_TOOLS] : [...FORCED_TOOLS, ...CLI_DEFAULT_TOOLS];
1602
1706
  return [.../* @__PURE__ */ new Set([...toolNames, ...injected])];
1603
1707
  }
@@ -1605,6 +1709,10 @@ function resolveCliEffectiveEnabledPacks(args) {
1605
1709
  return resolveEffectiveEnabledPacks({
1606
1710
  enabledPacks: resolveAgentRequiredPackIds(args),
1607
1711
  declaredOnly: args.declaredOnly,
1712
+ // 子任务不继承 ALWAYS_ON 交互默认(memory/skills)——agent 显式声明
1713
+ // (enabledPacks / required skill packs)的包照常展开;code 兜底是
1714
+ // host-required,子任务保留(否则零声明叶子上没有任何文件/shell 工具)。
1715
+ includeAlwaysOnPacks: args.isSubtask !== true,
1608
1716
  emptyFallbackPacks: ["code"]
1609
1717
  });
1610
1718
  }
@@ -1626,46 +1734,48 @@ function withRuntimeEnabledPacksAndPrompt(config) {
1626
1734
  }
1627
1735
  function resolveCliRequestedToolNames(agentConfig, env, systemBuiltinSkills) {
1628
1736
  const declaredOnly = shouldUseDeclaredOnlyLocalWorkspaceTools(env);
1629
- const expanded = addDefaultLightWebToolsForConfiguredAgents(
1630
- addDefaultCliCoreTools(
1631
- canonicalizeToolNames(
1632
- expandEnabledPacks(
1633
- resolveCliEffectiveEnabledPacks({
1634
- enabledPacks: agentConfig?.enabledPacks,
1635
- skills: agentConfig?.skills,
1636
- declaredOnly
1637
- }),
1638
- resolveRequestedRuntimeToolNames({ agentConfig })
1639
- )
1640
- ),
1641
- env
1737
+ const isSubtask = isSubtaskRun(env);
1738
+ const coreExpanded = addDefaultCliCoreTools(
1739
+ canonicalizeToolNames(
1740
+ expandEnabledPacks(
1741
+ resolveCliEffectiveEnabledPacks({
1742
+ enabledPacks: agentConfig?.enabledPacks,
1743
+ skills: agentConfig?.skills,
1744
+ declaredOnly,
1745
+ isSubtask
1746
+ }),
1747
+ resolveRequestedRuntimeToolNames({ agentConfig })
1748
+ )
1642
1749
  ),
1643
- agentConfig
1750
+ env,
1751
+ { skipHostDefaults: isSubtask }
1644
1752
  );
1753
+ const expanded = isSubtask ? coreExpanded : addDefaultLightWebToolsForConfiguredAgents(coreExpanded, agentConfig);
1645
1754
  const filtered = applySystemBuiltinSkillFilter(
1646
1755
  // Default-on system capabilities (agent-orchestration) are mounted for
1647
- // every non-declared-only agent before the global filter runs, so the
1648
- // user's global "off" still wins. declared-only (ablation) runs keep
1649
- // their strict surface.
1650
- declaredOnly ? expanded : addDefaultSystemCapabilityTools(expanded),
1756
+ // every non-declared-only interactive agent before the global filter runs,
1757
+ // so the user's global "off" still wins. declared-only (ablation) and
1758
+ // subtask runs keep their strict surface.
1759
+ declaredOnly || isSubtask ? expanded : addDefaultSystemCapabilityTools(expanded),
1651
1760
  systemBuiltinSkills
1652
1761
  );
1653
1762
  const afterDisabled = applyDisabledTools(
1654
1763
  filtered,
1655
1764
  agentConfig?.disabledTools
1656
1765
  );
1657
- return filterToolNamesForRunKind(afterDisabled, isSubtaskRun(env));
1766
+ return filterToolNamesForRunKind(afterDisabled, isSubtask);
1658
1767
  }
1659
1768
  function resolveProviderOpenAiToolBundle(agentConfig, env, buildTools = buildOpenAiTools, additionalToolNames = []) {
1660
1769
  const requestedToolNames = [
1661
1770
  .../* @__PURE__ */ new Set([
1662
- ...resolveCliRequestedToolNames(agentConfig, env, null),
1771
+ ...Array.isArray(agentConfig.runScopedToolSurface?.finalToolNames) ? agentConfig.runScopedToolSurface.finalToolNames : resolveCliRequestedToolNames(agentConfig, env, null),
1663
1772
  ...additionalToolNames
1664
1773
  ])
1665
1774
  ];
1666
1775
  const tools = buildTools({
1667
1776
  agentKey: agentConfig.key,
1668
1777
  toolNames: requestedToolNames,
1778
+ ...Array.isArray(agentConfig.runScopedToolSurface?.finalToolNames) ? { effectiveToolNames: requestedToolNames } : {},
1669
1779
  env
1670
1780
  });
1671
1781
  return { requestedToolNames, tools };
@@ -1674,9 +1784,9 @@ function buildLocalWorkspaceToolsetForEnv(args) {
1674
1784
  const toolset = buildLocalWorkspaceToolset({
1675
1785
  declaredToolNames: args.toolNames,
1676
1786
  exposeShellTools: true,
1677
- useDeclaredToolNamesOnly: shouldUseDeclaredOnlyLocalWorkspaceTools(
1678
- args.env
1679
- )
1787
+ // The requested list is already the effective run surface. Re-expanding
1788
+ // shell/workspace defaults here would bypass run-scoped constraints.
1789
+ useDeclaredToolNamesOnly: args.useDeclaredToolNamesOnly === true || args.useDeclaredToolNamesOnly === void 0 && shouldUseDeclaredOnlyLocalWorkspaceTools(args.env)
1680
1790
  });
1681
1791
  return toolset;
1682
1792
  }
@@ -1807,9 +1917,11 @@ var resolveAnthropicOAuthTransport = async (ctx) => {
1807
1917
  provider: "anthropic",
1808
1918
  ...tool_calls ? { tool_calls } : {},
1809
1919
  // fetchAnthropicMessagesCompletion 已把 Anthropic Messages 响应归一化成
1810
- // OpenAI chat.completions 形状:choices[0] + usageprompt_tokens/
1811
- // output_tokens/cache_*)。必须透传,否则 localLoop 的 lastUsage 无
1812
- // token 数,TUI context chip 拿不到更新(与 Codex OAuth 分支同因)。
1920
+ // OpenAI chat.completions 形状:choices[0].finish_reason"stop"/"tool_calls")
1921
+ // + usage(prompt_tokens/output_tokens/cache_*)。必须透传,否则 localLoop
1922
+ // 收尾轮无 finish_reason / stream_complete 时会误判成 stream_truncated(与 Antigravity 同理)。
1923
+ finish_reason: typeof choice?.finish_reason === "string" ? choice.finish_reason : void 0,
1924
+ stream_complete: true,
1813
1925
  usage: result.body?.usage,
1814
1926
  trace: messages
1815
1927
  };
@@ -1819,519 +1931,256 @@ var resolveAnthropicOAuthTransport = async (ctx) => {
1819
1931
  return null;
1820
1932
  };
1821
1933
 
1822
- // packages/core/chat/upstreamErrorBody.ts
1823
- function parseUpstreamErrorBody(errorText, statusText) {
1824
- if (errorText) {
1825
- try {
1826
- const parsed = JSON.parse(errorText);
1827
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1828
- const error = parsed.error;
1829
- if (error && typeof error === "object" && !Array.isArray(error)) {
1830
- return parsed;
1831
- }
1934
+ // packages/agent-runtime/antigravityInvocation.ts
1935
+ var AUTH_RETRYABLE_STATUSES = /* @__PURE__ */ new Set([401, 403]);
1936
+ function antigravityAttemptEffect(args) {
1937
+ return Effect_exports.suspend(() => {
1938
+ const attemptController = new AbortController();
1939
+ const externalSignal = args.externalSignal;
1940
+ let onExternalAbort;
1941
+ const forwardExternalAbort = () => {
1942
+ if (!attemptController.signal.aborted) attemptController.abort(externalSignal?.reason);
1943
+ };
1944
+ if (externalSignal) {
1945
+ if (externalSignal.aborted) forwardExternalAbort();
1946
+ else {
1947
+ onExternalAbort = forwardExternalAbort;
1948
+ externalSignal.addEventListener("abort", onExternalAbort, { once: true });
1832
1949
  }
1833
- } catch {
1834
1950
  }
1835
- }
1836
- return { error: { message: errorText || statusText } };
1951
+ const removeExternalListener = () => {
1952
+ if (onExternalAbort) {
1953
+ externalSignal?.removeEventListener("abort", onExternalAbort);
1954
+ onExternalAbort = void 0;
1955
+ }
1956
+ };
1957
+ const attempt = Effect_exports.callback((resume, fiberSignal) => {
1958
+ const onFiberAbort = () => forwardExternalAbort();
1959
+ if (fiberSignal?.aborted) forwardExternalAbort();
1960
+ else fiberSignal?.addEventListener("abort", onFiberAbort);
1961
+ const removeFiberListener = () => {
1962
+ if (onFiberAbort) fiberSignal?.removeEventListener("abort", onFiberAbort);
1963
+ };
1964
+ if (attemptController.signal.aborted) {
1965
+ removeFiberListener();
1966
+ removeExternalListener();
1967
+ resume(Effect_exports.fail(buildInvocationError(
1968
+ "ANTIGRAVITY_INVOCATION_ABORTED",
1969
+ "Antigravity invocation aborted before request."
1970
+ )));
1971
+ return Effect_exports.succeed(void 0);
1972
+ }
1973
+ const pending = fetchAntigravityCloudCodeCompletion({
1974
+ agentConfig: args.agentConfig,
1975
+ accessToken: args.credential.accessToken,
1976
+ metadata: args.credential.metadata,
1977
+ openAiBody: args.openAiBody,
1978
+ signal: attemptController.signal,
1979
+ fetchImpl: args.fetchImpl,
1980
+ ...args.onTextDelta ? { onTextDelta: args.onTextDelta } : {},
1981
+ ...args.onReasoningDelta ? { onReasoningDelta: args.onReasoningDelta } : {}
1982
+ });
1983
+ pending.then(
1984
+ (result) => resume(Effect_exports.succeed(result)),
1985
+ (error) => resume(Effect_exports.fail(error))
1986
+ );
1987
+ return Effect_exports.sync(() => {
1988
+ removeFiberListener();
1989
+ removeExternalListener();
1990
+ });
1991
+ }).pipe(
1992
+ // 兜底:winner 路径(正常 settle)也要摘 listener;timeout 赢时 attempt
1993
+ // 是输家 fiber,callback cleanup 已由 race/timeout 的 interrupt 触发,
1994
+ // 这里保证任何出口 listener 都被移除。
1995
+ Effect_exports.ensuring(Effect_exports.sync(() => {
1996
+ removeExternalListener();
1997
+ }))
1998
+ );
1999
+ return attempt;
2000
+ });
1837
2001
  }
1838
-
1839
- // packages/agent-runtime/antigravityCloudCodeProvider.ts
1840
- import { randomUUID as randomUUID2 } from "node:crypto";
1841
-
1842
- // packages/agent-runtime/antigravityWireModel.ts
1843
- var WIRE_PROFILES = {
1844
- // Antigravity discovery exposes 3.7 Flash as one tiered wire model.
1845
- // The UI labels its effort variants (Low/Medium/High), but the literal
1846
- // -medium/-high ids return 404 from streamGenerateContent.
1847
- "gemini-3.7-flash-tiered": { modelEnum: "MODEL_PLACEHOLDER_M301", maxOutputTokens: 65536 },
1848
- // Gemini 3.8 Flash 沿用 3.7 的 tiered 兼容策略:仓库内暂无 Antigravity discovery
1849
- // 证据确认 3.8 的 wire modelEnum,禁止虚构,先只声明同档输出上限;enum 待
1850
- // discovery 证据到位后补齐。
1851
- "gemini-3.8-flash-tiered": { maxOutputTokens: 65536 },
1852
- "gemini-3.6-flash-low": { maxOutputTokens: 65536 },
1853
- "gemini-3.6-flash-medium": { maxOutputTokens: 65536 },
1854
- "gemini-3.6-flash-high": { maxOutputTokens: 65536 },
1855
- // 旧模型 wire 映射保留:存量自定义 agent 仍可能引用(注册表已下线不影响此处)。
1856
- "gemini-3.5-flash-extra-low": { modelEnum: "MODEL_PLACEHOLDER_M187", maxOutputTokens: 65536 },
1857
- "gemini-3.5-flash-low": { modelEnum: "MODEL_PLACEHOLDER_M20", maxOutputTokens: 65536 },
1858
- "gemini-3-flash-agent": { modelEnum: "MODEL_PLACEHOLDER_M132", maxOutputTokens: 65536 },
1859
- "gemini-3.1-pro-low": { modelEnum: "MODEL_PLACEHOLDER_M36", maxOutputTokens: 65535 },
1860
- "gemini-pro-agent": { modelEnum: "MODEL_PLACEHOLDER_M16", maxOutputTokens: 65535 },
1861
- "claude-sonnet-5": { maxOutputTokens: 64e3 },
1862
- "claude-sonnet-4-6": { maxOutputTokens: 64e3 },
1863
- "claude-opus-4-6-thinking": { maxOutputTokens: 64e3 },
1864
- "gemini-2.5-flash": { maxOutputTokens: 65536 }
1865
- };
1866
- function resolveAntigravityWireModel(logicalModelId) {
1867
- const id = logicalModelId.trim();
1868
- const lower = id.toLowerCase();
1869
- if (lower === "gemini-3.5-flash") {
1870
- const wireModelId = "gemini-3.5-flash-low";
1871
- return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
1872
- }
1873
- if (lower === "gemini-3.7-flash" || ["gemini-3.7-flash-low", "gemini-3.7-flash-medium", "gemini-3.7-flash-high"].includes(lower)) {
1874
- const wireModelId = "gemini-3.7-flash-tiered";
1875
- return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
2002
+ function attemptWithAbort(args) {
2003
+ const externalSignal = args.externalSignal;
2004
+ if (!externalSignal) {
2005
+ return antigravityAttemptEffect(args);
1876
2006
  }
1877
- if (lower === "gemini-3.8-flash" || ["gemini-3.8-flash-low", "gemini-3.8-flash-medium", "gemini-3.8-flash-high"].includes(lower)) {
1878
- const wireModelId = "gemini-3.8-flash-tiered";
1879
- return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
1880
- }
1881
- if (lower === "gemini-3.6-flash") {
1882
- const wireModelId = "gemini-3.6-flash-low";
1883
- return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
1884
- }
1885
- if (lower === "gemini-3.1-pro" || lower === "gemini-3.1-pro-preview") {
1886
- const wireModelId = "gemini-3.1-pro-low";
1887
- return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
1888
- }
1889
- if (WIRE_PROFILES[id]) {
1890
- return { wireModelId: id, profile: WIRE_PROFILES[id] };
1891
- }
1892
- return { wireModelId: id };
1893
- }
1894
-
1895
- // packages/agent-runtime/geminiNativeShared.ts
1896
- var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
1897
- function resolveGeminiModelQuirks(modelId) {
1898
- const lower = modelId.toLowerCase();
1899
- const isGemini3 = lower.includes("gemini-3");
1900
- const isStrictSignatureModel = lower.includes("gemini-3.5") || lower.includes("flash-preview");
1901
- const isClaude = lower.includes("claude");
1902
- return {
1903
- requiresThoughtSignature: isGemini3,
1904
- allowsThoughtSignatureSentinel: isGemini3 && !isStrictSignatureModel,
1905
- isClaudeCrossModel: isClaude
2007
+ let abortListener;
2008
+ const removeAbortListener = () => {
2009
+ if (abortListener) externalSignal.removeEventListener("abort", abortListener);
2010
+ abortListener = void 0;
1906
2011
  };
1907
- }
1908
- function isGemini3Model(modelId) {
1909
- return resolveGeminiModelQuirks(modelId).requiresThoughtSignature;
1910
- }
1911
- function messageText(content) {
1912
- if (typeof content === "string") return content;
1913
- if (!Array.isArray(content)) return "";
1914
- return content.filter(
1915
- (part) => part?.type === "text"
1916
- ).map((part) => part.text).join("\n").trim();
1917
- }
1918
- function parseDataUrlToInlineData(url) {
1919
- const match = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
1920
- url
2012
+ const abortEffect = Effect_exports.callback((resume) => {
2013
+ const finish = () => resume(Effect_exports.succeed("aborted"));
2014
+ if (externalSignal.aborted) {
2015
+ finish();
2016
+ return;
2017
+ }
2018
+ abortListener = () => finish();
2019
+ externalSignal.addEventListener("abort", abortListener, { once: true });
2020
+ return Effect_exports.sync(removeAbortListener);
2021
+ }).pipe(Effect_exports.ensuring(Effect_exports.sync(removeAbortListener)));
2022
+ return Effect_exports.raceFirst(
2023
+ antigravityAttemptEffect(args),
2024
+ abortEffect
1921
2025
  );
1922
- if (!match) return null;
1923
- return { mimeType: match[1], data: match[2] };
1924
2026
  }
1925
- function extractInlineDataParts(content) {
1926
- if (!Array.isArray(content)) return [];
1927
- const parts = [];
1928
- for (const part of content) {
1929
- if (!part || typeof part !== "object") continue;
1930
- if (part.type !== "image_url") continue;
1931
- const url = part.image_url?.url;
1932
- if (typeof url !== "string" || !url.trim()) continue;
1933
- const inline = parseDataUrlToInlineData(url);
1934
- if (inline) parts.push({ inlineData: inline });
1935
- }
1936
- return parts;
1937
- }
1938
- function convertOpenAiMessagesToGemini(messages, options) {
1939
- const contents = [];
1940
- const systemTexts = [];
1941
- let toolCallIndex = 0;
1942
- let pendingFunctionCalls = [];
1943
- const pushOrMergeContent = (role, parts) => {
1944
- if (parts.length === 0) return;
1945
- const last = contents[contents.length - 1];
1946
- if (last && last.role === role) {
1947
- last.parts.push(...parts);
1948
- } else {
1949
- contents.push({ role, parts });
1950
- }
1951
- };
1952
- const flushPendingFunctionCalls = () => {
1953
- if (pendingFunctionCalls.length === 0) return;
1954
- const dummyResponses = pendingFunctionCalls.map(
1955
- ({ name, id }) => ({
1956
- functionResponse: {
1957
- name,
1958
- response: { output: "{}" },
1959
- ...id ? { id } : {}
1960
- }
1961
- })
2027
+ function invokeAntigravityEffect(args) {
2028
+ const authRetryable = args.authRetryableStatuses ?? AUTH_RETRYABLE_STATUSES;
2029
+ const timeoutMs = typeof args.timeoutMs === "number" && args.timeoutMs > 0 ? args.timeoutMs : void 0;
2030
+ const runOneAttempt = (credential) => Effect_exports.suspend(
2031
+ () => attemptWithAbort({
2032
+ agentConfig: args.agentConfig,
2033
+ credential,
2034
+ openAiBody: args.openAiBody,
2035
+ externalSignal: args.signal,
2036
+ fetchImpl: args.fetchImpl ?? fetch,
2037
+ ...args.onTextDelta ? { onTextDelta: args.onTextDelta } : {},
2038
+ ...args.onReasoningDelta ? { onReasoningDelta: args.onReasoningDelta } : {}
2039
+ })
2040
+ );
2041
+ const orchestration = Effect_exports.gen(function* () {
2042
+ const firstCredential = yield* Effect_exports.tryPromise({
2043
+ try: () => args.resolveCredential({ forceRefresh: false }),
2044
+ catch: (error) => error
2045
+ });
2046
+ const first = yield* Effect_exports.exit(
2047
+ runOneAttempt(firstCredential)
1962
2048
  );
1963
- pendingFunctionCalls = [];
1964
- pushOrMergeContent("user", dummyResponses);
1965
- };
1966
- for (const raw of messages) {
1967
- if (!raw || typeof raw !== "object" || !("role" in raw)) continue;
1968
- const role = String(raw.role);
1969
- const content = "content" in raw ? raw.content : null;
1970
- if (role === "system") {
1971
- const text = messageText(
1972
- content
1973
- );
1974
- if (text) systemTexts.push(text);
1975
- continue;
1976
- }
1977
- if (role === "user") {
1978
- flushPendingFunctionCalls();
1979
- const text = messageText(
1980
- content
1981
- );
1982
- const imageParts = extractInlineDataParts(
1983
- content
1984
- );
1985
- if (!text && imageParts.length === 0) continue;
1986
- const parts = [];
1987
- if (text) parts.push({ text });
1988
- for (const img of imageParts) parts.push(img);
1989
- pushOrMergeContent("user", parts);
1990
- continue;
1991
- }
1992
- if (role === "assistant") {
1993
- flushPendingFunctionCalls();
1994
- const text = messageText(
1995
- content
2049
+ if (Exit_exports.isFailure(first)) {
2050
+ const errorOption = Exit_exports.findErrorOption(first);
2051
+ const error = Option_exports.isSome(errorOption) ? errorOption.value : first.cause;
2052
+ if (isAntigravityAbortErrorValue(error)) {
2053
+ return { kind: "aborted" };
2054
+ }
2055
+ return { kind: "failed", error };
2056
+ }
2057
+ let current = first.value;
2058
+ if (typeof current !== "string" && supportsAuthRetry(args.supportsAuthRetry, current.status, authRetryable)) {
2059
+ const refreshed = yield* Effect_exports.exit(
2060
+ Effect_exports.tryPromise({
2061
+ try: () => args.resolveCredential({ forceRefresh: true }),
2062
+ catch: (error) => error
2063
+ })
1996
2064
  );
1997
- const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
1998
- const parts = [];
1999
- if (text) {
2000
- parts.push({ text });
2001
- }
2002
- for (const call of toolCalls) {
2003
- const name = call?.function?.name?.trim();
2004
- if (!name) continue;
2005
- const id = call.id?.trim() || `${name}_${toolCallIndex++}`;
2006
- pendingFunctionCalls.push({ name, id });
2007
- const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
2008
- const isFirstFunctionCallPart = !parts.some(
2009
- (p) => "functionCall" in p
2065
+ if (Exit_exports.isSuccess(refreshed) && credentialChanged(firstCredential, refreshed.value)) {
2066
+ const retried = yield* Effect_exports.exit(
2067
+ runOneAttempt(refreshed.value)
2010
2068
  );
2011
- const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
2012
- const part = {
2013
- functionCall: {
2014
- name,
2015
- args: parseToolArgs(call.function?.arguments),
2016
- ...id ? { id } : {}
2017
- },
2018
- ...signature ? { thoughtSignature: signature } : {}
2019
- };
2020
- parts.push(part);
2021
- }
2022
- pushOrMergeContent("model", parts);
2023
- continue;
2024
- }
2025
- if (role === "tool") {
2026
- const toolCallId = "tool_call_id" in raw && typeof raw.tool_call_id === "string" ? raw.tool_call_id : "";
2027
- const rawName = "name" in raw && typeof raw.name === "string" ? raw.name.trim() : "";
2028
- const pendingIndex = pendingFunctionCalls.findIndex(
2029
- (p) => toolCallId ? p.id === toolCallId : rawName ? p.name === rawName : true
2030
- );
2031
- if (pendingIndex === -1) continue;
2032
- const [{ name, id }] = pendingFunctionCalls.splice(pendingIndex, 1);
2033
- const output = messageText(content) || "{}";
2034
- pushOrMergeContent("user", [
2035
- {
2036
- functionResponse: {
2037
- name,
2038
- response: { output },
2039
- // 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
2040
- // Gemini contents 转成 Claude messages 时需要 functionResponse →
2041
- // tool_result 的 tool_use_id;缺 id 时网关报
2042
- // "tool_result.tool_use_id: Field required"(HTTP 400)。
2043
- ...id ? { id } : {}
2044
- }
2069
+ if (Exit_exports.isSuccess(retried)) {
2070
+ current = retried.value;
2045
2071
  }
2046
- ]);
2047
- }
2048
- }
2049
- flushPendingFunctionCalls();
2050
- if (contents.length > 0 && contents[0]?.role === "model") {
2051
- contents.unshift({
2052
- role: "user",
2053
- parts: [{ text: "Continue the conversation." }]
2054
- });
2055
- }
2056
- return { contents, systemTexts };
2057
- }
2058
- function parseToolArgs(raw) {
2059
- if (typeof raw === "string") {
2060
- try {
2061
- const parsed = JSON.parse(raw);
2062
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
2063
- return parsed;
2064
2072
  }
2065
- } catch {
2066
2073
  }
2067
- }
2068
- if (raw && typeof raw === "object" && !Array.isArray(raw)) {
2069
- return raw;
2070
- }
2071
- return {};
2074
+ if (current === "aborted") return { kind: "aborted" };
2075
+ return { kind: "done", result: current };
2076
+ }).pipe(Effect_exports.catch((error) => Effect_exports.succeed({
2077
+ kind: "failed",
2078
+ error
2079
+ })));
2080
+ if (typeof timeoutMs !== "number") return orchestration;
2081
+ return Effect_exports.gen(function* () {
2082
+ const outcome = yield* Effect_exports.timeoutOption(orchestration, Duration_exports.millis(timeoutMs));
2083
+ return Option_exports.isNone(outcome) ? { kind: "timeout" } : outcome.value;
2084
+ });
2072
2085
  }
2073
- function convertOpenAiToolsToGemini(tools) {
2074
- if (!Array.isArray(tools) || tools.length === 0) return void 0;
2075
- const declarations = [];
2076
- for (const tool of tools) {
2077
- if (!tool || typeof tool !== "object" || !("function" in tool)) continue;
2078
- const fn = tool.function;
2079
- const name = typeof fn.name === "string" ? fn.name : "";
2080
- if (!name) continue;
2081
- declarations.push({
2082
- name,
2083
- description: typeof fn.description === "string" ? fn.description : "",
2084
- parameters: fn.parameters ?? { type: "object", properties: {} }
2085
- });
2086
- }
2087
- if (declarations.length === 0) return void 0;
2088
- return [{ functionDeclarations: declarations }];
2086
+ function supportsAuthRetry(supports, status, authRetryable) {
2087
+ return supports && authRetryable.has(status);
2089
2088
  }
2090
- function createGeminiAccumulatorState() {
2091
- return {
2092
- text: "",
2093
- toolCalls: []
2094
- };
2089
+ function isAntigravityAbortErrorValue(error) {
2090
+ const code = error?.code;
2091
+ return code === "ANTIGRAVITY_INVOCATION_ABORTED" || error instanceof Error && error.name === "AbortError" || typeof DOMException !== "undefined" && error instanceof DOMException && error.name === "AbortError";
2095
2092
  }
2096
- function applyGeminiChunk(chunk, state, options) {
2097
- if (!chunk || typeof chunk !== "object") return;
2098
- const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
2099
- if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
2100
- const meta = response.usageMetadata;
2101
- const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
2102
- const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
2103
- const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
2104
- const cached = typeof meta.cachedContentTokenCount === "number" && Number.isFinite(meta.cachedContentTokenCount) ? (
2105
- // cached ⊆ prompt;对畸形上游防御性钳位,避免 cache_read > input 破坏归一化与计费
2106
- Math.min(Math.max(0, Math.floor(meta.cachedContentTokenCount)), prompt)
2107
- ) : 0;
2108
- state.usage = {
2109
- prompt_tokens: prompt,
2110
- completion_tokens: candidates2,
2111
- total_tokens: total,
2112
- ...cached > 0 ? { cache_read_input_tokens: cached } : {}
2113
- };
2093
+ function credentialChanged(before, after) {
2094
+ return before.accessToken !== after.accessToken || before.accountId !== after.accountId || before.projectId !== after.projectId || JSON.stringify(before.metadata) !== JSON.stringify(after.metadata);
2095
+ }
2096
+ async function invokeAntigravity(args) {
2097
+ const outcome = await (args.runtime ? args.runtime.runPromise(invokeAntigravityEffect(args)) : Effect_exports.runPromise(invokeAntigravityEffect(args)));
2098
+ if (outcome.kind === "done") return outcome.result;
2099
+ if (outcome.kind === "timeout") {
2100
+ throw buildInvocationError("ANTIGRAVITY_INVOCATION_TIMEOUT", "Antigravity invocation timed out.");
2114
2101
  }
2115
- const candidates = Array.isArray(response.candidates) ? response.candidates : [];
2116
- for (const candidate of candidates) {
2117
- if (!candidate || typeof candidate !== "object") continue;
2118
- const parts = Array.isArray(
2119
- candidate.content?.parts
2120
- ) ? candidate.content.parts : [];
2121
- for (const part of parts) {
2122
- if (!part || typeof part !== "object") continue;
2123
- const partSignature = part.thoughtSignature;
2124
- const isThought = Boolean(part.thought);
2125
- if ("text" in part && typeof part.text === "string") {
2126
- const piece = part.text;
2127
- if (!isThought) {
2128
- state.text += piece;
2129
- if (piece && options?.onTextDelta) {
2130
- options.onTextDelta(piece);
2131
- }
2132
- } else {
2133
- if (piece && options?.onReasoningDelta) {
2134
- options.onReasoningDelta(piece);
2135
- }
2136
- }
2137
- }
2138
- if (isThought && typeof partSignature === "string" && partSignature) {
2139
- state.pendingThoughtSignature = partSignature;
2140
- }
2141
- if ("functionCall" in part && part.functionCall) {
2142
- const call = part.functionCall;
2143
- const name = typeof call.name === "string" ? call.name : "tool";
2144
- const id = typeof call.id === "string" ? call.id : `${name}_${state.toolCalls.length}`;
2145
- const argsObj = call.args && typeof call.args === "object" ? call.args : {};
2146
- const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : state.pendingThoughtSignature;
2147
- state.pendingThoughtSignature = void 0;
2148
- state.toolCalls.push({
2149
- id,
2150
- type: "function",
2151
- function: { name, arguments: JSON.stringify(argsObj) },
2152
- ...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
2153
- });
2154
- }
2155
- }
2102
+ if (outcome.kind === "aborted") {
2103
+ throw buildInvocationError("ANTIGRAVITY_INVOCATION_ABORTED", "Antigravity invocation aborted.");
2156
2104
  }
2105
+ throw outcome.error ?? new Error("Antigravity invocation failed.");
2157
2106
  }
2158
- function accumulateGeminiChunks(chunks, options) {
2159
- const state = createGeminiAccumulatorState();
2160
- for (const chunk of chunks) {
2161
- applyGeminiChunk(chunk, state, options);
2162
- }
2163
- return {
2164
- text: state.text,
2165
- toolCalls: state.toolCalls,
2166
- usage: state.usage
2167
- };
2107
+ function buildInvocationError(code, message) {
2108
+ const error = new Error(message);
2109
+ error.code = code;
2110
+ return error;
2168
2111
  }
2169
- async function accumulateGeminiStream(stream, options) {
2170
- const state = createGeminiAccumulatorState();
2171
- for await (const chunk of stream) {
2172
- applyGeminiChunk(chunk, state, options);
2173
- }
2112
+ function isAntigravityInvocationAbortError(error) {
2113
+ const code = error?.code;
2114
+ return error instanceof Error && (code === "ANTIGRAVITY_INVOCATION_ABORTED" || code === "ANTIGRAVITY_INVOCATION_TIMEOUT");
2115
+ }
2116
+
2117
+ // packages/agent-runtime/antigravityCredential.ts
2118
+ function createAntigravityCredentialPlan(args) {
2119
+ const owner = asOptionalTrimmedString(args.credentialOwnerUserId);
2120
+ if (!owner) throw new Error("Antigravity credential owner is required.");
2174
2121
  return {
2175
- text: state.text,
2176
- toolCalls: state.toolCalls,
2177
- usage: state.usage
2122
+ provider: "antigravity",
2123
+ credentialOwnerUserId: owner,
2124
+ source: args.source,
2125
+ forceRefresh: args.forceRefresh === true
2178
2126
  };
2179
2127
  }
2180
- function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
2181
- return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
2182
- }
2183
- function buildGeminiGenerateContentRequest(args) {
2184
- const { contents, systemTexts } = convertOpenAiMessagesToGemini(
2185
- args.messages,
2186
- { attachSkipThoughtSignature: args.attachSkipThoughtSignature }
2187
- );
2188
- const request = { contents };
2189
- if (systemTexts.length > 0) {
2190
- request.systemInstruction = {
2191
- role: "user",
2192
- parts: systemTexts.map((text) => ({ text }))
2193
- };
2128
+ function resolveAntigravityCredential(args) {
2129
+ if (args.plan.provider !== "antigravity") {
2130
+ throw new Error("Unsupported Antigravity credential plan provider.");
2194
2131
  }
2195
- const toolsResult = convertOpenAiToolsToGemini(args.tools);
2196
- if (toolsResult) {
2197
- request.tools = toolsResult;
2198
- request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
2199
- }
2200
- const generationConfig = {};
2201
- if (typeof args.maxTokens === "number" && args.maxTokens > 0) {
2202
- generationConfig.maxOutputTokens = args.maxTokens;
2203
- }
2204
- if (typeof args.temperature === "number") {
2205
- generationConfig.temperature = args.temperature;
2206
- }
2207
- if (Object.keys(generationConfig).length > 0) {
2208
- request.generationConfig = generationConfig;
2209
- }
2210
- return request;
2132
+ return toResolvedAntigravityCredential(args);
2211
2133
  }
2212
-
2213
- // packages/agent-runtime/antigravityCloudCodeProvider.ts
2214
- var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
2215
- function buildCloudCodeAssistPayload(args) {
2216
- const projectId = readAntigravityProjectId(args.metadata);
2134
+ function toResolvedAntigravityCredential(args) {
2135
+ const accessToken = asOptionalTrimmedString(args.accessToken);
2136
+ const projectId = asOptionalTrimmedString(args.metadata?.projectId);
2137
+ if (!accessToken) throw new Error("Antigravity credential access token is missing.");
2217
2138
  if (!projectId) {
2218
2139
  throw new Error(
2219
2140
  "Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
2220
2141
  );
2221
2142
  }
2222
- const logicalModel = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gemini-3.1-pro";
2223
- const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
2224
- const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
2225
- const quirks = resolveGeminiModelQuirks(model);
2226
- const isClaude = quirks.isClaudeCrossModel;
2227
- const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
2228
- attachSkipThoughtSignature: quirks.allowsThoughtSignatureSentinel
2229
- });
2230
- if (contents.length === 0) {
2231
- throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
2232
- }
2233
- const prompt = args.agentConfig.prompt?.trim();
2234
- if (prompt) systemTexts.unshift(prompt);
2235
- const request = { contents };
2236
- if (systemTexts.length > 0) {
2237
- request.systemInstruction = {
2238
- role: "user",
2239
- parts: systemTexts.map((text) => ({ text }))
2240
- };
2241
- }
2242
- const tools = convertOpenAiToolsToGemini(
2243
- Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
2244
- );
2245
- if (tools) {
2246
- request.tools = tools;
2247
- request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
2248
- }
2249
- const generationConfig = {};
2250
- if (profile?.maxOutputTokens) {
2251
- generationConfig.maxOutputTokens = profile.maxOutputTokens;
2252
- } else if (typeof args.agentConfig.max_tokens === "number" && args.agentConfig.max_tokens > 0) {
2253
- generationConfig.maxOutputTokens = args.agentConfig.max_tokens;
2254
- }
2255
- if (typeof args.agentConfig.temperature === "number") {
2256
- generationConfig.temperature = args.agentConfig.temperature;
2257
- }
2258
- if (Object.keys(generationConfig).length > 0) {
2259
- request.generationConfig = generationConfig;
2260
- }
2261
- const agentId = randomUUID2();
2262
- const trajectoryId = randomUUID2();
2263
- const step = 2;
2264
- const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
2265
- const labels = {
2266
- trajectory_id: trajectoryId,
2267
- last_step_index: String(step - 1),
2268
- used_claude: String(isClaude),
2269
- used_claude_conservative: String(isClaude)
2270
- };
2271
- if (profile?.modelEnum) {
2272
- labels.model_enum = profile.modelEnum;
2273
- }
2274
- request.labels = labels;
2275
- request.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
2276
2143
  return {
2277
- url: `${resolveAntigravityCloudCodeBaseUrl(args.agentConfig.customProviderUrl)}${STREAM_PATH}`,
2278
- envelope: {
2279
- project: projectId,
2280
- model,
2281
- request,
2282
- requestId,
2283
- requestType: "agent",
2284
- userAgent: "antigravity"
2285
- }
2144
+ provider: "antigravity",
2145
+ accessToken,
2146
+ projectId,
2147
+ metadata: { ...args.metadata ?? {}, projectId },
2148
+ accountId: asOptionalTrimmedString(args.accountId) ?? null
2286
2149
  };
2287
2150
  }
2288
- async function fetchAntigravityCloudCodeCompletion(args) {
2289
- const fetchImpl = args.fetchImpl ?? fetch;
2290
- const { url, envelope } = buildCloudCodeAssistPayload(args);
2291
- const response = await fetchImpl(url, {
2292
- method: "POST",
2293
- headers: {
2294
- Authorization: `Bearer ${args.accessToken}`,
2295
- "Content-Type": "application/json",
2296
- "User-Agent": getAntigravityUserAgent()
2297
- },
2298
- body: JSON.stringify(envelope),
2299
- signal: args.signal
2300
- });
2301
- if (!response.ok) {
2302
- const errorText = await response.text();
2303
- return {
2304
- status: response.status,
2305
- // 保留上游结构:Antigravity 的限流 body 同样携带结构化的重置信息,
2306
- // 压成字符串会让冷却退化成 5 分钟默认值。
2307
- body: parseUpstreamErrorBody(errorText, response.statusText)
2308
- };
2309
- }
2310
- const chunkStream = streamSseDataValues(response, parseSseDataLineJson);
2311
- const { text, toolCalls, usage } = await accumulateGeminiStream(chunkStream, {
2312
- onTextDelta: args.onTextDelta,
2313
- onReasoningDelta: args.onReasoningDelta
2314
- });
2315
- const message = {
2316
- role: "assistant",
2317
- content: text || null
2318
- };
2319
- if (toolCalls.length > 0) {
2320
- message.tool_calls = toolCalls;
2151
+ async function resolveLocalAntigravityCredential(args) {
2152
+ const rawRef = asTrimmedLowercaseString(args.apiKeyRef);
2153
+ const isApiKeyRef = rawRef.startsWith("api-key:");
2154
+ const providerRef = isApiKeyRef ? rawRef : rawRef || "antigravity";
2155
+ if (isApiKeyRef && args.forceRefresh) {
2156
+ throw new Error(`Cannot force-refresh non-OAuth API key ref "${rawRef}".`);
2321
2157
  }
2322
- return {
2323
- status: 200,
2324
- body: {
2325
- choices: [
2326
- {
2327
- index: 0,
2328
- message,
2329
- finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop"
2330
- }
2331
- ],
2332
- ...usage ? { usage } : {}
2158
+ const token = await args.apiKeyRefResolver(
2159
+ providerRef,
2160
+ args.forceRefresh ? { force: true } : void 0
2161
+ );
2162
+ const trimmedToken = asOptionalTrimmedString(token);
2163
+ if (!trimmedToken) {
2164
+ if (isApiKeyRef) {
2165
+ throw new Error(`API key for "${rawRef}" not found locally.`);
2333
2166
  }
2334
- };
2167
+ throw new Error(
2168
+ 'OAuth credential for "antigravity" not found locally. Run `nolo auth antigravity`.'
2169
+ );
2170
+ }
2171
+ const read = args.readCredential ?? readOAuthCredential;
2172
+ const raw = read("antigravity");
2173
+ const plan = createAntigravityCredentialPlan({
2174
+ credentialOwnerUserId: args.credentialOwnerUserId || "local",
2175
+ source: args.source || "local",
2176
+ forceRefresh: args.forceRefresh === true
2177
+ });
2178
+ return resolveAntigravityCredential({
2179
+ plan,
2180
+ accessToken: trimmedToken,
2181
+ metadata: raw?.metadata ?? args.metadata ?? null,
2182
+ accountId: raw?.accountId ?? args.accountId ?? null
2183
+ });
2335
2184
  }
2336
2185
 
2337
2186
  // packages/core/summarizeEndpoint.ts
@@ -2345,21 +2194,98 @@ function summarizeEndpoint(value) {
2345
2194
  }
2346
2195
  }
2347
2196
 
2197
+ // packages/cli/client/localRuntimeHelpers.ts
2198
+ var REMOTE_DIALOG_SYNC_TIMEOUT_MS = 1e4;
2199
+ var remoteDialogSyncTimeoutMsForTest;
2200
+ function remoteDialogSyncTimeout() {
2201
+ return remoteDialogSyncTimeoutMsForTest ?? REMOTE_DIALOG_SYNC_TIMEOUT_MS;
2202
+ }
2203
+ function resolveRuntimeServerUrl(env) {
2204
+ return (env?.NOLO_SERVER_URL || env?.NOLO_SERVER || env?.BASE_URL || "").replace(/\/+$/, "");
2205
+ }
2206
+ function resolveRuntimeAuthToken(env) {
2207
+ return resolvePlatformAuthToken(env ?? {});
2208
+ }
2209
+
2210
+ // packages/cli/client/cliAgentConfigHelpers.ts
2211
+ var BUILTIN_NOLO_AGENT_KEY = NOLO_DEFAULT_AGENT_KEY;
2212
+ var BUILTIN_NOLO_AGENT_ID = NOLO_DEFAULT_AGENT_ID;
2213
+ function resolveLocalUserId(env) {
2214
+ const explicitUserId = env.NOLO_LOCAL_USER_ID || env.NOLO_USER_ID;
2215
+ if (explicitUserId) return explicitUserId;
2216
+ const tokenUserId = parseUserIdFromAuthToken(resolveRuntimeAuthToken(env));
2217
+ return tokenUserId || "local";
2218
+ }
2219
+ function isBuiltinNoloAgentRef(ref) {
2220
+ if (typeof ref !== "string") return false;
2221
+ const normalized = ref.trim();
2222
+ return normalized === BUILTIN_NOLO_AGENT_KEY || normalized === BUILTIN_NOLO_AGENT_ID || normalized.endsWith(`-${BUILTIN_NOLO_AGENT_ID}`);
2223
+ }
2224
+ function isBuiltinNoloAgentConfig(agentConfig) {
2225
+ const key = agentConfig?.key || agentConfig?.rawRecord?.dbKey || agentConfig?.rawRecord?.agentKey;
2226
+ const id = agentConfig?.rawRecord?.id;
2227
+ return isBuiltinNoloAgentRef(key) || isBuiltinNoloAgentRef(id);
2228
+ }
2229
+ function withResolvedRuntimeToolSurface(agentConfig, env) {
2230
+ if (!agentConfig) return agentConfig;
2231
+ const currentUserId = resolveLocalUserId(env);
2232
+ const rawRecord = agentConfig.rawRecord ?? {};
2233
+ const ownerId = asOptionalTrimmedString(rawRecord.userId) ?? null;
2234
+ const agentKey = rawRecord.dbKey ?? agentConfig.key;
2235
+ const toolSurface = resolveRuntimeToolSurfaceForAgent({
2236
+ explicitToolNames: agentConfig.toolNames,
2237
+ currentUserId,
2238
+ agentOwnerId: ownerId,
2239
+ agentKey,
2240
+ isPublic: !isBuiltinNoloAgentConfig(agentConfig) && rawRecord.isPublic === true,
2241
+ sharingLevel: typeof rawRecord.sharingLevel === "string" ? rawRecord.sharingLevel : null,
2242
+ trustedPrivateInvocation: isBuiltinNoloAgentConfig(agentConfig) || isSystemBuiltinTrustedAgentKey(agentKey),
2243
+ runtimeHost: "cli"
2244
+ });
2245
+ return {
2246
+ ...agentConfig,
2247
+ toolNames: toolSurface.finalToolNames,
2248
+ toolSurface,
2249
+ prompt: agentConfig.prompt
2250
+ };
2251
+ }
2252
+ function extractLastUserText(messages) {
2253
+ const lastUser = [...messages].reverse().find((m) => m.role === "user");
2254
+ if (!lastUser) return "";
2255
+ if (typeof lastUser.content === "string") return lastUser.content;
2256
+ if (Array.isArray(lastUser.content)) {
2257
+ return lastUser.content.filter((part) => part?.type === "text").map((part) => part.text ?? "").join(" ");
2258
+ }
2259
+ return "";
2260
+ }
2261
+ function localTurnHasSubjectRefs(input) {
2262
+ return Array.isArray(input.runtimeContext?.subjectRefs) && input.runtimeContext.subjectRefs.length > 0;
2263
+ }
2264
+
2348
2265
  // packages/cli/client/providerResolution/antigravityTransport.ts
2349
2266
  var resolveAntigravityTransport = async (ctx) => {
2350
- const { agentConfig, deps, fetchImpl, loopbackRequest, additionalToolNames, buildProviderOpenAiTools, recordLocalAvailability, apiKeyRefResolver } = ctx;
2267
+ const {
2268
+ agentConfig,
2269
+ deps,
2270
+ fetchImpl,
2271
+ loopbackRequest,
2272
+ additionalToolNames,
2273
+ buildProviderOpenAiTools,
2274
+ recordLocalAvailability,
2275
+ apiKeyRefResolver
2276
+ } = ctx;
2277
+ const legacyCredentialMigration = { enableLegacyMigration: true };
2351
2278
  if (isAntigravityOAuthAgent(agentConfig)) {
2352
- const resolveAccessToken = async () => {
2353
- const accessToken = await apiKeyRefResolver("antigravity");
2354
- if (!accessToken) {
2355
- throw new Error(
2356
- 'OAuth credential for "antigravity" not found locally. Run `nolo auth antigravity`.'
2357
- );
2358
- }
2359
- return accessToken;
2360
- };
2361
- await resolveAccessToken();
2362
- const credential = readOAuthCredential("antigravity");
2279
+ const credentialOwnerUserId = resolveLocalUserId(deps.env) || "local";
2280
+ const apiKeyRef = asTrimmedLowercaseString(agentConfig.apiKeyRef);
2281
+ const isApiKeyRef = apiKeyRef.startsWith("api-key:");
2282
+ const initialCredential = await resolveLocalAntigravityCredential({
2283
+ credentialOwnerUserId,
2284
+ apiKeyRefResolver,
2285
+ apiKeyRef: agentConfig.apiKeyRef,
2286
+ readCredential: () => readOAuthCredential("antigravity", void 0, legacyCredentialMigration),
2287
+ migration: legacyCredentialMigration
2288
+ });
2363
2289
  const { requestedToolNames, tools } = resolveProviderOpenAiToolBundle(
2364
2290
  agentConfig,
2365
2291
  deps.env,
@@ -2374,7 +2300,7 @@ var resolveAntigravityTransport = async (ctx) => {
2374
2300
  model: agentConfig.model ?? null,
2375
2301
  customProviderEndpoint: summarizeEndpoint(agentConfig.customProviderUrl) ?? null,
2376
2302
  hasApiKey: true,
2377
- hasProjectId: Boolean(credential?.metadata?.projectId)
2303
+ hasProjectId: Boolean(initialCredential?.projectId)
2378
2304
  });
2379
2305
  return {
2380
2306
  model: agentConfig.model || "gemini-3.1-pro",
@@ -2394,52 +2320,79 @@ var resolveAntigravityTransport = async (ctx) => {
2394
2320
  requestedToolNames,
2395
2321
  openAiToolNames: summarizeOpenAiToolNames(tools)
2396
2322
  });
2397
- const accessToken = await resolveAccessToken();
2398
- const sendCcaRequest = (token) => fetchAntigravityCloudCodeCompletion({
2399
- agentConfig,
2400
- accessToken: token,
2401
- metadata: credential?.metadata ?? null,
2402
- openAiBody,
2403
- signal: options?.signal,
2404
- onTextDelta: options?.onTextDelta,
2405
- onReasoningDelta: options?.onReasoningDelta,
2406
- fetchImpl: (url, init) => fetchWithTransientRetry(fetchImpl, url, init, {
2407
- sleep: deps.sleep,
2408
- loopbackRequest
2409
- })
2323
+ const resolveLocalCredential = async ({ forceRefresh }) => resolveLocalAntigravityCredential({
2324
+ credentialOwnerUserId,
2325
+ apiKeyRefResolver,
2326
+ apiKeyRef: agentConfig.apiKeyRef,
2327
+ readCredential: () => readOAuthCredential("antigravity", void 0, legacyCredentialMigration),
2328
+ migration: legacyCredentialMigration,
2329
+ forceRefresh
2410
2330
  });
2411
- let result = await sendCcaRequest(accessToken);
2412
- if (result.status === 401) {
2413
- try {
2414
- const refreshed = await apiKeyRefResolver("antigravity", {
2415
- force: true
2416
- });
2417
- if (refreshed && refreshed !== accessToken) {
2418
- logLocalRuntimeDiagnostic("provider.request.auth_retry", {
2419
- agentKey: agentConfig.key,
2420
- transport: "antigravity-cloud-code"
2421
- });
2422
- result = await sendCcaRequest(refreshed);
2423
- }
2424
- } catch (error) {
2425
- logLocalRuntimeDiagnostic("provider.request.auth_retry_failed", {
2426
- agentKey: agentConfig.key,
2427
- transport: "antigravity-cloud-code",
2428
- error: toErrorMessage(error)
2429
- });
2430
- }
2331
+ let result;
2332
+ try {
2333
+ result = await invokeAntigravity({
2334
+ agentConfig,
2335
+ resolveCredential: resolveLocalCredential,
2336
+ // 非 OAuth(api-key ref)不重试:metered key 没有 refresh 语义。
2337
+ supportsAuthRetry: !isApiKeyRef,
2338
+ openAiBody,
2339
+ ...options?.signal ? { signal: options.signal } : {},
2340
+ // whole-invocation timeout 透传:seam 最外层 timeoutOption 统一 interrupt
2341
+ // 整个 orchestration(resolve/attempt/refresh 共享预算)并真实 abort fetch/SSE。
2342
+ ...typeof options?.timeoutMs === "number" ? { timeoutMs: options.timeoutMs } : {},
2343
+ onTextDelta: options?.onTextDelta,
2344
+ onReasoningDelta: options?.onReasoningDelta,
2345
+ fetchImpl: (url, init) => fetchWithTransientRetry(fetchImpl, url, init, {
2346
+ sleep: deps.sleep,
2347
+ loopbackRequest
2348
+ })
2349
+ });
2350
+ } catch (error) {
2351
+ if (isAntigravityInvocationAbortError(error)) throw error;
2352
+ logLocalRuntimeDiagnostic("provider.request.result", {
2353
+ agentKey: agentConfig.key,
2354
+ transport: "antigravity-cloud-code",
2355
+ ok: false,
2356
+ error: toErrorMessage(error)
2357
+ });
2358
+ throw error;
2431
2359
  }
2432
2360
  await recordLocalAvailability(result.status, result.body);
2361
+ if (result.providerFailure) {
2362
+ logLocalRuntimeDiagnostic("provider.request.failure", {
2363
+ agentKey: agentConfig.key,
2364
+ transport: "antigravity-cloud-code",
2365
+ code: result.providerFailure.code,
2366
+ providerReason: result.providerFailure.providerReason,
2367
+ retryable: result.providerFailure.retryable
2368
+ });
2369
+ return {
2370
+ content: "",
2371
+ model: agentConfig.model || "gemini-3.1-pro",
2372
+ provider: agentConfig.provider || "google-antigravity",
2373
+ finish_reason: "error",
2374
+ stream_complete: true,
2375
+ error: true,
2376
+ errorMessage: result.providerFailure.message,
2377
+ providerEvents: result.providerEvents,
2378
+ providerFailure: result.providerFailure,
2379
+ runtimeProviderFailure: result.runtimeProviderFailure,
2380
+ trace: messages
2381
+ };
2382
+ }
2433
2383
  if (result.status < 200 || result.status >= 300) {
2434
2384
  const errMsg = result.body && typeof result.body === "object" && result.body.error && typeof result.body.error.message === "string" ? result.body.error.message : JSON.stringify(result.body);
2435
2385
  throw new Error(
2436
2386
  `local antigravity provider failed: HTTP ${result.status} ${errMsg}`
2437
2387
  );
2438
2388
  }
2439
- const choice = Array.isArray(result.body.choices) ? result.body.choices[0] : void 0;
2389
+ const choice = Array.isArray(result.body?.choices) ? result.body.choices[0] : void 0;
2440
2390
  const message = choice?.message ?? {};
2441
- const content = typeof message.content === "string" ? message.content : message.content == null ? "" : String(message.content);
2442
- const tool_calls = Array.isArray(message.tool_calls) ? message.tool_calls : void 0;
2391
+ const tool_calls = Array.isArray(result.toolCalls) && result.toolCalls.length > 0 ? result.toolCalls : Array.isArray(message.tool_calls) ? message.tool_calls : void 0;
2392
+ const content = typeof result.text === "string" ? result.text : typeof message.content === "string" ? message.content : message.content == null ? "" : String(message.content);
2393
+ const reasoning_content = typeof result.reasoningContent === "string" ? result.reasoningContent : typeof message.reasoning_content === "string" ? message.reasoning_content : void 0;
2394
+ const finish_reason = tool_calls && tool_calls.length > 0 ? "tool_calls" : typeof result.finishReason === "string" ? resolveAntigravityFinishReason(result.finishReason) : typeof choice?.finish_reason === "string" ? choice.finish_reason : void 0;
2395
+ const usage = result.usage ?? result.body?.usage;
2443
2396
  logLocalRuntimeDiagnostic("provider.request.result", {
2444
2397
  agentKey: agentConfig.key,
2445
2398
  transport: "antigravity-cloud-code",
@@ -2452,12 +2405,14 @@ var resolveAntigravityTransport = async (ctx) => {
2452
2405
  model: agentConfig.model || "gemini-3.1-pro",
2453
2406
  provider: agentConfig.provider || "google-antigravity",
2454
2407
  ...tool_calls ? { tool_calls } : {},
2455
- // fetchAntigravityCloudCodeCompletion 已把 CCA 流聚合完毕并归一化成
2456
- // OpenAI chat.completions 形状:choices[0] + usage
2457
- // (prompt_tokens/completion_tokens/total_tokens)。必须透传,否则
2458
- // localLoop lastUsage token 数,TUI context chip 拿不到更新。
2459
- usage: result.body?.usage,
2460
- trace: messages
2408
+ ...reasoning_content ? { reasoning_content } : {},
2409
+ finish_reason,
2410
+ stream_complete: true,
2411
+ ...usage ? { usage } : {},
2412
+ trace: messages,
2413
+ providerEvents: result.providerEvents,
2414
+ ...result.providerFailure ? { providerFailure: result.providerFailure } : {},
2415
+ ...result.runtimeProviderFailure ? { runtimeProviderFailure: result.runtimeProviderFailure } : {}
2461
2416
  };
2462
2417
  }
2463
2418
  };
@@ -2465,14 +2420,136 @@ var resolveAntigravityTransport = async (ctx) => {
2465
2420
  return null;
2466
2421
  };
2467
2422
 
2423
+ // packages/cli/client/agentRunTypes.ts
2424
+ function resolveAuthToken(env) {
2425
+ return resolvePlatformAuthToken(env);
2426
+ }
2427
+ function resolveFileWriteGateEnabled(env) {
2428
+ const raw = (env.NOLO_CLI_WRITE_GATE ?? "").trim().toLowerCase();
2429
+ return raw !== "off" && raw !== "0" && raw !== "false";
2430
+ }
2431
+ function isMachineBoundLocalhostCustomProvider(agentConfig) {
2432
+ const machineId = agentConfig?.runtimeBinding && typeof agentConfig.runtimeBinding === "object" ? String(agentConfig.runtimeBinding.machineId ?? "").trim() : "";
2433
+ const providerUrl = asTrimmedString(agentConfig?.customProviderUrl);
2434
+ if (!machineId || !providerUrl) return false;
2435
+ return isLoopbackUrl(providerUrl);
2436
+ }
2437
+ function resolveBoundMachineId(agentConfig) {
2438
+ return agentConfig?.runtimeBinding && typeof agentConfig.runtimeBinding === "object" ? String(agentConfig.runtimeBinding.machineId ?? "").trim() : "";
2439
+ }
2440
+ var CLI_PROVIDER_NAMES = /* @__PURE__ */ new Set([
2441
+ "agy",
2442
+ "claude",
2443
+ "codex",
2444
+ "copilot",
2445
+ "gemini",
2446
+ "grok",
2447
+ "kimi",
2448
+ "opencode",
2449
+ "qoder"
2450
+ ]);
2451
+ function isCliProviderAgentConfig(agentConfig) {
2452
+ if (asTrimmedLowercaseString(agentConfig?.apiSource) === "cli") return true;
2453
+ const cliProvider = asTrimmedLowercaseString(agentConfig?.cliProvider);
2454
+ if (cliProvider && CLI_PROVIDER_NAMES.has(cliProvider)) return true;
2455
+ const provider = asTrimmedLowercaseString(agentConfig?.provider);
2456
+ if (provider === "cli") return true;
2457
+ return CLI_PROVIDER_NAMES.has(provider);
2458
+ }
2459
+ async function detectCurrentMachineId(env) {
2460
+ const fromEnv = (env.NOLO_CURRENT_MACHINE_ID || env.NOLO_MACHINE_ID || "").trim();
2461
+ if (fromEnv) return fromEnv;
2462
+ try {
2463
+ const { detectMachineInfo } = await import("./machineInfo-66ZFUMLE.js");
2464
+ const machine = await detectMachineInfo({ probeLaunchable: true });
2465
+ return asOptionalTrimmedString(machine?.machineId);
2466
+ } catch {
2467
+ return void 0;
2468
+ }
2469
+ }
2470
+
2468
2471
  // packages/cli/client/cliProviderHelpers.ts
2472
+ function buildDelegatedTaskContent(task, input) {
2473
+ if (input === void 0 || input === null) {
2474
+ return task;
2475
+ }
2476
+ if (typeof input === "string") {
2477
+ const trimmedInput = input.trim();
2478
+ if (!trimmedInput || trimmedInput === task.trim()) {
2479
+ return task;
2480
+ }
2481
+ return `${task}
2482
+
2483
+ --- INPUT (text) ---
2484
+ ${input}`;
2485
+ }
2486
+ let jsonStr;
2487
+ try {
2488
+ const serialized = JSON.stringify(input, null, 2);
2489
+ if (serialized === void 0) {
2490
+ return task;
2491
+ }
2492
+ jsonStr = serialized;
2493
+ } catch {
2494
+ jsonStr = "[Unserializable Input]";
2495
+ }
2496
+ return `${task}
2497
+
2498
+ --- INPUT (json) ---
2499
+ ${jsonStr}`;
2500
+ }
2501
+ function calculateDelegatedPayloadMetrics(task, input, delegatedContent) {
2502
+ const taskText = typeof task === "string" ? task : "";
2503
+ const taskChars = taskText.length;
2504
+ let inputChars = 0;
2505
+ let serializedInputForTokens = void 0;
2506
+ if (input !== void 0 && input !== null) {
2507
+ if (typeof input === "string") {
2508
+ inputChars = input.length;
2509
+ serializedInputForTokens = input;
2510
+ } else {
2511
+ try {
2512
+ const serialized = JSON.stringify(input, null, 2);
2513
+ if (serialized !== void 0) {
2514
+ inputChars = serialized.length;
2515
+ serializedInputForTokens = serialized;
2516
+ } else {
2517
+ inputChars = 0;
2518
+ }
2519
+ } catch {
2520
+ const fallback = "[Unserializable Input]";
2521
+ inputChars = fallback.length;
2522
+ serializedInputForTokens = fallback;
2523
+ }
2524
+ }
2525
+ }
2526
+ const finalContent = delegatedContent ?? buildDelegatedTaskContent(task, input);
2527
+ const totalChars = finalContent.length;
2528
+ const estimatedTaskTokens = estimateTokenCount(taskText);
2529
+ const estimatedTotalTokens = estimateTokenCount(finalContent);
2530
+ const estimatedInputTokens = serializedInputForTokens && inputChars > 0 ? estimateTokenCount(serializedInputForTokens) : 0;
2531
+ return {
2532
+ taskChars,
2533
+ inputChars,
2534
+ totalChars,
2535
+ estimatedTaskTokens,
2536
+ estimatedInputTokens,
2537
+ estimatedTotalTokens
2538
+ };
2539
+ }
2469
2540
  function isCliProviderAgent(agentConfig) {
2470
- return Boolean(
2471
- agentConfig.apiSource === "cli" || agentConfig.provider === "cli" || agentConfig.cliProvider
2472
- );
2541
+ const providerName = asTrimmedLowercaseString(agentConfig.cliProvider);
2542
+ if (providerName && CLI_PROVIDER_NAMES.has(providerName)) return true;
2543
+ if (agentConfig.apiSource === "cli") return true;
2544
+ if (asTrimmedLowercaseString(agentConfig.provider) === "cli") return true;
2545
+ return false;
2473
2546
  }
2474
2547
  function resolveCliProviderName(agentConfig) {
2475
- return (agentConfig.cliProvider || agentConfig.provider || "codex").trim() || "codex";
2548
+ const explicit = asTrimmedLowercaseString(agentConfig.cliProvider);
2549
+ if (explicit && CLI_PROVIDER_NAMES.has(explicit)) return explicit;
2550
+ const providerName = asTrimmedLowercaseString(agentConfig.provider);
2551
+ if (providerName && CLI_PROVIDER_NAMES.has(providerName)) return providerName;
2552
+ return "codex";
2476
2553
  }
2477
2554
  function stringifyRuntimeMessageContent(content) {
2478
2555
  if (typeof content === "string") return content;
@@ -2578,13 +2655,13 @@ var resolveCliProviderTransport = async (ctx) => {
2578
2655
  };
2579
2656
 
2580
2657
  // packages/agent-runtime/codexResponsesProvider.ts
2581
- import { randomUUID as randomUUID3 } from "node:crypto";
2658
+ import { randomUUID as randomUUID2 } from "node:crypto";
2582
2659
  var CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
2583
- var CODEX_CLIENT_VERSION = "0.144.1";
2660
+ var CODEX_CLIENT_VERSION = "0.154.0";
2584
2661
  var CODEX_ORIGINATOR = "codex_cli_rs";
2585
2662
  var CODEX_OPENAI_BETA = "responses=experimental";
2586
2663
  var OPENAI_AUTH_CLAIM = "https://api.openai.com/auth";
2587
- var CODEX_INSTALLATION_ID = randomUUID3();
2664
+ var CODEX_INSTALLATION_ID = randomUUID2();
2588
2665
  function decodeCodexAccountId(accessToken) {
2589
2666
  const parts = accessToken.split(".");
2590
2667
  if (parts.length < 2) return void 0;
@@ -2600,10 +2677,10 @@ function decodeCodexAccountId(accessToken) {
2600
2677
  }
2601
2678
  }
2602
2679
  function createCodexRequestIdentity(installationId = CODEX_INSTALLATION_ID) {
2603
- const sessionId = randomUUID3();
2604
- const threadId = randomUUID3();
2605
- const windowId = randomUUID3();
2606
- const turnId = randomUUID3();
2680
+ const sessionId = randomUUID2();
2681
+ const threadId = randomUUID2();
2682
+ const windowId = randomUUID2();
2683
+ const turnId = randomUUID2();
2607
2684
  const turnMetadata = {
2608
2685
  installation_id: installationId,
2609
2686
  session_id: sessionId,
@@ -2723,7 +2800,7 @@ async function readSseEvents(response) {
2723
2800
  });
2724
2801
  }
2725
2802
  var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2726
- async function callCodexResponsesOnce(args, accountId) {
2803
+ async function callCodexResponsesOnce(args, accountId, timingTracker) {
2727
2804
  const fetchImpl = args.fetchImpl ?? fetch;
2728
2805
  const identity = createCodexRequestIdentity();
2729
2806
  const body = buildCodexRequestBody(args, identity);
@@ -2743,7 +2820,17 @@ async function callCodexResponsesOnce(args, accountId) {
2743
2820
  };
2744
2821
  }
2745
2822
  const events = await readSseEvents(response);
2746
- const { text, toolCalls, usage, failure } = aggregateResponsesStream(events);
2823
+ let firstAcceptedOutputAt;
2824
+ const { text, toolCalls, usage, failure } = aggregateResponsesStream(events, {
2825
+ onMeaningfulDelta: () => {
2826
+ firstAcceptedOutputAt ??= timingTracker.now();
2827
+ }
2828
+ });
2829
+ if (!failure && firstAcceptedOutputAt !== void 0) {
2830
+ observeMeaningfulProviderResponseAt(timingTracker, firstAcceptedOutputAt);
2831
+ }
2832
+ const timingFields = finalizeProviderCallTiming(timingTracker);
2833
+ const usageWithTiming = withProviderCallTimingFields(usage, timingFields);
2747
2834
  if (failure) {
2748
2835
  return {
2749
2836
  status: codexStreamFailureStatus(failure),
@@ -2771,7 +2858,7 @@ async function callCodexResponsesOnce(args, accountId) {
2771
2858
  finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop"
2772
2859
  }
2773
2860
  ],
2774
- ...usage ? { usage } : {}
2861
+ ...usageWithTiming ? { usage: usageWithTiming } : {}
2775
2862
  }
2776
2863
  };
2777
2864
  }
@@ -2790,12 +2877,13 @@ async function fetchCodexResponsesCompletion(args) {
2790
2877
  const sleep = args.sleep ?? defaultSleep;
2791
2878
  const requestedMaxAttempts = Number(args.maxAttempts);
2792
2879
  const maxAttempts = Number.isFinite(requestedMaxAttempts) ? Math.min(10, Math.max(1, Math.floor(requestedMaxAttempts))) : CODEX_STREAM_MAX_ATTEMPTS;
2793
- let result = await callCodexResponsesOnce(args, accountId);
2880
+ const timingTracker = createProviderCallTimingTracker(args.now);
2881
+ let result = await callCodexResponsesOnce(args, accountId, timingTracker);
2794
2882
  for (let attempt = 1; attempt < maxAttempts; attempt += 1) {
2795
2883
  if (!RETRYABLE_CODEX_STREAM_STATUSES.has(result.status)) break;
2796
2884
  if (args.signal?.aborted) break;
2797
2885
  await sleep(CODEX_STREAM_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1));
2798
- result = await callCodexResponsesOnce(args, accountId);
2886
+ result = await callCodexResponsesOnce(args, accountId, timingTracker);
2799
2887
  }
2800
2888
  return result;
2801
2889
  }
@@ -2891,7 +2979,7 @@ var resolveCodexOAuthTransport = async (ctx) => {
2891
2979
  };
2892
2980
 
2893
2981
  // packages/agent-runtime/cursor/cursorProvider.ts
2894
- import { createHash, randomUUID as randomUUID4 } from "node:crypto";
2982
+ import { createHash, randomUUID as randomUUID3 } from "node:crypto";
2895
2983
  import http2 from "node:http2";
2896
2984
 
2897
2985
  // node_modules/@bufbuild/protobuf/dist/esm/is-message.js
@@ -7650,7 +7738,7 @@ function deterministicUuid(seed) {
7650
7738
  const hex = hash.slice(0, 32);
7651
7739
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-4${hex.slice(13, 16)}-8${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
7652
7740
  }
7653
- function createCursorUserMessage(content, text, messageId = randomUUID4()) {
7741
+ function createCursorUserMessage(content, text, messageId = randomUUID3()) {
7654
7742
  const images = extractImages(content);
7655
7743
  return create(UserMessageSchema, {
7656
7744
  text,
@@ -7669,7 +7757,7 @@ function extractImages(content) {
7669
7757
  const match = url.match(/^data:([^;,]+);base64,(.+)$/s);
7670
7758
  if (!match) return null;
7671
7759
  return create(SelectedImageSchema, {
7672
- uuid: randomUUID4(),
7760
+ uuid: randomUUID3(),
7673
7761
  mimeType: match[1],
7674
7762
  dataOrBlobId: {
7675
7763
  case: "data",
@@ -7680,7 +7768,7 @@ function extractImages(content) {
7680
7768
  }
7681
7769
  function buildCursorRunRequestBytes(args) {
7682
7770
  const blobStore = args.blobStore ?? /* @__PURE__ */ new Map();
7683
- const conversationId = args.conversationId ?? randomUUID4();
7771
+ const conversationId = args.conversationId ?? randomUUID3();
7684
7772
  const systemPromptIds = buildCursorSystemPromptJsons(
7685
7773
  args.systemPrompt ? [args.systemPrompt] : void 0
7686
7774
  ).map(
@@ -7818,7 +7906,7 @@ function processCursorServerMessage(msg, state, onTextDelta, onReasoningDelta) {
7818
7906
  async function streamCursorChat(messages, options) {
7819
7907
  const baseUrl = options.baseUrl || CURSOR_API_URL;
7820
7908
  const clientVersion = options.clientVersion || CURSOR_CLIENT_VERSION;
7821
- const conversationId = options.conversationId ?? randomUUID4();
7909
+ const conversationId = options.conversationId ?? randomUUID3();
7822
7910
  const toolCalls = [];
7823
7911
  const state = createStreamState();
7824
7912
  const execCtx = {
@@ -7856,7 +7944,7 @@ async function streamCursorChat(messages, options) {
7856
7944
  "x-ghost-mode": "true",
7857
7945
  "x-cursor-client-version": clientVersion,
7858
7946
  "x-cursor-client-type": "cli",
7859
- "x-request-id": randomUUID4()
7947
+ "x-request-id": randomUUID3()
7860
7948
  };
7861
7949
  try {
7862
7950
  h2Client = http2.connect(baseUrl);
@@ -8411,7 +8499,7 @@ async function handleExecServerMessage(execMsg, h2Request, ctx) {
8411
8499
  switch (execCase) {
8412
8500
  case "readArgs": {
8413
8501
  const args = execMsg.message.value;
8414
- if (!args.toolCallId) args.toolCallId = randomUUID4();
8502
+ if (!args.toolCallId) args.toolCallId = randomUUID3();
8415
8503
  const path = args.path;
8416
8504
  const toolCallBlock = synthesizeCursorExecToolCall(ctx, args.toolCallId, "readFile", { path });
8417
8505
  let result;
@@ -8471,7 +8559,7 @@ async function handleExecServerMessage(execMsg, h2Request, ctx) {
8471
8559
  case "shellArgs":
8472
8560
  case "shellStreamArgs": {
8473
8561
  const args = execMsg.message.value;
8474
- if (!args.toolCallId) args.toolCallId = randomUUID4();
8562
+ if (!args.toolCallId) args.toolCallId = randomUUID3();
8475
8563
  const command = args.command;
8476
8564
  const workingDirectory = args.workingDirectory || process.cwd();
8477
8565
  const shellTimeout = args.timeout && args.timeout > 0 ? args.timeout : void 0;
@@ -8570,7 +8658,7 @@ async function handleExecServerMessage(execMsg, h2Request, ctx) {
8570
8658
  }
8571
8659
  case "grepArgs": {
8572
8660
  const args = execMsg.message.value;
8573
- if (!args.toolCallId) args.toolCallId = randomUUID4();
8661
+ if (!args.toolCallId) args.toolCallId = randomUUID3();
8574
8662
  const searchPath = args.glob ? `${args.path || "."}/${args.glob}` : args.path || ".";
8575
8663
  const pattern = args.pattern || "";
8576
8664
  const toolCallBlock = synthesizeCursorExecToolCall(ctx, args.toolCallId, "searchWorkspace", {
@@ -8638,7 +8726,7 @@ async function handleExecServerMessage(execMsg, h2Request, ctx) {
8638
8726
  }
8639
8727
  case "writeArgs": {
8640
8728
  const args = execMsg.message.value;
8641
- if (!args.toolCallId) args.toolCallId = randomUUID4();
8729
+ if (!args.toolCallId) args.toolCallId = randomUUID3();
8642
8730
  const path = args.path;
8643
8731
  const content = args.fileText ?? new TextDecoder().decode(args.fileBytes ?? new Uint8Array());
8644
8732
  const toolCallBlock = synthesizeCursorExecToolCall(ctx, args.toolCallId, "writeFile", { path, content });
@@ -8701,7 +8789,7 @@ async function handleExecServerMessage(execMsg, h2Request, ctx) {
8701
8789
  }
8702
8790
  case "deleteArgs": {
8703
8791
  const args = execMsg.message.value;
8704
- if (!args.toolCallId) args.toolCallId = randomUUID4();
8792
+ if (!args.toolCallId) args.toolCallId = randomUUID3();
8705
8793
  const path = args.path;
8706
8794
  const toolCallBlock = synthesizeCursorExecToolCall(ctx, args.toolCallId, "deleteFile", { path });
8707
8795
  let result;
@@ -8760,7 +8848,7 @@ async function handleExecServerMessage(execMsg, h2Request, ctx) {
8760
8848
  }
8761
8849
  case "lsArgs": {
8762
8850
  const args = execMsg.message.value;
8763
- if (!args.toolCallId) args.toolCallId = randomUUID4();
8851
+ if (!args.toolCallId) args.toolCallId = randomUUID3();
8764
8852
  const path = args.path;
8765
8853
  const toolCallBlock = synthesizeCursorExecToolCall(ctx, args.toolCallId, "listWorkspaceEntries", { path: path || "." });
8766
8854
  let result;
@@ -8821,7 +8909,7 @@ async function handleExecServerMessage(execMsg, h2Request, ctx) {
8821
8909
  for (const [key, value] of Object.entries(args.args ?? {})) {
8822
8910
  decodedArgs[key] = decodeMcpArgValue(value);
8823
8911
  }
8824
- if (!args.toolCallId) args.toolCallId = randomUUID4();
8912
+ if (!args.toolCallId) args.toolCallId = randomUUID3();
8825
8913
  const toolCallBlock = synthesizeCursorExecToolCall(ctx, args.toolCallId, toolName, decodedArgs);
8826
8914
  let result;
8827
8915
  if (ctx.executeTool) {
@@ -9261,6 +9349,8 @@ var resolveGeminiNativeToolTransport = async (ctx) => {
9261
9349
  content: text,
9262
9350
  model,
9263
9351
  tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
9352
+ finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop",
9353
+ stream_complete: true,
9264
9354
  ...usage ? { usage } : {},
9265
9355
  trace: messages
9266
9356
  };
@@ -9322,6 +9412,7 @@ var resolvePlatformProxyTransport = async (ctx) => {
9322
9412
  return {
9323
9413
  model: providerConfig.model,
9324
9414
  complete: async (messages, options) => {
9415
+ const requestId = crypto.randomUUID();
9325
9416
  const usesResponsesApi = providerConfig.endpoint.includes("/responses");
9326
9417
  const stream = Boolean(options?.onTextDelta);
9327
9418
  const request = buildPlatformChatCompletionRequest({
@@ -9329,6 +9420,7 @@ var resolvePlatformProxyTransport = async (ctx) => {
9329
9420
  messages,
9330
9421
  tools,
9331
9422
  stream,
9423
+ requestId,
9332
9424
  ...options?.dialogId ? { dialogId: options.dialogId } : {}
9333
9425
  });
9334
9426
  logLocalRuntimeDiagnostic("provider.request.start", {
@@ -9341,93 +9433,122 @@ var resolvePlatformProxyTransport = async (ctx) => {
9341
9433
  toolCount: tools.length,
9342
9434
  requestedToolNames,
9343
9435
  openAiToolNames: summarizeOpenAiToolNames(tools),
9344
- stream
9436
+ stream,
9437
+ requestId
9345
9438
  });
9346
- let res = await fetchWithTransientRetry(
9347
- fetchImpl,
9348
- request.url,
9349
- {
9350
- ...request.init
9351
- },
9352
- {
9353
- sleep: deps.sleep,
9354
- loopbackRequest,
9355
- // A chat POST is not safe to replay after an ambiguous network or
9356
- // gateway failure: the server/provider may already have accepted
9357
- // it. The client only waits through the server's explicit pre-
9358
- // admission deployment drain signal.
9359
- retryableStatuses: /* @__PURE__ */ new Set([503]),
9360
- shouldRetryResponse: shouldRetryPlatformProxyResponse,
9361
- retryNetworkErrors: false,
9362
- onRetry: deps.activityReporter ? ({ attempt, maxAttempts, delayMs }) => {
9363
- deps.activityReporter(
9364
- `\u81EA\u52A8\u91CD\u8BD5 ${attempt}/${maxAttempts} \xB7 ${Math.ceil(delayMs / 1e3)}s`
9365
- );
9366
- } : void 0
9367
- }
9368
- );
9369
- if (!res.ok) {
9370
- const raw2 = await res.text().catch(() => "");
9371
- const data2 = parsePlatformChatCompletionData(raw2);
9372
- await recordLocalAvailability(res.status, data2);
9373
- const rawPreview = raw2.length > 200 ? `${raw2.slice(0, 200)}\u2026(${raw2.length}b)` : raw2;
9374
- const gatewayHeaders = [
9375
- "server",
9376
- "cf-ray",
9377
- "cf-cache-status",
9378
- "content-length"
9379
- ].map((h) => {
9380
- const v = res.headers.get(h);
9381
- return v ? `${h}=${v}` : null;
9382
- }).filter(Boolean).join(" ");
9383
- throw new Error(
9384
- `platform provider failed: HTTP ${res.status} ${JSON.stringify(data2)}` + (rawPreview ? ` raw="${rawPreview}"` : "") + (gatewayHeaders ? ` headers=[${gatewayHeaders}]` : "")
9439
+ try {
9440
+ let res = await fetchWithTransientRetry(
9441
+ fetchImpl,
9442
+ request.url,
9443
+ {
9444
+ ...request.init
9445
+ },
9446
+ {
9447
+ sleep: deps.sleep,
9448
+ loopbackRequest,
9449
+ // A chat POST is not safe to replay after an ambiguous network or
9450
+ // gateway failure: the server/provider may already have accepted
9451
+ // it. The client only waits through the server's explicit pre-
9452
+ // admission deployment drain signal.
9453
+ retryableStatuses: /* @__PURE__ */ new Set([503]),
9454
+ shouldRetryResponse: shouldRetryPlatformProxyResponse,
9455
+ retryNetworkErrors: false,
9456
+ onRetry: deps.activityReporter ? ({ attempt, maxAttempts, delayMs }) => {
9457
+ deps.activityReporter(
9458
+ `\u81EA\u52A8\u91CD\u8BD5 ${attempt}/${maxAttempts} \xB7 ${Math.ceil(delayMs / 1e3)}s`
9459
+ );
9460
+ } : void 0
9461
+ }
9385
9462
  );
9386
- }
9387
- await recordLocalAvailability(res.status);
9388
- const contentType = res.headers.get("content-type") ?? "";
9389
- const shouldStream = Boolean(stream && options?.onTextDelta) && contentType.includes("text/event-stream");
9390
- if (shouldStream && options?.onTextDelta) {
9391
- const streamed = await readPlatformChatSseCompletion({
9392
- response: res,
9393
- usesResponsesApi,
9394
- onTextDelta: options.onTextDelta,
9395
- onReasoningDelta: options.onReasoningDelta
9396
- });
9463
+ if (!res.ok) {
9464
+ const raw2 = await res.text().catch(() => "");
9465
+ const data2 = parsePlatformChatCompletionData(raw2);
9466
+ await recordLocalAvailability(res.status, data2);
9467
+ const rawPreview = raw2.length > 200 ? `${raw2.slice(0, 200)}\u2026(${raw2.length}b)` : raw2;
9468
+ const gatewayHeaders = [
9469
+ "server",
9470
+ "cf-ray",
9471
+ "cf-cache-status",
9472
+ "content-length"
9473
+ ].map((h) => {
9474
+ const v = res.headers.get(h);
9475
+ return v ? `${h}=${v}` : null;
9476
+ }).filter(Boolean).join(" ");
9477
+ throw new Error(
9478
+ `platform provider failed: HTTP ${res.status} ${JSON.stringify(data2)}` + (rawPreview ? ` raw="${rawPreview}"` : "") + (gatewayHeaders ? ` headers=[${gatewayHeaders}]` : "")
9479
+ );
9480
+ }
9481
+ await recordLocalAvailability(res.status);
9482
+ const contentType = res.headers.get("content-type") ?? "";
9483
+ const shouldStream = Boolean(stream && options?.onTextDelta) && contentType.includes("text/event-stream");
9484
+ if (shouldStream && options?.onTextDelta) {
9485
+ const streamed = await readPlatformChatSseCompletion({
9486
+ response: res,
9487
+ usesResponsesApi,
9488
+ onTextDelta: options.onTextDelta,
9489
+ onReasoningDelta: options.onReasoningDelta
9490
+ });
9491
+ if (streamed.streamTruncated) {
9492
+ logLocalRuntimeDiagnostic("provider.stream.truncated", {
9493
+ phase: "streaming",
9494
+ contentChars: streamed.content.length,
9495
+ toolCallCount: streamed.tool_calls?.length ?? 0,
9496
+ requestId,
9497
+ ...options?.dialogId ? { dialogId: options.dialogId } : {}
9498
+ });
9499
+ }
9500
+ logLocalRuntimeDiagnostic("provider.request.result", {
9501
+ agentKey: agentConfig.key,
9502
+ transport: "platform-proxy",
9503
+ ok: true,
9504
+ stream: true,
9505
+ contentChars: streamed.content.length,
9506
+ toolCallCount: streamed.tool_calls?.length ?? 0
9507
+ });
9508
+ return {
9509
+ content: streamed.content,
9510
+ model: providerConfig.model,
9511
+ provider: providerConfig.provider,
9512
+ ...streamed.tool_calls ? { tool_calls: streamed.tool_calls } : {},
9513
+ ...streamed.reasoning_content ? { reasoning_content: streamed.reasoning_content } : {},
9514
+ ...streamed.usage ? { usage: streamed.usage } : {},
9515
+ ...streamed.finish_reason ? { finish_reason: streamed.finish_reason } : {},
9516
+ ...streamed.stream_complete ? { stream_complete: streamed.stream_complete } : {},
9517
+ ...streamed.streamTruncated ? { stream_truncated: true } : {},
9518
+ trace: messages
9519
+ };
9520
+ }
9521
+ const raw = await res.text().catch(() => "");
9397
9522
  logLocalRuntimeDiagnostic("provider.request.result", {
9398
9523
  agentKey: agentConfig.key,
9399
9524
  transport: "platform-proxy",
9400
- ok: true,
9401
- stream: true,
9402
- contentChars: streamed.content.length,
9403
- toolCallCount: streamed.tool_calls?.length ?? 0
9525
+ status: res.status,
9526
+ ok: res.ok,
9527
+ responseBytes: raw.length
9404
9528
  });
9405
- return {
9406
- content: streamed.content,
9407
- model: providerConfig.model,
9408
- provider: providerConfig.provider,
9409
- ...streamed.tool_calls ? { tool_calls: streamed.tool_calls } : {},
9410
- ...streamed.reasoning_content ? { reasoning_content: streamed.reasoning_content } : {},
9411
- ...streamed.usage ? { usage: streamed.usage } : {},
9412
- ...streamed.finish_reason ? { finish_reason: streamed.finish_reason } : {},
9413
- ...streamed.stream_complete ? { stream_complete: streamed.stream_complete } : {},
9529
+ const data = parsePlatformChatCompletionData(raw);
9530
+ return parsePlatformChatCompletionResponse({
9531
+ providerConfig,
9532
+ data,
9414
9533
  trace: messages
9415
- };
9534
+ });
9535
+ } catch (error) {
9536
+ if (error instanceof PlatformStreamInterruptedError) {
9537
+ logLocalRuntimeDiagnostic("provider.stream.interrupted", {
9538
+ phase: error.phase,
9539
+ frameCount: error.frameCount,
9540
+ textChars: error.textChars,
9541
+ sawDone: error.sawDone,
9542
+ sawUsage: error.sawUsage,
9543
+ sawFinishReason: error.sawFinishReason,
9544
+ elapsedMs: error.elapsedMs,
9545
+ requestId,
9546
+ ...options?.dialogId ? { dialogId: options.dialogId } : {},
9547
+ cause: error.cause instanceof Error ? error.cause.message : typeof error.cause === "string" ? error.cause : error.message
9548
+ });
9549
+ }
9550
+ throw error;
9416
9551
  }
9417
- const raw = await res.text().catch(() => "");
9418
- logLocalRuntimeDiagnostic("provider.request.result", {
9419
- agentKey: agentConfig.key,
9420
- transport: "platform-proxy",
9421
- status: res.status,
9422
- ok: res.ok,
9423
- responseBytes: raw.length
9424
- });
9425
- const data = parsePlatformChatCompletionData(raw);
9426
- return parsePlatformChatCompletionResponse({
9427
- providerConfig,
9428
- data,
9429
- trace: messages
9430
- });
9431
9552
  }
9432
9553
  };
9433
9554
  }
@@ -9520,19 +9641,6 @@ function withProviderStreamRetry(provider, deps) {
9520
9641
  };
9521
9642
  }
9522
9643
 
9523
- // packages/cli/client/localRuntimeHelpers.ts
9524
- var REMOTE_DIALOG_SYNC_TIMEOUT_MS = 1e4;
9525
- var remoteDialogSyncTimeoutMsForTest;
9526
- function remoteDialogSyncTimeout() {
9527
- return remoteDialogSyncTimeoutMsForTest ?? REMOTE_DIALOG_SYNC_TIMEOUT_MS;
9528
- }
9529
- function resolveRuntimeServerUrl(env) {
9530
- return (env?.NOLO_SERVER_URL || env?.NOLO_SERVER || env?.BASE_URL || "").replace(/\/+$/, "");
9531
- }
9532
- function resolveRuntimeAuthToken(env) {
9533
- return resolvePlatformAuthToken(env ?? {});
9534
- }
9535
-
9536
9644
  // packages/cli/client/cliRemoteDialogSync.ts
9537
9645
  function prepareRemoteDialogEvidenceRecord(key, value) {
9538
9646
  const record = isRecord(value) ? { ...value } : {};
@@ -9541,9 +9649,6 @@ function prepareRemoteDialogEvidenceRecord(key, value) {
9541
9649
  }
9542
9650
  return record;
9543
9651
  }
9544
- function normalizeRemoteStringList(value) {
9545
- return [...new Set(asTrimmedNonEmptyStringArray(value))];
9546
- }
9547
9652
  function normalizeRemoteSubjectRef(value) {
9548
9653
  if (!isRecord(value)) return null;
9549
9654
  const kind = asOptionalTrimmedString(value.kind);
@@ -9694,15 +9799,6 @@ async function maybeWakeParentDialogAfterLocalSync(args) {
9694
9799
  args.childDialogRecord.subjectRefs,
9695
9800
  [{ kind: "dialog", id: childDialogId, role: "completed-child-dialog" }]
9696
9801
  );
9697
- const allowedChildAgentKeys = normalizeRemoteStringList(
9698
- args.input.runtimeContext?.allowedChildAgentKeys
9699
- );
9700
- const allowedToolNames = normalizeRemoteStringList(
9701
- args.input.runtimeContext?.allowedToolNames
9702
- );
9703
- const blockedToolNames = normalizeRemoteStringList(
9704
- args.input.runtimeContext?.blockedToolNames
9705
- );
9706
9802
  const wakeResponse = await args.fetchImpl(`${args.serverUrl}/api/agent/run`, {
9707
9803
  method: "POST",
9708
9804
  headers: {
@@ -9730,10 +9826,7 @@ async function maybeWakeParentDialogAfterLocalSync(args) {
9730
9826
  label: args.childDialogRecord.taskLabel ?? args.childDialogRecord.title,
9731
9827
  terminalStatus: "done"
9732
9828
  }),
9733
- subjectRefs,
9734
- ...allowedChildAgentKeys.length ? { allowedChildAgentKeys } : {},
9735
- ...allowedToolNames.length ? { allowedToolNames } : {},
9736
- ...blockedToolNames.length ? { blockedToolNames } : {}
9829
+ subjectRefs
9737
9830
  }
9738
9831
  })
9739
9832
  });
@@ -9866,61 +9959,6 @@ async function readDialogMessages(args) {
9866
9959
  return messages;
9867
9960
  }
9868
9961
 
9869
- // packages/cli/client/cliAgentConfigHelpers.ts
9870
- var BUILTIN_NOLO_AGENT_KEY = NOLO_DEFAULT_AGENT_KEY;
9871
- var BUILTIN_NOLO_AGENT_ID = NOLO_DEFAULT_AGENT_ID;
9872
- function resolveLocalUserId(env) {
9873
- const explicitUserId = env.NOLO_LOCAL_USER_ID || env.NOLO_USER_ID;
9874
- if (explicitUserId) return explicitUserId;
9875
- const tokenUserId = parseUserIdFromAuthToken(resolveRuntimeAuthToken(env));
9876
- return tokenUserId || "local";
9877
- }
9878
- function isBuiltinNoloAgentRef(ref) {
9879
- if (typeof ref !== "string") return false;
9880
- const normalized = ref.trim();
9881
- return normalized === BUILTIN_NOLO_AGENT_KEY || normalized === BUILTIN_NOLO_AGENT_ID || normalized.endsWith(`-${BUILTIN_NOLO_AGENT_ID}`);
9882
- }
9883
- function isBuiltinNoloAgentConfig(agentConfig) {
9884
- const key = agentConfig?.key || agentConfig?.rawRecord?.dbKey || agentConfig?.rawRecord?.agentKey;
9885
- const id = agentConfig?.rawRecord?.id;
9886
- return isBuiltinNoloAgentRef(key) || isBuiltinNoloAgentRef(id);
9887
- }
9888
- function withResolvedRuntimeToolSurface(agentConfig, env) {
9889
- if (!agentConfig) return agentConfig;
9890
- const currentUserId = resolveLocalUserId(env);
9891
- const rawRecord = agentConfig.rawRecord ?? {};
9892
- const ownerId = asOptionalTrimmedString(rawRecord.userId) ?? null;
9893
- const agentKey = rawRecord.dbKey ?? agentConfig.key;
9894
- const toolSurface = resolveRuntimeToolSurfaceForAgent({
9895
- explicitToolNames: agentConfig.toolNames,
9896
- currentUserId,
9897
- agentOwnerId: ownerId,
9898
- agentKey,
9899
- isPublic: !isBuiltinNoloAgentConfig(agentConfig) && rawRecord.isPublic === true,
9900
- sharingLevel: typeof rawRecord.sharingLevel === "string" ? rawRecord.sharingLevel : null,
9901
- trustedPrivateInvocation: isBuiltinNoloAgentConfig(agentConfig) || isSystemBuiltinTrustedAgentKey(agentKey),
9902
- runtimeHost: "cli"
9903
- });
9904
- return {
9905
- ...agentConfig,
9906
- toolNames: toolSurface.finalToolNames,
9907
- toolSurface,
9908
- prompt: agentConfig.prompt
9909
- };
9910
- }
9911
- function extractLastUserText(messages) {
9912
- const lastUser = [...messages].reverse().find((m) => m.role === "user");
9913
- if (!lastUser) return "";
9914
- if (typeof lastUser.content === "string") return lastUser.content;
9915
- if (Array.isArray(lastUser.content)) {
9916
- return lastUser.content.filter((part) => part?.type === "text").map((part) => part.text ?? "").join(" ");
9917
- }
9918
- return "";
9919
- }
9920
- function localTurnHasSubjectRefs(input) {
9921
- return Array.isArray(input.runtimeContext?.subjectRefs) && input.runtimeContext.subjectRefs.length > 0;
9922
- }
9923
-
9924
9962
  // packages/core/fetchWebpageShaping.ts
9925
9963
  var FETCH_WEBPAGE_PREVIEW_LENGTH = 1200;
9926
9964
  var FETCH_WEBPAGE_MAX_CONTENT_LENGTH = 12 * 1024;
@@ -10246,6 +10284,60 @@ function buildServerPlatformToolExecutors(args) {
10246
10284
 
10247
10285
  // packages/cli/client/cliAgentRunToolExecutors.ts
10248
10286
  import * as nodeFs2 from "node:fs";
10287
+
10288
+ // packages/agent-runtime/waitForRunTerminal.ts
10289
+ var readEffect = (read) => Effect_exports.tryPromise({ try: () => Promise.resolve(read()), catch: (error) => error });
10290
+ function waitForRunTerminal(args) {
10291
+ let lastState;
10292
+ let token = null;
10293
+ let committed = false;
10294
+ const abort = args.abortSignal;
10295
+ let removeAbortListener;
10296
+ const abortEffect = abort ? Effect_exports.callback((resume) => {
10297
+ const listener = () => resume(Effect_exports.succeed("aborted"));
10298
+ if (abort.aborted) {
10299
+ listener();
10300
+ return;
10301
+ }
10302
+ removeAbortListener = () => {
10303
+ abort.removeEventListener("abort", listener);
10304
+ removeAbortListener = void 0;
10305
+ };
10306
+ abort.addEventListener("abort", listener, { once: true });
10307
+ return Effect_exports.sync(() => removeAbortListener?.());
10308
+ }).pipe(Effect_exports.ensuring(Effect_exports.sync(() => removeAbortListener?.()))) : void 0;
10309
+ const sleep = (ms) => {
10310
+ const effect = args.sleep ? Effect_exports.tryPromise({ try: () => Promise.resolve(args.sleep(ms)), catch: (error) => error }) : Effect_exports.sleep(Duration_exports.millis(ms));
10311
+ return abortEffect ? Effect_exports.raceFirst(effect, abortEffect) : effect;
10312
+ };
10313
+ const loop = Effect_exports.gen(function* () {
10314
+ token = args.claim?.acquire() ?? null;
10315
+ while (true) {
10316
+ const state = yield* readEffect(args.read);
10317
+ lastState = state;
10318
+ if (args.isTerminal(state)) {
10319
+ if (args.claim) {
10320
+ args.claim.commit(token);
10321
+ committed = true;
10322
+ }
10323
+ return { kind: "terminal", state };
10324
+ }
10325
+ const slept = yield* sleep(args.pollIntervalMs);
10326
+ if (slept === "aborted") return { kind: "aborted" };
10327
+ }
10328
+ }).pipe(
10329
+ Effect_exports.timeoutOption(Duration_exports.millis(args.timeoutMs)),
10330
+ Effect_exports.map((result) => Option_exports.isNone(result) ? { kind: "timeout", waitedMs: args.timeoutMs, lastState } : result.value),
10331
+ Effect_exports.catch((error) => Effect_exports.succeed({ kind: "failed", error })),
10332
+ Effect_exports.ensuring(Effect_exports.sync(() => {
10333
+ if (args.claim && !committed) args.claim.release(token);
10334
+ }))
10335
+ );
10336
+ const run = args.runtime ? args.runtime.runPromise(loop) : Effect_exports.runPromise(loop);
10337
+ return run;
10338
+ }
10339
+
10340
+ // packages/cli/client/cliAgentRunToolExecutors.ts
10249
10341
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
10250
10342
 
10251
10343
  // packages/cli/client/agentRunSnapshot.ts
@@ -10333,6 +10425,24 @@ function parseAgentRunEvent(event) {
10333
10425
  if (!snapshot.runId) return null;
10334
10426
  return { kind: "status", snapshot };
10335
10427
  }
10428
+ function isFailedToolEvent(event) {
10429
+ if (event.type === "tool-error") return true;
10430
+ if (event.metadata?.actionGate) return false;
10431
+ const exitCode = event.metadata?.exitCode;
10432
+ if (typeof exitCode === "number" && exitCode !== 0) return true;
10433
+ if (event.metadata?.failed || event.metadata?.timedOut) return true;
10434
+ return false;
10435
+ }
10436
+ var LIVE_RUN_STATUSES = /* @__PURE__ */ new Set(["running", "pending"]);
10437
+ function isLiveAgentRunObservation(event, parsed) {
10438
+ if (event.type !== "tool-result") return false;
10439
+ if (event.toolName !== "controlAgentRun") return false;
10440
+ if (isFailedToolEvent(event)) return false;
10441
+ const resolved = parsed !== void 0 ? parsed : parseAgentRunEvent(event);
10442
+ if (!resolved || resolved.kind !== "status") return false;
10443
+ if (!LIVE_RUN_STATUSES.has(resolved.snapshot.status)) return false;
10444
+ return true;
10445
+ }
10336
10446
 
10337
10447
  // packages/ai/tools/agent/batchAggregation.ts
10338
10448
  var DEFAULT_BATCH_TIMEOUT_MS = 30 * 60 * 1e3;
@@ -10624,9 +10734,6 @@ function buildRunStatusPayload(reconciled, deps, opts = {}) {
10624
10734
  const logLines = opts.logTail ? opts.logTail.split("\n") : void 0;
10625
10735
  const name = resolveRunLabel(reconciled);
10626
10736
  const labels = agentRunCardLabels();
10627
- const fs = resolveFs(deps);
10628
- const reportPath = resolveRunReportPath(reconciled.runId, deps.env, deps.homedir);
10629
- const reportExists = Boolean(fs.existsSync?.(reportPath));
10630
10737
  return {
10631
10738
  content: JSON.stringify({
10632
10739
  runId: reconciled.runId,
@@ -10646,7 +10753,6 @@ function buildRunStatusPayload(reconciled, deps, opts = {}) {
10646
10753
  ephemeral: true,
10647
10754
  dialogNote: "\u6B64 run \u672A\u6301\u4E45\u5316 dialog\uFF0C\u7ED3\u679C\u89C1 run \u8F93\u51FA"
10648
10755
  } : reconciled.dialogId ? { dialogId: reconciled.dialogId } : {},
10649
- ...reportExists ? { reportPath } : {},
10650
10756
  // Progress is what makes tailLines:0 an actual answer to "is it
10651
10757
  // stuck?". Without it a poll returns `running` and a pid, so the only
10652
10758
  // way to tell a working run from a wedged one was to pull 30 lines of
@@ -10658,7 +10764,6 @@ function buildRunStatusPayload(reconciled, deps, opts = {}) {
10658
10764
  ...logLines ? { logLines } : {}
10659
10765
  }),
10660
10766
  metadata: {
10661
- ...reportExists ? { reportPath } : {},
10662
10767
  displayData: formatStatusRunCard(name, reconciled.status, {
10663
10768
  runId: reconciled.runId,
10664
10769
  timing: {
@@ -10679,10 +10784,8 @@ function createCliStartAgentRunExecutor(deps = {}) {
10679
10784
  if (!agentKey) throw new Error("startAgentRun: \u7F3A\u5C11 agentKey \u53C2\u6570\u3002");
10680
10785
  if (!task) throw new Error("startAgentRun: \u7F3A\u5C11\u6709\u6548\u7684 task \u6587\u672C\u63CF\u8FF0\u3002");
10681
10786
  const nowMs = resolveNowMs(deps);
10682
- const message = typeof args.input === "undefined" ? task : `${task}
10683
-
10684
- --- \u9644\u52A0\u8F93\u5165 ---
10685
- ${JSON.stringify(args.input)}`;
10787
+ const message = buildDelegatedTaskContent(task, args.input);
10788
+ const payloadMetrics = calculateDelegatedPayloadMetrics(task, args.input, message);
10686
10789
  const rawArgs = [
10687
10790
  "--agent",
10688
10791
  agentKey,
@@ -10749,14 +10852,16 @@ ${JSON.stringify(args.input)}`;
10749
10852
  // even when the caller didn't supply one, a fresh id was generated.
10750
10853
  batchId: resolvedBatchId,
10751
10854
  ...agentName ? { agentName } : {},
10752
- ...taskPreview ? { taskPreview } : {}
10855
+ ...taskPreview ? { taskPreview } : {},
10856
+ payloadMetrics
10753
10857
  }),
10754
10858
  metadata: {
10755
10859
  displayData: formatStartRunCard(displayName, "running", {
10756
10860
  task: taskPreview,
10757
10861
  runId,
10758
10862
  labels
10759
- })
10863
+ }),
10864
+ payloadMetrics
10760
10865
  }
10761
10866
  };
10762
10867
  };
@@ -10937,21 +11042,21 @@ function createCliControlAgentRunExecutor(deps = {}) {
10937
11042
  metadata: { displayData: formatNotFoundRunCard(labels2) }
10938
11043
  };
10939
11044
  }
10940
- let reconciled = checkStaleRun(record2.runId, deps) ?? record2;
10941
- if (!isAgentRunTerminalStatus(reconciled.status)) {
10942
- if (!reconciled.queuePath) {
11045
+ let reconciled2 = checkStaleRun(record2.runId, deps) ?? record2;
11046
+ if (!isAgentRunTerminalStatus(reconciled2.status)) {
11047
+ if (!reconciled2.queuePath) {
10943
11048
  throw new Error("\u8BE5 run \u542F\u52A8\u65F6\u4E0D\u652F\u6301\u8FD0\u884C\u4E2D\u5165\u961F\uFF08\u65E0\u961F\u5217\u901A\u9053\uFF09\uFF0C\u8BF7\u7B49\u7EC8\u6001\u540E\u518D append");
10944
11049
  }
10945
- const queuePath = reconciled.queuePath;
11050
+ const queuePath = reconciled2.queuePath;
10946
11051
  const { queuedCount, entryId } = await appendRunQueue(queuePath, userInput, deps);
10947
11052
  const displayName = resolveRunLabel({
10948
- agentName: reconciled.agentName,
10949
- agentKey: reconciled.agentKey,
10950
- runId: reconciled.runId
11053
+ agentName: reconciled2.agentName,
11054
+ agentKey: reconciled2.agentKey,
11055
+ runId: reconciled2.runId
10951
11056
  });
10952
11057
  const labels2 = agentRunCardLabels();
10953
11058
  const taskPreview = userInput.replace(/\s+/g, " ").trim().slice(0, TASK_PREVIEW_MAX);
10954
- const afterCheck = checkStaleRun(reconciled.runId, deps) ?? reconciled;
11059
+ const afterCheck = checkStaleRun(reconciled2.runId, deps) ?? reconciled2;
10955
11060
  if (isAgentRunTerminalStatus(afterCheck.status)) {
10956
11061
  const remainingEntries = await popAllQueueEntries(queuePath, deps);
10957
11062
  const ourEntryFound = remainingEntries.some((e) => e.id === entryId);
@@ -10965,19 +11070,19 @@ function createCliControlAgentRunExecutor(deps = {}) {
10965
11070
  }
10966
11071
  return {
10967
11072
  content: JSON.stringify({
10968
- runId: reconciled.runId,
11073
+ runId: reconciled2.runId,
10969
11074
  // ephemeral 不外泄合成 dialogId;非 ephemeral 保持原 dialogId 透出。
10970
- ...reconciled.ephemeral ? { ephemeral: true } : afterCheck.dialogId || reconciled.dialogId ? { dialogId: afterCheck.dialogId ?? reconciled.dialogId } : {},
11075
+ ...reconciled2.ephemeral ? { ephemeral: true } : afterCheck.dialogId || reconciled2.dialogId ? { dialogId: afterCheck.dialogId ?? reconciled2.dialogId } : {},
10971
11076
  mode: "enqueue",
10972
11077
  consumed: true,
10973
11078
  status: afterCheck.status,
10974
- ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
11079
+ ...reconciled2.agentName ? { agentName: reconciled2.agentName } : {},
10975
11080
  ...taskPreview ? { taskPreview } : {}
10976
11081
  }),
10977
11082
  metadata: {
10978
11083
  displayData: formatStartRunCard(displayName, afterCheck.status, {
10979
11084
  task: `[consumed] ${taskPreview}`,
10980
- runId: reconciled.runId,
11085
+ runId: reconciled2.runId,
10981
11086
  labels: labels2
10982
11087
  })
10983
11088
  }
@@ -10988,25 +11093,25 @@ function createCliControlAgentRunExecutor(deps = {}) {
10988
11093
  }
10989
11094
  return {
10990
11095
  content: JSON.stringify({
10991
- runId: reconciled.runId,
11096
+ runId: reconciled2.runId,
10992
11097
  // ephemeral 不外泄合成 dialogId(enqueue 场景同样收敛)。
10993
- ...reconciled.ephemeral ? { ephemeral: true } : reconciled.dialogId ? { dialogId: reconciled.dialogId } : {},
11098
+ ...reconciled2.ephemeral ? { ephemeral: true } : reconciled2.dialogId ? { dialogId: reconciled2.dialogId } : {},
10994
11099
  mode: "enqueue",
10995
11100
  queued: queuedCount,
10996
11101
  status: "running",
10997
- ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
11102
+ ...reconciled2.agentName ? { agentName: reconciled2.agentName } : {},
10998
11103
  ...taskPreview ? { taskPreview } : {}
10999
11104
  }),
11000
11105
  metadata: {
11001
11106
  displayData: formatStartRunCard(displayName, "running", {
11002
11107
  task: `[enqueued ${queuedCount}] ${taskPreview}`,
11003
- runId: reconciled.runId,
11108
+ runId: reconciled2.runId,
11004
11109
  labels: labels2
11005
11110
  })
11006
11111
  }
11007
11112
  };
11008
11113
  }
11009
- return await spawnContinuationRun(reconciled, userInput, deps);
11114
+ return await spawnContinuationRun(reconciled2, userInput, deps);
11010
11115
  }
11011
11116
  if (action !== "status" && action !== "stop" && action !== "wait") {
11012
11117
  throw new Error(`controlAgentRun: \u672A\u77E5 action "${action}"\u3002`);
@@ -11021,82 +11126,65 @@ function createCliControlAgentRunExecutor(deps = {}) {
11021
11126
  };
11022
11127
  }
11023
11128
  if (action === "status") {
11024
- const reconciled = checkStaleRun(record.runId, deps) ?? record;
11129
+ const reconciled2 = checkStaleRun(record.runId, deps) ?? record;
11025
11130
  const logTail = tailLines > 0 ? tailFile(record.logPath, tailLines, resolveFs(deps)) : void 0;
11026
- return buildRunStatusPayload(reconciled, deps, { logTail });
11131
+ return buildRunStatusPayload(reconciled2, deps, { logTail });
11027
11132
  }
11028
11133
  if (action === "wait") {
11029
11134
  const timeoutMs = typeof args.timeoutMs === "number" && args.timeoutMs > 0 ? args.timeoutMs : DEFAULT_WAIT_TIMEOUT_MS;
11030
- const claimToken = claimRunRecord(record.runId, {
11031
- ...deps,
11032
- ttlMs: timeoutMs + ACK_LEASE_GRACE_MS
11033
- });
11034
- let claimConsumed = false;
11035
- try {
11036
- const startMs = resolveNowMs(deps);
11037
- const deadline = startMs + timeoutMs;
11038
- const baseSleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
11039
- const sleep = abortSignal ? (ms) => new Promise((resolve, reject) => {
11040
- const done = () => {
11041
- abortSignal.removeEventListener("abort", done);
11042
- resolve();
11043
- };
11044
- abortSignal.addEventListener("abort", done, { once: true });
11045
- Promise.resolve(baseSleep(ms)).then(done).catch((err) => {
11046
- abortSignal.removeEventListener("abort", done);
11047
- reject(err);
11048
- });
11049
- }) : baseSleep;
11050
- let reconciled = record;
11051
- for (; ; ) {
11052
- reconciled = checkStaleRun(record.runId, deps) ?? record;
11053
- if (isAgentRunTerminalStatus(reconciled.status)) break;
11054
- if (abortSignal?.aborted) {
11055
- throw new Error("controlAgentRun(wait) \u5DF2\u88AB\u4E2D\u6B62\u3002");
11056
- }
11057
- const nowMs = resolveNowMs(deps);
11058
- const waitedMs = nowMs - startMs;
11059
- if (nowMs >= deadline) {
11060
- return {
11061
- content: JSON.stringify({
11062
- runId: reconciled.runId,
11063
- found: true,
11064
- status: "timeout",
11065
- runStatus: reconciled.status,
11066
- pid: reconciled.pid ?? null,
11067
- agentKey: reconciled.agentKey,
11068
- ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
11069
- startedAt: reconciled.startedAt,
11070
- waitedMs,
11071
- timeoutMs,
11072
- ...buildProgressField(reconciled, nowMs)
11073
- }),
11074
- metadata: {
11075
- displayData: `\u23F3 wait \u8D85\u65F6\uFF08${Math.round(waitedMs / 1e3)}s\uFF09\uFF0Crun \u4ECD\u5728\u8FD0\u884C\uFF1A\u53EF\u7A0D\u540E\u518D wait\uFF0C\u6216\u6539\u7528 status/stop`
11076
- }
11077
- };
11135
+ let claimToken = null;
11136
+ const result = await waitForRunTerminal({
11137
+ read: () => checkStaleRun(record.runId, deps) ?? record,
11138
+ isTerminal: (state) => isAgentRunTerminalStatus(state.status),
11139
+ pollIntervalMs: WAIT_POLL_INTERVAL_MS,
11140
+ timeoutMs,
11141
+ abortSignal,
11142
+ sleep: deps.sleep,
11143
+ claim: {
11144
+ acquire: () => {
11145
+ claimToken = claimRunRecord(record.runId, { ...deps, ttlMs: timeoutMs + ACK_LEASE_GRACE_MS });
11146
+ return claimToken;
11147
+ },
11148
+ commit: (token) => {
11149
+ if (token) commitRunRecordClaim(record.runId, token, deps);
11150
+ else ackRunRecord(record.runId, deps);
11151
+ },
11152
+ release: (token) => {
11153
+ if (token) releaseRunRecordAck(record.runId, token, deps);
11078
11154
  }
11079
- await sleep(WAIT_POLL_INTERVAL_MS);
11080
- }
11081
- const payload = buildRunStatusPayload(reconciled, deps);
11082
- if (claimToken) commitRunRecordClaim(record.runId, claimToken, deps);
11083
- else ackRunRecord(reconciled.runId, deps);
11084
- claimConsumed = true;
11085
- return payload;
11086
- } finally {
11087
- if (!claimConsumed && claimToken) {
11088
- releaseRunRecordAck(record.runId, claimToken, deps);
11089
11155
  }
11156
+ });
11157
+ if (result.kind === "aborted") throw new Error("controlAgentRun(wait) \u5DF2\u88AB\u4E2D\u6B62\u3002");
11158
+ if (result.kind === "failed") throw result.error;
11159
+ if (result.kind === "timeout") {
11160
+ const reconciled2 = result.lastState ?? record;
11161
+ const nowMs = resolveNowMs(deps);
11162
+ return { content: JSON.stringify({ runId: reconciled2.runId, found: true, status: "timeout", runStatus: reconciled2.status, pid: reconciled2.pid ?? null, agentKey: reconciled2.agentKey, ...reconciled2.agentName ? { agentName: reconciled2.agentName } : {}, startedAt: reconciled2.startedAt, waitedMs: result.waitedMs, timeoutMs, ...buildProgressField(reconciled2, nowMs) }), metadata: { displayData: `\u23F3 wait \u8D85\u65F6\uFF08${Math.round(result.waitedMs / 1e3)}s\uFF09\uFF0Crun \u4ECD\u5728\u8FD0\u884C\uFF1A\u53EF\u7A0D\u540E\u518D wait\uFF0C\u6216\u6539\u7528 status/stop` } };
11090
11163
  }
11164
+ return buildRunStatusPayload(result.state, deps);
11165
+ }
11166
+ const reconciled = checkStaleRun(record.runId, deps) ?? record;
11167
+ if (isAgentRunTerminalStatus(reconciled.status)) {
11168
+ const labels2 = agentRunCardLabels();
11169
+ return {
11170
+ content: JSON.stringify({
11171
+ runId: reconciled.runId,
11172
+ found: true,
11173
+ status: reconciled.status
11174
+ }),
11175
+ metadata: {
11176
+ displayData: formatStopRunCard(reconciled.status, labels2)
11177
+ }
11178
+ };
11091
11179
  }
11092
- if (typeof record.pid === "number") {
11093
- const confirmed = await terminateRunProcess(record, "SIGTERM", deps);
11180
+ if (typeof reconciled.pid === "number") {
11181
+ const confirmed = await (deps.terminateRunProcess ?? terminateRunProcess)(reconciled, "SIGTERM", deps);
11094
11182
  if (!confirmed) {
11095
11183
  return {
11096
11184
  content: JSON.stringify({
11097
11185
  runId: record.runId,
11098
11186
  found: true,
11099
- status: record.status,
11187
+ status: reconciled.status,
11100
11188
  stopConfirmed: false
11101
11189
  }),
11102
11190
  metadata: {
@@ -11105,11 +11193,21 @@ function createCliControlAgentRunExecutor(deps = {}) {
11105
11193
  };
11106
11194
  }
11107
11195
  }
11108
- finalizeRunRecord(record.runId, { status: "killed" }, deps);
11196
+ const transition = transitionRunToTerminal(reconciled.runId, { status: "killed" }, deps);
11197
+ const finalRecord = transition.kind === "not_found" ? reconciled : transition.record;
11109
11198
  const labels = agentRunCardLabels();
11110
11199
  return {
11111
- content: JSON.stringify({ runId: record.runId, found: true, status: "killed" }),
11112
- metadata: { displayData: formatStopRunCard("killed", labels) }
11200
+ content: JSON.stringify({
11201
+ runId: finalRecord.runId,
11202
+ found: true,
11203
+ status: finalRecord.status,
11204
+ // 进程已确认终止、但 terminal 记录被并发 writer 占住(待 reconcile):
11205
+ // 如实标记 terminal 未落盘,不偷偷重写 killed。
11206
+ ...transition.kind === "contended" ? { terminalPersisted: false } : {}
11207
+ }),
11208
+ metadata: {
11209
+ displayData: transition.kind === "contended" ? `${formatStopRunCard(finalRecord.status, labels)} (pending reconcile)` : formatStopRunCard(finalRecord.status, labels)
11210
+ }
11113
11211
  };
11114
11212
  };
11115
11213
  }
@@ -11408,7 +11506,7 @@ function buildLocalToolExecutors(args) {
11408
11506
  var REFRESH_BY_PROVIDER = {
11409
11507
  chatgpt: refreshOpenAiCodexToken,
11410
11508
  // Previously only chatgpt was wired; expired antigravity/xai tokens then
11411
- // surfaced as "OAuth credential not found" even when ~/.nolo/credentials
11509
+ // surfaced as "OAuth credential not found" even when `$NOLO_HOME/credentials` (or `~/.nolo/credentials` when `NOLO_HOME` is unset)
11412
11510
  // still held a valid refresh_token.
11413
11511
  antigravity: refreshAntigravityOAuthToken,
11414
11512
  xai: xaiRefresh,
@@ -11426,11 +11524,12 @@ function createOAuthApiKeyRefResolver(options = {}) {
11426
11524
  const token = await resolveFreshAccessToken({
11427
11525
  provider,
11428
11526
  ...options.homeDir ? { homeDir: options.homeDir } : {},
11527
+ ...options.migration ? { migration: options.migration } : {},
11429
11528
  ...refresh ? { refresh } : {},
11430
11529
  ...opts?.force ? { force: true } : {}
11431
11530
  });
11432
11531
  if (token) return token;
11433
- const store = createOAuthTokenStore(options.homeDir);
11532
+ const store = createOAuthTokenStore(options.homeDir, options.migration);
11434
11533
  const credential = store.read(provider);
11435
11534
  if (credential && isTokenExpired(credential)) {
11436
11535
  throw new Error(
@@ -11451,7 +11550,7 @@ function resolveFallbackServers(env) {
11451
11550
  ].filter((value) => typeof value === "string" && value.trim().length > 0);
11452
11551
  return [...new Set(values.map(normalizeServerOrigin))];
11453
11552
  }
11454
- function resolveAuthToken(env) {
11553
+ function resolveAuthToken2(env) {
11455
11554
  return resolvePlatformAuthToken(env);
11456
11555
  }
11457
11556
  function resolveHybridReadTimeoutMs(env = process.env) {
@@ -11470,7 +11569,7 @@ function createCliHybridRecordStore(deps) {
11470
11569
  deps.env.NOLO_SERVER || deps.env.BASE_URL || DEFAULT_NOLO_SERVER_URL
11471
11570
  ),
11472
11571
  fallbackServers: resolveFallbackServers(deps.env),
11473
- authToken: resolveAuthToken(deps.env),
11572
+ authToken: resolveAuthToken2(deps.env),
11474
11573
  fetchImpl: deps.fetchImpl,
11475
11574
  requestTimeoutMs: resolveHybridReadTimeoutMs(deps.env)
11476
11575
  });
@@ -12258,10 +12357,15 @@ function createCliLocalRuntimeAdapter(deps) {
12258
12357
  deps.env,
12259
12358
  systemBuiltinSkills
12260
12359
  ) : [];
12360
+ const effectiveToolNames = [...requestedToolNames, ...additionalToolNames];
12261
12361
  activeAgentToolNames = buildLocalPolicyToolNames({
12262
12362
  agentKey: agentConfig?.key,
12263
- toolNames: [...requestedToolNames, ...additionalToolNames],
12264
- env: deps.env
12363
+ toolNames: effectiveToolNames,
12364
+ env: deps.env,
12365
+ buildProviderOpenAiTools: (toolArgs) => buildOpenAiTools({
12366
+ ...toolArgs,
12367
+ effectiveToolNames
12368
+ })
12265
12369
  });
12266
12370
  runtimeToolExecutionLimits = resolveLocalWorkspaceExecutorOptionsFromPolicy(
12267
12371
  resolveCurrentRunRuntimeToolPolicy(agentConfig)
@@ -12322,8 +12426,12 @@ function createCliLocalRuntimeAdapter(deps) {
12322
12426
  output: deps.output,
12323
12427
  cwd: workspaceRoot,
12324
12428
  titleGenerator: createLocalDialogTitleGenerator(deps, {
12325
- apiKeyRefResolver: createOAuthApiKeyRefResolver(),
12326
- credentialBroker: createFileCredentialBroker(),
12429
+ apiKeyRefResolver: createOAuthApiKeyRefResolver({
12430
+ migration: { enableLegacyMigration: true }
12431
+ }),
12432
+ credentialBroker: createFileCredentialBroker({
12433
+ migration: { enableLegacyMigration: true }
12434
+ }),
12327
12435
  loopbackRequest
12328
12436
  })
12329
12437
  }),
@@ -12366,8 +12474,15 @@ function createCliLocalRuntimeAdapter(deps) {
12366
12474
  () => void 0
12367
12475
  );
12368
12476
  }
12369
- const apiKeyRefResolver = createOAuthApiKeyRefResolver();
12370
- const credentialBroker = createFileCredentialBroker();
12477
+ const legacyCredentialMigration = {
12478
+ enableLegacyMigration: true
12479
+ };
12480
+ const apiKeyRefResolver = createOAuthApiKeyRefResolver({
12481
+ migration: legacyCredentialMigration
12482
+ });
12483
+ const credentialBroker = createFileCredentialBroker({
12484
+ migration: legacyCredentialMigration
12485
+ });
12371
12486
  const serverUrl = asOptionalTrimmedString(deps.env.NOLO_SERVER) ?? "https://us.nolo.chat";
12372
12487
  const authToken = asOptionalTrimmedString(deps.env.AUTH_TOKEN);
12373
12488
  const syncFetcher = authToken ? async (ref) => {
@@ -12442,6 +12557,7 @@ function createCliLocalRuntimeAdapter(deps) {
12442
12557
  const result = await executeLocalToolWithPolicy({
12443
12558
  env: deps.env,
12444
12559
  agentToolNames: activeAgentToolNames,
12560
+ runToolNames: activeAgentToolNames,
12445
12561
  call: injectedCall,
12446
12562
  executors: localToolExecutors,
12447
12563
  abortSignal: opts?.abortSignal,
@@ -12497,13 +12613,22 @@ export {
12497
12613
  isSubtaskRun,
12498
12614
  RUN_WAKE_CHANNEL_ENV,
12499
12615
  summarizeEndpoint,
12616
+ resolveLocalUserId,
12500
12617
  isBuiltinNoloAgentRef,
12618
+ resolveAuthToken,
12619
+ resolveFileWriteGateEnabled,
12620
+ isMachineBoundLocalhostCustomProvider,
12621
+ resolveBoundMachineId,
12622
+ isCliProviderAgentConfig,
12623
+ detectCurrentMachineId,
12501
12624
  readTimestamp,
12502
12625
  parseAgentRunEvent,
12626
+ isLiveAgentRunObservation,
12503
12627
  parseCliLocale,
12504
12628
  getCliLocale,
12505
12629
  setCliLocale,
12506
12630
  initCliLocale,
12631
+ dailyWelcomeTip,
12507
12632
  t,
12508
12633
  toolLabel,
12509
12634
  agentRunCardLabels,