nolo-cli 0.212.0-alpha.1 → 0.213.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{_executeModel-KE6MBNUJ.js → _executeModel-CUJLCFWR.js} +35 -35
- package/{addContentAction-N2YC5IL3.js → addContentAction-WERAONNY.js} +5 -5
- package/{addDialogAgentAction-3NKVQCEC.js → addDialogAgentAction-7VI7YRML.js} +4 -4
- package/{agentDeleteCommand-NWK7VU4N.js → agentDeleteCommand-XJORXPGU.js} +42 -42
- package/{agentEmailCommands-UZ4DHEX2.js → agentEmailCommands-XTYYFR6Z.js} +43 -43
- package/{agentListCommands-HE7L2A6L.js → agentListCommands-OBLRBLHS.js} +60 -51
- package/{agentMachineCommands-6TE4MBMP.js → agentMachineCommands-5FMT3OT5.js} +13 -12
- package/{agentRecordCommands-L3QQ7HZ4.js → agentRecordCommands-ZQ7SVYGG.js} +42 -42
- package/{agentRunCommand-2IFGQHCO.js → agentRunCommand-WS7IGO2W.js} +43 -43
- package/{agentRunControl-OI3LOENH.js → agentRunControl-TAMHJQSR.js} +3 -3
- package/{agentRuntimeLocal-HL526DNQ.js → agentRuntimeLocal-SOO2OPJG.js} +10 -10
- package/{agentSlice-TMYP2UEA.js → agentSlice-CHR6KOZN.js} +5 -5
- package/{appDeleteCommands-ZERW4AXY.js → appDeleteCommands-GUP6P5YE.js} +15 -14
- package/{appDeployCommands-DUWSMYHL.js → appDeployCommands-MH2FX4O5.js} +15 -14
- package/{appDeployStatusCommands-N2KIE4BF.js → appDeployStatusCommands-SUHN3HPJ.js} +15 -14
- package/{appGetCommands-YVR4NPVY.js → appGetCommands-YWDEX6Z4.js} +15 -14
- package/{appListCommands-JS6HOHZS.js → appListCommands-ZQVMLPAY.js} +15 -14
- package/{authCommand-FE2C3ZUM.js → authCommand-PWX2ZNUP.js} +2 -2
- package/{builtinSkillRegistry-3YOIGEF6.js → builtinSkillRegistry-2QETTQPM.js} +2 -2
- package/{chromeOpsCommands-HEN5AX2J.js → chromeOpsCommands-DIVM2K3T.js} +1 -1
- package/{chunk-YUXQAVRD.js → chunk-3UKL3HPD.js} +251 -14
- package/{chunk-PDGKOTO7.js → chunk-4T2WNOY7.js} +4 -4
- package/{chunk-NOMIGOST.js → chunk-5MQRBSMW.js} +35 -41
- package/{chunk-5RYBGBQH.js → chunk-6DWMYIUY.js} +3 -3
- package/{chunk-KSTEXKL6.js → chunk-75XIDFBW.js} +4 -3
- package/{chunk-CZM5YTZ7.js → chunk-7BT37FK3.js} +193 -305
- package/{chunk-GPO7FCEZ.js → chunk-7QTZCMKL.js} +159 -106
- package/{chunk-NJR3WKVP.js → chunk-7Y4YTDQF.js} +6 -6
- package/{chunk-CKAHAVMK.js → chunk-A7TFUNZO.js} +35 -25
- package/{chunk-PJNFNEJE.js → chunk-ALQ3657A.js} +28 -2
- package/{chunk-YJMRHHGY.js → chunk-BBJ22CLB.js} +5 -5
- package/{chunk-AVTVGMDY.js → chunk-COFEN36Z.js} +1 -1
- package/{chunk-DM6UMOEL.js → chunk-CRHOO2ZR.js} +1 -1
- package/{chunk-EYUBHHFB.js → chunk-EHGEOAHI.js} +2 -2
- package/{chunk-Y2WUYX4I.js → chunk-EHSZD5OI.js} +1 -1
- package/{chunk-QT6PKHYJ.js → chunk-FUGMREBO.js} +2 -2
- package/{chunk-BFM34N54.js → chunk-FW6YHHLI.js} +4 -4
- package/{chunk-3FOQHGHN.js → chunk-G2BQWAVT.js} +2 -2
- package/{chunk-VPAZOH2D.js → chunk-GPVRUGGY.js} +1 -1
- package/{chunk-JNKSDZFS.js → chunk-H4UOTUOX.js} +162 -48
- package/{chunk-UTV2AYEG.js → chunk-H5HF7TJA.js} +1 -1
- package/{chunk-IJXYFTV7.js → chunk-H7PPIYWP.js} +1 -1
- package/{chunk-NRFKLKRU.js → chunk-HSVBJRF4.js} +1 -1
- package/{chunk-GNDJKC4B.js → chunk-HUBHAQK2.js} +8 -8
- package/{chunk-LKDF3ATR.js → chunk-INUFILG6.js} +1 -1
- package/{chunk-OHNELDTO.js → chunk-IXNGOHV5.js} +2 -2
- package/{chunk-WXYLV624.js → chunk-J2NHJ7WX.js} +4 -4
- package/{chunk-YPD3VJZW.js → chunk-KFLT5KAD.js} +4 -4
- package/{chunk-OOF4UPC5.js → chunk-LLRPJECG.js} +4 -4
- package/{chunk-B7NJ3T4A.js → chunk-MDB67IWP.js} +4 -4
- package/{chunk-IF45XG7K.js → chunk-MOIJOHA5.js} +9 -4
- package/{chunk-IIQ6JGRI.js → chunk-NJLL224W.js} +1 -1
- package/{chunk-YOIW77S2.js → chunk-NOKUNJON.js} +2 -2
- package/{chunk-HIRC32DV.js → chunk-NSAPDIN2.js} +8 -4
- package/{chunk-JIT6FSXJ.js → chunk-O2TZF4AI.js} +1 -1
- package/{chunk-4KH4J3G5.js → chunk-OQPKUBPB.js} +1 -1
- package/{chunk-OXME3PEE.js → chunk-PCLE46CE.js} +1 -1
- package/{chunk-CJRONOYL.js → chunk-QG4AOSON.js} +8 -45
- package/{chunk-6OQUPIQF.js → chunk-QHPRUL4O.js} +3 -3
- package/{chunk-MMNYUVLW.js → chunk-R5O4QAWG.js} +1 -1
- package/{chunk-IAPCBNEE.js → chunk-RLBNLZVC.js} +1 -1
- package/{chunk-FHU44LN3.js → chunk-RSHTSUEG.js} +246 -77
- package/{chunk-25JZEIXN.js → chunk-RZOV7OMV.js} +11 -11
- package/{chunk-D2MDMY2M.js → chunk-SVYO6AO7.js} +7 -1
- package/{chunk-INSBKSBB.js → chunk-TAKB25RM.js} +1 -1
- package/{chunk-RU4SD66C.js → chunk-TX5EYMGT.js} +5 -5
- package/{chunk-D5RCRX4A.js → chunk-UYD5HQ6T.js} +746 -177
- package/{chunk-JTDORD5P.js → chunk-V5Y3R6BT.js} +110 -2
- package/{chunk-3RQVYR4B.js → chunk-VNYYOX3V.js} +59 -20
- package/{chunk-3AKFVZ2I.js → chunk-VO4WSAVP.js} +3 -3
- package/{chunk-6NSSLV67.js → chunk-WMTBPBMP.js} +6 -6
- package/{chunk-EZFQ6XRV.js → chunk-WRYQ35LQ.js} +4 -4
- package/{chunk-SOHTHFV2.js → chunk-WYDI6TGM.js} +14 -14
- package/{chunk-M6RL5JCD.js → chunk-X7SDOJUM.js} +3 -3
- package/{chunk-CQ46IRNN.js → chunk-XHQC4PXX.js} +48 -34
- package/{chunk-2WZXXAQD.js → chunk-YB3YZK56.js} +67 -1
- package/{chunk-22CIEBYO.js → chunk-YJAFKXMU.js} +11 -11
- package/{chunk-GSQNH63I.js → chunk-YTF4WH7J.js} +3 -19
- package/{chunk-5AQR3DGV.js → chunk-ZNWI6OVT.js} +2 -2
- package/{chunk-VZKUKCA6.js → chunk-ZXOUUDCG.js} +49 -40
- package/{commandRegistry-VVMTPFAX.js → commandRegistry-W63CYRZJ.js} +64 -64
- package/{contentThunks-N52O67MI.js → contentThunks-U7PL5MQD.js} +12 -12
- package/{cooldownCommands-YXLWOXWR.js → cooldownCommands-TIGUHXTD.js} +3 -3
- package/{createAgentAutomationAction-ZC57YRSV.js → createAgentAutomationAction-OLBQDD6R.js} +12 -12
- package/{createDialogAction-VQW5WDYX.js → createDialogAction-SVH6B3SB.js} +14 -14
- package/{createPageAction-M5VDA7SC.js → createPageAction-F4DIWZ2Z.js} +14 -14
- package/{dbSlice-HP7G4LX3.js → dbSlice-BVH2YZPQ.js} +4 -4
- package/{deleteFile-7VQGLK2V.js → deleteFile-5YOEKV4U.js} +2 -2
- package/{dialogCommands-JHMR2N2Y.js → dialogCommands-KHIEPY3M.js} +18 -18
- package/{dialogSlice-GRSVGDTF.js → dialogSlice-ZCTDV2PZ.js} +11 -11
- package/{docCreateCommands-F2K3UPSQ.js → docCreateCommands-DPMZI7G5.js} +14 -13
- package/{docDeleteCommands-XGXB5RFT.js → docDeleteCommands-IRQQLUBT.js} +16 -16
- package/{docReadCommands-7HWZZV6J.js → docReadCommands-LK37XH6L.js} +14 -13
- package/{docStore-KNZK6Y2G.js → docStore-V2KECILA.js} +5 -5
- package/{docUpdateCommands-OZZ7NQII.js → docUpdateCommands-O6T3HJHH.js} +14 -13
- package/{fetchMessages-M3QU7ZCQ.js → fetchMessages-NR4KNQLO.js} +2 -2
- package/{handleSendMessageAction-SHIH74GJ.js → handleSendMessageAction-2PE25WM3.js} +25 -25
- package/{hostCredentialCreate-X64WK4JD.js → hostCredentialCreate-S233UMAP.js} +42 -42
- package/index.js +7 -7
- package/{localDialogRead-XRLAH4CZ.js → localDialogRead-7NNDVVF7.js} +1 -1
- package/{localRuntimeAdapter-A7K3ABA6.js → localRuntimeAdapter-KY6WXNBR.js} +41 -41
- package/{machineCommands-DE3MR7CJ.js → machineCommands-Q6HA3IXF.js} +42 -42
- package/{machineWsRunDispatch-R26P5V36.js → machineWsRunDispatch-WWJQ6WR3.js} +42 -42
- package/{memberThunks-7WJAY5V6.js → memberThunks-7EDJADWU.js} +5 -5
- package/package.json +1 -1
- package/{projectArchive-GGL5HLMD.js → projectArchive-DRTDIMEV.js} +14 -14
- package/{read-4VZQODSN.js → read-4V2RMG7N.js} +2 -2
- package/{readDocTool-AVD32RUJ.js → readDocTool-BH6ATGQO.js} +1 -1
- package/{readlineWorkspace-XKYKNL2I.js → readlineWorkspace-2W4WRCOU.js} +322 -159
- package/{removeDialogAgentAction-FKL4BYMR.js → removeDialogAgentAction-LYAZGNKW.js} +5 -5
- package/{runAgentClientLoop-V7E2WBVM.js → runAgentClientLoop-J2VQBS2Z.js} +33 -33
- package/{secretCommands-4QS3HCA2.js → secretCommands-LXDWOLZ6.js} +1 -1
- package/{setDialogExtraReferencesAction-TLIOLWWI.js → setDialogExtraReferencesAction-OCRPGPYH.js} +5 -5
- package/{setPrimaryDialogAgentAction-2OLWRFYR.js → setPrimaryDialogAgentAction-HFJDQIBU.js} +5 -5
- package/{settingThunks-UGBPCNYF.js → settingThunks-RAMHMTGM.js} +7 -7
- package/{spaceCommands-4KSLKVNF.js → spaceCommands-KVJZVKVO.js} +14 -14
- package/{streamAgentChatTurn-7FR7X2NU.js → streamAgentChatTurn-GHBMJJ6S.js} +37 -37
- package/{switchDialogAgentAction-UZSAG2N5.js → switchDialogAgentAction-EBRMW3RA.js} +4 -4
- package/{tools-ZLKCC25W.js → tools-EWKCPKMS.js} +28 -28
- package/{tuiSummaryLlmCaller-WC54MVGP.js → tuiSummaryLlmCaller-ALQYUUWB.js} +41 -12
- package/{updateCommands-4744PL3P.js → updateCommands-ZQYU6SCI.js} +3 -3
- package/{updateDialogTitleAction-U53ZT7PJ.js → updateDialogTitleAction-5GGMBTDF.js} +12 -12
- package/{windowsSelfUpdate-XSQVF2GK.js → windowsSelfUpdate-257DV2T6.js} +2 -2
- package/{workloadLifecycle-4BEQHMSD.js → workloadLifecycle-4C42SVBD.js} +1 -0
|
@@ -4,16 +4,14 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
clearCredentialAvailability,
|
|
6
6
|
markCredentialUnavailable,
|
|
7
|
-
readCredentialEntry
|
|
8
|
-
|
|
9
|
-
recordCredentialProbe
|
|
10
|
-
} from "./chunk-GSQNH63I.js";
|
|
7
|
+
readCredentialEntry
|
|
8
|
+
} from "./chunk-YTF4WH7J.js";
|
|
11
9
|
import {
|
|
12
10
|
CREDENTIAL_STORE_SESSION_FALLBACK_WARNING,
|
|
13
11
|
OAUTH_PROVIDER_REFS,
|
|
14
12
|
buildLocalAgentLookupKeys,
|
|
15
13
|
getSharedSessionCredentialBroker
|
|
16
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-MOIJOHA5.js";
|
|
17
15
|
import {
|
|
18
16
|
customNativeAuthHeaders,
|
|
19
17
|
detectDeclaredCustomNativeWire,
|
|
@@ -73,7 +71,7 @@ import {
|
|
|
73
71
|
import {
|
|
74
72
|
inlineImageUrlsForCustomProvider,
|
|
75
73
|
prepareTools
|
|
76
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-G2BQWAVT.js";
|
|
77
75
|
import {
|
|
78
76
|
getServerProviderSecret
|
|
79
77
|
} from "./chunk-HS7MLR74.js";
|
|
@@ -95,7 +93,7 @@ import {
|
|
|
95
93
|
resolveCliLocalRuntimeKeyCapability,
|
|
96
94
|
resolveCliLocalSpawnDispatch,
|
|
97
95
|
resolveStartAgentRunCwd
|
|
98
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-XHQC4PXX.js";
|
|
99
97
|
import {
|
|
100
98
|
fetchWithTransientRetry,
|
|
101
99
|
isTransientFetchError
|
|
@@ -103,22 +101,22 @@ import {
|
|
|
103
101
|
import {
|
|
104
102
|
deriveCredentialGroup,
|
|
105
103
|
deriveCustomProviderCredentialGroup
|
|
106
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-QG4AOSON.js";
|
|
107
105
|
import {
|
|
108
106
|
inferCaptureIntent,
|
|
109
107
|
resolveUserSkillRuntime
|
|
110
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-ZNWI6OVT.js";
|
|
111
109
|
import {
|
|
112
110
|
resolveAgentRequiredPackIds,
|
|
113
111
|
resolveUserEnabledSkills
|
|
114
|
-
} from "./chunk-
|
|
112
|
+
} from "./chunk-R5O4QAWG.js";
|
|
115
113
|
import {
|
|
116
114
|
applyBuiltinAgentRuntimeOverride,
|
|
117
115
|
prepareTokenUsageData,
|
|
118
116
|
resolveBuiltinPlatformAgentConfig,
|
|
119
117
|
runKeyed,
|
|
120
118
|
validateAskChoiceInput
|
|
121
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-ZXOUUDCG.js";
|
|
122
120
|
import {
|
|
123
121
|
applyTokenUsageToDayStats,
|
|
124
122
|
require_format
|
|
@@ -129,13 +127,13 @@ import {
|
|
|
129
127
|
} from "./chunk-523DITKR.js";
|
|
130
128
|
import {
|
|
131
129
|
fetchServerSyncedCredential
|
|
132
|
-
} from "./chunk-
|
|
130
|
+
} from "./chunk-KFLT5KAD.js";
|
|
133
131
|
import {
|
|
134
132
|
getDefaultCliLocalRuntimeDb
|
|
135
133
|
} from "./chunk-AZMYUSVF.js";
|
|
136
134
|
import {
|
|
137
135
|
isTombstoneRecord
|
|
138
|
-
} from "./chunk-
|
|
136
|
+
} from "./chunk-SVYO6AO7.js";
|
|
139
137
|
import {
|
|
140
138
|
FORCED_TOOLS,
|
|
141
139
|
addDefaultLightWebToolsForConfiguredAgents,
|
|
@@ -145,7 +143,7 @@ import {
|
|
|
145
143
|
applySystemBuiltinSkillFilter,
|
|
146
144
|
expandEnabledPacks,
|
|
147
145
|
resolveEffectiveEnabledPacks
|
|
148
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-EHGEOAHI.js";
|
|
149
147
|
import {
|
|
150
148
|
DEFAULT_HYBRID_READ_TIMEOUT_MS,
|
|
151
149
|
Duration_exports,
|
|
@@ -191,7 +189,7 @@ import {
|
|
|
191
189
|
runExecShellGates,
|
|
192
190
|
validateConfiguredRootExecutionLease,
|
|
193
191
|
verifyOwnerRouteAck
|
|
194
|
-
} from "./chunk-
|
|
192
|
+
} from "./chunk-RSHTSUEG.js";
|
|
195
193
|
import {
|
|
196
194
|
PlatformStreamInterruptedError,
|
|
197
195
|
buildPlatformChatCompletionRequest,
|
|
@@ -202,7 +200,7 @@ import {
|
|
|
202
200
|
readPlatformChatSseCompletion,
|
|
203
201
|
resolvePlatformChatProviderConfig,
|
|
204
202
|
shouldUsePlatformChatProvider
|
|
205
|
-
} from "./chunk-
|
|
203
|
+
} from "./chunk-OQPKUBPB.js";
|
|
206
204
|
import {
|
|
207
205
|
accumulateGeminiChunks,
|
|
208
206
|
buildGeminiGenerateContentRequest,
|
|
@@ -228,7 +226,7 @@ import {
|
|
|
228
226
|
findAgentStatePairingIssues,
|
|
229
227
|
stablePromptCacheKey,
|
|
230
228
|
toResponsesTools
|
|
231
|
-
} from "./chunk-
|
|
229
|
+
} from "./chunk-H5HF7TJA.js";
|
|
232
230
|
import {
|
|
233
231
|
EMPTY_TOOL_RESULT_TEXT,
|
|
234
232
|
createToolImageBudget,
|
|
@@ -241,21 +239,22 @@ import {
|
|
|
241
239
|
import {
|
|
242
240
|
buildNoloWorkspaceOpenAiTools,
|
|
243
241
|
filterClientNoloWorkspaceToolNames,
|
|
244
|
-
parseNoloWorkspaceToolArguments
|
|
245
|
-
|
|
242
|
+
parseNoloWorkspaceToolArguments,
|
|
243
|
+
resolveDispatchedSubtaskBudget
|
|
244
|
+
} from "./chunk-RZOV7OMV.js";
|
|
246
245
|
import {
|
|
246
|
+
extractQuotaSnapshot,
|
|
247
247
|
isCapacitySaturatedRateLimit,
|
|
248
248
|
mergeAvailabilityDeadline,
|
|
249
249
|
resolveAvailabilityAction,
|
|
250
|
-
resolveCooldownGate,
|
|
251
250
|
resolveCredentialKeyWithFallback
|
|
252
|
-
} from "./chunk-
|
|
251
|
+
} from "./chunk-3UKL3HPD.js";
|
|
253
252
|
import {
|
|
254
253
|
resolveRequestToolSurface
|
|
255
254
|
} from "./chunk-KC4XDTT3.js";
|
|
256
255
|
import {
|
|
257
256
|
resolveHistoricalToolContentCap
|
|
258
|
-
} from "./chunk-
|
|
257
|
+
} from "./chunk-YB3YZK56.js";
|
|
259
258
|
import {
|
|
260
259
|
resolveToolImagePolicy
|
|
261
260
|
} from "./chunk-YWSEPJ7C.js";
|
|
@@ -264,8 +263,16 @@ import {
|
|
|
264
263
|
normalizeDialogTitle
|
|
265
264
|
} from "./chunk-2MBTWINN.js";
|
|
266
265
|
import {
|
|
267
|
-
|
|
268
|
-
|
|
266
|
+
CODEX_OAUTH_CATALOG_RETRY_FLOOR_MS,
|
|
267
|
+
CODEX_OAUTH_CATALOG_TTL_MS,
|
|
268
|
+
codexOAuthCatalogAccountKey,
|
|
269
|
+
codexOAuthCatalogSnapshot,
|
|
270
|
+
commitCodexOAuthCatalogWindows,
|
|
271
|
+
isCodexOAuthAgent,
|
|
272
|
+
markCodexOAuthCatalogFailure,
|
|
273
|
+
normalizeUsage,
|
|
274
|
+
resolveCodexOAuthEffectiveModel
|
|
275
|
+
} from "./chunk-V5Y3R6BT.js";
|
|
269
276
|
import {
|
|
270
277
|
createProviderCallTimingTracker,
|
|
271
278
|
finalizeProviderCallTiming,
|
|
@@ -326,7 +333,7 @@ import {
|
|
|
326
333
|
terminateRunProcess,
|
|
327
334
|
transitionRunToTerminal,
|
|
328
335
|
withQueueLock
|
|
329
|
-
} from "./chunk-
|
|
336
|
+
} from "./chunk-NSAPDIN2.js";
|
|
330
337
|
import {
|
|
331
338
|
remoteDialogSyncTimeout,
|
|
332
339
|
resolveRuntimeAuthToken,
|
|
@@ -334,6 +341,7 @@ import {
|
|
|
334
341
|
} from "./chunk-HRMJUN5J.js";
|
|
335
342
|
import {
|
|
336
343
|
TASK_PREVIEW_MAX,
|
|
344
|
+
formatControlRunMessageCard,
|
|
337
345
|
formatListRunsCard,
|
|
338
346
|
formatNotFoundRunCard,
|
|
339
347
|
formatStartRunCard,
|
|
@@ -344,7 +352,7 @@ import {
|
|
|
344
352
|
normalizeRunTitle,
|
|
345
353
|
resolveRunLabel,
|
|
346
354
|
shortRunId
|
|
347
|
-
} from "./chunk-
|
|
355
|
+
} from "./chunk-ALQ3657A.js";
|
|
348
356
|
import {
|
|
349
357
|
estimateTokenCount
|
|
350
358
|
} from "./chunk-PSCNXBYA.js";
|
|
@@ -394,7 +402,7 @@ import {
|
|
|
394
402
|
import {
|
|
395
403
|
agentRunCardLabels,
|
|
396
404
|
t
|
|
397
|
-
} from "./chunk-
|
|
405
|
+
} from "./chunk-VNYYOX3V.js";
|
|
398
406
|
import {
|
|
399
407
|
createOAuthTokenStore,
|
|
400
408
|
isTokenExpired,
|
|
@@ -1060,7 +1068,7 @@ async function fetchAnthropicMessagesCompletion(args) {
|
|
|
1060
1068
|
const errorBody = await response.json().catch(async () => ({
|
|
1061
1069
|
error: { message: await response.text().catch(() => response.statusText) }
|
|
1062
1070
|
}));
|
|
1063
|
-
if (adoptRequiredClaudeCodeVersion(errorBody)) {
|
|
1071
|
+
if (!args.noRetries && adoptRequiredClaudeCodeVersion(errorBody)) {
|
|
1064
1072
|
response = await (args.fetchImpl ?? fetch)(ANTHROPIC_MESSAGES_URL, {
|
|
1065
1073
|
method: "POST",
|
|
1066
1074
|
headers: buildHeaders(),
|
|
@@ -1527,6 +1535,8 @@ var resolveAnthropicOAuthTransport = async (ctx) => {
|
|
|
1527
1535
|
const result = await fetchAnthropicMessagesCompletion({
|
|
1528
1536
|
agentConfig,
|
|
1529
1537
|
accessToken,
|
|
1538
|
+
signal: options?.signal,
|
|
1539
|
+
...options?.noRetries ? { noRetries: true } : {},
|
|
1530
1540
|
openAiBody: {
|
|
1531
1541
|
model: agentConfig.model || "claude-sonnet-5",
|
|
1532
1542
|
messages,
|
|
@@ -1535,7 +1545,8 @@ var resolveAnthropicOAuthTransport = async (ctx) => {
|
|
|
1535
1545
|
},
|
|
1536
1546
|
fetchImpl: (url, init) => fetchWithTransientRetry(fetchImpl, url, init, {
|
|
1537
1547
|
sleep: deps.sleep,
|
|
1538
|
-
loopbackRequest
|
|
1548
|
+
loopbackRequest,
|
|
1549
|
+
...options?.noRetries ? { maxAttempts: 1, coreDrainingMaxAttempts: 1 } : {}
|
|
1539
1550
|
})
|
|
1540
1551
|
});
|
|
1541
1552
|
await recordLocalAvailability(result.status, result.body);
|
|
@@ -1926,7 +1937,7 @@ var resolveAntigravityTransport = async (ctx) => {
|
|
|
1926
1937
|
agentConfig,
|
|
1927
1938
|
resolveCredential: resolveLocalCredential,
|
|
1928
1939
|
// 非 OAuth(api-key ref)不重试:metered key 没有 refresh 语义。
|
|
1929
|
-
supportsAuthRetry: !isApiKeyRef,
|
|
1940
|
+
supportsAuthRetry: !isApiKeyRef && !options?.noRetries,
|
|
1930
1941
|
openAiBody,
|
|
1931
1942
|
...options?.signal ? { signal: options.signal } : {},
|
|
1932
1943
|
// whole-invocation timeout 透传:seam 最外层 timeoutOption 统一 interrupt
|
|
@@ -1936,7 +1947,8 @@ var resolveAntigravityTransport = async (ctx) => {
|
|
|
1936
1947
|
onReasoningDelta: options?.onReasoningDelta,
|
|
1937
1948
|
fetchImpl: (url, init) => fetchWithTransientRetry(fetchImpl, url, init, {
|
|
1938
1949
|
sleep: deps.sleep,
|
|
1939
|
-
loopbackRequest
|
|
1950
|
+
loopbackRequest,
|
|
1951
|
+
...options?.noRetries ? { maxAttempts: 1, coreDrainingMaxAttempts: 1 } : {}
|
|
1940
1952
|
})
|
|
1941
1953
|
});
|
|
1942
1954
|
} catch (error) {
|
|
@@ -2257,6 +2269,7 @@ function collectCliProviderImageInputs(messages) {
|
|
|
2257
2269
|
var resolveCliProviderTransport = async (ctx) => {
|
|
2258
2270
|
const { agentConfig, deps, workspaceRoot } = ctx;
|
|
2259
2271
|
if (isCliProviderAgent(agentConfig)) {
|
|
2272
|
+
if (ctx.textOnly) throw new Error("local CLI subprocess does not support isolated text-only mode");
|
|
2260
2273
|
const provider = resolveCliProviderName(agentConfig);
|
|
2261
2274
|
logLocalRuntimeDiagnostic("provider.selected", {
|
|
2262
2275
|
agentKey: agentConfig.key,
|
|
@@ -2319,41 +2332,6 @@ var resolveCliProviderTransport = async (ctx) => {
|
|
|
2319
2332
|
// packages/agent-runtime/codexResponsesProvider.ts
|
|
2320
2333
|
import { createHash } from "node:crypto";
|
|
2321
2334
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2322
|
-
|
|
2323
|
-
// packages/agent-runtime/codexOAuthModelAliases.ts
|
|
2324
|
-
var CODEX_OAUTH_MODEL_ALIASES = {
|
|
2325
|
-
// sol 家族最新:gpt-6.1-sol
|
|
2326
|
-
"gpt-6-sol": {
|
|
2327
|
-
aliasOf: "gpt-6.1-sol",
|
|
2328
|
-
since: "2026-11-01",
|
|
2329
|
-
reason: "\u540C\u5BB6\u65CF\u6362\u4EE3\uFF0Cowner \u51B3\u5B9A\u900F\u660E\u91CD\u5B9A\u5411\uFF08sol \u5BB6\u65CF\u6700\u65B0\u4E3A gpt-6.1-sol\uFF09\u3002"
|
|
2330
|
-
},
|
|
2331
|
-
"gpt-5.6-sol": {
|
|
2332
|
-
aliasOf: "gpt-6.1-sol",
|
|
2333
|
-
since: "2026-11-01",
|
|
2334
|
-
reason: "\u540C\u5BB6\u65CF\u6362\u4EE3\uFF0Cowner \u51B3\u5B9A\u900F\u660E\u91CD\u5B9A\u5411\uFF08sol \u5BB6\u65CF\u6700\u65B0\u4E3A gpt-6.1-sol\uFF09\u3002"
|
|
2335
|
-
},
|
|
2336
|
-
// terra 家族最新:gpt-6.1-terra
|
|
2337
|
-
"gpt-5.6-terra": {
|
|
2338
|
-
aliasOf: "gpt-6.1-terra",
|
|
2339
|
-
since: "2026-11-01",
|
|
2340
|
-
reason: "\u540C\u5BB6\u65CF\u6362\u4EE3\uFF0Cowner \u51B3\u5B9A\u900F\u660E\u91CD\u5B9A\u5411\uFF08terra \u5BB6\u65CF\u6700\u65B0\u4E3A gpt-6.1-terra\uFF09\u3002"
|
|
2341
|
-
},
|
|
2342
|
-
// luna 家族最新:gpt-6-luna(上游无 6.1-luna,luna 家族最新即为 gpt-6-luna)
|
|
2343
|
-
"gpt-5.6-luna": {
|
|
2344
|
-
aliasOf: "gpt-6-luna",
|
|
2345
|
-
since: "2026-11-01",
|
|
2346
|
-
reason: "\u540C\u5BB6\u65CF\u6362\u4EE3\uFF0Cowner \u51B3\u5B9A\u900F\u660E\u91CD\u5B9A\u5411\uFF08luna \u5BB6\u65CF\u6700\u65B0\u4E3A gpt-6-luna\uFF09\u3002"
|
|
2347
|
-
}
|
|
2348
|
-
};
|
|
2349
|
-
function resolveCodexOAuthEffectiveModel(model) {
|
|
2350
|
-
const raw = asOptionalTrimmedString(model);
|
|
2351
|
-
if (!raw) return void 0;
|
|
2352
|
-
const normalized = raw.toLowerCase();
|
|
2353
|
-
return CODEX_OAUTH_MODEL_ALIASES[normalized]?.aliasOf ?? raw;
|
|
2354
|
-
}
|
|
2355
|
-
|
|
2356
|
-
// packages/agent-runtime/codexResponsesProvider.ts
|
|
2357
2335
|
var CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
|
|
2358
2336
|
var CODEX_CLIENT_VERSION = "0.162.1";
|
|
2359
2337
|
var CODEX_ORIGINATOR = "codex_cli_rs";
|
|
@@ -2504,6 +2482,8 @@ function buildCodexRequestBody(args, identity = createCodexRequestIdentity(), se
|
|
|
2504
2482
|
prompt_cache_key: sessionKey && isStableSessionIdentityEnabled() ? identity.sessionId : stablePromptCacheKey([model, stableInstructions, tools ?? []], "nolo-codex"),
|
|
2505
2483
|
client_metadata: identity.clientMetadata
|
|
2506
2484
|
};
|
|
2485
|
+
const reasoningEffort = args.openAiBody.reasoning_effort;
|
|
2486
|
+
if (reasoningEffort === "low") body.reasoning = { effort: reasoningEffort };
|
|
2507
2487
|
if (instructions) body.instructions = instructions;
|
|
2508
2488
|
if (tools && tools.length > 0) {
|
|
2509
2489
|
body.tools = tools;
|
|
@@ -2679,10 +2659,96 @@ async function fetchCodexResponsesCompletion(args) {
|
|
|
2679
2659
|
}
|
|
2680
2660
|
return result;
|
|
2681
2661
|
}
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2662
|
+
|
|
2663
|
+
// packages/agent-runtime/codexOAuthModelCatalog.ts
|
|
2664
|
+
var CODEX_OAUTH_MODELS_URL = "https://chatgpt.com/backend-api/codex/models";
|
|
2665
|
+
var CODEX_OAUTH_CATALOG_REQUEST_TIMEOUT_MS = 4e3;
|
|
2666
|
+
var inFlightCatalogFetches = /* @__PURE__ */ new Map();
|
|
2667
|
+
var catalogRequestUrl = () => `${CODEX_OAUTH_MODELS_URL}?client_version=${encodeURIComponent(CODEX_CLIENT_VERSION)}`;
|
|
2668
|
+
var parseCodexOAuthModelCatalog = (payload) => {
|
|
2669
|
+
const models = payload?.models;
|
|
2670
|
+
if (!Array.isArray(models)) return null;
|
|
2671
|
+
const windows = {};
|
|
2672
|
+
for (const entry of models) {
|
|
2673
|
+
if (!entry || typeof entry !== "object") continue;
|
|
2674
|
+
const record = entry;
|
|
2675
|
+
const slug = typeof record.slug === "string" ? record.slug.trim().toLowerCase() : "";
|
|
2676
|
+
if (!slug) continue;
|
|
2677
|
+
const contextWindow = record.context_window;
|
|
2678
|
+
if (typeof contextWindow !== "number" || !Number.isInteger(contextWindow) || contextWindow <= 0) {
|
|
2679
|
+
continue;
|
|
2680
|
+
}
|
|
2681
|
+
windows[slug] = contextWindow;
|
|
2682
|
+
}
|
|
2683
|
+
return windows;
|
|
2684
|
+
};
|
|
2685
|
+
var reportCodexOAuthCatalogFailure = (stage, accountId) => {
|
|
2686
|
+
try {
|
|
2687
|
+
const account = accountId ? accountId.slice(0, 6) : null;
|
|
2688
|
+
console.debug(
|
|
2689
|
+
`[codexOAuthModelCatalog] ${stage}${account ? ` account=${account}\u2026` : ""}`
|
|
2690
|
+
);
|
|
2691
|
+
} catch {
|
|
2692
|
+
}
|
|
2693
|
+
};
|
|
2694
|
+
async function ensureCodexOAuthModelCatalog(args) {
|
|
2695
|
+
const accessToken = args.accessToken?.trim();
|
|
2696
|
+
if (!accessToken) return;
|
|
2697
|
+
const accountId = args.accountId?.trim() || void 0;
|
|
2698
|
+
const nowMs = () => args.now ? args.now() : Date.now();
|
|
2699
|
+
const ttlMs = args.ttlMs ?? CODEX_OAUTH_CATALOG_TTL_MS;
|
|
2700
|
+
const accountKey = codexOAuthCatalogAccountKey(accountId);
|
|
2701
|
+
const snapshot = codexOAuthCatalogSnapshot(accountId);
|
|
2702
|
+
const now = nowMs();
|
|
2703
|
+
if (snapshot.fetchedAt !== null && now - snapshot.fetchedAt < ttlMs) return;
|
|
2704
|
+
if (snapshot.lastFailureAt !== null && now - snapshot.lastFailureAt < CODEX_OAUTH_CATALOG_RETRY_FLOOR_MS) {
|
|
2705
|
+
return;
|
|
2706
|
+
}
|
|
2707
|
+
const pending = inFlightCatalogFetches.get(accountKey);
|
|
2708
|
+
if (pending) {
|
|
2709
|
+
await pending;
|
|
2710
|
+
return;
|
|
2711
|
+
}
|
|
2712
|
+
const fetchImpl = args.fetchImpl ?? fetch;
|
|
2713
|
+
const timeoutMs = args.timeoutMs ?? CODEX_OAUTH_CATALOG_REQUEST_TIMEOUT_MS;
|
|
2714
|
+
const job = (async () => {
|
|
2715
|
+
try {
|
|
2716
|
+
const headers = {
|
|
2717
|
+
Authorization: `Bearer ${accessToken}`,
|
|
2718
|
+
originator: CODEX_ORIGINATOR,
|
|
2719
|
+
version: CODEX_CLIENT_VERSION,
|
|
2720
|
+
Accept: "application/json"
|
|
2721
|
+
};
|
|
2722
|
+
if (accountId) headers["chatgpt-account-id"] = accountId;
|
|
2723
|
+
const response = await fetchImpl(catalogRequestUrl(), {
|
|
2724
|
+
method: "GET",
|
|
2725
|
+
headers,
|
|
2726
|
+
signal: typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function" && timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : void 0
|
|
2727
|
+
});
|
|
2728
|
+
if (!response.ok) {
|
|
2729
|
+
markCodexOAuthCatalogFailure({ accountId, now: nowMs() });
|
|
2730
|
+
reportCodexOAuthCatalogFailure(`http ${response.status}`, accountId);
|
|
2731
|
+
return;
|
|
2732
|
+
}
|
|
2733
|
+
const payload = await response.json();
|
|
2734
|
+
const windows = parseCodexOAuthModelCatalog(payload);
|
|
2735
|
+
if (!windows) {
|
|
2736
|
+
markCodexOAuthCatalogFailure({ accountId, now: nowMs() });
|
|
2737
|
+
reportCodexOAuthCatalogFailure("malformed payload", accountId);
|
|
2738
|
+
return;
|
|
2739
|
+
}
|
|
2740
|
+
commitCodexOAuthCatalogWindows({ accountId, models: windows, now: nowMs() });
|
|
2741
|
+
} catch {
|
|
2742
|
+
markCodexOAuthCatalogFailure({ accountId, now: nowMs() });
|
|
2743
|
+
reportCodexOAuthCatalogFailure("request failed", accountId);
|
|
2744
|
+
}
|
|
2745
|
+
})();
|
|
2746
|
+
inFlightCatalogFetches.set(accountKey, job);
|
|
2747
|
+
try {
|
|
2748
|
+
await job;
|
|
2749
|
+
} finally {
|
|
2750
|
+
inFlightCatalogFetches.delete(accountKey);
|
|
2751
|
+
}
|
|
2686
2752
|
}
|
|
2687
2753
|
|
|
2688
2754
|
// packages/cli/client/providerResolution/codexOAuthTransport.ts
|
|
@@ -2787,7 +2853,12 @@ var resolveCodexOAuthTransport = async (ctx) => {
|
|
|
2787
2853
|
trace.log("headers", { attempt, status: res.status });
|
|
2788
2854
|
return res;
|
|
2789
2855
|
};
|
|
2856
|
+
if (!options?.noRetries) void ensureCodexOAuthModelCatalog({
|
|
2857
|
+
accessToken,
|
|
2858
|
+
...accountId ? { accountId } : {}
|
|
2859
|
+
});
|
|
2790
2860
|
const result = await fetchCodexResponsesCompletion({
|
|
2861
|
+
...options?.noRetries ? { maxAttempts: 1 } : {},
|
|
2791
2862
|
agentConfig,
|
|
2792
2863
|
accessToken,
|
|
2793
2864
|
...accountId ? { accountId } : {},
|
|
@@ -2795,7 +2866,8 @@ var resolveCodexOAuthTransport = async (ctx) => {
|
|
|
2795
2866
|
model: agentConfig.model || "gpt-5.6-sol",
|
|
2796
2867
|
messages,
|
|
2797
2868
|
stream: false,
|
|
2798
|
-
...tools.length > 0 ? { tools } : {}
|
|
2869
|
+
...tools.length > 0 ? { tools } : {},
|
|
2870
|
+
...options?.reasoning_effort ? { reasoning_effort: options.reasoning_effort } : {}
|
|
2799
2871
|
},
|
|
2800
2872
|
sessionKey: resolveSessionKey({ dialogId: options?.dialogId }),
|
|
2801
2873
|
signal: options?.signal,
|
|
@@ -2804,7 +2876,8 @@ var resolveCodexOAuthTransport = async (ctx) => {
|
|
|
2804
2876
|
fetchImpl: (url, init) => fetchWithTransientRetry(observedFetch, url, init, {
|
|
2805
2877
|
// 内层退避也要能被本次请求的 signal 打断(见 abortableSleep 注释)。
|
|
2806
2878
|
sleep: (ms) => abortableSleep(deps.sleep, ms, init?.signal ?? options?.signal),
|
|
2807
|
-
loopbackRequest
|
|
2879
|
+
loopbackRequest,
|
|
2880
|
+
...options?.noRetries ? { maxAttempts: 1, coreDrainingMaxAttempts: 1 } : {}
|
|
2808
2881
|
})
|
|
2809
2882
|
});
|
|
2810
2883
|
await recordLocalAvailability(result.status, result.body);
|
|
@@ -3191,7 +3264,11 @@ var resolveCursorTransport = async (ctx) => {
|
|
|
3191
3264
|
}
|
|
3192
3265
|
};
|
|
3193
3266
|
};
|
|
3194
|
-
const
|
|
3267
|
+
const hostConfirm = deps.confirmDestructiveAction;
|
|
3268
|
+
const confirmExternalFileAccess = hostConfirm ? async (request) => {
|
|
3269
|
+
const decision = await hostConfirm(request);
|
|
3270
|
+
return typeof decision === "boolean" ? decision : decision.approved === true;
|
|
3271
|
+
} : void 0;
|
|
3195
3272
|
const cursorSearchWorkspace = (args) => internalSearchWorkspace({
|
|
3196
3273
|
workspaceRoot,
|
|
3197
3274
|
query: args.query,
|
|
@@ -3213,9 +3290,11 @@ var resolveCursorTransport = async (ctx) => {
|
|
|
3213
3290
|
model: agentConfig.model || "cursor-default",
|
|
3214
3291
|
systemPrompt: agentConfig.prompt?.trim() || void 0,
|
|
3215
3292
|
tools,
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3293
|
+
...ctx.textOnly ? {} : {
|
|
3294
|
+
executeTool: cursorExecuteTool,
|
|
3295
|
+
searchWorkspace: cursorSearchWorkspace,
|
|
3296
|
+
listWorkspaceEntries: cursorListWorkspaceEntries
|
|
3297
|
+
}
|
|
3219
3298
|
});
|
|
3220
3299
|
return {
|
|
3221
3300
|
model: agentConfig.model || "cursor-default",
|
|
@@ -3402,13 +3481,15 @@ var resolveDirectOpenAiCompatibleTransport = async (ctx) => {
|
|
|
3402
3481
|
tools,
|
|
3403
3482
|
fetchImpl: (url, init) => fetchWithTransientRetry(fetchImpl, url, init, {
|
|
3404
3483
|
sleep: deps.sleep,
|
|
3405
|
-
loopbackRequest
|
|
3484
|
+
loopbackRequest,
|
|
3485
|
+
...options?.noRetries ? { maxAttempts: 1, coreDrainingMaxAttempts: 1 } : {}
|
|
3406
3486
|
}),
|
|
3407
3487
|
stream,
|
|
3408
3488
|
sessionId: asOptionalTrimmedString(options?.dialogId) ?? asOptionalTrimmedString(agentConfig.key),
|
|
3409
3489
|
onTextDelta: options?.onTextDelta,
|
|
3410
3490
|
onReasoningDelta: options?.onReasoningDelta,
|
|
3411
3491
|
signal: options?.signal,
|
|
3492
|
+
...options?.noRetries ? { noRetries: true } : {},
|
|
3412
3493
|
outboundDiagnostics: options?.requestId ? { callId: options.requestId } : void 0,
|
|
3413
3494
|
onHttpResult: ({ status, body }) => recordLocalAvailability(status, body),
|
|
3414
3495
|
...resolveRequestApiKey ? { resolveApiKey: resolveRequestApiKey } : {}
|
|
@@ -3738,14 +3819,8 @@ var resolveOwnerOAuthProxyTransport = async (ctx) => {
|
|
|
3738
3819
|
retryNetworkErrors: false,
|
|
3739
3820
|
// 内层预算按「剩余总额度」裁剪:普通可重试状态码 ≤ 3 次、503
|
|
3740
3821
|
// core_draining 排空窗口 ≤ 30 次,且都不超过剩余总额度。
|
|
3741
|
-
maxAttempts: Math.min(
|
|
3742
|
-
|
|
3743
|
-
remaining
|
|
3744
|
-
),
|
|
3745
|
-
coreDrainingMaxAttempts: Math.min(
|
|
3746
|
-
OWNER_PROXY_CORE_DRAINING_MAX_ATTEMPTS,
|
|
3747
|
-
remaining
|
|
3748
|
-
),
|
|
3822
|
+
maxAttempts: options?.noRetries ? 1 : Math.min(OWNER_PROXY_GENERIC_MAX_ATTEMPTS, remaining),
|
|
3823
|
+
coreDrainingMaxAttempts: options?.noRetries ? 1 : Math.min(OWNER_PROXY_CORE_DRAINING_MAX_ATTEMPTS, remaining),
|
|
3749
3824
|
// 注意:计数必须**无条件**挂在 onRetry 上——若只在有 activityReporter
|
|
3750
3825
|
// 时才挂,innerRetries / usedAttempts 会漏计,重试预算就形同虚设。
|
|
3751
3826
|
onRetry: ({ attempt, maxAttempts, delayMs }) => {
|
|
@@ -3760,7 +3835,7 @@ var resolveOwnerOAuthProxyTransport = async (ctx) => {
|
|
|
3760
3835
|
usedAttempts += 1;
|
|
3761
3836
|
return { response, innerRetried: innerRetries > 0 };
|
|
3762
3837
|
};
|
|
3763
|
-
const res = await sendWithOwnerOriginMismatchRetry(
|
|
3838
|
+
const res = options?.noRetries ? (await send()).response : await sendWithOwnerOriginMismatchRetry(
|
|
3764
3839
|
send,
|
|
3765
3840
|
init.signal ?? void 0,
|
|
3766
3841
|
deps.activityReporter ? ({ attempt, maxAttempts, delayMs }) => {
|
|
@@ -3963,6 +4038,7 @@ var resolvePlatformProxyTransport = async (ctx) => {
|
|
|
3963
4038
|
{
|
|
3964
4039
|
sleep: deps.sleep,
|
|
3965
4040
|
loopbackRequest,
|
|
4041
|
+
...options?.noRetries ? { maxAttempts: 1, coreDrainingMaxAttempts: 1 } : {},
|
|
3966
4042
|
// A chat POST is not safe to replay after an ambiguous network or
|
|
3967
4043
|
// gateway failure: the server/provider may already have accepted
|
|
3968
4044
|
// it. The client only waits through the server's explicit pre-
|
|
@@ -4113,6 +4189,27 @@ async function resolveLocalProvider(ctx) {
|
|
|
4113
4189
|
);
|
|
4114
4190
|
}
|
|
4115
4191
|
|
|
4192
|
+
// packages/cli/client/providerResolveOverrides.ts
|
|
4193
|
+
function resolveProviderResolveOverrides(agentConfig, options) {
|
|
4194
|
+
if (!options) return agentConfig;
|
|
4195
|
+
const { toolNames, prompt } = options;
|
|
4196
|
+
if (toolNames === void 0 && prompt === void 0) return agentConfig;
|
|
4197
|
+
const current = agentConfig;
|
|
4198
|
+
return {
|
|
4199
|
+
...agentConfig,
|
|
4200
|
+
...toolNames !== void 0 ? {
|
|
4201
|
+
toolNames,
|
|
4202
|
+
exposedToolNames: toolNames,
|
|
4203
|
+
toolSurface: { ...current.toolSurface, finalToolNames: toolNames },
|
|
4204
|
+
runScopedToolSurface: {
|
|
4205
|
+
...current.runScopedToolSurface,
|
|
4206
|
+
finalToolNames: toolNames
|
|
4207
|
+
}
|
|
4208
|
+
} : {},
|
|
4209
|
+
...prompt !== void 0 ? { prompt } : {}
|
|
4210
|
+
};
|
|
4211
|
+
}
|
|
4212
|
+
|
|
4116
4213
|
// packages/cli/client/localRuntimePaths.ts
|
|
4117
4214
|
import { dirname, extname, join } from "node:path";
|
|
4118
4215
|
import { fileURLToPath } from "node:url";
|
|
@@ -4401,7 +4498,7 @@ function clipLocalWakeEvidence(value, max = 1200) {
|
|
|
4401
4498
|
function buildLocalWakeDisplayText(args) {
|
|
4402
4499
|
const failed = args.terminalStatus !== "done";
|
|
4403
4500
|
const duration = typeof args.durationMs === "number" && args.durationMs >= 0 ? ` \xB7 ${Math.floor(args.durationMs / 6e4)}m${Math.floor(args.durationMs / 1e3) % 60}s` : "";
|
|
4404
|
-
return `1 \u6761\u540E\u53F0 run \u5DF2\
|
|
4501
|
+
return `1 \u6761\u540E\u53F0 run \u5DF2\u7ED3\u675F \xB7 ${failed ? "\u2717" : "\u2713"} ${args.label || "\u540E\u53F0 run"} [${args.terminalStatus}]${duration}`;
|
|
4405
4502
|
}
|
|
4406
4503
|
function buildLocalParentWakeMessage(args) {
|
|
4407
4504
|
return [
|
|
@@ -5898,21 +5995,27 @@ var INSTABOX_DEFAULT_BASE_URL = "https://api.instabox.sh/v1";
|
|
|
5898
5995
|
var INSTABOX_MAX_EXEC_SECONDS = 600;
|
|
5899
5996
|
var INSTABOX_MAX_STDIN_BYTES = 1024 * 1024;
|
|
5900
5997
|
var SAFE_MESSAGE = {
|
|
5998
|
+
instabox_upload_failed: "Instabox file upload failed",
|
|
5999
|
+
instabox_recovery_failed: "Instabox recovery persistence or authority validation failed",
|
|
6000
|
+
instabox_recovery_unknown: "Instabox machine identity is unknown; manual reconciliation required",
|
|
5901
6001
|
"instabox_invalid_config": "Rejected: instabox backend needs an apiKey and a templateId",
|
|
5902
6002
|
"instabox_invalid_ticket": "Rejected: execution ticket cannot be satisfied by the instabox backend",
|
|
5903
6003
|
"instabox_unsupported_request": "Request is not supported by the instabox backend",
|
|
5904
6004
|
"instabox_lease_not_found": "Unknown execution lease",
|
|
5905
6005
|
"instabox_lease_mismatch": "Lease does not match this backend or ticket",
|
|
5906
6006
|
"instabox_lease_released": "Lease was already released",
|
|
6007
|
+
"instabox_lease_stopping": "Lease stop was requested; execution is fenced",
|
|
5907
6008
|
"instabox_create_failed": "Instabox machine create failed",
|
|
5908
6009
|
"instabox_create_unconfirmed": "Instabox machine create could not be confirmed",
|
|
5909
6010
|
"instabox_exec_failed": "Instabox exec could not be completed",
|
|
6011
|
+
"instabox_delete_forbidden": "Instabox machine deletion is forbidden; machine was not cleaned up",
|
|
5910
6012
|
"instabox_cleanup_pending": "Instabox machine delete could not be confirmed; cleanup is pending"
|
|
5911
6013
|
};
|
|
5912
6014
|
var InstaboxBackendError = class extends Error {
|
|
5913
|
-
constructor(code, detail, cleanupPending = false, machineId, upstreamErrorCode) {
|
|
6015
|
+
constructor(code, detail, cleanupPending = false, machineId, upstreamErrorCode, recovery) {
|
|
5914
6016
|
super(detail ? `${SAFE_MESSAGE[code]} (${detail})` : SAFE_MESSAGE[code]);
|
|
5915
6017
|
this.machineId = machineId;
|
|
6018
|
+
this.recovery = recovery;
|
|
5916
6019
|
this.name = "InstaboxBackendError";
|
|
5917
6020
|
this.code = code;
|
|
5918
6021
|
this.cleanupPending = cleanupPending;
|
|
@@ -5923,6 +6026,7 @@ var InstaboxBackendError = class extends Error {
|
|
|
5923
6026
|
cleanupPending;
|
|
5924
6027
|
upstreamErrorCode;
|
|
5925
6028
|
};
|
|
6029
|
+
var INSTABOX_MAX_UPLOAD_BYTES = 5 * 1024 ** 3;
|
|
5926
6030
|
var DEFAULT_OPERATION_WAIT_SECONDS = 20;
|
|
5927
6031
|
var DEFAULT_POLL_INTERVAL_MS = 1e3;
|
|
5928
6032
|
var DEFAULT_MAX_POLL_ATTEMPTS = 30;
|
|
@@ -5999,6 +6103,7 @@ var InstaboxBackend = class {
|
|
|
5999
6103
|
#machineTimeoutSeconds;
|
|
6000
6104
|
#createTimeoutMs;
|
|
6001
6105
|
#deleteTimeoutMs;
|
|
6106
|
+
#stopTimeoutMs;
|
|
6002
6107
|
#operationWaitSeconds;
|
|
6003
6108
|
#pollIntervalMs;
|
|
6004
6109
|
#maxPollAttempts;
|
|
@@ -6007,9 +6112,23 @@ var InstaboxBackend = class {
|
|
|
6007
6112
|
#creationPlan;
|
|
6008
6113
|
#freeOrgObservation;
|
|
6009
6114
|
#billingPolicy;
|
|
6115
|
+
#deletionPolicy;
|
|
6010
6116
|
#deleteMachineImpl;
|
|
6117
|
+
#recovery;
|
|
6011
6118
|
#leases = /* @__PURE__ */ new Map();
|
|
6119
|
+
#recoveryWrites = /* @__PURE__ */ new WeakMap();
|
|
6012
6120
|
constructor(options) {
|
|
6121
|
+
if (options.deletionPolicy !== void 0 && options.deletionPolicy !== "legacy" && options.deletionPolicy !== "forbid") {
|
|
6122
|
+
throw new InstaboxBackendError("instabox_invalid_config", "invalid deletion policy");
|
|
6123
|
+
}
|
|
6124
|
+
this.#deletionPolicy = options.deletionPolicy ?? "legacy";
|
|
6125
|
+
if (options.recovery) {
|
|
6126
|
+
const a = options.recovery.authority;
|
|
6127
|
+
if (this.#deletionPolicy !== "forbid" || !options.creationPlan || !options.recovery.accountId?.trim() || !a?.ownerUserId?.trim() || !a.ticketId?.trim() || !a.grantId?.trim() || !Number.isSafeInteger(a.generation) || a.generation < 0) {
|
|
6128
|
+
throw new InstaboxBackendError("instabox_invalid_config", "invalid recovery binding");
|
|
6129
|
+
}
|
|
6130
|
+
this.#recovery = { ...options.recovery, authority: structuredClone(a) };
|
|
6131
|
+
}
|
|
6013
6132
|
const apiKey = options.apiKey?.trim() ?? "";
|
|
6014
6133
|
const templateId = options.templateId?.trim() ?? "";
|
|
6015
6134
|
if (!apiKey || !templateId) {
|
|
@@ -6035,11 +6154,21 @@ var InstaboxBackend = class {
|
|
|
6035
6154
|
""
|
|
6036
6155
|
);
|
|
6037
6156
|
this.#now = options.now ?? Date.now;
|
|
6038
|
-
this.#fetch = options.fetchImpl ?? ((url, init) =>
|
|
6157
|
+
this.#fetch = options.fetchImpl ?? ((url, init) => {
|
|
6158
|
+
const { rawBody, ...request } = init;
|
|
6159
|
+
return globalThis.fetch(url, {
|
|
6160
|
+
...request,
|
|
6161
|
+
...rawBody === void 0 ? {} : { body: rawBody }
|
|
6162
|
+
});
|
|
6163
|
+
});
|
|
6039
6164
|
this.#sleep = options.sleepImpl ?? ((ms) => new Promise((resolve5) => setTimeout(resolve5, ms)));
|
|
6040
6165
|
this.#machineTimeoutSeconds = options.machineTimeoutSeconds ?? 1800;
|
|
6041
6166
|
this.#createTimeoutMs = options.createTimeoutMs ?? 18e4;
|
|
6042
6167
|
this.#deleteTimeoutMs = options.deleteTimeoutMs ?? 12e4;
|
|
6168
|
+
this.#stopTimeoutMs = options.stopTimeoutMs ?? 12e4;
|
|
6169
|
+
if (!Number.isFinite(this.#stopTimeoutMs) || this.#stopTimeoutMs <= 0) {
|
|
6170
|
+
throw new InstaboxBackendError("instabox_invalid_config");
|
|
6171
|
+
}
|
|
6043
6172
|
this.#operationWaitSeconds = options.operationWaitSeconds ?? DEFAULT_OPERATION_WAIT_SECONDS;
|
|
6044
6173
|
this.#pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
6045
6174
|
this.#maxPollAttempts = options.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS;
|
|
@@ -6061,6 +6190,15 @@ var InstaboxBackend = class {
|
|
|
6061
6190
|
* 成功时刻(不采信 202 响应时间,那是「已受理」不是「可用」)。
|
|
6062
6191
|
*/
|
|
6063
6192
|
async prepare(ticket) {
|
|
6193
|
+
const context = {};
|
|
6194
|
+
try {
|
|
6195
|
+
return await this.#prepare(ticket, context);
|
|
6196
|
+
} catch (error) {
|
|
6197
|
+
if (context.record) throw this.#withRecovery(error, context.record);
|
|
6198
|
+
throw error;
|
|
6199
|
+
}
|
|
6200
|
+
}
|
|
6201
|
+
async #prepare(ticket, context) {
|
|
6064
6202
|
if (ticket.version !== 1 || !ticket.ticketId || !ticket.grantId) {
|
|
6065
6203
|
throw new InstaboxBackendError("instabox_invalid_ticket");
|
|
6066
6204
|
}
|
|
@@ -6074,23 +6212,61 @@ var InstaboxBackend = class {
|
|
|
6074
6212
|
}
|
|
6075
6213
|
}
|
|
6076
6214
|
const machineName = plan?.name ?? buildInstaboxMachineName(ticket.ticketId, ticket.agentKey);
|
|
6215
|
+
const createBody = plan ? {
|
|
6216
|
+
name: plan.name,
|
|
6217
|
+
templateId: plan.templateId,
|
|
6218
|
+
orgId: plan.orgId,
|
|
6219
|
+
vcpus: plan.vcpus,
|
|
6220
|
+
memMiB: plan.memMiB
|
|
6221
|
+
} : {
|
|
6222
|
+
name: machineName,
|
|
6223
|
+
templateId: this.#templateId,
|
|
6224
|
+
timeoutSeconds: this.#machineTimeoutSeconds
|
|
6225
|
+
};
|
|
6226
|
+
const createKey2 = buildInstaboxCreateIdempotencyKey(ticket.ticketId);
|
|
6227
|
+
if (this.#recovery && plan) {
|
|
6228
|
+
const authority = this.#recovery.authority;
|
|
6229
|
+
if (ticket.ticketId !== authority.ticketId || ticket.grantId !== authority.grantId || ticket.callerUserId !== authority.ownerUserId) {
|
|
6230
|
+
throw new InstaboxBackendError("instabox_recovery_failed");
|
|
6231
|
+
}
|
|
6232
|
+
const expectedSpec = this.#freeOrgObservation.allowedSpecs.find(
|
|
6233
|
+
(s) => s.vcpus === plan.vcpus && s.memMiB === plan.memMiB
|
|
6234
|
+
);
|
|
6235
|
+
context.record = {
|
|
6236
|
+
version: 1,
|
|
6237
|
+
recordId: crypto.randomUUID(),
|
|
6238
|
+
revision: 0,
|
|
6239
|
+
...authority,
|
|
6240
|
+
accountId: this.#recovery.accountId,
|
|
6241
|
+
provider: "instabox",
|
|
6242
|
+
baseUrl: this.#baseUrl,
|
|
6243
|
+
plan: structuredClone(plan),
|
|
6244
|
+
billingPolicy: this.#billingPolicy,
|
|
6245
|
+
persistentDiskGiB: expectedSpec.persistentDiskGiB,
|
|
6246
|
+
create: {
|
|
6247
|
+
method: "POST",
|
|
6248
|
+
path: "/machines",
|
|
6249
|
+
body: JSON.stringify(createBody),
|
|
6250
|
+
idempotencyKey: createKey2,
|
|
6251
|
+
requestedAt,
|
|
6252
|
+
state: "submitted-unknown"
|
|
6253
|
+
},
|
|
6254
|
+
stop: { intent: false, accepted: false }
|
|
6255
|
+
};
|
|
6256
|
+
await this.#saveRecovery(context.record);
|
|
6257
|
+
}
|
|
6077
6258
|
const created = await this.#call({
|
|
6078
6259
|
method: "POST",
|
|
6079
6260
|
path: "/machines",
|
|
6080
|
-
idempotencyKey:
|
|
6081
|
-
body:
|
|
6082
|
-
name: plan.name,
|
|
6083
|
-
templateId: plan.templateId,
|
|
6084
|
-
orgId: plan.orgId,
|
|
6085
|
-
vcpus: plan.vcpus,
|
|
6086
|
-
memMiB: plan.memMiB
|
|
6087
|
-
// Ordinary API keys cannot change free maxRunMinutes. Do not send it.
|
|
6088
|
-
} : {
|
|
6089
|
-
name: machineName,
|
|
6090
|
-
templateId: this.#templateId,
|
|
6091
|
-
timeoutSeconds: this.#machineTimeoutSeconds
|
|
6092
|
-
}
|
|
6261
|
+
idempotencyKey: createKey2,
|
|
6262
|
+
body: createBody
|
|
6093
6263
|
});
|
|
6264
|
+
if (context.record) {
|
|
6265
|
+
context.record.machineId = readString2(asRecord(created.payload)?.machineId) ?? void 0;
|
|
6266
|
+
context.record.createOperationId = readString2(asRecord(created.payload)?.id) ?? void 0;
|
|
6267
|
+
if (isSuccess(created.status)) context.record.create.state = "responded";
|
|
6268
|
+
await this.#saveRecovery(context.record);
|
|
6269
|
+
}
|
|
6094
6270
|
if (!isSuccess(created.status)) {
|
|
6095
6271
|
const upstreamCode = extractInstaboxErrorCode(created.payload);
|
|
6096
6272
|
let detail = `create HTTP ${created.status}`;
|
|
@@ -6163,6 +6339,7 @@ var InstaboxBackend = class {
|
|
|
6163
6339
|
if (this.#billingPolicy === "free-only" && machine.maxRunMinutes !== 480) mismatches.push("maxRunMinutes mismatch");
|
|
6164
6340
|
if (mismatches.length > 0) {
|
|
6165
6341
|
const reason = mismatches.join("; ");
|
|
6342
|
+
this.#assertDeletionAllowed(machineId, reason);
|
|
6166
6343
|
try {
|
|
6167
6344
|
if (this.#deleteMachineImpl) {
|
|
6168
6345
|
await this.#deleteMachineImpl(machineId);
|
|
@@ -6208,6 +6385,7 @@ var InstaboxBackend = class {
|
|
|
6208
6385
|
const usageBaselineRunningMs = baseline === null ? null : Math.round(baseline.runningSeconds * 1e3);
|
|
6209
6386
|
const leaseId = `${machineId}:${ticket.ticketId}`;
|
|
6210
6387
|
this.#leases.set(leaseId, {
|
|
6388
|
+
recovery: context.record,
|
|
6211
6389
|
machineId,
|
|
6212
6390
|
ticketId: ticket.ticketId,
|
|
6213
6391
|
grantId: ticket.grantId,
|
|
@@ -6216,7 +6394,9 @@ var InstaboxBackend = class {
|
|
|
6216
6394
|
createOperationId: operationId,
|
|
6217
6395
|
usageBaselineRunningMs,
|
|
6218
6396
|
releasedAt: null,
|
|
6219
|
-
releaseOutcome: null
|
|
6397
|
+
releaseOutcome: null,
|
|
6398
|
+
stopState: null,
|
|
6399
|
+
stopAccepted: false
|
|
6220
6400
|
});
|
|
6221
6401
|
return {
|
|
6222
6402
|
leaseId,
|
|
@@ -6227,6 +6407,7 @@ var InstaboxBackend = class {
|
|
|
6227
6407
|
readableRoots: [...ticket.filesystem.readableRoots],
|
|
6228
6408
|
writableRoots: [...ticket.filesystem.writableRoots],
|
|
6229
6409
|
metadata: {
|
|
6410
|
+
...context.record ? { recoveryRecordId: context.record.recordId } : {},
|
|
6230
6411
|
machineId,
|
|
6231
6412
|
machineName,
|
|
6232
6413
|
templateId: this.#templateId,
|
|
@@ -6237,11 +6418,92 @@ var InstaboxBackend = class {
|
|
|
6237
6418
|
}
|
|
6238
6419
|
};
|
|
6239
6420
|
}
|
|
6421
|
+
/** Official OpenAPI: upload-url is on the API's own origin, then PUT raw
|
|
6422
|
+
* bytes with the signed token and NO API credential. No redirect is followed.
|
|
6423
|
+
* Caller retains ownership of bytes and must not mutate them until completion.
|
|
6424
|
+
* Provider follows target symlinks: lexical /workspace validation is not an OS
|
|
6425
|
+
* containment guarantee. Deliver source before executing untrusted code. */
|
|
6426
|
+
async uploadFile(lease, input) {
|
|
6427
|
+
const entry = this.#requireEntry(lease);
|
|
6428
|
+
const checkLease = () => {
|
|
6429
|
+
if (entry.releasedAt !== null) throw new InstaboxBackendError("instabox_lease_released");
|
|
6430
|
+
if (entry.stopState !== null) throw new InstaboxBackendError("instabox_lease_stopping");
|
|
6431
|
+
};
|
|
6432
|
+
const fail5 = () => new InstaboxBackendError("instabox_upload_failed");
|
|
6433
|
+
checkLease();
|
|
6434
|
+
if (!input || typeof input.path !== "string" || !input.path.startsWith("/workspace/") || input.path.endsWith("/") || input.path.split("/").some((p, i) => i > 0 && (!p || p === "." || p === "..")) || /[\\\x00-\x1f\x7f]/.test(input.path) || !(input.bytes instanceof Uint8Array) || input.bytes.byteLength > INSTABOX_MAX_UPLOAD_BYTES || !input.signal || !Number.isFinite(input.deadlineAt)) throw fail5();
|
|
6435
|
+
let base;
|
|
6436
|
+
try {
|
|
6437
|
+
base = new URL(this.#baseUrl);
|
|
6438
|
+
} catch {
|
|
6439
|
+
throw fail5();
|
|
6440
|
+
}
|
|
6441
|
+
if (base.protocol !== "https:" || base.username || base.password || base.search || base.hash) throw fail5();
|
|
6442
|
+
const controller = new AbortController();
|
|
6443
|
+
const remaining = input.deadlineAt - this.#now();
|
|
6444
|
+
if (input.signal.aborted || remaining <= 0) throw fail5();
|
|
6445
|
+
const started = performance.now();
|
|
6446
|
+
const timeLeft = () => Math.min(input.deadlineAt - this.#now(), remaining - (performance.now() - started));
|
|
6447
|
+
let timer;
|
|
6448
|
+
let onAbort;
|
|
6449
|
+
const interrupted = new Promise((_resolve, reject) => {
|
|
6450
|
+
onAbort = () => {
|
|
6451
|
+
controller.abort();
|
|
6452
|
+
reject(fail5());
|
|
6453
|
+
};
|
|
6454
|
+
input.signal.addEventListener("abort", onAbort, { once: true });
|
|
6455
|
+
const tick = () => {
|
|
6456
|
+
const left = timeLeft();
|
|
6457
|
+
if (left <= 0) onAbort();
|
|
6458
|
+
else timer = setTimeout(tick, Math.min(left, 2147483647));
|
|
6459
|
+
};
|
|
6460
|
+
tick();
|
|
6461
|
+
});
|
|
6462
|
+
const check = () => {
|
|
6463
|
+
checkLease();
|
|
6464
|
+
if (input.signal.aborted || controller.signal.aborted || timeLeft() <= 0) throw fail5();
|
|
6465
|
+
};
|
|
6466
|
+
try {
|
|
6467
|
+
check();
|
|
6468
|
+
const response = await Promise.race([this.#call({
|
|
6469
|
+
method: "POST",
|
|
6470
|
+
path: `/machines/${encodeURIComponent(entry.machineId)}/files/upload-url`,
|
|
6471
|
+
body: { path: input.path, parents: true },
|
|
6472
|
+
signal: controller.signal,
|
|
6473
|
+
redirect: "error"
|
|
6474
|
+
}), interrupted]);
|
|
6475
|
+
check();
|
|
6476
|
+
const payload = asRecord(response.payload);
|
|
6477
|
+
if (response.status !== 201 || !payload || payload.method !== "PUT" || payload.path !== input.path || typeof payload.url !== "string" || typeof payload.expiresAt !== "string" || !Number.isSafeInteger(payload.maxBytes) || payload.maxBytes < input.bytes.byteLength || payload.maxBytes > INSTABOX_MAX_UPLOAD_BYTES || !Number.isFinite(Date.parse(payload.expiresAt)) || Date.parse(payload.expiresAt) <= this.#now()) throw fail5();
|
|
6478
|
+
const url = new URL(payload.url);
|
|
6479
|
+
if (url.protocol !== "https:" || url.origin !== base.origin || url.username || url.password || url.hash || url.pathname !== `${base.pathname}/machines/${encodeURIComponent(entry.machineId)}/files` || !url.searchParams.get("token")) throw fail5();
|
|
6480
|
+
check();
|
|
6481
|
+
const uploaded = await Promise.race([this.#fetch(url.href, {
|
|
6482
|
+
method: "PUT",
|
|
6483
|
+
headers: { "Content-Type": "application/octet-stream" },
|
|
6484
|
+
rawBody: input.bytes,
|
|
6485
|
+
signal: controller.signal,
|
|
6486
|
+
redirect: "error"
|
|
6487
|
+
}), interrupted]);
|
|
6488
|
+
check();
|
|
6489
|
+
if (uploaded.redirected || !isSuccess(uploaded.status)) throw fail5();
|
|
6490
|
+
} catch (error) {
|
|
6491
|
+
checkLease();
|
|
6492
|
+
throw fail5();
|
|
6493
|
+
} finally {
|
|
6494
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
6495
|
+
if (onAbort) input.signal.removeEventListener("abort", onAbort);
|
|
6496
|
+
controller.abort();
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6240
6499
|
async execute(lease, request, onEvent) {
|
|
6241
6500
|
const entry = this.#requireEntry(lease);
|
|
6242
6501
|
if (entry.releasedAt !== null) {
|
|
6243
6502
|
throw new InstaboxBackendError("instabox_lease_released");
|
|
6244
6503
|
}
|
|
6504
|
+
if (entry.stopState !== null) {
|
|
6505
|
+
throw entry.recovery ? this.#withRecovery(new InstaboxBackendError("instabox_lease_stopping"), entry.recovery) : new InstaboxBackendError("instabox_lease_stopping");
|
|
6506
|
+
}
|
|
6245
6507
|
if (request.kind !== "command") {
|
|
6246
6508
|
throw new InstaboxBackendError(
|
|
6247
6509
|
"instabox_unsupported_request",
|
|
@@ -6260,11 +6522,17 @@ var InstaboxBackend = class {
|
|
|
6260
6522
|
const executionId = `${entry.machineId}:${this.#now().toString(36)}`;
|
|
6261
6523
|
const startedAt = this.#now();
|
|
6262
6524
|
onEvent?.({ type: "started", executionId, at: startedAt });
|
|
6525
|
+
if (entry.stopState !== null) {
|
|
6526
|
+
throw entry.recovery ? this.#withRecovery(new InstaboxBackendError("instabox_lease_stopping"), entry.recovery) : new InstaboxBackendError("instabox_lease_stopping");
|
|
6527
|
+
}
|
|
6263
6528
|
const response = await this.#call({
|
|
6264
6529
|
method: "POST",
|
|
6265
6530
|
path: `/machines/${encodeURIComponent(entry.machineId)}/exec`,
|
|
6266
6531
|
body: { cmd, timeoutSeconds, ...stdin === void 0 ? {} : { stdin } }
|
|
6267
6532
|
});
|
|
6533
|
+
if (entry.stopState !== null) {
|
|
6534
|
+
throw entry.recovery ? this.#withRecovery(new InstaboxBackendError("instabox_lease_stopping"), entry.recovery) : new InstaboxBackendError("instabox_lease_stopping");
|
|
6535
|
+
}
|
|
6268
6536
|
if (!isSuccess(response.status)) {
|
|
6269
6537
|
throw new InstaboxBackendError(
|
|
6270
6538
|
"instabox_exec_failed",
|
|
@@ -6299,6 +6567,9 @@ var InstaboxBackend = class {
|
|
|
6299
6567
|
usage: { wallMs: Math.max(0, this.#now() - startedAt) }
|
|
6300
6568
|
});
|
|
6301
6569
|
onEvent?.({ type: "exited", executionId, exitCode });
|
|
6570
|
+
if (entry.stopState !== null) {
|
|
6571
|
+
throw entry.recovery ? this.#withRecovery(new InstaboxBackendError("instabox_lease_stopping"), entry.recovery) : new InstaboxBackendError("instabox_lease_stopping");
|
|
6572
|
+
}
|
|
6302
6573
|
return {
|
|
6303
6574
|
executionId,
|
|
6304
6575
|
ok: !timedOut && exitCode === 0,
|
|
@@ -6311,6 +6582,114 @@ var InstaboxBackend = class {
|
|
|
6311
6582
|
}
|
|
6312
6583
|
};
|
|
6313
6584
|
}
|
|
6585
|
+
/**
|
|
6586
|
+
* Official contract verified from https://api.instabox.sh/v1/openapi.json:
|
|
6587
|
+
* POST /v1/machines/{id}/stop -> 202 Operation (not a Machine).
|
|
6588
|
+
* GET /v1/machines/{id} -> Machine; only state=stopped confirms shutdown.
|
|
6589
|
+
* No release/delete, and no inference from operation success, 404 or desiredState.
|
|
6590
|
+
* State is process-local. Restart recovery requires a durable lease/machine binding,
|
|
6591
|
+
* stop intent, idempotency key and reconciliation API owned by the caller.
|
|
6592
|
+
* A caller publishing an already-resolved execute result must also fence its
|
|
6593
|
+
* own run generation/cancellation state: this backend cannot revoke that result.
|
|
6594
|
+
* The request deadline bounds observation, not transport cancellation; an HTTP
|
|
6595
|
+
* request may settle late, so retries keep the same stop idempotency key.
|
|
6596
|
+
*/
|
|
6597
|
+
async stop(lease) {
|
|
6598
|
+
const entry = this.#requireEntry(lease);
|
|
6599
|
+
if (entry.releasedAt !== null) {
|
|
6600
|
+
throw new InstaboxBackendError("instabox_lease_released");
|
|
6601
|
+
}
|
|
6602
|
+
if (entry.stopState === "stopped") {
|
|
6603
|
+
return { ok: true, state: "stopped", machineId: entry.machineId };
|
|
6604
|
+
}
|
|
6605
|
+
if (entry.stopTask) return entry.stopTask;
|
|
6606
|
+
entry.stopState = "unknown";
|
|
6607
|
+
const task = this.#stopEntry(entry);
|
|
6608
|
+
entry.stopTask = task;
|
|
6609
|
+
try {
|
|
6610
|
+
return await task;
|
|
6611
|
+
} catch (error) {
|
|
6612
|
+
if (entry.recovery) throw this.#withRecovery(error, entry.recovery);
|
|
6613
|
+
throw error;
|
|
6614
|
+
} finally {
|
|
6615
|
+
entry.stopTask = void 0;
|
|
6616
|
+
}
|
|
6617
|
+
}
|
|
6618
|
+
async #stopEntry(entry) {
|
|
6619
|
+
const startedAt = this.#now();
|
|
6620
|
+
const wallStartedAt = Date.now();
|
|
6621
|
+
const remaining = () => this.#stopTimeoutMs - Math.max(
|
|
6622
|
+
this.#now() - startedAt,
|
|
6623
|
+
Date.now() - wallStartedAt
|
|
6624
|
+
);
|
|
6625
|
+
if (entry.recovery) {
|
|
6626
|
+
entry.recovery.stop.intent = true;
|
|
6627
|
+
entry.recovery.stop.idempotencyKey ??= `nolo-stop-${entry.machineId}`;
|
|
6628
|
+
await this.#saveRecovery(entry.recovery);
|
|
6629
|
+
}
|
|
6630
|
+
const result = async (state2) => {
|
|
6631
|
+
if (entry.recovery) {
|
|
6632
|
+
entry.recovery.stop.lastObservedState = state2;
|
|
6633
|
+
await this.#saveRecovery(entry.recovery);
|
|
6634
|
+
}
|
|
6635
|
+
entry.stopState = state2;
|
|
6636
|
+
return { ok: state2 === "stopped", state: state2, machineId: entry.machineId };
|
|
6637
|
+
};
|
|
6638
|
+
const path = `/machines/${encodeURIComponent(entry.machineId)}`;
|
|
6639
|
+
let state = "unknown";
|
|
6640
|
+
for (let attempt = 0; attempt < this.#maxPollAttempts && remaining() > 0; attempt += 1) {
|
|
6641
|
+
const observed = await this.#call({ method: "GET", path, timeoutMs: remaining() });
|
|
6642
|
+
const machine = observed.status === 200 ? asRecord(observed.payload) : null;
|
|
6643
|
+
if (machine?.id !== entry.machineId || typeof machine.state !== "string") {
|
|
6644
|
+
return result("unknown");
|
|
6645
|
+
}
|
|
6646
|
+
if (machine.state === "stopped") return result("stopped");
|
|
6647
|
+
if (machine.state !== "running" && machine.state !== "stopping") {
|
|
6648
|
+
return result("unknown");
|
|
6649
|
+
}
|
|
6650
|
+
state = entry.stopAccepted || machine.state === "stopping" ? "pending" : "unknown";
|
|
6651
|
+
if (!entry.stopAccepted && machine.state === "running" && remaining() > 0) {
|
|
6652
|
+
const accepted = await this.#call({
|
|
6653
|
+
method: "POST",
|
|
6654
|
+
path: `${path}/stop`,
|
|
6655
|
+
idempotencyKey: entry.recovery?.stop.idempotencyKey ?? `nolo-stop-${entry.machineId}`,
|
|
6656
|
+
timeoutMs: remaining(),
|
|
6657
|
+
// Runs even when the HTTP response arrives after the observation deadline.
|
|
6658
|
+
onResult: entry.recovery ? async (response) => {
|
|
6659
|
+
if (response.status === 202) {
|
|
6660
|
+
entry.stopAccepted = true;
|
|
6661
|
+
entry.recovery.stop.accepted = true;
|
|
6662
|
+
const operation2 = asRecord(response.payload);
|
|
6663
|
+
if (this.#isStopOperation(operation2, entry)) {
|
|
6664
|
+
entry.recovery.stop.operationId = readString2(operation2?.id);
|
|
6665
|
+
}
|
|
6666
|
+
await this.#saveRecovery(entry.recovery);
|
|
6667
|
+
}
|
|
6668
|
+
} : void 0
|
|
6669
|
+
});
|
|
6670
|
+
if (accepted.status === 202) entry.stopAccepted = true;
|
|
6671
|
+
const operation = asRecord(accepted.payload);
|
|
6672
|
+
if (accepted.status !== 202 || !this.#isStopOperation(operation, entry)) {
|
|
6673
|
+
return result("unknown");
|
|
6674
|
+
}
|
|
6675
|
+
state = "pending";
|
|
6676
|
+
}
|
|
6677
|
+
if (attempt + 1 < this.#maxPollAttempts && remaining() > 0 && this.#pollIntervalMs > 0) {
|
|
6678
|
+
let timer;
|
|
6679
|
+
try {
|
|
6680
|
+
await Promise.race([
|
|
6681
|
+
this.#sleep(Math.min(this.#pollIntervalMs, remaining())),
|
|
6682
|
+
new Promise((resolve5) => {
|
|
6683
|
+
timer = setTimeout(resolve5, remaining());
|
|
6684
|
+
})
|
|
6685
|
+
]);
|
|
6686
|
+
} finally {
|
|
6687
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
6688
|
+
}
|
|
6689
|
+
}
|
|
6690
|
+
}
|
|
6691
|
+
return result(state);
|
|
6692
|
+
}
|
|
6314
6693
|
/**
|
|
6315
6694
|
* DELETE 只是「已受理」;必须轮询 delete operation 到 `succeeded` 才算清理完成。
|
|
6316
6695
|
* 未确认一律抛 `instabox_cleanup_pending`(`cleanupPending: true`),lease 保持可重试。
|
|
@@ -6318,6 +6697,12 @@ var InstaboxBackend = class {
|
|
|
6318
6697
|
*/
|
|
6319
6698
|
async release(lease, reason) {
|
|
6320
6699
|
const entry = this.#requireEntry(lease);
|
|
6700
|
+
try {
|
|
6701
|
+
this.#assertDeletionAllowed(entry.machineId);
|
|
6702
|
+
} catch (error) {
|
|
6703
|
+
if (entry.recovery) throw this.#withRecovery(error, entry.recovery);
|
|
6704
|
+
throw error;
|
|
6705
|
+
}
|
|
6321
6706
|
if (entry.releasedAt !== null) {
|
|
6322
6707
|
return entry.releaseOutcome ?? { ok: true };
|
|
6323
6708
|
}
|
|
@@ -6366,6 +6751,145 @@ var InstaboxBackend = class {
|
|
|
6366
6751
|
});
|
|
6367
6752
|
return this.#confirmRelease(entry, providerUsageMs);
|
|
6368
6753
|
}
|
|
6754
|
+
#assertDeletionAllowed(machineId, detail) {
|
|
6755
|
+
if (this.#deletionPolicy === "forbid") {
|
|
6756
|
+
throw new InstaboxBackendError("instabox_delete_forbidden", detail, true, machineId);
|
|
6757
|
+
}
|
|
6758
|
+
}
|
|
6759
|
+
#isStopOperation(operation, entry) {
|
|
6760
|
+
const id = readString2(operation?.id);
|
|
6761
|
+
const knownId = entry.recovery?.stop.operationId;
|
|
6762
|
+
return id !== null && operation?.machineId === entry.machineId && (!entry.recovery || operation.type === "stop") && ["queued", "running", "succeeded", "failed"].includes(String(operation.state)) && (knownId === void 0 || knownId === id);
|
|
6763
|
+
}
|
|
6764
|
+
#withRecovery(error, record) {
|
|
6765
|
+
const known = error instanceof InstaboxBackendError ? error : void 0;
|
|
6766
|
+
return new InstaboxBackendError(
|
|
6767
|
+
known?.code ?? "instabox_recovery_failed",
|
|
6768
|
+
void 0,
|
|
6769
|
+
true,
|
|
6770
|
+
record.machineId,
|
|
6771
|
+
known?.upstreamErrorCode,
|
|
6772
|
+
{
|
|
6773
|
+
recordId: record.recordId,
|
|
6774
|
+
machineId: record.machineId,
|
|
6775
|
+
createOperationId: record.createOperationId,
|
|
6776
|
+
stopOperationId: record.stop.operationId,
|
|
6777
|
+
machineState: record.machineId ? "known" : "unknown"
|
|
6778
|
+
}
|
|
6779
|
+
);
|
|
6780
|
+
}
|
|
6781
|
+
async #saveRecovery(record) {
|
|
6782
|
+
const previous = this.#recoveryWrites.get(record) ?? Promise.resolve();
|
|
6783
|
+
const task = previous.then(async () => {
|
|
6784
|
+
const revision = record.revision;
|
|
6785
|
+
const next = structuredClone({ ...record, revision: revision + 1 });
|
|
6786
|
+
try {
|
|
6787
|
+
await this.#recovery.store.save(next, revision);
|
|
6788
|
+
record.revision = next.revision;
|
|
6789
|
+
} catch {
|
|
6790
|
+
throw this.#withRecovery(new InstaboxBackendError("instabox_recovery_failed"), record);
|
|
6791
|
+
}
|
|
6792
|
+
});
|
|
6793
|
+
this.#recoveryWrites.set(record, task);
|
|
6794
|
+
await task;
|
|
6795
|
+
}
|
|
6796
|
+
/** Authority must come from authenticated host context, never from a request body. */
|
|
6797
|
+
async restoreForStop(recordId, authority) {
|
|
6798
|
+
if (typeof recordId !== "string" || !/^[a-zA-Z0-9_-]{1,128}$/.test(recordId)) {
|
|
6799
|
+
throw new InstaboxBackendError("instabox_recovery_failed");
|
|
6800
|
+
}
|
|
6801
|
+
try {
|
|
6802
|
+
return await this.#restoreForStop(recordId, authority);
|
|
6803
|
+
} catch (error) {
|
|
6804
|
+
if (error instanceof InstaboxBackendError && error.recovery) throw error;
|
|
6805
|
+
throw new InstaboxBackendError(
|
|
6806
|
+
"instabox_recovery_failed",
|
|
6807
|
+
void 0,
|
|
6808
|
+
true,
|
|
6809
|
+
void 0,
|
|
6810
|
+
void 0,
|
|
6811
|
+
{ recordId, machineState: "unknown" }
|
|
6812
|
+
);
|
|
6813
|
+
}
|
|
6814
|
+
}
|
|
6815
|
+
async #restoreForStop(recordId, authority) {
|
|
6816
|
+
const binding = this.#recovery;
|
|
6817
|
+
if (!binding || !/^[a-zA-Z0-9_-]{1,128}$/.test(recordId)) {
|
|
6818
|
+
throw new InstaboxBackendError("instabox_recovery_failed");
|
|
6819
|
+
}
|
|
6820
|
+
let record;
|
|
6821
|
+
try {
|
|
6822
|
+
record = await binding.store.load(recordId);
|
|
6823
|
+
} catch {
|
|
6824
|
+
throw new InstaboxBackendError("instabox_recovery_failed");
|
|
6825
|
+
}
|
|
6826
|
+
if (!record || record.version !== 1 || record.recordId !== recordId || !Number.isSafeInteger(record.revision) || record.revision < 1 || record.provider !== "instabox" || record.accountId !== binding.accountId || record.baseUrl !== this.#baseUrl || ![authority, binding.authority].every((a) => a.ticketId === record.ticketId && a.grantId === record.grantId && a.generation === record.generation && a.ownerUserId === record.ownerUserId) || !record.plan || !this.#creationPlan || ![
|
|
6827
|
+
"orgId",
|
|
6828
|
+
"name",
|
|
6829
|
+
"templateId",
|
|
6830
|
+
"vcpus",
|
|
6831
|
+
"memMiB",
|
|
6832
|
+
"maxRunMinutes",
|
|
6833
|
+
"snapshotId",
|
|
6834
|
+
"persistentDiskGiB",
|
|
6835
|
+
"rootDiskGiB"
|
|
6836
|
+
].every(
|
|
6837
|
+
(key) => record.plan[key] === this.#creationPlan[key]
|
|
6838
|
+
) || record.billingPolicy !== this.#billingPolicy || !Number.isSafeInteger(record.persistentDiskGiB) || record.persistentDiskGiB < 0 || record.create?.method !== "POST" || record.create.path !== "/machines" || record.create.idempotencyKey !== buildInstaboxCreateIdempotencyKey(record.ticketId) || !Number.isFinite(record.create.requestedAt) || !["submitted-unknown", "responded"].includes(record.create.state) || typeof record.stop?.intent !== "boolean" || typeof record.stop.accepted !== "boolean" || record.stop.accepted && !record.stop.intent || record.stop.intent && record.stop.idempotencyKey !== `nolo-stop-${record.machineId}`) {
|
|
6839
|
+
throw new InstaboxBackendError("instabox_recovery_failed");
|
|
6840
|
+
}
|
|
6841
|
+
const plan = this.#creationPlan;
|
|
6842
|
+
const expectedSpec = this.#freeOrgObservation?.allowedSpecs.filter(
|
|
6843
|
+
(spec2) => spec2.vcpus === plan.vcpus && spec2.memMiB === plan.memMiB
|
|
6844
|
+
);
|
|
6845
|
+
if (expectedSpec?.length !== 1 || expectedSpec[0].persistentDiskGiB !== record.persistentDiskGiB) {
|
|
6846
|
+
throw new InstaboxBackendError("instabox_recovery_failed");
|
|
6847
|
+
}
|
|
6848
|
+
const body = JSON.stringify({
|
|
6849
|
+
name: plan.name,
|
|
6850
|
+
templateId: plan.templateId,
|
|
6851
|
+
orgId: plan.orgId,
|
|
6852
|
+
vcpus: plan.vcpus,
|
|
6853
|
+
memMiB: plan.memMiB
|
|
6854
|
+
});
|
|
6855
|
+
if (record.create.body !== body) throw new InstaboxBackendError("instabox_recovery_failed");
|
|
6856
|
+
if (!readString2(record.machineId)) {
|
|
6857
|
+
throw this.#withRecovery(new InstaboxBackendError("instabox_recovery_unknown"), record);
|
|
6858
|
+
}
|
|
6859
|
+
const machineId = record.machineId;
|
|
6860
|
+
const response = await this.#call({ method: "GET", path: `/machines/${encodeURIComponent(machineId)}` });
|
|
6861
|
+
const machine = asRecord(response.payload);
|
|
6862
|
+
const spec = asRecord(machine?.spec);
|
|
6863
|
+
if (response.status !== 200 || machine?.id !== machineId || machine.orgId !== plan.orgId || machine.name !== plan.name || asRecord(machine.template)?.id !== plan.templateId || spec?.vcpus !== plan.vcpus || spec?.memMiB !== plan.memMiB || spec?.persistentDiskGiB !== record.persistentDiskGiB || typeof machine.free !== "boolean" || record.billingPolicy === "free-only" && (machine.free !== true || machine.maxRunMinutes !== plan.maxRunMinutes)) {
|
|
6864
|
+
throw this.#withRecovery(new InstaboxBackendError("instabox_recovery_failed"), record);
|
|
6865
|
+
}
|
|
6866
|
+
const leaseId = `${machineId}:${record.ticketId}`;
|
|
6867
|
+
if (this.#leases.has(leaseId)) throw this.#withRecovery(new InstaboxBackendError("instabox_lease_mismatch"), record);
|
|
6868
|
+
this.#leases.set(leaseId, {
|
|
6869
|
+
recovery: structuredClone(record),
|
|
6870
|
+
machineId,
|
|
6871
|
+
ticketId: record.ticketId,
|
|
6872
|
+
grantId: record.grantId,
|
|
6873
|
+
requestedAt: record.create.requestedAt,
|
|
6874
|
+
readyAt: this.#now(),
|
|
6875
|
+
createOperationId: record.createOperationId ?? "",
|
|
6876
|
+
usageBaselineRunningMs: null,
|
|
6877
|
+
releasedAt: null,
|
|
6878
|
+
releaseOutcome: null,
|
|
6879
|
+
stopState: "unknown",
|
|
6880
|
+
stopAccepted: record.stop.accepted
|
|
6881
|
+
});
|
|
6882
|
+
return {
|
|
6883
|
+
leaseId,
|
|
6884
|
+
backendId: INSTABOX_BACKEND_ID,
|
|
6885
|
+
ticketId: record.ticketId,
|
|
6886
|
+
grantId: record.grantId,
|
|
6887
|
+
createdAt: this.#now(),
|
|
6888
|
+
readableRoots: [],
|
|
6889
|
+
writableRoots: [],
|
|
6890
|
+
metadata: { machineId, recoveryRecordId: recordId, stopOnly: true }
|
|
6891
|
+
};
|
|
6892
|
+
}
|
|
6369
6893
|
#confirmRelease(entry, providerUsageMs) {
|
|
6370
6894
|
const outcome = providerUsageMs === void 0 ? { ok: true } : { ok: true, providerUsageMs };
|
|
6371
6895
|
entry.releasedAt = this.#now();
|
|
@@ -6452,6 +6976,25 @@ var InstaboxBackend = class {
|
|
|
6452
6976
|
return segments.join(" && ");
|
|
6453
6977
|
}
|
|
6454
6978
|
async #call(args) {
|
|
6979
|
+
if (args.timeoutMs !== void 0) {
|
|
6980
|
+
if (args.timeoutMs <= 0) return { status: 0, payload: null, transportError: "Timeout" };
|
|
6981
|
+
let timer;
|
|
6982
|
+
try {
|
|
6983
|
+
return await Promise.race([
|
|
6984
|
+
this.#call({ ...args, timeoutMs: void 0 }),
|
|
6985
|
+
new Promise((resolve5) => {
|
|
6986
|
+
timer = setTimeout(() => resolve5({ status: 0, payload: null, transportError: "Timeout" }), args.timeoutMs);
|
|
6987
|
+
})
|
|
6988
|
+
]);
|
|
6989
|
+
} finally {
|
|
6990
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
6991
|
+
}
|
|
6992
|
+
}
|
|
6993
|
+
if (args.onResult) {
|
|
6994
|
+
const response = await this.#call({ ...args, onResult: void 0 });
|
|
6995
|
+
await args.onResult(response);
|
|
6996
|
+
return response;
|
|
6997
|
+
}
|
|
6455
6998
|
const headers = {
|
|
6456
6999
|
"X-API-Key": this.#apiKey,
|
|
6457
7000
|
Accept: "application/json"
|
|
@@ -6462,8 +7005,11 @@ var InstaboxBackend = class {
|
|
|
6462
7005
|
const response = await this.#fetch(`${this.#baseUrl}${args.path}`, {
|
|
6463
7006
|
method: args.method,
|
|
6464
7007
|
headers,
|
|
7008
|
+
...args.signal ? { signal: args.signal } : {},
|
|
7009
|
+
...args.redirect ? { redirect: args.redirect } : {},
|
|
6465
7010
|
...args.body !== void 0 ? { body: JSON.stringify(args.body) } : {}
|
|
6466
7011
|
});
|
|
7012
|
+
if (args.redirect === "error" && response.redirected) return { status: 0, payload: null };
|
|
6467
7013
|
let payload = null;
|
|
6468
7014
|
if (typeof response?.json === "function") {
|
|
6469
7015
|
try {
|
|
@@ -7392,6 +7938,11 @@ function createCliStartAgentRunExecutor(deps = {}) {
|
|
|
7392
7938
|
allowCredentialConcurrency: effectiveAllowCredentialConcurrency
|
|
7393
7939
|
});
|
|
7394
7940
|
const dodCommands = Array.isArray(args.dodCommands) ? args.dodCommands.filter((c) => typeof c === "string" && c.trim().length > 0).map((c) => c.trim()) : typeof args.dod === "string" && args.dod.trim().length > 0 ? [args.dod.trim()] : Array.isArray(args.dod) ? args.dod.filter((c) => typeof c === "string" && c.trim().length > 0).map((c) => c.trim()) : void 0;
|
|
7941
|
+
const dispatchedBudget = resolveDispatchedSubtaskBudget({
|
|
7942
|
+
...typeof args.maxToolCalls === "number" ? { maxToolCalls: args.maxToolCalls } : {},
|
|
7943
|
+
...typeof args.maxWallClockMs === "number" ? { maxWallClockMs: args.maxWallClockMs } : {},
|
|
7944
|
+
env: deps.env
|
|
7945
|
+
});
|
|
7395
7946
|
const { runId, batchId: resolvedBatchId } = await spawnLocalBackgroundRun(
|
|
7396
7947
|
{
|
|
7397
7948
|
rawArgs,
|
|
@@ -7409,6 +7960,7 @@ function createCliStartAgentRunExecutor(deps = {}) {
|
|
|
7409
7960
|
...dodCommands && dodCommands.length > 0 ? { dodCommands } : {},
|
|
7410
7961
|
cwd: requestedCwd ?? deps.cwd ?? process.cwd(),
|
|
7411
7962
|
message,
|
|
7963
|
+
subtaskBudgetLimits: dispatchedBudget.limits,
|
|
7412
7964
|
...args.ephemeral === true ? { ephemeral: true } : {},
|
|
7413
7965
|
output: noopOutput
|
|
7414
7966
|
},
|
|
@@ -7469,7 +8021,11 @@ function createCliStartAgentRunExecutor(deps = {}) {
|
|
|
7469
8021
|
};
|
|
7470
8022
|
};
|
|
7471
8023
|
}
|
|
7472
|
-
|
|
8024
|
+
function controlMessageLabels(queuedCount) {
|
|
8025
|
+
const labels = agentRunCardLabels().controlMessage;
|
|
8026
|
+
return { ...labels, queued: queuedCount === void 0 ? labels.queued : labels.enqueued(queuedCount) };
|
|
8027
|
+
}
|
|
8028
|
+
async function spawnContinuationRun(reconciled, message, userInput, deps) {
|
|
7473
8029
|
if (!reconciled.ephemeral && !reconciled.dialogId) {
|
|
7474
8030
|
throw new Error(t("agentRunTool.noDialogToContinue"));
|
|
7475
8031
|
}
|
|
@@ -7504,19 +8060,13 @@ async function spawnContinuationRun(reconciled, userInput, deps) {
|
|
|
7504
8060
|
// 续跑继承原 run 的凭证组(同一 agent),供并发扇出守卫判定。
|
|
7505
8061
|
...reconciled.credentialGroup ? { credentialGroup: reconciled.credentialGroup } : {},
|
|
7506
8062
|
cwd: reconciled.cwd ?? deps.cwd ?? process.cwd(),
|
|
7507
|
-
message
|
|
8063
|
+
message,
|
|
7508
8064
|
...reconciled.ephemeral ? { ephemeral: true } : {},
|
|
7509
8065
|
continuedFrom,
|
|
7510
8066
|
output: noopOutput
|
|
7511
8067
|
},
|
|
7512
8068
|
{ ...deps, shellApprovalHost: deps.shellApprovalHostForAgent ? await deps.shellApprovalHostForAgent(agentKey) : deps.shellApprovalHost }
|
|
7513
8069
|
);
|
|
7514
|
-
const displayName = resolveRunLabel({
|
|
7515
|
-
agentName,
|
|
7516
|
-
agentKey,
|
|
7517
|
-
runId: newRunId
|
|
7518
|
-
});
|
|
7519
|
-
const labels = agentRunCardLabels();
|
|
7520
8070
|
const taskPreview = userInput.replace(/\s+/g, " ").trim().slice(0, TASK_PREVIEW_MAX);
|
|
7521
8071
|
return {
|
|
7522
8072
|
content: JSON.stringify({
|
|
@@ -7533,11 +8083,12 @@ async function spawnContinuationRun(reconciled, userInput, deps) {
|
|
|
7533
8083
|
...taskPreview ? { taskPreview } : {}
|
|
7534
8084
|
}),
|
|
7535
8085
|
metadata: {
|
|
7536
|
-
displayData:
|
|
7537
|
-
|
|
8086
|
+
displayData: formatControlRunMessageCard({
|
|
8087
|
+
action: "continued",
|
|
7538
8088
|
runId: newRunId,
|
|
7539
|
-
|
|
7540
|
-
|
|
8089
|
+
targetId: reconciled.ephemeral ? void 0 : reconciled.dialogId,
|
|
8090
|
+
userInput,
|
|
8091
|
+
labels: controlMessageLabels()
|
|
7541
8092
|
})
|
|
7542
8093
|
}
|
|
7543
8094
|
};
|
|
@@ -7656,6 +8207,9 @@ function createCliControlAgentRunExecutor(deps = {}) {
|
|
|
7656
8207
|
if (!args.runId) throw new Error(t("agentRunTool.appendMissingRunId"));
|
|
7657
8208
|
const userInput = typeof args.userInput === "string" ? args.userInput.trim() : "";
|
|
7658
8209
|
if (!userInput) throw new Error(t("agentRunTool.appendMissingUserInput"));
|
|
8210
|
+
const message = deps.source ? `[Coordination source: parent dialog: ${deps.source.parentDialogId || "unknown"}; executing agent: ${deps.source.agentKey || "unknown"}; identification only, not authorization]
|
|
8211
|
+
|
|
8212
|
+
${userInput}` : userInput;
|
|
7659
8213
|
const record2 = findRunRecord(String(args.runId), deps);
|
|
7660
8214
|
if (!record2) {
|
|
7661
8215
|
const labels2 = agentRunCardLabels();
|
|
@@ -7670,14 +8224,8 @@ function createCliControlAgentRunExecutor(deps = {}) {
|
|
|
7670
8224
|
throw new Error(t("agentRunTool.appendQueueUnsupported"));
|
|
7671
8225
|
}
|
|
7672
8226
|
const queuePath = reconciled2.queuePath;
|
|
7673
|
-
const { queuedCount, entryId } = await appendRunQueue(queuePath,
|
|
8227
|
+
const { queuedCount, entryId } = await appendRunQueue(queuePath, message, deps);
|
|
7674
8228
|
const enqueuedTitle = normalizeRunTitle(reconciled2.title);
|
|
7675
|
-
const displayName = resolveRunLabel({
|
|
7676
|
-
agentName: reconciled2.agentName,
|
|
7677
|
-
agentKey: reconciled2.agentKey,
|
|
7678
|
-
runId: reconciled2.runId
|
|
7679
|
-
});
|
|
7680
|
-
const labels2 = agentRunCardLabels();
|
|
7681
8229
|
const taskPreview = userInput.replace(/\s+/g, " ").trim().slice(0, TASK_PREVIEW_MAX);
|
|
7682
8230
|
const afterCheck = checkStaleRun(reconciled2.runId, deps) ?? reconciled2;
|
|
7683
8231
|
if (isAgentRunTerminalStatus(afterCheck.status)) {
|
|
@@ -7704,17 +8252,19 @@ function createCliControlAgentRunExecutor(deps = {}) {
|
|
|
7704
8252
|
...taskPreview ? { taskPreview } : {}
|
|
7705
8253
|
}),
|
|
7706
8254
|
metadata: {
|
|
7707
|
-
displayData:
|
|
7708
|
-
|
|
8255
|
+
displayData: formatControlRunMessageCard({
|
|
8256
|
+
action: "consumed",
|
|
7709
8257
|
runId: reconciled2.runId,
|
|
7710
|
-
|
|
7711
|
-
|
|
8258
|
+
targetId: reconciled2.ephemeral ? void 0 : afterCheck.dialogId ?? reconciled2.dialogId,
|
|
8259
|
+
userInput,
|
|
8260
|
+
labels: controlMessageLabels()
|
|
7712
8261
|
})
|
|
7713
8262
|
}
|
|
7714
8263
|
};
|
|
7715
8264
|
}
|
|
7716
|
-
const mergedMessage = remainingEntries.map((
|
|
7717
|
-
|
|
8265
|
+
const mergedMessage = remainingEntries.length === 1 ? remainingEntries[0].text : remainingEntries.map((entry, index) => `--- queued message ${index + 1} of ${remainingEntries.length} (${entry.text.length} characters) ---
|
|
8266
|
+
${entry.text}`).join("\n\n");
|
|
8267
|
+
return await spawnContinuationRun(afterCheck, mergedMessage, userInput, deps);
|
|
7718
8268
|
}
|
|
7719
8269
|
return {
|
|
7720
8270
|
content: JSON.stringify({
|
|
@@ -7729,16 +8279,17 @@ function createCliControlAgentRunExecutor(deps = {}) {
|
|
|
7729
8279
|
...taskPreview ? { taskPreview } : {}
|
|
7730
8280
|
}),
|
|
7731
8281
|
metadata: {
|
|
7732
|
-
displayData:
|
|
7733
|
-
|
|
8282
|
+
displayData: formatControlRunMessageCard({
|
|
8283
|
+
action: "queued",
|
|
7734
8284
|
runId: reconciled2.runId,
|
|
7735
|
-
|
|
7736
|
-
|
|
8285
|
+
targetId: reconciled2.ephemeral ? void 0 : reconciled2.dialogId,
|
|
8286
|
+
userInput,
|
|
8287
|
+
labels: controlMessageLabels(queuedCount)
|
|
7737
8288
|
})
|
|
7738
8289
|
}
|
|
7739
8290
|
};
|
|
7740
8291
|
}
|
|
7741
|
-
return await spawnContinuationRun(reconciled2, userInput, deps);
|
|
8292
|
+
return await spawnContinuationRun(reconciled2, message, userInput, deps);
|
|
7742
8293
|
}
|
|
7743
8294
|
if (action !== "status" && action !== "stop" && action !== "wait") {
|
|
7744
8295
|
throw new Error(t("agentRunTool.unknownAction", String(action)));
|
|
@@ -8421,6 +8972,7 @@ function buildLocalToolExecutors(args) {
|
|
|
8421
8972
|
currentAgentKey: args.agentKey
|
|
8422
8973
|
}),
|
|
8423
8974
|
controlAgentRun: createCliControlAgentRunExecutor({
|
|
8975
|
+
source: { parentDialogId: args.sourceParentDialogId, agentKey: args.agentKey },
|
|
8424
8976
|
shellApprovalHostForAgent: args.shellApprovalHostForAgent,
|
|
8425
8977
|
cwd: args.workspaceRoot,
|
|
8426
8978
|
cliEntrypoint: args.cliEntrypoint,
|
|
@@ -10018,7 +10570,7 @@ async function createLocalDockerWorkload(args) {
|
|
|
10018
10570
|
}
|
|
10019
10571
|
const createLifecycle = args.createLifecycle ?? (async () => {
|
|
10020
10572
|
const [{ DockerWorkloadLifecycle, createDockerBindingAuthorizer }, accounts] = await Promise.all([
|
|
10021
|
-
import("./workloadLifecycle-
|
|
10573
|
+
import("./workloadLifecycle-4C42SVBD.js"),
|
|
10022
10574
|
import("./accountResolver-4LKIHEKL.js")
|
|
10023
10575
|
]);
|
|
10024
10576
|
const resolveAccount = args.resolveAccount ?? accounts.createDockerAccountResolver({
|
|
@@ -12467,7 +13019,6 @@ async function recordLocalAvailabilityForAgent(args) {
|
|
|
12467
13019
|
return typeof entry?.nextAvailableAt === "number" ? entry.nextAvailableAt : action.nextAvailableAt;
|
|
12468
13020
|
}
|
|
12469
13021
|
const record = current;
|
|
12470
|
-
if (action.kind === "clear" && !("nextAvailableAt" in record)) return void 0;
|
|
12471
13022
|
const next = { ...record };
|
|
12472
13023
|
let effectiveNextAvailableAt;
|
|
12473
13024
|
if (action.kind === "mark") {
|
|
@@ -12478,7 +13029,30 @@ async function recordLocalAvailabilityForAgent(args) {
|
|
|
12478
13029
|
next.nextAvailableAt = merged;
|
|
12479
13030
|
effectiveNextAvailableAt = merged;
|
|
12480
13031
|
} else {
|
|
13032
|
+
const hadCooldown = "nextAvailableAt" in record;
|
|
12481
13033
|
delete next.nextAvailableAt;
|
|
13034
|
+
const observedAt = now();
|
|
13035
|
+
const snapshot = extractQuotaSnapshot(
|
|
13036
|
+
typeof agentConfig?.provider === "string" ? agentConfig.provider : void 0,
|
|
13037
|
+
status,
|
|
13038
|
+
void 0,
|
|
13039
|
+
args.body,
|
|
13040
|
+
observedAt
|
|
13041
|
+
);
|
|
13042
|
+
const previous = record.quota && typeof record.quota === "object" ? record.quota : void 0;
|
|
13043
|
+
const hasFreshSnapshot = Boolean(snapshot) && (!previous?.observedAt || previous.observedAt <= observedAt);
|
|
13044
|
+
if (!hadCooldown && !hasFreshSnapshot) return void 0;
|
|
13045
|
+
if (hasFreshSnapshot) {
|
|
13046
|
+
const windows = new Map(
|
|
13047
|
+
(Array.isArray(previous?.windows) ? previous.windows : []).map((window) => [window.scope, window])
|
|
13048
|
+
);
|
|
13049
|
+
for (const window of snapshot?.windows ?? []) windows.set(window.scope, window);
|
|
13050
|
+
next.quota = {
|
|
13051
|
+
...previous,
|
|
13052
|
+
windows: [...windows.values()],
|
|
13053
|
+
observedAt
|
|
13054
|
+
};
|
|
13055
|
+
}
|
|
12482
13056
|
}
|
|
12483
13057
|
await store.write(key, next).catch(() => void 0);
|
|
12484
13058
|
if (action.kind !== "mark") return void 0;
|
|
@@ -12672,7 +13246,7 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
12672
13246
|
emitRunIsolationNotice(fact, { runId });
|
|
12673
13247
|
try {
|
|
12674
13248
|
const { writeFileSync: writeFileSync4, mkdirSync: mkdirSync4 } = await import("node:fs");
|
|
12675
|
-
const { resolveRunsDir: resolveRunsDir2 } = await import("./agentRunControl-
|
|
13249
|
+
const { resolveRunsDir: resolveRunsDir2 } = await import("./agentRunControl-TAMHJQSR.js");
|
|
12676
13250
|
recordLocalRunExecutionIsolation({
|
|
12677
13251
|
runId,
|
|
12678
13252
|
runsDir: resolveRunsDir2(deps.env),
|
|
@@ -12697,7 +13271,7 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
12697
13271
|
dockerWorkloadReleased = true;
|
|
12698
13272
|
dockerWorkloadLoad = null;
|
|
12699
13273
|
if (loaded) {
|
|
12700
|
-
const { resolveRunsDir: resolveRunsDir2 } = await import("./agentRunControl-
|
|
13274
|
+
const { resolveRunsDir: resolveRunsDir2 } = await import("./agentRunControl-TAMHJQSR.js");
|
|
12701
13275
|
const exportRunDiff = deps.exportDockerRunDiffArtifact ?? exportDockerRunDiffArtifact;
|
|
12702
13276
|
const warn = (message) => process.stderr.write(`[nolo] ${message}
|
|
12703
13277
|
`);
|
|
@@ -12780,6 +13354,7 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
12780
13354
|
let runtimeToolExecutionLimits = {};
|
|
12781
13355
|
const buildCurrentToolExecutors = (agentKey) => buildLocalToolExecutors({
|
|
12782
13356
|
workspaceRoot,
|
|
13357
|
+
sourceParentDialogId: deps.parentDialogId,
|
|
12783
13358
|
env: deps.env,
|
|
12784
13359
|
fetchImpl,
|
|
12785
13360
|
...deps.chromeConnectorClient ? { chromeConnectorClient: deps.chromeConnectorClient } : {},
|
|
@@ -12844,6 +13419,8 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
12844
13419
|
);
|
|
12845
13420
|
}
|
|
12846
13421
|
});
|
|
13422
|
+
let nextSettingsRemoteAttempt = 0;
|
|
13423
|
+
let settingsDiagnosticEmitted = false;
|
|
12847
13424
|
const adapterBase = {
|
|
12848
13425
|
host: "cli",
|
|
12849
13426
|
capabilities: [
|
|
@@ -12859,10 +13436,23 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
12859
13436
|
const sharedStore = await getOrCreateSharedStore(deps);
|
|
12860
13437
|
if (userId) {
|
|
12861
13438
|
try {
|
|
12862
|
-
const
|
|
12863
|
-
|
|
12864
|
-
|
|
12865
|
-
|
|
13439
|
+
const settingsKey = createUserKey.settings(userId);
|
|
13440
|
+
let settingsRecord = await sharedStore.read(settingsKey, { remote: false });
|
|
13441
|
+
if (!settingsRecord && Date.now() >= nextSettingsRemoteAttempt) {
|
|
13442
|
+
nextSettingsRemoteAttempt = Date.now() + 3e4;
|
|
13443
|
+
let unavailable = false;
|
|
13444
|
+
settingsRecord = await sharedStore.read(settingsKey, {
|
|
13445
|
+
onRemoteUnavailable: () => {
|
|
13446
|
+
unavailable = true;
|
|
13447
|
+
}
|
|
13448
|
+
});
|
|
13449
|
+
if (!settingsRecord && !settingsDiagnosticEmitted) {
|
|
13450
|
+
process.stderr.write(`[nolo] Account skill settings ${unavailable ? "unavailable" : "not found"}; preferences unknown, retrying on a later load.
|
|
13451
|
+
`);
|
|
13452
|
+
settingsDiagnosticEmitted = true;
|
|
13453
|
+
}
|
|
13454
|
+
}
|
|
13455
|
+
if (settingsRecord) settingsDiagnosticEmitted = false;
|
|
12866
13456
|
if (settingsRecord && typeof settingsRecord === "object") {
|
|
12867
13457
|
skillPreferences = {
|
|
12868
13458
|
...Object.prototype.hasOwnProperty.call(settingsRecord, "enabledSkills") ? { enabledSkills: settingsRecord.enabledSkills } : {},
|
|
@@ -12871,6 +13461,10 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
12871
13461
|
}
|
|
12872
13462
|
systemBuiltinSkills = settingsRecord && typeof settingsRecord === "object" ? settingsRecord.systemBuiltinSkills ?? null : null;
|
|
12873
13463
|
} catch {
|
|
13464
|
+
if (!settingsDiagnosticEmitted) {
|
|
13465
|
+
process.stderr.write("[nolo] Account skill settings unavailable; preferences unknown, retrying on a later load.\n");
|
|
13466
|
+
settingsDiagnosticEmitted = true;
|
|
13467
|
+
}
|
|
12874
13468
|
}
|
|
12875
13469
|
}
|
|
12876
13470
|
const enabledSkills = resolveUserEnabledSkills(skillPreferences).sort();
|
|
@@ -13037,8 +13631,7 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
13037
13631
|
loopbackRequest
|
|
13038
13632
|
})
|
|
13039
13633
|
}),
|
|
13040
|
-
resolveProviderBase: async (agentConfig) => {
|
|
13041
|
-
const nowMs = now();
|
|
13634
|
+
resolveProviderBase: async (agentConfig, options) => {
|
|
13042
13635
|
const serverUrl = asOptionalTrimmedString(deps.env.NOLO_SERVER) ?? "https://us.nolo.chat";
|
|
13043
13636
|
const authToken = asOptionalTrimmedString(deps.env.AUTH_TOKEN);
|
|
13044
13637
|
let ownerOriginExecution;
|
|
@@ -13134,18 +13727,6 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
13134
13727
|
let recordLocalAvailability = async () => ownerRouteLeakGuard("availability write");
|
|
13135
13728
|
let apiKeyRefResolver = () => ownerRouteLeakGuard("apiKeyRefResolver read");
|
|
13136
13729
|
if (!ownerOriginExecution) {
|
|
13137
|
-
const credentialKeyForGate = resolveCredentialKeyWithFallback(
|
|
13138
|
-
agentConfig
|
|
13139
|
-
);
|
|
13140
|
-
const gateEntry = credentialKeyForGate ? await readEffectiveCredentialEntry(credentialKeyForGate, deps.env, nowMs).catch(
|
|
13141
|
-
() => void 0
|
|
13142
|
-
) : void 0;
|
|
13143
|
-
const credentialCooldownAt = gateEntry?.nextAvailableAt;
|
|
13144
|
-
const agentLevelNextAvailableAt = agentConfig.nextAvailableAt;
|
|
13145
|
-
const effectiveNextAvailableAt = typeof credentialCooldownAt === "number" ? mergeAvailabilityDeadline(
|
|
13146
|
-
agentLevelNextAvailableAt,
|
|
13147
|
-
credentialCooldownAt
|
|
13148
|
-
) : agentLevelNextAvailableAt;
|
|
13149
13730
|
recordLocalAvailability = (status, body) => recordLocalAvailabilityForAgent({
|
|
13150
13731
|
deps,
|
|
13151
13732
|
agentConfig,
|
|
@@ -13153,24 +13734,6 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
13153
13734
|
body,
|
|
13154
13735
|
now
|
|
13155
13736
|
}).then(() => void 0);
|
|
13156
|
-
const gateDecision = resolveCooldownGate(
|
|
13157
|
-
{
|
|
13158
|
-
nextAvailableAt: effectiveNextAvailableAt,
|
|
13159
|
-
lastProbeAt: gateEntry?.lastProbeAt
|
|
13160
|
-
},
|
|
13161
|
-
nowMs
|
|
13162
|
-
);
|
|
13163
|
-
if (gateDecision === "blocked") {
|
|
13164
|
-
throw new Error(
|
|
13165
|
-
`agent temporarily unavailable until ${new Date(Number(effectiveNextAvailableAt)).toISOString()}`
|
|
13166
|
-
);
|
|
13167
|
-
}
|
|
13168
|
-
const activeKeyForGate = gateEntry?.matchedKey || credentialKeyForGate;
|
|
13169
|
-
if (gateDecision === "probe" && activeKeyForGate) {
|
|
13170
|
-
await recordCredentialProbe(activeKeyForGate, deps.env, nowMs).catch(
|
|
13171
|
-
() => void 0
|
|
13172
|
-
);
|
|
13173
|
-
}
|
|
13174
13737
|
const legacyCredentialMigration = {
|
|
13175
13738
|
enableLegacyMigration: true
|
|
13176
13739
|
};
|
|
@@ -13200,14 +13763,18 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
13200
13763
|
return null;
|
|
13201
13764
|
}
|
|
13202
13765
|
} : void 0;
|
|
13766
|
+
const resolvedAgentConfig = resolveProviderResolveOverrides(agentConfig, options?.textOnly ? { ...options, toolNames: [] } : options);
|
|
13203
13767
|
return resolveLocalProvider({
|
|
13204
|
-
agentConfig,
|
|
13768
|
+
agentConfig: resolvedAgentConfig,
|
|
13205
13769
|
deps,
|
|
13206
13770
|
fetchImpl,
|
|
13207
13771
|
loopbackRequest,
|
|
13208
13772
|
now,
|
|
13209
13773
|
workspaceRoot,
|
|
13210
|
-
|
|
13774
|
+
...options?.textOnly ? { textOnly: true } : {},
|
|
13775
|
+
// 请求空工具面时连 host 追加项(readPastedText)也一并去掉,
|
|
13776
|
+
// 否则 `toolNames: []` 的契约会被 additionalToolNames 刺破。
|
|
13777
|
+
additionalToolNames: options?.textOnly || options?.toolNames !== void 0 ? [] : additionalToolNames,
|
|
13211
13778
|
activeAgentToolNames,
|
|
13212
13779
|
localToolExecutors,
|
|
13213
13780
|
buildProviderOpenAiTools,
|
|
@@ -13434,10 +14001,12 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
13434
14001
|
get compactionSummaryFallback() {
|
|
13435
14002
|
return cliAutoCompactionSummaryFallback;
|
|
13436
14003
|
},
|
|
13437
|
-
resolveProvider: async (agentConfig) => {
|
|
14004
|
+
resolveProvider: async (agentConfig, options) => {
|
|
13438
14005
|
const provider = await adapterBase.resolveProviderBase(
|
|
13439
|
-
agentConfig
|
|
14006
|
+
agentConfig,
|
|
14007
|
+
options
|
|
13440
14008
|
);
|
|
14009
|
+
if (options?.textOnly) return { ...provider, textOnly: true };
|
|
13441
14010
|
return shouldUsePlatformChatProvider(deps.env, agentConfig) ? withProviderStreamRetry(provider, {
|
|
13442
14011
|
...deps,
|
|
13443
14012
|
retryOnly: isBusyProviderStreamError
|