@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
@@ -1,158 +1,244 @@
1
- /*
2
- * Usage:
3
- *
4
- * import { GuardPro } from '@salimassili/ai-costguard';
5
- *
6
- * const guard = new GuardPro({
7
- * redisUrl: 'redis://localhost:6379',
8
- * budget: 25,
9
- * windowSeconds: 86400,
10
- * slackWebhook: process.env.SLACK_WEBHOOK,
11
- * licenseKey: process.env.COSTGUARD_LICENSE
12
- * });
13
- *
14
- * await guard.checkAndCharge('production', 0.0042);
15
- * await guard.shutdown();
16
- *
17
- * No Redis? Get a free one at https://upstash.com
18
- */
19
1
  import { Redis } from 'ioredis';
20
- import { GuardError } from './GuardFree.js';
2
+ import { GuardError } from './GuardCore.js';
3
+ import { notifyBlockWebhooks } from './webhooks.js';
4
+ /**
5
+ * Redis-backed budget guard with local fallback when Redis is unavailable.
6
+ */
21
7
  export class GuardPro {
22
- redis;
8
+ static pools = new Map();
9
+ redisUrl;
10
+ redisClient;
11
+ poolEntry;
23
12
  budget;
24
13
  windowSeconds;
25
- slackWebhook;
26
- connected = false;
14
+ webhooks;
15
+ localSpend = new Map();
16
+ directRedisFailed = false;
17
+ directRedisReady = false;
18
+ /**
19
+ * Creates a GuardPro instance and reuses a pooled Redis connection for the same URL.
20
+ */
27
21
  constructor(config) {
28
- if (config.licenseKey && !validateLicense(config.licenseKey)) {
29
- throw new GuardError('Invalid CostGuard Pro license key. ' +
30
- 'Your key must be at least 16 characters and pass checksum validation.');
22
+ this.redisUrl = config.redisUrl;
23
+ this.budget = config.budget;
24
+ this.windowSeconds = config.windowSeconds ?? 86_400;
25
+ this.webhooks = {
26
+ ...config.webhooks,
27
+ slack: config.webhooks?.slack ?? config.slackWebhook,
28
+ discord: config.webhooks?.discord ?? config.discordWebhook,
29
+ };
30
+ if (config.redisClient) {
31
+ this.redisClient = config.redisClient;
32
+ this.attachConnectionEvents(config.redisClient);
33
+ return;
31
34
  }
32
- try {
33
- this.redis = new Redis(config.redisUrl, {
34
- lazyConnect: true,
35
- enableOfflineQueue: false,
36
- retryStrategy: () => null,
37
- });
38
- this.redis.on('ready', () => {
39
- this.connected = true;
40
- });
41
- this.redis.on('error', () => {
42
- this.connected = false;
43
- });
44
- this.redis.on('close', () => {
45
- this.connected = false;
46
- });
47
- this.redis.connect().then(() => {
48
- this.connected = true;
49
- }).catch(() => {
50
- throw new GuardError('GuardPro requires a Redis connection. ' +
51
- 'Pass a valid redisUrl in GuardProConfig. ' +
52
- 'Free option: create an Upstash account at https://upstash.com ' +
53
- 'and paste your Redis URL.');
54
- });
55
- }
56
- catch (error) {
57
- if (error instanceof GuardError)
58
- throw error;
59
- throw new GuardError('GuardPro failed to initialize Redis. ' +
60
- 'Pass a valid redisUrl in GuardProConfig. ' +
61
- 'Free option: create an Upstash account at https://upstash.com ' +
62
- 'and paste your Redis URL.');
35
+ if (config.redisUrl.trim()) {
36
+ this.poolEntry = GuardPro.getPoolEntry(config.redisUrl);
37
+ this.redisClient = this.poolEntry.client;
63
38
  }
64
- this.budget = config.budget;
65
- this.windowSeconds = config.windowSeconds ?? 86400;
66
- this.slackWebhook = config.slackWebhook;
67
39
  }
40
+ /**
41
+ * Atomically charges estimated spend for a project and throws GuardError when budget is exceeded.
42
+ */
68
43
  async checkAndCharge(projectId, estimatedCost) {
69
- if (!this.connected) {
70
- throw new GuardError('GuardPro lost Redis connection. ' +
71
- 'Spending is blocked until connection is restored.');
72
- }
73
- let total;
74
- try {
75
- const key = this.getSpendKey(projectId);
76
- total = await this.incrementSpend(key, estimatedCost);
77
- }
78
- catch (error) {
79
- if (error instanceof GuardError)
80
- throw error;
81
- throw new GuardError('GuardPro lost Redis connection. ' +
82
- 'Spending is blocked until connection is restored.');
83
- }
44
+ const key = this.getSpendKey(projectId);
45
+ const redis = await this.getUsableRedis();
46
+ const total = redis
47
+ ? await this.incrementRedisOrFallback(redis, key, projectId, estimatedCost)
48
+ : this.incrementLocal(projectId, estimatedCost);
84
49
  if (total > this.budget) {
85
- if (this.slackWebhook) {
86
- try {
87
- await this.sendBudgetAlert(projectId, total);
88
- }
89
- catch {
90
- console.error('[CostGuard] Slack webhook failed — budget still enforced.');
91
- }
92
- }
93
- throw new GuardError(`Project "${projectId}" exceeded budget. ` +
94
- `Spend: $${total.toFixed(6)} / Budget: $${this.budget.toFixed(6)}`, this.createContext(projectId, estimatedCost));
50
+ const context = this.createContext(projectId, estimatedCost);
51
+ const reason = `Project "${projectId}" exceeded budget. ` +
52
+ `Spend: $${total.toFixed(6)} / Budget: $${this.budget.toFixed(6)}`;
53
+ await notifyBlockWebhooks(this.webhooks, { reason, context });
54
+ throw new GuardError(reason, context, 'BUDGET_EXCEEDED');
95
55
  }
96
56
  }
57
+ /**
58
+ * Returns current spend for a project from Redis when available, otherwise from local fallback state.
59
+ */
97
60
  async getSpend(projectId) {
98
- if (!this.connected)
99
- return 0;
100
- try {
101
- const value = await this.redis.get(this.getSpendKey(projectId));
102
- return value ? Number(value) : 0;
103
- }
104
- catch {
105
- return 0;
61
+ const redis = await this.getUsableRedis();
62
+ if (redis) {
63
+ try {
64
+ const value = await redis.get(this.getSpendKey(projectId));
65
+ return value ? Number(value) : 0;
66
+ }
67
+ catch {
68
+ this.markDisconnected();
69
+ }
106
70
  }
71
+ return this.getLocal(projectId).total;
107
72
  }
73
+ /**
74
+ * Resets spend for a project in Redis when available and always clears local fallback state.
75
+ */
108
76
  async resetSpend(projectId) {
109
- if (!this.connected)
77
+ this.localSpend.delete(projectId);
78
+ const redis = await this.getUsableRedis();
79
+ if (!redis)
110
80
  return;
111
81
  try {
112
- await this.redis.del(this.getSpendKey(projectId));
82
+ await redis.del(this.getSpendKey(projectId));
113
83
  }
114
84
  catch {
115
- // silent — reset is best-effort
85
+ this.markDisconnected();
116
86
  }
117
87
  }
88
+ /**
89
+ * Returns true when the pooled or supplied Redis client is currently connected.
90
+ */
118
91
  isConnected() {
119
- return this.connected;
92
+ if (this.poolEntry)
93
+ return this.poolEntry.connected;
94
+ return !this.directRedisFailed && (this.redisClient?.status === 'ready' || this.directRedisReady);
120
95
  }
96
+ /**
97
+ * Releases this instance's pooled Redis reference and closes the connection when unused.
98
+ */
121
99
  async shutdown() {
100
+ if (this.poolEntry) {
101
+ this.poolEntry.refs -= 1;
102
+ if (this.poolEntry.refs <= 0) {
103
+ GuardPro.pools.delete(this.redisUrl);
104
+ await this.safeQuit(this.poolEntry.client);
105
+ }
106
+ return;
107
+ }
108
+ if (this.redisClient) {
109
+ await this.safeQuit(this.redisClient);
110
+ }
111
+ }
112
+ static getPoolEntry(redisUrl) {
113
+ const existing = GuardPro.pools.get(redisUrl);
114
+ if (existing) {
115
+ existing.refs += 1;
116
+ return existing;
117
+ }
118
+ const entry = {
119
+ client: new Redis(redisUrl, {
120
+ lazyConnect: true,
121
+ enableOfflineQueue: false,
122
+ retryStrategy: () => null,
123
+ }),
124
+ refs: 1,
125
+ connected: false,
126
+ };
127
+ entry.client.on?.('ready', () => {
128
+ entry.connected = true;
129
+ });
130
+ entry.client.on?.('error', () => {
131
+ entry.connected = false;
132
+ });
133
+ entry.client.on?.('close', () => {
134
+ entry.connected = false;
135
+ });
136
+ GuardPro.pools.set(redisUrl, entry);
137
+ return entry;
138
+ }
139
+ attachConnectionEvents(client) {
140
+ client.on?.('ready', () => {
141
+ this.directRedisReady = true;
142
+ this.directRedisFailed = false;
143
+ });
144
+ client.on?.('error', () => {
145
+ this.directRedisReady = false;
146
+ this.directRedisFailed = true;
147
+ });
148
+ client.on?.('close', () => {
149
+ this.directRedisReady = false;
150
+ });
151
+ }
152
+ async getUsableRedis() {
153
+ const client = this.redisClient;
154
+ if (!client)
155
+ return null;
156
+ if (!this.poolEntry && this.directRedisFailed)
157
+ return null;
158
+ if (client.status === 'ready')
159
+ return client;
160
+ if (this.poolEntry) {
161
+ if (this.poolEntry.connected)
162
+ return client;
163
+ this.poolEntry.connectPromise ??= this.connect(client);
164
+ return this.poolEntry.connectPromise;
165
+ }
166
+ return this.connect(client);
167
+ }
168
+ async connect(client) {
122
169
  try {
123
- await this.redis.quit();
170
+ await client.connect?.();
171
+ if (this.poolEntry) {
172
+ this.poolEntry.connected = client.status === undefined || client.status === 'ready';
173
+ this.poolEntry.connectPromise = undefined;
174
+ }
175
+ else {
176
+ this.directRedisFailed = false;
177
+ this.directRedisReady = true;
178
+ }
179
+ return client;
124
180
  }
125
181
  catch {
126
- // ignore close errors
182
+ this.markDisconnected();
183
+ return null;
184
+ }
185
+ }
186
+ async incrementRedisOrFallback(redis, key, projectId, estimatedCost) {
187
+ try {
188
+ return await this.incrementRedis(redis, key, estimatedCost);
127
189
  }
128
- finally {
129
- this.connected = false;
190
+ catch {
191
+ this.markDisconnected();
192
+ return this.incrementLocal(projectId, estimatedCost);
130
193
  }
131
194
  }
132
- async incrementSpend(key, estimatedCost) {
133
- const script = `
134
- local total = redis.call("INCRBYFLOAT", KEYS[1], ARGV[1])
135
- local ttl = redis.call("TTL", KEYS[1])
136
- if ttl == -1 then
137
- redis.call("EXPIRE", KEYS[1], ARGV[2])
138
- end
139
- return total
195
+ async incrementRedis(redis, key, estimatedCost) {
196
+ const script = `
197
+ local total = redis.call("INCRBYFLOAT", KEYS[1], ARGV[1])
198
+ local ttl = redis.call("TTL", KEYS[1])
199
+ if ttl == -1 then
200
+ redis.call("EXPIRE", KEYS[1], ARGV[2])
201
+ end
202
+ return total
140
203
  `;
141
- const total = await this.redis.eval(script, 1, key, estimatedCost.toString(), this.windowSeconds.toString());
204
+ const total = await redis.eval(script, 1, key, estimatedCost.toString(), this.windowSeconds.toString());
142
205
  return Number(total);
143
206
  }
144
- async sendBudgetAlert(projectId, currentSpend) {
145
- if (!this.slackWebhook)
146
- return;
147
- const response = await fetch(this.slackWebhook, {
148
- method: 'POST',
149
- headers: { 'content-type': 'application/json' },
150
- body: JSON.stringify({
151
- text: `[CostGuard] 🚨 Project "${projectId}" exceeded budget.\nSpend: $${currentSpend.toFixed(6)} / Budget: $${this.budget.toFixed(6)}`
152
- })
153
- });
154
- if (!response.ok) {
155
- throw new Error(`Slack webhook responded with status ${response.status}`);
207
+ incrementLocal(projectId, estimatedCost) {
208
+ const record = this.getLocal(projectId);
209
+ record.total += estimatedCost;
210
+ this.localSpend.set(projectId, record);
211
+ return record.total;
212
+ }
213
+ getLocal(projectId) {
214
+ const now = Date.now();
215
+ const existing = this.localSpend.get(projectId);
216
+ if (existing && existing.expiresAt > now) {
217
+ return existing;
218
+ }
219
+ const fresh = {
220
+ total: 0,
221
+ expiresAt: now + this.windowSeconds * 1000,
222
+ };
223
+ this.localSpend.set(projectId, fresh);
224
+ return fresh;
225
+ }
226
+ markDisconnected() {
227
+ if (this.poolEntry) {
228
+ this.poolEntry.connected = false;
229
+ this.poolEntry.connectPromise = undefined;
230
+ }
231
+ else {
232
+ this.directRedisFailed = true;
233
+ this.directRedisReady = false;
234
+ }
235
+ }
236
+ async safeQuit(client) {
237
+ try {
238
+ await client.quit?.();
239
+ }
240
+ catch {
241
+ // Best-effort shutdown only.
156
242
  }
157
243
  }
158
244
  getSpendKey(projectId) {
@@ -162,21 +248,18 @@ export class GuardPro {
162
248
  return {
163
249
  model: 'unknown',
164
250
  tokens: 0,
251
+ inputTokens: 0,
252
+ outputTokens: 0,
165
253
  estimatedCost,
166
254
  timestamp: Date.now(),
167
- prompt: `project:${projectId}`
255
+ prompt: `project:${projectId}`,
168
256
  };
169
257
  }
170
258
  }
171
- export function validateLicense(key) {
172
- if (typeof key !== 'string' || key.length < 16)
173
- return false;
174
- const checksum = Array.from(key).reduce((sum, char) => sum + char.charCodeAt(0), 0);
175
- return checksum % 7 === 0;
176
- }
259
+ /**
260
+ * Creates GuardPro.
261
+ */
177
262
  export function getProGuard(config) {
178
- if (config.licenseKey && !validateLicense(config.licenseKey))
179
- return null;
180
263
  return new GuardPro(config);
181
264
  }
182
265
  //# sourceMappingURL=GuardPro.js.map
@@ -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,37 @@
1
+ import type { GuardEvent } from './types.js';
2
+ /**
3
+ * Prompt retention mode for JSONL event logs.
4
+ */
5
+ export type EventLogPromptMode = 'none' | 'preview';
6
+ /**
7
+ * Stable JSONL record written for local dashboards and offline analysis.
8
+ */
9
+ export interface GuardEventLogRecord {
10
+ version: 1;
11
+ timestamp: string;
12
+ type: GuardEvent['type'];
13
+ code?: GuardEvent['code'];
14
+ reason?: string;
15
+ model: string;
16
+ method?: string;
17
+ scopeKey: string;
18
+ estimatedCost: number;
19
+ actualCost?: number;
20
+ inputTokens?: number;
21
+ outputTokens?: number;
22
+ tokens: number;
23
+ promptPreview?: string;
24
+ state: {
25
+ requestCount: number;
26
+ blockedCount: number;
27
+ totalCost: number;
28
+ attemptedCost: number;
29
+ blockedCost: number;
30
+ actualCost: number;
31
+ };
32
+ }
33
+ /**
34
+ * Appends a redacted guard event to a local JSONL file.
35
+ */
36
+ export declare function appendGuardEventLog(eventLogPath: string | undefined, event: GuardEvent, promptMode?: EventLogPromptMode): void;
37
+ //# sourceMappingURL=event-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-log.d.ts","sourceRoot":"","sources":["../../src/core/event-log.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IACzB,IAAI,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,KAAK,EAAE,UAAU,EACjB,UAAU,GAAE,kBAA2B,GACtC,IAAI,CASN"}
@@ -0,0 +1,49 @@
1
+ import { mkdirSync, appendFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ /**
4
+ * Appends a redacted guard event to a local JSONL file.
5
+ */
6
+ export function appendGuardEventLog(eventLogPath, event, promptMode = 'none') {
7
+ if (!eventLogPath)
8
+ return;
9
+ try {
10
+ mkdirSync(dirname(eventLogPath), { recursive: true });
11
+ appendFileSync(eventLogPath, JSON.stringify(toEventLogRecord(event, promptMode)) + '\n', 'utf8');
12
+ }
13
+ catch {
14
+ // Event logs are local observability only and must not affect guard decisions.
15
+ }
16
+ }
17
+ function toEventLogRecord(event, promptMode) {
18
+ const record = {
19
+ version: 1,
20
+ timestamp: new Date(event.context.timestamp).toISOString(),
21
+ type: event.type,
22
+ code: event.code,
23
+ reason: event.reason,
24
+ model: event.context.model,
25
+ method: event.context.method,
26
+ scopeKey: event.context.scopeKey ?? 'default',
27
+ estimatedCost: roundMoney(event.context.estimatedCost),
28
+ actualCost: event.context.actualCost === undefined ? undefined : roundMoney(event.context.actualCost),
29
+ inputTokens: event.context.inputTokens,
30
+ outputTokens: event.context.outputTokens,
31
+ tokens: event.context.tokens,
32
+ state: {
33
+ requestCount: event.state.requestCount,
34
+ blockedCount: event.state.blockedCount,
35
+ totalCost: roundMoney(event.state.totalCost),
36
+ attemptedCost: roundMoney(event.state.attemptedCost),
37
+ blockedCost: roundMoney(event.state.blockedCost),
38
+ actualCost: roundMoney(event.state.actualCost),
39
+ },
40
+ };
41
+ if (promptMode === 'preview' && event.context.prompt.trim()) {
42
+ record.promptPreview = event.context.prompt.slice(0, 160);
43
+ }
44
+ return record;
45
+ }
46
+ function roundMoney(value) {
47
+ return Math.round(value * 1_000_000) / 1_000_000;
48
+ }
49
+ //# sourceMappingURL=event-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-log.js","sourceRoot":"","sources":["../../src/core/event-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoCpC;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,YAAgC,EAChC,KAAiB,EACjB,aAAiC,MAAM;IAEvC,IAAI,CAAC,YAAY;QAAE,OAAO;IAE1B,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,cAAc,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;IACnG,CAAC;IAAC,MAAM,CAAC;QACP,+EAA+E;IACjF,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAiB,EAAE,UAA8B;IACzE,MAAM,MAAM,GAAwB;QAClC,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;QAC1D,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK;QAC1B,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;QAC5B,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,IAAI,SAAS;QAC7C,aAAa,EAAE,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC;QACtD,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;QACrG,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,WAAW;QACtC,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,YAAY;QACxC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;QAC5B,KAAK,EAAE;YACL,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY;YACtC,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,YAAY;YACtC,SAAS,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC;YAC5C,aAAa,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC;YACpD,WAAW,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC;YAChD,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC;SAC/C;KACF,CAAC;IAEF,IAAI,UAAU,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5D,MAAM,CAAC,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;AACnD,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { GuardEvent, GuardEventHandler, GuardEventName } from './types.js';
2
+ /**
3
+ * Small synchronous event emitter used by guarded clients.
4
+ */
5
+ export declare class GuardEventEmitter {
6
+ private readonly handlers;
7
+ /**
8
+ * Subscribes to a guard event and returns an unsubscribe function.
9
+ */
10
+ on(eventName: GuardEventName, handler: GuardEventHandler): () => void;
11
+ /**
12
+ * Removes one event handler from a guard event.
13
+ */
14
+ off(eventName: GuardEventName, handler: GuardEventHandler): void;
15
+ /**
16
+ * Emits an event to all current subscribers.
17
+ */
18
+ emit(event: GuardEvent): void;
19
+ }
20
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/core/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEhF;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqD;IAE9E;;OAEG;IACH,EAAE,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,iBAAiB,GAAG,MAAM,IAAI;IAUrE;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAUhE;;OAEG;IACH,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAY9B"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Small synchronous event emitter used by guarded clients.
3
+ */
4
+ export class GuardEventEmitter {
5
+ handlers = new Map();
6
+ /**
7
+ * Subscribes to a guard event and returns an unsubscribe function.
8
+ */
9
+ on(eventName, handler) {
10
+ const handlers = this.handlers.get(eventName) ?? new Set();
11
+ handlers.add(handler);
12
+ this.handlers.set(eventName, handlers);
13
+ return () => {
14
+ this.off(eventName, handler);
15
+ };
16
+ }
17
+ /**
18
+ * Removes one event handler from a guard event.
19
+ */
20
+ off(eventName, handler) {
21
+ const handlers = this.handlers.get(eventName);
22
+ if (!handlers)
23
+ return;
24
+ handlers.delete(handler);
25
+ if (handlers.size === 0) {
26
+ this.handlers.delete(eventName);
27
+ }
28
+ }
29
+ /**
30
+ * Emits an event to all current subscribers.
31
+ */
32
+ emit(event) {
33
+ const handlers = this.handlers.get(event.type);
34
+ if (!handlers)
35
+ return;
36
+ for (const handler of handlers) {
37
+ try {
38
+ handler(event);
39
+ }
40
+ catch {
41
+ // Event handlers are opt-in observability hooks and must not affect the guard decision.
42
+ }
43
+ }
44
+ }
45
+ }
46
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/core/events.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,iBAAiB;IACX,QAAQ,GAAG,IAAI,GAAG,EAA0C,CAAC;IAE9E;;OAEG;IACH,EAAE,CAAC,SAAyB,EAAE,OAA0B;QACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,GAAG,EAAqB,CAAC;QAC9E,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEvC,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC/B,CAAC,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,SAAyB,EAAE,OAA0B;QACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ;YAAE,OAAO;QAEtB,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,KAAiB;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,QAAQ;YAAE,OAAO;QAEtB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,wFAAwF;YAC1F,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Builds a character trigram frequency vector for a prompt.
3
+ */
4
+ export declare function characterTrigrams(input: string): Map<string, number>;
5
+ /**
6
+ * Calculates cosine similarity between two strings using character trigrams.
7
+ */
8
+ export declare function cosineSimilarity(left: string, right: string): number;
9
+ /**
10
+ * Returns the highest trigram cosine similarity between a prompt and a prompt history.
11
+ */
12
+ export declare function maxCosineSimilarity(prompt: string, history: readonly string[]): number;
13
+ //# sourceMappingURL=similarity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"similarity.d.ts","sourceRoot":"","sources":["../../src/core/similarity.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBpE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAqBpE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEtF"}