@salimassili/ai-costguard 2.1.1 → 2.1.4

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 CHANGED
@@ -1,34 +1,37 @@
1
1
  # Changelog
2
2
 
3
- ## 2.1.1 - Unreleased
4
-
5
- ### Changed
6
-
7
- - Recalibrated the built-in zero-dependency token estimator with simple model-family and text-shape heuristics.
8
- - Improved the fixed proxy token benchmark from `237.76%` average error to `9.68%` average error while keeping `registerTokenizer()` as the recommended exact-counting path.
9
-
10
- ## 2.1.0 - 2026-06-09
11
-
12
- ### Added
13
-
14
- - Added `registerTokenizer()` for exact/provider-specific token counting without adding production dependencies.
15
- - Added `getPricingMeta()` and `aifw pricing --check-stale --days <n>` for pricing freshness checks.
16
- - Added structured `loopDetection` config with `similarityThreshold`, `minHistorySize`, and `windowSize`.
17
- - Expanded the token accuracy benchmark to a 24-sample proxy corpus with per-sample output.
18
-
19
- ### Changed
20
-
21
- - Removed obsolete license-related surfaces. AI CostGuard does not contain license-key checks or local commercial-license enforcement.
22
- - Added explicit built-in pricing freshness notice: `2026-06-07`.
23
- - Updated README loop detection tuning, pricing freshness, token accuracy, and trust guidance.
24
- - Documented that the built-in estimator materially overestimates the fixed proxy corpus and that production users can register exact tokenizers.
25
-
26
- ## 2.0.0 - 2026-06-08
3
+ ## 2.1.1 - Unreleased
4
+
5
+ ### Changed
6
+
7
+ - Recalibrated the built-in zero-dependency token estimator with simple model-family and text-shape heuristics.
8
+ - Improved the fixed proxy token benchmark from `237.76%` average error to `9.68%` average error while keeping `registerTokenizer()` as the recommended exact-counting path.
9
+ - Removed tracked generated coverage output, legacy artifacts, and archived pre-CostGuard concept docs from the active repository.
10
+ - Renamed starter templates from `*-firewall` to `*-costguard` and updated template dependencies to `@salimassili/ai-costguard` `^2.1.1`.
11
+ - Aligned Pro copy around the current $19/month or $199/year Lemon Squeezy plan and marked the `pro-v0.1` folder as a Redis-focused starter.
12
+
13
+ ## 2.1.0 - 2026-06-09
14
+
15
+ ### Added
16
+
17
+ - Added `registerTokenizer()` for exact/provider-specific token counting without adding production dependencies.
18
+ - Added `getPricingMeta()` and `aifw pricing --check-stale --days <n>` for pricing freshness checks.
19
+ - Added structured `loopDetection` config with `similarityThreshold`, `minHistorySize`, and `windowSize`.
20
+ - Expanded the token accuracy benchmark to a 24-sample proxy corpus with per-sample output.
21
+
22
+ ### Changed
23
+
24
+ - Removed obsolete license-related surfaces. AI CostGuard does not contain license-key checks or local commercial-license enforcement.
25
+ - Added explicit built-in pricing freshness notice: `2026-06-07`.
26
+ - Updated README loop detection tuning, pricing freshness, token accuracy, and trust guidance.
27
+ - Documented that the built-in estimator materially overestimates the fixed proxy corpus and that production users can register exact tokenizers.
28
+
29
+ ## 2.0.0 - 2026-06-08
27
30
 
28
31
  ### Changed
29
32
 
30
33
  - Moved Redis-backed `GuardPro` exports to `@salimassili/ai-costguard/pro` so the root import stays lightweight.
31
- - Removed fake local license enforcement from `GuardPro`.
34
+ - Removed fake local license enforcement from `GuardPro`.
32
35
  - Unknown models now block by default unless runtime pricing, guard pricing overrides, or explicit fallback pricing is configured.
33
36
  - Guard proxy now checks known AI SDK method paths instead of charging every function call on the wrapped client.
34
37
  - Loop detection now requires repeated similar prompts in the same scope before blocking.
package/README.md CHANGED
@@ -1,27 +1,28 @@
1
1
  # AI CostGuard
2
2
  [![npm version](https://img.shields.io/npm/v/@salimassili/ai-costguard)](https://www.npmjs.com/package/@salimassili/ai-costguard)
3
+ [![AI CostGuard Pro](https://img.shields.io/badge/Pro-$19%2Fmo-orange)](https://salimassili.lemonsqueezy.com/buy/ai-costguard-pro)
3
4
 
4
5
  AI CostGuard is a local-first runtime safety layer for AI agents that prevents runaway costs, loops, retries, and budget explosions before API calls execute. It wraps OpenAI-compatible clients and function-style SDK calls, estimates request cost locally, blocks budget overruns, detects repeated prompts, emits structured events, and exposes CLI checks plus a local dashboard.
5
6
 
6
- It is local-first. It does not include a SaaS control plane, cloud dashboard, proxy gateway, telemetry service, billing reconciliation service, or hard security boundary.
7
-
8
- ## What AI CostGuard Does
9
-
10
- - Checks selected AI SDK calls before they execute.
11
- - Estimates request cost from model pricing, prompt text, and reserved output tokens.
12
- - Blocks unknown models unless explicit pricing is supplied.
13
- - Blocks budget overruns, repeated prompt loops, retry storms, and max-step overruns.
14
- - Emits structured errors and local events your app can handle.
15
-
16
- ## What AI CostGuard Does Not Do
17
-
18
- - It does not call providers for real-time pricing.
19
- - It does not reconcile provider invoices or replace provider billing alerts.
20
- - It does not provide auth, API-key security, or a hard security boundary.
21
- - It does not run a hosted dashboard, SaaS backend, or cloud telemetry service.
22
- - It does not guarantee exact tokenizer parity with OpenAI, Anthropic, or other providers.
23
-
24
- ## Install
7
+ It is local-first. It does not include a SaaS control plane, cloud dashboard, proxy gateway, telemetry service, billing reconciliation service, or hard security boundary.
8
+
9
+ ## What AI CostGuard Does
10
+
11
+ - Checks selected AI SDK calls before they execute.
12
+ - Estimates request cost from model pricing, prompt text, and reserved output tokens.
13
+ - Blocks unknown models unless explicit pricing is supplied.
14
+ - Blocks budget overruns, repeated prompt loops, retry storms, and max-step overruns.
15
+ - Emits structured errors and local events your app can handle.
16
+
17
+ ## What AI CostGuard Does Not Do
18
+
19
+ - It does not call providers for real-time pricing.
20
+ - It does not reconcile provider invoices or replace provider billing alerts.
21
+ - It does not provide auth, API-key security, or a hard security boundary.
22
+ - It does not run a hosted dashboard, SaaS backend, or cloud telemetry service.
23
+ - It does not guarantee exact tokenizer parity with OpenAI, Anthropic, or other providers.
24
+
25
+ ## Install
25
26
 
26
27
  ```bash
27
28
  npm install @salimassili/ai-costguard
@@ -53,30 +54,30 @@ try {
53
54
  } else {
54
55
  throw error;
55
56
  }
56
- }
57
- ```
58
-
59
- ## Before / After
60
-
61
- Without AI CostGuard:
62
-
63
- ```ts
64
- await openai.chat.completions.create(request);
65
- ```
66
-
67
- With AI CostGuard:
68
-
69
- ```ts
70
- const openai = guard(new OpenAI({ apiKey: process.env.OPENAI_API_KEY }), {
71
- budget: 5,
72
- maxSteps: 50,
73
- scope: { projectId: 'agent-api', sessionId: runId },
74
- });
75
-
76
- await openai.chat.completions.create(request);
77
- ```
78
-
79
- ## What It Guards
57
+ }
58
+ ```
59
+
60
+ ## Before / After
61
+
62
+ Without AI CostGuard:
63
+
64
+ ```ts
65
+ await openai.chat.completions.create(request);
66
+ ```
67
+
68
+ With AI CostGuard:
69
+
70
+ ```ts
71
+ const openai = guard(new OpenAI({ apiKey: process.env.OPENAI_API_KEY }), {
72
+ budget: 5,
73
+ maxSteps: 50,
74
+ scope: { projectId: 'agent-api', sessionId: runId },
75
+ });
76
+
77
+ await openai.chat.completions.create(request);
78
+ ```
79
+
80
+ ## What It Guards
80
81
 
81
82
  By default AI CostGuard evaluates these SDK method paths:
82
83
 
@@ -143,21 +144,21 @@ Current runtime block codes:
143
144
  - `LOOP_DETECTED`
144
145
  - `RETRY_STORM_DETECTED`
145
146
 
146
- ## Configuration
147
+ ## Configuration
147
148
 
148
149
  ```ts
149
150
  guard(client, {
150
151
  budget: 10,
151
152
  maxSteps: 100,
152
- behaviorAnalysis: true,
153
- maxHistory: 32,
154
- historyTtlMs: 5 * 60 * 1000,
155
- loopDetection: {
156
- similarityThreshold: 0.85,
157
- minHistorySize: 2,
158
- windowSize: 5,
159
- },
160
- retryThreshold: 2,
153
+ behaviorAnalysis: true,
154
+ maxHistory: 32,
155
+ historyTtlMs: 5 * 60 * 1000,
156
+ loopDetection: {
157
+ similarityThreshold: 0.85,
158
+ minHistorySize: 2,
159
+ windowSize: 5,
160
+ },
161
+ retryThreshold: 2,
161
162
  scope: {
162
163
  projectId: 'production-api',
163
164
  userId: 'optional-user',
@@ -176,38 +177,38 @@ guard(client, {
176
177
  });
177
178
  ```
178
179
 
179
- `scope` isolates budgets and behavior history. If no scope is supplied, the guard uses one process-local default scope.
180
-
181
- ## Loop Detection Tuning
182
-
183
- Default loop detection uses character trigram cosine similarity with:
184
-
185
- - `loopDetection.similarityThreshold: 0.85`
186
- - `loopDetection.minHistorySize: 2`
187
- - `loopDetection.windowSize: 5`
188
-
189
- - Higher threshold, such as `0.95`: fewer false positives, but near-duplicate loops can slip through.
190
- - Lower threshold, such as `0.75`: catches looser repeats, but unrelated prompts can be blocked.
191
- - Higher `minHistorySize`: waits for more repeated prompts before blocking.
192
- - Lower `minHistorySize`: blocks faster, but is more aggressive.
193
- - Smaller `windowSize`: compares fewer recent prompts, reducing old-history false positives.
194
- - Larger `windowSize`: compares more history, improving catch rate but increasing false-positive risk in repetitive workflows.
195
-
196
- ```ts
197
- const openai = guard(client, {
198
- budget: 5,
199
- loopDetection: {
200
- similarityThreshold: 0.9,
201
- minHistorySize: 3,
202
- windowSize: 6,
203
- },
204
- scope: { sessionId: 'agent-run-123' },
205
- });
206
- ```
207
-
208
- Legacy `loopSimilarityThreshold` and `loopMinRepeats` config fields are still accepted, but `loopDetection` takes precedence. Loop detection is heuristic. Expect false positives and false negatives, especially for short prompts, templated prompts, and prompts that share a lot of boilerplate.
209
-
210
- ## Accounting Semantics
180
+ `scope` isolates budgets and behavior history. If no scope is supplied, the guard uses one process-local default scope.
181
+
182
+ ## Loop Detection Tuning
183
+
184
+ Default loop detection uses character trigram cosine similarity with:
185
+
186
+ - `loopDetection.similarityThreshold: 0.85`
187
+ - `loopDetection.minHistorySize: 2`
188
+ - `loopDetection.windowSize: 5`
189
+
190
+ - Higher threshold, such as `0.95`: fewer false positives, but near-duplicate loops can slip through.
191
+ - Lower threshold, such as `0.75`: catches looser repeats, but unrelated prompts can be blocked.
192
+ - Higher `minHistorySize`: waits for more repeated prompts before blocking.
193
+ - Lower `minHistorySize`: blocks faster, but is more aggressive.
194
+ - Smaller `windowSize`: compares fewer recent prompts, reducing old-history false positives.
195
+ - Larger `windowSize`: compares more history, improving catch rate but increasing false-positive risk in repetitive workflows.
196
+
197
+ ```ts
198
+ const openai = guard(client, {
199
+ budget: 5,
200
+ loopDetection: {
201
+ similarityThreshold: 0.9,
202
+ minHistorySize: 3,
203
+ windowSize: 6,
204
+ },
205
+ scope: { sessionId: 'agent-run-123' },
206
+ });
207
+ ```
208
+
209
+ Legacy `loopSimilarityThreshold` and `loopMinRepeats` config fields are still accepted, but `loopDetection` takes precedence. Loop detection is heuristic. Expect false positives and false negatives, especially for short prompts, templated prompts, and prompts that share a lot of boilerplate.
210
+
211
+ ## Accounting Semantics
211
212
 
212
213
  AI CostGuard is a pre-call estimator, not a billing ledger.
213
214
 
@@ -218,14 +219,14 @@ AI CostGuard is a pre-call estimator, not a billing ledger.
218
219
 
219
220
  Budget decisions use estimated allowed cost. Actual usage is recorded for observability but does not rewrite earlier decisions.
220
221
 
221
- ## Pricing
222
-
223
- Known model pricing comes from built-in registry entries, runtime registrations, or per-guard overrides. Unknown models are blocked by default.
224
-
225
- Pricing last updated: `2026-06-07`. Provider pricing changes; AI CostGuard does not fetch real-time pricing. Override pricing manually when provider pages or your contract pricing differ from the built-ins.
222
+ ## Pricing
223
+
224
+ Known model pricing comes from built-in registry entries, runtime registrations, or per-guard overrides. Unknown models are blocked by default.
225
+
226
+ Pricing last updated: `2026-06-07`. Provider pricing changes; AI CostGuard does not fetch real-time pricing. Override pricing manually when provider pages or your contract pricing differ from the built-ins.
226
227
 
227
228
  ```ts
228
- import { getPricingMeta, registerPricing } from '@salimassili/ai-costguard';
229
+ import { getPricingMeta, registerPricing } from '@salimassili/ai-costguard';
229
230
 
230
231
  registerPricing([
231
232
  {
@@ -235,18 +236,18 @@ registerPricing([
235
236
  lastUpdated: '2026-06-07',
236
237
  source: 'internal',
237
238
  },
238
- ]);
239
-
240
- console.log(getPricingMeta('gpt-4o-mini'));
241
- ```
242
-
243
- Check built-in pricing freshness from CI or a release script:
244
-
245
- ```bash
246
- aifw pricing --check-stale --days 30
247
- ```
248
-
249
- The command exits `0` when all registry entries are within the threshold and `1` when one or more entries are stale.
239
+ ]);
240
+
241
+ console.log(getPricingMeta('gpt-4o-mini'));
242
+ ```
243
+
244
+ Check built-in pricing freshness from CI or a release script:
245
+
246
+ ```bash
247
+ aifw pricing --check-stale --days 30
248
+ ```
249
+
250
+ The command exits `0` when all registry entries are within the threshold and `1` when one or more entries are stale.
250
251
 
251
252
  If you intentionally want fallback pricing for unknown models:
252
253
 
@@ -264,31 +265,31 @@ guard(client, {
264
265
  });
265
266
  ```
266
267
 
267
- Pricing changes frequently. Verify provider pricing before production use and override entries when needed.
268
-
269
- ## Token Counting Accuracy
270
-
271
- AI CostGuard ships with a dependency-free token estimator so the root package stays small. It warns once per model/scope when approximate counting is used:
272
-
273
- ```text
274
- [ai-costguard] Using approximate token counting for model: gpt-4o-mini. Register an exact tokenizer via registerTokenizer() for production use.
275
- ```
276
-
277
- For production budgets that need tighter input-token estimates, register a provider tokenizer:
278
-
279
- ```ts
280
- import { registerTokenizer } from '@salimassili/ai-costguard';
281
-
282
- registerTokenizer('gpt-4o-mini', (text) => {
283
- return myTokenizer.encode(text).length;
284
- });
285
-
286
- registerTokenizer(/^claude-/u, (text) => {
287
- return myAnthropicTokenizer.count(text);
288
- });
289
- ```
290
-
291
- String patterns match model-name substrings case-insensitively. `RegExp` patterns are tested against the original model string. If a registered tokenizer throws or returns an invalid count, AI CostGuard falls back to the built-in approximation and keeps guarding the call.
268
+ Pricing changes frequently. Verify provider pricing before production use and override entries when needed.
269
+
270
+ ## Token Counting Accuracy
271
+
272
+ AI CostGuard ships with a dependency-free token estimator so the root package stays small. It warns once per model/scope when approximate counting is used:
273
+
274
+ ```text
275
+ [ai-costguard] Using approximate token counting for model: gpt-4o-mini. Register an exact tokenizer via registerTokenizer() for production use.
276
+ ```
277
+
278
+ For production budgets that need tighter input-token estimates, register a provider tokenizer:
279
+
280
+ ```ts
281
+ import { registerTokenizer } from '@salimassili/ai-costguard';
282
+
283
+ registerTokenizer('gpt-4o-mini', (text) => {
284
+ return myTokenizer.encode(text).length;
285
+ });
286
+
287
+ registerTokenizer(/^claude-/u, (text) => {
288
+ return myAnthropicTokenizer.count(text);
289
+ });
290
+ ```
291
+
292
+ String patterns match model-name substrings case-insensitively. `RegExp` patterns are tested against the original model string. If a registered tokenizer throws or returns an invalid count, AI CostGuard falls back to the built-in approximation and keeps guarding the call.
292
293
 
293
294
  ## Events
294
295
 
@@ -400,7 +401,25 @@ await pro.shutdown();
400
401
 
401
402
  `ioredis` is an optional dependency and is not loaded by the root import.
402
403
 
403
- AI CostGuard does not include license-key checks or local commercial-license enforcement.
404
+ AI CostGuard does not include license-key checks or local commercial-license enforcement.
405
+
406
+ ## AI CostGuard Pro
407
+
408
+ AI CostGuard Free is the open-source npm package above — free forever, MIT licensed.
409
+
410
+ **AI CostGuard Pro** is a $19/month or $199/year subscription for teams taking AI agents into production. Lemon Squeezy handles purchase, receipts, and subscription management. The npm package does not perform runtime license-key enforcement.
411
+
412
+ Current `pro-v0.1` materials include:
413
+
414
+ - Redis/GuardPro setup guide
415
+ - Multi-process shared-budget example
416
+ - Environment-variable based Redis/webhook configuration guidance
417
+
418
+ Planned monthly updates include multi-tenant examples, tokenizer adapter recipes, `GuardError` handling patterns, pricing override guides, production checklists, and framework config starters as those files are completed.
419
+
420
+ No runtime license-key enforcement. No private npm package. No SaaS backend. You get a downloadable folder of setup materials and examples that use the public package API. Use environment variables or your deployment secret manager for provider keys, `REDIS_URL`, and webhook URLs; never hardcode secrets.
421
+
422
+ [Get AI CostGuard Pro →](https://salimassili.lemonsqueezy.com/buy/ai-costguard-pro)
404
423
 
405
424
  ## CLI
406
425
 
@@ -436,11 +455,11 @@ npm run build
436
455
  npm run benchmark
437
456
  ```
438
457
 
439
- The script reports runtime overhead, approximate heap delta, false-positive scenarios, loop detection behavior, and cost-estimation boundaries. Results are local measurements, not universal guarantees. See `docs/BENCHMARKS.md`.
440
-
441
- Latest local benchmark in this repo on Node `v24.14.1` / Windows measured `0.023937 ms` added per mocked guarded call over `5000` iterations. Re-run on your target runtime before using this number in performance-sensitive claims.
442
-
443
- Token accuracy benchmark, fixed proxy corpus: average error `9.68%`, median error `11.43%`, max error `28.57%`, `24` samples. The dependency-free estimator is a rough guardrail, not provider-tokenizer parity. Register an exact tokenizer for production use when token accuracy matters.
458
+ The script reports runtime overhead, approximate heap delta, false-positive scenarios, loop detection behavior, and cost-estimation boundaries. Results are local measurements, not universal guarantees. See `docs/BENCHMARKS.md`.
459
+
460
+ Latest local benchmark in this repo on Node `v24.14.1` / Windows measured `0.023937 ms` added per mocked guarded call over `5000` iterations. Re-run on your target runtime before using this number in performance-sensitive claims.
461
+
462
+ Token accuracy benchmark, fixed proxy corpus: average error `9.68%`, median error `11.43%`, max error `28.57%`, `24` samples. The dependency-free estimator is a rough guardrail, not provider-tokenizer parity. Register an exact tokenizer for production use when token accuracy matters.
444
463
 
445
464
  ## Why Not 50 Lines Of Code?
446
465
 
@@ -463,18 +482,18 @@ npm ci
463
482
  npm run build
464
483
  npm run typecheck
465
484
  npm test
466
- npm run smoke
467
- npm run benchmark
468
- npm run benchmark:tokens
469
- npm audit --omit=dev
470
- npm pack --dry-run
485
+ npm run smoke
486
+ npm run benchmark
487
+ npm run benchmark:tokens
488
+ npm audit --omit=dev
489
+ npm pack --dry-run
471
490
  ```
472
491
 
473
492
  ## Limitations
474
493
 
475
- - Token counting is approximate and dependency-free unless you register an exact tokenizer.
476
- - Token estimation is intentionally conservative and can overestimate materially; see the token accuracy benchmark.
477
- - Pricing entries can become stale; override them for production.
494
+ - Token counting is approximate and dependency-free unless you register an exact tokenizer.
495
+ - Token estimation is intentionally conservative and can overestimate materially; see the token accuracy benchmark.
496
+ - Pricing entries can become stale; override them for production.
478
497
  - The free guard is process-local.
479
498
  - Loop detection uses character trigram similarity, not embeddings.
480
499
  - Retry detection is heuristic.
@@ -1 +1 @@
1
- {"version":3,"file":"GuardPro.d.ts","sourceRoot":"","sources":["../../src/core/GuardPro.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAkB,MAAM,YAAY,CAAC;AAGrE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,EAAE,CAAC,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IAC1E,0DAA0D;IAC1D,OAAO,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,uDAAuD;IACvD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtG,qCAAqC;IACrC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,2BAA2B;IAC3B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,6BAA6B;IAC7B,IAAI,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,6FAA6F;IAC7F,WAAW,CAAC,EAAE,mBAAmB,CAAC;CACnC;AAcD;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAElE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAiB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAqB;IAC/C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuC;IAClE,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,gBAAgB,CAAS;IAEjC;;OAEG;gBACS,MAAM,EAAE,cAAc;IAsBlC;;OAEG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB7E;;OAEG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAclD;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAalD;;OAEG;IACH,WAAW,IAAI,OAAO;IAKtB;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAe/B,OAAO,CAAC,MAAM,CAAC,YAAY;IA+B3B,OAAO,CAAC,sBAAsB;YAchB,cAAc;YAed,OAAO;YAiBP,wBAAwB;YAcxB,cAAc;IAc5B,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,QAAQ;IAgBhB,OAAO,CAAC,gBAAgB;YAUV,QAAQ;IAQtB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,aAAa;CAWtB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ,CAE5D"}
1
+ {"version":3,"file":"GuardPro.d.ts","sourceRoot":"","sources":["../../src/core/GuardPro.ts"],"names":[],"mappings":"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"}
@@ -41,6 +41,12 @@ export class GuardPro {
41
41
  * Atomically charges estimated spend for a project and throws GuardError when budget is exceeded.
42
42
  */
43
43
  async checkAndCharge(projectId, estimatedCost) {
44
+ if (!projectId.trim()) {
45
+ throw new Error('GuardPro projectId must be a non-empty string');
46
+ }
47
+ if (!Number.isFinite(estimatedCost) || estimatedCost < 0) {
48
+ throw new Error('GuardPro estimatedCost must be a finite non-negative number');
49
+ }
44
50
  const key = this.getSpendKey(projectId);
45
51
  const redis = await this.getUsableRedis();
46
52
  const total = redis
@@ -202,7 +208,11 @@ export class GuardPro {
202
208
  return total
203
209
  `;
204
210
  const total = await redis.eval(script, 1, key, estimatedCost.toString(), this.windowSeconds.toString());
205
- return Number(total);
211
+ const numericTotal = Number(total);
212
+ if (!Number.isFinite(numericTotal) || numericTotal < 0) {
213
+ throw new Error('Redis returned an invalid spend total');
214
+ }
215
+ return numericTotal;
206
216
  }
207
217
  incrementLocal(projectId, estimatedCost) {
208
218
  const record = this.getLocal(projectId);
@@ -1 +1 @@
1
- {"version":3,"file":"GuardPro.js","sourceRoot":"","sources":["../../src/core/GuardPro.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GuardPro.js","sourceRoot":"","sources":["../../src/core/GuardPro.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { guard, GuardError, registerTokenizer } from '@salimassili/ai-costguard';
2
+
3
+ const slackWebhook = process.env.COSTGUARD_SLACK_WEBHOOK;
4
+ let providerCalls = 0;
5
+
6
+ // Keeps this demo output quiet and deterministic. Production apps can keep the
7
+ // default estimator or register a provider-specific tokenizer.
8
+ registerTokenizer('gpt-4o-mini', (text) => Math.ceil(text.length / 4));
9
+
10
+ const mockedOpenAI = {
11
+ chat: {
12
+ completions: {
13
+ create: async () => {
14
+ providerCalls += 1;
15
+ return {
16
+ id: 'mocked-provider-response',
17
+ choices: [{ message: { content: 'This should never execute in the demo.' } }],
18
+ };
19
+ },
20
+ },
21
+ },
22
+ };
23
+
24
+ const openai = guard(mockedOpenAI, {
25
+ budget: 0.0001,
26
+ scope: { projectId: 'sales-demo', sessionId: 'slack-webhook-block-demo' },
27
+ webhooks: {
28
+ slack: slackWebhook,
29
+ retries: 0,
30
+ timeoutMs: 1000,
31
+ },
32
+ });
33
+
34
+ console.log('AI CostGuard Slack webhook block demo');
35
+ console.log('Scenario: an agent tries to start an expensive model call with almost no budget left.');
36
+ console.log(`Slack alert: ${slackWebhook ? 'enabled from COSTGUARD_SLACK_WEBHOOK' : 'off by default'}`);
37
+
38
+ try {
39
+ await openai.chat.completions.create({
40
+ model: 'gpt-4o-mini',
41
+ messages: [
42
+ {
43
+ role: 'user',
44
+ content:
45
+ 'Run a large analysis job, summarize every retry, and reserve enough output for a long report.',
46
+ },
47
+ ],
48
+ max_tokens: 800,
49
+ });
50
+
51
+ throw new Error('Expected AI CostGuard to block before the mocked provider ran.');
52
+ } catch (error) {
53
+ if (!(error instanceof GuardError)) {
54
+ throw error;
55
+ }
56
+
57
+ console.log('Result: BLOCKED before provider execution');
58
+ console.log(`Reason: ${error.code}`);
59
+ console.log(`Estimated avoided spend: $${error.context.estimatedCost.toFixed(6)}`);
60
+ console.log(`Provider calls executed: ${providerCalls}`);
61
+ console.log('Webhook URL printed: no');
62
+ }
63
+
64
+ if (providerCalls !== 0) {
65
+ throw new Error(`Provider executed ${providerCalls} time(s); expected 0.`);
66
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salimassili/ai-costguard",
3
- "version": "2.1.1",
3
+ "version": "2.1.4",
4
4
  "description": "Local-first runtime safety layer for AI agents that blocks runaway costs, loops, retries, and budget overruns before API calls execute.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -31,11 +31,11 @@
31
31
  "files": [
32
32
  "dist",
33
33
  "docs/DASHBOARD.md",
34
- "docs/INTEGRATIONS.md",
35
- "docs/BENCHMARKS.md",
36
- "examples/integrations",
37
- "benchmarks/run.mjs",
38
- "benchmarks/token-accuracy.mjs",
34
+ "docs/INTEGRATIONS.md",
35
+ "docs/BENCHMARKS.md",
36
+ "examples/integrations",
37
+ "benchmarks/run.mjs",
38
+ "benchmarks/token-accuracy.mjs",
39
39
  "README.md",
40
40
  "CHANGELOG.md",
41
41
  "LICENSE"
@@ -44,10 +44,10 @@
44
44
  "clean": "rimraf dist",
45
45
  "build": "npm run clean && tsc",
46
46
  "typecheck": "tsc --noEmit",
47
- "test": "npm run build && node --test --experimental-test-coverage --test-coverage-include=dist/**/*.js --test-coverage-lines=80 --test-coverage-functions=80 --test-coverage-branches=70 \"test/**/*.test.mjs\"",
47
+ "test": "npm run build && node scripts/run-tests.js",
48
48
  "smoke": "node test/smoke-examples.mjs",
49
- "benchmark": "node benchmarks/run.mjs",
50
- "benchmark:tokens": "node benchmarks/token-accuracy.mjs",
49
+ "benchmark": "node benchmarks/run.mjs",
50
+ "benchmark:tokens": "node benchmarks/token-accuracy.mjs",
51
51
  "preflight": "node scripts/preflight.js",
52
52
  "prepublishOnly": "npm run preflight"
53
53
  },