agent-nuvira 3.5.2 → 3.5.6

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 (155) hide show
  1. package/README.md +66 -0
  2. package/dist/cli/chat.d.ts.map +1 -1
  3. package/dist/cli/chat.js +72 -19
  4. package/dist/cli/chat.js.map +1 -1
  5. package/dist/cli/config.d.ts.map +1 -1
  6. package/dist/cli/config.js +17 -3
  7. package/dist/cli/config.js.map +1 -1
  8. package/dist/cli/execute.d.ts.map +1 -1
  9. package/dist/cli/execute.js +63 -22
  10. package/dist/cli/execute.js.map +1 -1
  11. package/dist/cli/failover-runner.js +4 -4
  12. package/dist/cli/failover-runner.js.map +1 -1
  13. package/dist/cli/gateway.js +13 -13
  14. package/dist/cli/gateway.js.map +1 -1
  15. package/dist/cli/loop-executor.d.ts +22 -0
  16. package/dist/cli/loop-executor.d.ts.map +1 -1
  17. package/dist/cli/loop-executor.js +56 -12
  18. package/dist/cli/loop-executor.js.map +1 -1
  19. package/dist/cli/stats.d.ts +62 -4
  20. package/dist/cli/stats.d.ts.map +1 -1
  21. package/dist/cli/stats.js +282 -5
  22. package/dist/cli/stats.js.map +1 -1
  23. package/dist/cli/ui/index.d.ts +2 -2
  24. package/dist/cli/ui/index.d.ts.map +1 -1
  25. package/dist/cli/ui/index.js +1 -1
  26. package/dist/cli/ui/index.js.map +1 -1
  27. package/dist/cli/ui/presenter.d.ts +43 -0
  28. package/dist/cli/ui/presenter.d.ts.map +1 -1
  29. package/dist/cli/ui/presenter.js +88 -1
  30. package/dist/cli/ui/presenter.js.map +1 -1
  31. package/dist/config/manager.d.ts +29 -1
  32. package/dist/config/manager.d.ts.map +1 -1
  33. package/dist/config/manager.js +178 -143
  34. package/dist/config/manager.js.map +1 -1
  35. package/dist/config/paths.d.ts +48 -1
  36. package/dist/config/paths.d.ts.map +1 -1
  37. package/dist/config/paths.js +59 -9
  38. package/dist/config/paths.js.map +1 -1
  39. package/dist/config/service-catalog.js +1 -1
  40. package/dist/config/service-catalog.js.map +1 -1
  41. package/dist/config/service-probe.js +1 -1
  42. package/dist/config/service-probe.js.map +1 -1
  43. package/dist/config/types.d.ts +22 -0
  44. package/dist/config/types.d.ts.map +1 -1
  45. package/dist/gateway/adapters.js +8 -8
  46. package/dist/gateway/adapters.js.map +1 -1
  47. package/dist/gateway/registry.js +1 -1
  48. package/dist/gateway/registry.js.map +1 -1
  49. package/dist/learning/auto-router.d.ts +30 -4
  50. package/dist/learning/auto-router.d.ts.map +1 -1
  51. package/dist/learning/auto-router.js +54 -38
  52. package/dist/learning/auto-router.js.map +1 -1
  53. package/dist/learning/cost-classification.d.ts +188 -0
  54. package/dist/learning/cost-classification.d.ts.map +1 -0
  55. package/dist/learning/cost-classification.js +294 -0
  56. package/dist/learning/cost-classification.js.map +1 -0
  57. package/dist/learning/cost-ledger-maintenance.d.ts +122 -0
  58. package/dist/learning/cost-ledger-maintenance.d.ts.map +1 -0
  59. package/dist/learning/cost-ledger-maintenance.js +289 -0
  60. package/dist/learning/cost-ledger-maintenance.js.map +1 -0
  61. package/dist/learning/cost-reconcile.d.ts +160 -0
  62. package/dist/learning/cost-reconcile.d.ts.map +1 -0
  63. package/dist/learning/cost-reconcile.js +238 -0
  64. package/dist/learning/cost-reconcile.js.map +1 -0
  65. package/dist/learning/cost-tracker.d.ts +134 -13
  66. package/dist/learning/cost-tracker.d.ts.map +1 -1
  67. package/dist/learning/cost-tracker.js +190 -68
  68. package/dist/learning/cost-tracker.js.map +1 -1
  69. package/dist/learning/model-pricing.d.ts +240 -0
  70. package/dist/learning/model-pricing.d.ts.map +1 -0
  71. package/dist/learning/model-pricing.js +309 -0
  72. package/dist/learning/model-pricing.js.map +1 -0
  73. package/dist/learning/model-selection.d.ts +15 -0
  74. package/dist/learning/model-selection.d.ts.map +1 -1
  75. package/dist/learning/model-selection.js +22 -2
  76. package/dist/learning/model-selection.js.map +1 -1
  77. package/dist/learning/model-warmup.d.ts.map +1 -1
  78. package/dist/learning/model-warmup.js +4 -1
  79. package/dist/learning/model-warmup.js.map +1 -1
  80. package/dist/learning/session-store.d.ts +1 -5
  81. package/dist/learning/session-store.d.ts.map +1 -1
  82. package/dist/learning/session-store.js +10 -1
  83. package/dist/learning/session-store.js.map +1 -1
  84. package/dist/learning/step-checkpoint.d.ts +32 -3
  85. package/dist/learning/step-checkpoint.d.ts.map +1 -1
  86. package/dist/learning/step-checkpoint.js +33 -4
  87. package/dist/learning/step-checkpoint.js.map +1 -1
  88. package/dist/mcp/settings.d.ts +15 -3
  89. package/dist/mcp/settings.d.ts.map +1 -1
  90. package/dist/mcp/settings.js +30 -15
  91. package/dist/mcp/settings.js.map +1 -1
  92. package/dist/parity/drivers.d.ts.map +1 -1
  93. package/dist/parity/drivers.js +31 -5
  94. package/dist/parity/drivers.js.map +1 -1
  95. package/dist/tools/child-agent-runtime.d.ts.map +1 -1
  96. package/dist/tools/child-agent-runtime.js +13 -7
  97. package/dist/tools/child-agent-runtime.js.map +1 -1
  98. package/dist/tools/followup-utils.d.ts +36 -0
  99. package/dist/tools/followup-utils.d.ts.map +1 -1
  100. package/dist/tools/followup-utils.js +66 -0
  101. package/dist/tools/followup-utils.js.map +1 -1
  102. package/dist/tools/modality/browser.js +2 -2
  103. package/dist/tools/modality/browser.js.map +1 -1
  104. package/dist/tools/modality/image-gen.d.ts +1 -1
  105. package/dist/tools/modality/image-gen.js +1 -1
  106. package/dist/tools/modality/image-providers.js +1 -1
  107. package/dist/tools/modality/image-providers.js.map +1 -1
  108. package/dist/tools/modality/vision.d.ts +1 -1
  109. package/dist/tools/modality/vision.js +1 -1
  110. package/dist/tools/modality/voice.js +2 -2
  111. package/dist/tools/modality/voice.js.map +1 -1
  112. package/dist/tools/neutts-synth.d.ts +3 -3
  113. package/dist/tools/neutts-synth.js +3 -3
  114. package/dist/tools/neutts-synth.js.map +1 -1
  115. package/dist/tools/process-liveness.d.ts +50 -0
  116. package/dist/tools/process-liveness.d.ts.map +1 -1
  117. package/dist/tools/process-liveness.js +82 -9
  118. package/dist/tools/process-liveness.js.map +1 -1
  119. package/dist/tools/registry.d.ts +1 -1
  120. package/dist/tools/registry.d.ts.map +1 -1
  121. package/dist/tools/registry.js +27 -4
  122. package/dist/tools/registry.js.map +1 -1
  123. package/dist/tools/run-registry.d.ts.map +1 -1
  124. package/dist/tools/run-registry.js +14 -1
  125. package/dist/tools/run-registry.js.map +1 -1
  126. package/dist/tools/run-terminal.d.ts.map +1 -1
  127. package/dist/tools/run-terminal.js +18 -1
  128. package/dist/tools/run-terminal.js.map +1 -1
  129. package/dist/tools/tool-loop.d.ts.map +1 -1
  130. package/dist/tools/tool-loop.js +5 -3
  131. package/dist/tools/tool-loop.js.map +1 -1
  132. package/dist/tools/web-research.d.ts +1 -1
  133. package/dist/tools/web-research.js +3 -3
  134. package/dist/tools/web-research.js.map +1 -1
  135. package/dist/web-dashboard/chat-console.d.ts +56 -0
  136. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  137. package/dist/web-dashboard/chat-console.js +57 -1
  138. package/dist/web-dashboard/chat-console.js.map +1 -1
  139. package/dist/web-dashboard/server.d.ts.map +1 -1
  140. package/dist/web-dashboard/server.js +122 -2
  141. package/dist/web-dashboard/server.js.map +1 -1
  142. package/dist/web-dashboard/src/types.d.ts +63 -0
  143. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  144. package/dist/web-dashboard/task-runner.d.ts +17 -1
  145. package/dist/web-dashboard/task-runner.d.ts.map +1 -1
  146. package/dist/web-dashboard/task-runner.js +84 -9
  147. package/dist/web-dashboard/task-runner.js.map +1 -1
  148. package/package.json +1 -1
  149. package/src/web-dashboard/public/assets/index-DeSsNU94.css +1 -0
  150. package/src/web-dashboard/public/assets/index-Do_O67Kv.js +236 -0
  151. package/src/web-dashboard/public/assets/index-Do_O67Kv.js.map +1 -0
  152. package/src/web-dashboard/public/index.html +2 -2
  153. package/src/web-dashboard/public/assets/index-DycGBWwy.js +0 -236
  154. package/src/web-dashboard/public/assets/index-DycGBWwy.js.map +0 -1
  155. package/src/web-dashboard/public/assets/index-aO3aG7ex.css +0 -1
@@ -26,6 +26,7 @@ import { ConfigManager } from '../config/manager.js';
26
26
  import { parseRuntimeSpec } from '../mcp/runtime.js';
27
27
  import { runAllChecks } from '../cli/doctor.js';
28
28
  import { getAutoRouter } from '../learning/auto-router.js';
29
+ import { classifyEntries, } from '../learning/cost-classification.js';
29
30
  import { acceptanceSummary, collectLabelledTurns, serializeLabelledTurns, parseCorpusText, detectCorpusFormat, mergeImportedLabels, } from '../learning/acceptance-model.js';
30
31
  import { readDecisions, recallDecisions, reviseDecision } from '../learning/decision-log.js';
31
32
  import { degradedCallsFromTraces } from '../learning/reasoning-trace.js';
@@ -1513,9 +1514,52 @@ function readCostData() {
1513
1514
  if (!data?.entries) {
1514
1515
  // The empty state deliberately omits `recent` entirely (the dashboard reads
1515
1516
  // a missing list as "nothing recorded"), matching the other zero counters.
1516
- return { totalRequests: 0, totalCost: 0, byProvider: {}, byModel: {} };
1517
+ return {
1518
+ totalRequests: 0,
1519
+ totalCost: 0,
1520
+ byProvider: {},
1521
+ byModel: {},
1522
+ billedUsd: 0,
1523
+ billedReportedUsd: 0,
1524
+ billedListedUsd: 0,
1525
+ unverifiedListedUsd: 0,
1526
+ notBilledValueUsd: 0,
1527
+ unpricedCalls: 0,
1528
+ unpricedTokens: 0,
1529
+ recomputedCalls: 0,
1530
+ testOriginCalls: 0,
1531
+ // No invoice has been checked yet — stated, not implied.
1532
+ reconciliations: [],
1533
+ };
1517
1534
  }
1518
1535
  const entries = data.entries;
1536
+ // ── The classified view (ONE judgement for every surface) ────────────────
1537
+ // The Cost page's headline used to be `totalCost` — the sum of a column the
1538
+ // ledger had priced from its own hardcoded table — printed under the words
1539
+ // "Total Spent". It is now split by EVIDENCE: what was billed (provider-reported
1540
+ // exact + list-priced with a declared paid account), the value a free tier
1541
+ // absorbed, the list-priced rows whose tier is undeclared, and the calls with no
1542
+ // price at all. Test-origin rows are excluded here: a row written by a test run
1543
+ // is not the user's usage (the model registry takes the same posture).
1544
+ const classified = classifyEntries(entries, {
1545
+ excludeTestOrigin: true,
1546
+ });
1547
+ const byProviderBilled = {};
1548
+ const byProviderUnverified = {};
1549
+ const byProviderValue = {};
1550
+ const byProviderUnpricedCalls = {};
1551
+ const byModelBilled = {};
1552
+ const byModelValue = {};
1553
+ for (const [provider, t] of Object.entries(classified.byProvider)) {
1554
+ byProviderBilled[provider] = t.billedUsd;
1555
+ byProviderUnverified[provider] = t.unverifiedListedUsd;
1556
+ byProviderValue[provider] = t.notBilledValueUsd;
1557
+ byProviderUnpricedCalls[provider] = t.unpricedCalls;
1558
+ }
1559
+ for (const [model, t] of Object.entries(classified.byModel)) {
1560
+ byModelBilled[model] = t.billedUsd;
1561
+ byModelValue[model] = t.notBilledValueUsd;
1562
+ }
1519
1563
  const totalCost = entries.reduce((s, e) => s + (typeof e.costUsd === 'number' ? e.costUsd : 0), 0);
1520
1564
  const totalTokens = entries.reduce((s, e) => s + (typeof e.totalTokens === 'number' ? e.totalTokens : 0), 0);
1521
1565
  const byProvider = {};
@@ -1567,9 +1611,53 @@ function readCostData() {
1567
1611
  measured: e.measured === true,
1568
1612
  reported: e.costReported === true,
1569
1613
  }));
1614
+ // ── Invoice checks: the only EXTERNAL figures on this page ───────────────
1615
+ // Written by `nuvira stats cost reconcile` when the operator enters the
1616
+ // provider's own charge for a window. Everything else here is an estimate of
1617
+ // money owed; this is the one place the page can be compared against what was
1618
+ // ACTUALLY charged. Read straight from the file (no module import) so the
1619
+ // dashboard keeps resolving its own memory dir, and capped like `recent`.
1620
+ const reconciliationFile = readJSON(join(MEMORY_DIR, 'cost-reconciliations.json'));
1621
+ const reconciliations = (Array.isArray(reconciliationFile?.reconciliations) ? reconciliationFile.reconciliations : [])
1622
+ .filter((r) => r && typeof r.provider === 'string' && typeof r.invoiceUsd === 'number')
1623
+ .slice(0, 20)
1624
+ .map((r) => ({
1625
+ provider: r.provider,
1626
+ invoiceUsd: r.invoiceUsd,
1627
+ billedUsd: r.billedUsd,
1628
+ deltaUsd: r.deltaUsd,
1629
+ verdict: r.verdict,
1630
+ since: r.since,
1631
+ until: r.until,
1632
+ recordedAt: r.recordedAt,
1633
+ ...(r.note ? { note: r.note } : {}),
1634
+ ...(r.tierEvidence ? { tier: r.tierEvidence.tier } : {}),
1635
+ }));
1570
1636
  return {
1571
1637
  totalRequests: entries.length,
1572
1638
  totalCost: Math.round(totalCost * 100000) / 100000,
1639
+ // The evidence-backed figures. `totalCost` above is kept for compatibility
1640
+ // (it is the ledger total as recorded, including rows priced by the retired
1641
+ // hardcoded table); these are what the page headlines.
1642
+ billedUsd: classified.billedUsd,
1643
+ billedReportedUsd: classified.billedReportedUsd,
1644
+ billedListedUsd: classified.billedListedUsd,
1645
+ billedReportedCalls: classified.billedReportedCalls,
1646
+ billedListedCalls: classified.billedListedCalls,
1647
+ unverifiedListedUsd: classified.unverifiedListedUsd,
1648
+ unverifiedListedCalls: classified.unverifiedListedCalls,
1649
+ notBilledValueUsd: classified.notBilledValueUsd,
1650
+ notBilledValueCalls: classified.notBilledValueCalls,
1651
+ unpricedCalls: classified.unpricedCalls,
1652
+ unpricedTokens: classified.unpricedTokens,
1653
+ recomputedCalls: classified.recomputedCalls,
1654
+ testOriginCalls: classified.testOriginCalls,
1655
+ byProviderBilled,
1656
+ byProviderUnverified,
1657
+ byProviderValue,
1658
+ byProviderUnpricedCalls,
1659
+ byModelBilled,
1660
+ byModelValue,
1573
1661
  totalTokens,
1574
1662
  byProvider,
1575
1663
  byModel,
@@ -1581,6 +1669,7 @@ function readCostData() {
1581
1669
  estimatedCost: Math.round(estimatedCost * 100000) / 100000,
1582
1670
  reportedCalls,
1583
1671
  reportedCost: Math.round(reportedCost * 100000) / 100000,
1672
+ reconciliations,
1584
1673
  recent,
1585
1674
  };
1586
1675
  }
@@ -7216,7 +7305,27 @@ function handleRequest(req, res) {
7216
7305
  // `busy` lets a client that reloaded mid-turn know the answer is still being
7217
7306
  // produced, so it can keep the bubble alive and poll instead of showing a
7218
7307
  // finished-looking thread.
7219
- writeJson(res, 200, { ok: true, session: { id, ...rec, busy: chatConsole.isBusy(id) } });
7308
+ // `pendingQuestion` rides with the transcript because a reload has to be
7309
+ // able to SEE an open question, not just guess at it from `busy`. The turn
7310
+ // holding for an answer reports `busy: true` exactly like one that is
7311
+ // working, so without this the resumed page showed "⏳ Still working on the
7312
+ // server" for a turn that was waiting on the user (measured 2026-10-14:
7313
+ // trace-1791996357488-wpm352 sat in `ask_user` for 5m02s and was cancelled
7314
+ // with the question never on screen).
7315
+ // `busySince` is when the RUNNING turn started, so a client that gave up on
7316
+ // its own POST (a 5-minute ceiling) or reloaded mid-turn reports how long
7317
+ // the wait really is rather than counting from whenever it attached
7318
+ // (measured 2026-10-14: a 664s turn shown as "1m 25s elapsed").
7319
+ writeJson(res, 200, {
7320
+ ok: true,
7321
+ session: {
7322
+ id,
7323
+ ...rec,
7324
+ busy: chatConsole.isBusy(id),
7325
+ ...(chatConsole.busySince(id) !== null ? { busySince: chatConsole.busySince(id) } : {}),
7326
+ ...(chatConsole.pendingQuestionFor(id) ? { pendingQuestion: chatConsole.pendingQuestionFor(id) } : {}),
7327
+ },
7328
+ });
7220
7329
  return;
7221
7330
  }
7222
7331
  // GET /api/continuity — the stored session snapshots + the semantic recall
@@ -7949,6 +8058,17 @@ function handleRequest(req, res) {
7949
8058
  'X-Accel-Buffering': 'no',
7950
8059
  });
7951
8060
  res.write(`event: init\ndata: ${JSON.stringify({ sessionId })}\n\n`);
8061
+ // A question asked BEFORE this client attached is still waiting for an
8062
+ // answer, and the turn will hold until one arrives. Replaying it here is
8063
+ // what makes a reload (or a second tab) able to ANSWER it: without this the
8064
+ // new page shows a "still working" notice and no choice card at all, while
8065
+ // the turn waits on a reply the page has no way to send — the exact
8066
+ // "the model asked something but nothing appeared on screen" report
8067
+ // (2026-10-14, trace-1791996357488-wpm352, 5m02s in `ask_user`).
8068
+ const pendingQuestion = chatConsole.pendingQuestionFor(sessionId);
8069
+ if (pendingQuestion) {
8070
+ res.write(`event: question\ndata: ${JSON.stringify(pendingQuestion)}\n\n`);
8071
+ }
7952
8072
  const heartbeat = setInterval(() => {
7953
8073
  try {
7954
8074
  res.write(': heartbeat\n\n');