nolo-cli 0.19.0 → 0.24.0-alpha.6

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 (133) hide show
  1. package/{_executeModel-X5PCIZN6.js → _executeModel-ARCMGGMY.js} +46 -44
  2. package/{action-LT7BRFLK.js → action-5MNAXR5B.js} +7 -6
  3. package/{addContentAction-PL3KKBDH.js → addContentAction-UNSYTVTB.js} +5 -5
  4. package/{addDialogAgentAction-FCMSKYAF.js → addDialogAgentAction-LJGNP2AO.js} +5 -5
  5. package/{agentDeleteCommand-2BZDQV36.js → agentDeleteCommand-C5PIEBMZ.js} +27 -26
  6. package/{agentEmailCommands-2QJDGRMB.js → agentEmailCommands-QTGQ3ZAD.js} +57 -55
  7. package/{agentListCommands-6VEPTKBI.js → agentListCommands-LRHBS3A5.js} +30 -26
  8. package/{agentMachineCommands-NVVHNWYI.js → agentMachineCommands-4PXIT4BP.js} +25 -24
  9. package/{agentRecordCommands-4GGRDMD4.js → agentRecordCommands-ZZPTYTYR.js} +52 -50
  10. package/{agentRunCommand-XOLQNKBZ.js → agentRunCommand-7ZTPZNUX.js} +55 -54
  11. package/{agentRunControl-Y5AFH5PQ.js → agentRunControl-SNUKXN6J.js} +6 -2
  12. package/{agentRuntimeLocal-7WYWCGL4.js → agentRuntimeLocal-QOYY5UV2.js} +19 -18
  13. package/{agentSlice-EAXPGEYV.js → agentSlice-J3W3RX2I.js} +5 -5
  14. package/{appDeleteCommands-77KR2RJ4.js → appDeleteCommands-7NS46XDH.js} +23 -22
  15. package/{appDeployCommands-K7CAHGBI.js → appDeployCommands-RSRNQ67U.js} +23 -22
  16. package/{appDeployStatusCommands-4OEKLTBT.js → appDeployStatusCommands-EF4RSGC6.js} +23 -22
  17. package/{appGetCommands-VM2WDLAZ.js → appGetCommands-YA7JWYUX.js} +23 -22
  18. package/{appListCommands-GX6BBA6U.js → appListCommands-WM2ON6JW.js} +23 -22
  19. package/{authCommand-DY6UUL6O.js → authCommand-HJP7FURK.js} +12 -13
  20. package/{authCommands-XTBV7OFZ.js → authCommands-NYZM2B2I.js} +4 -5
  21. package/{chunk-MKA6QE5E.js → chunk-2IPEVBUO.js} +126 -68
  22. package/{chunk-OWOHNGCN.js → chunk-2MBTWINN.js} +42 -3
  23. package/{chunk-K6EUAOW3.js → chunk-35RYGII3.js} +1 -1
  24. package/{chunk-TRT4I4UD.js → chunk-4POUK2BV.js} +2 -2
  25. package/{chunk-LLWKHDG4.js → chunk-4ULSC37S.js} +1 -3
  26. package/{chunk-EDV7EBOI.js → chunk-4ZH6GUJF.js} +2151 -1500
  27. package/{chunk-MVQ4TBSD.js → chunk-54VHTARN.js} +1 -1
  28. package/{chunk-L4F3I4SR.js → chunk-5HQQ4LUU.js} +4 -6
  29. package/{chunk-Z4NR32XR.js → chunk-5RGU3J7P.js} +13 -0
  30. package/{chunk-7BUYEZ6U.js → chunk-7H3UTGPM.js} +12 -72
  31. package/{chunk-RQN4SEKL.js → chunk-7W6GFNJL.js} +1 -1
  32. package/{chunk-HEGV7BH3.js → chunk-AQZCWJOG.js} +1 -1
  33. package/{chunk-3ND52WIL.js → chunk-ATWUOTJP.js} +180 -24
  34. package/chunk-CF7S2RYZ.js +376 -0
  35. package/{chunk-I2ZJKTG5.js → chunk-CGVRC2TB.js} +7 -7
  36. package/{chunk-UAIVG4J6.js → chunk-CHSCAUZN.js} +1 -8
  37. package/{chunk-KFEVY3ST.js → chunk-D34RI6NI.js} +18 -8
  38. package/{chunk-ROWQEJRP.js → chunk-DXJS7VSG.js} +3 -2
  39. package/{chunk-MHSGJW4Z.js → chunk-EHOYZRTI.js} +44 -14
  40. package/{chunk-XRZJGPFI.js → chunk-FON47ACC.js} +4 -4
  41. package/{chunk-SCTYAHYK.js → chunk-H2NAWOLH.js} +217 -141
  42. package/{chunk-MPVYDS7I.js → chunk-H6ODMJR3.js} +3 -3
  43. package/{chunk-R35XMF6F.js → chunk-H73ZV2GL.js} +352 -30
  44. package/{chunk-4T5F7YZQ.js → chunk-I6RJGORZ.js} +1 -1
  45. package/{chunk-OK6YSWLH.js → chunk-IICW77GI.js} +1 -1
  46. package/{chunk-VDXCXCXH.js → chunk-IUDMBCXC.js} +1 -1
  47. package/{chunk-AHCY2S2I.js → chunk-JADNODCQ.js} +1 -1
  48. package/{chunk-DFCFMCY6.js → chunk-JBLY6HQP.js} +2 -2
  49. package/{chunk-UGUW3FHG.js → chunk-JMSCXQUG.js} +2 -2
  50. package/{chunk-N54HIJVJ.js → chunk-KFUCLS7Z.js} +101 -9
  51. package/{chunk-FQZZLA3C.js → chunk-KXKQO4Q6.js} +17 -0
  52. package/{chunk-3Q7WHGCB.js → chunk-L65QKSVJ.js} +1 -1
  53. package/{chunk-3ZX7PERL.js → chunk-LALVWNE4.js} +20 -7
  54. package/{chunk-PJSV3IZ5.js → chunk-M3TMVJKG.js} +1 -1
  55. package/{chunk-REA4JLBH.js → chunk-M5OZCOBV.js} +7 -6
  56. package/{chunk-JLA4FXYC.js → chunk-MALVZUYL.js} +1 -1
  57. package/{chunk-GFUIQ4RY.js → chunk-MXFQHRSS.js} +1 -1
  58. package/{chunk-LSFAWXKC.js → chunk-N7J63Q6C.js} +1 -0
  59. package/{chunk-6Y7A3OQQ.js → chunk-NRY4GCKJ.js} +2 -0
  60. package/{chunk-G5U6LDLG.js → chunk-NVHPMDSZ.js} +6 -6
  61. package/{chunk-23FZYPLC.js → chunk-OJFYT3ZQ.js} +842 -1060
  62. package/{chunk-ELT65PZW.js → chunk-OXLLFZNF.js} +1 -1
  63. package/{chunk-CZ6NYQTV.js → chunk-P4QWLZGU.js} +2 -2
  64. package/{chunk-5MIDPSSK.js → chunk-PB7G5MAM.js} +3 -3
  65. package/{chunk-HWW2M4SN.js → chunk-QLVWFXZQ.js} +5 -4
  66. package/{chunk-VYHDJEQD.js → chunk-QNLLGS37.js} +136 -78
  67. package/{chunk-XHG22OEX.js → chunk-ROJI6DRT.js} +2 -2
  68. package/{chunk-BV4VEE3W.js → chunk-ROYOKSX4.js} +243 -354
  69. package/{chunk-VNAEBGDK.js → chunk-RZNYL4LW.js} +123 -26
  70. package/{chunk-RVOUXDFU.js → chunk-S6KVFOUG.js} +6 -34
  71. package/{chunk-V3ED5AWK.js → chunk-S77SCVBU.js} +27 -16
  72. package/{chunk-UBHAWFQ6.js → chunk-S7RWIPDI.js} +42 -19
  73. package/{chunk-B5TOXZAK.js → chunk-SIZQB7BD.js} +1 -1
  74. package/{chunk-DFFIZ25G.js → chunk-SLOGKB7M.js} +4 -1
  75. package/{chunk-FXUSIQC2.js → chunk-SROR5TSM.js} +1 -1
  76. package/{chunk-PIZYJVHQ.js → chunk-TN4YHAI3.js} +4 -4
  77. package/{chunk-IYEXFJPC.js → chunk-TW35GDNW.js} +64 -57
  78. package/chunk-UZ6XXCVR.js +50 -0
  79. package/{chunk-DKZFOK24.js → chunk-UZH44DWK.js} +7 -288
  80. package/{chunk-YGW4G5W5.js → chunk-X546QUDT.js} +61 -12
  81. package/chunk-YYLHWIW6.js +48 -0
  82. package/{chunk-SWDPIPOY.js → chunk-ZGVW7MSZ.js} +1 -1
  83. package/{chunk-34WPV75U.js → chunk-ZUXIXYJI.js} +1 -1
  84. package/{chunk-VC6OZXO5.js → chunk-ZWJOGMKH.js} +2 -26
  85. package/{cliExecutor-DNE7TCC4.js → cliExecutor-K3F7DMRO.js} +2 -2
  86. package/{codingSkills-36KN5NQT.js → codingSkills-EN6Z6G6U.js} +4 -4
  87. package/{createAgentAutomationAction-GNFF524X.js → createAgentAutomationAction-MKQWN4VQ.js} +19 -18
  88. package/{createDialogAction-RB55KCLO.js → createDialogAction-YWIZPLFS.js} +22 -20
  89. package/{createPageAction-Y7343GLU.js → createPageAction-74TTEIPC.js} +20 -19
  90. package/{db-W3O47YGF.js → db-W5UHK4P3.js} +150 -0
  91. package/{dbSlice-CGSRFJN3.js → dbSlice-5BKDURDL.js} +4 -4
  92. package/{dialogCommands-IAZK6YHQ.js → dialogCommands-MJIP32FL.js} +24 -23
  93. package/{dialogSlice-UQAXF23P.js → dialogSlice-KLLVH4WI.js} +24 -18
  94. package/{docCreateCommands-I2EWZGCI.js → docCreateCommands-5DN472U6.js} +24 -27
  95. package/{docDeleteCommands-IZ45UZKG.js → docDeleteCommands-HE76LBN4.js} +25 -24
  96. package/{docReadCommands-R6Z4QJYU.js → docReadCommands-XVGZSCBS.js} +24 -23
  97. package/{docStore-5HOJ4D7D.js → docStore-SPH3D6BT.js} +20 -19
  98. package/{docUpdateCommands-2LRBKQPY.js → docUpdateCommands-P7IAWUAD.js} +24 -27
  99. package/{fetchMessages-BMGVZVSE.js → fetchMessages-W4IKHPCS.js} +2 -3
  100. package/{getPricing-G7DLAST6.js → getPricing-WENPBVWH.js} +3 -3
  101. package/{handleSendMessageAction-Q4HY35WX.js → handleSendMessageAction-ZU6WJVL7.js} +23 -20
  102. package/index.js +74 -74
  103. package/{localDialogRead-4H3QJFLW.js → localDialogRead-JXTAHW2E.js} +2 -2
  104. package/{machineCommands-PKBPQKTY.js → machineCommands-NI76PVHK.js} +59 -57
  105. package/{machineWsRunDispatch-UZAW4OXJ.js → machineWsRunDispatch-W3G6NJVQ.js} +51 -49
  106. package/{models-DJFSJ7SW.js → models-DB27UAE3.js} +2 -2
  107. package/package.json +1 -1
  108. package/{read-3FMPZPER.js → read-F3L3T2WJ.js} +2 -1
  109. package/{readDocTool-VSYHKK3V.js → readDocTool-FOHWVA4R.js} +1 -1
  110. package/{readlineWorkspace-Y2RDOFZG.js → readlineWorkspace-BDH4G477.js} +880 -425
  111. package/{removeDialogAgentAction-OAGA2G3U.js → removeDialogAgentAction-QCFGIUIH.js} +8 -7
  112. package/{runAgentClientLoop-NBPIKJ6J.js → runAgentClientLoop-ZPKMXCM5.js} +45 -38
  113. package/{setDialogExtraReferencesAction-JZEXA5SL.js → setDialogExtraReferencesAction-DK4CKERU.js} +5 -5
  114. package/{setPrimaryDialogAgentAction-4ZUQQKDG.js → setPrimaryDialogAgentAction-SJSO6N27.js} +8 -7
  115. package/{settingSlice-7MNKHZ6R.js → settingSlice-XNM5AFPU.js} +6 -5
  116. package/{spaceCommands-DHCZ7J5I.js → spaceCommands-3GGBJRQR.js} +25 -24
  117. package/{spaceSlice-ZXLLG3CR.js → spaceSlice-47Z6XLFQ.js} +21 -18
  118. package/{streamAgentChatTurn-L3YW6LSB.js → streamAgentChatTurn-VT5K5JSD.js} +140 -98
  119. package/switchDialogAgentAction-4OAC6QRN.js +61 -0
  120. package/{tableCommands-BEQAGE4I.js → tableCommands-HEQYT2KP.js} +1 -1
  121. package/{toolApiClient-QI3YBNWB.js → toolApiClient-ISM4ZQX4.js} +2 -2
  122. package/{tools-ECGXR5QF.js → tools-L7RCHAPT.js} +36 -33
  123. package/{tuiSummaryLlmCaller-OMSCNHXA.js → tuiSummaryLlmCaller-3DYOLTVN.js} +6 -6
  124. package/{updateCommands-XTW55TOT.js → updateCommands-HTCOBXCA.js} +2 -2
  125. package/{updateDialogTitleAction-HQ2EUDFT.js → updateDialogTitleAction-KMPVPQ4A.js} +28 -27
  126. package/chunk-DL6EPNIK.js +0 -50
  127. package/chunk-V5R4NZP2.js +0 -78
  128. package/chunk-X4Q4UZEY.js +0 -26
  129. package/queryRunOverlay-O4LOMMPO.js +0 -161
  130. package/runOverlayPresentation-ZO4VCWEU.js +0 -11
  131. package/types-ZSTJ7MPR.js +0 -7
  132. package/{chunk-X7W4TNB4.js → chunk-CMKUBIGW.js} +3 -3
  133. package/{runtimeDoctorCommands-E2OUORHK.js → runtimeDoctorCommands-HSU632DY.js} +3 -3
@@ -3,11 +3,11 @@ import {
3
3
  refreshAntigravityOAuthToken,
4
4
  refreshOpenAiCodexToken,
5
5
  refreshXaiOAuthToken
6
- } from "./chunk-OK6YSWLH.js";
6
+ } from "./chunk-IICW77GI.js";
7
7
  import {
8
8
  buildLocalAgentLookupKeys,
9
9
  shouldReadAgentKeyRemotely
10
- } from "./chunk-SWDPIPOY.js";
10
+ } from "./chunk-ZGVW7MSZ.js";
11
11
  import {
12
12
  LOCAL_CODEX_AGENT_ID,
13
13
  LOCAL_CODEX_AGENT_KEY,
@@ -16,57 +16,61 @@ import {
16
16
  } from "./chunk-VHBWHNVT.js";
17
17
  import {
18
18
  inferCaptureIntent
19
- } from "./chunk-MVQ4TBSD.js";
19
+ } from "./chunk-54VHTARN.js";
20
20
  import {
21
21
  inlineImageUrlsForCustomProvider,
22
22
  prepareTools
23
- } from "./chunk-CZ6NYQTV.js";
23
+ } from "./chunk-P4QWLZGU.js";
24
24
  import {
25
25
  getAntigravityUserAgent,
26
26
  isAntigravityOAuthAgent,
27
27
  readAntigravityProjectId,
28
28
  resolveAntigravityCloudCodeBaseUrl
29
- } from "./chunk-FXUSIQC2.js";
29
+ } from "./chunk-SROR5TSM.js";
30
30
  import {
31
- FORCED_TOOLS,
32
- addDefaultLightWebToolsForConfiguredAgents,
33
- addDefaultSystemCapabilityTools,
34
- appendEnabledPackPromptPatches,
35
- applyDisabledTools,
36
- applySystemBuiltinSkillFilter,
37
- expandEnabledPacks,
38
31
  readXPostFunc,
39
32
  readXPostFunctionSchema,
40
33
  readXhsProfileFunc,
41
34
  readXhsProfileFunctionSchema,
42
35
  rememberMemoryFunctionSchema,
43
- resolveEffectiveEnabledPacks
44
- } from "./chunk-EDV7EBOI.js";
36
+ resolveAgentRequiredPackIds,
37
+ setTodoListFunc
38
+ } from "./chunk-4ZH6GUJF.js";
45
39
  import {
46
40
  createDrainExhaustedResponse,
47
41
  isCoreDrainingBody,
48
42
  normalizeNonNegativeMs,
49
43
  parseRetryAfterHeaderMs
50
44
  } from "./chunk-RQSOAMPJ.js";
51
- import {
52
- normalizeDialogTitle
53
- } from "./chunk-OWOHNGCN.js";
54
45
  import {
55
46
  getDefaultCliLocalRuntimeDb
56
47
  } from "./chunk-WJRJDX2W.js";
57
48
  import {
58
- prepareTokenUsageData
59
- } from "./chunk-SCTYAHYK.js";
49
+ prepareTokenUsageData,
50
+ resolveBuiltinPlatformAgentConfig
51
+ } from "./chunk-H2NAWOLH.js";
60
52
  import {
61
53
  BUILTIN_TITLE_LLM_CONFIG
62
54
  } from "./chunk-XOIF2TNF.js";
63
55
  import {
64
56
  fetchServerSyncedCredential
65
- } from "./chunk-REA4JLBH.js";
57
+ } from "./chunk-M5OZCOBV.js";
58
+ import {
59
+ FORCED_TOOLS,
60
+ addDefaultLightWebToolsForConfiguredAgents,
61
+ addDefaultSystemCapabilityTools,
62
+ appendEnabledPackPromptPatches,
63
+ applyDisabledTools,
64
+ applySystemBuiltinSkillFilter,
65
+ expandEnabledPacks,
66
+ resolveEffectiveEnabledPacks
67
+ } from "./chunk-CF7S2RYZ.js";
66
68
  import {
67
69
  buildAgentRuntimeDialogWritePlan,
70
+ buildLoadSkillExecutor,
68
71
  buildLocalWorkspaceOpenAiTools,
69
72
  buildLocalWorkspaceToolset,
73
+ buildNoloWorkspaceCliToolExecutors,
70
74
  createHybridRecordStore,
71
75
  createLocalWorkspaceToolExecutors,
72
76
  dialogMessageRecordToAgentRuntimeMessage,
@@ -76,36 +80,39 @@ import {
76
80
  parseSseDataLineObject,
77
81
  readOpenAiCompatibleSseCompletion,
78
82
  resolveOpenAiCompatibleProviderConfig
79
- } from "./chunk-R35XMF6F.js";
83
+ } from "./chunk-H73ZV2GL.js";
80
84
  import {
81
85
  buildPlatformChatCompletionRequest,
82
86
  canUsePlatformChatProvider,
87
+ hasDirectOpenAiCompatibleProvider,
83
88
  parsePlatformChatCompletionData,
84
89
  parsePlatformChatCompletionResponse,
85
90
  readSseDataValues,
86
91
  resolvePlatformChatProviderConfig,
87
92
  shouldUsePlatformChatProvider
88
- } from "./chunk-N54HIJVJ.js";
93
+ } from "./chunk-KFUCLS7Z.js";
89
94
  import {
90
95
  resolveAgentRuntimeConfigFromRecord
91
96
  } from "./chunk-OIQPORYI.js";
92
97
  import {
93
98
  summarizeToolArguments
94
- } from "./chunk-YGW4G5W5.js";
99
+ } from "./chunk-X546QUDT.js";
95
100
  import {
96
101
  convertMessagesToResponsesInput,
97
102
  toResponsesTools
98
- } from "./chunk-KFEVY3ST.js";
103
+ } from "./chunk-D34RI6NI.js";
99
104
  import {
100
105
  resolvePlatformAuthToken
101
- } from "./chunk-MHSGJW4Z.js";
106
+ } from "./chunk-EHOYZRTI.js";
102
107
  import {
103
- buildLoadSkillExecutor,
104
- buildNoloWorkspaceCliToolExecutors,
105
108
  buildNoloWorkspaceOpenAiTools,
106
109
  parseNoloWorkspaceToolArguments,
107
110
  resolveRuntimeToolSurfaceForAgent
108
- } from "./chunk-DKZFOK24.js";
111
+ } from "./chunk-UZH44DWK.js";
112
+ import {
113
+ buildDialogFallbackTitleFromUserInput,
114
+ normalizeDialogTitle
115
+ } from "./chunk-2MBTWINN.js";
109
116
  import {
110
117
  clipCompactText
111
118
  } from "./chunk-5MMAK75Q.js";
@@ -123,10 +130,7 @@ import {
123
130
  } from "./chunk-JZPBVBIY.js";
124
131
  import {
125
132
  isAdaptiveThinkingModelId
126
- } from "./chunk-UAIVG4J6.js";
127
- import {
128
- toErrorMessage
129
- } from "./chunk-HNMXYYJR.js";
133
+ } from "./chunk-CHSCAUZN.js";
130
134
  import {
131
135
  canonicalizeToolNames
132
136
  } from "./chunk-ZZ2MH7LE.js";
@@ -134,13 +138,14 @@ import {
134
138
  compactWhitespace
135
139
  } from "./chunk-DWLEOOGR.js";
136
140
  import {
141
+ ackRunRecord,
137
142
  checkStaleRun,
138
143
  finalizeRunRecord,
139
144
  findRunRecord,
140
145
  gcRunRecords,
141
146
  queryRunRecords,
142
147
  spawnLocalBackgroundRun
143
- } from "./chunk-VNAEBGDK.js";
148
+ } from "./chunk-RZNYL4LW.js";
144
149
  import {
145
150
  TASK_PREVIEW_MAX,
146
151
  formatListRunsCard,
@@ -152,14 +157,17 @@ import {
152
157
  isAgentRunTerminalStatus,
153
158
  resolveRunLabel,
154
159
  shortRunId
155
- } from "./chunk-FQZZLA3C.js";
160
+ } from "./chunk-KXKQO4Q6.js";
156
161
  import {
157
162
  CliProviderQuotaError,
158
163
  executeCli
159
- } from "./chunk-X7W4TNB4.js";
164
+ } from "./chunk-CMKUBIGW.js";
160
165
  import {
161
166
  buildCliPrompt
162
167
  } from "./chunk-ATNTHIZI.js";
168
+ import {
169
+ toErrorMessage
170
+ } from "./chunk-HNMXYYJR.js";
163
171
  import {
164
172
  isCompiledBinary,
165
173
  parseUserIdFromAuthToken
@@ -171,7 +179,7 @@ import {
171
179
  createTokenKey,
172
180
  createUserKey,
173
181
  dialogMessageRange
174
- } from "./chunk-6Y7A3OQQ.js";
182
+ } from "./chunk-NRY4GCKJ.js";
175
183
  import {
176
184
  asOptionalFiniteNumber
177
185
  } from "./chunk-WWC7I6TA.js";
@@ -182,15 +190,8 @@ import {
182
190
  asTrimmedLowercaseString
183
191
  } from "./chunk-QSJ3HFEF.js";
184
192
  import {
185
- BUILTIN_NOLO_AGENT_KEY,
186
- PUBLIC_DEEPSEEK_V4_FLASH_AGENT_KEY,
187
- PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
188
- PUBLIC_GLM_52_AGENT_KEY,
189
- PUBLIC_KIMI_K26_IMAGE_AGENT_KEY
190
- } from "./chunk-3ND52WIL.js";
191
- import {
192
- asTrimmedString
193
- } from "./chunk-3EUW3WEO.js";
193
+ isSystemBuiltinTrustedAgentKey
194
+ } from "./chunk-ATWUOTJP.js";
194
195
  import {
195
196
  isRecord
196
197
  } from "./chunk-KUG52IAP.js";
@@ -782,6 +783,18 @@ var STRINGS = {
782
783
  en: "Forked dialog {0} \u2192 {1} (no summary needed).",
783
784
  zh: "\u5DF2\u5206\u53C9\u5BF9\u8BDD {0} \u2192 {1}\uFF08\u65E0\u9700\u538B\u7F29\uFF09\u3002"
784
785
  },
786
+ compactSuccess: {
787
+ en: "\u2713 Compacted dialog {0} \u2192 {1} in {2}.",
788
+ zh: "\u2713 \u5DF2\u538B\u7F29\u5BF9\u8BDD {0} \u2192 {1}\uFF0C\u8017\u65F6 {2}\u3002"
789
+ },
790
+ compactSuccessWithCount: {
791
+ en: "\u2713 Compacted dialog {0} \u2192 {1} in {2} ({3} messages compressed).",
792
+ zh: "\u2713 \u5DF2\u538B\u7F29\u5BF9\u8BDD {0} \u2192 {1}\uFF0C\u8017\u65F6 {2}\uFF08\u538B\u7F29 {3} \u6761\u6D88\u606F\uFF09\u3002"
793
+ },
794
+ compactForked: {
795
+ en: "\u2713 Forked dialog {0} \u2192 {1} in {2} (no summary needed).",
796
+ zh: "\u2713 \u5DF2\u5206\u53C9\u5BF9\u8BDD {0} \u2192 {1}\uFF0C\u8017\u65F6 {2}\uFF08\u65E0\u9700\u538B\u7F29\uFF09\u3002"
797
+ },
785
798
  agentCurrent: { en: "Current agent: {0} ({1})", zh: "\u5F53\u524D agent\uFF1A{0}\uFF08{1}\uFF09" },
786
799
  agentUnknown: {
787
800
  en: `I don't know agent "{0}" yet.
@@ -915,6 +928,11 @@ var TOOL_LABELS = {
915
928
  captureVisualState: { en: "Capture", zh: "\u622A\u5C4F" },
916
929
  // Workspace / diagnostics
917
930
  searchWorkspace: { en: "Search workspace", zh: "\u641C\u7D22\u5DE5\u4F5C\u533A" },
931
+ // 同一工具在 web/server 工具面用 snake_case 命名(packages/ai/tools/index.ts)。
932
+ search_workspace: { en: "Search workspace", zh: "\u641C\u7D22\u5DE5\u4F5C\u533A" },
933
+ // 全空间搜索:内置 skill search-all-spaces 声明的工作区工具,loadSkill 后进入
934
+ // 工具面;同样需要中英文标签,避免回退成裸工具名。
935
+ search_all_spaces: { en: "Search all spaces", zh: "\u641C\u7D22\u5168\u90E8\u7A7A\u95F4" },
918
936
  cliDoctor: { en: "Doctor", zh: "\u81EA\u68C0" },
919
937
  cliWhoami: { en: "Whoami", zh: "\u67E5\u770B\u8EAB\u4EFD" },
920
938
  checkEnv: { en: "Check env", zh: "\u68C0\u67E5\u73AF\u5883" },
@@ -960,185 +978,6 @@ function agentRunCardLabels() {
960
978
  };
961
979
  }
962
980
 
963
- // packages/ai/tools/agent/quotaCircuitBreaker.ts
964
- var QUOTA_ERROR_PATTERNS = [
965
- /429/,
966
- /quota/i,
967
- /rate\s*limit/i,
968
- /too\s*many\s*requests/i,
969
- /额度/,
970
- /上限/,
971
- /用尽/,
972
- /CliProviderQuotaError/i
973
- ];
974
- var AGENT_NOT_FOUND_PATTERNS = [
975
- /agent[^\n]{0,80}not\s+found/i,
976
- /agent[^\n]{0,80}not\s+exist/i,
977
- /agent[^\n]{0,80}不存在/i,
978
- /agent[^\n]{0,80}未找到/i,
979
- /AGENT_NOT_FOUND/
980
- ];
981
- var AUTH_ERROR_PATTERNS = [
982
- /401/,
983
- /403/,
984
- /unauthori[sz]ed/i,
985
- /authentication\s+failed/i,
986
- /invalid\s+(api[-\s]?key|token|credential)/i,
987
- /api[-\s]?key\s+(invalid|missing|not\s+found)/i,
988
- /token\s*(invalid|expired|失效|过期)/i,
989
- /未授权/,
990
- /认证失败/,
991
- /凭证/
992
- ];
993
- var NETWORK_ERROR_PATTERNS = [
994
- /ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND|EHOSTUNREACH|EPIPE/i,
995
- /getaddrinfo|DNS\s+(error|fail)/i,
996
- /fetch\s+failed/i,
997
- /network\s+(error|unreachable|down|disconnected)/i,
998
- /socket\s+(hang|closed|error)/i,
999
- /连接失败/,
1000
- /网络错误|网络异常|无法连接/
1001
- ];
1002
- function findActiveBreaker(now, table, target) {
1003
- if (!Number.isFinite(now)) return void 0;
1004
- for (const entry of table) {
1005
- if (entry.target !== target) continue;
1006
- if (typeof entry.until === "number" && entry.until > now) return entry;
1007
- }
1008
- return void 0;
1009
- }
1010
- function isCliProviderQuotaErrorShape(error) {
1011
- if (!error || typeof error !== "object") return false;
1012
- const e = error;
1013
- return e.name === "CliProviderQuotaError" || typeof e.message === "string" && e.message.startsWith("[QUOTA_LIMITED:");
1014
- }
1015
- function isQuotaExhaustedError(error) {
1016
- if (!error) return false;
1017
- if (isCliProviderQuotaErrorShape(error)) return true;
1018
- if (error instanceof Error) {
1019
- return QUOTA_ERROR_PATTERNS.some((pattern) => pattern.test(error.message));
1020
- }
1021
- if (typeof error === "string") {
1022
- return QUOTA_ERROR_PATTERNS.some((pattern) => pattern.test(error));
1023
- }
1024
- const maybeStatus = error.status;
1025
- if (typeof maybeStatus === "number" && maybeStatus === 429) return true;
1026
- const maybeStatusCode = error.statusCode;
1027
- if (typeof maybeStatusCode === "number" && maybeStatusCode === 429) return true;
1028
- return false;
1029
- }
1030
- function isAgentNotFoundError(error) {
1031
- if (!error) return false;
1032
- const e = error;
1033
- if (e.code === "AGENT_NOT_FOUND") return true;
1034
- const message = typeof e.message === "string" ? e.message : typeof error === "string" ? error : "";
1035
- if (AGENT_NOT_FOUND_PATTERNS.some((pattern) => pattern.test(message))) return true;
1036
- if ((e.status === 404 || e.statusCode === 404) && /agent|不存在|未找到/i.test(message)) {
1037
- return true;
1038
- }
1039
- return false;
1040
- }
1041
- function extractMessage(error) {
1042
- if (typeof error === "string") return error;
1043
- if (error instanceof Error) return error.message;
1044
- if (error && typeof error === "object") {
1045
- const m = error.message;
1046
- return typeof m === "string" ? m : "";
1047
- }
1048
- return "";
1049
- }
1050
- function extractStatus(error) {
1051
- if (!error || typeof error !== "object") return void 0;
1052
- const e = error;
1053
- const s = typeof e.status === "number" ? e.status : void 0;
1054
- const sc = typeof e.statusCode === "number" ? e.statusCode : void 0;
1055
- return s ?? sc;
1056
- }
1057
- function parseResetsInMs(text) {
1058
- if (!text) return void 0;
1059
- const unitMs = (n, unit) => {
1060
- if (/^d/.test(unit)) return n * 24 * 3600 * 1e3;
1061
- if (/^h/.test(unit)) return n * 3600 * 1e3;
1062
- if (/^m/.test(unit)) return n * 60 * 1e3;
1063
- if (/^s/.test(unit)) return n * 1e3;
1064
- return NaN;
1065
- };
1066
- const re = /(\d+)\s*(d(?:ay|ays)?|h(?:r|rs|our|ours)?|m(?:in|ins|inute|inutes)?|s(?:ec|ecs|econd|econds)?)/gi;
1067
- let totalMs = 0;
1068
- let matched = false;
1069
- let m;
1070
- while ((m = re.exec(text)) !== null) {
1071
- const ms = unitMs(Number(m[1]), m[2]);
1072
- if (!Number.isFinite(ms)) continue;
1073
- totalMs += ms;
1074
- matched = true;
1075
- }
1076
- return matched ? totalMs : void 0;
1077
- }
1078
- function extractProvider(error) {
1079
- if (!error || typeof error !== "object") return void 0;
1080
- const p = error.provider;
1081
- if (typeof p === "string" && p.length > 0) return p;
1082
- const message = extractMessage(error);
1083
- const tag = /\[QUOTA_LIMITED:([^\]]+)\]/i.exec(message);
1084
- if (tag?.[1]) return tag[1];
1085
- return void 0;
1086
- }
1087
- function extractRetryAfterHeader(error) {
1088
- if (!error || typeof error !== "object") return void 0;
1089
- const headers = error.headers;
1090
- if (!headers || typeof headers !== "object") return void 0;
1091
- const raw = headers["retry-after"];
1092
- if (typeof raw !== "string" && typeof raw !== "number") return void 0;
1093
- const secs = Number(raw);
1094
- return Number.isFinite(secs) && secs > 0 ? secs * 1e3 : void 0;
1095
- }
1096
- function classifyRunFailure(error) {
1097
- const message = extractMessage(error);
1098
- const status = extractStatus(error);
1099
- const retryAfterMs = extractRetryAfterHeader(error) ?? parseResetsInMs(message);
1100
- if (isQuotaExhaustedError(error)) {
1101
- return {
1102
- reason: "quota",
1103
- provider: extractProvider(error),
1104
- // 纯函数不取时钟:resetsAt 由调用方用 now + retryAfterMs 计算后补齐
1105
- retryAfterMs,
1106
- message
1107
- };
1108
- }
1109
- if (isAgentNotFoundError(error)) {
1110
- return { reason: "agent-not-found", message };
1111
- }
1112
- if (isAuthError(error)) {
1113
- return { reason: "auth", message };
1114
- }
1115
- if (isNetworkError(error)) {
1116
- return { reason: "network", message };
1117
- }
1118
- return { reason: "other", message };
1119
- }
1120
- function isAuthError(error) {
1121
- const message = extractMessage(error);
1122
- const status = extractStatus(error);
1123
- if (status === 401 || status === 403) return true;
1124
- return AUTH_ERROR_PATTERNS.some((pattern) => pattern.test(message));
1125
- }
1126
- function isNetworkError(error) {
1127
- const message = extractMessage(error);
1128
- return NETWORK_ERROR_PATTERNS.some((pattern) => pattern.test(message));
1129
- }
1130
- var DEFAULT_QUOTA_BREAKER_MS = 6 * 3600 * 1e3;
1131
- var DEFAULT_AGENT_NOT_FOUND_BREAKER_MS = 15 * 60 * 1e3;
1132
- function buildBreakerEntry(now, target, kind, retryAfterMs) {
1133
- const ttl = kind === "quota" ? typeof retryAfterMs === "number" && retryAfterMs > 0 ? retryAfterMs : DEFAULT_QUOTA_BREAKER_MS : DEFAULT_AGENT_NOT_FOUND_BREAKER_MS;
1134
- return {
1135
- target,
1136
- kind,
1137
- until: now + ttl,
1138
- ...kind === "quota" && typeof retryAfterMs === "number" ? { resetsAt: now + retryAfterMs } : {}
1139
- };
1140
- }
1141
-
1142
981
  // packages/cli/client/localRuntimeDiagnostics.ts
1143
982
  import { ulid } from "ulid";
1144
983
  var preparedAgentRuntimeCache = /* @__PURE__ */ new Map();
@@ -1177,6 +1016,36 @@ function summarizeOpenAiToolNames(tools) {
1177
1016
  }, []);
1178
1017
  }
1179
1018
 
1019
+ // packages/agent-runtime/agentRunIsolation.ts
1020
+ var ORCHESTRATION_TOOL_NAMES = /* @__PURE__ */ new Set([
1021
+ "startAgentRun",
1022
+ "controlAgentRun",
1023
+ "listAgents",
1024
+ "readAgent",
1025
+ "startAgentDialog",
1026
+ "runStreamingAgent",
1027
+ "streamParallelAgents"
1028
+ ]);
1029
+ var SUBTASK_REMOVED_GIT_TOOL_NAMES = /* @__PURE__ */ new Set([
1030
+ "gitAdd",
1031
+ "gitCommit",
1032
+ "gitCreateBranch",
1033
+ "commitWorkspace"
1034
+ ]);
1035
+ var SUBTASK_REMOVED_TOOL_NAMES = /* @__PURE__ */ new Set([
1036
+ ...ORCHESTRATION_TOOL_NAMES,
1037
+ ...SUBTASK_REMOVED_GIT_TOOL_NAMES
1038
+ ]);
1039
+ function isSubtaskRun(env) {
1040
+ if (!env) return false;
1041
+ const value = env.NOLO_AGENT_RUN_CHILD;
1042
+ return typeof value === "string" && value.length > 0 && value !== "0";
1043
+ }
1044
+ function filterToolNamesForRunKind(toolNames, isSubtask) {
1045
+ if (!isSubtask) return [...toolNames];
1046
+ return toolNames.filter((name) => !SUBTASK_REMOVED_TOOL_NAMES.has(name));
1047
+ }
1048
+
1180
1049
  // packages/cli/client/localRuntimeAdapter.ts
1181
1050
  import { dirname as dirname2, extname, join as join2 } from "node:path";
1182
1051
  import { fileURLToPath } from "node:url";
@@ -1662,93 +1531,6 @@ function assertWithinLocalToolBudget(args) {
1662
1531
  );
1663
1532
  }
1664
1533
 
1665
- // packages/agent-runtime/builtinPlatformAgentConfigs.ts
1666
- var BUILTIN_PLATFORM_AGENT_CONFIGS = {
1667
- [PUBLIC_DEEPSEEK_V4_FLASH_AGENT_KEY]: {
1668
- key: PUBLIC_DEEPSEEK_V4_FLASH_AGENT_KEY,
1669
- name: "DeepSeek V4 Flash",
1670
- provider: "nolo",
1671
- model: "deepseek-v4-flash",
1672
- apiSource: "platform",
1673
- useServerProxy: true,
1674
- rawRecord: {
1675
- dbKey: PUBLIC_DEEPSEEK_V4_FLASH_AGENT_KEY,
1676
- isPublic: true,
1677
- provider: "nolo",
1678
- model: "deepseek-v4-flash",
1679
- apiSource: "platform",
1680
- useServerProxy: true
1681
- }
1682
- },
1683
- [PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY]: {
1684
- key: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
1685
- name: "DeepSeek V4 Pro",
1686
- provider: "nolo",
1687
- model: "deepseek-v4-pro",
1688
- apiSource: "platform",
1689
- useServerProxy: true,
1690
- rawRecord: {
1691
- dbKey: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
1692
- isPublic: true,
1693
- provider: "nolo",
1694
- model: "deepseek-v4-pro",
1695
- apiSource: "platform",
1696
- useServerProxy: true
1697
- }
1698
- },
1699
- [PUBLIC_GLM_52_AGENT_KEY]: {
1700
- key: PUBLIC_GLM_52_AGENT_KEY,
1701
- name: "GLM 5.2",
1702
- provider: "nolo",
1703
- model: "glm-5.2",
1704
- apiSource: "platform",
1705
- useServerProxy: true,
1706
- rawRecord: {
1707
- dbKey: PUBLIC_GLM_52_AGENT_KEY,
1708
- isPublic: true,
1709
- provider: "nolo",
1710
- model: "glm-5.2",
1711
- apiSource: "platform",
1712
- useServerProxy: true
1713
- }
1714
- },
1715
- [PUBLIC_KIMI_K26_IMAGE_AGENT_KEY]: {
1716
- key: PUBLIC_KIMI_K26_IMAGE_AGENT_KEY,
1717
- name: "Kimi K2.6",
1718
- provider: "nolo",
1719
- model: "kimi-k2.6",
1720
- apiSource: "platform",
1721
- useServerProxy: true,
1722
- rawRecord: {
1723
- dbKey: PUBLIC_KIMI_K26_IMAGE_AGENT_KEY,
1724
- isPublic: true,
1725
- provider: "nolo",
1726
- model: "kimi-k2.6",
1727
- apiSource: "platform",
1728
- useServerProxy: true
1729
- }
1730
- },
1731
- [BUILTIN_NOLO_AGENT_KEY]: {
1732
- key: BUILTIN_NOLO_AGENT_KEY,
1733
- name: "Nolo",
1734
- provider: "nolo",
1735
- model: "deepseek-v4-flash",
1736
- apiSource: "platform",
1737
- useServerProxy: true,
1738
- rawRecord: {
1739
- dbKey: BUILTIN_NOLO_AGENT_KEY,
1740
- isPublic: true,
1741
- provider: "nolo",
1742
- model: "deepseek-v4-flash",
1743
- apiSource: "platform",
1744
- useServerProxy: true
1745
- }
1746
- }
1747
- };
1748
- function resolveBuiltinPlatformAgentConfig(agentRef) {
1749
- return BUILTIN_PLATFORM_AGENT_CONFIGS[agentRef] ?? null;
1750
- }
1751
-
1752
1534
  // packages/cli/client/localDialogRecords.ts
1753
1535
  var localDialogMessageRecordToRuntimeMessage = dialogMessageRecordToAgentRuntimeMessage;
1754
1536
  function buildLocalDialogWritePlan(args) {
@@ -1814,22 +1596,6 @@ async function readDialogMessages(args) {
1814
1596
  }
1815
1597
 
1816
1598
  // packages/cli/client/cliProviderHelpers.ts
1817
- function buildDelegatedTaskContent(task, input) {
1818
- if (input === void 0 || input === null) {
1819
- return task;
1820
- }
1821
- if (typeof input === "string") {
1822
- return `${task}
1823
-
1824
- --- INPUT (text) ---
1825
- ${input}`;
1826
- }
1827
- const jsonStr = JSON.stringify(input, null, 2);
1828
- return `${task}
1829
-
1830
- --- INPUT (json) ---
1831
- ${jsonStr}`;
1832
- }
1833
1599
  function isCliProviderAgent(agentConfig) {
1834
1600
  return Boolean(
1835
1601
  agentConfig.apiSource === "cli" || agentConfig.provider === "cli" || agentConfig.cliProvider
@@ -1890,7 +1656,7 @@ function collectCliProviderImageInputs(messages) {
1890
1656
  }
1891
1657
 
1892
1658
  // packages/cli/client/cliAgentConfigHelpers.ts
1893
- var BUILTIN_NOLO_AGENT_KEY2 = NOLO_DEFAULT_AGENT_KEY;
1659
+ var BUILTIN_NOLO_AGENT_KEY = NOLO_DEFAULT_AGENT_KEY;
1894
1660
  var BUILTIN_NOLO_AGENT_ID = NOLO_DEFAULT_AGENT_ID;
1895
1661
  function resolveLocalUserId(env) {
1896
1662
  const explicitUserId = env.NOLO_LOCAL_USER_ID || env.NOLO_USER_ID;
@@ -1901,7 +1667,7 @@ function resolveLocalUserId(env) {
1901
1667
  function isBuiltinNoloAgentRef(ref) {
1902
1668
  if (typeof ref !== "string") return false;
1903
1669
  const normalized = ref.trim();
1904
- return normalized === BUILTIN_NOLO_AGENT_KEY2 || normalized === BUILTIN_NOLO_AGENT_ID || normalized.endsWith(`-${BUILTIN_NOLO_AGENT_ID}`);
1670
+ return normalized === BUILTIN_NOLO_AGENT_KEY || normalized === BUILTIN_NOLO_AGENT_ID || normalized.endsWith(`-${BUILTIN_NOLO_AGENT_ID}`);
1905
1671
  }
1906
1672
  function isBuiltinNoloAgentConfig(agentConfig) {
1907
1673
  const key = agentConfig?.key || agentConfig?.rawRecord?.dbKey || agentConfig?.rawRecord?.agentKey;
@@ -1913,14 +1679,15 @@ function withResolvedRuntimeToolSurface(agentConfig, env) {
1913
1679
  const currentUserId = resolveLocalUserId(env);
1914
1680
  const rawRecord = agentConfig.rawRecord ?? {};
1915
1681
  const ownerId = asOptionalTrimmedString(rawRecord.userId) ?? null;
1682
+ const agentKey = rawRecord.dbKey ?? agentConfig.key;
1916
1683
  const toolSurface = resolveRuntimeToolSurfaceForAgent({
1917
1684
  explicitToolNames: agentConfig.toolNames,
1918
1685
  currentUserId,
1919
1686
  agentOwnerId: ownerId,
1920
- agentKey: rawRecord.dbKey ?? agentConfig.key,
1687
+ agentKey,
1921
1688
  isPublic: !isBuiltinNoloAgentConfig(agentConfig) && rawRecord.isPublic === true,
1922
1689
  sharingLevel: typeof rawRecord.sharingLevel === "string" ? rawRecord.sharingLevel : null,
1923
- trustedPrivateInvocation: isBuiltinNoloAgentConfig(agentConfig),
1690
+ trustedPrivateInvocation: isBuiltinNoloAgentConfig(agentConfig) || isSystemBuiltinTrustedAgentKey(agentKey),
1924
1691
  runtimeHost: "cli"
1925
1692
  });
1926
1693
  return {
@@ -2439,54 +2206,29 @@ function aggregateBatch(input) {
2439
2206
  };
2440
2207
  }
2441
2208
 
2442
- // packages/ai/tools/agent/runtimeTodo.ts
2443
- var TODO_REVIEW_BLOCK = "BLOCK";
2444
- function deriveTodoStatus(input) {
2209
+ // packages/ai/tools/agent/agentRunTodo.ts
2210
+ var SUCCESS_STATUSES = /* @__PURE__ */ new Set(["completed", "done", "success", "passed", "finished"]);
2211
+ var FAILED_STATUSES = /* @__PURE__ */ new Set(["failed", "error", "stopped", "cancelled", "orphaned", "blocked"]);
2212
+ function deriveAgentRunTodoStatus(input) {
2445
2213
  const { todo, runs } = input;
2446
- if (todo.status === "abandoned") {
2447
- return { status: "abandoned" };
2448
- }
2449
- if (runs.length === 0) {
2450
- return { status: todo.status };
2451
- }
2452
- if (runs.some((r) => !isAgentRunTerminalStatus(r.status))) {
2453
- return { status: "running", latestRun: latestRun(runs) };
2214
+ if (!runs || runs.length === 0) {
2215
+ return { status: todo.status ?? "pending" };
2454
2216
  }
2455
- const latest = latestRun(runs);
2456
- if (latest?.reviewVerdict === TODO_REVIEW_BLOCK) {
2457
- return {
2458
- status: "blocked",
2459
- latestRun: latest,
2460
- blockedReason: clipSummary(latest.reviewReason, MAX_ERROR_SUMMARY_CHARS)
2461
- };
2217
+ const latestRun = runs[runs.length - 1];
2218
+ const hasRunning = runs.some(
2219
+ (r) => r.status === "running" || r.status === "in_progress" || r.status === "executing"
2220
+ );
2221
+ if (hasRunning) {
2222
+ return { status: "running", latestRun };
2462
2223
  }
2463
- if (latest?.status === "done") {
2464
- return { status: "done", latestRun: latest };
2224
+ const runStatus = (latestRun.status || "").toLowerCase();
2225
+ if (SUCCESS_STATUSES.has(runStatus)) {
2226
+ return { status: "done", latestRun };
2465
2227
  }
2466
- return { status: "pending", latestRun: latest };
2467
- }
2468
- function toEpochMs2(iso) {
2469
- if (!iso) return void 0;
2470
- const ms = Date.parse(iso);
2471
- return Number.isFinite(ms) ? ms : void 0;
2472
- }
2473
- function latestRun(runs) {
2474
- let latest;
2475
- let latestScore = -1;
2476
- for (const run of runs) {
2477
- const score = toEpochMs2(run.finishedAt) ?? toEpochMs2(run.startedAt) ?? -1;
2478
- if (latest === void 0 || score >= latestScore) {
2479
- latest = run;
2480
- latestScore = score;
2481
- }
2228
+ if (FAILED_STATUSES.has(runStatus)) {
2229
+ return { status: "failed", latestRun };
2482
2230
  }
2483
- return latest;
2484
- }
2485
- function clipSummary(text, max) {
2486
- if (!text) return void 0;
2487
- const folded = text.replace(/\s+/g, " ").trim();
2488
- if (folded.length === 0) return void 0;
2489
- return folded.length > max ? `${folded.slice(0, max - 1)}\u2026` : folded;
2231
+ return { status: todo.status ?? "pending", latestRun };
2490
2232
  }
2491
2233
 
2492
2234
  // packages/cli/client/fileSystemStores.ts
@@ -2519,50 +2261,41 @@ function readJson(path, fs) {
2519
2261
  function writeJson(path, data, fs) {
2520
2262
  fs.writeFileSync(path, JSON.stringify(data, null, 2));
2521
2263
  }
2522
- function createFileSystemCircuitBreakerStore(opts = {}) {
2264
+ function createFileSystemTodoStore(opts = {}) {
2523
2265
  const env = opts.env ?? process.env;
2524
2266
  const homedir = opts.homedir ?? nodeHomedir;
2525
2267
  const fs = opts.fs ?? nodeFs;
2526
- const filePath = opts.filePath ?? join(resolveNoloHome(env, homedir), "breakers.json");
2268
+ const noloHome = resolveNoloHome(env, homedir);
2269
+ const filePath = opts.filePath ?? join(noloHome, "agent_run_todos.json");
2270
+ const oldFilePath = join(noloHome, "todos.json");
2527
2271
  const loadMap = () => {
2528
- const data = readJson(filePath, fs);
2529
- const map = /* @__PURE__ */ new Map();
2530
- if (data?.entries) {
2531
- for (const entry of data.entries) {
2532
- if (entry && typeof entry.target === "string") map.set(entry.target, entry);
2272
+ if (!opts.filePath && !fs.existsSync(filePath) && fs.existsSync(oldFilePath)) {
2273
+ const oldData = readJson(oldFilePath, fs);
2274
+ const map2 = /* @__PURE__ */ new Map();
2275
+ if (oldData?.todos) {
2276
+ for (const item of oldData.todos) {
2277
+ if (item && typeof item.id === "string") {
2278
+ let status = "pending";
2279
+ if (item.status === "running") status = "running";
2280
+ else if (item.status === "done") status = "done";
2281
+ else if (item.status === "blocked" || item.status === "abandoned" || item.status === "failed") status = "failed";
2282
+ const rec = {
2283
+ ...item,
2284
+ id: item.id,
2285
+ title: item.title || "Untitled Task",
2286
+ status,
2287
+ runIds: Array.isArray(item.runIds) ? item.runIds : [],
2288
+ createdAt: item.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
2289
+ updatedAt: item.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
2290
+ };
2291
+ map2.set(rec.id, rec);
2292
+ }
2293
+ }
2533
2294
  }
2295
+ ensureDir(dirname(filePath), fs);
2296
+ writeJson(filePath, { todos: [...map2.values()] }, fs);
2297
+ return map2;
2534
2298
  }
2535
- return map;
2536
- };
2537
- const persist = (map) => {
2538
- ensureDir(dirname(filePath), fs);
2539
- writeJson(filePath, { entries: [...map.values()] }, fs);
2540
- };
2541
- return {
2542
- get(target) {
2543
- return loadMap().get(target);
2544
- },
2545
- set(entry) {
2546
- const map = loadMap();
2547
- map.set(entry.target, entry);
2548
- persist(map);
2549
- },
2550
- clear(target) {
2551
- const map = loadMap();
2552
- map.delete(target);
2553
- persist(map);
2554
- },
2555
- clearAll() {
2556
- persist(/* @__PURE__ */ new Map());
2557
- }
2558
- };
2559
- }
2560
- function createFileSystemTodoStore(opts = {}) {
2561
- const env = opts.env ?? process.env;
2562
- const homedir = opts.homedir ?? nodeHomedir;
2563
- const fs = opts.fs ?? nodeFs;
2564
- const filePath = opts.filePath ?? join(resolveNoloHome(env, homedir), "todos.json");
2565
- const loadMap = () => {
2566
2299
  const data = readJson(filePath, fs);
2567
2300
  const map = /* @__PURE__ */ new Map();
2568
2301
  if (data?.todos) {
@@ -2578,13 +2311,15 @@ function createFileSystemTodoStore(opts = {}) {
2578
2311
  };
2579
2312
  return {
2580
2313
  async getTodo(id) {
2581
- return loadMap().get(id);
2314
+ return loadMap().get(id) ?? null;
2582
2315
  },
2583
- async listTodos(filter) {
2584
- const all = [...loadMap().values()];
2585
- if (!filter?.statuses || filter.statuses.length === 0) return all;
2586
- const wanted = new Set(filter.statuses);
2587
- return all.filter((t2) => wanted.has(t2.status));
2316
+ async listTodos() {
2317
+ return [...loadMap().values()];
2318
+ },
2319
+ async saveTodo(todo) {
2320
+ const map = loadMap();
2321
+ map.set(todo.id, todo);
2322
+ persist(map);
2588
2323
  },
2589
2324
  async putTodo(todo) {
2590
2325
  const map = loadMap();
@@ -2593,8 +2328,10 @@ function createFileSystemTodoStore(opts = {}) {
2593
2328
  },
2594
2329
  async deleteTodo(id) {
2595
2330
  const map = loadMap();
2331
+ const existed = map.has(id);
2596
2332
  map.delete(id);
2597
2333
  persist(map);
2334
+ return existed;
2598
2335
  }
2599
2336
  };
2600
2337
  }
@@ -2621,10 +2358,8 @@ var tailFile = (logPath, tailLines, fs) => {
2621
2358
  return void 0;
2622
2359
  }
2623
2360
  };
2624
- var resolveBreakerStore = (deps) => deps.breakerStore ?? createFileSystemCircuitBreakerStore({ env: deps.env, homedir: deps.homedir, fs: deps.fs });
2625
2361
  var resolveTodoStore = (deps) => deps.todoStore ?? createFileSystemTodoStore({ env: deps.env, homedir: deps.homedir, fs: deps.fs });
2626
2362
  var resolveNowMs = (deps) => typeof deps.nowMs === "function" ? deps.nowMs() : Date.now();
2627
- var resolveTarget = (deps, agentKey) => typeof deps.resolveProviderTarget === "function" ? deps.resolveProviderTarget(agentKey) : agentKey;
2628
2363
  function buildProgressField(record, nowMs) {
2629
2364
  const activity = record.activity;
2630
2365
  if (!activity || isAgentRunTerminalStatus(record.status)) return {};
@@ -2642,6 +2377,55 @@ function buildProgressField(record, nowMs) {
2642
2377
  }
2643
2378
  return { progress };
2644
2379
  }
2380
+ var WAIT_POLL_INTERVAL_MS = 500;
2381
+ var DEFAULT_WAIT_TIMEOUT_MS = 1e5;
2382
+ function buildRunStatusPayload(reconciled, deps, opts = {}) {
2383
+ const logLines = opts.logTail ? opts.logTail.split("\n") : void 0;
2384
+ const name = resolveRunLabel(reconciled);
2385
+ const labels = agentRunCardLabels();
2386
+ return {
2387
+ content: JSON.stringify({
2388
+ runId: reconciled.runId,
2389
+ found: true,
2390
+ status: reconciled.status,
2391
+ pid: reconciled.pid ?? null,
2392
+ agentKey: reconciled.agentKey,
2393
+ ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
2394
+ startedAt: reconciled.startedAt,
2395
+ endedAt: reconciled.endedAt ?? null,
2396
+ exitCode: reconciled.exitCode ?? null,
2397
+ // Expose dialogId so the caller can read the agent's actual output
2398
+ // via `nolo dialog read <dialogId>`. The dialog is the authoritative
2399
+ // result store; the run log is the child process stdout/stderr,
2400
+ // whose contents vary by provider (some stream tokens to stdout,
2401
+ // some only emit startup + stderr). Because status does not carry
2402
+ // logTail by default, a "done" run with an empty logTail is
2403
+ // indistinguishable from a hung run without this field. Surfacing
2404
+ // dialogId gives the caller a reliable way to fetch the result.
2405
+ ...reconciled.dialogId ? { dialogId: reconciled.dialogId } : {},
2406
+ // Progress is what makes tailLines:0 an actual answer to "is it
2407
+ // stuck?". Without it a poll returns `running` and a pid, so the only
2408
+ // way to tell a working run from a wedged one was to pull 30 lines of
2409
+ // log — the exact thing the orchestration prompt tells the model not
2410
+ // to do. The registry has been recording this all along and `nolo
2411
+ // agent status` has been printing it; only the tool was blind.
2412
+ ...buildProgressField(reconciled, resolveNowMs(deps)),
2413
+ ...opts.logTail !== void 0 ? { logTail: opts.logTail } : {},
2414
+ ...logLines ? { logLines } : {}
2415
+ }),
2416
+ metadata: {
2417
+ displayData: formatStatusRunCard(name, reconciled.status, {
2418
+ runId: reconciled.runId,
2419
+ timing: {
2420
+ startedAt: readTimestamp(reconciled.startedAt),
2421
+ finishedAt: readTimestamp(reconciled.endedAt)
2422
+ },
2423
+ logLines,
2424
+ labels
2425
+ })
2426
+ }
2427
+ };
2428
+ }
2645
2429
  function createCliStartAgentRunExecutor(deps = {}) {
2646
2430
  return async (call) => {
2647
2431
  const args = parseCallArgs(call);
@@ -2649,29 +2433,7 @@ function createCliStartAgentRunExecutor(deps = {}) {
2649
2433
  const task = typeof args.task === "string" ? args.task.trim() : "";
2650
2434
  if (!agentKey) throw new Error("startAgentRun: \u7F3A\u5C11 agentKey \u53C2\u6570\u3002");
2651
2435
  if (!task) throw new Error("startAgentRun: \u7F3A\u5C11\u6709\u6548\u7684 task \u6587\u672C\u63CF\u8FF0\u3002");
2652
- const breakerStore = resolveBreakerStore(deps);
2653
- const target = resolveTarget(deps, agentKey);
2654
2436
  const nowMs = resolveNowMs(deps);
2655
- const activeBreaker = findActiveBreaker(
2656
- nowMs,
2657
- [breakerStore.get(target)].filter(Boolean),
2658
- target
2659
- );
2660
- if (activeBreaker) {
2661
- const resetsAt = activeBreaker.resetsAt;
2662
- return {
2663
- content: JSON.stringify({
2664
- rejected: true,
2665
- reason: "quota",
2666
- provider: target,
2667
- ...resetsAt !== void 0 ? { resetsAt } : {},
2668
- message: `provider ${target} \u5904\u4E8E\u7194\u65AD\u671F\uFF08\u914D\u989D\u8017\u5C3D\uFF09\uFF0C\u5EFA\u8BAE\u6539\u6D3E\u5176\u5B83 provider\u3002`
2669
- }),
2670
- metadata: {
2671
- displayData: `Run rejected \xB7 quota breaker active on ${target}`
2672
- }
2673
- };
2674
- }
2675
2437
  const message = typeof args.input === "undefined" ? task : `${task}
2676
2438
 
2677
2439
  --- \u9644\u52A0\u8F93\u5165 ---
@@ -2719,16 +2481,15 @@ ${JSON.stringify(args.input)}`;
2719
2481
  id: todoId,
2720
2482
  title: taskPreview || task.slice(0, 100),
2721
2483
  status: existing?.status ?? "pending",
2722
- ...existing?.specPath ? { specPath: existing.specPath } : {},
2723
- ...existing?.worktree ? { worktree: existing.worktree } : {},
2724
- ...existing?.branch ? { branch: existing.branch } : {},
2725
- ...deps.cwd ? { worktree: deps.cwd } : {},
2726
2484
  runIds,
2727
- deps: existing?.deps ?? [],
2728
2485
  createdAt: existing?.createdAt ?? nowIso,
2729
2486
  updatedAt: nowIso
2730
2487
  };
2731
- await todoStore.putTodo(todo);
2488
+ if (typeof todoStore.saveTodo === "function") {
2489
+ await todoStore.saveTodo(todo);
2490
+ } else {
2491
+ await todoStore.putTodo(todo);
2492
+ }
2732
2493
  } catch {
2733
2494
  }
2734
2495
  }
@@ -2808,12 +2569,11 @@ function createCliControlAgentRunExecutor(deps = {}) {
2808
2569
  }
2809
2570
  };
2810
2571
  }
2811
- if (action === "todo") {
2572
+ if (action === "todo" || action === "agentRunTodo" || action === "agent_run_todo") {
2812
2573
  const todoStore = resolveTodoStore(deps);
2813
- const statusesRaw = typeof args.status === "string" ? args.status.trim() : void 0;
2814
- const filter = statusesRaw && statusesRaw !== "all" ? { statuses: statusesRaw.split(",").map((s) => s.trim()).filter(Boolean) } : void 0;
2815
- const todos = await todoStore.listTodos(filter);
2816
- const enriched = await Promise.all(
2574
+ const todos = await todoStore.listTodos();
2575
+ const statusFilter = typeof args.status === "string" ? args.status.trim().toLowerCase() : void 0;
2576
+ let enriched = await Promise.all(
2817
2577
  todos.map(async (todo) => {
2818
2578
  const runSummaries = [];
2819
2579
  for (const rid of todo.runIds) {
@@ -2822,26 +2582,29 @@ function createCliControlAgentRunExecutor(deps = {}) {
2822
2582
  runSummaries.push({
2823
2583
  runId: rec.runId,
2824
2584
  status: rec.status,
2825
- startedAt: rec.startedAt,
2585
+ startedAt: readTimestamp(rec.startedAt)?.toString(),
2586
+ finishedAt: readTimestamp(rec.endedAt)?.toString(),
2826
2587
  ...rec.agentName ? { agentName: rec.agentName } : {}
2827
2588
  });
2828
2589
  }
2829
- const derived = deriveTodoStatus({
2590
+ const derived = deriveAgentRunTodoStatus({
2830
2591
  todo: { id: todo.id, status: todo.status },
2831
- runs: runSummaries,
2832
- now: new Date(resolveNowMs(deps)).toISOString()
2592
+ runs: runSummaries
2833
2593
  });
2834
2594
  return {
2835
2595
  id: todo.id,
2836
2596
  title: todo.title,
2837
2597
  status: derived.status,
2838
2598
  runIds: todo.runIds,
2839
- ...derived.blockedReason ? { blockedReason: derived.blockedReason } : {},
2840
2599
  ...derived.latestRun ? { latestRunId: derived.latestRun.runId, latestRunStatus: derived.latestRun.status } : {},
2841
2600
  updatedAt: todo.updatedAt
2842
2601
  };
2843
2602
  })
2844
2603
  );
2604
+ if (statusFilter && statusFilter !== "all") {
2605
+ const wanted = new Set(statusFilter.split(",").map((s) => s.trim()).filter(Boolean));
2606
+ enriched = enriched.filter((t2) => wanted.has(t2.status.toLowerCase()));
2607
+ }
2845
2608
  return {
2846
2609
  content: JSON.stringify({ todos: enriched, count: enriched.length }),
2847
2610
  metadata: {
@@ -2855,7 +2618,7 @@ function createCliControlAgentRunExecutor(deps = {}) {
2855
2618
  }
2856
2619
  };
2857
2620
  }
2858
- if (action !== "status" && action !== "stop") {
2621
+ if (action !== "status" && action !== "stop" && action !== "wait") {
2859
2622
  throw new Error(`controlAgentRun: \u672A\u77E5 action "${action}"\u3002`);
2860
2623
  }
2861
2624
  if (!args.runId) throw new Error(`controlAgentRun(action:"${action}"): \u7F3A\u5C11 runId\u3002`);
@@ -2870,70 +2633,43 @@ function createCliControlAgentRunExecutor(deps = {}) {
2870
2633
  if (action === "status") {
2871
2634
  const reconciled = checkStaleRun(record.runId, deps) ?? record;
2872
2635
  const logTail = tailLines > 0 ? tailFile(record.logPath, tailLines, resolveFs(deps)) : void 0;
2873
- const name = resolveRunLabel(reconciled);
2874
- const logLines = logTail ? logTail.split("\n") : void 0;
2875
- const labels2 = agentRunCardLabels();
2876
- if (reconciled.status === "failed" || reconciled.status === "orphaned") {
2877
- try {
2878
- const failureSource = logTail ?? reconciled.note ?? "";
2879
- const failureInfo = classifyRunFailure(
2880
- failureSource || reconciled.status
2881
- );
2882
- if (failureInfo.reason === "quota") {
2883
- const t2 = resolveTarget(deps, reconciled.agentKey);
2884
- const entry = buildBreakerEntry(
2885
- resolveNowMs(deps),
2886
- t2,
2887
- "quota",
2888
- failureInfo.retryAfterMs
2889
- );
2890
- resolveBreakerStore(deps).set(entry);
2891
- }
2892
- } catch {
2636
+ return buildRunStatusPayload(reconciled, deps, { logTail });
2637
+ }
2638
+ if (action === "wait") {
2639
+ const timeoutMs = typeof args.timeoutMs === "number" && args.timeoutMs > 0 ? args.timeoutMs : DEFAULT_WAIT_TIMEOUT_MS;
2640
+ const startMs = resolveNowMs(deps);
2641
+ const deadline = startMs + timeoutMs;
2642
+ const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
2643
+ let reconciled = record;
2644
+ for (; ; ) {
2645
+ reconciled = checkStaleRun(record.runId, deps) ?? record;
2646
+ if (isAgentRunTerminalStatus(reconciled.status)) break;
2647
+ const nowMs = resolveNowMs(deps);
2648
+ const waitedMs = nowMs - startMs;
2649
+ if (nowMs >= deadline) {
2650
+ return {
2651
+ content: JSON.stringify({
2652
+ runId: reconciled.runId,
2653
+ found: true,
2654
+ status: "timeout",
2655
+ runStatus: reconciled.status,
2656
+ pid: reconciled.pid ?? null,
2657
+ agentKey: reconciled.agentKey,
2658
+ ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
2659
+ startedAt: reconciled.startedAt,
2660
+ waitedMs,
2661
+ timeoutMs,
2662
+ ...buildProgressField(reconciled, nowMs)
2663
+ }),
2664
+ metadata: {
2665
+ 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`
2666
+ }
2667
+ };
2893
2668
  }
2669
+ await sleep(WAIT_POLL_INTERVAL_MS);
2894
2670
  }
2895
- return {
2896
- content: JSON.stringify({
2897
- runId: reconciled.runId,
2898
- found: true,
2899
- status: reconciled.status,
2900
- pid: reconciled.pid ?? null,
2901
- agentKey: reconciled.agentKey,
2902
- ...reconciled.agentName ? { agentName: reconciled.agentName } : {},
2903
- startedAt: reconciled.startedAt,
2904
- endedAt: reconciled.endedAt ?? null,
2905
- exitCode: reconciled.exitCode ?? null,
2906
- // Expose dialogId so the caller can read the agent's actual output
2907
- // via `nolo dialog read <dialogId>`. The dialog is the authoritative
2908
- // result store; the run log is the child process stdout/stderr,
2909
- // whose contents vary by provider (some stream tokens to stdout,
2910
- // some only emit startup + stderr). Because status does not carry
2911
- // logTail by default, a "done" run with an empty logTail is
2912
- // indistinguishable from a hung run without this field. Surfacing
2913
- // dialogId gives the caller a reliable way to fetch the result.
2914
- ...reconciled.dialogId ? { dialogId: reconciled.dialogId } : {},
2915
- // Progress is what makes tailLines:0 an actual answer to "is it
2916
- // stuck?". Without it a poll returns `running` and a pid, so the only
2917
- // way to tell a working run from a wedged one was to pull 30 lines of
2918
- // log — the exact thing the orchestration prompt tells the model not
2919
- // to do. The registry has been recording this all along and `nolo
2920
- // agent status` has been printing it; only the tool was blind.
2921
- ...buildProgressField(reconciled, resolveNowMs(deps)),
2922
- ...logTail !== void 0 ? { logTail } : {},
2923
- ...logLines ? { logLines } : {}
2924
- }),
2925
- metadata: {
2926
- displayData: formatStatusRunCard(name, reconciled.status, {
2927
- runId: reconciled.runId,
2928
- timing: {
2929
- startedAt: readTimestamp(reconciled.startedAt),
2930
- finishedAt: readTimestamp(reconciled.endedAt)
2931
- },
2932
- logLines,
2933
- labels: labels2
2934
- })
2935
- }
2936
- };
2671
+ ackRunRecord(reconciled.runId, deps);
2672
+ return buildRunStatusPayload(reconciled, deps);
2937
2673
  }
2938
2674
  if (typeof record.pid === "number") {
2939
2675
  try {
@@ -3168,6 +2904,20 @@ function buildLocalToolExecutors(args) {
3168
2904
  controlAgentRun: createCliControlAgentRunExecutor({
3169
2905
  env: args.env
3170
2906
  }),
2907
+ setTodoList: async (call) => {
2908
+ const parsedArgs = typeof call?.arguments === "string" ? (() => {
2909
+ try {
2910
+ return JSON.parse(call.arguments);
2911
+ } catch {
2912
+ return {};
2913
+ }
2914
+ })() : call?.arguments || {};
2915
+ const res = await setTodoListFunc(parsedArgs);
2916
+ return {
2917
+ content: JSON.stringify(res.rawData),
2918
+ metadata: { displayData: res.displayData }
2919
+ };
2920
+ },
3171
2921
  ...args.pastedTextStore ? { readPastedText: createReadPastedTextExecutor(args.pastedTextStore) } : {},
3172
2922
  ...args.localToolExecutors ?? {}
3173
2923
  };
@@ -3297,12 +3047,15 @@ function convertOpenAiMessagesToGemini(messages, options) {
3297
3047
  }
3298
3048
  if (role === "assistant") {
3299
3049
  flushPendingFunctionCalls();
3300
- const parts = [];
3301
3050
  const text = messageText(
3302
3051
  content
3303
3052
  );
3304
- if (text) parts.push({ text });
3305
3053
  const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
3054
+ if (text) pushOrMergeContent("model", [{ text }]);
3055
+ if (toolCalls.length > 0 && contents.length > 0 && contents[contents.length - 1]?.role !== "user") {
3056
+ contents.push({ role: "user", parts: [{ text: "" }] });
3057
+ }
3058
+ const parts = [];
3306
3059
  for (const call of toolCalls) {
3307
3060
  const name = call?.function?.name?.trim();
3308
3061
  if (!name) continue;
@@ -3330,15 +3083,11 @@ function convertOpenAiMessagesToGemini(messages, options) {
3330
3083
  if (role === "tool") {
3331
3084
  const toolCallId = "tool_call_id" in raw && typeof raw.tool_call_id === "string" ? raw.tool_call_id : "";
3332
3085
  const rawName = "name" in raw && typeof raw.name === "string" ? raw.name.trim() : "";
3333
- const name = toolNamesById.get(toolCallId) || rawName || pendingFunctionCalls[0]?.name || "tool";
3334
3086
  const pendingIndex = pendingFunctionCalls.findIndex(
3335
- (p) => toolCallId ? p.id === toolCallId : p.name === name
3087
+ (p) => toolCallId ? p.id === toolCallId : rawName ? p.name === rawName : true
3336
3088
  );
3337
- if (pendingIndex !== -1) {
3338
- pendingFunctionCalls.splice(pendingIndex, 1);
3339
- } else if (pendingFunctionCalls.length > 0) {
3340
- pendingFunctionCalls.shift();
3341
- }
3089
+ if (pendingIndex === -1) continue;
3090
+ const [{ name, id }] = pendingFunctionCalls.splice(pendingIndex, 1);
3342
3091
  const output = messageText(content) || "{}";
3343
3092
  pushOrMergeContent("user", [
3344
3093
  {
@@ -3349,7 +3098,7 @@ function convertOpenAiMessagesToGemini(messages, options) {
3349
3098
  // Gemini contents 转成 Claude messages 时需要 functionResponse →
3350
3099
  // tool_result 的 tool_use_id;缺 id 时网关报
3351
3100
  // "tool_result.tool_use_id: Field required"(HTTP 400)。
3352
- ...toolCallId ? { id: toolCallId } : {}
3101
+ ...id ? { id } : {}
3353
3102
  }
3354
3103
  }
3355
3104
  ]);
@@ -10076,13 +9825,25 @@ function stablePromptCacheKey(parts) {
10076
9825
  }
10077
9826
  return `nolo-codex-${hash.toString(16).padStart(8, "0")}`;
10078
9827
  }
9828
+ function convertMessagesToCodexInput(messages) {
9829
+ return convertMessagesToResponsesInput(messages).map((item) => {
9830
+ if (item.type !== "reasoning") return item;
9831
+ return {
9832
+ type: "reasoning",
9833
+ summary: item.content.map((part) => ({
9834
+ type: "summary_text",
9835
+ text: part.text
9836
+ }))
9837
+ };
9838
+ });
9839
+ }
10079
9840
  function buildCodexRequestBody(args, identity = createCodexRequestIdentity()) {
10080
9841
  const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
10081
9842
  const nonSystem = rawMessages.filter((m) => {
10082
9843
  const role = m && typeof m === "object" ? String(m.role) : "";
10083
9844
  return role !== "system" && role !== "developer";
10084
9845
  });
10085
- const input = convertMessagesToResponsesInput(nonSystem);
9846
+ const input = convertMessagesToCodexInput(nonSystem);
10086
9847
  const instructions = collectInstructions(rawMessages, args.agentConfig.prompt);
10087
9848
  const stableInstructions = collectStableInstructions(rawMessages, args.agentConfig.prompt);
10088
9849
  const model = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gpt-5.5";
@@ -10107,12 +9868,47 @@ function buildCodexRequestBody(args, identity = createCodexRequestIdentity()) {
10107
9868
  }
10108
9869
  return body;
10109
9870
  }
9871
+ function codexStreamFailureStatus(failure) {
9872
+ const marker = `${failure.code ?? ""} ${failure.type ?? ""}`.toLowerCase();
9873
+ if (marker.includes("overload") || marker.includes("service_unavailable")) return 503;
9874
+ if (marker.includes("rate_limit") || marker.includes("usage_limit")) return 429;
9875
+ return 502;
9876
+ }
9877
+ var RETRYABLE_CODEX_STREAM_STATUSES = /* @__PURE__ */ new Set([503]);
9878
+ var CODEX_STREAM_MAX_ATTEMPTS = 3;
9879
+ var CODEX_STREAM_RETRY_BASE_DELAY_MS = 500;
9880
+ function toStreamFailure(raw) {
9881
+ if (!raw || typeof raw !== "object") return void 0;
9882
+ const err = raw;
9883
+ const reason = typeof err.reason === "string" ? err.reason : void 0;
9884
+ const message = typeof err.message === "string" && err.message ? err.message : reason ? `Codex upstream ended incomplete: ${reason}.` : "";
9885
+ if (!message) return void 0;
9886
+ const code = typeof err.code === "string" ? err.code : reason;
9887
+ return {
9888
+ ...code ? { code } : {},
9889
+ ...typeof err.type === "string" ? { type: err.type } : {},
9890
+ message
9891
+ };
9892
+ }
10110
9893
  function aggregateResponsesStream(events) {
10111
9894
  let text = "";
10112
9895
  const toolCalls = [];
10113
9896
  let usage;
9897
+ let failure;
10114
9898
  for (const ev of events) {
10115
9899
  const type = String(ev.type ?? "");
9900
+ if (type === "error") {
9901
+ failure = failure ?? toStreamFailure(ev.error);
9902
+ continue;
9903
+ }
9904
+ if (type === "response.failed" || type === "response.incomplete") {
9905
+ const response = ev.response;
9906
+ failure = failure ?? toStreamFailure(response?.error) ?? toStreamFailure(response?.incomplete_details) ?? {
9907
+ code: type === "response.incomplete" ? "response_incomplete" : "response_failed",
9908
+ message: `Codex upstream ended with ${type}.`
9909
+ };
9910
+ continue;
9911
+ }
10116
9912
  if (type === "response.output_text.delta" && typeof ev.delta === "string") {
10117
9913
  text += ev.delta;
10118
9914
  continue;
@@ -10149,7 +9945,7 @@ function aggregateResponsesStream(events) {
10149
9945
  }
10150
9946
  }
10151
9947
  }
10152
- return { text, toolCalls, usage };
9948
+ return { text, toolCalls, usage, failure };
10153
9949
  }
10154
9950
  async function readSseEvents(response) {
10155
9951
  return readSseDataValues(response, (line) => {
@@ -10157,19 +9953,9 @@ async function readSseEvents(response) {
10157
9953
  return ev && !Array.isArray(ev) ? ev : null;
10158
9954
  });
10159
9955
  }
10160
- async function fetchCodexResponsesCompletion(args) {
9956
+ var defaultSleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
9957
+ async function callCodexResponsesOnce(args, accountId) {
10161
9958
  const fetchImpl = args.fetchImpl ?? fetch;
10162
- const accountId = args.accountId?.trim() || decodeCodexAccountId(args.accessToken);
10163
- if (!accountId) {
10164
- return {
10165
- status: 401,
10166
- body: {
10167
- error: {
10168
- message: "ChatGPT Codex credential is missing chatgpt_account_id. Re-run `nolo auth chatgpt`."
10169
- }
10170
- }
10171
- };
10172
- }
10173
9959
  const identity = createCodexRequestIdentity();
10174
9960
  const body = buildCodexRequestBody(args, identity);
10175
9961
  const headers = buildCodexCompatibilityHeaders(identity, accountId);
@@ -10188,7 +9974,19 @@ async function fetchCodexResponsesCompletion(args) {
10188
9974
  };
10189
9975
  }
10190
9976
  const events = await readSseEvents(response);
10191
- const { text, toolCalls, usage } = aggregateResponsesStream(events);
9977
+ const { text, toolCalls, usage, failure } = aggregateResponsesStream(events);
9978
+ if (failure) {
9979
+ return {
9980
+ status: codexStreamFailureStatus(failure),
9981
+ body: {
9982
+ error: {
9983
+ message: failure.message,
9984
+ ...failure.code ? { code: failure.code } : {},
9985
+ ...failure.type ? { type: failure.type } : {}
9986
+ }
9987
+ }
9988
+ };
9989
+ }
10192
9990
  const message = {
10193
9991
  role: "assistant",
10194
9992
  content: text || null
@@ -10208,6 +10006,30 @@ async function fetchCodexResponsesCompletion(args) {
10208
10006
  }
10209
10007
  };
10210
10008
  }
10009
+ async function fetchCodexResponsesCompletion(args) {
10010
+ const accountId = args.accountId?.trim() || decodeCodexAccountId(args.accessToken);
10011
+ if (!accountId) {
10012
+ return {
10013
+ status: 401,
10014
+ body: {
10015
+ error: {
10016
+ message: "ChatGPT Codex credential is missing chatgpt_account_id. Re-run `nolo auth chatgpt`."
10017
+ }
10018
+ }
10019
+ };
10020
+ }
10021
+ const sleep = args.sleep ?? defaultSleep2;
10022
+ const requestedMaxAttempts = Number(args.maxAttempts);
10023
+ const maxAttempts = Number.isFinite(requestedMaxAttempts) ? Math.min(10, Math.max(1, Math.floor(requestedMaxAttempts))) : CODEX_STREAM_MAX_ATTEMPTS;
10024
+ let result = await callCodexResponsesOnce(args, accountId);
10025
+ for (let attempt = 1; attempt < maxAttempts; attempt += 1) {
10026
+ if (!RETRYABLE_CODEX_STREAM_STATUSES.has(result.status)) break;
10027
+ if (args.signal?.aborted) break;
10028
+ await sleep(CODEX_STREAM_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1));
10029
+ result = await callCodexResponsesOnce(args, accountId);
10030
+ }
10031
+ return result;
10032
+ }
10211
10033
  function isCodexOAuthAgent(agentConfig) {
10212
10034
  if (!agentConfig) return false;
10213
10035
  const apiKeyRef = asTrimmedLowercaseString(agentConfig.apiKeyRef);
@@ -10302,313 +10124,15 @@ function createOAuthApiKeyRefResolver(options = {}) {
10302
10124
  };
10303
10125
  }
10304
10126
 
10305
- // packages/cli/client/hybridRecordStore.ts
10306
- function resolveFallbackServers(env) {
10307
- const values = [
10308
- env.NOLO_SERVER_URL,
10309
- env.BASE_URL,
10310
- ...NOLO_CLUSTER_SERVERS
10311
- ].filter((value) => typeof value === "string" && value.trim().length > 0);
10312
- return [...new Set(values.map(normalizeServerOrigin))];
10127
+ // packages/cli/client/cliWorkspaceToolVariants.ts
10128
+ function shouldUseDeclaredOnlyLocalWorkspaceTools(env) {
10129
+ const value = env.NOLO_LOCAL_WORKSPACE_TOOLSET || env.NOLO_LOCAL_TOOLSET_MODE || "";
10130
+ return value === "declared-only" || value === "declared";
10313
10131
  }
10314
- function resolveAuthToken(env) {
10315
- return resolvePlatformAuthToken(env);
10316
- }
10317
- function createCliHybridRecordStore(deps) {
10318
- return createHybridRecordStore({
10319
- db: deps.db,
10320
- defaultServer: normalizeServerOrigin(
10321
- deps.env.NOLO_SERVER || deps.env.BASE_URL || DEFAULT_NOLO_SERVER_URL
10322
- ),
10323
- fallbackServers: resolveFallbackServers(deps.env),
10324
- authToken: resolveAuthToken(deps.env),
10325
- fetchImpl: deps.fetchImpl
10326
- });
10327
- }
10328
-
10329
- // packages/agent-runtime/dialogTitleLlm.ts
10330
- async function generateLocalDialogTitle(input) {
10331
- const { env, messages, fallbackTitle } = input;
10332
- const timeoutMs = input.timeoutMs ?? 15e3;
10333
- const visibleMessages = messages.filter((m) => m.role === "user" || m.role === "assistant").slice(-12).map((m) => ({
10334
- role: m.role,
10335
- content: typeof m.content === "string" ? m.content : extractText(m.content)
10336
- }));
10337
- if (visibleMessages.length === 0) {
10338
- return { title: fallbackTitle, source: "fallback" };
10339
- }
10340
- try {
10341
- const providerConfig = await input.resolveProviderConfig({
10342
- agentConfig: { ...BUILTIN_TITLE_LLM_CONFIG, key: BUILTIN_TITLE_LLM_CONFIG.id },
10343
- env
10344
- });
10345
- if (!providerConfig?.authToken) {
10346
- return { title: fallbackTitle, source: "fallback" };
10347
- }
10348
- const request = input.buildRequest({
10349
- providerConfig,
10350
- messages: [
10351
- {
10352
- role: "user",
10353
- content: JSON.stringify(
10354
- visibleMessages.map((m) => ({ role: m.role, content: m.content }))
10355
- )
10356
- }
10357
- ],
10358
- stream: false
10359
- });
10360
- const res = await input.fetchImpl(request.url, {
10361
- ...request.init,
10362
- signal: AbortSignal.timeout(timeoutMs)
10363
- });
10364
- if (!res.ok) {
10365
- return { title: fallbackTitle, source: "fallback" };
10366
- }
10367
- const raw = await res.text().catch(() => "");
10368
- const data = safeParseJson(raw);
10369
- if (!data) {
10370
- return { title: fallbackTitle, source: "fallback" };
10371
- }
10372
- const parsed = input.parseResponse({ providerConfig, data });
10373
- const generated = normalizeDialogTitle(parsed.content);
10374
- if (!generated) {
10375
- return { title: fallbackTitle, source: "fallback" };
10376
- }
10377
- return { title: generated, source: "llm" };
10378
- } catch {
10379
- return { title: fallbackTitle, source: "fallback" };
10380
- }
10381
- }
10382
- function extractText(content) {
10383
- if (typeof content === "string") return content;
10384
- if (Array.isArray(content)) {
10385
- return content.filter((part) => part?.type === "text").map((part) => part.text ?? "").join(" ");
10386
- }
10387
- return "";
10388
- }
10389
- function safeParseJson(raw) {
10390
- try {
10391
- return JSON.parse(raw);
10392
- } catch {
10393
- return null;
10394
- }
10395
- }
10396
-
10397
- // packages/cli/client/localRuntimeDialog.ts
10398
- async function resolveStore(deps) {
10399
- if (deps.store) return deps.store;
10400
- return createCliHybridRecordStore({
10401
- db: deps.db ?? await defaultLocalRuntimeDb(),
10402
- env: deps.env,
10403
- fetchImpl: deps.fetchImpl
10404
- });
10405
- }
10406
- async function getOrCreateSharedStore(deps) {
10407
- if (deps.store) return deps.store;
10408
- const cacheKey = normalizeRuntimeCacheCwd(deps.cwd);
10409
- let storePromise = hybridStoreCache.get(cacheKey);
10410
- if (!storePromise) {
10411
- storePromise = resolveStore(deps);
10412
- hybridStoreCache.set(cacheKey, storePromise);
10413
- }
10414
- return storePromise;
10415
- }
10416
- function createLocalDialogTitleGenerator(deps, ctx) {
10417
- return async (input) => {
10418
- if (!canUsePlatformChatProvider(deps.env)) {
10419
- return null;
10420
- }
10421
- const result = await generateLocalDialogTitle({
10422
- messages: input.messages,
10423
- env: deps.env,
10424
- fetchImpl: async (url, init) => fetchWithTransientRetry(
10425
- deps.fetchImpl ?? fetch,
10426
- url,
10427
- init,
10428
- {
10429
- sleep: deps.sleep,
10430
- loopbackRequest: ctx.loopbackRequest
10431
- }
10432
- ),
10433
- resolveProviderConfig: async (args) => resolvePlatformChatProviderConfig({
10434
- agentConfig: args.agentConfig,
10435
- env: args.env,
10436
- apiKeyRefResolver: ctx.apiKeyRefResolver,
10437
- credentialBroker: ctx.credentialBroker
10438
- }),
10439
- buildRequest: (args) => buildPlatformChatCompletionRequest({
10440
- providerConfig: args.providerConfig,
10441
- messages: args.messages,
10442
- stream: false
10443
- }),
10444
- parseResponse: (args) => parsePlatformChatCompletionResponse({
10445
- providerConfig: args.providerConfig,
10446
- data: args.data,
10447
- trace: []
10448
- }),
10449
- fallbackTitle: input.fallbackTitle,
10450
- timeoutMs: 15e3
10451
- });
10452
- return result.source === "llm" ? result.title : null;
10453
- };
10454
- }
10455
- async function writeLocalTokenRecord(args) {
10456
- const rawUsage = args.input.result.usage;
10457
- if (!rawUsage || typeof rawUsage !== "object" || Object.keys(rawUsage).length === 0) {
10458
- return;
10459
- }
10460
- const timestamp = args.now();
10461
- const prepared = prepareTokenUsageData({
10462
- rawUsage,
10463
- agentConfig: {
10464
- model: args.input.result.model || "unknown",
10465
- provider: args.input.result.provider,
10466
- apiSource: "cli"
10467
- },
10468
- userId: args.userId,
10469
- agentId: args.input.agentKey,
10470
- dialogId: args.dialogId,
10471
- timestamp,
10472
- entry_path: "cli-local"
10473
- });
10474
- const recordKey = createTokenKey.record(args.userId, timestamp);
10475
- const tokenRecord = {
10476
- id: args.createId(),
10477
- type: "token",
10478
- ...prepared.tokenData
10479
- };
10480
- await args.store.write(recordKey, tokenRecord);
10481
- }
10482
- async function writeDialog(args) {
10483
- let existingDialog = null;
10484
- if (args.input.continueDialogId) {
10485
- const dialogKey = `dialog-${args.userId}-${args.input.continueDialogId}`;
10486
- existingDialog = await args.store.read(dialogKey);
10487
- }
10488
- const authToken = resolveRuntimeAuthToken(args.env);
10489
- const isLoggedIn = Boolean(
10490
- authToken && (parseUserIdFromAuthToken(authToken) || args.env.NOLO_MACHINE_API_KEY?.trim())
10491
- );
10492
- const hasExistingTitle = typeof existingDialog?.title === "string" && existingDialog.title.trim();
10493
- let titleOverride;
10494
- if (isLoggedIn && !hasExistingTitle && args.titleGenerator) {
10495
- const fallbackTitle = extractLastUserText(args.input.messages).trim().slice(0, 80) || "Local agent run";
10496
- try {
10497
- const generated = await args.titleGenerator({
10498
- messages: args.input.messages,
10499
- fallbackTitle
10500
- });
10501
- if (generated) {
10502
- titleOverride = generated;
10503
- }
10504
- } catch {
10505
- }
10506
- }
10507
- const plan = buildLocalDialogWritePlan({
10508
- input: args.input,
10509
- userId: args.userId,
10510
- now: args.now(),
10511
- createId: args.createId,
10512
- existingDialog,
10513
- cwd: args.cwd,
10514
- ...titleOverride ? { titleOverride } : {}
10515
- });
10516
- await args.store.batch(plan.ops);
10517
- try {
10518
- await writeLocalTokenRecord({
10519
- store: args.store,
10520
- input: args.input,
10521
- userId: args.userId,
10522
- dialogId: plan.dialogId,
10523
- now: args.now,
10524
- createId: args.createId,
10525
- output: args.output
10526
- });
10527
- } catch (error) {
10528
- args.output?.write(
10529
- `[nolo] Token usage record write failed (non-fatal): ${toErrorMessage(error)}
10530
- `
10531
- );
10532
- }
10533
- const hasSubjectRefs = localTurnHasSubjectRefs(args.input);
10534
- const isLocalUser = args.userId === "local";
10535
- if (!isLocalUser) {
10536
- try {
10537
- const syncResult = await syncLocalDialogEvidenceToRemote({
10538
- env: args.env,
10539
- fetchImpl: args.fetchImpl,
10540
- input: args.input,
10541
- ops: plan.ops,
10542
- output: args.output,
10543
- userId: args.userId
10544
- });
10545
- if (!syncResult.attempted) {
10546
- if (hasSubjectRefs) {
10547
- args.output?.write(
10548
- "[nolo] Local dialog evidence is local-only; set NOLO_SERVER and AUTH_TOKEN to make subjectRefs remotely queryable.\n"
10549
- );
10550
- }
10551
- }
10552
- } catch (error) {
10553
- if (hasSubjectRefs) {
10554
- throw error;
10555
- }
10556
- args.output?.write(
10557
- `[nolo] Remote dialog evidence sync failed; local dialog only: ${toErrorMessage(
10558
- error
10559
- )}
10560
- `
10561
- );
10562
- }
10563
- }
10564
- return { dialogId: plan.dialogId, title: plan.title };
10565
- }
10566
- function resolveCliDialogRecordKey(userId, dialogId) {
10567
- if (dialogId.startsWith("dialog-") && !dialogId.includes("-msg-")) {
10568
- return dialogId;
10569
- }
10570
- return `dialog-${userId}-${dialogId}`;
10571
- }
10572
- async function loadCliDialogSummary(args) {
10573
- const dialogKey = resolveCliDialogRecordKey(args.userId, args.dialogId);
10574
- const record = await args.store.read(dialogKey);
10575
- if (!record || typeof record !== "object") return null;
10576
- const summary = typeof record.summary === "string" ? record.summary.trim() : "";
10577
- if (!summary) return null;
10578
- const summarizedBeforeId = record.summarizedBeforeId;
10579
- return {
10580
- summary,
10581
- ...typeof summarizedBeforeId === "string" && summarizedBeforeId ? { summarizedBeforeId } : {}
10582
- };
10583
- }
10584
- async function saveCliDialogSummary(args) {
10585
- const dialogKey = resolveCliDialogRecordKey(args.userId, args.dialogId);
10586
- const existing = await args.store.read(dialogKey) ?? {};
10587
- const bareId = typeof existing.id === "string" && existing.id ? existing.id : args.dialogId.startsWith("dialog-") ? args.dialogId.slice(args.dialogId.lastIndexOf("-") + 1) : args.dialogId;
10588
- const compressionCount = typeof existing.compressionCount === "number" ? existing.compressionCount + 1 : 1;
10589
- await args.store.write(dialogKey, {
10590
- ...existing,
10591
- id: bareId,
10592
- dbKey: dialogKey,
10593
- type: "dialog",
10594
- userId: args.userId,
10595
- summary: args.summary,
10596
- ...args.summarizedBeforeId !== void 0 ? { summarizedBeforeId: args.summarizedBeforeId } : {},
10597
- compressionCount,
10598
- summaryPending: false,
10599
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
10600
- });
10601
- }
10602
-
10603
- // packages/cli/client/cliWorkspaceToolVariants.ts
10604
- function shouldUseDeclaredOnlyLocalWorkspaceTools(env) {
10605
- const value = env.NOLO_LOCAL_WORKSPACE_TOOLSET || env.NOLO_LOCAL_TOOLSET_MODE || "";
10606
- return value === "declared-only" || value === "declared";
10607
- }
10608
- function resolveGlobFilesDescriptionVariant(env) {
10609
- return resolveLocalWorkspaceDescriptionVariant(
10610
- env.NOLO_GLOBFILES_DESCRIPTION_VARIANT
10611
- );
10132
+ function resolveGlobFilesDescriptionVariant(env) {
10133
+ return resolveLocalWorkspaceDescriptionVariant(
10134
+ env.NOLO_GLOBFILES_DESCRIPTION_VARIANT
10135
+ );
10612
10136
  }
10613
10137
  function resolveListFilesDescriptionVariant(env) {
10614
10138
  return resolveLocalWorkspaceDescriptionVariant(
@@ -10652,61 +10176,10 @@ function resolveLocalWorkspaceParameterVariant(value) {
10652
10176
  return value === "minimal" || value === "scoped" || value === "rich" ? value : "rich";
10653
10177
  }
10654
10178
 
10655
- // packages/cli/client/cliChildDialogPersist.ts
10656
- async function persistCliPendingChildDialog(args) {
10657
- const nowIso = new Date(args.now).toISOString();
10658
- const dialogKey = `dialog-${args.userId}-${args.dialogId}`;
10659
- const record = {
10660
- id: args.dialogId,
10661
- dbKey: dialogKey,
10662
- type: "dialog",
10663
- userId: args.userId,
10664
- cybots: [args.agentKey],
10665
- primaryAgentKey: args.agentKey,
10666
- title: args.title.slice(0, 80),
10667
- status: "pending",
10668
- triggerType: "cli-local",
10669
- executionMode: args.background ? "background" : "foreground",
10670
- createdAt: nowIso,
10671
- updatedAt: nowIso,
10672
- ...args.spaceId ? { spaceId: args.spaceId } : {},
10673
- ...args.parentDialogId ? { parentDialogId: args.parentDialogId } : {},
10674
- ...args.rootDialogId ? { rootDialogId: args.rootDialogId } : {},
10675
- localRuntime: {
10676
- host: "cli",
10677
- workspaceRoot: args.workspaceRoot,
10678
- workspaceKind: "current",
10679
- workspaceAccess: "inherited"
10680
- }
10681
- };
10682
- await args.store.batch([{ type: "put", key: dialogKey, value: record }]);
10683
- }
10684
- async function persistCliFailedChildDialog(args) {
10685
- const dialogKey = `dialog-${args.userId}-${args.dialogId}`;
10686
- const existing = await args.store.read(dialogKey);
10687
- const existingRecord = existing && typeof existing === "object" ? existing : {};
10688
- await args.store.batch([
10689
- {
10690
- type: "put",
10691
- key: dialogKey,
10692
- value: {
10693
- ...existingRecord,
10694
- id: args.dialogId,
10695
- dbKey: dialogKey,
10696
- status: "failed",
10697
- errorMessage: args.errorMessage,
10698
- updatedAt: new Date(args.now).toISOString(),
10699
- finishedAt: args.now
10700
- }
10701
- }
10702
- ]);
10703
- }
10704
-
10705
10179
  // packages/cli/client/localRuntimeTools.ts
10706
10180
  function buildOpenAiTools(args) {
10707
10181
  const toolset = buildLocalWorkspaceToolsetForEnv(args);
10708
10182
  const toolNameSet = new Set(args.toolNames ?? []);
10709
- const callAgentTools = toolNameSet.has("callAgent") ? prepareTools(["callAgent"]) : [];
10710
10183
  const uiAskChoiceTools = toolNameSet.has("ask_user") ? prepareTools(["ask_user"]) : [];
10711
10184
  const readPastedTextTools = toolNameSet.has("readPastedText") ? [
10712
10185
  {
@@ -10740,7 +10213,6 @@ function buildOpenAiTools(args) {
10740
10213
  }
10741
10214
  ] : [];
10742
10215
  return [
10743
- ...callAgentTools,
10744
10216
  ...uiAskChoiceTools,
10745
10217
  ...readPastedTextTools,
10746
10218
  ...buildLocalWorkspaceOpenAiTools({
@@ -10775,7 +10247,7 @@ function addDefaultCliCoreTools(toolNames, env, options) {
10775
10247
  }
10776
10248
  function resolveCliEffectiveEnabledPacks(args) {
10777
10249
  return resolveEffectiveEnabledPacks({
10778
- enabledPacks: args.enabledPacks,
10250
+ enabledPacks: resolveAgentRequiredPackIds(args),
10779
10251
  declaredOnly: args.declaredOnly,
10780
10252
  emptyFallbackPacks: ["code"]
10781
10253
  });
@@ -10804,6 +10276,7 @@ function resolveCliRequestedToolNames(agentConfig, env, systemBuiltinSkills, opt
10804
10276
  expandEnabledPacks(
10805
10277
  resolveCliEffectiveEnabledPacks({
10806
10278
  enabledPacks: agentConfig?.enabledPacks,
10279
+ skills: agentConfig?.skills,
10807
10280
  declaredOnly
10808
10281
  }),
10809
10282
  resolveRequestedRuntimeToolNames({ agentConfig })
@@ -10822,10 +10295,11 @@ function resolveCliRequestedToolNames(agentConfig, env, systemBuiltinSkills, opt
10822
10295
  declaredOnly ? expanded : addDefaultSystemCapabilityTools(expanded),
10823
10296
  systemBuiltinSkills
10824
10297
  );
10825
- return applyDisabledTools(
10298
+ const afterDisabled = applyDisabledTools(
10826
10299
  filtered,
10827
10300
  agentConfig?.disabledTools
10828
10301
  );
10302
+ return filterToolNamesForRunKind(afterDisabled, isSubtaskRun(env));
10829
10303
  }
10830
10304
  function resolveProviderOpenAiToolBundle(agentConfig, env, buildTools = buildOpenAiTools, additionalToolNames = [], options) {
10831
10305
  const requestedToolNames = [
@@ -10898,167 +10372,456 @@ function buildServerPlatformOpenAiTools(args) {
10898
10372
  ...webTools
10899
10373
  ];
10900
10374
  }
10901
- function createCliCallAgentToolExecutor(deps, ctx) {
10902
- const userId = resolveLocalUserId(deps.env);
10903
- const workspaceRoot = deps.cwd ?? process.cwd();
10904
- const now = deps.now ?? Date.now;
10905
- const createId = deps.createId ?? createFallbackId;
10906
- return async (call) => {
10907
- const parsed = parseNoloWorkspaceToolArguments(call.arguments);
10908
- const agentKey = asTrimmedString(parsed.agentKey);
10909
- const task = asTrimmedString(parsed.task);
10910
- if (!agentKey) {
10911
- return {
10912
- content: JSON.stringify({ error: "callAgent: agentKey is required" }),
10913
- metadata: { callAgent: true }
10914
- };
10915
- }
10916
- if (!task) {
10917
- return {
10918
- content: JSON.stringify({ error: "callAgent: task is required" }),
10919
- metadata: { callAgent: true }
10920
- };
10921
- }
10922
- const allowedChildAgentKeys = asTrimmedNonEmptyStringArray(
10923
- ctx.runtimeContext?.allowedChildAgentKeys
10924
- );
10925
- if (allowedChildAgentKeys.length > 0 && !allowedChildAgentKeys.includes(agentKey)) {
10926
- return {
10927
- content: JSON.stringify({
10928
- error: "callAgent: agentKey is not allowed by parent runtimeContext.allowedChildAgentKeys",
10929
- agentKey,
10930
- allowedChildAgentKeys
10931
- }),
10932
- metadata: { callAgent: true }
10933
- };
10934
- }
10935
- const background = parsed.background === true;
10936
- const parentDialogId = asOptionalTrimmedString(ctx.dialogId);
10937
- const parentThreadId = parentDialogId ?? asOptionalTrimmedString(ctx.runtimeContext?.parentThreadId);
10938
- const rootThreadId = asOptionalTrimmedString(ctx.runtimeContext?.rootThreadId) ?? asOptionalTrimmedString(ctx.runtimeContext?.parentThreadId) ?? parentThreadId;
10939
- const presentationIntent = background ? "background_handoff" : "inline_result";
10940
- const threadKind = background ? "background" : "inline";
10941
- const childRuntimeContext = {
10942
- ...ctx.runtimeContext ?? {},
10943
- surface: "cli",
10944
- entrypoint: "agent-tool:callAgent",
10945
- threadKind,
10946
- presentationIntent,
10947
- ...parentThreadId ? { parentThreadId } : {},
10948
- ...rootThreadId ? { rootThreadId } : {},
10949
- workspaceRoot,
10950
- workspaceKind: "current",
10951
- workspaceAccess: "inherited"
10952
- };
10953
- const childDialogId = createId();
10954
- const store = await getOrCreateSharedStore(deps);
10955
- await persistCliPendingChildDialog({
10956
- store,
10957
- userId,
10958
- dialogId: childDialogId,
10959
- agentKey,
10960
- title: task,
10961
- spaceId: ctx.spaceId,
10962
- parentDialogId,
10963
- rootDialogId: rootThreadId,
10964
- workspaceRoot,
10965
- background,
10966
- now: now()
10375
+
10376
+ // packages/cli/client/hybridRecordStore.ts
10377
+ function resolveFallbackServers(env) {
10378
+ const values = [
10379
+ env.NOLO_SERVER_URL,
10380
+ env.BASE_URL,
10381
+ ...NOLO_CLUSTER_SERVERS
10382
+ ].filter((value) => typeof value === "string" && value.trim().length > 0);
10383
+ return [...new Set(values.map(normalizeServerOrigin))];
10384
+ }
10385
+ function resolveAuthToken(env) {
10386
+ return resolvePlatformAuthToken(env);
10387
+ }
10388
+ function createCliHybridRecordStore(deps) {
10389
+ return createHybridRecordStore({
10390
+ db: deps.db,
10391
+ defaultServer: normalizeServerOrigin(
10392
+ deps.env.NOLO_SERVER || deps.env.BASE_URL || DEFAULT_NOLO_SERVER_URL
10393
+ ),
10394
+ fallbackServers: resolveFallbackServers(deps.env),
10395
+ authToken: resolveAuthToken(deps.env),
10396
+ fetchImpl: deps.fetchImpl
10397
+ });
10398
+ }
10399
+
10400
+ // packages/agent-runtime/dialogTitleLlm.ts
10401
+ async function generateLocalDialogTitle(input) {
10402
+ const { env, messages, fallbackTitle } = input;
10403
+ const timeoutMs = input.timeoutMs ?? 15e3;
10404
+ const normalized = messages.filter((m) => m.role === "user" || m.role === "assistant").map((m, index) => ({
10405
+ id: m.id || `msg-${index}`,
10406
+ role: m.role,
10407
+ content: typeof m.content === "string" ? m.content : extractText(m.content)
10408
+ })).filter((m) => Boolean(m.content.trim()));
10409
+ if (normalized.length === 0) {
10410
+ return { title: fallbackTitle, source: "fallback" };
10411
+ }
10412
+ const earlyUserTurns = normalized.filter((m) => m.role === "user").slice(0, 2);
10413
+ const recentTurns = normalized.slice(-10);
10414
+ const seen = /* @__PURE__ */ new Set();
10415
+ const visibleMessages = [...earlyUserTurns, ...recentTurns].filter((m) => {
10416
+ if (seen.has(m.id)) return false;
10417
+ seen.add(m.id);
10418
+ return true;
10419
+ }).map((m) => {
10420
+ const content = m.content.length > 500 ? `${m.content.slice(0, 500)}...` : m.content;
10421
+ return { role: m.role, content };
10422
+ });
10423
+ while (visibleMessages.length > 1 && JSON.stringify(visibleMessages).length > 4e3) {
10424
+ visibleMessages.shift();
10425
+ }
10426
+ if (visibleMessages.length === 0) {
10427
+ return { title: fallbackTitle, source: "fallback" };
10428
+ }
10429
+ if (input.resolveProviderConfig && input.buildRequest && input.parseResponse) {
10430
+ try {
10431
+ const providerConfig = await input.resolveProviderConfig({
10432
+ agentConfig: { ...BUILTIN_TITLE_LLM_CONFIG, key: BUILTIN_TITLE_LLM_CONFIG.id },
10433
+ env
10434
+ });
10435
+ if (providerConfig?.authToken) {
10436
+ const request = input.buildRequest({
10437
+ providerConfig,
10438
+ messages: [
10439
+ {
10440
+ role: "user",
10441
+ content: JSON.stringify(visibleMessages)
10442
+ }
10443
+ ],
10444
+ stream: false
10445
+ });
10446
+ const res = await input.fetchImpl(request.url, {
10447
+ ...request.init,
10448
+ signal: AbortSignal.timeout(timeoutMs)
10449
+ });
10450
+ if (res.ok) {
10451
+ const raw = await res.text().catch(() => "");
10452
+ const data = safeParseJson(raw);
10453
+ if (data) {
10454
+ const parsed = input.parseResponse({ providerConfig, data });
10455
+ const generated = normalizeDialogTitle(parsed.content);
10456
+ if (generated) {
10457
+ return { title: generated, source: "llm" };
10458
+ }
10459
+ }
10460
+ }
10461
+ }
10462
+ } catch {
10463
+ }
10464
+ }
10465
+ if (input.resolveDirectProviderConfig) {
10466
+ try {
10467
+ const envApiKey = env.OPENAI_API_KEY || env.NOLO_LOCAL_OPENAI_API_KEY || "";
10468
+ const directAgentConfig = input.agentConfig && input.agentConfig.apiSource !== "platform" ? {
10469
+ ...input.agentConfig,
10470
+ // Fill env key only when the caller's agentConfig has no key of
10471
+ // its own; never overwrite an explicit agentConfig.apiKey.
10472
+ ...envApiKey && !input.agentConfig.apiKey ? { apiKey: envApiKey } : {}
10473
+ } : {
10474
+ ...BUILTIN_TITLE_LLM_CONFIG,
10475
+ apiSource: "custom",
10476
+ useServerProxy: false,
10477
+ key: BUILTIN_TITLE_LLM_CONFIG.id,
10478
+ ...envApiKey ? { apiKey: envApiKey } : {}
10479
+ };
10480
+ const directConfig = await input.resolveDirectProviderConfig({
10481
+ agentConfig: directAgentConfig,
10482
+ env
10483
+ });
10484
+ if (directConfig?.endpoint) {
10485
+ const apiKeyHeader = directConfig.apiKeyHeader || "Authorization";
10486
+ const apiKey = directConfig.apiKey || "";
10487
+ if (!apiKey && isRemoteAuthEndpoint(directConfig.endpoint)) {
10488
+ return { title: fallbackTitle, source: "fallback" };
10489
+ }
10490
+ const authValue = apiKeyHeader.toLowerCase() === "authorization" && apiKey && !apiKey.startsWith("Bearer ") ? `Bearer ${apiKey}` : apiKey;
10491
+ const headers = {
10492
+ "content-type": "application/json",
10493
+ ...apiKey ? { [apiKeyHeader]: authValue } : {}
10494
+ };
10495
+ const res = await input.fetchImpl(directConfig.endpoint, {
10496
+ method: "POST",
10497
+ headers,
10498
+ body: JSON.stringify({
10499
+ model: directConfig.model || input.agentConfig?.model || BUILTIN_TITLE_LLM_CONFIG.model,
10500
+ messages: [
10501
+ { role: "system", content: BUILTIN_TITLE_LLM_CONFIG.prompt },
10502
+ { role: "user", content: JSON.stringify(visibleMessages) }
10503
+ ],
10504
+ stream: false
10505
+ }),
10506
+ signal: AbortSignal.timeout(timeoutMs)
10507
+ });
10508
+ if (res.ok) {
10509
+ const raw = await res.text().catch(() => "");
10510
+ const data = safeParseJson(raw);
10511
+ const rawContent = data?.choices?.[0]?.message?.content ?? "";
10512
+ const generated = normalizeDialogTitle(rawContent);
10513
+ if (generated) {
10514
+ return { title: generated, source: "llm" };
10515
+ }
10516
+ }
10517
+ }
10518
+ } catch {
10519
+ }
10520
+ }
10521
+ return { title: fallbackTitle, source: "fallback" };
10522
+ }
10523
+ function extractText(content) {
10524
+ if (typeof content === "string") return content;
10525
+ if (Array.isArray(content)) {
10526
+ const parts = content.map((part) => {
10527
+ if (!part) return "";
10528
+ if (typeof part === "string") return part;
10529
+ if (part.type === "text") return part.text ?? "";
10530
+ return "[\u56FE\u7247]";
10531
+ }).filter(Boolean);
10532
+ return parts.join(" ");
10533
+ }
10534
+ if (content && typeof content === "object") {
10535
+ const part = content;
10536
+ if (part.type === "text") return part.text ?? "";
10537
+ return "[\u56FE\u7247]";
10538
+ }
10539
+ return "";
10540
+ }
10541
+ function safeParseJson(raw) {
10542
+ try {
10543
+ return JSON.parse(raw);
10544
+ } catch {
10545
+ return null;
10546
+ }
10547
+ }
10548
+ function isRemoteAuthEndpoint(endpoint) {
10549
+ let host;
10550
+ try {
10551
+ host = new URL(endpoint).hostname.toLowerCase();
10552
+ } catch {
10553
+ return false;
10554
+ }
10555
+ if (!host) return false;
10556
+ if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host.endsWith(".local") || host.startsWith("192.168.") || host.startsWith("10.") || /^172\.(1[6-9]|2\d|3[01])\./.test(host)) {
10557
+ return false;
10558
+ }
10559
+ if (host === "api.openai.com" || host.endsWith(".openai.com") || host.endsWith(".openai.azure.com") || host === "api.deepseek.com" || host === "api.anthropic.com" || host === "generativelanguage.googleapis.com" || host === "api.together.xyz" || host === "api.groq.com" || host === "openrouter.ai" || host === "api.mistral.ai") {
10560
+ return true;
10561
+ }
10562
+ return false;
10563
+ }
10564
+
10565
+ // packages/cli/client/localRuntimeDialog.ts
10566
+ async function resolveStore(deps) {
10567
+ if (deps.store) return deps.store;
10568
+ return createCliHybridRecordStore({
10569
+ db: deps.db ?? await defaultLocalRuntimeDb(),
10570
+ env: deps.env,
10571
+ fetchImpl: deps.fetchImpl
10572
+ });
10573
+ }
10574
+ async function getOrCreateSharedStore(deps) {
10575
+ if (deps.store) return deps.store;
10576
+ const cacheKey = normalizeRuntimeCacheCwd(deps.cwd);
10577
+ let storePromise = hybridStoreCache.get(cacheKey);
10578
+ if (!storePromise) {
10579
+ storePromise = resolveStore(deps);
10580
+ hybridStoreCache.set(cacheKey, storePromise);
10581
+ }
10582
+ return storePromise;
10583
+ }
10584
+ function createLocalDialogTitleGenerator(deps, ctx) {
10585
+ if (!canUsePlatformChatProvider(deps.env) && !hasDirectOpenAiCompatibleProvider(deps.env)) {
10586
+ return null;
10587
+ }
10588
+ return async (input) => {
10589
+ const result = await generateLocalDialogTitle({
10590
+ messages: input.messages,
10591
+ env: deps.env,
10592
+ fetchImpl: async (url, init) => fetchWithTransientRetry(
10593
+ deps.fetchImpl ?? fetch,
10594
+ url,
10595
+ init,
10596
+ {
10597
+ sleep: deps.sleep,
10598
+ loopbackRequest: ctx.loopbackRequest,
10599
+ maxAttempts: 1
10600
+ }
10601
+ ),
10602
+ resolveProviderConfig: async (args) => resolvePlatformChatProviderConfig({
10603
+ agentConfig: args.agentConfig,
10604
+ env: args.env,
10605
+ apiKeyRefResolver: ctx.apiKeyRefResolver,
10606
+ credentialBroker: ctx.credentialBroker
10607
+ }),
10608
+ resolveDirectProviderConfig: async (args) => resolveOpenAiCompatibleProviderConfig({
10609
+ agentConfig: args.agentConfig,
10610
+ env: args.env,
10611
+ apiKeyRefResolver: ctx.apiKeyRefResolver,
10612
+ credentialBroker: ctx.credentialBroker
10613
+ }),
10614
+ buildRequest: (args) => buildPlatformChatCompletionRequest({
10615
+ providerConfig: args.providerConfig,
10616
+ messages: args.messages,
10617
+ stream: false
10618
+ }),
10619
+ parseResponse: (args) => parsePlatformChatCompletionResponse({
10620
+ providerConfig: args.providerConfig,
10621
+ data: args.data,
10622
+ trace: []
10623
+ }),
10624
+ fallbackTitle: input.fallbackTitle,
10625
+ timeoutMs: 4e3
10967
10626
  });
10968
- const childAdapter = ctx.createChildAdapter({
10969
- dialogId: childDialogId,
10970
- spaceId: ctx.spaceId,
10971
- runtimeContext: childRuntimeContext
10627
+ return result.source === "llm" ? result.title : null;
10628
+ };
10629
+ }
10630
+ async function writeLocalTokenRecord(args) {
10631
+ const usageRecords = args.input.usageRecords?.length ? args.input.usageRecords : args.input.result.usage ? [{
10632
+ callId: typeof args.input.result.usage?.provider_call_id === "string" && args.input.result.usage.provider_call_id.trim() ? args.input.result.usage.provider_call_id.trim() : args.createId(),
10633
+ usage: args.input.result.usage,
10634
+ model: args.input.result.model,
10635
+ ...args.input.result.provider ? { provider: args.input.result.provider } : {}
10636
+ }] : [];
10637
+ if (usageRecords.length === 0) {
10638
+ return [];
10639
+ }
10640
+ const ops = [];
10641
+ for (const item of usageRecords) {
10642
+ if (!item.usage || Object.keys(item.usage).length === 0) continue;
10643
+ const timestamp = args.now();
10644
+ const callId = item.callId || typeof item.usage.provider_call_id === "string" && item.usage.provider_call_id.trim() || args.createId();
10645
+ const prepared = prepareTokenUsageData({
10646
+ rawUsage: item.usage,
10647
+ agentConfig: {
10648
+ model: item.model || args.input.billingConfig?.model || "unknown",
10649
+ provider: item.provider || args.input.billingConfig?.provider,
10650
+ apiSource: args.input.billingConfig?.apiSource,
10651
+ apiKeyRef: args.input.billingConfig?.apiKeyRef,
10652
+ inputPrice: args.input.billingConfig?.inputPrice,
10653
+ outputPrice: args.input.billingConfig?.outputPrice,
10654
+ sharingLevel: args.input.billingConfig?.sharingLevel,
10655
+ id: args.input.billingConfig?.id,
10656
+ userId: args.input.billingConfig?.userId
10657
+ },
10658
+ userId: args.userId,
10659
+ agentId: args.input.agentKey,
10660
+ dialogId: args.dialogId,
10661
+ timestamp,
10662
+ entry_path: "cli-local"
10972
10663
  });
10973
- const childInputBase = {
10974
- adapter: childAdapter,
10975
- agentRef: agentKey,
10976
- input: buildDelegatedTaskContent(task, parsed.input),
10977
- runtimeContext: childRuntimeContext,
10978
- spaceId: ctx.spaceId,
10979
- continueDialogId: childDialogId,
10980
- parentDialogId
10664
+ const recordKey = createTokenKey.recordForStableCall(args.userId, callId);
10665
+ const tokenRecord = {
10666
+ id: args.createId(),
10667
+ type: "token",
10668
+ ...prepared.tokenData
10981
10669
  };
10982
- if (background) {
10983
- void ctx.runChildTurn(childInputBase).catch(async (error) => {
10984
- const errorMessage = toErrorMessage(error);
10985
- try {
10986
- await persistCliFailedChildDialog({
10987
- store,
10988
- userId,
10989
- dialogId: childDialogId,
10990
- errorMessage,
10991
- now: now()
10992
- });
10993
- } catch (persistError) {
10994
- deps.output?.write(
10995
- `[nolo] failed to persist background child failure: ${toErrorMessage(
10996
- persistError
10997
- )}
10670
+ await args.store.write(recordKey, tokenRecord);
10671
+ ops.push({ type: "put", key: recordKey, value: tokenRecord });
10672
+ }
10673
+ return ops;
10674
+ }
10675
+ async function writeDialog(args) {
10676
+ let existingDialog = null;
10677
+ if (args.input.continueDialogId) {
10678
+ const dialogKey = `dialog-${args.userId}-${args.input.continueDialogId}`;
10679
+ existingDialog = await args.store.read(dialogKey);
10680
+ }
10681
+ const nowMs = args.now();
10682
+ const existingTitle = typeof existingDialog?.title === "string" ? existingDialog.title.trim() : "";
10683
+ const existingTitleSource = existingDialog?.titleSource;
10684
+ const titleTimeoutMs = args.titleTimeoutMs ?? 2500;
10685
+ let needsTitleUpdate = false;
10686
+ if (existingTitleSource === "manual") {
10687
+ needsTitleUpdate = false;
10688
+ } else if (!existingTitle) {
10689
+ needsTitleUpdate = true;
10690
+ } else {
10691
+ const titleUpdatedAtMs = parseTitleUpdatedAtMs(existingDialog);
10692
+ if (titleUpdatedAtMs > 0) {
10693
+ if (nowMs - titleUpdatedAtMs >= 30 * 60 * 1e3) {
10694
+ needsTitleUpdate = true;
10695
+ }
10696
+ } else {
10697
+ needsTitleUpdate = false;
10698
+ }
10699
+ }
10700
+ let titlePromise;
10701
+ if (needsTitleUpdate && args.titleGenerator) {
10702
+ const rawLastUserText = extractLastUserText(args.input.messages);
10703
+ const fallbackTitle = buildDialogFallbackTitleFromUserInput(rawLastUserText) || "Local agent run";
10704
+ titlePromise = args.titleGenerator({ messages: args.input.messages, fallbackTitle }).catch(() => null);
10705
+ }
10706
+ let resolvedTitle = null;
10707
+ if (titlePromise) {
10708
+ let timeoutId;
10709
+ const timeoutPromise = new Promise((resolve) => {
10710
+ timeoutId = setTimeout(() => resolve(null), titleTimeoutMs);
10711
+ });
10712
+ try {
10713
+ resolvedTitle = await Promise.race([titlePromise, timeoutPromise]);
10714
+ } catch {
10715
+ resolvedTitle = null;
10716
+ } finally {
10717
+ if (timeoutId) clearTimeout(timeoutId);
10718
+ }
10719
+ }
10720
+ const plan = buildLocalDialogWritePlan({
10721
+ input: args.input,
10722
+ userId: args.userId,
10723
+ now: nowMs,
10724
+ createId: args.createId,
10725
+ existingDialog,
10726
+ cwd: args.cwd,
10727
+ ...resolvedTitle ? { titleOverride: resolvedTitle } : {}
10728
+ });
10729
+ await args.store.batch(plan.ops);
10730
+ let tokenOps = [];
10731
+ try {
10732
+ tokenOps = await writeLocalTokenRecord({
10733
+ store: args.store,
10734
+ input: args.input,
10735
+ userId: args.userId,
10736
+ dialogId: plan.dialogId,
10737
+ now: args.now,
10738
+ createId: args.createId,
10739
+ output: args.output
10740
+ });
10741
+ } catch (error) {
10742
+ args.output?.write(
10743
+ `[nolo] Token usage record write failed (non-fatal): ${toErrorMessage(error)}
10998
10744
  `
10745
+ );
10746
+ }
10747
+ const hasSubjectRefs = localTurnHasSubjectRefs(args.input);
10748
+ const isLocalUser = args.userId === "local";
10749
+ if (!isLocalUser) {
10750
+ try {
10751
+ const syncResult = await syncLocalDialogEvidenceToRemote({
10752
+ env: args.env,
10753
+ fetchImpl: args.fetchImpl,
10754
+ input: args.input,
10755
+ ops: [...plan.ops, ...tokenOps],
10756
+ output: args.output,
10757
+ userId: args.userId
10758
+ });
10759
+ if (!syncResult.attempted) {
10760
+ if (hasSubjectRefs) {
10761
+ args.output?.write(
10762
+ "[nolo] Local dialog evidence is local-only; set NOLO_SERVER and AUTH_TOKEN to make subjectRefs remotely queryable.\n"
10999
10763
  );
11000
10764
  }
11001
- });
11002
- return {
11003
- content: JSON.stringify({
11004
- success: true,
11005
- status: "pending",
11006
- agentKey,
11007
- childDialogId,
11008
- ...parentDialogId ? { parentDialogId } : {}
11009
- }),
11010
- metadata: { callAgent: true, background: true, localRuntime: true }
11011
- };
11012
- }
11013
- try {
11014
- const childResult = await ctx.runChildTurn(childInputBase);
11015
- return {
11016
- content: JSON.stringify({
11017
- success: true,
11018
- agentKey,
11019
- dialogId: childDialogId,
11020
- model: childResult.model ?? null,
11021
- provider: childResult.provider ?? null,
11022
- content: childResult.content ?? "",
11023
- usage: childResult.usage ?? null
11024
- }),
11025
- metadata: { callAgent: true, background: false, localRuntime: true }
11026
- };
10765
+ }
11027
10766
  } catch (error) {
11028
- const errorMessage = toErrorMessage(error);
11029
- try {
11030
- await persistCliFailedChildDialog({
11031
- store,
11032
- userId,
11033
- dialogId: childDialogId,
11034
- errorMessage,
11035
- now: now()
11036
- });
11037
- } catch (persistError) {
11038
- deps.output?.write(
11039
- `[nolo] failed to persist foreground child failure: ${toErrorMessage(
11040
- persistError
11041
- )}
11042
- `
11043
- );
10767
+ if (hasSubjectRefs) {
10768
+ throw error;
11044
10769
  }
11045
- return {
11046
- content: JSON.stringify({
11047
- success: false,
11048
- agentKey,
11049
- dialogId: childDialogId,
11050
- error: errorMessage
11051
- }),
11052
- metadata: {
11053
- callAgent: true,
11054
- background: false,
11055
- localRuntime: true,
11056
- error: true
11057
- }
11058
- };
10770
+ args.output?.write(
10771
+ `[nolo] Remote dialog evidence sync failed; local dialog only: ${toErrorMessage(
10772
+ error
10773
+ )}
10774
+ `
10775
+ );
11059
10776
  }
10777
+ }
10778
+ return { dialogId: plan.dialogId, title: plan.title };
10779
+ }
10780
+ function resolveCliDialogRecordKey(userId, dialogId) {
10781
+ if (dialogId.startsWith("dialog-") && !dialogId.includes("-msg-")) {
10782
+ return dialogId;
10783
+ }
10784
+ return `dialog-${userId}-${dialogId}`;
10785
+ }
10786
+ async function loadCliDialogSummary(args) {
10787
+ const dialogKey = resolveCliDialogRecordKey(args.userId, args.dialogId);
10788
+ const record = await args.store.read(dialogKey);
10789
+ if (!record || typeof record !== "object") return null;
10790
+ const summary = typeof record.summary === "string" ? record.summary.trim() : "";
10791
+ if (!summary) return null;
10792
+ const summarizedBeforeId = record.summarizedBeforeId;
10793
+ return {
10794
+ summary,
10795
+ ...typeof summarizedBeforeId === "string" && summarizedBeforeId ? { summarizedBeforeId } : {}
11060
10796
  };
11061
10797
  }
10798
+ async function saveCliDialogSummary(args) {
10799
+ const dialogKey = resolveCliDialogRecordKey(args.userId, args.dialogId);
10800
+ const existing = await args.store.read(dialogKey) ?? {};
10801
+ const bareId = typeof existing.id === "string" && existing.id ? existing.id : args.dialogId.startsWith("dialog-") ? args.dialogId.slice(args.dialogId.lastIndexOf("-") + 1) : args.dialogId;
10802
+ const compressionCount = typeof existing.compressionCount === "number" ? existing.compressionCount + 1 : 1;
10803
+ await args.store.write(dialogKey, {
10804
+ ...existing,
10805
+ id: bareId,
10806
+ dbKey: dialogKey,
10807
+ type: "dialog",
10808
+ userId: args.userId,
10809
+ summary: args.summary,
10810
+ ...args.summarizedBeforeId !== void 0 ? { summarizedBeforeId: args.summarizedBeforeId } : {},
10811
+ compressionCount,
10812
+ summaryPending: false,
10813
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
10814
+ });
10815
+ }
10816
+ function parseTitleUpdatedAtMs(existingDialog) {
10817
+ const raw = existingDialog?.titleUpdatedAt;
10818
+ if (typeof raw === "number" && !Number.isNaN(raw)) return raw;
10819
+ if (typeof raw === "string" && raw.trim()) {
10820
+ const parsed = Date.parse(raw);
10821
+ if (!Number.isNaN(parsed)) return parsed;
10822
+ }
10823
+ return 0;
10824
+ }
11062
10825
 
11063
10826
  // packages/cli/client/localRuntimeAdapter.ts
11064
10827
  var currentMetaFile = fileURLToPath(import.meta.url);
@@ -11260,7 +11023,20 @@ function createCliLocalRuntimeAdapter(deps) {
11260
11023
  const credentialBroker = createFileCredentialBroker();
11261
11024
  const serverUrl = asOptionalTrimmedString(deps.env.NOLO_SERVER) ?? "https://us.nolo.chat";
11262
11025
  const authToken = asOptionalTrimmedString(deps.env.AUTH_TOKEN);
11263
- const syncFetcher = authToken ? (ref) => fetchServerSyncedCredential({ currentServer: serverUrl, authToken }, ref) : void 0;
11026
+ const syncFetcher = authToken ? async (ref) => {
11027
+ try {
11028
+ return await fetchServerSyncedCredential(
11029
+ { currentServer: serverUrl, authToken },
11030
+ ref
11031
+ );
11032
+ } catch (error) {
11033
+ logLocalRuntimeDiagnostic("credential.sync.unavailable", {
11034
+ ref,
11035
+ error: toErrorMessage(error)
11036
+ });
11037
+ return null;
11038
+ }
11039
+ } : void 0;
11264
11040
  if (isAntigravityOAuthAgent(agentConfig)) {
11265
11041
  const accessToken = await apiKeyRefResolver("antigravity");
11266
11042
  if (!accessToken) {
@@ -11474,6 +11250,14 @@ function createCliLocalRuntimeAdapter(deps) {
11474
11250
  return {
11475
11251
  content,
11476
11252
  ...tool_calls ? { tool_calls } : {},
11253
+ // fetchCodexResponsesCompletion 已把 codex responses 流聚合完毕并归一化成
11254
+ // OpenAI chat.completions 形状:choices[0].finish_reason("stop"/"tool_calls")
11255
+ // + usage(prompt/completion/total_tokens)。必须透传,否则 localLoop 把正常走完
11256
+ // 的空轮误判成 stream_truncated、TUI context chip 也拿不到 token 数更新。
11257
+ finish_reason: typeof choice?.finish_reason === "string" ? choice.finish_reason : void 0,
11258
+ stream_complete: true,
11259
+ // body 类型是 Record<string, unknown>,透传 usage 需 cast 到 AgentRuntimeResult.usage。
11260
+ usage: result.body?.usage,
11477
11261
  trace: messages
11478
11262
  };
11479
11263
  }
@@ -11923,9 +11707,7 @@ export {
11923
11707
  t,
11924
11708
  toolLabel,
11925
11709
  agentRunCardLabels,
11926
- QUOTA_ERROR_PATTERNS,
11927
- isQuotaExhaustedError,
11928
11710
  clearCliLocalRuntimePreparedAgentCache,
11929
- createCliCallAgentToolExecutor,
11711
+ isSubtaskRun,
11930
11712
  createCliLocalRuntimeAdapter
11931
11713
  };