@askalf/dario 6.0.16 → 6.0.18
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.
|
@@ -496,7 +496,7 @@ export declare function detectDrift(t: TemplateData, installedOverride?: string
|
|
|
496
496
|
*/
|
|
497
497
|
export declare const SUPPORTED_CC_RANGE: {
|
|
498
498
|
readonly min: "1.0.0";
|
|
499
|
-
readonly maxTested: "2.1.
|
|
499
|
+
readonly maxTested: "2.1.260";
|
|
500
500
|
};
|
|
501
501
|
/**
|
|
502
502
|
* Compare two dotted-numeric version strings. Returns negative if `a<b`,
|
package/dist/live-fingerprint.js
CHANGED
|
@@ -1194,7 +1194,7 @@ export function detectDrift(t, installedOverride) {
|
|
|
1194
1194
|
*/
|
|
1195
1195
|
export const SUPPORTED_CC_RANGE = {
|
|
1196
1196
|
min: '1.0.0',
|
|
1197
|
-
maxTested: '2.1.
|
|
1197
|
+
maxTested: '2.1.260',
|
|
1198
1198
|
};
|
|
1199
1199
|
/**
|
|
1200
1200
|
* Compare two dotted-numeric version strings. Returns negative if `a<b`,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Backward-compatible selection of a pool-fallback target for one request.
|
|
2
|
+
* A bare value or comma-separated model chain retains the legacy meaning.
|
|
3
|
+
* Tier maps use `tier:model`, e.g. `haiku:gpt-5.4-mini,sonnet:gpt-5.6-terra`.
|
|
4
|
+
* Unknown models use `default`, or the first (normally cheapest) configured tier.
|
|
5
|
+
*/
|
|
6
|
+
export declare function selectPoolFallbackModels(spec: string | undefined, requestedModel: string): string[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Backward-compatible selection of a pool-fallback target for one request.
|
|
2
|
+
* A bare value or comma-separated model chain retains the legacy meaning.
|
|
3
|
+
* Tier maps use `tier:model`, e.g. `haiku:gpt-5.4-mini,sonnet:gpt-5.6-terra`.
|
|
4
|
+
* Unknown models use `default`, or the first (normally cheapest) configured tier.
|
|
5
|
+
*/
|
|
6
|
+
export function selectPoolFallbackModels(spec, requestedModel) {
|
|
7
|
+
const entries = (spec ?? '').trim().split(',').map((entry) => entry.trim()).filter(Boolean);
|
|
8
|
+
if (entries.length === 0)
|
|
9
|
+
return [];
|
|
10
|
+
const mapped = entries.every((entry) => /^(haiku|sonnet|opus|default):/i.test(entry));
|
|
11
|
+
if (!mapped)
|
|
12
|
+
return entries;
|
|
13
|
+
const tiers = new Map();
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
const colon = entry.indexOf(':');
|
|
16
|
+
const tier = entry.slice(0, colon).trim().toLowerCase();
|
|
17
|
+
const model = entry.slice(colon + 1).trim();
|
|
18
|
+
if (tier && model)
|
|
19
|
+
tiers.set(tier, model);
|
|
20
|
+
}
|
|
21
|
+
const model = requestedModel.toLowerCase();
|
|
22
|
+
const tier = /haiku|mini|small/.test(model) ? 'haiku'
|
|
23
|
+
: /opus|sol|large/.test(model) ? 'opus'
|
|
24
|
+
: /sonnet|terra|medium/.test(model) ? 'sonnet'
|
|
25
|
+
: 'default';
|
|
26
|
+
const target = tiers.get(tier) ?? tiers.get('default') ?? tiers.values().next().value;
|
|
27
|
+
return target ? [target] : [];
|
|
28
|
+
}
|
package/dist/proxy.js
CHANGED
|
@@ -24,6 +24,7 @@ import { forwardToCodex, getCodexModelSlugs, peekCodexModelSlugs, pickCodexFallb
|
|
|
24
24
|
import { readCompareTarget, teeResponse, runCompare, writeCompareRecord, COMPARE_RESULT_HEADER } from './compare.js';
|
|
25
25
|
import { listCodexAccountAliases, loadAllCodexAccounts, codexAccountNeedsRefresh, hasAnyCodexAccount, selectCodexAccount, getFreshCodexAccount } from './codex-accounts.js';
|
|
26
26
|
import { route as routeProvider } from './provider-adapter.js';
|
|
27
|
+
import { selectPoolFallbackModels } from './pool-fallback-tier.js';
|
|
27
28
|
import { RequestQueue, QueueFullError, QueueTimeoutError, DEFAULT_MAX_CONCURRENT, DEFAULT_MAX_QUEUED, DEFAULT_QUEUE_TIMEOUT_MS } from './request-queue.js';
|
|
28
29
|
import { redactSecrets } from './redact.js';
|
|
29
30
|
import { BAKED_BASE_MODELS, withLongContextVariants, buildOpenAIModelsList, getModelCatalog, getCachedBases, resolveAliasAgainst, prewarmModelCatalog, retryModelCatalogNow, isSuspendedModel } from './model-catalog.js';
|
|
@@ -1256,9 +1257,19 @@ export async function startProxy(opts = {}) {
|
|
|
1256
1257
|
// The value may name a chain — see pickCodexFallback/pickClaudeFallback.
|
|
1257
1258
|
// `poolFallbackModel` stays the FIRST entry so every pre-6.0 reference and
|
|
1258
1259
|
// every single-value config keeps its exact previous meaning.
|
|
1259
|
-
const
|
|
1260
|
-
|
|
1260
|
+
const poolFallbackSpec = opts.poolFallbackModel;
|
|
1261
|
+
// Tier maps are selected per request; this retains the legacy chain for startup reporting.
|
|
1262
|
+
const poolFallbackModels = selectPoolFallbackModels(poolFallbackSpec, 'default');
|
|
1261
1263
|
const poolFallbackModel = poolFallbackModels[0] ?? null;
|
|
1264
|
+
const selectPoolFallbackForBody = (body) => {
|
|
1265
|
+
try {
|
|
1266
|
+
const parsed = JSON.parse(body.toString());
|
|
1267
|
+
return selectPoolFallbackModels(poolFallbackSpec, String(parsed.model ?? ""));
|
|
1268
|
+
}
|
|
1269
|
+
catch {
|
|
1270
|
+
return poolFallbackModels;
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1262
1273
|
if (poolFallbackModel) {
|
|
1263
1274
|
const targets = [];
|
|
1264
1275
|
if (startupCodexAliases.length > 0)
|
|
@@ -1905,15 +1916,16 @@ export async function startProxy(opts = {}) {
|
|
|
1905
1916
|
* this by construction, not by remembering to copy six lines correctly.
|
|
1906
1917
|
*/
|
|
1907
1918
|
const attemptPoolFallbackOn429 = async (req, res, body, isOpenAI, attempted) => {
|
|
1908
|
-
if (await tryCodexPoolFallback(req, res, body,
|
|
1919
|
+
if (await tryCodexPoolFallback(req, res, body, selectPoolFallbackForBody(body), isOpenAI ? 'openai' : 'anthropic', 'pool exhausted mid-flight (429, no peer)', attempted)) {
|
|
1909
1920
|
return true;
|
|
1910
1921
|
}
|
|
1911
|
-
|
|
1912
|
-
|
|
1922
|
+
const fallbackModel = selectPoolFallbackForBody(body)[0] ?? null;
|
|
1923
|
+
if (isOpenAI && fallbackModel && openaiBackend) {
|
|
1924
|
+
const fallbackBody = buildPoolFallbackBody(body, fallbackModel);
|
|
1913
1925
|
if (fallbackBody) {
|
|
1914
|
-
console.log(`[dario] #${requestCount} pool exhausted mid-flight (429, no peer) → ${openaiBackend.name} as ${
|
|
1926
|
+
console.log(`[dario] #${requestCount} pool exhausted mid-flight (429, no peer) → ${openaiBackend.name} as ${fallbackModel}`);
|
|
1915
1927
|
requestCount++;
|
|
1916
|
-
await forwardToOpenAI(req, res, fallbackBody, openaiBackend, corsOrigin, { ...SECURITY_HEADERS, 'x-dario-pool-fallback':
|
|
1928
|
+
await forwardToOpenAI(req, res, fallbackBody, openaiBackend, corsOrigin, { ...SECURITY_HEADERS, 'x-dario-pool-fallback': fallbackModel }, upstreamTimeoutMs, verbose);
|
|
1917
1929
|
return true;
|
|
1918
1930
|
}
|
|
1919
1931
|
}
|
|
@@ -2755,6 +2767,8 @@ export async function startProxy(opts = {}) {
|
|
|
2755
2767
|
try {
|
|
2756
2768
|
const peek = JSON.parse(body.toString());
|
|
2757
2769
|
const rawModel = (peek.model || '').toString();
|
|
2770
|
+
const requestPoolFallbackModels = selectPoolFallbackModels(poolFallbackSpec, rawModel);
|
|
2771
|
+
const requestPoolFallbackModel = requestPoolFallbackModels[0] ?? null;
|
|
2758
2772
|
// Credentials are re-read per request (not cached at startup) because
|
|
2759
2773
|
// a refresh rotates them on disk; getFreshCodexAccount refreshes when
|
|
2760
2774
|
// inside the expiry buffer, collapsing concurrent refreshes per alias.
|
|
@@ -2781,7 +2795,7 @@ export async function startProxy(opts = {}) {
|
|
|
2781
2795
|
hasOpenAIBackend: openaiBackend !== null,
|
|
2782
2796
|
hasCodexAccount: codexCreds !== null,
|
|
2783
2797
|
codexModels,
|
|
2784
|
-
poolFallbackModel,
|
|
2798
|
+
poolFallbackModel: requestPoolFallbackModel,
|
|
2785
2799
|
poolSize: pool.size,
|
|
2786
2800
|
});
|
|
2787
2801
|
if (rawModel && codexCreds && decision.provider === 'codex') {
|
|
@@ -2801,7 +2815,7 @@ export async function startProxy(opts = {}) {
|
|
|
2801
2815
|
// request, and the classifier validates the id that would actually
|
|
2802
2816
|
// be forwarded. The entry's own effort suffix (`claude:opus:high`)
|
|
2803
2817
|
// comes back with it — see the swap below.
|
|
2804
|
-
const claudeTarget = pickClaudeTarget(
|
|
2818
|
+
const claudeTarget = pickClaudeTarget(requestPoolFallbackModels, codexModels, getCachedBases(), (m) => resolveClaudeAlias(applyModelAlias(m, modelAliases) ?? m));
|
|
2805
2819
|
const claudeTargetModel = claudeTarget?.model ?? null;
|
|
2806
2820
|
const canDefer = claudeTarget !== null && pool.size > 0 && !upstreamApiKey;
|
|
2807
2821
|
// DEV-f66b131c: an account still inside its 429 cool-down is not
|
|
@@ -2921,7 +2935,7 @@ export async function startProxy(opts = {}) {
|
|
|
2921
2935
|
if (!upstreamApiKey && !poolAccount) {
|
|
2922
2936
|
attemptedProviders.add('claude');
|
|
2923
2937
|
}
|
|
2924
|
-
if (!upstreamApiKey && !poolAccount && await tryCodexPoolFallback(req, res, body,
|
|
2938
|
+
if (!upstreamApiKey && !poolAccount && await tryCodexPoolFallback(req, res, body, selectPoolFallbackForBody(body), isOpenAI ? 'openai' : 'anthropic', 'pool exhausted', attemptedProviders)) {
|
|
2925
2939
|
return;
|
|
2926
2940
|
}
|
|
2927
2941
|
// `isOpenAI` is REQUIRED here and was not, before v6.0.0 — the selector's
|
|
@@ -2931,15 +2945,16 @@ export async function startProxy(opts = {}) {
|
|
|
2931
2945
|
// hand the client an OpenAI-shaped response for a Messages request. This
|
|
2932
2946
|
// route still has no reverse translation; the codex route above does,
|
|
2933
2947
|
// which is why it takes both shapes and this one does not.
|
|
2934
|
-
|
|
2935
|
-
|
|
2948
|
+
const fallbackModel = selectPoolFallbackForBody(body)[0] ?? null;
|
|
2949
|
+
if (!upstreamApiKey && !poolAccount && fallbackModel && openaiBackend && isOpenAI) {
|
|
2950
|
+
const fallbackBody = buildPoolFallbackBody(body, fallbackModel);
|
|
2936
2951
|
if (!fallbackBody) {
|
|
2937
2952
|
writePoolUnavailable();
|
|
2938
2953
|
return;
|
|
2939
2954
|
}
|
|
2940
|
-
console.log(`[dario] #${requestCount} pool exhausted — /v1/chat/completions → ${openaiBackend.name} as ${
|
|
2955
|
+
console.log(`[dario] #${requestCount} pool exhausted — /v1/chat/completions → ${openaiBackend.name} as ${fallbackModel}`);
|
|
2941
2956
|
requestCount++;
|
|
2942
|
-
await forwardToOpenAI(req, res, fallbackBody, openaiBackend, corsOrigin, { ...SECURITY_HEADERS, 'x-dario-pool-fallback':
|
|
2957
|
+
await forwardToOpenAI(req, res, fallbackBody, openaiBackend, corsOrigin, { ...SECURITY_HEADERS, 'x-dario-pool-fallback': fallbackModel }, upstreamTimeoutMs, verbose);
|
|
2943
2958
|
return;
|
|
2944
2959
|
}
|
|
2945
2960
|
// Deferred at selection because a fallback was armed, but nothing could
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.18",
|
|
4
4
|
"description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|