@salimassili/ai-costguard 2.0.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.
- package/CHANGELOG.md +59 -50
- package/LICENSE +21 -21
- package/README.md +399 -339
- package/benchmarks/run.mjs +229 -229
- package/benchmarks/token-accuracy.mjs +86 -0
- package/dist/core/CostGuard.d.ts +1 -1
- package/dist/core/CostGuard.d.ts.map +1 -1
- package/dist/core/CostGuard.js +1 -1
- package/dist/core/CostGuard.js.map +1 -1
- package/dist/core/GuardPro.d.ts +1 -13
- package/dist/core/GuardPro.d.ts.map +1 -1
- package/dist/core/GuardPro.js +7 -19
- package/dist/core/GuardPro.js.map +1 -1
- package/dist/core/types.d.ts +1 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/dashboard.js +49 -49
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pricing/index.d.ts +7 -0
- package/dist/pricing/index.d.ts.map +1 -1
- package/dist/pricing/index.js +7 -0
- package/dist/pricing/index.js.map +1 -1
- package/dist/pro.d.ts +1 -1
- package/dist/pro.d.ts.map +1 -1
- package/dist/pro.js +1 -1
- package/dist/pro.js.map +1 -1
- package/docs/BENCHMARKS.md +60 -41
- package/docs/DASHBOARD.md +61 -61
- package/docs/INTEGRATIONS.md +153 -153
- package/examples/integrations/anthropic-workflow-budget.mjs +36 -36
- package/examples/integrations/ci-budget-check.mjs +32 -32
- package/examples/integrations/crewai-budget-gate.mjs +31 -31
- package/examples/integrations/langchain-retry-storm.mjs +32 -32
- package/examples/integrations/mastra-agent.mjs +41 -41
- package/examples/integrations/openai-agent-loop.mjs +44 -44
- package/examples/integrations/vercel-ai-chatbot.mjs +29 -29
- package/package.json +71 -69
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import { guard, GuardError } from '@salimassili/ai-costguard';
|
|
2
|
-
|
|
3
|
-
const fakeOpenAI = {
|
|
4
|
-
chat: {
|
|
5
|
-
completions: {
|
|
6
|
-
create: async (request) => ({
|
|
7
|
-
id: `mock-${request.messages.length}`,
|
|
8
|
-
choices: [{ message: { content: 'mocked OpenAI response' } }],
|
|
9
|
-
usage: { prompt_tokens: 24, completion_tokens: request.max_tokens ?? 16 },
|
|
10
|
-
}),
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const openai = guard(fakeOpenAI, {
|
|
16
|
-
budget: 1,
|
|
17
|
-
loopSimilarityThreshold: 0.9,
|
|
18
|
-
loopMinRepeats: 2,
|
|
19
|
-
scope: { projectId: 'openai-agent-demo', sessionId: 'run-1' },
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
let blocked = false;
|
|
23
|
-
|
|
24
|
-
for (let step = 1; step <= 3; step++) {
|
|
25
|
-
try {
|
|
26
|
-
await openai.chat.completions.create({
|
|
27
|
-
model: 'gpt-4o-mini',
|
|
28
|
-
messages: [{ role: 'user', content: 'inspect the same failing tool result and try to continue' }],
|
|
29
|
-
max_tokens: 64,
|
|
30
|
-
});
|
|
31
|
-
} catch (error) {
|
|
32
|
-
if (error instanceof GuardError) {
|
|
33
|
-
blocked = true;
|
|
34
|
-
console.log(JSON.stringify({ blocked, step, code: error.code }, null, 2));
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (!blocked) {
|
|
43
|
-
throw new Error('Expected loop protection to block the repeated agent prompt.');
|
|
44
|
-
}
|
|
1
|
+
import { guard, GuardError } from '@salimassili/ai-costguard';
|
|
2
|
+
|
|
3
|
+
const fakeOpenAI = {
|
|
4
|
+
chat: {
|
|
5
|
+
completions: {
|
|
6
|
+
create: async (request) => ({
|
|
7
|
+
id: `mock-${request.messages.length}`,
|
|
8
|
+
choices: [{ message: { content: 'mocked OpenAI response' } }],
|
|
9
|
+
usage: { prompt_tokens: 24, completion_tokens: request.max_tokens ?? 16 },
|
|
10
|
+
}),
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const openai = guard(fakeOpenAI, {
|
|
16
|
+
budget: 1,
|
|
17
|
+
loopSimilarityThreshold: 0.9,
|
|
18
|
+
loopMinRepeats: 2,
|
|
19
|
+
scope: { projectId: 'openai-agent-demo', sessionId: 'run-1' },
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
let blocked = false;
|
|
23
|
+
|
|
24
|
+
for (let step = 1; step <= 3; step++) {
|
|
25
|
+
try {
|
|
26
|
+
await openai.chat.completions.create({
|
|
27
|
+
model: 'gpt-4o-mini',
|
|
28
|
+
messages: [{ role: 'user', content: 'inspect the same failing tool result and try to continue' }],
|
|
29
|
+
max_tokens: 64,
|
|
30
|
+
});
|
|
31
|
+
} catch (error) {
|
|
32
|
+
if (error instanceof GuardError) {
|
|
33
|
+
blocked = true;
|
|
34
|
+
console.log(JSON.stringify({ blocked, step, code: error.code }, null, 2));
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!blocked) {
|
|
43
|
+
throw new Error('Expected loop protection to block the repeated agent prompt.');
|
|
44
|
+
}
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { guardFunction, GuardError } from '@salimassili/ai-costguard';
|
|
2
|
-
|
|
3
|
-
async function mockGenerateText(request) {
|
|
4
|
-
return {
|
|
5
|
-
text: `mocked answer for ${request.prompt}`,
|
|
6
|
-
usage: { prompt_tokens: 40, completion_tokens: request.max_tokens ?? 80 },
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const generateText = guardFunction(mockGenerateText, {
|
|
11
|
-
budget: 0.001,
|
|
12
|
-
scope: { projectId: 'vercel-chatbot-demo', sessionId: 'chat-123' },
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
const result = await generateText({
|
|
17
|
-
model: 'gpt-4o-mini',
|
|
18
|
-
prompt: 'Answer the user in one paragraph.',
|
|
19
|
-
max_tokens: 80,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
console.log(JSON.stringify({ ok: true, text: result.text }, null, 2));
|
|
23
|
-
} catch (error) {
|
|
24
|
-
if (error instanceof GuardError) {
|
|
25
|
-
console.log(JSON.stringify({ ok: false, code: error.code }, null, 2));
|
|
26
|
-
} else {
|
|
27
|
-
throw error;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
1
|
+
import { guardFunction, GuardError } from '@salimassili/ai-costguard';
|
|
2
|
+
|
|
3
|
+
async function mockGenerateText(request) {
|
|
4
|
+
return {
|
|
5
|
+
text: `mocked answer for ${request.prompt}`,
|
|
6
|
+
usage: { prompt_tokens: 40, completion_tokens: request.max_tokens ?? 80 },
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const generateText = guardFunction(mockGenerateText, {
|
|
11
|
+
budget: 0.001,
|
|
12
|
+
scope: { projectId: 'vercel-chatbot-demo', sessionId: 'chat-123' },
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const result = await generateText({
|
|
17
|
+
model: 'gpt-4o-mini',
|
|
18
|
+
prompt: 'Answer the user in one paragraph.',
|
|
19
|
+
max_tokens: 80,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
console.log(JSON.stringify({ ok: true, text: result.text }, null, 2));
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (error instanceof GuardError) {
|
|
25
|
+
console.log(JSON.stringify({ ok: false, code: error.code }, null, 2));
|
|
26
|
+
} else {
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,74 +1,76 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@salimassili/ai-costguard",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "Local-first runtime safety layer for AI agents that blocks runaway costs, loops, retries, and budget overruns before API calls execute.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"module": "./dist/index.js",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"sideEffects": false,
|
|
10
|
-
"bin": {
|
|
11
|
-
"aifw": "
|
|
12
|
-
"ai-costguard": "
|
|
13
|
-
},
|
|
14
|
-
"exports": {
|
|
15
|
-
".": {
|
|
16
|
-
"types": "./dist/index.d.ts",
|
|
17
|
-
"import": "./dist/index.js",
|
|
18
|
-
"default": "./dist/index.js"
|
|
19
|
-
},
|
|
20
|
-
"./pro": {
|
|
21
|
-
"types": "./dist/pro.d.ts",
|
|
22
|
-
"import": "./dist/pro.js",
|
|
23
|
-
"default": "./dist/pro.js"
|
|
24
|
-
},
|
|
25
|
-
"./pricing": {
|
|
26
|
-
"types": "./dist/pricing/index.d.ts",
|
|
27
|
-
"import": "./dist/pricing/index.js",
|
|
28
|
-
"default": "./dist/pricing/index.js"
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"files": [
|
|
32
|
-
"dist",
|
|
33
|
-
"docs/DASHBOARD.md",
|
|
1
|
+
{
|
|
2
|
+
"name": "@salimassili/ai-costguard",
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "Local-first runtime safety layer for AI agents that blocks runaway costs, loops, retries, and budget overruns before API calls execute.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"sideEffects": false,
|
|
10
|
+
"bin": {
|
|
11
|
+
"aifw": "dist/cli.js",
|
|
12
|
+
"ai-costguard": "dist/cli.js"
|
|
13
|
+
},
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./pro": {
|
|
21
|
+
"types": "./dist/pro.d.ts",
|
|
22
|
+
"import": "./dist/pro.js",
|
|
23
|
+
"default": "./dist/pro.js"
|
|
24
|
+
},
|
|
25
|
+
"./pricing": {
|
|
26
|
+
"types": "./dist/pricing/index.d.ts",
|
|
27
|
+
"import": "./dist/pricing/index.js",
|
|
28
|
+
"default": "./dist/pricing/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"docs/DASHBOARD.md",
|
|
34
34
|
"docs/INTEGRATIONS.md",
|
|
35
35
|
"docs/BENCHMARKS.md",
|
|
36
36
|
"examples/integrations",
|
|
37
37
|
"benchmarks/run.mjs",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
38
|
+
"benchmarks/token-accuracy.mjs",
|
|
39
|
+
"README.md",
|
|
40
|
+
"CHANGELOG.md",
|
|
41
|
+
"LICENSE"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"clean": "rimraf dist",
|
|
45
|
+
"build": "npm run clean && tsc",
|
|
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\"",
|
|
48
|
+
"smoke": "node test/smoke-examples.mjs",
|
|
48
49
|
"benchmark": "node benchmarks/run.mjs",
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
50
|
+
"benchmark:tokens": "node benchmarks/token-accuracy.mjs",
|
|
51
|
+
"preflight": "node scripts/preflight.js",
|
|
52
|
+
"prepublishOnly": "npm run preflight"
|
|
53
|
+
},
|
|
54
|
+
"keywords": [
|
|
55
|
+
"ai",
|
|
56
|
+
"openai",
|
|
57
|
+
"llm",
|
|
58
|
+
"cost-control",
|
|
59
|
+
"agent",
|
|
60
|
+
"runtime-safety",
|
|
61
|
+
"ai-agents",
|
|
62
|
+
"budget-guard"
|
|
63
|
+
],
|
|
64
|
+
"author": "Salim Assili",
|
|
65
|
+
"license": "MIT",
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=18"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"rimraf": "^5.0.10",
|
|
71
|
+
"typescript": "^5.3.3"
|
|
72
|
+
},
|
|
73
|
+
"optionalDependencies": {
|
|
74
|
+
"ioredis": "^5.10.1"
|
|
75
|
+
}
|
|
76
|
+
}
|