agent-nuvira 3.5.1 → 3.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/cli/chat.d.ts +42 -0
  2. package/dist/cli/chat.d.ts.map +1 -1
  3. package/dist/cli/chat.js +240 -16
  4. package/dist/cli/chat.js.map +1 -1
  5. package/dist/cli/edit.d.ts.map +1 -1
  6. package/dist/cli/edit.js +3 -2
  7. package/dist/cli/edit.js.map +1 -1
  8. package/dist/cli/execute.d.ts.map +1 -1
  9. package/dist/cli/execute.js +10 -3
  10. package/dist/cli/execute.js.map +1 -1
  11. package/dist/cli/loop-executor.d.ts +16 -0
  12. package/dist/cli/loop-executor.d.ts.map +1 -1
  13. package/dist/cli/loop-executor.js +9 -0
  14. package/dist/cli/loop-executor.js.map +1 -1
  15. package/dist/cli/plan.d.ts.map +1 -1
  16. package/dist/cli/plan.js +18 -6
  17. package/dist/cli/plan.js.map +1 -1
  18. package/dist/cli/run.d.ts.map +1 -1
  19. package/dist/cli/run.js +23 -8
  20. package/dist/cli/run.js.map +1 -1
  21. package/dist/cli/ui/answer-view.d.ts +38 -0
  22. package/dist/cli/ui/answer-view.d.ts.map +1 -0
  23. package/dist/cli/ui/answer-view.js +72 -0
  24. package/dist/cli/ui/answer-view.js.map +1 -0
  25. package/dist/cli/ui/cards.d.ts +61 -0
  26. package/dist/cli/ui/cards.d.ts.map +1 -0
  27. package/dist/cli/ui/cards.js +141 -0
  28. package/dist/cli/ui/cards.js.map +1 -0
  29. package/dist/cli/ui/highlight.d.ts +32 -0
  30. package/dist/cli/ui/highlight.d.ts.map +1 -0
  31. package/dist/cli/ui/highlight.js +261 -0
  32. package/dist/cli/ui/highlight.js.map +1 -0
  33. package/dist/cli/ui/index.d.ts +21 -0
  34. package/dist/cli/ui/index.d.ts.map +1 -0
  35. package/dist/cli/ui/index.js +14 -0
  36. package/dist/cli/ui/index.js.map +1 -0
  37. package/dist/cli/ui/markdown.d.ts +90 -0
  38. package/dist/cli/ui/markdown.d.ts.map +1 -0
  39. package/dist/cli/ui/markdown.js +292 -0
  40. package/dist/cli/ui/markdown.js.map +1 -0
  41. package/dist/cli/ui/presenter.d.ts +147 -0
  42. package/dist/cli/ui/presenter.d.ts.map +1 -0
  43. package/dist/cli/ui/presenter.js +313 -0
  44. package/dist/cli/ui/presenter.js.map +1 -0
  45. package/dist/cli/ui/render.d.ts +52 -0
  46. package/dist/cli/ui/render.d.ts.map +1 -0
  47. package/dist/cli/ui/render.js +384 -0
  48. package/dist/cli/ui/render.js.map +1 -0
  49. package/dist/cli/ui/theme.d.ts +36 -0
  50. package/dist/cli/ui/theme.d.ts.map +1 -0
  51. package/dist/cli/ui/theme.js +92 -0
  52. package/dist/cli/ui/theme.js.map +1 -0
  53. package/dist/inference/model-entitlement.d.ts +10 -0
  54. package/dist/inference/model-entitlement.d.ts.map +1 -1
  55. package/dist/inference/model-entitlement.js +1 -1
  56. package/dist/inference/model-entitlement.js.map +1 -1
  57. package/dist/learning/auto-router.d.ts +10 -1
  58. package/dist/learning/auto-router.d.ts.map +1 -1
  59. package/dist/learning/auto-router.js +63 -11
  60. package/dist/learning/auto-router.js.map +1 -1
  61. package/dist/learning/reasoning-trace.d.ts +21 -1
  62. package/dist/learning/reasoning-trace.d.ts.map +1 -1
  63. package/dist/learning/reasoning-trace.js.map +1 -1
  64. package/dist/learning/resilient-call.d.ts.map +1 -1
  65. package/dist/learning/resilient-call.js +70 -4
  66. package/dist/learning/resilient-call.js.map +1 -1
  67. package/dist/tools/process-liveness.d.ts +227 -0
  68. package/dist/tools/process-liveness.d.ts.map +1 -0
  69. package/dist/tools/process-liveness.js +486 -0
  70. package/dist/tools/process-liveness.js.map +1 -0
  71. package/dist/tools/registry.d.ts.map +1 -1
  72. package/dist/tools/registry.js +4 -2
  73. package/dist/tools/registry.js.map +1 -1
  74. package/dist/tools/run-registry.d.ts +282 -0
  75. package/dist/tools/run-registry.d.ts.map +1 -0
  76. package/dist/tools/run-registry.js +557 -0
  77. package/dist/tools/run-registry.js.map +1 -0
  78. package/dist/tools/run-terminal.d.ts +100 -2
  79. package/dist/tools/run-terminal.d.ts.map +1 -1
  80. package/dist/tools/run-terminal.js +841 -67
  81. package/dist/tools/run-terminal.js.map +1 -1
  82. package/dist/tools/tool-loop.d.ts +46 -0
  83. package/dist/tools/tool-loop.d.ts.map +1 -1
  84. package/dist/tools/tool-loop.js +115 -2
  85. package/dist/tools/tool-loop.js.map +1 -1
  86. package/dist/web-dashboard/chat-console.d.ts +25 -0
  87. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  88. package/dist/web-dashboard/chat-console.js +16 -1
  89. package/dist/web-dashboard/chat-console.js.map +1 -1
  90. package/dist/web-dashboard/server.d.ts.map +1 -1
  91. package/dist/web-dashboard/server.js +7 -1
  92. package/dist/web-dashboard/server.js.map +1 -1
  93. package/dist/web-dashboard/src/types.d.ts +32 -1
  94. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  95. package/dist/web-dashboard/task-registry.d.ts +98 -0
  96. package/dist/web-dashboard/task-registry.d.ts.map +1 -0
  97. package/dist/web-dashboard/task-registry.js +159 -0
  98. package/dist/web-dashboard/task-registry.js.map +1 -0
  99. package/dist/web-dashboard/task-runner.d.ts +155 -5
  100. package/dist/web-dashboard/task-runner.d.ts.map +1 -1
  101. package/dist/web-dashboard/task-runner.js +544 -14
  102. package/dist/web-dashboard/task-runner.js.map +1 -1
  103. package/package.json +1 -1
  104. package/src/web-dashboard/public/assets/index-DycGBWwy.js +236 -0
  105. package/src/web-dashboard/public/assets/index-DycGBWwy.js.map +1 -0
  106. package/src/web-dashboard/public/index.html +1 -1
  107. package/src/web-dashboard/public/assets/index-Bik91KJh.js +0 -236
  108. package/src/web-dashboard/public/assets/index-Bik91KJh.js.map +0 -1
@@ -674,6 +674,27 @@ export declare class ChatCommand extends BaseCommand {
674
674
  * isolation on a surface the CLI did not.
675
675
  */
676
676
  private ws5Overrides;
677
+ /**
678
+ * Live answer streaming for the interactive REPL.
679
+ *
680
+ * Returns the per-turn context overrides that paint the answer as it is
681
+ * generated, plus a `stop()` the caller MUST invoke once the turn returns.
682
+ * `stop()` unmounts the live view WITHOUT archiving, because the turn's own
683
+ * answer-printing path renders the authoritative final `answer.content` —
684
+ * archiving here as well would print the answer twice. The streamed tokens
685
+ * are a PREVIEW; the final frame is what stays in the transcript.
686
+ *
687
+ * ON A REAL TERMINAL ONLY. A pipe, CI run or `--json-events` gets no Ink view
688
+ * and no `onToken`, so a later step never streams and the bytes on stdout are
689
+ * exactly what they were before this existed.
690
+ *
691
+ * WHY THE RESET ON `tool:started`. `onToken` is invoked for EVERY model call
692
+ * in the tool loop, not only for the answer, so a turn that calls a tool
693
+ * would otherwise append the next step's answer onto the previous step's
694
+ * preamble. A tool starting is the boundary between steps, so the preview is
695
+ * cleared there.
696
+ */
697
+ private liveAnswer;
677
698
  private execute;
678
699
  /**
679
700
  * E3b — run one chat answer as a TOOL-CALL TURN.
@@ -820,6 +841,27 @@ export declare class ChatCommand extends BaseCommand {
820
841
  * the ranked candidates and picks the first one whose isAvailable() passes —
821
842
  * so Auto routing never sends a request to a provider that would 401.
822
843
  */
844
+ /**
845
+ * Point the routing snapshot at the pair this step will ACTUALLY use.
846
+ *
847
+ * THE DEFECT THIS CLOSES (measured 2026-10-13). The snapshot was assigned once
848
+ * per `routeMessageAuto` call, from the router's DECISION — before the
849
+ * candidate walk had a chance to substitute a pair — so a step could record
850
+ * `routing: gemini/gemini-3.1-flash-lite, agenticCapable: true` while the
851
+ * request went to `local/deepseek-coder:latest`: the Trace tab, the console
852
+ * line and the capability verdict all named a model the turn never ran, and the
853
+ * disagreement was invisible (trace-1791907393457-7seewg). The pair that really
854
+ * ran was in `lastAttempt` only.
855
+ *
856
+ * So the snapshot now FOLLOWS the attempt: provider/model are the pair being
857
+ * asked, the capability verdict is recomputed for THAT pair (the field asks
858
+ * "may the final routed model hold an agentic software task", so it must
859
+ * describe the model that ran), and the router's intended pair is kept once as
860
+ * `substitutedFor` so the substitution stays auditable instead of being erased.
861
+ * The first substitution wins, because that is the DECISION the walk moved away
862
+ * from — a later hop does not overwrite it with an intermediate pair.
863
+ */
864
+ private noteServedRoute;
823
865
  private routeMessageAuto;
824
866
  /**
825
867
  * Read multi-line input from stdin using readline.
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/cli/chat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/cli/chat.ts"],"names":[],"mappings":"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"}
package/dist/cli/chat.js CHANGED
@@ -16,6 +16,7 @@ import { decisionsRecordingEnabled, recallDecisionBlock } from '../learning/deci
16
16
  import { getMemoryManager } from '../memory/manager.js';
17
17
  import { logger } from '../utils/logger.js';
18
18
  import { printOrchestrationResult } from './execute.js';
19
+ import { AnswerStream, attachShellCards, gitDiffCard, presentAnswer, shouldUseRichUi, toolCallCard, } from './ui/index.js';
19
20
  // WS5 (#27) — isolation (a git worktree around the turn) and resume (replaying
20
21
  // recorded steps instead of re-paying for them). See the module headers for why
21
22
  // the worktree is created HERE, around the whole turn, and why a replay is
@@ -29,7 +30,7 @@ import { recordActionFailure, } from '../learning/failure-bookkeeping.js';
29
30
  import { getRouterBandit } from '../learning/router-bandit.js';
30
31
  import { UnusableModelResponseError } from '../learning/response-usability.js';
31
32
  import { resolveThreadBudgetChars } from '../learning/context-budget.js';
32
- import { getAutoRouter, isAgentAutoRoute, isAutoModel, isAutoProvider, governanceVerdict, adminBudgetVerdict } from '../learning/auto-router.js';
33
+ import { getAutoRouter, isAgentAutoRoute, isAutoModel, isAutoProvider, governanceVerdict, adminBudgetVerdict, isAgenticTask } from '../learning/auto-router.js';
33
34
  import { continuationSoftwareText } from '../learning/continuation-intent.js';
34
35
  import { TaskModelContinuity, taskSignature } from '../learning/task-model-continuity.js';
35
36
  import { describeFailureKind, renderExhaustionReport, } from '../learning/exhaustion-report.js';
@@ -1292,6 +1293,63 @@ export class ChatCommand extends BaseCommand {
1292
1293
  resume: options?.resume,
1293
1294
  };
1294
1295
  }
1296
+ /**
1297
+ * Live answer streaming for the interactive REPL.
1298
+ *
1299
+ * Returns the per-turn context overrides that paint the answer as it is
1300
+ * generated, plus a `stop()` the caller MUST invoke once the turn returns.
1301
+ * `stop()` unmounts the live view WITHOUT archiving, because the turn's own
1302
+ * answer-printing path renders the authoritative final `answer.content` —
1303
+ * archiving here as well would print the answer twice. The streamed tokens
1304
+ * are a PREVIEW; the final frame is what stays in the transcript.
1305
+ *
1306
+ * ON A REAL TERMINAL ONLY. A pipe, CI run or `--json-events` gets no Ink view
1307
+ * and no `onToken`, so a later step never streams and the bytes on stdout are
1308
+ * exactly what they were before this existed.
1309
+ *
1310
+ * WHY THE RESET ON `tool:started`. `onToken` is invoked for EVERY model call
1311
+ * in the tool loop, not only for the answer, so a turn that calls a tool
1312
+ * would otherwise append the next step's answer onto the previous step's
1313
+ * preamble. A tool starting is the boundary between steps, so the preview is
1314
+ * cleared there.
1315
+ */
1316
+ liveAnswer(header, opts = {}) {
1317
+ if (!shouldUseRichUi(opts))
1318
+ return { overrides: {}, stop: () => { }, stream: null };
1319
+ const stream = new AnswerStream({ header, headerColor: 'assistant' }, opts);
1320
+ let begun = false;
1321
+ // Shell commands are emitted on the process-wide bus (utils/shell.ts owns
1322
+ // them), so the turn subscribes for its own duration and detaches on stop().
1323
+ const detachShell = attachShellCards((card) => stream.card(card));
1324
+ return {
1325
+ stream,
1326
+ overrides: {
1327
+ onToken: (token) => {
1328
+ if (!begun) {
1329
+ begun = true;
1330
+ stream.begin();
1331
+ }
1332
+ stream.append(token);
1333
+ },
1334
+ onToolCall: (phase, info) => {
1335
+ if (phase === 'started') {
1336
+ // The step's preamble is not the answer: clear it so the preview
1337
+ // shows the step that is actually producing the reply.
1338
+ if (begun)
1339
+ stream.reset();
1340
+ return;
1341
+ }
1342
+ // Completed call → an archived card (this is what the turn DID).
1343
+ stream.card(toolCallCard({ tool: info.tool, ok: info.ok, error: info.error, result: info.result, durationMs: info.durationMs, args: info.args }));
1344
+ },
1345
+ onGitDiff: (payload) => stream.card(gitDiffCard(payload)),
1346
+ },
1347
+ stop: () => {
1348
+ detachShell();
1349
+ stream.finish({ archive: false });
1350
+ },
1351
+ };
1352
+ }
1295
1353
  async execute(prompt, options) {
1296
1354
  // Apply the active model state from `nuvira model switch` as defaults
1297
1355
  const activeOpts = applyActiveModel({ provider: options?.provider, model: options?.model });
@@ -1418,10 +1476,14 @@ export class ChatCommand extends BaseCommand {
1418
1476
  // failed entirely), never as a bypass.
1419
1477
  const parsed = parseRequestSync(prompt);
1420
1478
  const dispatchDecision = resolvePipelineDispatch(parsed, { dev: options?.dev, text: prompt });
1479
+ // P7 — paint the answer live while it generates (TTY only; a no-op
1480
+ // elsewhere). `stop()` unmounts the preview once the turn returns; the
1481
+ // final frame is printed by the answer path below.
1482
+ const live = this.liveAnswer(`nuvira · ${provider.name}${model ? ` / ${model}` : ''}`);
1421
1483
  const answer = await this.runChatAnswer(prompt, [], { type, provider, model }, options || {}, cacheEnabled, { auto: autoMode }, parsed,
1422
1484
  // WS5 (#27) — isolation and resume ride on the CLI's own flags. Passed
1423
1485
  // per turn: in the REPL each message is its own turn (see the manual).
1424
- this.ws5Overrides(options));
1486
+ { ...this.ws5Overrides(options), ...live.overrides }).finally(() => live.stop());
1425
1487
  // No-model fallback: the tool loop could not generate a single response
1426
1488
  // AND the rules assessed a high-confidence pipeline intent — run the
1427
1489
  // pipeline directly (rules decide only when the model is unavailable;
@@ -1456,7 +1518,8 @@ export class ChatCommand extends BaseCommand {
1456
1518
  // JSON blob, or the empty ```json fence the fallback transport leaves
1457
1519
  // behind) — see stripToolCallArtifacts.
1458
1520
  else if (answer.content.trim()) {
1459
- console.log('\n' + stripToolCallArtifacts(answer.content) + '\n');
1521
+ console.log('');
1522
+ presentAnswer(stripToolCallArtifacts(answer.content));
1460
1523
  }
1461
1524
  if (!process.stdin.isTTY) {
1462
1525
  await this.renderFollowups(answer.followups ?? [], false);
@@ -1470,12 +1533,14 @@ export class ChatCommand extends BaseCommand {
1470
1533
  const picked = await this.renderFollowups(singleAnswer.followups ?? [], true);
1471
1534
  if (!picked)
1472
1535
  break;
1536
+ const liveNext = this.liveAnswer(`nuvira · ${provider.name}${model ? ` / ${model}` : ''}`);
1473
1537
  const next = await this.runChatAnswer(picked, history, { type, provider, model }, options || {}, cacheEnabled, { auto: autoMode }, parseRequestSync(picked),
1474
1538
  // P5 — a picked followup continues the previous execution.
1475
- { continuation: true, ...this.ws5Overrides(options) });
1539
+ { continuation: true, ...this.ws5Overrides(options), ...liveNext.overrides }).finally(() => liveNext.stop());
1476
1540
  const nextText = stripToolCallArtifacts(next.content);
1477
1541
  if (nextText) {
1478
- console.log('\n' + nextText + '\n');
1542
+ console.log('');
1543
+ presentAnswer(nextText);
1479
1544
  // NOTE: no history.push here — runChatAnswer already recorded the
1480
1545
  // assistant turn. The old duplicate push gave every subsequent turn
1481
1546
  // TWO copies of the previous answer (relevance noise).
@@ -1565,13 +1630,16 @@ export class ChatCommand extends BaseCommand {
1565
1630
  const parsed = recordMetricTime('rule.parse.ms', () => parseRequestSync(message));
1566
1631
  const dispatchDecision = recordMetricTime('rule.dispatch.ms', () => resolvePipelineDispatch(parsed, { dev: this.devModeAuto, text: message }));
1567
1632
  const session = { type, provider, model: effectiveModel };
1633
+ // P7 — live preview for this turn (see `liveAnswer`).
1634
+ const live = this.liveAnswer(`nuvira · ${provider.name}${effectiveModel ? ` / ${effectiveModel}` : ''}`);
1568
1635
  const answer = await withLogCorrelation({ sessionId: chatSessionId }, () => recordMetricTime('llm.answer.ms', () => this.runChatAnswer(message, history, session, options || {}, cacheEnabled, { auto: autoMode }, parsed,
1569
1636
  // P5 — a picked followup (or a typed one that matches the last
1570
1637
  // suggestions) is a continuation, not a fresh independent request.
1571
1638
  {
1572
1639
  continuation: pickedFollowup || isSuggestedFollowup(message, lastFollowups),
1573
1640
  ...this.ws5Overrides(options),
1574
- })));
1641
+ ...live.overrides,
1642
+ }))).finally(() => live.stop());
1575
1643
  // No-model fallback: the tool loop could not generate a single response
1576
1644
  // AND the rules assessed a high-confidence pipeline intent — run the
1577
1645
  // pipeline directly (rules decide only when the model is unavailable).
@@ -1591,7 +1659,8 @@ export class ChatCommand extends BaseCommand {
1591
1659
  // followup pick becomes the next message). The user asked for the
1592
1660
  // content — the menu must never print before it.
1593
1661
  if (answer.content.trim()) {
1594
- console.log('\n' + answer.content + '\n');
1662
+ console.log('');
1663
+ presentAnswer(answer.content);
1595
1664
  }
1596
1665
  lastFollowups = answer.followups ?? [];
1597
1666
  const followupPrompt = await this.renderFollowups(lastFollowups, true);
@@ -2557,6 +2626,37 @@ export class ChatCommand extends BaseCommand {
2557
2626
  callModel: callModelWithTrace,
2558
2627
  // P2 — the empty-response handoff (see `requestModelSwitch` above).
2559
2628
  requestModelSwitch,
2629
+ // P5 — the SAME blip policy the thrown-empty path uses, reachable from
2630
+ // the loop's empty-response path too. A provider that answers 200 with
2631
+ // no content never throws, so it never reached
2632
+ // `generateWithTransientRetry` and its empty schedule was computed but
2633
+ // never spent: both live failures (trace-1791906998502-txddq4,
2634
+ // trace-1791907393457-7seewg) handed off after the loop's single retry
2635
+ // and landed on the local last resort. The plan knows whether waiting
2636
+ // is worth it (a proven pair, or alternatives that would de-escalate),
2637
+ // so the loop asks the CALLER rather than inventing a backoff.
2638
+ emptyResponsePatienceMs: ({ emptyStreak, deliveredWorkThisTurn }) => {
2639
+ try {
2640
+ const pair = {
2641
+ provider: session.type,
2642
+ model: this.lastAttempt?.model ?? session.model ?? 'default',
2643
+ };
2644
+ return planBlipPatience({
2645
+ current: pair,
2646
+ alternatives: failoverAlternatives(this.configManager, pair.provider),
2647
+ evidence: registryPatienceEvidence(pair.provider, pair.model),
2648
+ // An entry here means an EARLIER step of this turn already failed
2649
+ // on this pair — the same pair failing twice is a pattern, not a
2650
+ // blip, and patience collapses there.
2651
+ failedEarlierStep: this.turnAttempts.some((a) => a.provider === pair.provider && a.model === pair.model),
2652
+ deliveredWorkThisTurn,
2653
+ }).emptyResponseDelaysMs;
2654
+ }
2655
+ catch {
2656
+ // No evidence → no extra patience (the pre-P5 behaviour).
2657
+ return [];
2658
+ }
2659
+ },
2560
2660
  // C5 — `requestModelSwitch` installs the replacement on `session`, so
2561
2661
  // re-resolve the thread budget from the session AFTER a handoff: a
2562
2662
  // handoff to a smaller window is the case that overflows, and the
@@ -3514,6 +3614,10 @@ export class ChatCommand extends BaseCommand {
3514
3614
  // (`answered()`, and the walks that install what they served) are the
3515
3615
  // ones that own `session.model`.
3516
3616
  this.lastAttempt = { provider: typ, model: effectiveModel };
3617
+ // G5/P6 — and the trace's routing snapshot follows the ATTEMPT, so a step
3618
+ // can never record a pair the request did not go to (see
3619
+ // `noteServedRoute`).
3620
+ this.noteServedRoute(typ, effectiveModel ?? 'default');
3517
3621
  const nativeKey = `${typ}|${effectiveModel ?? ''}`;
3518
3622
  // Answer-quality resilience: a CONFUSED reply — the model talking about
3519
3623
  // the tool contract (e.g. apologizing that "the provided example call
@@ -3710,7 +3814,44 @@ export class ChatCommand extends BaseCommand {
3710
3814
  // success log per landed candidate — and now the failure KIND in the
3711
3815
  // line, so the console says what went wrong instead of only that it did.
3712
3816
  logger.warn(` ⚠️ ${session.provider.name} failed (${describeFailureKind(primaryKind)}) — trying the next auto candidate...`);
3713
- const failed = new Set([session.type]);
3817
+ /**
3818
+ * ── PAIR-SCOPED WALK: follow what is ROUTABLE, not one model per
3819
+ * provider ────────────────────────────────────────────────────────
3820
+ *
3821
+ * The walk used to track PROVIDERS: the failing provider was put in
3822
+ * `failed` and every re-route passed it as `excludeProviders`, so each
3823
+ * iteration could only ever land on a DIFFERENT provider — one model
3824
+ * tried per provider no matter how many that provider serves. Measured
3825
+ * live (trace-1791906998502-txddq4): a per-model 429 on
3826
+ * `gemini/gemma-4-31b-it` ended gemini's part of the turn, a `model not
3827
+ * found` on one openrouter id ended openrouter's, and the walk reached
3828
+ * the local last resort while ~370 routable pairs were never tried.
3829
+ *
3830
+ * The registry, the quota ledger and the exclusion filter all treat
3831
+ * these failures as PAIR-scoped (`recordActionFailure` parks the pair,
3832
+ * `ledger.parkModel` parks the model, and only
3833
+ * `PROVIDER_RATE_LIMIT_ESCALATION_MODELS` distinct models 429ing
3834
+ * escalates to a provider park). The walk was the one place
3835
+ * contradicting that, so it is the one place fixed here: it follows the
3836
+ * pair-scoped exclusions the bookkeeping just wrote, and only leaves a
3837
+ * provider when the EVIDENCE says the provider itself is out — a
3838
+ * transient/server failure, a provider-wide rate limit, a refused
3839
+ * account or a provider the registry has blocked.
3840
+ */
3841
+ const firstPair = `${this.lastAttempt?.provider ?? session.type}|${this.lastAttempt?.model ?? session.model ?? 'default'}`;
3842
+ const failedPairs = new Set([firstPair]);
3843
+ const failedProviders = new Set();
3844
+ try {
3845
+ // The bookkeeping already ran for the failure above: a provider still
3846
+ // carrying an ACTIVE provider-scoped exclusion is out for this walk,
3847
+ // whatever kind the failure was classified as.
3848
+ if ((this.sessionFailedProviders.get(session.type) ?? 0) > Date.now()) {
3849
+ failedProviders.add(session.type);
3850
+ }
3851
+ }
3852
+ catch {
3853
+ // Best-effort — evidence must never break the walk.
3854
+ }
3714
3855
  // Intent-aware escalation for the FAILOVER walk (the live junk path):
3715
3856
  // a mid-turn failure used to re-route on the bare message alone, so a
3716
3857
  // software turn whose first cloud provider died fell through to a tiny
@@ -3720,25 +3861,34 @@ export class ChatCommand extends BaseCommand {
3720
3861
  // applies here too — but NEVER drop a candidate the floor would keep,
3721
3862
  // so auto still cannot dead-end (local stays the last resort).
3722
3863
  const failoverRoutingText = routingText;
3723
- // Try ALL ranked candidates (no 3-candidate cap) — bounded by
3724
- // the number of known providers to prevent infinite loops.
3864
+ // Try ALL routable candidates (no 3-candidate cap) — bounded by a
3865
+ // fixed attempt count so a churning pool cannot spin the turn.
3725
3866
  const maxAttempts = 10;
3726
3867
  for (let i = 0; i < maxAttempts; i++) {
3727
3868
  let next = null;
3728
3869
  try {
3729
3870
  next = failoverRoutingText
3730
- ? await this.routeMessageAuto(message, [...failed], {
3871
+ ? await this.routeMessageAuto(message, [...failedProviders], {
3731
3872
  routingText: failoverRoutingText,
3732
3873
  fallbackFrom: firstType,
3874
+ excludePairs: [...failedPairs],
3733
3875
  })
3734
- : await this.routeMessageAuto(message, [...failed], { fallbackFrom: firstType });
3876
+ : await this.routeMessageAuto(message, [...failedProviders], {
3877
+ fallbackFrom: firstType,
3878
+ excludePairs: [...failedPairs],
3879
+ });
3735
3880
  }
3736
3881
  catch {
3737
3882
  break;
3738
3883
  }
3739
- if (!next || next.type === session.type || failed.has(next.type))
3884
+ if (!next)
3740
3885
  break;
3741
- failed.add(next.type);
3886
+ const nextPair = `${next.type}|${next.model ?? 'default'}`;
3887
+ // A pair this walk already tried means nothing NEW is routable — stop
3888
+ // rather than re-paying for a known-bad call.
3889
+ if (failedPairs.has(nextPair))
3890
+ break;
3891
+ failedPairs.add(nextPair);
3742
3892
  // Last-resort truthfulness: if even the agentic floor could not
3743
3893
  // avoid a weak model, say so ONCE so a degraded answer is never
3744
3894
  // mistaken for a real one (the tiny local model fabricated tool
@@ -3801,7 +3951,23 @@ export class ChatCommand extends BaseCommand {
3801
3951
  catch {
3802
3952
  // Best-effort — bookkeeping must never break the turn.
3803
3953
  }
3804
- logger.warn(` ⚠️ ${next.type}/${next.model ?? 'default'} failed (${describeFailureKind(nextKind)}) — trying the next auto candidate...`);
3954
+ // Is the PROVIDER out, or only this PAIR? The bookkeeping just
3955
+ // wrote the answer; read it rather than re-deriving the rule, so
3956
+ // the walk and the exclusion filter can never disagree.
3957
+ let providerOut = false;
3958
+ try {
3959
+ providerOut = (this.sessionFailedProviders.get(next.type) ?? 0) > Date.now();
3960
+ }
3961
+ catch {
3962
+ // Unknown scope → treat it as pair-scoped (the conservative
3963
+ // direction for staying routable).
3964
+ }
3965
+ if (providerOut)
3966
+ failedProviders.add(next.type);
3967
+ logger.warn(` ⚠️ ${next.type}/${next.model ?? 'default'} failed (${describeFailureKind(nextKind)}) — ` +
3968
+ (providerOut
3969
+ ? 'that provider is out; trying the next auto candidate...'
3970
+ : `trying ${next.type}'s next model, then the next provider...`));
3805
3971
  // Next candidate.
3806
3972
  }
3807
3973
  }
@@ -4165,6 +4331,44 @@ export class ChatCommand extends BaseCommand {
4165
4331
  * the ranked candidates and picks the first one whose isAvailable() passes —
4166
4332
  * so Auto routing never sends a request to a provider that would 401.
4167
4333
  */
4334
+ /**
4335
+ * Point the routing snapshot at the pair this step will ACTUALLY use.
4336
+ *
4337
+ * THE DEFECT THIS CLOSES (measured 2026-10-13). The snapshot was assigned once
4338
+ * per `routeMessageAuto` call, from the router's DECISION — before the
4339
+ * candidate walk had a chance to substitute a pair — so a step could record
4340
+ * `routing: gemini/gemini-3.1-flash-lite, agenticCapable: true` while the
4341
+ * request went to `local/deepseek-coder:latest`: the Trace tab, the console
4342
+ * line and the capability verdict all named a model the turn never ran, and the
4343
+ * disagreement was invisible (trace-1791907393457-7seewg). The pair that really
4344
+ * ran was in `lastAttempt` only.
4345
+ *
4346
+ * So the snapshot now FOLLOWS the attempt: provider/model are the pair being
4347
+ * asked, the capability verdict is recomputed for THAT pair (the field asks
4348
+ * "may the final routed model hold an agentic software task", so it must
4349
+ * describe the model that ran), and the router's intended pair is kept once as
4350
+ * `substitutedFor` so the substitution stays auditable instead of being erased.
4351
+ * The first substitution wins, because that is the DECISION the walk moved away
4352
+ * from — a later hop does not overwrite it with an intermediate pair.
4353
+ */
4354
+ noteServedRoute(provider, model) {
4355
+ const snap = this.lastRouteSnapshot;
4356
+ if (!snap)
4357
+ return;
4358
+ const served = `${provider}/${model}`;
4359
+ const intended = `${snap.provider}/${snap.model}`;
4360
+ const next = {
4361
+ ...snap,
4362
+ provider,
4363
+ model,
4364
+ agenticCapable: isAgenticCapableModel(model, provider),
4365
+ };
4366
+ if (snap.substitutedFor)
4367
+ next.substitutedFor = snap.substitutedFor;
4368
+ else if (served !== intended)
4369
+ next.substitutedFor = intended;
4370
+ this.lastRouteSnapshot = next;
4371
+ }
4168
4372
  async routeMessageAuto(message, excludeProviders = [], opts) {
4169
4373
  // The text ROUTING is decided from — the prior software ask for a bare
4170
4374
  // continuation, otherwise the message itself. `message` is used everywhere
@@ -4235,6 +4439,13 @@ export class ChatCommand extends BaseCommand {
4235
4439
  const decision = opts?.noCache === true
4236
4440
  ? resolveFresh()
4237
4441
  : withRoutingCache(cacheSignature, 30_000, resolveFresh);
4442
+ /**
4443
+ * Does this ask need CAPACITY (not just a healthy model)? One predicate for
4444
+ * the whole route, shared by the capability floor, the model-first override
4445
+ * and this walk's per-provider model resolution — so a `default` model is
4446
+ * resolved capability-first exactly when the ask is agentic.
4447
+ */
4448
+ const agenticAsk = isAgenticTask(decision.complexity, decision.taskProfile);
4238
4449
  // G5 — record the routing snapshot now (the winner + why), so the reasoning
4239
4450
  // trace for this turn can show the decision instead of a blank column.
4240
4451
  // P3 — the TASK this turn belongs to, as far as model continuity is
@@ -4362,6 +4573,10 @@ export class ChatCommand extends BaseCommand {
4362
4573
  if (isModelExcluded(prov, model))
4363
4574
  return;
4364
4575
  const key = `${prov}|${model}`;
4576
+ // Pairs this WALK already tried (see `opts.excludePairs`) — a pair-scoped
4577
+ // exclusion, so a provider's remaining models stay reachable.
4578
+ if (opts?.excludePairs?.includes(key))
4579
+ return;
4365
4580
  if (seenPairs.has(key))
4366
4581
  return;
4367
4582
  // NOTE: deliberately NO registry-usability skip here. `resolveWorkingModel`
@@ -4412,9 +4627,18 @@ export class ChatCommand extends BaseCommand {
4412
4627
  try {
4413
4628
  const resolved = resolveProvider(this.configManager, candidate.provider);
4414
4629
  if (await resolved.provider.isAvailable()) {
4630
+ // A `default` model is resolved by the router, and for a task that
4631
+ // NEEDS capacity that resolution is told so: the health ranking it
4632
+ // otherwise follows picks the fastest model, which is how a keyless
4633
+ // local rung ended up on `local/deepseek-coder:latest` (a
4634
+ // confabulation) with a verified `gpt-oss:120b-cloud` unused
4635
+ // (trace-1791907393457-7seewg). `agenticAsk` is the same predicate the
4636
+ // router's own capability floor uses, so the two cannot disagree.
4415
4637
  const desired = candidate.model !== 'default'
4416
4638
  ? candidate.model
4417
- : getAutoRouter().resolveModel(candidate.provider, 'chat', this.configManager);
4639
+ : getAutoRouter().resolveModel(candidate.provider, 'chat', this.configManager, undefined, {
4640
+ agenticAsk,
4641
+ });
4418
4642
  // Model health: only use models that actually exist on the provider.
4419
4643
  // A provider's pinned config.model can be deprecated or a placeholder
4420
4644
  // (e.g. gemini-2.0-flash-exp → 404) — repair to a live model. The pair