nexus-agents 3.8.0 → 3.8.2
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/dist/{child-mcp-config-R4GQMDAV.js → child-mcp-config-6NPPPUVY.js} +2 -2
- package/dist/{chunk-SQ35C5SD.js → chunk-222AX67B.js} +4 -4
- package/dist/{chunk-GJDNMK3G.js → chunk-24KV7AHU.js} +7 -7
- package/dist/{chunk-MB2T54VO.js → chunk-2CTS47RO.js} +2 -2
- package/dist/{chunk-SJGNFNFT.js → chunk-2IFBPQX2.js} +5 -5
- package/dist/{chunk-A5P7Y4SB.js → chunk-2VYSPAPK.js} +3 -3
- package/dist/{chunk-P3XQMXIW.js → chunk-7LEFPG22.js} +35 -35
- package/dist/{chunk-D55LWKBW.js → chunk-A4DFWNLB.js} +8 -8
- package/dist/{chunk-OIBSPO6Q.js → chunk-A7NXSL62.js} +3 -3
- package/dist/{chunk-2XFBHREJ.js → chunk-ATOORYKU.js} +2 -2
- package/dist/{chunk-C62JS6A7.js → chunk-BIG3SAUY.js} +2 -2
- package/dist/{chunk-JIZ7B6FX.js → chunk-CYGJGP52.js} +5 -5
- package/dist/{chunk-6Y4QIIQD.js → chunk-DVVYK7AU.js} +2 -2
- package/dist/{chunk-H5G4N5UL.js → chunk-E25DVSOH.js} +2 -2
- package/dist/{chunk-IJXJGQUY.js → chunk-FG3BJ3EG.js} +4 -4
- package/dist/{chunk-GX3QJX7X.js → chunk-FH5GVIUB.js} +2 -2
- package/dist/{chunk-PPZTSOSH.js → chunk-FJNCXY4H.js} +8 -8
- package/dist/{chunk-NTBGFI5Q.js → chunk-FN4IJNEL.js} +3 -3
- package/dist/{chunk-5WGOPKHZ.js → chunk-K4PIBH4M.js} +2 -2
- package/dist/{chunk-QWI4VF5L.js → chunk-LIYYP74L.js} +2 -2
- package/dist/{chunk-P4QFJ7OX.js → chunk-LLO24WNM.js} +2 -2
- package/dist/{chunk-C5O7Z4P7.js → chunk-NDIEJ2IW.js} +2 -2
- package/dist/{chunk-RYJ2VU7E.js → chunk-NEEDICVD.js} +2 -2
- package/dist/{chunk-DHWEXVCJ.js → chunk-OVDMUJJJ.js} +3 -3
- package/dist/{chunk-RYOQ3WJR.js → chunk-PRMJRGTB.js} +2 -2
- package/dist/{chunk-6G4FMCXS.js → chunk-Q4N2AMUH.js} +262 -230
- package/dist/chunk-Q4N2AMUH.js.map +1 -0
- package/dist/{chunk-7ILVQDUT.js → chunk-RH2XESKI.js} +2 -2
- package/dist/{chunk-Q4L2DXA4.js → chunk-SDKH4DZS.js} +5 -5
- package/dist/{chunk-5LFB77LA.js → chunk-SIAT5KIP.js} +2 -2
- package/dist/{chunk-YSE3VQ4A.js → chunk-TSCF7SCI.js} +3 -3
- package/dist/{chunk-YUPUHMWP.js → chunk-WN4GPQEW.js} +4 -4
- package/dist/{chunk-PQCKQKKP.js → chunk-XF5NBPHS.js} +5 -5
- package/dist/{chunk-5CXAYPSU.js → chunk-YCJVIYXU.js} +2 -2
- package/dist/{chunk-R3ZNOB3V.js → chunk-YIMAWNZF.js} +2 -2
- package/dist/{cli-circuit-breaker-YKY7NCQ5.js → cli-circuit-breaker-GGDXSODU.js} +3 -3
- package/dist/cli.js +41 -41
- package/dist/{composite-router-63QDM6CQ.js → composite-router-3JTQWELQ.js} +2 -2
- package/dist/{consensus-vote-C7QTJJH7.js → consensus-vote-VIVMYSH7.js} +16 -16
- package/dist/{context-retriever-DIKQ7QZA.js → context-retriever-CD4M2XZI.js} +8 -8
- package/dist/{doctor-deep-JVUEAUAG.js → doctor-deep-DGIEA3BS.js} +3 -3
- package/dist/{doctor-live-CT2SKNLI.js → doctor-live-UAXCKP2P.js} +9 -9
- package/dist/{expert-bridge-G5WXRNUH.js → expert-bridge-NJ7ROLKV.js} +4 -4
- package/dist/{factory-LYRONJ3P.js → factory-HXTWV5M2.js} +9 -9
- package/dist/{factory-72QUNWLV.js → factory-YQTOTSAG.js} +5 -5
- package/dist/{improvement-review-CJMYGUDM.js → improvement-review-BXMMAIF7.js} +5 -5
- package/dist/index.js +30 -30
- package/dist/{init-opencode-UATS6Q6W.js → init-opencode-5JABJDNL.js} +6 -6
- package/dist/{issue-triage-CZWWJSOT.js → issue-triage-EV64NQRS.js} +6 -6
- package/dist/{pr-reviewer-helpers-OLEK46AR.js → pr-reviewer-helpers-MDLLZ2XR.js} +4 -4
- package/dist/{registry-command-FKRZFXYQ.js → registry-command-LP7HOKWD.js} +2 -2
- package/dist/{repo-security-plan-BULZVX3A.js → repo-security-plan-CJNJQNIM.js} +3 -3
- package/dist/{research-helpers-synthesize-LTMSKVUB.js → research-helpers-synthesize-J5ZVG6PP.js} +4 -4
- package/dist/{routing-memory-H7DT3HVY.js → routing-memory-UPCTNDFG.js} +2 -2
- package/dist/{session-memory-UTPN4MCS.js → session-memory-K67JAZTU.js} +3 -3
- package/dist/{setup-command-TGGSIV6F.js → setup-command-UR4CR5UA.js} +14 -14
- package/dist/{setup-config-WIXJT5YV.js → setup-config-UEQMYXQ5.js} +3 -3
- package/dist/{setup-custom-api-36BFRFWO.js → setup-custom-api-SHMT2T3M.js} +4 -4
- package/dist/{tool-memory-YQTO4WUG.js → tool-memory-J2RP3FTT.js} +5 -5
- package/dist/{unified-registry-N2BQJSLK.js → unified-registry-2JCOLE4F.js} +10 -10
- package/dist/{weather-report-AOX6RULO.js → weather-report-XHGOK6E7.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-6G4FMCXS.js.map +0 -1
- /package/dist/{child-mcp-config-R4GQMDAV.js.map → child-mcp-config-6NPPPUVY.js.map} +0 -0
- /package/dist/{chunk-SQ35C5SD.js.map → chunk-222AX67B.js.map} +0 -0
- /package/dist/{chunk-GJDNMK3G.js.map → chunk-24KV7AHU.js.map} +0 -0
- /package/dist/{chunk-MB2T54VO.js.map → chunk-2CTS47RO.js.map} +0 -0
- /package/dist/{chunk-SJGNFNFT.js.map → chunk-2IFBPQX2.js.map} +0 -0
- /package/dist/{chunk-A5P7Y4SB.js.map → chunk-2VYSPAPK.js.map} +0 -0
- /package/dist/{chunk-P3XQMXIW.js.map → chunk-7LEFPG22.js.map} +0 -0
- /package/dist/{chunk-D55LWKBW.js.map → chunk-A4DFWNLB.js.map} +0 -0
- /package/dist/{chunk-OIBSPO6Q.js.map → chunk-A7NXSL62.js.map} +0 -0
- /package/dist/{chunk-2XFBHREJ.js.map → chunk-ATOORYKU.js.map} +0 -0
- /package/dist/{chunk-C62JS6A7.js.map → chunk-BIG3SAUY.js.map} +0 -0
- /package/dist/{chunk-JIZ7B6FX.js.map → chunk-CYGJGP52.js.map} +0 -0
- /package/dist/{chunk-6Y4QIIQD.js.map → chunk-DVVYK7AU.js.map} +0 -0
- /package/dist/{chunk-H5G4N5UL.js.map → chunk-E25DVSOH.js.map} +0 -0
- /package/dist/{chunk-IJXJGQUY.js.map → chunk-FG3BJ3EG.js.map} +0 -0
- /package/dist/{chunk-GX3QJX7X.js.map → chunk-FH5GVIUB.js.map} +0 -0
- /package/dist/{chunk-PPZTSOSH.js.map → chunk-FJNCXY4H.js.map} +0 -0
- /package/dist/{chunk-NTBGFI5Q.js.map → chunk-FN4IJNEL.js.map} +0 -0
- /package/dist/{chunk-5WGOPKHZ.js.map → chunk-K4PIBH4M.js.map} +0 -0
- /package/dist/{chunk-QWI4VF5L.js.map → chunk-LIYYP74L.js.map} +0 -0
- /package/dist/{chunk-P4QFJ7OX.js.map → chunk-LLO24WNM.js.map} +0 -0
- /package/dist/{chunk-C5O7Z4P7.js.map → chunk-NDIEJ2IW.js.map} +0 -0
- /package/dist/{chunk-RYJ2VU7E.js.map → chunk-NEEDICVD.js.map} +0 -0
- /package/dist/{chunk-DHWEXVCJ.js.map → chunk-OVDMUJJJ.js.map} +0 -0
- /package/dist/{chunk-RYOQ3WJR.js.map → chunk-PRMJRGTB.js.map} +0 -0
- /package/dist/{chunk-7ILVQDUT.js.map → chunk-RH2XESKI.js.map} +0 -0
- /package/dist/{chunk-Q4L2DXA4.js.map → chunk-SDKH4DZS.js.map} +0 -0
- /package/dist/{chunk-5LFB77LA.js.map → chunk-SIAT5KIP.js.map} +0 -0
- /package/dist/{chunk-YSE3VQ4A.js.map → chunk-TSCF7SCI.js.map} +0 -0
- /package/dist/{chunk-YUPUHMWP.js.map → chunk-WN4GPQEW.js.map} +0 -0
- /package/dist/{chunk-PQCKQKKP.js.map → chunk-XF5NBPHS.js.map} +0 -0
- /package/dist/{chunk-5CXAYPSU.js.map → chunk-YCJVIYXU.js.map} +0 -0
- /package/dist/{chunk-R3ZNOB3V.js.map → chunk-YIMAWNZF.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-YKY7NCQ5.js.map → cli-circuit-breaker-GGDXSODU.js.map} +0 -0
- /package/dist/{composite-router-63QDM6CQ.js.map → composite-router-3JTQWELQ.js.map} +0 -0
- /package/dist/{consensus-vote-C7QTJJH7.js.map → consensus-vote-VIVMYSH7.js.map} +0 -0
- /package/dist/{context-retriever-DIKQ7QZA.js.map → context-retriever-CD4M2XZI.js.map} +0 -0
- /package/dist/{doctor-deep-JVUEAUAG.js.map → doctor-deep-DGIEA3BS.js.map} +0 -0
- /package/dist/{doctor-live-CT2SKNLI.js.map → doctor-live-UAXCKP2P.js.map} +0 -0
- /package/dist/{expert-bridge-G5WXRNUH.js.map → expert-bridge-NJ7ROLKV.js.map} +0 -0
- /package/dist/{factory-72QUNWLV.js.map → factory-HXTWV5M2.js.map} +0 -0
- /package/dist/{factory-LYRONJ3P.js.map → factory-YQTOTSAG.js.map} +0 -0
- /package/dist/{improvement-review-CJMYGUDM.js.map → improvement-review-BXMMAIF7.js.map} +0 -0
- /package/dist/{init-opencode-UATS6Q6W.js.map → init-opencode-5JABJDNL.js.map} +0 -0
- /package/dist/{issue-triage-CZWWJSOT.js.map → issue-triage-EV64NQRS.js.map} +0 -0
- /package/dist/{pr-reviewer-helpers-OLEK46AR.js.map → pr-reviewer-helpers-MDLLZ2XR.js.map} +0 -0
- /package/dist/{registry-command-FKRZFXYQ.js.map → registry-command-LP7HOKWD.js.map} +0 -0
- /package/dist/{repo-security-plan-BULZVX3A.js.map → repo-security-plan-CJNJQNIM.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-LTMSKVUB.js.map → research-helpers-synthesize-J5ZVG6PP.js.map} +0 -0
- /package/dist/{routing-memory-H7DT3HVY.js.map → routing-memory-UPCTNDFG.js.map} +0 -0
- /package/dist/{session-memory-UTPN4MCS.js.map → session-memory-K67JAZTU.js.map} +0 -0
- /package/dist/{setup-command-TGGSIV6F.js.map → setup-command-UR4CR5UA.js.map} +0 -0
- /package/dist/{setup-config-WIXJT5YV.js.map → setup-config-UEQMYXQ5.js.map} +0 -0
- /package/dist/{setup-custom-api-36BFRFWO.js.map → setup-custom-api-SHMT2T3M.js.map} +0 -0
- /package/dist/{tool-memory-YQTO4WUG.js.map → tool-memory-J2RP3FTT.js.map} +0 -0
- /package/dist/{unified-registry-N2BQJSLK.js.map → unified-registry-2JCOLE4F.js.map} +0 -0
- /package/dist/{weather-report-AOX6RULO.js.map → weather-report-XHGOK6E7.js.map} +0 -0
|
@@ -5,34 +5,34 @@ import {
|
|
|
5
5
|
planOptionalParams,
|
|
6
6
|
requireApiKey,
|
|
7
7
|
validateApiKeyPresence
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-PRMJRGTB.js";
|
|
9
9
|
import {
|
|
10
10
|
CUSTOM_API_DEFAULT_MODEL
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-BIG3SAUY.js";
|
|
12
12
|
import {
|
|
13
13
|
CUSTOM_API_BASE_URL_ENV,
|
|
14
14
|
PROVIDER_ENV_KEYS,
|
|
15
15
|
assertCustomApiHostResolvesPublic,
|
|
16
16
|
validateCustomApiBaseUrl
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-ATOORYKU.js";
|
|
18
18
|
import {
|
|
19
19
|
nexusMkdtempSync
|
|
20
20
|
} from "./chunk-SNJNRDKZ.js";
|
|
21
21
|
import {
|
|
22
22
|
getAvailabilityCache
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-YCJVIYXU.js";
|
|
24
24
|
import {
|
|
25
25
|
extractSystemPrompt
|
|
26
26
|
} from "./chunk-QZUG667L.js";
|
|
27
27
|
import {
|
|
28
28
|
generateHyphenId
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-FH5GVIUB.js";
|
|
30
30
|
import {
|
|
31
31
|
CliCircuitBreaker,
|
|
32
32
|
DEFAULT_CIRCUIT_BREAKER_CONFIG,
|
|
33
33
|
getCliCircuitBreakerSnapshot,
|
|
34
34
|
getDefaultCliCircuitBreakerRegistry
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-RH2XESKI.js";
|
|
36
36
|
import {
|
|
37
37
|
CLI_SUBPROCESS_TIMEOUTS,
|
|
38
38
|
CLI_TIMEOUTS,
|
|
@@ -69,7 +69,7 @@ import {
|
|
|
69
69
|
ok,
|
|
70
70
|
parseRetryAfterMs,
|
|
71
71
|
resolveCliAlias
|
|
72
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-TSCF7SCI.js";
|
|
73
73
|
|
|
74
74
|
// src/cli-adapters/cli-to-model-adapter.ts
|
|
75
75
|
var CliToModelAdapter = class {
|
|
@@ -221,6 +221,210 @@ function createCliToModelAdapter(cliAdapter, config) {
|
|
|
221
221
|
return new CliToModelAdapter(cliAdapter, config);
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
// src/cli-adapters/capacity-tracker.ts
|
|
225
|
+
var DEFAULT_TOKEN_LIMITS = {
|
|
226
|
+
claude: 1e5,
|
|
227
|
+
// Claude API Build tier
|
|
228
|
+
gemini: 1e6,
|
|
229
|
+
// Gemini Pro generous limits
|
|
230
|
+
codex: 5e5,
|
|
231
|
+
// OpenAI tier 1
|
|
232
|
+
opencode: 5e5
|
|
233
|
+
// Multi-provider proxy
|
|
234
|
+
};
|
|
235
|
+
var DEFAULT_REQUEST_LIMITS = {
|
|
236
|
+
claude: 50,
|
|
237
|
+
// Claude API Build tier
|
|
238
|
+
gemini: 60,
|
|
239
|
+
// Gemini Pro
|
|
240
|
+
codex: 500,
|
|
241
|
+
// OpenAI tier 1
|
|
242
|
+
opencode: 300
|
|
243
|
+
// Multi-provider proxy
|
|
244
|
+
};
|
|
245
|
+
var RATE_LIMIT_WINDOW_MS = 6e4;
|
|
246
|
+
function getDefaultConfig(cli) {
|
|
247
|
+
const envPrefix = `NEXUS_${cli.toUpperCase()}`;
|
|
248
|
+
const tokenEnv = process.env[`${envPrefix}_TOKEN_LIMIT`];
|
|
249
|
+
const requestEnv = process.env[`${envPrefix}_REQUEST_LIMIT`];
|
|
250
|
+
return {
|
|
251
|
+
tokenLimit: tokenEnv !== void 0 && tokenEnv !== "" ? parseInt(tokenEnv, 10) : DEFAULT_TOKEN_LIMITS[cli],
|
|
252
|
+
requestLimit: requestEnv !== void 0 && requestEnv !== "" ? parseInt(requestEnv, 10) : DEFAULT_REQUEST_LIMITS[cli],
|
|
253
|
+
windowMs: RATE_LIMIT_WINDOW_MS
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
var CapacityTracker = class {
|
|
257
|
+
config;
|
|
258
|
+
usageHistory;
|
|
259
|
+
requestCount;
|
|
260
|
+
windowStart;
|
|
261
|
+
/**
|
|
262
|
+
* Timestamps of every recorded request (#3026 finding 4).
|
|
263
|
+
*
|
|
264
|
+
* Pre-fix, `requestCount` was a plain counter reset only by the
|
|
265
|
+
* tumbling-window branch of `pruneOldEntries`. Under continuous
|
|
266
|
+
* traffic across a window boundary, that branch drops requests that
|
|
267
|
+
* are still inside the *sliding* window — e.g. with windowMs=60s, a
|
|
268
|
+
* request at t=59s followed by one at t=61s would tumbling-reset
|
|
269
|
+
* the counter to 1 even though the t=59s request is still inside
|
|
270
|
+
* the [1s, 61s] window. The downstream `remainingRequests === 0`
|
|
271
|
+
* exhaustion check fired prematurely (or too late) depending on
|
|
272
|
+
* burst patterns.
|
|
273
|
+
*
|
|
274
|
+
* Counting via a per-request timestamp array that's pruned the same
|
|
275
|
+
* way as `usageHistory` keeps the two views consistent. Every
|
|
276
|
+
* `recordUsage` pushes here; `requestCount` is derived from
|
|
277
|
+
* `.length` after pruning.
|
|
278
|
+
*/
|
|
279
|
+
requestTimestamps;
|
|
280
|
+
/**
|
|
281
|
+
* Whether this process has recorded even one request against this adapter
|
|
282
|
+
* (#4374). Sticky: pruning the usage window back to empty does NOT clear it,
|
|
283
|
+
* because the process has still seen the adapter work — it simply has no
|
|
284
|
+
* recent samples. Without this flag a never-used tracker is indistinguishable
|
|
285
|
+
* from an idle healthy one, and both report full remaining capacity.
|
|
286
|
+
*/
|
|
287
|
+
hasObserved = false;
|
|
288
|
+
/**
|
|
289
|
+
* Provider-asserted quota exhaustion (#4456), with the horizon the provider
|
|
290
|
+
* gave. Null until a provider says so — never inferred from local counting.
|
|
291
|
+
*/
|
|
292
|
+
quotaExhaustedUntil = null;
|
|
293
|
+
constructor(config) {
|
|
294
|
+
this.config = config;
|
|
295
|
+
this.usageHistory = [];
|
|
296
|
+
this.requestCount = 0;
|
|
297
|
+
this.requestTimestamps = [];
|
|
298
|
+
this.windowStart = getTimeProvider().now();
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Records token usage from a completed request.
|
|
302
|
+
*/
|
|
303
|
+
recordUsage(usage) {
|
|
304
|
+
const now = getTimeProvider().now();
|
|
305
|
+
this.hasObserved = true;
|
|
306
|
+
this.pruneOldEntries(now);
|
|
307
|
+
this.quotaExhaustedUntil = null;
|
|
308
|
+
this.requestTimestamps.push(now);
|
|
309
|
+
this.requestCount = this.requestTimestamps.length;
|
|
310
|
+
if (usage !== void 0) {
|
|
311
|
+
const tokens = usage.totalTokens ?? usage.inputTokens + usage.outputTokens;
|
|
312
|
+
this.usageHistory.push({
|
|
313
|
+
timestamp: now,
|
|
314
|
+
tokens
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Gets current capacity status based on tracked usage.
|
|
320
|
+
*/
|
|
321
|
+
getCapacity() {
|
|
322
|
+
const now = getTimeProvider().now();
|
|
323
|
+
this.pruneOldEntries(now);
|
|
324
|
+
const usedTokens = this.usageHistory.reduce((sum, entry) => sum + entry.tokens, 0);
|
|
325
|
+
const remainingTokens = Math.max(0, this.config.tokenLimit - usedTokens);
|
|
326
|
+
const remainingRequests = Math.max(0, this.config.requestLimit - this.requestCount);
|
|
327
|
+
const tokenUtilization = usedTokens / this.config.tokenLimit * 100;
|
|
328
|
+
const requestUtilization = this.requestCount / this.config.requestLimit * 100;
|
|
329
|
+
const utilizationPercent = clampPercent(Math.max(tokenUtilization, requestUtilization));
|
|
330
|
+
const rateLimited = remainingTokens === 0 || remainingRequests === 0;
|
|
331
|
+
const resetTime = new Date(this.windowStart + this.config.windowMs);
|
|
332
|
+
if (this.quotaExhaustedUntil !== null && now >= this.quotaExhaustedUntil) {
|
|
333
|
+
this.quotaExhaustedUntil = null;
|
|
334
|
+
}
|
|
335
|
+
const quotaExhausted = this.quotaExhaustedUntil !== null;
|
|
336
|
+
return {
|
|
337
|
+
remainingTokens,
|
|
338
|
+
remainingRequests,
|
|
339
|
+
resetTime,
|
|
340
|
+
utilizationPercent: Math.round(utilizationPercent * 100) / 100,
|
|
341
|
+
rateLimited,
|
|
342
|
+
// #4456: identical value, deprecated name. Kept so the rename is not a
|
|
343
|
+
// breaking change to an exported type; removal is scheduled for the next
|
|
344
|
+
// major, and `no-restricted-syntax` blocks new reads in the meantime.
|
|
345
|
+
exhausted: rateLimited,
|
|
346
|
+
quotaExhausted,
|
|
347
|
+
...this.quotaExhaustedUntil !== null ? { quotaResetAt: new Date(this.quotaExhaustedUntil) } : {},
|
|
348
|
+
observed: this.hasObserved
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Record a PROVIDER's assertion that durable quota is exhausted (#4456).
|
|
353
|
+
*
|
|
354
|
+
* Only a `retryAfterMs` longer than the local window counts. A shorter one
|
|
355
|
+
* is an ordinary per-minute throttle, which {@link CapacityStatus.rateLimited}
|
|
356
|
+
* already covers — treating it as quota exhaustion would empty the candidate
|
|
357
|
+
* pool for a condition that clears in under a minute, the failure mode that
|
|
358
|
+
* kept #4373's enforcement stage switched off.
|
|
359
|
+
*
|
|
360
|
+
* Without a `retryAfterMs` the provider gave no horizon, so nothing is
|
|
361
|
+
* asserted: an exhaustion with no end is not distinguishable here from a
|
|
362
|
+
* transient error, and inventing a horizon would manufacture a measurement.
|
|
363
|
+
*
|
|
364
|
+
* @param retryAfterMs - The provider's stated wait, from `retry-after`.
|
|
365
|
+
* @returns true when the assertion was durable enough to record.
|
|
366
|
+
*/
|
|
367
|
+
recordProviderQuotaExhaustion(retryAfterMs) {
|
|
368
|
+
if (retryAfterMs === void 0 || retryAfterMs <= this.config.windowMs) return false;
|
|
369
|
+
this.hasObserved = true;
|
|
370
|
+
this.quotaExhaustedUntil = getTimeProvider().now() + retryAfterMs;
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Gets time until the rate limit window resets.
|
|
375
|
+
*/
|
|
376
|
+
getTimeUntilReset() {
|
|
377
|
+
const now = getTimeProvider().now();
|
|
378
|
+
const resetTime = this.windowStart + this.config.windowMs;
|
|
379
|
+
return Math.max(0, resetTime - now);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Resets all tracked usage (for testing or manual reset).
|
|
383
|
+
*/
|
|
384
|
+
reset() {
|
|
385
|
+
this.usageHistory.length = 0;
|
|
386
|
+
this.requestTimestamps.length = 0;
|
|
387
|
+
this.requestCount = 0;
|
|
388
|
+
this.windowStart = getTimeProvider().now();
|
|
389
|
+
this.quotaExhaustedUntil = null;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Updates configuration (e.g., after receiving actual rate limit info).
|
|
393
|
+
*/
|
|
394
|
+
updateConfig(partial) {
|
|
395
|
+
Object.assign(this.config, partial);
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Gets current configuration.
|
|
399
|
+
*/
|
|
400
|
+
getConfig() {
|
|
401
|
+
return { ...this.config };
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Removes entries older than the window duration.
|
|
405
|
+
*/
|
|
406
|
+
pruneOldEntries(now) {
|
|
407
|
+
const cutoff = now - this.config.windowMs;
|
|
408
|
+
while (this.usageHistory[0] !== void 0 && this.usageHistory[0].timestamp < cutoff) {
|
|
409
|
+
this.usageHistory.shift();
|
|
410
|
+
}
|
|
411
|
+
while (this.requestTimestamps[0] !== void 0 && this.requestTimestamps[0] < cutoff) {
|
|
412
|
+
this.requestTimestamps.shift();
|
|
413
|
+
}
|
|
414
|
+
this.requestCount = this.requestTimestamps.length;
|
|
415
|
+
const earliestRequest = this.requestTimestamps[0];
|
|
416
|
+
const earliestUsage = this.usageHistory[0]?.timestamp;
|
|
417
|
+
if (earliestRequest === void 0 && earliestUsage === void 0) {
|
|
418
|
+
this.windowStart = now;
|
|
419
|
+
} else {
|
|
420
|
+
this.windowStart = Math.min(earliestRequest ?? Infinity, earliestUsage ?? Infinity);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
function createCapacityTracker(cli) {
|
|
425
|
+
return new CapacityTracker(getDefaultConfig(cli));
|
|
426
|
+
}
|
|
427
|
+
|
|
224
428
|
// src/cli-adapters/model-to-cli-adapter.ts
|
|
225
429
|
var DEFAULT_CONTEXT_WINDOW = FALLBACK_CONTEXT_WINDOW;
|
|
226
430
|
var NEUTRAL_CAPABILITIES = {
|
|
@@ -236,10 +440,18 @@ var ModelToCliAdapter = class {
|
|
|
236
440
|
transport = API_TRANSPORT;
|
|
237
441
|
capabilities;
|
|
238
442
|
modelAdapter;
|
|
443
|
+
/**
|
|
444
|
+
* Per-arm capacity state (#4602). The same canonical `CapacityTracker` the
|
|
445
|
+
* subprocess adapters use — this bridge previously answered `getCapacity()`
|
|
446
|
+
* from literals, so no API/SDK arm could report a quota signal at all.
|
|
447
|
+
* Per-instance, so one arm's exhaustion never speaks for another's.
|
|
448
|
+
*/
|
|
449
|
+
capacityTracker;
|
|
239
450
|
constructor(modelAdapter, config) {
|
|
240
451
|
this.modelAdapter = modelAdapter;
|
|
241
452
|
this.name = config.name;
|
|
242
453
|
this.capabilities = config.capabilities ?? NEUTRAL_CAPABILITIES;
|
|
454
|
+
this.capacityTracker = createCapacityTracker(config.name);
|
|
243
455
|
}
|
|
244
456
|
/** Build a single-turn CompletionRequest from a CliTask. */
|
|
245
457
|
toCompletionRequest(task, options) {
|
|
@@ -284,24 +496,50 @@ var ModelToCliAdapter = class {
|
|
|
284
496
|
* Convert a ModelError to a CliError. Rate-limit text → RATE_LIMITED
|
|
285
497
|
* (retryable); everything else → EXECUTION_ERROR (non-retryable) so the
|
|
286
498
|
* routing/circuit layers see a real, typed failure.
|
|
499
|
+
*
|
|
500
|
+
* #4602: parses `retryAfterMs` off the message, mirroring
|
|
501
|
+
* `base-adapter.ts`'s `createError`. Pre-fix this bridge classified
|
|
502
|
+
* RATE_LIMITED and then threw the provider's stated horizon away — and that
|
|
503
|
+
* horizon is the sole input `CapacityTracker.recordProviderQuotaExhaustion`
|
|
504
|
+
* accepts, so the API/SDK arms could never assert quota exhaustion.
|
|
505
|
+
*
|
|
506
|
+
* Only parsed on a retryable error, as on the subprocess path: a wait hint
|
|
507
|
+
* inside a 500 body is not a rate-limit assertion.
|
|
287
508
|
*/
|
|
288
509
|
toCliError(error) {
|
|
289
510
|
const rateLimited = isRateLimitText(error.message);
|
|
290
511
|
const code = rateLimited ? "RATE_LIMITED" : "EXECUTION_ERROR";
|
|
512
|
+
const retryAfterMs = rateLimited ? parseRetryAfterMs(error.message) : void 0;
|
|
291
513
|
const base = {
|
|
292
514
|
code,
|
|
293
515
|
message: error.message,
|
|
294
516
|
cli: this.name,
|
|
295
|
-
retryable: rateLimited
|
|
517
|
+
retryable: rateLimited,
|
|
518
|
+
...retryAfterMs !== void 0 && { retryAfterMs }
|
|
296
519
|
};
|
|
297
520
|
return error.cause instanceof Error ? { ...base, cause: error.cause } : base;
|
|
298
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* Feed a provider's own rate-limit assertion into capacity tracking (#4602).
|
|
524
|
+
*
|
|
525
|
+
* The API-side counterpart of `BaseCliAdapter.recordQuotaSignal`. The
|
|
526
|
+
* tracker — not this adapter — decides whether the stated wait is long
|
|
527
|
+
* enough to mean durable quota rather than a per-minute throttle.
|
|
528
|
+
*/
|
|
529
|
+
recordQuotaSignal(error) {
|
|
530
|
+
if (error.code !== "RATE_LIMITED") return;
|
|
531
|
+
this.capacityTracker.recordProviderQuotaExhaustion(error.retryAfterMs);
|
|
532
|
+
}
|
|
299
533
|
async execute(task, options) {
|
|
300
534
|
const result = await this.modelAdapter.complete(this.toCompletionRequest(task, options));
|
|
301
535
|
if (!result.ok) {
|
|
302
|
-
|
|
536
|
+
const cliError = this.toCliError(result.error);
|
|
537
|
+
this.recordQuotaSignal(cliError);
|
|
538
|
+
return err(cliError);
|
|
303
539
|
}
|
|
304
|
-
|
|
540
|
+
const response = this.toCliResponse(result.value);
|
|
541
|
+
this.capacityTracker.recordUsage(response.usage);
|
|
542
|
+
return ok(response);
|
|
305
543
|
}
|
|
306
544
|
/** Health is derived from the model adapter's config validation. */
|
|
307
545
|
async healthCheck() {
|
|
@@ -315,25 +553,22 @@ var ModelToCliAdapter = class {
|
|
|
315
553
|
});
|
|
316
554
|
}
|
|
317
555
|
/**
|
|
318
|
-
*
|
|
319
|
-
* non-exhausted capacity. Real rate-limit signals surface via execute()'s
|
|
320
|
-
* RATE_LIMITED error, which the resilience layer acts on.
|
|
556
|
+
* Report this arm's capacity from its `CapacityTracker` (#4602).
|
|
321
557
|
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
558
|
+
* Previously this returned literals: `POSITIVE_INFINITY` remaining,
|
|
559
|
+
* `quotaExhausted: false`, `observed: false`. The `observed: false` half was
|
|
560
|
+
* honest (#4374 — nothing had been observed), but `quotaExhausted: false`
|
|
561
|
+
* asserted a measurement that never happened, and since `assessCapacity`
|
|
562
|
+
* reaches `'exhausted'` only through `quotaExhausted`, it made every
|
|
563
|
+
* API/SDK arm unexcludable for quota by construction — a check that cannot
|
|
564
|
+
* fail, whatever the provider said.
|
|
565
|
+
*
|
|
566
|
+
* The tracker keeps the honest empty case: until this arm has served a call
|
|
567
|
+
* or a provider has asserted a horizon, it reports `observed: false` and the
|
|
568
|
+
* stage grades it `unmeasured`, never `healthy`.
|
|
325
569
|
*/
|
|
326
570
|
getCapacity() {
|
|
327
|
-
return Promise.resolve(
|
|
328
|
-
remainingTokens: Number.POSITIVE_INFINITY,
|
|
329
|
-
remainingRequests: Number.POSITIVE_INFINITY,
|
|
330
|
-
resetTime: /* @__PURE__ */ new Date(0),
|
|
331
|
-
utilizationPercent: 0,
|
|
332
|
-
rateLimited: false,
|
|
333
|
-
exhausted: false,
|
|
334
|
-
quotaExhausted: false,
|
|
335
|
-
observed: false
|
|
336
|
-
});
|
|
571
|
+
return Promise.resolve(this.capacityTracker.getCapacity());
|
|
337
572
|
}
|
|
338
573
|
getVersion() {
|
|
339
574
|
return Promise.resolve("api");
|
|
@@ -1620,209 +1855,6 @@ function getTimeoutForTaskAuto(cli, taskDescription) {
|
|
|
1620
1855
|
return getAdaptiveTimeout(cli, taskDescription);
|
|
1621
1856
|
}
|
|
1622
1857
|
|
|
1623
|
-
// src/cli-adapters/capacity-tracker.ts
|
|
1624
|
-
var DEFAULT_TOKEN_LIMITS = {
|
|
1625
|
-
claude: 1e5,
|
|
1626
|
-
// Claude API Build tier
|
|
1627
|
-
gemini: 1e6,
|
|
1628
|
-
// Gemini Pro generous limits
|
|
1629
|
-
codex: 5e5,
|
|
1630
|
-
// OpenAI tier 1
|
|
1631
|
-
opencode: 5e5
|
|
1632
|
-
// Multi-provider proxy
|
|
1633
|
-
};
|
|
1634
|
-
var DEFAULT_REQUEST_LIMITS = {
|
|
1635
|
-
claude: 50,
|
|
1636
|
-
// Claude API Build tier
|
|
1637
|
-
gemini: 60,
|
|
1638
|
-
// Gemini Pro
|
|
1639
|
-
codex: 500,
|
|
1640
|
-
// OpenAI tier 1
|
|
1641
|
-
opencode: 300
|
|
1642
|
-
// Multi-provider proxy
|
|
1643
|
-
};
|
|
1644
|
-
var RATE_LIMIT_WINDOW_MS = 6e4;
|
|
1645
|
-
function getDefaultConfig(cli) {
|
|
1646
|
-
const envPrefix = `NEXUS_${cli.toUpperCase()}`;
|
|
1647
|
-
const tokenEnv = process.env[`${envPrefix}_TOKEN_LIMIT`];
|
|
1648
|
-
const requestEnv = process.env[`${envPrefix}_REQUEST_LIMIT`];
|
|
1649
|
-
return {
|
|
1650
|
-
tokenLimit: tokenEnv !== void 0 && tokenEnv !== "" ? parseInt(tokenEnv, 10) : DEFAULT_TOKEN_LIMITS[cli],
|
|
1651
|
-
requestLimit: requestEnv !== void 0 && requestEnv !== "" ? parseInt(requestEnv, 10) : DEFAULT_REQUEST_LIMITS[cli],
|
|
1652
|
-
windowMs: RATE_LIMIT_WINDOW_MS
|
|
1653
|
-
};
|
|
1654
|
-
}
|
|
1655
|
-
var CapacityTracker = class {
|
|
1656
|
-
config;
|
|
1657
|
-
usageHistory;
|
|
1658
|
-
requestCount;
|
|
1659
|
-
windowStart;
|
|
1660
|
-
/**
|
|
1661
|
-
* Timestamps of every recorded request (#3026 finding 4).
|
|
1662
|
-
*
|
|
1663
|
-
* Pre-fix, `requestCount` was a plain counter reset only by the
|
|
1664
|
-
* tumbling-window branch of `pruneOldEntries`. Under continuous
|
|
1665
|
-
* traffic across a window boundary, that branch drops requests that
|
|
1666
|
-
* are still inside the *sliding* window — e.g. with windowMs=60s, a
|
|
1667
|
-
* request at t=59s followed by one at t=61s would tumbling-reset
|
|
1668
|
-
* the counter to 1 even though the t=59s request is still inside
|
|
1669
|
-
* the [1s, 61s] window. The downstream `remainingRequests === 0`
|
|
1670
|
-
* exhaustion check fired prematurely (or too late) depending on
|
|
1671
|
-
* burst patterns.
|
|
1672
|
-
*
|
|
1673
|
-
* Counting via a per-request timestamp array that's pruned the same
|
|
1674
|
-
* way as `usageHistory` keeps the two views consistent. Every
|
|
1675
|
-
* `recordUsage` pushes here; `requestCount` is derived from
|
|
1676
|
-
* `.length` after pruning.
|
|
1677
|
-
*/
|
|
1678
|
-
requestTimestamps;
|
|
1679
|
-
/**
|
|
1680
|
-
* Whether this process has recorded even one request against this adapter
|
|
1681
|
-
* (#4374). Sticky: pruning the usage window back to empty does NOT clear it,
|
|
1682
|
-
* because the process has still seen the adapter work — it simply has no
|
|
1683
|
-
* recent samples. Without this flag a never-used tracker is indistinguishable
|
|
1684
|
-
* from an idle healthy one, and both report full remaining capacity.
|
|
1685
|
-
*/
|
|
1686
|
-
hasObserved = false;
|
|
1687
|
-
/**
|
|
1688
|
-
* Provider-asserted quota exhaustion (#4456), with the horizon the provider
|
|
1689
|
-
* gave. Null until a provider says so — never inferred from local counting.
|
|
1690
|
-
*/
|
|
1691
|
-
quotaExhaustedUntil = null;
|
|
1692
|
-
constructor(config) {
|
|
1693
|
-
this.config = config;
|
|
1694
|
-
this.usageHistory = [];
|
|
1695
|
-
this.requestCount = 0;
|
|
1696
|
-
this.requestTimestamps = [];
|
|
1697
|
-
this.windowStart = getTimeProvider().now();
|
|
1698
|
-
}
|
|
1699
|
-
/**
|
|
1700
|
-
* Records token usage from a completed request.
|
|
1701
|
-
*/
|
|
1702
|
-
recordUsage(usage) {
|
|
1703
|
-
const now = getTimeProvider().now();
|
|
1704
|
-
this.hasObserved = true;
|
|
1705
|
-
this.pruneOldEntries(now);
|
|
1706
|
-
this.quotaExhaustedUntil = null;
|
|
1707
|
-
this.requestTimestamps.push(now);
|
|
1708
|
-
this.requestCount = this.requestTimestamps.length;
|
|
1709
|
-
if (usage !== void 0) {
|
|
1710
|
-
const tokens = usage.totalTokens ?? usage.inputTokens + usage.outputTokens;
|
|
1711
|
-
this.usageHistory.push({
|
|
1712
|
-
timestamp: now,
|
|
1713
|
-
tokens
|
|
1714
|
-
});
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
/**
|
|
1718
|
-
* Gets current capacity status based on tracked usage.
|
|
1719
|
-
*/
|
|
1720
|
-
getCapacity() {
|
|
1721
|
-
const now = getTimeProvider().now();
|
|
1722
|
-
this.pruneOldEntries(now);
|
|
1723
|
-
const usedTokens = this.usageHistory.reduce((sum, entry) => sum + entry.tokens, 0);
|
|
1724
|
-
const remainingTokens = Math.max(0, this.config.tokenLimit - usedTokens);
|
|
1725
|
-
const remainingRequests = Math.max(0, this.config.requestLimit - this.requestCount);
|
|
1726
|
-
const tokenUtilization = usedTokens / this.config.tokenLimit * 100;
|
|
1727
|
-
const requestUtilization = this.requestCount / this.config.requestLimit * 100;
|
|
1728
|
-
const utilizationPercent = clampPercent(Math.max(tokenUtilization, requestUtilization));
|
|
1729
|
-
const rateLimited = remainingTokens === 0 || remainingRequests === 0;
|
|
1730
|
-
const resetTime = new Date(this.windowStart + this.config.windowMs);
|
|
1731
|
-
if (this.quotaExhaustedUntil !== null && now >= this.quotaExhaustedUntil) {
|
|
1732
|
-
this.quotaExhaustedUntil = null;
|
|
1733
|
-
}
|
|
1734
|
-
const quotaExhausted = this.quotaExhaustedUntil !== null;
|
|
1735
|
-
return {
|
|
1736
|
-
remainingTokens,
|
|
1737
|
-
remainingRequests,
|
|
1738
|
-
resetTime,
|
|
1739
|
-
utilizationPercent: Math.round(utilizationPercent * 100) / 100,
|
|
1740
|
-
rateLimited,
|
|
1741
|
-
// #4456: identical value, deprecated name. Kept so the rename is not a
|
|
1742
|
-
// breaking change to an exported type; removal is scheduled for the next
|
|
1743
|
-
// major, and `no-restricted-syntax` blocks new reads in the meantime.
|
|
1744
|
-
exhausted: rateLimited,
|
|
1745
|
-
quotaExhausted,
|
|
1746
|
-
...this.quotaExhaustedUntil !== null ? { quotaResetAt: new Date(this.quotaExhaustedUntil) } : {},
|
|
1747
|
-
observed: this.hasObserved
|
|
1748
|
-
};
|
|
1749
|
-
}
|
|
1750
|
-
/**
|
|
1751
|
-
* Record a PROVIDER's assertion that durable quota is exhausted (#4456).
|
|
1752
|
-
*
|
|
1753
|
-
* Only a `retryAfterMs` longer than the local window counts. A shorter one
|
|
1754
|
-
* is an ordinary per-minute throttle, which {@link CapacityStatus.rateLimited}
|
|
1755
|
-
* already covers — treating it as quota exhaustion would empty the candidate
|
|
1756
|
-
* pool for a condition that clears in under a minute, the failure mode that
|
|
1757
|
-
* kept #4373's enforcement stage switched off.
|
|
1758
|
-
*
|
|
1759
|
-
* Without a `retryAfterMs` the provider gave no horizon, so nothing is
|
|
1760
|
-
* asserted: an exhaustion with no end is not distinguishable here from a
|
|
1761
|
-
* transient error, and inventing a horizon would manufacture a measurement.
|
|
1762
|
-
*
|
|
1763
|
-
* @param retryAfterMs - The provider's stated wait, from `retry-after`.
|
|
1764
|
-
* @returns true when the assertion was durable enough to record.
|
|
1765
|
-
*/
|
|
1766
|
-
recordProviderQuotaExhaustion(retryAfterMs) {
|
|
1767
|
-
if (retryAfterMs === void 0 || retryAfterMs <= this.config.windowMs) return false;
|
|
1768
|
-
this.quotaExhaustedUntil = getTimeProvider().now() + retryAfterMs;
|
|
1769
|
-
return true;
|
|
1770
|
-
}
|
|
1771
|
-
/**
|
|
1772
|
-
* Gets time until the rate limit window resets.
|
|
1773
|
-
*/
|
|
1774
|
-
getTimeUntilReset() {
|
|
1775
|
-
const now = getTimeProvider().now();
|
|
1776
|
-
const resetTime = this.windowStart + this.config.windowMs;
|
|
1777
|
-
return Math.max(0, resetTime - now);
|
|
1778
|
-
}
|
|
1779
|
-
/**
|
|
1780
|
-
* Resets all tracked usage (for testing or manual reset).
|
|
1781
|
-
*/
|
|
1782
|
-
reset() {
|
|
1783
|
-
this.usageHistory.length = 0;
|
|
1784
|
-
this.requestTimestamps.length = 0;
|
|
1785
|
-
this.requestCount = 0;
|
|
1786
|
-
this.windowStart = getTimeProvider().now();
|
|
1787
|
-
this.quotaExhaustedUntil = null;
|
|
1788
|
-
}
|
|
1789
|
-
/**
|
|
1790
|
-
* Updates configuration (e.g., after receiving actual rate limit info).
|
|
1791
|
-
*/
|
|
1792
|
-
updateConfig(partial) {
|
|
1793
|
-
Object.assign(this.config, partial);
|
|
1794
|
-
}
|
|
1795
|
-
/**
|
|
1796
|
-
* Gets current configuration.
|
|
1797
|
-
*/
|
|
1798
|
-
getConfig() {
|
|
1799
|
-
return { ...this.config };
|
|
1800
|
-
}
|
|
1801
|
-
/**
|
|
1802
|
-
* Removes entries older than the window duration.
|
|
1803
|
-
*/
|
|
1804
|
-
pruneOldEntries(now) {
|
|
1805
|
-
const cutoff = now - this.config.windowMs;
|
|
1806
|
-
while (this.usageHistory[0] !== void 0 && this.usageHistory[0].timestamp < cutoff) {
|
|
1807
|
-
this.usageHistory.shift();
|
|
1808
|
-
}
|
|
1809
|
-
while (this.requestTimestamps[0] !== void 0 && this.requestTimestamps[0] < cutoff) {
|
|
1810
|
-
this.requestTimestamps.shift();
|
|
1811
|
-
}
|
|
1812
|
-
this.requestCount = this.requestTimestamps.length;
|
|
1813
|
-
const earliestRequest = this.requestTimestamps[0];
|
|
1814
|
-
const earliestUsage = this.usageHistory[0]?.timestamp;
|
|
1815
|
-
if (earliestRequest === void 0 && earliestUsage === void 0) {
|
|
1816
|
-
this.windowStart = now;
|
|
1817
|
-
} else {
|
|
1818
|
-
this.windowStart = Math.min(earliestRequest ?? Infinity, earliestUsage ?? Infinity);
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
};
|
|
1822
|
-
function createCapacityTracker(cli) {
|
|
1823
|
-
return new CapacityTracker(getDefaultConfig(cli));
|
|
1824
|
-
}
|
|
1825
|
-
|
|
1826
1858
|
// src/utils/async-utils.ts
|
|
1827
1859
|
function sleep(ms) {
|
|
1828
1860
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -4824,4 +4856,4 @@ export {
|
|
|
4824
4856
|
SdkAdapter,
|
|
4825
4857
|
createAutoAdapter
|
|
4826
4858
|
};
|
|
4827
|
-
//# sourceMappingURL=chunk-
|
|
4859
|
+
//# sourceMappingURL=chunk-Q4N2AMUH.js.map
|