@blockrun/franklin 3.15.11 → 3.15.12
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/agent/loop.js +3 -5
- package/dist/router/index.d.ts +6 -0
- package/dist/router/index.js +36 -1
- package/package.json +1 -1
package/dist/agent/loop.js
CHANGED
|
@@ -24,7 +24,7 @@ import { logger, setDebugMode } from '../logger.js';
|
|
|
24
24
|
import { estimateCost, OPUS_PRICING } from '../pricing.js';
|
|
25
25
|
import { maybeMidSessionExtract } from '../learnings/extractor.js';
|
|
26
26
|
import { extractMentions, buildEntityContext, loadEntities } from '../brain/store.js';
|
|
27
|
-
import { routeRequestAsync, resolveTierToModel, parseRoutingProfile, getFallbackChain } from '../router/index.js';
|
|
27
|
+
import { routeRequestAsync, resolveTierToModel, parseRoutingProfile, getFallbackChain, pickFreeFallback } from '../router/index.js';
|
|
28
28
|
import { recordOutcome } from '../router/local-elo.js';
|
|
29
29
|
import { shouldPlan, getPlanningPrompt, getExecutorModel, isExecutorStuck, toolCallSignature } from './planner.js';
|
|
30
30
|
import { shouldVerify, runVerification } from './verification.js';
|
|
@@ -1098,8 +1098,7 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
1098
1098
|
if (lastRoutedCategory) {
|
|
1099
1099
|
recordOutcome(lastRoutedCategory, config.model, 'payment');
|
|
1100
1100
|
}
|
|
1101
|
-
const
|
|
1102
|
-
const nextFree = FREE_MODELS.find(m => !turnFailedModels.has(m));
|
|
1101
|
+
const nextFree = pickFreeFallback(lastRoutedCategory, turnFailedModels);
|
|
1103
1102
|
if (nextFree) {
|
|
1104
1103
|
const oldModel = config.model;
|
|
1105
1104
|
config.model = nextFree;
|
|
@@ -1120,8 +1119,7 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
1120
1119
|
if (lastRoutedCategory) {
|
|
1121
1120
|
recordOutcome(lastRoutedCategory, config.model, 'rate_limit');
|
|
1122
1121
|
}
|
|
1123
|
-
const
|
|
1124
|
-
const nextFree = FREE_MODELS.find(m => !turnFailedModels.has(m));
|
|
1122
|
+
const nextFree = pickFreeFallback(lastRoutedCategory, turnFailedModels);
|
|
1125
1123
|
if (nextFree) {
|
|
1126
1124
|
const oldModel = config.model;
|
|
1127
1125
|
config.model = nextFree;
|
package/dist/router/index.d.ts
CHANGED
|
@@ -49,6 +49,12 @@ export declare function routeRequest(prompt: string, profile?: RoutingProfile):
|
|
|
49
49
|
* Get fallback models for a tier
|
|
50
50
|
*/
|
|
51
51
|
export declare function getFallbackChain(tier: Tier, profile?: RoutingProfile): string[];
|
|
52
|
+
/**
|
|
53
|
+
* Pick the next free model to try given the question category and which
|
|
54
|
+
* free models have already failed this turn. Returns undefined when every
|
|
55
|
+
* candidate has been exhausted (caller should surface an error to user).
|
|
56
|
+
*/
|
|
57
|
+
export declare function pickFreeFallback(category: string, alreadyFailed: Set<string>): string | undefined;
|
|
52
58
|
/**
|
|
53
59
|
* Parse routing profile from model string
|
|
54
60
|
*/
|
package/dist/router/index.js
CHANGED
|
@@ -483,10 +483,45 @@ function computeSavings(model) {
|
|
|
483
483
|
*/
|
|
484
484
|
export function getFallbackChain(tier, profile = 'auto') {
|
|
485
485
|
if (profile === 'free')
|
|
486
|
-
return
|
|
486
|
+
return FREE_MODELS_BY_CATEGORY.chat;
|
|
487
487
|
const config = AUTO_TIERS[tier];
|
|
488
488
|
return [config.primary, ...config.fallback];
|
|
489
489
|
}
|
|
490
|
+
// ─── Free-tier fallback (used when paid models 402 / rate-limit) ───
|
|
491
|
+
// Free fallback chains by question category. Used when a paid model fails
|
|
492
|
+
// mid-turn (402 payment, rate-limit) and we need a zero-cost replacement
|
|
493
|
+
// to keep the user moving without waiting for funding.
|
|
494
|
+
//
|
|
495
|
+
// The lists are ordered: best-fit free model first, then degraded fallbacks.
|
|
496
|
+
// Coding goes to qwen3-coder; everything else (chat / trading / research /
|
|
497
|
+
// reasoning / creative) prefers general-purpose free models that aren't
|
|
498
|
+
// coder-tuned. Without this split, a BTC question that exhausted paid
|
|
499
|
+
// models was being handed to qwen3-coder-480b — a coder model trying to
|
|
500
|
+
// do technical analysis. Reported 2026-05-03 with a markets question
|
|
501
|
+
// routed to a coder model on Sonnet failure.
|
|
502
|
+
const FREE_MODELS_BY_CATEGORY = {
|
|
503
|
+
coding: ['nvidia/qwen3-coder-480b', 'nvidia/glm-4.7', 'nvidia/llama-4-maverick'],
|
|
504
|
+
trading: ['nvidia/glm-4.7', 'nvidia/llama-4-maverick', 'nvidia/qwen3-coder-480b'],
|
|
505
|
+
research: ['nvidia/glm-4.7', 'nvidia/llama-4-maverick', 'nvidia/qwen3-coder-480b'],
|
|
506
|
+
reasoning: ['nvidia/glm-4.7', 'nvidia/qwen3-coder-480b', 'nvidia/llama-4-maverick'],
|
|
507
|
+
chat: ['nvidia/llama-4-maverick', 'nvidia/glm-4.7', 'nvidia/qwen3-coder-480b'],
|
|
508
|
+
creative: ['nvidia/llama-4-maverick', 'nvidia/glm-4.7', 'nvidia/qwen3-coder-480b'],
|
|
509
|
+
};
|
|
510
|
+
const DEFAULT_FREE_CHAIN = [
|
|
511
|
+
'nvidia/glm-4.7',
|
|
512
|
+
'nvidia/llama-4-maverick',
|
|
513
|
+
'nvidia/qwen3-coder-480b',
|
|
514
|
+
];
|
|
515
|
+
/**
|
|
516
|
+
* Pick the next free model to try given the question category and which
|
|
517
|
+
* free models have already failed this turn. Returns undefined when every
|
|
518
|
+
* candidate has been exhausted (caller should surface an error to user).
|
|
519
|
+
*/
|
|
520
|
+
export function pickFreeFallback(category, alreadyFailed) {
|
|
521
|
+
const chain = FREE_MODELS_BY_CATEGORY[category]
|
|
522
|
+
?? DEFAULT_FREE_CHAIN;
|
|
523
|
+
return chain.find(m => !alreadyFailed.has(m));
|
|
524
|
+
}
|
|
490
525
|
/**
|
|
491
526
|
* Parse routing profile from model string
|
|
492
527
|
*/
|
package/package.json
CHANGED