@salimassili/ai-costguard 1.2.0 → 2.0.1

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 (76) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/LICENSE +21 -0
  3. package/README.md +415 -177
  4. package/benchmarks/run.mjs +229 -0
  5. package/benchmarks/token-accuracy.mjs +86 -0
  6. package/dist/cli.d.ts +50 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +178 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/core/CostGuard.d.ts +4 -5
  11. package/dist/core/CostGuard.d.ts.map +1 -1
  12. package/dist/core/CostGuard.js +2 -3
  13. package/dist/core/CostGuard.js.map +1 -1
  14. package/dist/core/GuardCore.d.ts +93 -13
  15. package/dist/core/GuardCore.d.ts.map +1 -1
  16. package/dist/core/GuardCore.js +372 -158
  17. package/dist/core/GuardCore.js.map +1 -1
  18. package/dist/core/GuardFree.d.ts +42 -18
  19. package/dist/core/GuardFree.d.ts.map +1 -1
  20. package/dist/core/GuardFree.js +95 -140
  21. package/dist/core/GuardFree.js.map +1 -1
  22. package/dist/core/GuardPro.d.ts +76 -8
  23. package/dist/core/GuardPro.d.ts.map +1 -1
  24. package/dist/core/GuardPro.js +213 -130
  25. package/dist/core/GuardPro.js.map +1 -1
  26. package/dist/core/event-log.d.ts +37 -0
  27. package/dist/core/event-log.d.ts.map +1 -0
  28. package/dist/core/event-log.js +49 -0
  29. package/dist/core/event-log.js.map +1 -0
  30. package/dist/core/events.d.ts +20 -0
  31. package/dist/core/events.d.ts.map +1 -0
  32. package/dist/core/events.js +46 -0
  33. package/dist/core/events.js.map +1 -0
  34. package/dist/core/similarity.d.ts +13 -0
  35. package/dist/core/similarity.d.ts.map +1 -0
  36. package/dist/core/similarity.js +51 -0
  37. package/dist/core/similarity.js.map +1 -0
  38. package/dist/core/tokenizer.d.ts +18 -0
  39. package/dist/core/tokenizer.d.ts.map +1 -0
  40. package/dist/core/tokenizer.js +137 -0
  41. package/dist/core/tokenizer.js.map +1 -0
  42. package/dist/core/types.d.ts +151 -5
  43. package/dist/core/types.d.ts.map +1 -1
  44. package/dist/core/types.js +0 -3
  45. package/dist/core/types.js.map +1 -1
  46. package/dist/core/webhooks.d.ts +15 -0
  47. package/dist/core/webhooks.d.ts.map +1 -0
  48. package/dist/core/webhooks.js +58 -0
  49. package/dist/core/webhooks.js.map +1 -0
  50. package/dist/dashboard.d.ts +73 -0
  51. package/dist/dashboard.d.ts.map +1 -0
  52. package/dist/dashboard.js +201 -0
  53. package/dist/dashboard.js.map +1 -0
  54. package/dist/index.d.ts +4 -5
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +2 -3
  57. package/dist/index.js.map +1 -1
  58. package/dist/pricing/index.d.ts +26 -2
  59. package/dist/pricing/index.d.ts.map +1 -1
  60. package/dist/pricing/index.js +100 -13
  61. package/dist/pricing/index.js.map +1 -1
  62. package/dist/pro.d.ts +3 -0
  63. package/dist/pro.d.ts.map +1 -0
  64. package/dist/pro.js +2 -0
  65. package/dist/pro.js.map +1 -0
  66. package/docs/BENCHMARKS.md +70 -0
  67. package/docs/DASHBOARD.md +61 -0
  68. package/docs/INTEGRATIONS.md +153 -0
  69. package/examples/integrations/anthropic-workflow-budget.mjs +36 -0
  70. package/examples/integrations/ci-budget-check.mjs +32 -0
  71. package/examples/integrations/crewai-budget-gate.mjs +31 -0
  72. package/examples/integrations/langchain-retry-storm.mjs +32 -0
  73. package/examples/integrations/mastra-agent.mjs +41 -0
  74. package/examples/integrations/openai-agent-loop.mjs +44 -0
  75. package/examples/integrations/vercel-ai-chatbot.mjs +29 -0
  76. package/package.json +76 -46
@@ -0,0 +1,201 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { createServer } from 'node:http';
3
+ const DEFAULT_EVENT_LOG_PATH = '.ai-costguard/events.jsonl';
4
+ const DEFAULT_DASHBOARD_HOST = '127.0.0.1';
5
+ const DEFAULT_DASHBOARD_PORT = 4318;
6
+ /**
7
+ * Returns the default local event log path.
8
+ */
9
+ export function getDefaultEventLogPath() {
10
+ return DEFAULT_EVENT_LOG_PATH;
11
+ }
12
+ /**
13
+ * Reads dashboard events from a local JSONL event log.
14
+ */
15
+ export function readDashboardEvents(eventLogPath = DEFAULT_EVENT_LOG_PATH) {
16
+ if (!existsSync(eventLogPath))
17
+ return [];
18
+ const lines = readFileSync(eventLogPath, 'utf8')
19
+ .split(/\r?\n/u)
20
+ .map((line) => line.trim())
21
+ .filter(Boolean);
22
+ const events = [];
23
+ for (const line of lines) {
24
+ const event = parseDashboardEvent(line);
25
+ if (event)
26
+ events.push(event);
27
+ }
28
+ return events;
29
+ }
30
+ /**
31
+ * Builds dashboard metrics from a local event log.
32
+ */
33
+ export function summarizeDashboard(options = {}) {
34
+ const eventLogPath = options.eventLogPath ?? DEFAULT_EVENT_LOG_PATH;
35
+ const recentLimit = Math.max(1, Math.trunc(options.recentLimit ?? 25));
36
+ const events = readDashboardEvents(eventLogPath);
37
+ const allowed = events.filter((event) => event.type === 'allow');
38
+ const blocked = events.filter((event) => event.type === 'block');
39
+ const costEvents = events.filter((event) => event.type === 'cost');
40
+ const estimatedSpendUsd = sum(allowed.map((event) => event.estimatedCost));
41
+ const estimatedSavingsUsd = sum(blocked.map((event) => event.estimatedCost));
42
+ const attemptedSpendUsd = costEvents.length
43
+ ? sum(costEvents.map((event) => event.estimatedCost))
44
+ : estimatedSpendUsd + estimatedSavingsUsd;
45
+ const actualSpendUsd = sum(events.map((event) => event.actualCost ?? 0));
46
+ const budgetUsd = options.budgetUsd;
47
+ return {
48
+ eventLogPath,
49
+ generatedAt: new Date().toISOString(),
50
+ budgetUsd,
51
+ budgetUsedPercent: budgetUsd && budgetUsd > 0 ? round((estimatedSpendUsd / budgetUsd) * 100, 2) : undefined,
52
+ requestsAllowed: allowed.length,
53
+ requestsBlocked: blocked.length,
54
+ estimatedSpendUsd: roundMoney(estimatedSpendUsd),
55
+ estimatedSavingsUsd: roundMoney(estimatedSavingsUsd),
56
+ attemptedSpendUsd: roundMoney(attemptedSpendUsd),
57
+ actualSpendUsd: roundMoney(actualSpendUsd),
58
+ loopDetections: blocked.filter((event) => event.code === 'LOOP_DETECTED').length,
59
+ retryDetections: blocked.filter((event) => event.code === 'RETRY_STORM_DETECTED').length,
60
+ recentEvents: events.slice(-recentLimit).reverse(),
61
+ };
62
+ }
63
+ /**
64
+ * Formats a dashboard summary for terminal output.
65
+ */
66
+ export function formatDashboardSummary(summary) {
67
+ const budgetLine = summary.budgetUsd === undefined
68
+ ? `Budget used: $${summary.estimatedSpendUsd.toFixed(6)} estimated`
69
+ : `Budget used: ${summary.budgetUsedPercent?.toFixed(2) ?? '0.00'}% ($${summary.estimatedSpendUsd.toFixed(6)} / $${summary.budgetUsd.toFixed(6)})`;
70
+ return [
71
+ 'AI CostGuard local dashboard',
72
+ `Event log: ${summary.eventLogPath}`,
73
+ budgetLine,
74
+ `Requests allowed: ${summary.requestsAllowed}`,
75
+ `Requests blocked: ${summary.requestsBlocked}`,
76
+ `Estimated spend: $${summary.estimatedSpendUsd.toFixed(6)}`,
77
+ `Estimated savings: $${summary.estimatedSavingsUsd.toFixed(6)}`,
78
+ `Attempted spend: $${summary.attemptedSpendUsd.toFixed(6)}`,
79
+ `Actual spend: $${summary.actualSpendUsd.toFixed(6)}`,
80
+ `Loop detections: ${summary.loopDetections}`,
81
+ `Retry detections: ${summary.retryDetections}`,
82
+ `Recent events: ${summary.recentEvents.length}`,
83
+ '',
84
+ ].join('\n');
85
+ }
86
+ /**
87
+ * Starts a local-only HTTP dashboard server.
88
+ */
89
+ export function startDashboardServer(options = {}) {
90
+ const host = options.host ?? DEFAULT_DASHBOARD_HOST;
91
+ const port = options.port ?? DEFAULT_DASHBOARD_PORT;
92
+ const server = createServer((request, response) => {
93
+ const summary = summarizeDashboard(options);
94
+ if (request.url?.startsWith('/events.json')) {
95
+ response.writeHead(200, { 'content-type': 'application/json; charset=utf-8' });
96
+ response.end(JSON.stringify(summary, null, 2));
97
+ return;
98
+ }
99
+ response.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });
100
+ response.end(renderDashboardHtml(summary));
101
+ });
102
+ return new Promise((resolve, reject) => {
103
+ server.once('error', reject);
104
+ server.listen(port, host, () => {
105
+ server.off('error', reject);
106
+ const address = server.address();
107
+ const actualPort = typeof address === 'object' && address ? address.port : port;
108
+ resolve({ server, url: `http://${host}:${actualPort}` });
109
+ });
110
+ });
111
+ }
112
+ function renderDashboardHtml(summary) {
113
+ const recentRows = summary.recentEvents
114
+ .map((event) => `<tr>
115
+ <td>${escapeHtml(event.timestamp)}</td>
116
+ <td>${escapeHtml(event.type)}</td>
117
+ <td>${escapeHtml(event.code ?? '')}</td>
118
+ <td>${escapeHtml(event.model)}</td>
119
+ <td>${escapeHtml(event.scopeKey)}</td>
120
+ <td>$${event.estimatedCost.toFixed(6)}</td>
121
+ </tr>`)
122
+ .join('');
123
+ return `<!doctype html>
124
+ <html lang="en">
125
+ <head>
126
+ <meta charset="utf-8">
127
+ <meta name="viewport" content="width=device-width, initial-scale=1">
128
+ <title>AI CostGuard Local Dashboard</title>
129
+ <style>
130
+ body { margin: 0; font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #101418; color: #eef2f4; }
131
+ main { max-width: 1120px; margin: 0 auto; padding: 32px 20px; }
132
+ h1 { margin: 0 0 8px; font-size: 32px; }
133
+ p { color: #a8b3bd; }
134
+ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; margin: 24px 0; }
135
+ .metric { border: 1px solid #2d363e; border-radius: 8px; padding: 16px; background: #161c22; }
136
+ .label { color: #8d99a5; font-size: 13px; }
137
+ .value { margin-top: 8px; font-size: 24px; font-weight: 700; }
138
+ table { width: 100%; border-collapse: collapse; margin-top: 20px; background: #161c22; }
139
+ th, td { border-bottom: 1px solid #2d363e; padding: 10px; text-align: left; font-size: 14px; }
140
+ th { color: #a8b3bd; }
141
+ code { color: #90cdf4; }
142
+ </style>
143
+ </head>
144
+ <body>
145
+ <main>
146
+ <h1>AI CostGuard Local Dashboard</h1>
147
+ <p>Local-only view generated from <code>${escapeHtml(summary.eventLogPath)}</code>. Refresh the page for updates.</p>
148
+ <section class="grid">
149
+ ${metric('Budget used', summary.budgetUsedPercent === undefined ? `$${summary.estimatedSpendUsd.toFixed(6)}` : `${summary.budgetUsedPercent.toFixed(2)}%`)}
150
+ ${metric('Requests allowed', String(summary.requestsAllowed))}
151
+ ${metric('Requests blocked', String(summary.requestsBlocked))}
152
+ ${metric('Estimated spend', `$${summary.estimatedSpendUsd.toFixed(6)}`)}
153
+ ${metric('Estimated savings', `$${summary.estimatedSavingsUsd.toFixed(6)}`)}
154
+ ${metric('Loop detections', String(summary.loopDetections))}
155
+ ${metric('Retry detections', String(summary.retryDetections))}
156
+ ${metric('Actual spend', `$${summary.actualSpendUsd.toFixed(6)}`)}
157
+ </section>
158
+ <h2>Recent Guard Events</h2>
159
+ <table>
160
+ <thead><tr><th>Time</th><th>Type</th><th>Code</th><th>Model</th><th>Scope</th><th>Estimated Cost</th></tr></thead>
161
+ <tbody>${recentRows || '<tr><td colspan="6">No events yet.</td></tr>'}</tbody>
162
+ </table>
163
+ </main>
164
+ </body>
165
+ </html>`;
166
+ }
167
+ function metric(label, value) {
168
+ return `<div class="metric"><div class="label">${escapeHtml(label)}</div><div class="value">${escapeHtml(value)}</div></div>`;
169
+ }
170
+ function parseDashboardEvent(line) {
171
+ try {
172
+ const value = JSON.parse(line);
173
+ if (value.version !== 1 || !value.timestamp || !value.type || !value.model || !value.scopeKey)
174
+ return undefined;
175
+ if (typeof value.estimatedCost !== 'number' || typeof value.tokens !== 'number')
176
+ return undefined;
177
+ return value;
178
+ }
179
+ catch {
180
+ return undefined;
181
+ }
182
+ }
183
+ function sum(values) {
184
+ return values.reduce((total, value) => total + value, 0);
185
+ }
186
+ function roundMoney(value) {
187
+ return round(value, 6);
188
+ }
189
+ function round(value, digits) {
190
+ const factor = 10 ** digits;
191
+ return Math.round(value * factor) / factor;
192
+ }
193
+ function escapeHtml(value) {
194
+ return value
195
+ .replaceAll('&', '&amp;')
196
+ .replaceAll('<', '&lt;')
197
+ .replaceAll('>', '&gt;')
198
+ .replaceAll('"', '&quot;')
199
+ .replaceAll("'", '&#39;');
200
+ }
201
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- export { guard, GuardError, middleware } from './core/GuardFree.js';
2
- export { GuardPro, validateLicense, getProGuard } from './core/GuardPro.js';
3
- export type { GuardProConfig } from './core/GuardPro.js';
4
- export { getPricing, registerPricing, listPricing } from './pricing/index.js';
1
+ export { guard, guardFunction, GuardError, middleware } from './core/GuardFree.js';
2
+ export type { GuardedClient, GuardEventControls } from './core/GuardFree.js';
3
+ export { BUILTIN_PRICING_LAST_UPDATED, getPricing, registerPricing, listPricing } from './pricing/index.js';
5
4
  export type { ModelPricing } from './pricing/index.js';
6
- export type { GuardConfig } from './core/types.js';
5
+ export type { GuardConfig, GuardErrorCode, GuardEvent, GuardEventHandler, GuardEventName, GuardScope, GuardState, GuardWebhookConfig, RequestContext, } from './core/types.js';
7
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC5E,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC9E,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACnF,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,4BAA4B,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC5G,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,YAAY,EACV,WAAW,EACX,cAAc,EACd,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,UAAU,EACV,UAAU,EACV,kBAAkB,EAClB,cAAc,GACf,MAAM,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- export { guard, GuardError, middleware } from './core/GuardFree.js';
2
- export { GuardPro, validateLicense, getProGuard } from './core/GuardPro.js';
3
- export { getPricing, registerPricing, listPricing } from './pricing/index.js';
1
+ export { guard, guardFunction, GuardError, middleware } from './core/GuardFree.js';
2
+ export { BUILTIN_PRICING_LAST_UPDATED, getPricing, registerPricing, listPricing } from './pricing/index.js';
4
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEnF,OAAO,EAAE,4BAA4B,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1,11 +1,35 @@
1
+ /**
2
+ * Last manual verification date for the built-in pricing registry.
3
+ *
4
+ * Provider pricing changes; use pricingOverrides/registerPricing for current
5
+ * production pricing when provider pages differ from these built-ins.
6
+ */
7
+ export declare const BUILTIN_PRICING_LAST_UPDATED = "2026-06-07";
8
+ /**
9
+ * Pricing entry expressed in USD per 1,000 tokens.
10
+ */
1
11
  export interface ModelPricing {
12
+ /** Model name or model family prefix. */
2
13
  model: string;
14
+ /** USD price per 1,000 input tokens. */
3
15
  inputPer1kTokens: number;
16
+ /** USD price per 1,000 output tokens. */
4
17
  outputPer1kTokens: number;
18
+ /** Date this pricing entry was last checked, formatted as YYYY-MM-DD. */
5
19
  lastUpdated: string;
20
+ /** Human-readable source for the pricing entry. */
6
21
  source: string;
7
22
  }
8
- export declare function getPricing(model: string, overrides?: ModelPricing[]): ModelPricing | undefined;
9
- export declare function registerPricing(entries: ModelPricing[]): void;
23
+ /**
24
+ * Returns pricing for a model from overrides, runtime entries, or built-in entries.
25
+ */
26
+ export declare function getPricing(model: string, overrides?: readonly ModelPricing[]): ModelPricing | undefined;
27
+ /**
28
+ * Registers or replaces runtime pricing entries by model name.
29
+ */
30
+ export declare function registerPricing(entries: readonly ModelPricing[]): void;
31
+ /**
32
+ * Lists built-in and runtime pricing entries, deduplicated by normalized model name.
33
+ */
10
34
  export declare function listPricing(): ModelPricing[];
11
35
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pricing/index.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAwDD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,YAAY,EAAO,GAAG,YAAY,GAAG,SAAS,CAkBlG;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI,CAI7D;AAED,wBAAgB,WAAW,IAAI,YAAY,EAAE,CAY5C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pricing/index.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,eAAe,CAAC;AAGzD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;CAChB;AA0GD;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,SAAS,YAAY,EAAO,GAAG,YAAY,GAAG,SAAS,CAuB3G;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,IAAI,CAMtE;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,YAAY,EAAE,CAe5C"}
@@ -1,60 +1,121 @@
1
- /* MAINTENANCE: update BUILTIN_PRICING when model prices change.
2
- Check: https://openai.com/pricing and https://www.anthropic.com/pricing
3
- Update the lastUpdated field on every change. */
1
+ const STALE_PRICING_DAYS = 30;
2
+ /**
3
+ * Last manual verification date for the built-in pricing registry.
4
+ *
5
+ * Provider pricing changes; use pricingOverrides/registerPricing for current
6
+ * production pricing when provider pages differ from these built-ins.
7
+ */
8
+ export const BUILTIN_PRICING_LAST_UPDATED = '2026-06-07';
4
9
  const BUILTIN_PRICING = [
10
+ {
11
+ model: 'gpt-5.5',
12
+ inputPer1kTokens: 0.005,
13
+ outputPer1kTokens: 0.03,
14
+ lastUpdated: '2026-06-07',
15
+ source: 'https://developers.openai.com/api/docs/pricing',
16
+ },
17
+ {
18
+ model: 'gpt-5.4',
19
+ inputPer1kTokens: 0.0025,
20
+ outputPer1kTokens: 0.015,
21
+ lastUpdated: '2026-06-07',
22
+ source: 'https://developers.openai.com/api/docs/pricing',
23
+ },
24
+ {
25
+ model: 'gpt-5.4-mini',
26
+ inputPer1kTokens: 0.00075,
27
+ outputPer1kTokens: 0.0045,
28
+ lastUpdated: '2026-06-07',
29
+ source: 'https://developers.openai.com/api/docs/pricing',
30
+ },
31
+ {
32
+ model: 'gpt-5.4-nano',
33
+ inputPer1kTokens: 0.0002,
34
+ outputPer1kTokens: 0.00125,
35
+ lastUpdated: '2026-06-07',
36
+ source: 'https://developers.openai.com/api/docs/pricing',
37
+ },
5
38
  {
6
39
  model: 'gpt-4',
7
40
  inputPer1kTokens: 0.03,
8
41
  outputPer1kTokens: 0.06,
9
42
  lastUpdated: '2026-05-21',
10
- source: 'https://openai.com/pricing'
43
+ source: 'https://openai.com/pricing',
11
44
  },
12
45
  {
13
46
  model: 'gpt-4o',
14
47
  inputPer1kTokens: 0.005,
15
48
  outputPer1kTokens: 0.015,
16
49
  lastUpdated: '2026-05-21',
17
- source: 'https://openai.com/pricing'
50
+ source: 'https://openai.com/pricing',
18
51
  },
19
52
  {
20
53
  model: 'gpt-4o-mini',
21
54
  inputPer1kTokens: 0.00015,
22
55
  outputPer1kTokens: 0.0006,
23
56
  lastUpdated: '2026-05-21',
24
- source: 'https://openai.com/pricing'
57
+ source: 'https://openai.com/pricing',
25
58
  },
26
59
  {
27
60
  model: 'gpt-3.5-turbo',
28
61
  inputPer1kTokens: 0.0005,
29
62
  outputPer1kTokens: 0.0015,
30
63
  lastUpdated: '2026-05-21',
31
- source: 'https://openai.com/pricing'
64
+ source: 'https://openai.com/pricing',
65
+ },
66
+ {
67
+ model: 'claude-opus-4.8',
68
+ inputPer1kTokens: 0.005,
69
+ outputPer1kTokens: 0.025,
70
+ lastUpdated: '2026-06-07',
71
+ source: 'https://claude.com/platform/api',
72
+ },
73
+ {
74
+ model: 'claude-sonnet-4.6',
75
+ inputPer1kTokens: 0.003,
76
+ outputPer1kTokens: 0.015,
77
+ lastUpdated: '2026-06-07',
78
+ source: 'https://claude.com/platform/api',
79
+ },
80
+ {
81
+ model: 'claude-haiku-4.5',
82
+ inputPer1kTokens: 0.001,
83
+ outputPer1kTokens: 0.005,
84
+ lastUpdated: '2026-06-07',
85
+ source: 'https://claude.com/platform/api',
32
86
  },
33
87
  {
34
88
  model: 'claude-3-opus',
35
89
  inputPer1kTokens: 0.015,
36
90
  outputPer1kTokens: 0.075,
37
91
  lastUpdated: '2026-05-21',
38
- source: 'https://www.anthropic.com/pricing'
92
+ source: 'https://www.anthropic.com/pricing',
39
93
  },
40
94
  {
41
95
  model: 'claude-3-sonnet',
42
96
  inputPer1kTokens: 0.003,
43
97
  outputPer1kTokens: 0.015,
44
98
  lastUpdated: '2026-05-21',
45
- source: 'https://www.anthropic.com/pricing'
99
+ source: 'https://www.anthropic.com/pricing',
46
100
  },
47
101
  {
48
102
  model: 'claude-3-haiku',
49
103
  inputPer1kTokens: 0.00025,
50
104
  outputPer1kTokens: 0.00125,
51
105
  lastUpdated: '2026-05-21',
52
- source: 'https://www.anthropic.com/pricing'
53
- }
106
+ source: 'https://www.anthropic.com/pricing',
107
+ },
54
108
  ];
55
109
  const runtimePricing = new Map();
110
+ const staleWarnings = new Set();
111
+ /**
112
+ * Returns pricing for a model from overrides, runtime entries, or built-in entries.
113
+ */
56
114
  export function getPricing(model, overrides = []) {
57
115
  const normalizedModel = normalizeModel(model);
116
+ warnIfAnyStale(overrides);
117
+ warnIfAnyStale(runtimePricing.values());
118
+ warnIfAnyStale(BUILTIN_PRICING);
58
119
  const overrideExact = findExact(normalizedModel, overrides);
59
120
  if (overrideExact)
60
121
  return overrideExact;
@@ -72,11 +133,18 @@ export function getPricing(model, overrides = []) {
72
133
  return builtinExact;
73
134
  return findFuzzy(normalizedModel, BUILTIN_PRICING);
74
135
  }
136
+ /**
137
+ * Registers or replaces runtime pricing entries by model name.
138
+ */
75
139
  export function registerPricing(entries) {
140
+ warnIfAnyStale(entries);
76
141
  for (const entry of entries) {
77
142
  runtimePricing.set(normalizeModel(entry.model), entry);
78
143
  }
79
144
  }
145
+ /**
146
+ * Lists built-in and runtime pricing entries, deduplicated by normalized model name.
147
+ */
80
148
  export function listPricing() {
81
149
  const merged = new Map();
82
150
  for (const entry of BUILTIN_PRICING) {
@@ -85,7 +153,9 @@ export function listPricing() {
85
153
  for (const entry of runtimePricing.values()) {
86
154
  merged.set(normalizeModel(entry.model), entry);
87
155
  }
88
- return Array.from(merged.values());
156
+ const entries = Array.from(merged.values());
157
+ warnIfAnyStale(entries);
158
+ return entries;
89
159
  }
90
160
  function findExact(model, entries) {
91
161
  return entries.find((entry) => normalizeModel(entry.model) === model);
@@ -94,10 +164,27 @@ function findFuzzy(model, entries) {
94
164
  const sortedEntries = [...entries].sort((a, b) => b.model.length - a.model.length);
95
165
  return sortedEntries.find((entry) => {
96
166
  const entryModel = normalizeModel(entry.model);
97
- return model.includes(entryModel) || entryModel.includes(model);
167
+ return model.startsWith(`${entryModel}-`) || model.startsWith(`${entryModel}:`);
98
168
  });
99
169
  }
100
170
  function normalizeModel(model) {
101
171
  return model.trim().toLowerCase();
102
172
  }
173
+ function warnIfAnyStale(entries) {
174
+ for (const entry of entries) {
175
+ warnIfStale(entry);
176
+ }
177
+ }
178
+ function warnIfStale(entry) {
179
+ const lastUpdatedMs = Date.parse(`${entry.lastUpdated}T00:00:00.000Z`);
180
+ if (!Number.isFinite(lastUpdatedMs))
181
+ return;
182
+ const ageDays = (Date.now() - lastUpdatedMs) / 86_400_000;
183
+ const warningKey = `${normalizeModel(entry.model)}:${entry.lastUpdated}`;
184
+ if (ageDays > STALE_PRICING_DAYS && !staleWarnings.has(warningKey)) {
185
+ staleWarnings.add(warningKey);
186
+ console.warn(`[AI CostGuard] Pricing for "${entry.model}" is older than ${STALE_PRICING_DAYS} days. ` +
187
+ `Last checked ${entry.lastUpdated}; verify ${entry.source}.`);
188
+ }
189
+ }
103
190
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pricing/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pricing/index.ts"],"names":[],"mappings":"AAAA,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAE9B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,YAAY,CAAC;AAmBzD,MAAM,eAAe,GAA4B;IAC/C;QACE,KAAK,EAAE,SAAS;QAChB,gBAAgB,EAAE,KAAK;QACvB,iBAAiB,EAAE,IAAI;QACvB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,gDAAgD;KACzD;IACD;QACE,KAAK,EAAE,SAAS;QAChB,gBAAgB,EAAE,MAAM;QACxB,iBAAiB,EAAE,KAAK;QACxB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,gDAAgD;KACzD;IACD;QACE,KAAK,EAAE,cAAc;QACrB,gBAAgB,EAAE,OAAO;QACzB,iBAAiB,EAAE,MAAM;QACzB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,gDAAgD;KACzD;IACD;QACE,KAAK,EAAE,cAAc;QACrB,gBAAgB,EAAE,MAAM;QACxB,iBAAiB,EAAE,OAAO;QAC1B,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,gDAAgD;KACzD;IACD;QACE,KAAK,EAAE,OAAO;QACd,gBAAgB,EAAE,IAAI;QACtB,iBAAiB,EAAE,IAAI;QACvB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,4BAA4B;KACrC;IACD;QACE,KAAK,EAAE,QAAQ;QACf,gBAAgB,EAAE,KAAK;QACvB,iBAAiB,EAAE,KAAK;QACxB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,4BAA4B;KACrC;IACD;QACE,KAAK,EAAE,aAAa;QACpB,gBAAgB,EAAE,OAAO;QACzB,iBAAiB,EAAE,MAAM;QACzB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,4BAA4B;KACrC;IACD;QACE,KAAK,EAAE,eAAe;QACtB,gBAAgB,EAAE,MAAM;QACxB,iBAAiB,EAAE,MAAM;QACzB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,4BAA4B;KACrC;IACD;QACE,KAAK,EAAE,iBAAiB;QACxB,gBAAgB,EAAE,KAAK;QACvB,iBAAiB,EAAE,KAAK;QACxB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,iCAAiC;KAC1C;IACD;QACE,KAAK,EAAE,mBAAmB;QAC1B,gBAAgB,EAAE,KAAK;QACvB,iBAAiB,EAAE,KAAK;QACxB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,iCAAiC;KAC1C;IACD;QACE,KAAK,EAAE,kBAAkB;QACzB,gBAAgB,EAAE,KAAK;QACvB,iBAAiB,EAAE,KAAK;QACxB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,iCAAiC;KAC1C;IACD;QACE,KAAK,EAAE,eAAe;QACtB,gBAAgB,EAAE,KAAK;QACvB,iBAAiB,EAAE,KAAK;QACxB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,mCAAmC;KAC5C;IACD;QACE,KAAK,EAAE,iBAAiB;QACxB,gBAAgB,EAAE,KAAK;QACvB,iBAAiB,EAAE,KAAK;QACxB,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,mCAAmC;KAC5C;IACD;QACE,KAAK,EAAE,gBAAgB;QACvB,gBAAgB,EAAE,OAAO;QACzB,iBAAiB,EAAE,OAAO;QAC1B,WAAW,EAAE,YAAY;QACzB,MAAM,EAAE,mCAAmC;KAC5C;CACF,CAAC;AAEF,MAAM,cAAc,GAAG,IAAI,GAAG,EAAwB,CAAC;AACvD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;AAExC;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,YAAqC,EAAE;IAC/E,MAAM,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAE9C,cAAc,CAAC,SAAS,CAAC,CAAC;IAC1B,cAAc,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC;IACxC,cAAc,CAAC,eAAe,CAAC,CAAC;IAEhC,MAAM,aAAa,GAAG,SAAS,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;IAC5D,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IAExC,MAAM,aAAa,GAAG,SAAS,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;IAC5D,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IAExC,MAAM,YAAY,GAAG,cAAc,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACzD,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IAEtC,MAAM,YAAY,GAAG,SAAS,CAAC,eAAe,EAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACrF,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IAEtC,MAAM,YAAY,GAAG,SAAS,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;IACjE,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IAEtC,OAAO,SAAS,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;AACrD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,OAAgC;IAC9D,cAAc,CAAC,OAAO,CAAC,CAAC;IAExB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;IAE/C,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,cAAc,CAAC,OAAO,CAAC,CAAC;IAExB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,SAAS,CAAC,KAAa,EAAE,OAAgC;IAChE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,SAAS,CAAC,KAAa,EAAE,OAAgC;IAChE,MAAM,aAAa,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEnF,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QAClC,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/C,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC;AAED,SAAS,cAAc,CAAC,OAA+B;IACrD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,WAAW,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,KAAmB;IACtC,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,WAAW,gBAAgB,CAAC,CAAC;IACvE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC;QAAE,OAAO;IAE5C,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,GAAG,UAAU,CAAC;IAC1D,MAAM,UAAU,GAAG,GAAG,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;IAEzE,IAAI,OAAO,GAAG,kBAAkB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QACnE,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC9B,OAAO,CAAC,IAAI,CACV,+BAA+B,KAAK,CAAC,KAAK,mBAAmB,kBAAkB,SAAS;YACtF,gBAAgB,KAAK,CAAC,WAAW,YAAY,KAAK,CAAC,MAAM,GAAG,CAC/D,CAAC;IACJ,CAAC;AACH,CAAC"}
package/dist/pro.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { GuardPro, getProGuard } from './core/GuardPro.js';
2
+ export type { GuardProConfig, GuardProRedisClient } from './core/GuardPro.js';
3
+ //# sourceMappingURL=pro.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pro.d.ts","sourceRoot":"","sources":["../src/pro.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/pro.js ADDED
@@ -0,0 +1,2 @@
1
+ export { GuardPro, getProGuard } from './core/GuardPro.js';
2
+ //# sourceMappingURL=pro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pro.js","sourceRoot":"","sources":["../src/pro.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,70 @@
1
+ # Benchmarks
2
+
3
+ Benchmarks are local measurements, not universal guarantees. Hardware, Node version, model request shape, history size, and enabled behavior checks all matter.
4
+
5
+ Run:
6
+
7
+ ```bash
8
+ npm run build
9
+ npm run benchmark
10
+ ```
11
+
12
+ For shorter sanity runs:
13
+
14
+ ```bash
15
+ node benchmarks/run.mjs --iterations 500
16
+ ```
17
+
18
+ The benchmark script measures:
19
+
20
+ - Runtime overhead per guarded function call
21
+ - Approximate heap delta after guarded calls
22
+ - Benign false-positive scenario for repeated "again" prompts
23
+ - Loop detection block step for repeated prompts
24
+ - Cost-estimation sample boundaries
25
+
26
+ Token accuracy benchmark:
27
+
28
+ ```bash
29
+ npm run build
30
+ npm run benchmark:tokens
31
+ ```
32
+
33
+ ## Current Local Result
34
+
35
+ Current local run:
36
+
37
+ - Date: `2026-06-08T13:03:42.459Z`
38
+ - Node: `v24.14.1`
39
+ - Platform: `win32`
40
+ - Iterations: `5000`
41
+ - Direct mocked async call: `0.000310 ms/call`
42
+ - Guarded mocked async call: `0.021001 ms/call`
43
+ - Added overhead: `0.020691 ms/call`
44
+ - Benign repeated "again" prompts blocked: `0`
45
+ - Repeated loop prompt blocked at step: `3`
46
+ - GC exposed for memory run: `false`
47
+
48
+ Do not quote benchmark numbers without the Node version, platform, iteration count, and date.
49
+
50
+ Generated benchmark output is intentionally not published in the npm package. Re-run the benchmark on your target runtime before using numbers in public claims.
51
+
52
+ ## Token Accuracy Result
53
+
54
+ Current fixed-corpus token accuracy run:
55
+
56
+ - Reference: `gpt-tokenizer cl100k_base` fixture counts
57
+ - Samples: `8`
58
+ - Average error: `259.08%`
59
+ - Median error: `263.98%`
60
+ - Max error: `323.53%`
61
+
62
+ This shows the current dependency-free estimator is conservative and materially overestimates this corpus. Treat AI CostGuard estimates as pre-call guardrails, not exact provider tokenizer counts.
63
+
64
+ ## Interpreting Results
65
+
66
+ - `runtimeOverhead.addedPerCallMs` is the local overhead added by the guard wrapper in the benchmark request shape.
67
+ - `memoryOverhead.heapDeltaBytes` is noisy unless Node runs with `--expose-gc`.
68
+ - `falsePositiveScenarios.blocked` should remain `0` for the included benign repeated "again" prompts.
69
+ - `loopDetectionBehavior.blockedAtStep` should show when a repeated loop is stopped.
70
+ - `costEstimationBoundaries` reports this package's dependency-free estimator, not exact provider tokenizer output.
@@ -0,0 +1,61 @@
1
+ # Local Dashboard
2
+
3
+ AI CostGuard includes a local-only dashboard command. It does not create an account, send telemetry, or run a cloud backend.
4
+
5
+ The dashboard reads a JSONL event log written by guarded clients:
6
+
7
+ ```ts
8
+ import { guard } from '@salimassili/ai-costguard';
9
+
10
+ const openai = guard(client, {
11
+ budget: 5,
12
+ eventLogPath: '.ai-costguard/events.jsonl',
13
+ eventLogPrompt: 'none',
14
+ });
15
+ ```
16
+
17
+ Start the dashboard:
18
+
19
+ ```bash
20
+ ai-costguard dashboard --events .ai-costguard/events.jsonl --budget 5
21
+ ```
22
+
23
+ For scoped packages or one-off runs:
24
+
25
+ ```bash
26
+ npx @salimassili/ai-costguard dashboard --events .ai-costguard/events.jsonl --budget 5
27
+ ```
28
+
29
+ If the package is installed locally, this also works:
30
+
31
+ ```bash
32
+ npx ai-costguard dashboard --events .ai-costguard/events.jsonl --budget 5
33
+ ```
34
+
35
+ ## What It Shows
36
+
37
+ - Budget used
38
+ - Requests allowed
39
+ - Requests blocked
40
+ - Estimated spend
41
+ - Estimated savings
42
+ - Attempted spend
43
+ - Actual spend when provider usage is available
44
+ - Loop detections
45
+ - Retry detections
46
+ - Recent guard events
47
+
48
+ ## Non-Interactive Summary
49
+
50
+ Use `--once` for CI, smoke tests, or terminal summaries:
51
+
52
+ ```bash
53
+ ai-costguard dashboard --events .ai-costguard/events.jsonl --budget 5 --once
54
+ ai-costguard dashboard --events .ai-costguard/events.jsonl --budget 5 --once --json
55
+ ```
56
+
57
+ ## Privacy Notes
58
+
59
+ `eventLogPrompt` defaults to `none`, so prompt text is not written to disk. Set `eventLogPrompt: 'preview'` only for local debugging where prompt previews are acceptable.
60
+
61
+ The dashboard is a local development view, not a billing ledger. Use provider billing exports for financial reconciliation.