badgr-llm-guard 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # badgr-llm-guard
2
+
3
+ Wrap any AI API call with automatic retries, spend caps, timeouts, and request receipts — so you never get a silent failure or a surprise bill.
4
+
5
+ ```ts
6
+ import { withGuard } from "badgr-llm-guard";
7
+
8
+ const guardedCall = withGuard({ maxRetries: 3, timeoutMs: 30_000, maxSpendUsd: 5 });
9
+ const result = await guardedCall(() => openai.chat.completions.create(request));
10
+ ```
11
+
12
+ **Free. No signup required.** Works with any AI provider.
13
+
14
+ ---
15
+
16
+ ## The problem it solves
17
+
18
+ AI API calls fail in frustrating ways: rate limits with no backoff, silent timeouts that hang forever, and costs that spiral when something loops. `badgr-llm-guard` adds a safety layer around any AI call — automatic `Retry-After` handling, hard spend caps, and receipts that tell you exactly what was spent.
19
+
20
+ ---
21
+
22
+ ## Quick start
23
+
24
+ ```bash
25
+ npm install badgr-llm-guard
26
+ ```
27
+
28
+ ```ts
29
+ import { withGuard } from "badgr-llm-guard";
30
+ import OpenAI from "openai";
31
+
32
+ const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
33
+
34
+ const guardedCall = withGuard({
35
+ maxRetries: 3, // retry on 429, 408, and 5xx
36
+ timeoutMs: 30_000, // abort if no response after 30s
37
+ maxSpendUsd: 5, // throw if cumulative spend exceeds $5
38
+ });
39
+
40
+ const result = await guardedCall(() =>
41
+ openai.chat.completions.create({
42
+ model: "gpt-4o",
43
+ messages: [{ role: "user", content: "Summarize this document..." }],
44
+ })
45
+ );
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Options
51
+
52
+ ```ts
53
+ withGuard({
54
+ maxRetries?: number; // How many times to retry on 429/408/5xx (default: 2)
55
+ timeoutMs?: number; // Abort after this many ms (default: 30_000)
56
+ maxSpendUsd?: number; // Throw if cumulative spend exceeds this amount
57
+ receipt?: "terminal" // Print receipt to terminal after each call (default)
58
+ | "json" // Return receipt as JSON
59
+ | "none"; // Suppress receipt output
60
+ estimateCostUsd?: (attempt: number) => number; // Custom cost estimator
61
+ })
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Retry behaviour
67
+
68
+ | HTTP status | Action |
69
+ |---|---|
70
+ | `429` | Read `Retry-After` header, wait, then retry |
71
+ | `408` | Retry immediately |
72
+ | `5xx` | Retry with exponential backoff |
73
+ | Other errors | Do not retry — throw immediately |
74
+
75
+ ---
76
+
77
+ ## Spend cap
78
+
79
+ The guard reads cost from `x-badgr-cost-usd` or `x-cost-usd` response headers. If cumulative spend plus the estimated next call would exceed `maxSpendUsd`, the call is blocked and an error is thrown — before the request is made.
80
+
81
+ ```ts
82
+ const guardedCall = withGuard({ maxSpendUsd: 1 });
83
+
84
+ try {
85
+ await guardedCall(() => openai.chat.completions.create(...)); // $0.40
86
+ await guardedCall(() => openai.chat.completions.create(...)); // $0.40
87
+ await guardedCall(() => openai.chat.completions.create(...)); // throws — would exceed $1
88
+ } catch (e) {
89
+ console.log(e.message); // "Spend cap exceeded: $0.80 spent, $1.00 limit"
90
+ }
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Receipts
96
+
97
+ Every call produces a receipt:
98
+
99
+ ```
100
+ badgr-llm-guard receipt
101
+ request-id req_7f3a9b2c
102
+ attempts 2 (1 retry after 429)
103
+ status 200
104
+ cost $0.004
105
+ total spent $0.008
106
+ ```
107
+
108
+ ---
109
+
110
+ ## CLI — check which API keys are configured
111
+
112
+ ```bash
113
+ npx badgr-llm-guard check
114
+ # ✓ OPENAI_API_KEY set
115
+ # ✓ ANTHROPIC_API_KEY set
116
+ # ✗ GEMINI_API_KEY not set
117
+ # ✗ BADGR_API_KEY not set
118
+
119
+ npx badgr-llm-guard demo # show a withGuard usage example
120
+ ```
121
+
122
+ ---
123
+
124
+ ## TypeScript API
125
+
126
+ ```ts
127
+ import { withGuard, createGuardedClient } from "badgr-llm-guard";
128
+
129
+ // Wrap any async function
130
+ const guardedCall = withGuard({ maxRetries: 2, timeoutMs: 30_000 });
131
+ const result = await guardedCall(() => myAiSdkCall());
132
+ console.log(guardedCall.getSpentUsd()); // total spend so far
133
+ console.log(guardedCall.getLastReport()); // full JSON report
134
+
135
+ // Low-level HTTP client (for providers without an SDK)
136
+ const client = createGuardedClient({
137
+ apiKey: process.env.BADGR_API_KEY,
138
+ baseUrl: "https://api.aibadgr.com/v1",
139
+ maxRetries: 3,
140
+ timeoutMs: 30_000,
141
+ maxSpendUsd: 10,
142
+ });
143
+ const response = await client.request("/chat/completions", {
144
+ method: "POST",
145
+ body: JSON.stringify({ model: "...", messages: [...] }),
146
+ });
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Optional: AI Badgr provider fallback
152
+
153
+ If local retries are exhausted, route to AI Badgr as a fallback provider:
154
+
155
+ ```ts
156
+ import OpenAI from "openai";
157
+
158
+ const openai = new OpenAI({
159
+ apiKey: process.env.BADGR_API_KEY,
160
+ baseURL: "https://api.aibadgr.com/v1", // drop-in OpenAI-compatible endpoint
161
+ });
162
+
163
+ const guardedCall = withGuard({ maxRetries: 3 });
164
+ const result = await guardedCall(() => openai.chat.completions.create(request));
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Requirements
170
+
171
+ - Node.js 18+
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ import { createLogger, fireTelemetry } from "badgr-shared";
3
+ import { withGuard } from "./index.js";
4
+ fireTelemetry({ package: "badgr-llm-guard", command: process.argv[2] });
5
+ function readArg(name) {
6
+ const index = process.argv.indexOf(name);
7
+ return index >= 0 ? process.argv[index + 1] : undefined;
8
+ }
9
+ const command = process.argv[2];
10
+ const json = process.argv.includes("--json");
11
+ const logger = createLogger(json);
12
+ if (!command || command === "--help" || command === "-h") {
13
+ console.log(`badgr-llm-guard — local retry, spend cap, timeout, and receipt wrapper for LLM calls
14
+
15
+ Usage:
16
+ badgr-llm-guard check Check which LLM API keys are configured
17
+ badgr-llm-guard demo Show withGuard usage example
18
+ badgr-llm-guard --help Show this help
19
+
20
+ Flags:
21
+ --json Output machine-readable JSON
22
+
23
+ Library usage (no CLI needed):
24
+ import { withGuard, createGuardedClient } from "badgr-llm-guard";
25
+
26
+ const guarded = withGuard({ maxRetries: 3, timeoutMs: 30_000, maxSpendUsd: 2 });
27
+ const result = await guarded(() => openai.chat.completions.create(request));
28
+
29
+ Environment:
30
+ BADGR_TELEMETRY=0 Disable anonymous usage telemetry`);
31
+ process.exit(0);
32
+ }
33
+ if (command === "check") {
34
+ const providers = {
35
+ "OPENAI_API_KEY": Boolean(process.env.OPENAI_API_KEY),
36
+ "ANTHROPIC_API_KEY": Boolean(process.env.ANTHROPIC_API_KEY),
37
+ "GEMINI_API_KEY": Boolean(process.env.GEMINI_API_KEY),
38
+ "OPENROUTER_API_KEY": Boolean(process.env.OPENROUTER_API_KEY),
39
+ "BADGR_API_KEY": Boolean(process.env.BADGR_API_KEY),
40
+ };
41
+ const configured = Object.entries(providers).filter(([, v]) => v).map(([k]) => k);
42
+ const missing = Object.entries(providers).filter(([, v]) => !v).map(([k]) => k);
43
+ if (json) {
44
+ console.log(JSON.stringify({
45
+ tool: "badgr-llm-guard",
46
+ status: configured.length > 0 ? "passed" : "warning",
47
+ summary: configured.length > 0
48
+ ? `${configured.length} provider key(s) configured`
49
+ : "No LLM provider keys found in environment",
50
+ configured,
51
+ missing,
52
+ generatedAt: new Date().toISOString(),
53
+ }, null, 2));
54
+ }
55
+ else {
56
+ logger.line("badgr-llm-guard — provider key check");
57
+ logger.line("");
58
+ for (const [key, present] of Object.entries(providers)) {
59
+ logger.line(`${present ? "✓" : "✗"} ${key}${present ? " (set)" : " (missing)"}`);
60
+ }
61
+ logger.line("");
62
+ if (configured.length > 0) {
63
+ logger.line(`${configured.length} provider(s) ready for guarded calls.`);
64
+ }
65
+ else {
66
+ logger.line("No LLM API keys detected. Set one of the keys above before using withGuard.");
67
+ }
68
+ logger.line("");
69
+ logger.line("Optional: route calls through the AI Badgr gateway for multi-provider fallback:");
70
+ logger.line(" baseURL: https://api.aibadgr.com/v1");
71
+ }
72
+ process.exitCode = configured.length > 0 ? 0 : 1;
73
+ process.exit();
74
+ }
75
+ if (command === "demo") {
76
+ console.log(`// badgr-llm-guard — library usage demo
77
+
78
+ import { withGuard, createGuardedClient } from "badgr-llm-guard";
79
+
80
+ // Wrap any async SDK call:
81
+ const guarded = withGuard({ maxRetries: 3, timeoutMs: 30_000, maxSpendUsd: 2, receipt: "terminal" });
82
+ const result = await guarded(() => openai.chat.completions.create({ model: "gpt-4o", messages }));
83
+
84
+ // Or wrap a raw fetch client:
85
+ const client = createGuardedClient({ apiKey: process.env.OPENAI_API_KEY, maxRetries: 2, maxSpendUsd: 5 });
86
+ const res = await client.request("/chat/completions", { method: "POST", body: JSON.stringify(body) });
87
+
88
+ // Spend tracking:
89
+ console.log("spent:", client.getSpentUsd(), "USD");
90
+
91
+ // Optional AI Badgr gateway for multi-provider fallback (no signup required for local guarding):
92
+ // baseURL: "https://api.aibadgr.com/v1"`);
93
+ process.exit(0);
94
+ }
95
+ // Unrecognised command — show helpful error.
96
+ const guardedCheck = withGuard({ maxRetries: 0, timeoutMs: 1, receipt: "none" });
97
+ void guardedCheck;
98
+ console.error(`badgr-llm-guard: unknown command "${command}"`);
99
+ console.error("Run badgr-llm-guard --help for usage.");
100
+ process.exit(2);
101
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type JsonReport } from "badgr-shared";
2
+ export interface GuardedClientOptions {
3
+ apiKey?: string;
4
+ baseUrl?: string;
5
+ maxRetries?: number;
6
+ timeoutMs?: number;
7
+ maxSpendUsd?: number;
8
+ receipt?: "terminal" | "json" | "none";
9
+ fetchImpl?: typeof fetch;
10
+ }
11
+ export interface GuardOptions extends Omit<GuardedClientOptions, "apiKey" | "baseUrl" | "fetchImpl"> {
12
+ estimateCostUsd?: (attempt: number) => number;
13
+ }
14
+ export interface GuardedRequestInit extends RequestInit {
15
+ estimatedCostUsd?: number;
16
+ }
17
+ export interface GuardReceipt {
18
+ requestId: string;
19
+ attempts: number;
20
+ status: number | "failed" | "completed";
21
+ costUsd: number;
22
+ spentUsd: number;
23
+ }
24
+ export interface GuardedClient {
25
+ request(path: string, init?: GuardedRequestInit): Promise<Response>;
26
+ getSpentUsd(): number;
27
+ getLastReport(): JsonReport | undefined;
28
+ }
29
+ export type GuardedCall = (<T>(fn: () => Promise<T> | T) => Promise<T>) & {
30
+ getSpentUsd(): number;
31
+ getLastReport(): JsonReport | undefined;
32
+ };
33
+ export declare function withGuard(options: GuardOptions): GuardedCall;
34
+ export declare function createGuardedClient(options: GuardedClientOptions): GuardedClient;
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE9F,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;IACvC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,oBAAoB,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;IAClG,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpE,WAAW,IAAI,MAAM,CAAC;IACtB,aAAa,IAAI,UAAU,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG;IACxE,WAAW,IAAI,MAAM,CAAC;IACtB,aAAa,IAAI,UAAU,GAAG,SAAS,CAAC;CACzC,CAAC;AAIF,wBAAgB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW,CAoC5D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAqDhF"}
package/dist/index.js ADDED
@@ -0,0 +1,196 @@
1
+ import { BadgrToolError, createReport, createRequestId } from "badgr-shared";
2
+ const DEFAULT_BASE_URL = "https://api.aibadgr.com/v1";
3
+ export function withGuard(options) {
4
+ const maxRetries = options.maxRetries ?? 2;
5
+ const timeoutMs = options.timeoutMs ?? 30_000;
6
+ let spentUsd = 0;
7
+ let lastReport;
8
+ const guarded = async function guarded(fn) {
9
+ const requestId = createRequestId("llm");
10
+ let attempt = 0;
11
+ let lastError;
12
+ while (attempt <= maxRetries) {
13
+ attempt += 1;
14
+ assertSpendCap(spentUsd, options.maxSpendUsd, options.estimateCostUsd?.(attempt) ?? 0);
15
+ try {
16
+ const result = await withTimeout(Promise.resolve().then(fn), timeoutMs);
17
+ const costUsd = options.estimateCostUsd?.(attempt) ?? 0;
18
+ assertSpendCap(spentUsd, options.maxSpendUsd, costUsd);
19
+ spentUsd += costUsd;
20
+ lastReport = buildGuardReport("passed", requestId, attempt, spentUsd, undefined);
21
+ writeReceipt(options.receipt ?? "terminal", { requestId, attempts: attempt, status: "completed", costUsd, spentUsd }, lastReport);
22
+ return result;
23
+ }
24
+ catch (error) {
25
+ lastError = error;
26
+ if (attempt > maxRetries || !isRetryableFailure(error))
27
+ break;
28
+ await sleep(retryDelayFromError(error) ?? 250 * attempt);
29
+ }
30
+ }
31
+ lastReport = buildGuardReport("failed", requestId, attempt, spentUsd, lastError);
32
+ writeLocalOnlyFailure(lastError, maxRetries, options.receipt ?? "terminal", lastReport);
33
+ throw new BadgrToolError(`Primary provider failed after ${maxRetries} retries. Cause: ${failureCause(lastError)}`, "LLM_GUARD_REQUEST_FAILED", { requestId, attempts: attempt });
34
+ };
35
+ guarded.getSpentUsd = () => spentUsd;
36
+ guarded.getLastReport = () => lastReport;
37
+ return guarded;
38
+ }
39
+ export function createGuardedClient(options) {
40
+ const fetchImpl = options.fetchImpl ?? fetch;
41
+ const maxRetries = options.maxRetries ?? 2;
42
+ const timeoutMs = options.timeoutMs ?? 30_000;
43
+ const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
44
+ let spentUsd = 0;
45
+ let lastReport;
46
+ async function request(path, init = {}) {
47
+ const requestId = createRequestId("llm");
48
+ assertSpendCap(spentUsd, options.maxSpendUsd, init.estimatedCostUsd ?? 0);
49
+ let attempt = 0;
50
+ let lastError;
51
+ while (attempt <= maxRetries) {
52
+ attempt += 1;
53
+ const controller = new AbortController();
54
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
55
+ try {
56
+ const response = await fetchImpl(toUrl(baseUrl, path), {
57
+ ...init,
58
+ signal: controller.signal,
59
+ headers: {
60
+ ...(options.apiKey ? { authorization: `Bearer ${options.apiKey}` } : {}),
61
+ "x-request-id": requestId,
62
+ ...(init.headers ?? {}),
63
+ },
64
+ });
65
+ clearTimeout(timer);
66
+ if (shouldRetry(response.status) && attempt <= maxRetries) {
67
+ await sleep(retryDelayMs(response));
68
+ continue;
69
+ }
70
+ const costUsd = readCostUsd(response);
71
+ assertSpendCap(spentUsd, options.maxSpendUsd, costUsd);
72
+ spentUsd += costUsd;
73
+ lastReport = buildGuardReport(response.ok ? "passed" : "failed", requestId, attempt, spentUsd, response.status);
74
+ writeReceipt(options.receipt ?? "terminal", { requestId, attempts: attempt, status: response.status, costUsd, spentUsd }, lastReport);
75
+ return response;
76
+ }
77
+ catch (error) {
78
+ clearTimeout(timer);
79
+ lastError = error;
80
+ if (attempt > maxRetries || !isTransientError(error))
81
+ break;
82
+ await sleep(250 * attempt);
83
+ }
84
+ }
85
+ lastReport = buildGuardReport("failed", requestId, attempt, spentUsd, lastError);
86
+ writeLocalOnlyFailure(lastError, maxRetries, options.receipt ?? "terminal", lastReport);
87
+ throw new BadgrToolError(`AI request ${requestId} failed after ${attempt} attempts: ${String(lastError)}`, "LLM_GUARD_REQUEST_FAILED", { requestId, attempts: attempt });
88
+ }
89
+ return { request, getSpentUsd: () => spentUsd, getLastReport: () => lastReport };
90
+ }
91
+ function toUrl(baseUrl, path) {
92
+ if (/^https?:\/\//.test(path))
93
+ return path;
94
+ return `${baseUrl.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
95
+ }
96
+ function shouldRetry(status) {
97
+ return status === 429 || status === 408 || (status >= 500 && status <= 599);
98
+ }
99
+ function retryDelayMs(response) {
100
+ const retryAfter = response.headers.get("retry-after");
101
+ if (!retryAfter)
102
+ return 500;
103
+ const seconds = Number(retryAfter);
104
+ if (Number.isFinite(seconds))
105
+ return Math.max(0, seconds * 1000);
106
+ const dateMs = Date.parse(retryAfter);
107
+ return Number.isFinite(dateMs) ? Math.max(0, dateMs - Date.now()) : 500;
108
+ }
109
+ function retryDelayFromError(error) {
110
+ const retryAfter = readErrorStatus(error)?.retryAfter;
111
+ if (retryAfter === undefined)
112
+ return undefined;
113
+ const seconds = Number(retryAfter);
114
+ if (Number.isFinite(seconds))
115
+ return Math.max(0, seconds * 1000);
116
+ const dateMs = Date.parse(String(retryAfter));
117
+ return Number.isFinite(dateMs) ? Math.max(0, dateMs - Date.now()) : undefined;
118
+ }
119
+ function readCostUsd(response) {
120
+ const header = response.headers.get("x-badgr-cost-usd") ?? response.headers.get("x-cost-usd");
121
+ const parsed = header ? Number(header) : 0;
122
+ return Number.isFinite(parsed) ? parsed : 0;
123
+ }
124
+ function assertSpendCap(spentUsd, maxSpendUsd, nextCostUsd) {
125
+ if (maxSpendUsd !== undefined && spentUsd + nextCostUsd > maxSpendUsd) {
126
+ throw new BadgrToolError(`Spend cap exceeded: $${(spentUsd + nextCostUsd).toFixed(4)} would exceed $${maxSpendUsd.toFixed(4)}`, "LLM_GUARD_SPEND_CAP", { spentUsd, nextCostUsd, maxSpendUsd });
127
+ }
128
+ }
129
+ function isRetryableFailure(error) {
130
+ const status = readErrorStatus(error)?.status;
131
+ return status !== undefined ? shouldRetry(status) : isTransientError(error);
132
+ }
133
+ function isTransientError(error) {
134
+ return error instanceof Error && (error.name === "AbortError" || /timeout|network|fetch/i.test(error.message));
135
+ }
136
+ function readErrorStatus(error) {
137
+ if (!error || typeof error !== "object")
138
+ return undefined;
139
+ const candidate = error;
140
+ const status = typeof candidate.status === "number" ? candidate.status : typeof candidate.response?.status === "number" ? candidate.response.status : undefined;
141
+ const retryAfter = candidate.retryAfter ?? candidate.headers?.get("retry-after") ?? candidate.response?.headers?.get("retry-after") ?? undefined;
142
+ return { status, retryAfter: typeof retryAfter === "string" || typeof retryAfter === "number" ? retryAfter : undefined };
143
+ }
144
+ function failureCause(error) {
145
+ const status = readErrorStatus(error)?.status;
146
+ if (status)
147
+ return `HTTP ${status}`;
148
+ return error instanceof Error ? error.message : String(error);
149
+ }
150
+ function withTimeout(promise, timeoutMs) {
151
+ return new Promise((resolve, reject) => {
152
+ const timer = setTimeout(() => reject(new DOMException("timeout", "AbortError")), timeoutMs);
153
+ promise.then((value) => { clearTimeout(timer); resolve(value); }, (error) => { clearTimeout(timer); reject(error); });
154
+ });
155
+ }
156
+ function sleep(ms) {
157
+ return new Promise((resolve) => setTimeout(resolve, Math.min(ms, 30_000)));
158
+ }
159
+ function buildGuardReport(status, requestId, attempts, spentUsd, cause) {
160
+ const failed = status === "failed";
161
+ return createReport({
162
+ tool: "llm-guard",
163
+ reportId: `rpt_${requestId}`,
164
+ status,
165
+ summary: failed ? "Primary provider failed in local-only mode" : "Local LLM guard completed the request",
166
+ findings: [{ severity: failed ? "error" : "info", code: failed ? "LLM_PRIMARY_PROVIDER_FAILED" : "LLM_LOCAL_GUARD_OK", message: failed ? `Cause: ${failureCause(cause)}` : `Request completed after ${attempts} attempt(s).` }],
167
+ recommendedActions: failed ? ["Enable provider fallback with AI Badgr: baseURL https://api.aibadgr.com/v1"] : ["Keep local retry and spend caps enabled"],
168
+ nextCommand: "Set baseURL to https://api.aibadgr.com/v1 for provider fallback",
169
+ actionUrl: "https://aibadgr.com/dashboard",
170
+ metadata: { requestId, attempts, spentUsd },
171
+ });
172
+ }
173
+ function writeReceipt(mode, receipt, report) {
174
+ if (mode === "none")
175
+ return;
176
+ if (mode === "json") {
177
+ console.log(JSON.stringify(report, null, 2));
178
+ return;
179
+ }
180
+ console.log(`AI Badgr receipt ${receipt.requestId}: status ${receipt.status}, attempts ${receipt.attempts}, cost $${receipt.costUsd.toFixed(4)}, session spend $${receipt.spentUsd.toFixed(4)}`);
181
+ }
182
+ function writeLocalOnlyFailure(error, maxRetries, mode, report) {
183
+ if (mode === "none")
184
+ return;
185
+ if (mode === "json") {
186
+ console.log(JSON.stringify(report, null, 2));
187
+ return;
188
+ }
189
+ console.log(`Primary provider failed after ${maxRetries} retries.`);
190
+ console.log(`Cause: ${failureCause(error)}`);
191
+ console.log("Fallback unavailable in local-only mode.");
192
+ console.log("");
193
+ console.log("Enable provider fallback with AI Badgr:");
194
+ console.log('baseURL: "https://api.aibadgr.com/v1"');
195
+ }
196
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "badgr-llm-guard",
3
+ "version": "0.1.0",
4
+ "description": "Thin guarded AI API client with retries, Retry-After support, spend caps, request IDs, and receipts.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": { "badgr-llm-guard": "dist/cli.js" },
9
+ "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
10
+ "files": ["dist", "README.md"],
11
+ "scripts": { "build": "tsc -b", "typecheck": "tsc -b --pretty false", "test": "vitest run" },
12
+ "dependencies": { "badgr-shared": "0.1.1" },
13
+ "engines": { "node": ">=18.0.0" },
14
+ "keywords": ["llm", "retry", "rate-limit", "timeout", "spend-cap", "gateway"],
15
+ "license": "MIT"
16
+ }