@agentguard-run/spend 0.15.10 → 0.15.12
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/README.md +65 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +5 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/route-demo.d.ts +16 -0
- package/dist/cli/route-demo.d.ts.map +1 -0
- package/dist/cli/route-demo.js +211 -0
- package/dist/cli/route-demo.js.map +1 -0
- package/dist/frameworks/index.d.ts +2 -0
- package/dist/frameworks/index.d.ts.map +1 -1
- package/dist/frameworks/index.js +2 -0
- package/dist/frameworks/index.js.map +1 -1
- package/dist/frameworks/langchain.d.ts +52 -0
- package/dist/frameworks/langchain.d.ts.map +1 -0
- package/dist/frameworks/langchain.js +84 -0
- package/dist/frameworks/langchain.js.map +1 -0
- package/dist/frameworks/openai.d.ts +33 -0
- package/dist/frameworks/openai.d.ts.map +1 -0
- package/dist/frameworks/openai.js +38 -0
- package/dist/frameworks/openai.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/router-engine.d.ts +123 -0
- package/dist/router-engine.d.ts.map +1 -0
- package/dist/router-engine.js +246 -0
- package/dist/router-engine.js.map +1 -0
- package/dist/router.d.ts +1 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +6 -0
- package/dist/router.js.map +1 -1
- package/dist/spend-guard.d.ts +20 -1
- package/dist/spend-guard.d.ts.map +1 -1
- package/dist/spend-guard.js +37 -0
- package/dist/spend-guard.js.map +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -1
- package/src/frameworks/README.md +35 -0
- package/src/frameworks/index.ts +2 -0
- package/src/frameworks/langchain.ts +159 -0
- package/src/frameworks/openai.ts +36 -0
- package/src/router.ts +16 -0
package/README.md
CHANGED
|
@@ -223,6 +223,71 @@ Only `InvokeModel` / `InvokeModelWithResponseStream` commands are gated; other B
|
|
|
223
223
|
|
|
224
224
|
Python includes OpenAI, Anthropic, Bedrock, LangChain, CrewAI, and LlamaIndex integration helpers.
|
|
225
225
|
|
|
226
|
+
## Framework integrations
|
|
227
|
+
|
|
228
|
+
Drop-in adapters translate each framework's own hook/middleware surface into the
|
|
229
|
+
same shared enforcement core (`guard.decide()` + the Ed25519-signed receipt
|
|
230
|
+
chain). They never proxy prompts, completions, or provider keys — only redacted
|
|
231
|
+
request shape reaches a receipt. One line each:
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
// Vercel AI SDK — wrapLanguageModel middleware (runs guard.decide before generate/stream)
|
|
235
|
+
import { wrapLanguageModel } from 'ai';
|
|
236
|
+
import { agentguardAiSdkMiddleware } from '@agentguard-run/spend/frameworks/vercel-ai';
|
|
237
|
+
const governed = wrapLanguageModel({ model, middleware: agentguardAiSdkMiddleware({ policy, scope }) });
|
|
238
|
+
|
|
239
|
+
// OpenAI SDK / OpenAI Agents SDK — wrap the client's chat.completions.create
|
|
240
|
+
import OpenAI from 'openai';
|
|
241
|
+
import { withSpendGuardOpenAI } from '@agentguard-run/spend/frameworks/openai';
|
|
242
|
+
const client = withSpendGuardOpenAI(new OpenAI(), { policy, scope });
|
|
243
|
+
|
|
244
|
+
// LangChain (JS) — BaseCallbackHandler (handleChatModelStart preflights, handleLLMEnd settles)
|
|
245
|
+
import { ChatOpenAI } from '@langchain/openai';
|
|
246
|
+
import { createLangChainHandler } from '@agentguard-run/spend/frameworks/langchain';
|
|
247
|
+
const llm = new ChatOpenAI({ callbacks: [createLangChainHandler({ policy, scope })] });
|
|
248
|
+
|
|
249
|
+
// OpenRouter — wrap an OpenAI-compatible client pointed at openrouter.ai
|
|
250
|
+
import { withSpendGuardOpenRouter } from '@agentguard-run/spend/frameworks/openrouter';
|
|
251
|
+
const or = withSpendGuardOpenRouter(new OpenAI({ baseURL: 'https://openrouter.ai/api/v1' }), { policy, scope });
|
|
252
|
+
|
|
253
|
+
// Claude Code — PreToolUse/PostToolUse hooks
|
|
254
|
+
import { createClaudeCodeHooks } from '@agentguard-run/spend/frameworks/claude-code';
|
|
255
|
+
const hooks = createClaudeCodeHooks({ policy, scope });
|
|
256
|
+
|
|
257
|
+
// Hermes — pre-tool-call / approval / post-tool-call plugin hooks
|
|
258
|
+
import { createHermesPlugin } from '@agentguard-run/spend/frameworks/hermes';
|
|
259
|
+
export default createHermesPlugin({ policy, scope });
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Spend-aware model router (removes vendor risk)
|
|
263
|
+
|
|
264
|
+
`createRouter(...)` composes the bindings, the enforcement engine, and the signed receipt chain into one call: it picks a candidate model across providers by policy, enforces the spend cap with the **same** enforcement path (block / downgrade / allow), executes it, and **fails over to the next provider** on a provider error/timeout or a cap breach on the chosen model. Every route is recorded in a signed, hash-chained routing receipt (candidates considered, winner, reason, resolved cost, fallbacks) that verifies with the existing `verifyChain`. No prompt/completion content or keys ever enter the receipt.
|
|
265
|
+
|
|
266
|
+
Selection policies: `cost` (cheapest capable first), `priority` (explicit failover order), or `capability` (filter by a capability tag, then cheapest-first).
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
import OpenAI from 'openai';
|
|
270
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
271
|
+
import { createRouter } from '@agentguard-run/spend';
|
|
272
|
+
|
|
273
|
+
const router = createRouter({
|
|
274
|
+
candidates: [
|
|
275
|
+
{ provider: 'anthropic', model: 'claude-sonnet-4-6', client: new Anthropic() },
|
|
276
|
+
{ provider: 'openai', model: 'gpt-5-mini', client: new OpenAI() },
|
|
277
|
+
],
|
|
278
|
+
policy: { mode: 'cost' }, // cheapest capable first; failover in order on error/cap
|
|
279
|
+
spendPolicy: policy, // your existing SpendPolicy — enforcement is REUSED, not forked
|
|
280
|
+
signingKeys, // same Ed25519 keys as the rest of the SDK
|
|
281
|
+
logStore, // routing receipts hash-chain onto the same signed log
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
const { response, chosen, reason, resolvedCents, fallbacks, routingReceipt } =
|
|
285
|
+
await router.route({ messages, params: { max_tokens: 1024 } });
|
|
286
|
+
// chosen -> { provider, model }, reason -> 'cost' | 'priority' | 'capability' | 'failover' | 'downgrade'
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Try it offline (mock providers, real signatures): `agentguard route-demo`.
|
|
290
|
+
|
|
226
291
|
## Sample receipts for outreach
|
|
227
292
|
|
|
228
293
|
Generate a realistic, signed sample receipt for a named flow plus a self-contained, self-verifying HTML page — "exactly what your counterparty would get":
|
package/dist/cli/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AAAA;;GAEG;AA8DH,wBAAsB,IAAI,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAqHlF"}
|
package/dist/cli/main.js
CHANGED
|
@@ -59,6 +59,7 @@ commands:
|
|
|
59
59
|
config Configure local CLI preferences.
|
|
60
60
|
tips Show AgentGuard usage tips.
|
|
61
61
|
demo Run a deterministic simulation with a real cryptographic receipt.
|
|
62
|
+
route-demo Demo the spend-aware model router: cost-first, failover, downgrade + signed receipt.
|
|
62
63
|
dag-demo Build + verify a multi-agent attestation diamond (TAT) with capability gating.
|
|
63
64
|
sample Generate a signed sample receipt + self-verifying HTML for a named flow.
|
|
64
65
|
anchor Externally timestamp the chain head via a public calendar (opt-in).
|
|
@@ -147,6 +148,10 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
147
148
|
const { runDemo } = await Promise.resolve().then(() => __importStar(require('./demo')));
|
|
148
149
|
return runDemo(rest);
|
|
149
150
|
}
|
|
151
|
+
if (command === 'route-demo') {
|
|
152
|
+
const { runRouteDemo } = await Promise.resolve().then(() => __importStar(require('./route-demo')));
|
|
153
|
+
return runRouteDemo(rest);
|
|
154
|
+
}
|
|
150
155
|
if (command === 'dag-demo') {
|
|
151
156
|
const { runDagDemo } = await Promise.resolve().then(() => __importStar(require('./dag-demo')));
|
|
152
157
|
return runDagDemo(rest);
|
package/dist/cli/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agentguard route-demo`: deterministic, offline demo of the spend-and-policy-
|
|
3
|
+
* aware model router.
|
|
4
|
+
*
|
|
5
|
+
* Shows, with mock provider clients (no real API calls):
|
|
6
|
+
* 1. cost-first routing to the cheapest capable candidate,
|
|
7
|
+
* 2. a clean FAILOVER when the primary provider errors (vendor risk removed),
|
|
8
|
+
* 3. a cap-breach triggering an in-flight DOWNGRADE route,
|
|
9
|
+
* 4. the signed routing receipt (candidates, winner, reason, cost), plus a
|
|
10
|
+
* note that it verifies with the existing verifier.
|
|
11
|
+
*
|
|
12
|
+
* The Ed25519 signatures + SHA-256 hash chain are REAL and reuse the existing
|
|
13
|
+
* receipt infra. Self-checks invariants and exits 1 on any failure.
|
|
14
|
+
*/
|
|
15
|
+
export declare function runRouteDemo(argv: string[]): Promise<number>;
|
|
16
|
+
//# sourceMappingURL=route-demo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-demo.d.ts","sourceRoot":"","sources":["../../src/cli/route-demo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAuDH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAoHlE"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `agentguard route-demo`: deterministic, offline demo of the spend-and-policy-
|
|
4
|
+
* aware model router.
|
|
5
|
+
*
|
|
6
|
+
* Shows, with mock provider clients (no real API calls):
|
|
7
|
+
* 1. cost-first routing to the cheapest capable candidate,
|
|
8
|
+
* 2. a clean FAILOVER when the primary provider errors (vendor risk removed),
|
|
9
|
+
* 3. a cap-breach triggering an in-flight DOWNGRADE route,
|
|
10
|
+
* 4. the signed routing receipt (candidates, winner, reason, cost), plus a
|
|
11
|
+
* note that it verifies with the existing verifier.
|
|
12
|
+
*
|
|
13
|
+
* The Ed25519 signatures + SHA-256 hash chain are REAL and reuse the existing
|
|
14
|
+
* receipt infra. Self-checks invariants and exits 1 on any failure.
|
|
15
|
+
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.runRouteDemo = runRouteDemo;
|
|
51
|
+
const ed = __importStar(require("@noble/ed25519"));
|
|
52
|
+
const router_engine_1 = require("../router-engine");
|
|
53
|
+
const decision_log_1 = require("../decision-log");
|
|
54
|
+
const store_memory_1 = require("../store-memory");
|
|
55
|
+
const cost_table_1 = require("../cost-table");
|
|
56
|
+
const index_1 = require("../index");
|
|
57
|
+
const colors_1 = require("./colors");
|
|
58
|
+
function mockClient(label, log, opts = {}) {
|
|
59
|
+
if (opts.kind === 'anthropic') {
|
|
60
|
+
return {
|
|
61
|
+
messages: {
|
|
62
|
+
create: async (params) => {
|
|
63
|
+
log.push(`${label}:${params.model}`);
|
|
64
|
+
if (opts.fail)
|
|
65
|
+
throw new Error('anthropic 503 upstream unavailable');
|
|
66
|
+
return { content: [{ text: 'ok' }], usage: { input_tokens: 1000, output_tokens: 1000 } };
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
chat: {
|
|
73
|
+
completions: {
|
|
74
|
+
create: async (params) => {
|
|
75
|
+
log.push(`${label}:${params.model}`);
|
|
76
|
+
if (opts.fail)
|
|
77
|
+
throw new Error('openai 500 upstream error');
|
|
78
|
+
return { choices: [{ message: { content: 'ok' } }], usage: { prompt_tokens: 1000, completion_tokens: 1000 } };
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function policy(overrides = {}) {
|
|
85
|
+
return {
|
|
86
|
+
id: 'route-demo',
|
|
87
|
+
name: 'route demo',
|
|
88
|
+
scope: { tenantId: 'route-demo' },
|
|
89
|
+
caps: [{ window: 'per_day', amountCents: 100000, action: 'allow' }],
|
|
90
|
+
mode: 'enforce',
|
|
91
|
+
version: 1,
|
|
92
|
+
effectiveFrom: '2026-07-20T00:00:00Z',
|
|
93
|
+
...overrides,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const REQUEST = { messages: [{ role: 'user', content: 'summarize this' }], params: { max_tokens: 1000 }, inputTokens: 1000, outputTokens: 1000 };
|
|
97
|
+
function usd(cents) {
|
|
98
|
+
return Number.isFinite(cents) ? `$${(cents / 100).toFixed(4)}` : 'n/a';
|
|
99
|
+
}
|
|
100
|
+
async function runRouteDemo(argv) {
|
|
101
|
+
if (argv.includes('--no-color'))
|
|
102
|
+
process.env.NO_COLOR = '1';
|
|
103
|
+
if (argv.includes('--help') || argv.includes('-h')) {
|
|
104
|
+
console.log('agentguard route-demo');
|
|
105
|
+
console.log('Deterministic, offline demo of the spend-and-policy-aware model router.');
|
|
106
|
+
console.log('Options:');
|
|
107
|
+
console.log(' --no-color Disable colored output (same as NO_COLOR=1).');
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
110
|
+
(0, cost_table_1.clearCostOverrides)();
|
|
111
|
+
(0, cost_table_1.setCostOverride)('gpt-cheap', { inputCentsPerKtok: 1, outputCentsPerKtok: 1 });
|
|
112
|
+
(0, cost_table_1.setCostOverride)('claude-mid', { inputCentsPerKtok: 5, outputCentsPerKtok: 5 });
|
|
113
|
+
(0, cost_table_1.setCostOverride)('gpt-pricey', { inputCentsPerKtok: 50, outputCentsPerKtok: 50 });
|
|
114
|
+
const privateKey = new Uint8Array(32);
|
|
115
|
+
for (let i = 0; i < 32; i++)
|
|
116
|
+
privateKey[i] = (i * 7 + 3) & 0xff;
|
|
117
|
+
const publicKey = await ed.getPublicKeyAsync(privateKey);
|
|
118
|
+
const logStore = new decision_log_1.InMemoryDecisionLogStore();
|
|
119
|
+
const spendStore = new store_memory_1.InMemorySpendStore();
|
|
120
|
+
const signingKeys = { privateKey, publicKey };
|
|
121
|
+
console.log('');
|
|
122
|
+
console.log(' ' + (0, colors_1.banner)(index_1.AGENTGUARD_SPEND_VERSION));
|
|
123
|
+
console.log(' ' + (0, colors_1.cyanBold)('AgentGuard Model Router Demo') + (0, colors_1.dim)(' · [mock providers · real cryptographic receipts]'));
|
|
124
|
+
console.log('');
|
|
125
|
+
let failed = false;
|
|
126
|
+
const check = (name, cond) => {
|
|
127
|
+
console.log(' ' + (cond ? (0, colors_1.green)('✓') : (0, colors_1.red)('✗')) + ' ' + (0, colors_1.dim)(name));
|
|
128
|
+
if (!cond)
|
|
129
|
+
failed = true;
|
|
130
|
+
};
|
|
131
|
+
// ---- Scenario 1: cost-first routing to the cheapest capable candidate ----
|
|
132
|
+
console.log(' ' + (0, colors_1.bold)('1) cost-first route') + (0, colors_1.dim)(' — cheapest capable candidate wins'));
|
|
133
|
+
const log1 = [];
|
|
134
|
+
const candidates1 = [
|
|
135
|
+
{ provider: 'openai', model: 'gpt-pricey', client: mockClient('openai', log1) },
|
|
136
|
+
{ provider: 'anthropic', model: 'claude-mid', client: mockClient('anthropic', log1, { kind: 'anthropic' }) },
|
|
137
|
+
{ provider: 'openai', model: 'gpt-cheap', client: mockClient('openai', log1) },
|
|
138
|
+
];
|
|
139
|
+
const router1 = (0, router_engine_1.createRouter)({ candidates: candidates1, spendPolicy: policy(), policy: { mode: 'cost' }, signingKeys, logStore, spendStore });
|
|
140
|
+
const r1 = await router1.route(REQUEST);
|
|
141
|
+
console.log(` winner: ${(0, colors_1.greenBold)(r1.chosen.provider + '/' + r1.chosen.model)} reason=${r1.reason} cost=${usd(r1.resolvedCents)}`);
|
|
142
|
+
check('cheapest model selected (gpt-cheap)', r1.chosen.model === 'gpt-cheap');
|
|
143
|
+
check('reason is cost', r1.reason === 'cost');
|
|
144
|
+
console.log('');
|
|
145
|
+
// ---- Scenario 2: provider error -> clean failover (vendor risk removed) ----
|
|
146
|
+
console.log(' ' + (0, colors_1.bold)('2) failover route') + (0, colors_1.dim)(' — primary provider errors, next provider takes over'));
|
|
147
|
+
const log2 = [];
|
|
148
|
+
const candidates2 = [
|
|
149
|
+
{ provider: 'anthropic', model: 'claude-mid', client: mockClient('anthropic', log2, { kind: 'anthropic', fail: true }) },
|
|
150
|
+
{ provider: 'openai', model: 'gpt-cheap', client: mockClient('openai', log2) },
|
|
151
|
+
];
|
|
152
|
+
const router2 = (0, router_engine_1.createRouter)({ candidates: candidates2, spendPolicy: policy(), policy: { mode: 'priority' }, signingKeys, logStore, spendStore });
|
|
153
|
+
const r2 = await router2.route(REQUEST);
|
|
154
|
+
for (const fb of r2.fallbacks)
|
|
155
|
+
console.log(` ${(0, colors_1.red)('failover')} ${fb.provider}/${fb.model}: ${fb.reason} (${(0, colors_1.dim)(fb.detail ?? '')})`);
|
|
156
|
+
console.log(` winner: ${(0, colors_1.greenBold)(r2.chosen.provider + '/' + r2.chosen.model)} reason=${r2.reason} cost=${usd(r2.resolvedCents)}`);
|
|
157
|
+
check('failed over across providers (anthropic -> openai)', r2.chosen.provider === 'openai' && r2.chosen.model === 'gpt-cheap');
|
|
158
|
+
check('one provider_error fallback recorded', r2.fallbacks.length === 1 && r2.fallbacks[0].reason === 'provider_error');
|
|
159
|
+
check('reason is failover', r2.reason === 'failover');
|
|
160
|
+
console.log('');
|
|
161
|
+
// ---- Scenario 3: cap breach -> downgrade route ----
|
|
162
|
+
console.log(' ' + (0, colors_1.bold)('3) cap-breach downgrade route') + (0, colors_1.dim)(' — per-call cap downgrades to a cheaper model'));
|
|
163
|
+
const log3 = [];
|
|
164
|
+
const dgPolicy = policy({ caps: [{ window: 'per_call', amountCents: 5, action: 'downgrade', downgradeTo: 'gpt-cheap' }] });
|
|
165
|
+
const candidates3 = [
|
|
166
|
+
{ provider: 'openai', model: 'gpt-pricey', client: mockClient('openai', log3) },
|
|
167
|
+
];
|
|
168
|
+
const router3 = (0, router_engine_1.createRouter)({ candidates: candidates3, spendPolicy: dgPolicy, policy: { mode: 'priority' }, signingKeys, logStore, spendStore });
|
|
169
|
+
const r3 = await router3.route(REQUEST);
|
|
170
|
+
console.log(` requested gpt-pricey (${usd(5000)}) over $0.05 cap -> downgraded`);
|
|
171
|
+
console.log(` winner: ${(0, colors_1.greenBold)(r3.chosen.provider + '/' + r3.chosen.model)} reason=${r3.reason} cost=${usd(r3.resolvedCents)}`);
|
|
172
|
+
check('downgraded to gpt-cheap', r3.chosen.model === 'gpt-cheap');
|
|
173
|
+
check('reason is downgrade', r3.reason === 'downgrade');
|
|
174
|
+
console.log('');
|
|
175
|
+
// ---- Signed routing receipt (from scenario 2, the failover) ----
|
|
176
|
+
console.log(' ' + (0, colors_1.bold)('signed routing receipt') + (0, colors_1.dim)(' — scenario 2 (failover)'));
|
|
177
|
+
const receipt = r2.routingReceipt;
|
|
178
|
+
if (!receipt) {
|
|
179
|
+
check('routing receipt signed', false);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
const payload = receipt.decision.routingReceipt;
|
|
183
|
+
console.log((0, colors_1.dim)(' ───────────────────────────────────────────'));
|
|
184
|
+
console.log(' candidates considered:');
|
|
185
|
+
for (const c of payload.candidates) {
|
|
186
|
+
console.log(` - ${c.provider}/${c.model} projected=${usd(c.projectedCents ?? Number.NaN)}`);
|
|
187
|
+
}
|
|
188
|
+
console.log(` ${(0, colors_1.dim)('chosen ')} ${payload.chosen.provider}/${payload.chosen.model}`);
|
|
189
|
+
console.log(` ${(0, colors_1.dim)('reason ')} ${payload.reason}`);
|
|
190
|
+
console.log(` ${(0, colors_1.dim)('cost ')} ${usd(payload.resolvedCents)}`);
|
|
191
|
+
console.log(` ${(0, colors_1.dim)('fallbacks ')} ${payload.fallbacks.length}`);
|
|
192
|
+
console.log(` ${(0, colors_1.dim)('receipt ')} ${receipt.entryHash.slice(0, 16)}${(0, colors_1.dim)('...')}`);
|
|
193
|
+
console.log(` ${(0, colors_1.dim)('signer ')} ${receipt.signerFingerprint.slice(0, 16)}${(0, colors_1.dim)('...')}`);
|
|
194
|
+
console.log(` ${(0, colors_1.dim)('entryType ')} ${receipt.decision.entryType}`);
|
|
195
|
+
console.log((0, colors_1.dim)(' ───────────────────────────────────────────'));
|
|
196
|
+
check('receipt entryType is routing', receipt.decision.entryType === 'routing');
|
|
197
|
+
check('receipt records the chosen model', receipt.decision.modelResolved === 'gpt-cheap');
|
|
198
|
+
}
|
|
199
|
+
console.log('');
|
|
200
|
+
// ---- Whole chain verifies with the EXISTING verifier ----
|
|
201
|
+
const entries = logStore.snapshot();
|
|
202
|
+
const verdict = await (0, decision_log_1.verifyChain)(entries, publicKey);
|
|
203
|
+
check(`entire signed chain verifies (${entries.length} entries)`, verdict.ok === true);
|
|
204
|
+
const noContent = !JSON.stringify(entries).includes('summarize this');
|
|
205
|
+
check('zero data plane: no prompt content in the log', noContent);
|
|
206
|
+
console.log('');
|
|
207
|
+
console.log(' ' + (0, colors_1.green)('→') + ' ' + (0, colors_1.dim)('this receipt verifies with:') + ' ' + (0, colors_1.greenBold)('verifyChain(entries, publicKey)'));
|
|
208
|
+
console.log('');
|
|
209
|
+
return failed ? 1 : 0;
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=route-demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-demo.js","sourceRoot":"","sources":["../../src/cli/route-demo.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/frameworks/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/frameworks/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|
package/dist/frameworks/index.js
CHANGED
|
@@ -20,4 +20,6 @@ __exportStar(require("./vercel-ai"), exports);
|
|
|
20
20
|
__exportStar(require("./claude-code"), exports);
|
|
21
21
|
__exportStar(require("./hermes"), exports);
|
|
22
22
|
__exportStar(require("./hermes-kanban"), exports);
|
|
23
|
+
__exportStar(require("./langchain"), exports);
|
|
24
|
+
__exportStar(require("./openai"), exports);
|
|
23
25
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/frameworks/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,+CAA6B;AAC7B,8CAA4B;AAC5B,gDAA8B;AAC9B,2CAAyB;AACzB,kDAAgC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/frameworks/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,+CAA6B;AAC7B,8CAA4B;AAC5B,gDAA8B;AAC9B,2CAAyB;AACzB,kDAAgC;AAChC,8CAA4B;AAC5B,2CAAyB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { SpendGuard } from '../spend-guard';
|
|
2
|
+
import { type FrameworkAdapterOptions } from './common';
|
|
3
|
+
/**
|
|
4
|
+
* LangChain.js callback handler that runs `guard.decide()` before every LLM /
|
|
5
|
+
* chat-model call and settles real token usage after it completes.
|
|
6
|
+
*
|
|
7
|
+
* Hook point: LangChain's `BaseCallbackHandler` lifecycle methods
|
|
8
|
+
* `handleChatModelStart` / `handleLLMStart` (preflight, may throw
|
|
9
|
+
* AgentGuardBlockedError) and `handleLLMEnd` (usage settlement). We do NOT
|
|
10
|
+
* extend the real BaseCallbackHandler (that would force a peer-dep import at
|
|
11
|
+
* module load); LangChain duck-types handlers by these method names, and we set
|
|
12
|
+
* `awaitHandlers = true` so a thrown block aborts the call.
|
|
13
|
+
*
|
|
14
|
+
* This adapter reuses the shared framework core (createFrameworkGuard +
|
|
15
|
+
* preflightFrameworkCall + settleFrameworkCall). It never proxies prompts,
|
|
16
|
+
* completions, or provider keys — only redacted request shape leaves for the
|
|
17
|
+
* signed receipt.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { ChatOpenAI } from '@langchain/openai';
|
|
21
|
+
* import { createLangChainHandler } from '@agentguard-run/spend/frameworks/langchain';
|
|
22
|
+
*
|
|
23
|
+
* const handler = createLangChainHandler({ policy, scope });
|
|
24
|
+
* const llm = new ChatOpenAI({ callbacks: [handler] });
|
|
25
|
+
* await llm.invoke('hello'); // throws AgentGuardBlockedError if a cap blocks
|
|
26
|
+
*/
|
|
27
|
+
export interface LangChainAdapterOptions extends FrameworkAdapterOptions {
|
|
28
|
+
framework?: 'langchain';
|
|
29
|
+
}
|
|
30
|
+
interface LangChainSerialized {
|
|
31
|
+
id?: string[];
|
|
32
|
+
kwargs?: Record<string, unknown>;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
export declare class AgentGuardLangChainHandler {
|
|
36
|
+
readonly name = "agentguard_spend";
|
|
37
|
+
/** Ensures LangChain awaits the handler so a thrown block actually aborts. */
|
|
38
|
+
readonly awaitHandlers = true;
|
|
39
|
+
readonly guard: SpendGuard;
|
|
40
|
+
private readonly opts;
|
|
41
|
+
private readonly pending;
|
|
42
|
+
constructor(opts: LangChainAdapterOptions);
|
|
43
|
+
handleChatModelStart(llm: LangChainSerialized, messages: unknown[][], runId: string, _parentRunId?: string, extraParams?: Record<string, unknown>, _tags?: string[], metadata?: Record<string, unknown>): Promise<void>;
|
|
44
|
+
handleLLMStart(llm: LangChainSerialized, prompts: unknown[], runId: string, _parentRunId?: string, extraParams?: Record<string, unknown>, _tags?: string[], metadata?: Record<string, unknown>): Promise<void>;
|
|
45
|
+
handleLLMEnd(output: unknown, runId: string): Promise<void>;
|
|
46
|
+
handleLLMError(_error: unknown, runId: string): Promise<void>;
|
|
47
|
+
private start;
|
|
48
|
+
}
|
|
49
|
+
export declare function createLangChainHandler(opts: LangChainAdapterOptions): AgentGuardLangChainHandler;
|
|
50
|
+
export declare const agentguardLangChainHandler: typeof createLangChainHandler;
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=langchain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langchain.d.ts","sourceRoot":"","sources":["../../src/frameworks/langchain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAUL,KAAK,uBAAuB,EAE7B,MAAM,UAAU,CAAC;AAElB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACtE,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB;AAED,UAAU,mBAAmB;IAC3B,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,0BAA0B;IACrC,QAAQ,CAAC,IAAI,sBAAsB;IACnC,8EAA8E;IAC9E,QAAQ,CAAC,aAAa,QAAQ;IAC9B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;gBAErD,IAAI,EAAE,uBAAuB;IAKnC,oBAAoB,CACxB,GAAG,EAAE,mBAAmB,EACxB,QAAQ,EAAE,OAAO,EAAE,EAAE,EACrB,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC;IAIV,cAAc,CAClB,GAAG,EAAE,mBAAmB,EACxB,OAAO,EAAE,OAAO,EAAE,EAClB,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC;IAIV,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3D,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAIrD,KAAK;CA2BpB;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,uBAAuB,GAAG,0BAA0B,CAEhG;AAED,eAAO,MAAM,0BAA0B,+BAAyB,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.agentguardLangChainHandler = exports.AgentGuardLangChainHandler = void 0;
|
|
4
|
+
exports.createLangChainHandler = createLangChainHandler;
|
|
5
|
+
const common_1 = require("./common");
|
|
6
|
+
class AgentGuardLangChainHandler {
|
|
7
|
+
name = 'agentguard_spend';
|
|
8
|
+
/** Ensures LangChain awaits the handler so a thrown block actually aborts. */
|
|
9
|
+
awaitHandlers = true;
|
|
10
|
+
guard;
|
|
11
|
+
opts;
|
|
12
|
+
pending = new Map();
|
|
13
|
+
constructor(opts) {
|
|
14
|
+
this.opts = { ...opts, framework: 'langchain' };
|
|
15
|
+
this.guard = (0, common_1.createFrameworkGuard)(this.opts);
|
|
16
|
+
}
|
|
17
|
+
async handleChatModelStart(llm, messages, runId, _parentRunId, extraParams, _tags, metadata) {
|
|
18
|
+
await this.start(runId, llm, messages, extraParams, metadata);
|
|
19
|
+
}
|
|
20
|
+
async handleLLMStart(llm, prompts, runId, _parentRunId, extraParams, _tags, metadata) {
|
|
21
|
+
await this.start(runId, llm, prompts, extraParams, metadata);
|
|
22
|
+
}
|
|
23
|
+
async handleLLMEnd(output, runId) {
|
|
24
|
+
const preflight = this.pending.get(runId);
|
|
25
|
+
if (!preflight)
|
|
26
|
+
return;
|
|
27
|
+
this.pending.delete(runId);
|
|
28
|
+
await (0, common_1.settleFrameworkCall)(preflight, normalizeUsage(output));
|
|
29
|
+
await (0, common_1.recordFrameworkReceipt)(this.guard, 'langchain', {
|
|
30
|
+
event: 'llm_end',
|
|
31
|
+
decisionId: preflight.decision.decisionId,
|
|
32
|
+
model: preflight.decision.modelResolved,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async handleLLMError(_error, runId) {
|
|
36
|
+
this.pending.delete(runId);
|
|
37
|
+
}
|
|
38
|
+
async start(runId, llm, payload, extraParams, metadata) {
|
|
39
|
+
const invocation = (0, common_1.objectRecord)(extraParams?.invocation_params) ?? {};
|
|
40
|
+
const model = (0, common_1.modelFromUnknown)(invocation.model ?? invocation.model_name ?? lastId(llm) ?? (0, common_1.objectRecord)(llm?.kwargs)?.model, this.opts.defaultModel ?? 'unknown');
|
|
41
|
+
const preflight = await (0, common_1.preflightFrameworkCall)(this.guard, this.opts, {
|
|
42
|
+
framework: 'langchain',
|
|
43
|
+
model,
|
|
44
|
+
params: payload,
|
|
45
|
+
outputTokens: (0, common_1.outputTokensFromParams)(invocation, this.opts.defaultOutputTokens ?? 1024),
|
|
46
|
+
metadata: (0, common_1.redactDataPlane)(metadata ?? {}),
|
|
47
|
+
workflowId: (0, common_1.stringValue)(metadata?.workflowId) ?? (0, common_1.stringValue)(metadata?.thread_id),
|
|
48
|
+
requestShape: {
|
|
49
|
+
toolCount: Array.isArray(invocation.tools) ? invocation.tools.length : 0,
|
|
50
|
+
maxTokens: invocation.max_tokens ?? invocation.maxTokens,
|
|
51
|
+
stream: invocation.stream === true,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
this.pending.set(runId, preflight);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.AgentGuardLangChainHandler = AgentGuardLangChainHandler;
|
|
58
|
+
function createLangChainHandler(opts) {
|
|
59
|
+
return new AgentGuardLangChainHandler(opts);
|
|
60
|
+
}
|
|
61
|
+
exports.agentguardLangChainHandler = createLangChainHandler;
|
|
62
|
+
function lastId(llm) {
|
|
63
|
+
const id = llm?.id;
|
|
64
|
+
return Array.isArray(id) && id.length ? id[id.length - 1] : undefined;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Map a LangChain LLMResult into the `{ usage: { inputTokens, outputTokens } }`
|
|
68
|
+
* shape that settleFrameworkCall expects. LangChain reports token usage on
|
|
69
|
+
* `llmOutput.tokenUsage` (OpenAI) or `llmOutput.usage`.
|
|
70
|
+
*/
|
|
71
|
+
function normalizeUsage(output) {
|
|
72
|
+
const record = (0, common_1.objectRecord)(output);
|
|
73
|
+
const llmOutput = (0, common_1.objectRecord)(record?.llmOutput);
|
|
74
|
+
const tokenUsage = (0, common_1.objectRecord)(llmOutput?.tokenUsage) ?? (0, common_1.objectRecord)(llmOutput?.usage);
|
|
75
|
+
if (!tokenUsage)
|
|
76
|
+
return null;
|
|
77
|
+
return {
|
|
78
|
+
usage: {
|
|
79
|
+
inputTokens: tokenUsage.promptTokens ?? tokenUsage.prompt_tokens ?? tokenUsage.input_tokens ?? tokenUsage.inputTokens,
|
|
80
|
+
outputTokens: tokenUsage.completionTokens ?? tokenUsage.completion_tokens ?? tokenUsage.output_tokens ?? tokenUsage.outputTokens,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=langchain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langchain.js","sourceRoot":"","sources":["../../src/frameworks/langchain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type OpenAIBindingOptions } from '../spend-guard';
|
|
2
|
+
/**
|
|
3
|
+
* One-line spend governance for the OpenAI SDK and the OpenAI Agents SDK.
|
|
4
|
+
*
|
|
5
|
+
* Hook point: the OpenAI client's `chat.completions.create`. `withSpendGuard`
|
|
6
|
+
* (the shared core binding) wraps that method so `guard.decide()` runs before
|
|
7
|
+
* every dispatch and can block/downgrade. Because the OpenAI Agents SDK
|
|
8
|
+
* (`@openai/agents`) drives the same underlying `OpenAI` client, passing the
|
|
9
|
+
* guarded client to the agent runner governs every model call the agent makes.
|
|
10
|
+
*
|
|
11
|
+
* This is a thin, named re-export of `withSpendGuard` so the OpenAI integration
|
|
12
|
+
* is discoverable at `@agentguard-run/spend/frameworks/openai`. It reuses the
|
|
13
|
+
* existing enforcement verbatim — no second code path.
|
|
14
|
+
*
|
|
15
|
+
* @example OpenAI SDK
|
|
16
|
+
* import OpenAI from 'openai';
|
|
17
|
+
* import { withSpendGuardOpenAI } from '@agentguard-run/spend/frameworks/openai';
|
|
18
|
+
*
|
|
19
|
+
* const client = withSpendGuardOpenAI(new OpenAI(), { policy, scope });
|
|
20
|
+
* await client.chat.completions.create({ model: 'gpt-5', messages });
|
|
21
|
+
*
|
|
22
|
+
* @example OpenAI Agents SDK
|
|
23
|
+
* import OpenAI from 'openai';
|
|
24
|
+
* import { Agent, run, setDefaultOpenAIClient } from '@openai/agents';
|
|
25
|
+
* import { withSpendGuardOpenAI } from '@agentguard-run/spend/frameworks/openai';
|
|
26
|
+
*
|
|
27
|
+
* setDefaultOpenAIClient(withSpendGuardOpenAI(new OpenAI(), { policy, scope }));
|
|
28
|
+
* await run(new Agent({ name: 'assistant' }), 'hello');
|
|
29
|
+
*/
|
|
30
|
+
export declare function withSpendGuardOpenAI<TClient>(client: TClient, opts: OpenAIBindingOptions): TClient;
|
|
31
|
+
export declare const withOpenAISpendGuard: typeof withSpendGuardOpenAI;
|
|
32
|
+
export type { OpenAIBindingOptions } from '../spend-guard';
|
|
33
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/frameworks/openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAElG;AAED,eAAO,MAAM,oBAAoB,6BAAuB,CAAC;AACzD,YAAY,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withOpenAISpendGuard = void 0;
|
|
4
|
+
exports.withSpendGuardOpenAI = withSpendGuardOpenAI;
|
|
5
|
+
const spend_guard_1 = require("../spend-guard");
|
|
6
|
+
/**
|
|
7
|
+
* One-line spend governance for the OpenAI SDK and the OpenAI Agents SDK.
|
|
8
|
+
*
|
|
9
|
+
* Hook point: the OpenAI client's `chat.completions.create`. `withSpendGuard`
|
|
10
|
+
* (the shared core binding) wraps that method so `guard.decide()` runs before
|
|
11
|
+
* every dispatch and can block/downgrade. Because the OpenAI Agents SDK
|
|
12
|
+
* (`@openai/agents`) drives the same underlying `OpenAI` client, passing the
|
|
13
|
+
* guarded client to the agent runner governs every model call the agent makes.
|
|
14
|
+
*
|
|
15
|
+
* This is a thin, named re-export of `withSpendGuard` so the OpenAI integration
|
|
16
|
+
* is discoverable at `@agentguard-run/spend/frameworks/openai`. It reuses the
|
|
17
|
+
* existing enforcement verbatim — no second code path.
|
|
18
|
+
*
|
|
19
|
+
* @example OpenAI SDK
|
|
20
|
+
* import OpenAI from 'openai';
|
|
21
|
+
* import { withSpendGuardOpenAI } from '@agentguard-run/spend/frameworks/openai';
|
|
22
|
+
*
|
|
23
|
+
* const client = withSpendGuardOpenAI(new OpenAI(), { policy, scope });
|
|
24
|
+
* await client.chat.completions.create({ model: 'gpt-5', messages });
|
|
25
|
+
*
|
|
26
|
+
* @example OpenAI Agents SDK
|
|
27
|
+
* import OpenAI from 'openai';
|
|
28
|
+
* import { Agent, run, setDefaultOpenAIClient } from '@openai/agents';
|
|
29
|
+
* import { withSpendGuardOpenAI } from '@agentguard-run/spend/frameworks/openai';
|
|
30
|
+
*
|
|
31
|
+
* setDefaultOpenAIClient(withSpendGuardOpenAI(new OpenAI(), { policy, scope }));
|
|
32
|
+
* await run(new Agent({ name: 'assistant' }), 'hello');
|
|
33
|
+
*/
|
|
34
|
+
function withSpendGuardOpenAI(client, opts) {
|
|
35
|
+
return (0, spend_guard_1.withSpendGuard)(client, opts);
|
|
36
|
+
}
|
|
37
|
+
exports.withOpenAISpendGuard = withSpendGuardOpenAI;
|
|
38
|
+
//# sourceMappingURL=openai.js.map
|