@salimassili/ai-costguard 1.2.0 → 2.0.0
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/CHANGELOG.md +53 -0
- package/LICENSE +21 -0
- package/README.md +281 -103
- package/benchmarks/run.mjs +229 -0
- package/dist/cli.d.ts +50 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +178 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/CostGuard.d.ts +3 -4
- package/dist/core/CostGuard.d.ts.map +1 -1
- package/dist/core/CostGuard.js +1 -2
- package/dist/core/CostGuard.js.map +1 -1
- package/dist/core/GuardCore.d.ts +93 -13
- package/dist/core/GuardCore.d.ts.map +1 -1
- package/dist/core/GuardCore.js +372 -158
- package/dist/core/GuardCore.js.map +1 -1
- package/dist/core/GuardFree.d.ts +42 -18
- package/dist/core/GuardFree.d.ts.map +1 -1
- package/dist/core/GuardFree.js +95 -140
- package/dist/core/GuardFree.js.map +1 -1
- package/dist/core/GuardPro.d.ts +85 -5
- package/dist/core/GuardPro.d.ts.map +1 -1
- package/dist/core/GuardPro.js +216 -121
- package/dist/core/GuardPro.js.map +1 -1
- package/dist/core/event-log.d.ts +37 -0
- package/dist/core/event-log.d.ts.map +1 -0
- package/dist/core/event-log.js +49 -0
- package/dist/core/event-log.js.map +1 -0
- package/dist/core/events.d.ts +20 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +46 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/similarity.d.ts +13 -0
- package/dist/core/similarity.d.ts.map +1 -0
- package/dist/core/similarity.js +51 -0
- package/dist/core/similarity.js.map +1 -0
- package/dist/core/tokenizer.d.ts +18 -0
- package/dist/core/tokenizer.d.ts.map +1 -0
- package/dist/core/tokenizer.js +137 -0
- package/dist/core/tokenizer.js.map +1 -0
- package/dist/core/types.d.ts +153 -5
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +0 -3
- package/dist/core/types.js.map +1 -1
- package/dist/core/webhooks.d.ts +15 -0
- package/dist/core/webhooks.d.ts.map +1 -0
- package/dist/core/webhooks.js +58 -0
- package/dist/core/webhooks.js.map +1 -0
- package/dist/dashboard.d.ts +73 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +201 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/pricing/index.d.ts +19 -2
- package/dist/pricing/index.d.ts.map +1 -1
- package/dist/pricing/index.js +93 -13
- package/dist/pricing/index.js.map +1 -1
- package/dist/pro.d.ts +3 -0
- package/dist/pro.d.ts.map +1 -0
- package/dist/pro.js +2 -0
- package/dist/pro.js.map +1 -0
- package/docs/BENCHMARKS.md +51 -0
- package/docs/DASHBOARD.md +61 -0
- package/docs/INTEGRATIONS.md +153 -0
- package/examples/integrations/anthropic-workflow-budget.mjs +36 -0
- package/examples/integrations/ci-budget-check.mjs +32 -0
- package/examples/integrations/crewai-budget-gate.mjs +31 -0
- package/examples/integrations/langchain-retry-storm.mjs +32 -0
- package/examples/integrations/mastra-agent.mjs +41 -0
- package/examples/integrations/openai-agent-loop.mjs +44 -0
- package/examples/integrations/vercel-ai-chatbot.mjs +29 -0
- package/package.json +35 -7
|
@@ -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('&', '&')
|
|
196
|
+
.replaceAll('<', '<')
|
|
197
|
+
.replaceAll('>', '>')
|
|
198
|
+
.replaceAll('"', '"')
|
|
199
|
+
.replaceAll("'", ''');
|
|
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 {
|
|
3
|
-
export type { GuardProConfig } from './core/GuardPro.js';
|
|
1
|
+
export { guard, guardFunction, GuardError, middleware } from './core/GuardFree.js';
|
|
2
|
+
export type { GuardedClient, GuardEventControls } from './core/GuardFree.js';
|
|
4
3
|
export { 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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC9E,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';
|
|
1
|
+
export { guard, guardFunction, GuardError, middleware } from './core/GuardFree.js';
|
|
3
2
|
export { 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,
|
|
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,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/pricing/index.d.ts
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing entry expressed in USD per 1,000 tokens.
|
|
3
|
+
*/
|
|
1
4
|
export interface ModelPricing {
|
|
5
|
+
/** Model name or model family prefix. */
|
|
2
6
|
model: string;
|
|
7
|
+
/** USD price per 1,000 input tokens. */
|
|
3
8
|
inputPer1kTokens: number;
|
|
9
|
+
/** USD price per 1,000 output tokens. */
|
|
4
10
|
outputPer1kTokens: number;
|
|
11
|
+
/** Date this pricing entry was last checked, formatted as YYYY-MM-DD. */
|
|
5
12
|
lastUpdated: string;
|
|
13
|
+
/** Human-readable source for the pricing entry. */
|
|
6
14
|
source: string;
|
|
7
15
|
}
|
|
8
|
-
|
|
9
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Returns pricing for a model from overrides, runtime entries, or built-in entries.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getPricing(model: string, overrides?: readonly ModelPricing[]): ModelPricing | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Registers or replaces runtime pricing entries by model name.
|
|
22
|
+
*/
|
|
23
|
+
export declare function registerPricing(entries: readonly ModelPricing[]): void;
|
|
24
|
+
/**
|
|
25
|
+
* Lists built-in and runtime pricing entries, deduplicated by normalized model name.
|
|
26
|
+
*/
|
|
10
27
|
export declare function listPricing(): ModelPricing[];
|
|
11
28
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pricing/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pricing/index.ts"],"names":[],"mappings":"AAEA;;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"}
|
package/dist/pricing/index.js
CHANGED
|
@@ -1,60 +1,114 @@
|
|
|
1
|
-
|
|
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;
|
|
4
2
|
const BUILTIN_PRICING = [
|
|
3
|
+
{
|
|
4
|
+
model: 'gpt-5.5',
|
|
5
|
+
inputPer1kTokens: 0.005,
|
|
6
|
+
outputPer1kTokens: 0.03,
|
|
7
|
+
lastUpdated: '2026-06-07',
|
|
8
|
+
source: 'https://developers.openai.com/api/docs/pricing',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
model: 'gpt-5.4',
|
|
12
|
+
inputPer1kTokens: 0.0025,
|
|
13
|
+
outputPer1kTokens: 0.015,
|
|
14
|
+
lastUpdated: '2026-06-07',
|
|
15
|
+
source: 'https://developers.openai.com/api/docs/pricing',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
model: 'gpt-5.4-mini',
|
|
19
|
+
inputPer1kTokens: 0.00075,
|
|
20
|
+
outputPer1kTokens: 0.0045,
|
|
21
|
+
lastUpdated: '2026-06-07',
|
|
22
|
+
source: 'https://developers.openai.com/api/docs/pricing',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
model: 'gpt-5.4-nano',
|
|
26
|
+
inputPer1kTokens: 0.0002,
|
|
27
|
+
outputPer1kTokens: 0.00125,
|
|
28
|
+
lastUpdated: '2026-06-07',
|
|
29
|
+
source: 'https://developers.openai.com/api/docs/pricing',
|
|
30
|
+
},
|
|
5
31
|
{
|
|
6
32
|
model: 'gpt-4',
|
|
7
33
|
inputPer1kTokens: 0.03,
|
|
8
34
|
outputPer1kTokens: 0.06,
|
|
9
35
|
lastUpdated: '2026-05-21',
|
|
10
|
-
source: 'https://openai.com/pricing'
|
|
36
|
+
source: 'https://openai.com/pricing',
|
|
11
37
|
},
|
|
12
38
|
{
|
|
13
39
|
model: 'gpt-4o',
|
|
14
40
|
inputPer1kTokens: 0.005,
|
|
15
41
|
outputPer1kTokens: 0.015,
|
|
16
42
|
lastUpdated: '2026-05-21',
|
|
17
|
-
source: 'https://openai.com/pricing'
|
|
43
|
+
source: 'https://openai.com/pricing',
|
|
18
44
|
},
|
|
19
45
|
{
|
|
20
46
|
model: 'gpt-4o-mini',
|
|
21
47
|
inputPer1kTokens: 0.00015,
|
|
22
48
|
outputPer1kTokens: 0.0006,
|
|
23
49
|
lastUpdated: '2026-05-21',
|
|
24
|
-
source: 'https://openai.com/pricing'
|
|
50
|
+
source: 'https://openai.com/pricing',
|
|
25
51
|
},
|
|
26
52
|
{
|
|
27
53
|
model: 'gpt-3.5-turbo',
|
|
28
54
|
inputPer1kTokens: 0.0005,
|
|
29
55
|
outputPer1kTokens: 0.0015,
|
|
30
56
|
lastUpdated: '2026-05-21',
|
|
31
|
-
source: 'https://openai.com/pricing'
|
|
57
|
+
source: 'https://openai.com/pricing',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
model: 'claude-opus-4.8',
|
|
61
|
+
inputPer1kTokens: 0.005,
|
|
62
|
+
outputPer1kTokens: 0.025,
|
|
63
|
+
lastUpdated: '2026-06-07',
|
|
64
|
+
source: 'https://claude.com/platform/api',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
model: 'claude-sonnet-4.6',
|
|
68
|
+
inputPer1kTokens: 0.003,
|
|
69
|
+
outputPer1kTokens: 0.015,
|
|
70
|
+
lastUpdated: '2026-06-07',
|
|
71
|
+
source: 'https://claude.com/platform/api',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
model: 'claude-haiku-4.5',
|
|
75
|
+
inputPer1kTokens: 0.001,
|
|
76
|
+
outputPer1kTokens: 0.005,
|
|
77
|
+
lastUpdated: '2026-06-07',
|
|
78
|
+
source: 'https://claude.com/platform/api',
|
|
32
79
|
},
|
|
33
80
|
{
|
|
34
81
|
model: 'claude-3-opus',
|
|
35
82
|
inputPer1kTokens: 0.015,
|
|
36
83
|
outputPer1kTokens: 0.075,
|
|
37
84
|
lastUpdated: '2026-05-21',
|
|
38
|
-
source: 'https://www.anthropic.com/pricing'
|
|
85
|
+
source: 'https://www.anthropic.com/pricing',
|
|
39
86
|
},
|
|
40
87
|
{
|
|
41
88
|
model: 'claude-3-sonnet',
|
|
42
89
|
inputPer1kTokens: 0.003,
|
|
43
90
|
outputPer1kTokens: 0.015,
|
|
44
91
|
lastUpdated: '2026-05-21',
|
|
45
|
-
source: 'https://www.anthropic.com/pricing'
|
|
92
|
+
source: 'https://www.anthropic.com/pricing',
|
|
46
93
|
},
|
|
47
94
|
{
|
|
48
95
|
model: 'claude-3-haiku',
|
|
49
96
|
inputPer1kTokens: 0.00025,
|
|
50
97
|
outputPer1kTokens: 0.00125,
|
|
51
98
|
lastUpdated: '2026-05-21',
|
|
52
|
-
source: 'https://www.anthropic.com/pricing'
|
|
53
|
-
}
|
|
99
|
+
source: 'https://www.anthropic.com/pricing',
|
|
100
|
+
},
|
|
54
101
|
];
|
|
55
102
|
const runtimePricing = new Map();
|
|
103
|
+
const staleWarnings = new Set();
|
|
104
|
+
/**
|
|
105
|
+
* Returns pricing for a model from overrides, runtime entries, or built-in entries.
|
|
106
|
+
*/
|
|
56
107
|
export function getPricing(model, overrides = []) {
|
|
57
108
|
const normalizedModel = normalizeModel(model);
|
|
109
|
+
warnIfAnyStale(overrides);
|
|
110
|
+
warnIfAnyStale(runtimePricing.values());
|
|
111
|
+
warnIfAnyStale(BUILTIN_PRICING);
|
|
58
112
|
const overrideExact = findExact(normalizedModel, overrides);
|
|
59
113
|
if (overrideExact)
|
|
60
114
|
return overrideExact;
|
|
@@ -72,11 +126,18 @@ export function getPricing(model, overrides = []) {
|
|
|
72
126
|
return builtinExact;
|
|
73
127
|
return findFuzzy(normalizedModel, BUILTIN_PRICING);
|
|
74
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Registers or replaces runtime pricing entries by model name.
|
|
131
|
+
*/
|
|
75
132
|
export function registerPricing(entries) {
|
|
133
|
+
warnIfAnyStale(entries);
|
|
76
134
|
for (const entry of entries) {
|
|
77
135
|
runtimePricing.set(normalizeModel(entry.model), entry);
|
|
78
136
|
}
|
|
79
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Lists built-in and runtime pricing entries, deduplicated by normalized model name.
|
|
140
|
+
*/
|
|
80
141
|
export function listPricing() {
|
|
81
142
|
const merged = new Map();
|
|
82
143
|
for (const entry of BUILTIN_PRICING) {
|
|
@@ -85,7 +146,9 @@ export function listPricing() {
|
|
|
85
146
|
for (const entry of runtimePricing.values()) {
|
|
86
147
|
merged.set(normalizeModel(entry.model), entry);
|
|
87
148
|
}
|
|
88
|
-
|
|
149
|
+
const entries = Array.from(merged.values());
|
|
150
|
+
warnIfAnyStale(entries);
|
|
151
|
+
return entries;
|
|
89
152
|
}
|
|
90
153
|
function findExact(model, entries) {
|
|
91
154
|
return entries.find((entry) => normalizeModel(entry.model) === model);
|
|
@@ -94,10 +157,27 @@ function findFuzzy(model, entries) {
|
|
|
94
157
|
const sortedEntries = [...entries].sort((a, b) => b.model.length - a.model.length);
|
|
95
158
|
return sortedEntries.find((entry) => {
|
|
96
159
|
const entryModel = normalizeModel(entry.model);
|
|
97
|
-
return model.
|
|
160
|
+
return model.startsWith(`${entryModel}-`) || model.startsWith(`${entryModel}:`);
|
|
98
161
|
});
|
|
99
162
|
}
|
|
100
163
|
function normalizeModel(model) {
|
|
101
164
|
return model.trim().toLowerCase();
|
|
102
165
|
}
|
|
166
|
+
function warnIfAnyStale(entries) {
|
|
167
|
+
for (const entry of entries) {
|
|
168
|
+
warnIfStale(entry);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function warnIfStale(entry) {
|
|
172
|
+
const lastUpdatedMs = Date.parse(`${entry.lastUpdated}T00:00:00.000Z`);
|
|
173
|
+
if (!Number.isFinite(lastUpdatedMs))
|
|
174
|
+
return;
|
|
175
|
+
const ageDays = (Date.now() - lastUpdatedMs) / 86_400_000;
|
|
176
|
+
const warningKey = `${normalizeModel(entry.model)}:${entry.lastUpdated}`;
|
|
177
|
+
if (ageDays > STALE_PRICING_DAYS && !staleWarnings.has(warningKey)) {
|
|
178
|
+
staleWarnings.add(warningKey);
|
|
179
|
+
console.warn(`[AI CostGuard] Pricing for "${entry.model}" is older than ${STALE_PRICING_DAYS} days. ` +
|
|
180
|
+
`Last checked ${entry.lastUpdated}; verify ${entry.source}.`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
103
183
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pricing/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pricing/index.ts"],"names":[],"mappings":"AAAA,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAkB9B,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 @@
|
|
|
1
|
+
{"version":3,"file":"pro.d.ts","sourceRoot":"","sources":["../src/pro.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC5E,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/pro.js
ADDED
package/dist/pro.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pro.js","sourceRoot":"","sources":["../src/pro.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
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
|
+
## Current Local Result
|
|
27
|
+
|
|
28
|
+
Current local run:
|
|
29
|
+
|
|
30
|
+
- Date: `2026-06-08T13:03:42.459Z`
|
|
31
|
+
- Node: `v24.14.1`
|
|
32
|
+
- Platform: `win32`
|
|
33
|
+
- Iterations: `5000`
|
|
34
|
+
- Direct mocked async call: `0.000310 ms/call`
|
|
35
|
+
- Guarded mocked async call: `0.021001 ms/call`
|
|
36
|
+
- Added overhead: `0.020691 ms/call`
|
|
37
|
+
- Benign repeated "again" prompts blocked: `0`
|
|
38
|
+
- Repeated loop prompt blocked at step: `3`
|
|
39
|
+
- GC exposed for memory run: `false`
|
|
40
|
+
|
|
41
|
+
Do not quote benchmark numbers without the Node version, platform, iteration count, and date.
|
|
42
|
+
|
|
43
|
+
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.
|
|
44
|
+
|
|
45
|
+
## Interpreting Results
|
|
46
|
+
|
|
47
|
+
- `runtimeOverhead.addedPerCallMs` is the local overhead added by the guard wrapper in the benchmark request shape.
|
|
48
|
+
- `memoryOverhead.heapDeltaBytes` is noisy unless Node runs with `--expose-gc`.
|
|
49
|
+
- `falsePositiveScenarios.blocked` should remain `0` for the included benign repeated "again" prompts.
|
|
50
|
+
- `loopDetectionBehavior.blockedAtStep` should show when a repeated loop is stopped.
|
|
51
|
+
- `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.
|