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.
- package/README.md +66 -0
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +72 -19
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +17 -3
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/execute.js +63 -22
- package/dist/cli/execute.js.map +1 -1
- package/dist/cli/failover-runner.js +4 -4
- package/dist/cli/failover-runner.js.map +1 -1
- package/dist/cli/gateway.js +13 -13
- package/dist/cli/gateway.js.map +1 -1
- package/dist/cli/loop-executor.d.ts +22 -0
- package/dist/cli/loop-executor.d.ts.map +1 -1
- package/dist/cli/loop-executor.js +56 -12
- package/dist/cli/loop-executor.js.map +1 -1
- package/dist/cli/stats.d.ts +62 -4
- package/dist/cli/stats.d.ts.map +1 -1
- package/dist/cli/stats.js +282 -5
- package/dist/cli/stats.js.map +1 -1
- package/dist/cli/ui/index.d.ts +2 -2
- package/dist/cli/ui/index.d.ts.map +1 -1
- package/dist/cli/ui/index.js +1 -1
- package/dist/cli/ui/index.js.map +1 -1
- package/dist/cli/ui/presenter.d.ts +43 -0
- package/dist/cli/ui/presenter.d.ts.map +1 -1
- package/dist/cli/ui/presenter.js +88 -1
- package/dist/cli/ui/presenter.js.map +1 -1
- package/dist/config/manager.d.ts +29 -1
- package/dist/config/manager.d.ts.map +1 -1
- package/dist/config/manager.js +178 -143
- package/dist/config/manager.js.map +1 -1
- package/dist/config/paths.d.ts +48 -1
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +59 -9
- package/dist/config/paths.js.map +1 -1
- package/dist/config/service-catalog.js +1 -1
- package/dist/config/service-catalog.js.map +1 -1
- package/dist/config/service-probe.js +1 -1
- package/dist/config/service-probe.js.map +1 -1
- package/dist/config/types.d.ts +22 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/gateway/adapters.js +8 -8
- package/dist/gateway/adapters.js.map +1 -1
- package/dist/gateway/registry.js +1 -1
- package/dist/gateway/registry.js.map +1 -1
- package/dist/learning/auto-router.d.ts +30 -4
- package/dist/learning/auto-router.d.ts.map +1 -1
- package/dist/learning/auto-router.js +54 -38
- package/dist/learning/auto-router.js.map +1 -1
- package/dist/learning/cost-classification.d.ts +188 -0
- package/dist/learning/cost-classification.d.ts.map +1 -0
- package/dist/learning/cost-classification.js +294 -0
- package/dist/learning/cost-classification.js.map +1 -0
- package/dist/learning/cost-ledger-maintenance.d.ts +122 -0
- package/dist/learning/cost-ledger-maintenance.d.ts.map +1 -0
- package/dist/learning/cost-ledger-maintenance.js +289 -0
- package/dist/learning/cost-ledger-maintenance.js.map +1 -0
- package/dist/learning/cost-reconcile.d.ts +160 -0
- package/dist/learning/cost-reconcile.d.ts.map +1 -0
- package/dist/learning/cost-reconcile.js +238 -0
- package/dist/learning/cost-reconcile.js.map +1 -0
- package/dist/learning/cost-tracker.d.ts +134 -13
- package/dist/learning/cost-tracker.d.ts.map +1 -1
- package/dist/learning/cost-tracker.js +190 -68
- package/dist/learning/cost-tracker.js.map +1 -1
- package/dist/learning/model-pricing.d.ts +240 -0
- package/dist/learning/model-pricing.d.ts.map +1 -0
- package/dist/learning/model-pricing.js +309 -0
- package/dist/learning/model-pricing.js.map +1 -0
- package/dist/learning/model-selection.d.ts +15 -0
- package/dist/learning/model-selection.d.ts.map +1 -1
- package/dist/learning/model-selection.js +22 -2
- package/dist/learning/model-selection.js.map +1 -1
- package/dist/learning/model-warmup.d.ts.map +1 -1
- package/dist/learning/model-warmup.js +4 -1
- package/dist/learning/model-warmup.js.map +1 -1
- package/dist/learning/session-store.d.ts +1 -5
- package/dist/learning/session-store.d.ts.map +1 -1
- package/dist/learning/session-store.js +10 -1
- package/dist/learning/session-store.js.map +1 -1
- package/dist/learning/step-checkpoint.d.ts +32 -3
- package/dist/learning/step-checkpoint.d.ts.map +1 -1
- package/dist/learning/step-checkpoint.js +33 -4
- package/dist/learning/step-checkpoint.js.map +1 -1
- package/dist/mcp/settings.d.ts +15 -3
- package/dist/mcp/settings.d.ts.map +1 -1
- package/dist/mcp/settings.js +30 -15
- package/dist/mcp/settings.js.map +1 -1
- package/dist/parity/drivers.d.ts.map +1 -1
- package/dist/parity/drivers.js +31 -5
- package/dist/parity/drivers.js.map +1 -1
- package/dist/tools/child-agent-runtime.d.ts.map +1 -1
- package/dist/tools/child-agent-runtime.js +13 -7
- package/dist/tools/child-agent-runtime.js.map +1 -1
- package/dist/tools/followup-utils.d.ts +36 -0
- package/dist/tools/followup-utils.d.ts.map +1 -1
- package/dist/tools/followup-utils.js +66 -0
- package/dist/tools/followup-utils.js.map +1 -1
- package/dist/tools/modality/browser.js +2 -2
- package/dist/tools/modality/browser.js.map +1 -1
- package/dist/tools/modality/image-gen.d.ts +1 -1
- package/dist/tools/modality/image-gen.js +1 -1
- package/dist/tools/modality/image-providers.js +1 -1
- package/dist/tools/modality/image-providers.js.map +1 -1
- package/dist/tools/modality/vision.d.ts +1 -1
- package/dist/tools/modality/vision.js +1 -1
- package/dist/tools/modality/voice.js +2 -2
- package/dist/tools/modality/voice.js.map +1 -1
- package/dist/tools/neutts-synth.d.ts +3 -3
- package/dist/tools/neutts-synth.js +3 -3
- package/dist/tools/neutts-synth.js.map +1 -1
- package/dist/tools/process-liveness.d.ts +50 -0
- package/dist/tools/process-liveness.d.ts.map +1 -1
- package/dist/tools/process-liveness.js +82 -9
- package/dist/tools/process-liveness.js.map +1 -1
- package/dist/tools/registry.d.ts +1 -1
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +27 -4
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/run-registry.d.ts.map +1 -1
- package/dist/tools/run-registry.js +14 -1
- package/dist/tools/run-registry.js.map +1 -1
- package/dist/tools/run-terminal.d.ts.map +1 -1
- package/dist/tools/run-terminal.js +18 -1
- package/dist/tools/run-terminal.js.map +1 -1
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +5 -3
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/tools/web-research.d.ts +1 -1
- package/dist/tools/web-research.js +3 -3
- package/dist/tools/web-research.js.map +1 -1
- package/dist/web-dashboard/chat-console.d.ts +56 -0
- package/dist/web-dashboard/chat-console.d.ts.map +1 -1
- package/dist/web-dashboard/chat-console.js +57 -1
- package/dist/web-dashboard/chat-console.js.map +1 -1
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +122 -2
- package/dist/web-dashboard/server.js.map +1 -1
- package/dist/web-dashboard/src/types.d.ts +63 -0
- package/dist/web-dashboard/src/types.d.ts.map +1 -1
- package/dist/web-dashboard/task-runner.d.ts +17 -1
- package/dist/web-dashboard/task-runner.d.ts.map +1 -1
- package/dist/web-dashboard/task-runner.js +84 -9
- package/dist/web-dashboard/task-runner.js.map +1 -1
- package/package.json +1 -1
- package/src/web-dashboard/public/assets/index-DeSsNU94.css +1 -0
- package/src/web-dashboard/public/assets/index-Do_O67Kv.js +236 -0
- package/src/web-dashboard/public/assets/index-Do_O67Kv.js.map +1 -0
- package/src/web-dashboard/public/index.html +2 -2
- package/src/web-dashboard/public/assets/index-DycGBWwy.js +0 -236
- package/src/web-dashboard/public/assets/index-DycGBWwy.js.map +0 -1
- package/src/web-dashboard/public/assets/index-aO3aG7ex.css +0 -1
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost reconciliation — the ONLY way the word "actual" can be earned.
|
|
3
|
+
*
|
|
4
|
+
* WHAT THIS REPLACES. Every figure the ledger reports is, at best, an ESTIMATE of
|
|
5
|
+
* money owed: a provider-reported per-call cost is exact about the call, and a
|
|
6
|
+
* list price on a declared-`paid` account is a guess at the bill. Neither is the
|
|
7
|
+
* bill. The ledger cannot see one, so the honest headline is "billed by evidence
|
|
8
|
+
* — $X" and never "you paid $X". This module closes that gap the only way it can
|
|
9
|
+
* be closed: the operator reads the provider's OWN number off the invoice and
|
|
10
|
+
* enters it, and everything else here is arithmetic on two figures that came from
|
|
11
|
+
* outside this machine.
|
|
12
|
+
*
|
|
13
|
+
* WHAT IT IS NOT. It never guesses an invoice, never scales one, and never
|
|
14
|
+
* "adjusts" the ledger to match. It reports the difference and what the
|
|
15
|
+
* difference most likely consists of — unpriced calls, calls whose list price was
|
|
16
|
+
* never claimed as spend (an undeclared billing tier), or rows the ledger is
|
|
17
|
+
* missing.
|
|
18
|
+
*
|
|
19
|
+
* ─── THE BILLING FACT, EARNED (read before changing tierEvidence) ───────────
|
|
20
|
+
*
|
|
21
|
+
* `providers.<id>.billingTier` decides whether a list-priced call is money owed
|
|
22
|
+
* (`paid`) or value absorbed (`free`/`subscription`), and it is the single fact
|
|
23
|
+
* that moves the headline the most. Being user-declared, it is an assumption —
|
|
24
|
+
* which is exactly what this change is here to remove. An invoice is evidence,
|
|
25
|
+
* so this module states what the invoice PROVES, and the CLI refuses to record a
|
|
26
|
+
* tier the invoice contradicts:
|
|
27
|
+
*
|
|
28
|
+
* - $0 charged across N calls in the window, and nothing billed by evidence
|
|
29
|
+
* → the key is not being charged per call: `free` is EVIDENCED.
|
|
30
|
+
* - A charge that matches the per-call costs the provider itself reported
|
|
31
|
+
* → the key is metered and billed: `paid` is EVIDENCED.
|
|
32
|
+
* - Anything else (a flat fee, a discounted charge, a mismatch) proves only
|
|
33
|
+
* what it says: the key IS charged. `subscription` and `paid` cannot be told
|
|
34
|
+
* apart from one invoice line, so no tier is claimed — the operator picks,
|
|
35
|
+
* and the CLI says why it is asking rather than picking for them.
|
|
36
|
+
*
|
|
37
|
+
* A period that has not closed yet must not be reconciled against (`--days` on a
|
|
38
|
+
* running month reads a partial invoice). The window is always printed with the
|
|
39
|
+
* result so the comparison can be judged, and `--until` exists to pin it.
|
|
40
|
+
*/
|
|
41
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
42
|
+
import { dirname, join } from 'node:path';
|
|
43
|
+
import { envBuff, resolveNuviraHome } from '../config/paths.js';
|
|
44
|
+
import { classifyEntries } from './cost-classification.js';
|
|
45
|
+
/**
|
|
46
|
+
* How close is "the same money". An invoice rounds to cents and the ledger's
|
|
47
|
+
* list prices are estimates, so exact equality would report `match` essentially
|
|
48
|
+
* never — and a verdict that is always "mismatch" teaches the operator to ignore
|
|
49
|
+
* it. The band is 1% of the larger figure, floored at one cent so a tiny account
|
|
50
|
+
* is not judged on fractions of a cent.
|
|
51
|
+
*/
|
|
52
|
+
function toleranceFor(invoiceUsd, billedUsd) {
|
|
53
|
+
const base = Math.max(Math.abs(invoiceUsd), Math.abs(billedUsd));
|
|
54
|
+
return Math.max(0.01, Math.round(base * 0.01 * 100000) / 100000);
|
|
55
|
+
}
|
|
56
|
+
const round6 = (n) => Math.round(n * 100000) / 100000;
|
|
57
|
+
// ─── The comparison ─────────────────────────────────────────────────────────
|
|
58
|
+
/**
|
|
59
|
+
* Reconcile a provider's invoice against the ledger rows in the same window.
|
|
60
|
+
*
|
|
61
|
+
* Pure with respect to the ledger: it reads rows and returns a report; nothing is
|
|
62
|
+
* written and no row is modified. `provider` matching is exact — a per-provider
|
|
63
|
+
* invoice must never be compared against a whole-profile total.
|
|
64
|
+
*
|
|
65
|
+
* Test-origin rows are excluded from EVERY figure (a fixture call is not a charge)
|
|
66
|
+
* and counted in `testOriginCalls`, so a window can be checked for the rows that
|
|
67
|
+
* were hidden rather than silently shrinking.
|
|
68
|
+
*/
|
|
69
|
+
export function reconcileEntries(claim, entries, ctx) {
|
|
70
|
+
const since = claim.since;
|
|
71
|
+
const until = claim.until;
|
|
72
|
+
// Half-open [since, until) — see `InvoiceClaim.until` for why a live `now`
|
|
73
|
+
// must arrive as `now + 1`.
|
|
74
|
+
const inWindow = entries.filter((e) => e.provider === claim.provider &&
|
|
75
|
+
typeof e.timestamp === 'number' &&
|
|
76
|
+
e.timestamp >= since &&
|
|
77
|
+
e.timestamp < until);
|
|
78
|
+
const totals = classifyEntries(inWindow, { ctx, excludeTestOrigin: true });
|
|
79
|
+
const invoiceUsd = round6(Math.max(0, claim.invoiceUsd));
|
|
80
|
+
const billedUsd = totals.billedUsd;
|
|
81
|
+
const deltaUsd = round6(invoiceUsd - billedUsd);
|
|
82
|
+
const toleranceUsd = toleranceFor(invoiceUsd, billedUsd);
|
|
83
|
+
const verdict = Math.abs(deltaUsd) <= toleranceUsd ? 'match' : deltaUsd > 0 ? 'under-evidenced' : 'over-recorded';
|
|
84
|
+
const windowText = `${new Date(since).toISOString()} → ${new Date(until).toISOString()}`;
|
|
85
|
+
const basis = `${claim.provider}: invoice $${invoiceUsd.toFixed(6)} vs ledger evidence $${billedUsd.toFixed(6)} ` +
|
|
86
|
+
`over ${totals.requests} call(s) in ${windowText}` +
|
|
87
|
+
`${claim.note ? ` (invoice source: ${claim.note})` : ''}`;
|
|
88
|
+
// ── What the invoice proves about the account ────────────────────────────
|
|
89
|
+
let tierEvidence;
|
|
90
|
+
if (invoiceUsd === 0 && totals.requests > 0 && billedUsd === 0) {
|
|
91
|
+
tierEvidence = {
|
|
92
|
+
tier: 'free',
|
|
93
|
+
basis: `the provider charged $0 for ${totals.requests} call(s) in this window — the key is not billed per call`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
else if (invoiceUsd > 0 &&
|
|
97
|
+
billedUsd > 0 &&
|
|
98
|
+
totals.billedReportedUsd > 0 &&
|
|
99
|
+
Math.abs(invoiceUsd - totals.billedReportedUsd) <= toleranceUsd) {
|
|
100
|
+
tierEvidence = {
|
|
101
|
+
tier: 'paid',
|
|
102
|
+
basis: `the invoice matches the per-call costs the provider itself reported ($${totals.billedReportedUsd.toFixed(6)}) — the key is metered and billed`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// ── What could explain the delta (never a silent adjustment) ─────────────
|
|
106
|
+
const hints = [];
|
|
107
|
+
if (totals.requests === 0) {
|
|
108
|
+
hints.push(`no ledger rows for ${claim.provider} in this window — if calls were made, the ledger is missing them (a different NUVIRA_MEMORY_DIR, a profile that was cleared, or a provider recorded under another id)`);
|
|
109
|
+
}
|
|
110
|
+
if (verdict === 'under-evidenced') {
|
|
111
|
+
if (totals.unpricedCalls > 0) {
|
|
112
|
+
hints.push(`${totals.unpricedCalls} call(s) in this window have NO price evidence (configure pricing.${claim.provider}.inputPer1K/outputPer1K) — they may be part of the $${deltaUsd.toFixed(6)}`);
|
|
113
|
+
}
|
|
114
|
+
if (totals.unverifiedListedUsd > 0) {
|
|
115
|
+
hints.push(`$${totals.unverifiedListedUsd.toFixed(6)} of list-priced calls are not counted as spend because providers.${claim.provider}.billingTier is undeclared`);
|
|
116
|
+
}
|
|
117
|
+
hints.push(`the invoice is the "actual" figure here: money the provider charged that this ledger cannot evidence`);
|
|
118
|
+
}
|
|
119
|
+
if (verdict === 'over-recorded') {
|
|
120
|
+
hints.push(`the ledger's evidence ($${billedUsd.toFixed(6)}) EXCEEDS the charge ($${invoiceUsd.toFixed(6)}) — either list prices are above what this account is really charged (a discount, credits, or a flat plan that the "paid" tier is metering per call), or rows were double-recorded`);
|
|
121
|
+
if (totals.billedListedUsd > 0) {
|
|
122
|
+
hints.push(`$${totals.billedListedUsd.toFixed(6)} of the ledger figure is list-priced on an account declared "paid", i.e. an estimate — the invoice is the truth`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (invoiceUsd > 0 && totals.notBilledValueUsd > 0) {
|
|
126
|
+
hints.push(`the invoice shows a charge while $${totals.notBilledValueUsd.toFixed(6)} of list value is classified not-billed (free/subscription) — re-check the tier or the window`);
|
|
127
|
+
}
|
|
128
|
+
if (totals.testOriginCalls > 0) {
|
|
129
|
+
hints.push(`${totals.testOriginCalls} test-origin row(s) were excluded from this comparison`);
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
provider: claim.provider,
|
|
133
|
+
since,
|
|
134
|
+
until,
|
|
135
|
+
invoiceUsd,
|
|
136
|
+
...(claim.note ? { note: claim.note } : {}),
|
|
137
|
+
requests: totals.requests,
|
|
138
|
+
tokens: totals.tokens,
|
|
139
|
+
billedUsd,
|
|
140
|
+
billedReportedUsd: totals.billedReportedUsd,
|
|
141
|
+
billedListedUsd: totals.billedListedUsd,
|
|
142
|
+
unverifiedListedUsd: totals.unverifiedListedUsd,
|
|
143
|
+
notBilledValueUsd: totals.notBilledValueUsd,
|
|
144
|
+
unpricedCalls: totals.unpricedCalls,
|
|
145
|
+
testOriginCalls: totals.testOriginCalls,
|
|
146
|
+
deltaUsd,
|
|
147
|
+
toleranceUsd,
|
|
148
|
+
verdict,
|
|
149
|
+
basis,
|
|
150
|
+
...(tierEvidence ? { tierEvidence } : {}),
|
|
151
|
+
hints,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/** Where the reconciliation records live, resolved lazily (see cost-tracker). */
|
|
155
|
+
export function reconciliationLedgerPath() {
|
|
156
|
+
const dir = envBuff('MEMORY_DIR') || join(resolveNuviraHome(), 'memory');
|
|
157
|
+
return join(dir, 'cost-reconciliations.json');
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Every recorded reconciliation, newest first. Never throws — a corrupt file
|
|
161
|
+
* reads as empty, because this is display/audit data and a broken history must
|
|
162
|
+
* not take down the cost page.
|
|
163
|
+
*/
|
|
164
|
+
export function readReconciliations(opts = {}) {
|
|
165
|
+
const path = opts.file ?? reconciliationLedgerPath();
|
|
166
|
+
try {
|
|
167
|
+
if (!existsSync(path))
|
|
168
|
+
return [];
|
|
169
|
+
const parsed = JSON.parse(readFileSync(path, 'utf-8'));
|
|
170
|
+
const list = Array.isArray(parsed?.reconciliations) ? parsed.reconciliations : [];
|
|
171
|
+
return list.filter((r) => r && typeof r.provider === 'string' && typeof r.invoiceUsd === 'number');
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/** Keep the file small: a reconciliation is a checkpoint, not a stream. */
|
|
178
|
+
const MAX_RECONCILIATIONS = 200;
|
|
179
|
+
/**
|
|
180
|
+
* Persist a reconciliation. Appending rather than replacing on purpose: the
|
|
181
|
+
* HISTORY is the audit trail ("this was checked against the October invoice, and
|
|
182
|
+
* the delta was 3 cents"), and a later check must not erase what an earlier one
|
|
183
|
+
* established.
|
|
184
|
+
*/
|
|
185
|
+
export function recordReconciliation(rec, opts = {}) {
|
|
186
|
+
const stored = { ...rec, recordedAt: opts.at ?? Date.now() };
|
|
187
|
+
const path = opts.file ?? reconciliationLedgerPath();
|
|
188
|
+
const dir = dirname(path);
|
|
189
|
+
try {
|
|
190
|
+
if (!existsSync(dir))
|
|
191
|
+
mkdirSync(dir, { recursive: true });
|
|
192
|
+
const all = [stored, ...readReconciliations({ file: path })].slice(0, MAX_RECONCILIATIONS);
|
|
193
|
+
writeFileSync(path, JSON.stringify({ version: 1, reconciliations: all }, null, 2), 'utf-8');
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// Best-effort: the report was already produced and returned to the caller.
|
|
197
|
+
}
|
|
198
|
+
return stored;
|
|
199
|
+
}
|
|
200
|
+
/** The most recent record for a provider, or undefined. */
|
|
201
|
+
export function lastReconciliationFor(provider, opts = {}) {
|
|
202
|
+
return readReconciliations(opts).find((r) => r.provider === provider);
|
|
203
|
+
}
|
|
204
|
+
// ─── Display ────────────────────────────────────────────────────────────────
|
|
205
|
+
const usd = (n) => `$${n.toFixed(6)}`;
|
|
206
|
+
/** The reconciliation, as text — shared by the CLI and any surface that prints it. */
|
|
207
|
+
export function formatReconciliation(rec) {
|
|
208
|
+
const lines = [
|
|
209
|
+
'🧾 Cost Reconciliation — the provider’s own figure vs this ledger',
|
|
210
|
+
'',
|
|
211
|
+
` Provider: ${rec.provider}`,
|
|
212
|
+
` Window: ${new Date(rec.since).toISOString()} → ${new Date(rec.until).toISOString()}`,
|
|
213
|
+
` Invoice: ${usd(rec.invoiceUsd)}${rec.note ? ` (${rec.note})` : ''}`,
|
|
214
|
+
` Ledger: ${usd(rec.billedUsd)} evidence-backed` +
|
|
215
|
+
` (🧾 exact ${usd(rec.billedReportedUsd)} + 📋 list-estimated ${usd(rec.billedListedUsd)})`,
|
|
216
|
+
` Calls: ${rec.requests} (${rec.tokens} tokens)` +
|
|
217
|
+
`${rec.testOriginCalls > 0 ? `, ${rec.testOriginCalls} test-origin excluded` : ''}`,
|
|
218
|
+
'',
|
|
219
|
+
];
|
|
220
|
+
const verdict = rec.verdict === 'match'
|
|
221
|
+
? `✅ MATCH — within ${usd(rec.toleranceUsd)} (delta ${rec.deltaUsd >= 0 ? '+' : ''}${usd(rec.deltaUsd)})`
|
|
222
|
+
: rec.verdict === 'under-evidenced'
|
|
223
|
+
? `⚠️ UNDER-EVIDENCED — the provider charged ${usd(rec.deltaUsd)} more than this ledger can prove`
|
|
224
|
+
: `⚠️ OVER-RECORDED — this ledger claims ${usd(-rec.deltaUsd)} more than the provider charged`;
|
|
225
|
+
lines.push(` ${verdict}`, '');
|
|
226
|
+
if (rec.tierEvidence) {
|
|
227
|
+
lines.push(` 🔑 Billing tier EVIDENCED by the invoice: ${rec.tierEvidence.tier}`, ` ${rec.tierEvidence.basis}`, '');
|
|
228
|
+
}
|
|
229
|
+
if (rec.hints.length > 0) {
|
|
230
|
+
lines.push(' What this means:');
|
|
231
|
+
for (const h of rec.hints)
|
|
232
|
+
lines.push(` • ${h}`);
|
|
233
|
+
lines.push('');
|
|
234
|
+
}
|
|
235
|
+
lines.push(` ${rec.basis}`, '');
|
|
236
|
+
return lines.join('\n');
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=cost-reconcile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-reconcile.js","sourceRoot":"","sources":["../../src/learning/cost-reconcile.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CostTracker —
|
|
2
|
+
* CostTracker — the append-only ledger of what each model call cost, stored at
|
|
3
|
+
* ~/.nuvira/memory/cost-tracker.json.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
* and
|
|
5
|
+
* TWO NUMBERS, NEVER ONE. Every row carries `costUsd` (money we have EVIDENCE was
|
|
6
|
+
* charged) and, when a price exists, `listPriceUsd` (what the same tokens would
|
|
7
|
+
* cost at list price — the VALUE a free tier absorbed). A single figure cannot
|
|
8
|
+
* express both, and conflating them is the defect this file was rewritten to
|
|
9
|
+
* remove: the ledger used to price every call from its OWN hardcoded table —
|
|
10
|
+
* five providers plus a `$0.00010/1K` generic fallback — while the router priced
|
|
11
|
+
* from `provider-catalog.ts`. On a real profile that printed
|
|
12
|
+
* `Total Spent $7.21` where the same ledger recorded $5.94 for the ONLY provider
|
|
13
|
+
* the user pays (the catalog's own DeepSeek numbers give ≈$17.36), invented
|
|
14
|
+
* $0.40 of spend on a localhost gateway the catalog declares free, and billed a
|
|
15
|
+
* free Groq tier at a 70B-class list rate.
|
|
6
16
|
*
|
|
7
|
-
*
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
* - Google Gemini: free tier (limited), paid tier ~$0.10/$1K
|
|
11
|
-
* - OpenRouter: varies by model (pass-through pricing)
|
|
12
|
-
* - Local: free
|
|
17
|
+
* There is now ONE price source of truth (`learning/model-pricing.ts`, reading
|
|
18
|
+
* `provider-catalog.ts`) and NO generic fallback: an unknown provider is
|
|
19
|
+
* `unpriced`, which is a first-class answer rather than an invented rate.
|
|
13
20
|
*
|
|
14
|
-
*
|
|
21
|
+
* WHAT DECIDES THE DOLLARS (in order):
|
|
22
|
+
* 1. the provider's own reported cost for the call — exact, including $0;
|
|
23
|
+
* 2. a provably-free pair: a local runtime, a provider-declared `:free` id, or an
|
|
24
|
+
* account the user declared `free`/`subscription` (`providers.<id>.billingTier`);
|
|
25
|
+
* 3. a keyless pass-through gateway → `passthrough` (its upstream bill is not
|
|
26
|
+
* visible here) and an unknown price → `unpriced` — neither is $0 "spend";
|
|
27
|
+
* 4. a list price we can NAME a source for → billed only when the account is
|
|
28
|
+
* declared `paid`, otherwise a labelled `unverified` figure.
|
|
29
|
+
*
|
|
30
|
+
* Rows written before this existed are re-derived at READ time (never rewritten)
|
|
31
|
+
* and counted in `recomputedCalls`; see `learning/cost-classification.ts`.
|
|
15
32
|
*/
|
|
33
|
+
import { type BillingTier, type CostSource } from './model-pricing.js';
|
|
34
|
+
import { setPricingContext, resetPricingContextCache, type CostTotals, type PricingContext } from './cost-classification.js';
|
|
35
|
+
export { setPricingContext, resetPricingContextCache, type PricingContext };
|
|
36
|
+
export { BILLING_TIERS, asBillingTier, type BillingTier, type CostSource, type CostBucket } from './model-pricing.js';
|
|
16
37
|
export interface CostEntry {
|
|
17
38
|
/** Provider name (e.g., 'groq', 'gemini', 'openrouter', 'nim', 'local') */
|
|
18
39
|
provider: string;
|
|
@@ -43,10 +64,66 @@ export interface CostEntry {
|
|
|
43
64
|
* wins over any estimate — see calculateCost's `reportedCostUsd` parameter.
|
|
44
65
|
*/
|
|
45
66
|
costReported?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* How `costUsd` was obtained (see `model-pricing.ts`). Absent on rows written
|
|
69
|
+
* before this existed — those are re-derived at read time, never rewritten.
|
|
70
|
+
*/
|
|
71
|
+
costSource?: CostSource;
|
|
72
|
+
/**
|
|
73
|
+
* What the same tokens would cost at the resolved LIST price — the value a
|
|
74
|
+
* free tier absorbed, and the figure an undeclared account sits at. Never spend.
|
|
75
|
+
*/
|
|
76
|
+
listPriceUsd?: number;
|
|
77
|
+
/** The account billing tier in force when the row was recorded. */
|
|
78
|
+
billingTier?: BillingTier;
|
|
79
|
+
/** One line naming the evidence behind the two numbers above. */
|
|
80
|
+
pricingBasis?: string;
|
|
81
|
+
/**
|
|
82
|
+
* `live` or `test` (`model-registry.telemetryOrigin`). A row written by a test
|
|
83
|
+
* run is not the user's usage — display surfaces exclude these, exactly as the
|
|
84
|
+
* model registry excludes test-origin telemetry from its views.
|
|
85
|
+
*/
|
|
86
|
+
origin?: 'live' | 'test';
|
|
46
87
|
}
|
|
47
88
|
export interface CostSummary {
|
|
48
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* The ledger total AS RECORDED — the sum of the stored `costUsd`. Kept in this
|
|
91
|
+
* spelling for compatibility, and deliberately NOT the headline: it includes
|
|
92
|
+
* rows priced by the retired hardcoded table. `billedUsd` below is the
|
|
93
|
+
* evidence-backed figure; a reader can reconcile the two rather than have
|
|
94
|
+
* history silently rewritten under them.
|
|
95
|
+
*/
|
|
49
96
|
totalCost: number;
|
|
97
|
+
/** Evidence-backed bill: provider-reported + list-priced with a declared paid account. */
|
|
98
|
+
billedUsd: number;
|
|
99
|
+
/** The exact, provider-stated part of `billedUsd`. */
|
|
100
|
+
billedReportedUsd: number;
|
|
101
|
+
/** The list-priced part of `billedUsd` — an ESTIMATE of money owed. */
|
|
102
|
+
billedListedUsd: number;
|
|
103
|
+
/** List-priced with the tier undeclared: shown, never presented as spend. */
|
|
104
|
+
unverifiedListedUsd: number;
|
|
105
|
+
/** Value a free/subscription tier absorbed — never spend. */
|
|
106
|
+
notBilledValueUsd: number;
|
|
107
|
+
/** Calls with no dollars at all (unknown price, or a pass-through gateway). */
|
|
108
|
+
unpricedCalls: number;
|
|
109
|
+
unpricedTokens: number;
|
|
110
|
+
/** Rows re-derived at read time because they predate `costSource`. */
|
|
111
|
+
recomputedCalls: number;
|
|
112
|
+
/** Rows tagged test-origin (excluded from the totals above; counted here). */
|
|
113
|
+
testOriginCalls: number;
|
|
114
|
+
/** Calls whose figure is exact (provider-reported). */
|
|
115
|
+
billedReportedCalls: number;
|
|
116
|
+
/** Calls list-priced with the account declared paid. */
|
|
117
|
+
billedListedCalls: number;
|
|
118
|
+
/** Calls list-priced with the tier undeclared. */
|
|
119
|
+
unverifiedListedCalls: number;
|
|
120
|
+
/** Calls a free/subscription tier absorbed. */
|
|
121
|
+
notBilledValueCalls: number;
|
|
122
|
+
/**
|
|
123
|
+
* The full classified roll-up (per provider and per model) — the ONE object
|
|
124
|
+
* every surface should read its buckets from, rather than re-deriving them.
|
|
125
|
+
*/
|
|
126
|
+
totals: CostTotals;
|
|
50
127
|
/** Total cost by provider */
|
|
51
128
|
byProvider: Record<string, number>;
|
|
52
129
|
/** Total cost by model */
|
|
@@ -62,6 +139,13 @@ export interface CostSummary {
|
|
|
62
139
|
/** Session start timestamp */
|
|
63
140
|
sessionStart: number;
|
|
64
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* The ledger file's location, exported so maintenance (`cost-ledger-maintenance`,
|
|
144
|
+
* the CLI's `stats cost reprice`, `scripts/prune-cost-ledger-rows.mjs`) acts on
|
|
145
|
+
* THIS file and the `NUVIRA_MEMORY_DIR` override keeps applying to it — a repair
|
|
146
|
+
* pass that resolved its own path could rewrite the wrong profile.
|
|
147
|
+
*/
|
|
148
|
+
export declare function costLedgerPath(): string;
|
|
65
149
|
/**
|
|
66
150
|
* Estimate the number of tokens from text length.
|
|
67
151
|
* Rough heuristic: ~4 characters per token for code, ~5 for prose.
|
|
@@ -86,7 +170,17 @@ export declare function isFreeModel(provider: string, model: string): boolean;
|
|
|
86
170
|
* what lets a free/subscription call report a TRUE $0 instead of a generic
|
|
87
171
|
* rate, and a discounted call report what was actually charged.
|
|
88
172
|
*/
|
|
89
|
-
export declare function calculateCost(provider: string, model: string, inputTokens: number, outputTokens: number, reportedCostUsd?: number
|
|
173
|
+
export declare function calculateCost(provider: string, model: string, inputTokens: number, outputTokens: number, reportedCostUsd?: number, opts?: {
|
|
174
|
+
configPricing?: {
|
|
175
|
+
inputPer1K?: number;
|
|
176
|
+
outputPer1K?: number;
|
|
177
|
+
};
|
|
178
|
+
catalogRow?: {
|
|
179
|
+
inputPer1K?: number;
|
|
180
|
+
outputPer1K?: number;
|
|
181
|
+
basis?: string;
|
|
182
|
+
};
|
|
183
|
+
}): number;
|
|
90
184
|
/**
|
|
91
185
|
* Tracks API usage costs per provider.
|
|
92
186
|
*/
|
|
@@ -119,10 +213,22 @@ export declare class CostTracker {
|
|
|
119
213
|
recordCallEstimated(provider: string, model: string, promptText: string, responseText: string, task?: string): CostEntry;
|
|
120
214
|
/**
|
|
121
215
|
* Get cost summary across all time and current session.
|
|
216
|
+
*
|
|
217
|
+
* The classified figures come from ONE pass (`cost-classification.ts`), so the
|
|
218
|
+
* CLI, the dashboard and the reconciliation check cannot disagree about which
|
|
219
|
+
* bucket a call belongs to — which is exactly how the cost picture drifted
|
|
220
|
+
* before. Test-origin rows are excluded from the buckets and counted instead.
|
|
122
221
|
*/
|
|
123
222
|
getSummary(): CostSummary;
|
|
124
223
|
/**
|
|
125
|
-
* Format
|
|
224
|
+
* Format the ledger HONESTLY: what is billed (and on what evidence), what a free
|
|
225
|
+
* tier absorbed as value, what is list-priced but unverified, and what has no
|
|
226
|
+
* price at all.
|
|
227
|
+
*
|
|
228
|
+
* "Total spent" is deliberately not a line. The ledger cannot see a provider's
|
|
229
|
+
* invoice, so it reports what it can evidence, separates the value a free tier
|
|
230
|
+
* saved from money owed, and says what it does not know — instead of printing
|
|
231
|
+
* one sum that is part spend, part list-price fiction.
|
|
126
232
|
*/
|
|
127
233
|
formatSummary(): string;
|
|
128
234
|
/**
|
|
@@ -149,6 +255,21 @@ export declare function costSince(since: number): {
|
|
|
149
255
|
tokens: number;
|
|
150
256
|
requests: number;
|
|
151
257
|
};
|
|
258
|
+
/**
|
|
259
|
+
* The full, provenance-carrying view of a window — for callers that must not
|
|
260
|
+
* conflate an estimate with a bill. `attributed` is what `costSince` returns.
|
|
261
|
+
*/
|
|
262
|
+
export declare function costSinceSplit(since: number): {
|
|
263
|
+
attributed: {
|
|
264
|
+
costUsd: number;
|
|
265
|
+
tokens: number;
|
|
266
|
+
requests: number;
|
|
267
|
+
};
|
|
268
|
+
billedUsd: number;
|
|
269
|
+
unverifiedListedUsd: number;
|
|
270
|
+
notBilledValueUsd: number;
|
|
271
|
+
unpricedCalls: number;
|
|
272
|
+
};
|
|
152
273
|
/**
|
|
153
274
|
* M2.2: record a call preferring MEASURED wire tokens when the provider
|
|
154
275
|
* reported usage; otherwise fall back to the length-based estimate. Shared by
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cost-tracker.d.ts","sourceRoot":"","sources":["../../src/learning/cost-tracker.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cost-tracker.d.ts","sourceRoot":"","sources":["../../src/learning/cost-tracker.ts"],"names":[],"mappings":"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"}
|