caplyr 0.1.9 → 0.2.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 +18 -44
- package/dist/index.d.mts +143 -28
- package/dist/index.d.ts +143 -28
- package/dist/index.js +394 -261
- package/dist/index.mjs +394 -261
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**AI Cost Control Plane** — Stop runaway API bills automatically.
|
|
4
4
|
|
|
5
|
-
Caplyr
|
|
5
|
+
Caplyr sits between your app and AI providers, controlling how requests execute based on cost constraints. Budget guardrails, auto-downgrade, and kill switch — in 2 lines of code.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -18,10 +18,9 @@ import { protect } from "caplyr";
|
|
|
18
18
|
|
|
19
19
|
// Wrap your client — everything else stays the same
|
|
20
20
|
const client = protect(new Anthropic(), {
|
|
21
|
-
apiKey: "caplyr_...",
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
fallback: "claude-haiku-4-5-20251001", // Auto-downgrade target
|
|
21
|
+
apiKey: "caplyr_...", // Get yours at https://app.caplyr.com
|
|
22
|
+
budget: 500, // Monthly cap in dollars
|
|
23
|
+
fallback: "claude-haiku-3-5-20241022", // Auto-downgrade target
|
|
25
24
|
});
|
|
26
25
|
|
|
27
26
|
// Use exactly as before — Caplyr is invisible
|
|
@@ -40,8 +39,7 @@ import { protect } from "caplyr";
|
|
|
40
39
|
|
|
41
40
|
const client = protect(new OpenAI(), {
|
|
42
41
|
apiKey: "caplyr_...",
|
|
43
|
-
|
|
44
|
-
budget: { monthly: 500 },
|
|
42
|
+
budget: 500,
|
|
45
43
|
fallback: "gpt-4o-mini",
|
|
46
44
|
});
|
|
47
45
|
|
|
@@ -55,57 +53,42 @@ const response = await client.chat.completions.create({
|
|
|
55
53
|
|
|
56
54
|
| Feature | Description |
|
|
57
55
|
|---------|-------------|
|
|
58
|
-
| **Budget Guardrails** | Daily and monthly caps. Hit the limit → requests are blocked
|
|
56
|
+
| **Budget Guardrails** | Daily and monthly caps enforced at the SDK level. Hit the limit → requests are blocked or downgraded. |
|
|
59
57
|
| **Auto Downgrade** | When budget threshold is reached, automatically route to a cheaper model. Your app keeps working. |
|
|
60
|
-
| **Kill Switch** | One-click emergency stop
|
|
61
|
-
|
|
62
|
-
## How Enforcement Works
|
|
63
|
-
|
|
64
|
-
Budget limits are managed **server-side** in your Caplyr project settings. The SDK sends your configured `budget` values to the server via heartbeats, and the server returns the current budget status (usage, limits, kill switch state). The SDK enforces limits locally based on that server response — the server is the source of truth, not the local config.
|
|
65
|
-
|
|
66
|
-
If you set `budget` in the SDK but have different limits in your dashboard, the dashboard settings take precedence.
|
|
58
|
+
| **Kill Switch** | One-click emergency stop. Halts all AI API calls instantly. |
|
|
67
59
|
|
|
68
60
|
## Modes
|
|
69
61
|
|
|
70
62
|
```typescript
|
|
71
|
-
// Alert-only (default): observe and
|
|
72
|
-
protect(client, { apiKey: "..." });
|
|
63
|
+
// Alert-only (default): observe and project, don't enforce
|
|
64
|
+
protect(client, { apiKey: "...", mode: "alert_only" });
|
|
73
65
|
|
|
74
66
|
// Cost protect: enforce budget caps and auto-downgrade
|
|
75
|
-
protect(client, { apiKey: "...", mode: "cost_protect", budget:
|
|
67
|
+
protect(client, { apiKey: "...", mode: "cost_protect", budget: 500 });
|
|
76
68
|
```
|
|
77
69
|
|
|
78
|
-
> **Tip:** Setting `budget` without specifying `mode` will automatically enable `cost_protect`.
|
|
79
|
-
|
|
80
|
-
## Currently Wrapped Endpoints
|
|
81
|
-
|
|
82
|
-
- **Anthropic:** `client.messages.create()`
|
|
83
|
-
- **OpenAI:** `client.chat.completions.create()`
|
|
84
|
-
|
|
85
|
-
Other endpoints (embeddings, images, Responses API) are not yet wrapped. Streaming requests (`stream: true`) are passed through but usage tracking may be incomplete.
|
|
86
|
-
|
|
87
70
|
## Configuration
|
|
88
71
|
|
|
89
72
|
| Option | Type | Default | Description |
|
|
90
73
|
|--------|------|---------|-------------|
|
|
91
74
|
| `apiKey` | `string` | required | Your Caplyr project API key |
|
|
92
|
-
| `budget` | `
|
|
75
|
+
| `budget` | `number` | — | Monthly budget cap in dollars |
|
|
76
|
+
| `dailyBudget` | `number` | — | Daily budget cap in dollars |
|
|
93
77
|
| `fallback` | `string` | auto | Fallback model for auto-downgrade |
|
|
94
|
-
| `mode` | `"alert_only" \| "cost_protect"`
|
|
78
|
+
| `mode` | `string` | `"alert_only"` | `"alert_only"` \| `"cost_protect"` \| `"kill_switch"` |
|
|
95
79
|
| `downgradeThreshold` | `number` | `0.8` | Budget % at which downgrade activates |
|
|
96
80
|
| `endpoint_tag` | `string` | — | Custom tag for cost attribution |
|
|
97
|
-
| `dashboardUrl` | `string` | `https://app.caplyr.com` | Dashboard URL for error messages |
|
|
98
|
-
| `endpoint` | `string` | `https://api.caplyr.com` | API endpoint for heartbeat/ingestion |
|
|
99
81
|
|
|
100
82
|
## Handling Blocked Requests
|
|
101
83
|
|
|
102
|
-
When a request is blocked
|
|
84
|
+
When a request is blocked, Caplyr throws a structured error:
|
|
103
85
|
|
|
104
86
|
```typescript
|
|
105
87
|
try {
|
|
106
88
|
const response = await client.messages.create({ ... });
|
|
107
89
|
} catch (err) {
|
|
108
90
|
if (err.caplyr) {
|
|
91
|
+
// Caplyr enforcement event
|
|
109
92
|
console.log(err.caplyr.code); // "BUDGET_EXCEEDED" | "KILL_SWITCH_ACTIVE"
|
|
110
93
|
console.log(err.caplyr.retry_after); // ISO timestamp for next reset
|
|
111
94
|
console.log(err.caplyr.budget_used); // Current spend
|
|
@@ -113,28 +96,19 @@ try {
|
|
|
113
96
|
}
|
|
114
97
|
```
|
|
115
98
|
|
|
116
|
-
In `alert_only` mode, the request proceeds and the `onEnforcement` callback is fired instead.
|
|
117
|
-
|
|
118
99
|
## Shutdown
|
|
119
100
|
|
|
120
|
-
Caplyr does **not** register SIGINT/SIGTERM handlers — your app owns its process lifecycle. Call `shutdown()` in your own signal handler to flush pending logs before exit:
|
|
121
|
-
|
|
122
101
|
```typescript
|
|
123
102
|
import { shutdown } from "caplyr";
|
|
124
103
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
process.exit(0);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
process.on("SIGTERM", gracefulShutdown);
|
|
131
|
-
process.on("SIGINT", gracefulShutdown);
|
|
104
|
+
// Flush pending logs on app exit
|
|
105
|
+
process.on("SIGTERM", () => shutdown());
|
|
132
106
|
```
|
|
133
107
|
|
|
134
108
|
## Links
|
|
135
109
|
|
|
136
110
|
- **Dashboard**: [app.caplyr.com](https://app.caplyr.com)
|
|
137
|
-
- **Docs**: [caplyr.com
|
|
111
|
+
- **Docs**: [docs.caplyr.com](https://docs.caplyr.com)
|
|
138
112
|
- **Website**: [caplyr.com](https://caplyr.com)
|
|
139
113
|
|
|
140
114
|
## License
|
package/dist/index.d.mts
CHANGED
|
@@ -1,53 +1,168 @@
|
|
|
1
|
+
/** Protection status of the SDK connection */
|
|
2
|
+
type ProtectionStatus = "ACTIVE" | "DEGRADED" | "OFF";
|
|
3
|
+
/** Supported AI providers */
|
|
4
|
+
type Provider = "anthropic" | "openai";
|
|
5
|
+
/** Operating mode for the SDK */
|
|
6
|
+
type CaplyrMode = "cost_protect" | "alert_only" | "kill_switch";
|
|
7
|
+
/** Configuration for the protect() function */
|
|
1
8
|
interface CaplyrConfig {
|
|
9
|
+
/** Your Caplyr project API key */
|
|
2
10
|
apiKey: string;
|
|
3
|
-
|
|
4
|
-
/** Budget limits. Enforcement is server-side, based on project settings tied to your API key. */
|
|
5
|
-
budget?: {
|
|
6
|
-
daily?: number;
|
|
7
|
-
monthly?: number;
|
|
8
|
-
};
|
|
9
|
-
downgradeThreshold?: number;
|
|
10
|
-
fallback?: string;
|
|
11
|
-
/** API endpoint for heartbeat and log ingestion (default: https://caplyr.com) */
|
|
11
|
+
/** Caplyr backend URL (defaults to https://api.caplyr.com) */
|
|
12
12
|
endpoint?: string;
|
|
13
|
-
/**
|
|
14
|
-
|
|
13
|
+
/** Operating mode (defaults to "alert_only" for trust-building) */
|
|
14
|
+
mode?: CaplyrMode;
|
|
15
|
+
/** Monthly budget cap in dollars */
|
|
16
|
+
budget?: number;
|
|
17
|
+
/** Daily budget cap in dollars */
|
|
18
|
+
dailyBudget?: number;
|
|
19
|
+
/** Fallback model when budget is approached/exceeded */
|
|
20
|
+
fallback?: string;
|
|
21
|
+
/** Budget threshold (0-1) at which auto-downgrade activates (default: 0.8) */
|
|
22
|
+
downgradeThreshold?: number;
|
|
23
|
+
/** Custom endpoint tag for attribution */
|
|
15
24
|
endpoint_tag?: string;
|
|
25
|
+
/** Batch size before flushing logs (default: 10) */
|
|
16
26
|
batchSize?: number;
|
|
27
|
+
/** Max interval in ms between log flushes (default: 30000) */
|
|
17
28
|
flushInterval?: number;
|
|
29
|
+
/** Heartbeat interval in ms (default: 60000) */
|
|
18
30
|
heartbeatInterval?: number;
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
/** Called when protection status changes */
|
|
32
|
+
onStatusChange?: (status: ProtectionStatus) => void;
|
|
33
|
+
/** Called when an enforcement event occurs */
|
|
34
|
+
onEnforcement?: (event: EnforcementEvent) => void;
|
|
35
|
+
/** Called when an error occurs in the SDK (non-blocking) */
|
|
36
|
+
onError?: (error: Error) => void;
|
|
37
|
+
}
|
|
38
|
+
/** Metadata captured for every AI API call */
|
|
39
|
+
interface RequestLog {
|
|
40
|
+
/** Unique request ID */
|
|
41
|
+
id: string;
|
|
42
|
+
/** Timestamp of the request */
|
|
43
|
+
timestamp: number;
|
|
44
|
+
/** Provider: "anthropic" | "openai" */
|
|
45
|
+
provider: Provider;
|
|
46
|
+
/** Model used (e.g., "claude-sonnet-4-20250514") */
|
|
47
|
+
model: string;
|
|
48
|
+
/** Input tokens consumed */
|
|
49
|
+
input_tokens: number;
|
|
50
|
+
/** Output tokens consumed */
|
|
51
|
+
output_tokens: number;
|
|
52
|
+
/** Calculated cost in dollars */
|
|
53
|
+
cost: number;
|
|
54
|
+
/** Request latency in milliseconds */
|
|
55
|
+
latency_ms: number;
|
|
56
|
+
/** Endpoint tag for attribution */
|
|
57
|
+
endpoint_tag?: string;
|
|
58
|
+
/** Whether this request was auto-downgraded */
|
|
59
|
+
downgraded: boolean;
|
|
60
|
+
/** Original model if downgraded */
|
|
61
|
+
original_model?: string;
|
|
62
|
+
/** Whether this request was blocked */
|
|
63
|
+
blocked: boolean;
|
|
64
|
+
/** Reason for block/downgrade if applicable */
|
|
65
|
+
enforcement_reason?: string;
|
|
21
66
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
67
|
+
/** Enforcement event emitted when guardrails activate */
|
|
68
|
+
interface EnforcementEvent {
|
|
69
|
+
type: "downgrade" | "block" | "kill_switch";
|
|
70
|
+
timestamp: number;
|
|
71
|
+
reason: string;
|
|
72
|
+
original_model?: string;
|
|
73
|
+
fallback_model?: string;
|
|
74
|
+
budget_used: number;
|
|
75
|
+
budget_limit: number;
|
|
76
|
+
estimated_savings: number;
|
|
28
77
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
78
|
+
/** Budget status returned from the backend */
|
|
79
|
+
interface BudgetStatus {
|
|
80
|
+
daily_used: number;
|
|
81
|
+
daily_limit: number | null;
|
|
82
|
+
monthly_used: number;
|
|
83
|
+
monthly_limit: number | null;
|
|
84
|
+
status: ProtectionStatus;
|
|
85
|
+
kill_switch_active: boolean;
|
|
86
|
+
}
|
|
87
|
+
/** Structured error returned when a request is blocked */
|
|
88
|
+
interface CaplyrBlockedError {
|
|
89
|
+
code: "BUDGET_EXCEEDED" | "KILL_SWITCH_ACTIVE" | "RATE_LIMITED";
|
|
90
|
+
message: string;
|
|
91
|
+
budget_used: number;
|
|
92
|
+
budget_limit: number;
|
|
93
|
+
retry_after?: string;
|
|
94
|
+
dashboard_url: string;
|
|
95
|
+
}
|
|
96
|
+
/** Internal state of the SDK */
|
|
97
|
+
interface CaplyrState {
|
|
98
|
+
status: ProtectionStatus;
|
|
99
|
+
mode: CaplyrMode;
|
|
34
100
|
budget_daily_used: number;
|
|
35
101
|
budget_monthly_used: number;
|
|
36
102
|
kill_switch_active: boolean;
|
|
37
|
-
last_heartbeat: number
|
|
103
|
+
last_heartbeat: number;
|
|
38
104
|
request_count: number;
|
|
39
105
|
total_cost: number;
|
|
40
|
-
|
|
106
|
+
total_savings: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Wrap an AI provider client with Caplyr cost control.
|
|
111
|
+
*
|
|
112
|
+
* Returns a proxy that is type-compatible with the original client.
|
|
113
|
+
* All existing code works unchanged — Caplyr is invisible to callers.
|
|
114
|
+
*
|
|
115
|
+
* @param client - An Anthropic or OpenAI client instance
|
|
116
|
+
* @param config - Caplyr configuration
|
|
117
|
+
* @returns A proxied client with cost control applied
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* import Anthropic from "@anthropic-ai/sdk"
|
|
122
|
+
* import { protect } from "caplyr"
|
|
123
|
+
*
|
|
124
|
+
* const client = protect(new Anthropic(), {
|
|
125
|
+
* apiKey: "caplyr_...",
|
|
126
|
+
* budget: 500,
|
|
127
|
+
* })
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
declare function protect<T>(client: T, config: CaplyrConfig): T;
|
|
131
|
+
/**
|
|
132
|
+
* Get the current protection status for a given API key.
|
|
133
|
+
*/
|
|
134
|
+
declare function getStatus(apiKey: string): ProtectionStatus;
|
|
135
|
+
/**
|
|
136
|
+
* Get the full SDK state for a given API key.
|
|
137
|
+
*/
|
|
138
|
+
declare function getState(apiKey: string): CaplyrState | null;
|
|
139
|
+
/**
|
|
140
|
+
* Flush all pending logs and stop background tasks.
|
|
141
|
+
* Call this during application shutdown.
|
|
142
|
+
*/
|
|
41
143
|
declare function shutdown(apiKey?: string): Promise<void>;
|
|
42
144
|
|
|
43
|
-
/** Per-million-token pricing: { input, output } */
|
|
44
145
|
interface ModelPricing {
|
|
45
146
|
input: number;
|
|
46
147
|
output: number;
|
|
47
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Calculate the cost of a single API request.
|
|
151
|
+
* Returns cost in dollars.
|
|
152
|
+
*/
|
|
48
153
|
declare function calculateCost(model: string, inputTokens: number, outputTokens: number): number;
|
|
154
|
+
/**
|
|
155
|
+
* Register a custom model with pricing at runtime.
|
|
156
|
+
* Useful for new models not yet in the built-in table.
|
|
157
|
+
*/
|
|
49
158
|
declare function registerModel(model: string, pricing: ModelPricing, fallback?: string): void;
|
|
159
|
+
/**
|
|
160
|
+
* Check if a model is known to the pricing table.
|
|
161
|
+
*/
|
|
50
162
|
declare function isKnownModel(model: string): boolean;
|
|
163
|
+
/**
|
|
164
|
+
* Get pricing for a model. Returns null if unknown.
|
|
165
|
+
*/
|
|
51
166
|
declare function getModelPricing(model: string): ModelPricing | null;
|
|
52
167
|
|
|
53
|
-
export { type CaplyrConfig, type
|
|
168
|
+
export { type BudgetStatus, type CaplyrBlockedError, type CaplyrConfig, type CaplyrMode, type CaplyrState, type EnforcementEvent, type ProtectionStatus, type Provider, type RequestLog, calculateCost, getModelPricing, getState, getStatus, isKnownModel, protect, registerModel, shutdown };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,53 +1,168 @@
|
|
|
1
|
+
/** Protection status of the SDK connection */
|
|
2
|
+
type ProtectionStatus = "ACTIVE" | "DEGRADED" | "OFF";
|
|
3
|
+
/** Supported AI providers */
|
|
4
|
+
type Provider = "anthropic" | "openai";
|
|
5
|
+
/** Operating mode for the SDK */
|
|
6
|
+
type CaplyrMode = "cost_protect" | "alert_only" | "kill_switch";
|
|
7
|
+
/** Configuration for the protect() function */
|
|
1
8
|
interface CaplyrConfig {
|
|
9
|
+
/** Your Caplyr project API key */
|
|
2
10
|
apiKey: string;
|
|
3
|
-
|
|
4
|
-
/** Budget limits. Enforcement is server-side, based on project settings tied to your API key. */
|
|
5
|
-
budget?: {
|
|
6
|
-
daily?: number;
|
|
7
|
-
monthly?: number;
|
|
8
|
-
};
|
|
9
|
-
downgradeThreshold?: number;
|
|
10
|
-
fallback?: string;
|
|
11
|
-
/** API endpoint for heartbeat and log ingestion (default: https://caplyr.com) */
|
|
11
|
+
/** Caplyr backend URL (defaults to https://api.caplyr.com) */
|
|
12
12
|
endpoint?: string;
|
|
13
|
-
/**
|
|
14
|
-
|
|
13
|
+
/** Operating mode (defaults to "alert_only" for trust-building) */
|
|
14
|
+
mode?: CaplyrMode;
|
|
15
|
+
/** Monthly budget cap in dollars */
|
|
16
|
+
budget?: number;
|
|
17
|
+
/** Daily budget cap in dollars */
|
|
18
|
+
dailyBudget?: number;
|
|
19
|
+
/** Fallback model when budget is approached/exceeded */
|
|
20
|
+
fallback?: string;
|
|
21
|
+
/** Budget threshold (0-1) at which auto-downgrade activates (default: 0.8) */
|
|
22
|
+
downgradeThreshold?: number;
|
|
23
|
+
/** Custom endpoint tag for attribution */
|
|
15
24
|
endpoint_tag?: string;
|
|
25
|
+
/** Batch size before flushing logs (default: 10) */
|
|
16
26
|
batchSize?: number;
|
|
27
|
+
/** Max interval in ms between log flushes (default: 30000) */
|
|
17
28
|
flushInterval?: number;
|
|
29
|
+
/** Heartbeat interval in ms (default: 60000) */
|
|
18
30
|
heartbeatInterval?: number;
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
/** Called when protection status changes */
|
|
32
|
+
onStatusChange?: (status: ProtectionStatus) => void;
|
|
33
|
+
/** Called when an enforcement event occurs */
|
|
34
|
+
onEnforcement?: (event: EnforcementEvent) => void;
|
|
35
|
+
/** Called when an error occurs in the SDK (non-blocking) */
|
|
36
|
+
onError?: (error: Error) => void;
|
|
37
|
+
}
|
|
38
|
+
/** Metadata captured for every AI API call */
|
|
39
|
+
interface RequestLog {
|
|
40
|
+
/** Unique request ID */
|
|
41
|
+
id: string;
|
|
42
|
+
/** Timestamp of the request */
|
|
43
|
+
timestamp: number;
|
|
44
|
+
/** Provider: "anthropic" | "openai" */
|
|
45
|
+
provider: Provider;
|
|
46
|
+
/** Model used (e.g., "claude-sonnet-4-20250514") */
|
|
47
|
+
model: string;
|
|
48
|
+
/** Input tokens consumed */
|
|
49
|
+
input_tokens: number;
|
|
50
|
+
/** Output tokens consumed */
|
|
51
|
+
output_tokens: number;
|
|
52
|
+
/** Calculated cost in dollars */
|
|
53
|
+
cost: number;
|
|
54
|
+
/** Request latency in milliseconds */
|
|
55
|
+
latency_ms: number;
|
|
56
|
+
/** Endpoint tag for attribution */
|
|
57
|
+
endpoint_tag?: string;
|
|
58
|
+
/** Whether this request was auto-downgraded */
|
|
59
|
+
downgraded: boolean;
|
|
60
|
+
/** Original model if downgraded */
|
|
61
|
+
original_model?: string;
|
|
62
|
+
/** Whether this request was blocked */
|
|
63
|
+
blocked: boolean;
|
|
64
|
+
/** Reason for block/downgrade if applicable */
|
|
65
|
+
enforcement_reason?: string;
|
|
21
66
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
67
|
+
/** Enforcement event emitted when guardrails activate */
|
|
68
|
+
interface EnforcementEvent {
|
|
69
|
+
type: "downgrade" | "block" | "kill_switch";
|
|
70
|
+
timestamp: number;
|
|
71
|
+
reason: string;
|
|
72
|
+
original_model?: string;
|
|
73
|
+
fallback_model?: string;
|
|
74
|
+
budget_used: number;
|
|
75
|
+
budget_limit: number;
|
|
76
|
+
estimated_savings: number;
|
|
28
77
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
78
|
+
/** Budget status returned from the backend */
|
|
79
|
+
interface BudgetStatus {
|
|
80
|
+
daily_used: number;
|
|
81
|
+
daily_limit: number | null;
|
|
82
|
+
monthly_used: number;
|
|
83
|
+
monthly_limit: number | null;
|
|
84
|
+
status: ProtectionStatus;
|
|
85
|
+
kill_switch_active: boolean;
|
|
86
|
+
}
|
|
87
|
+
/** Structured error returned when a request is blocked */
|
|
88
|
+
interface CaplyrBlockedError {
|
|
89
|
+
code: "BUDGET_EXCEEDED" | "KILL_SWITCH_ACTIVE" | "RATE_LIMITED";
|
|
90
|
+
message: string;
|
|
91
|
+
budget_used: number;
|
|
92
|
+
budget_limit: number;
|
|
93
|
+
retry_after?: string;
|
|
94
|
+
dashboard_url: string;
|
|
95
|
+
}
|
|
96
|
+
/** Internal state of the SDK */
|
|
97
|
+
interface CaplyrState {
|
|
98
|
+
status: ProtectionStatus;
|
|
99
|
+
mode: CaplyrMode;
|
|
34
100
|
budget_daily_used: number;
|
|
35
101
|
budget_monthly_used: number;
|
|
36
102
|
kill_switch_active: boolean;
|
|
37
|
-
last_heartbeat: number
|
|
103
|
+
last_heartbeat: number;
|
|
38
104
|
request_count: number;
|
|
39
105
|
total_cost: number;
|
|
40
|
-
|
|
106
|
+
total_savings: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Wrap an AI provider client with Caplyr cost control.
|
|
111
|
+
*
|
|
112
|
+
* Returns a proxy that is type-compatible with the original client.
|
|
113
|
+
* All existing code works unchanged — Caplyr is invisible to callers.
|
|
114
|
+
*
|
|
115
|
+
* @param client - An Anthropic or OpenAI client instance
|
|
116
|
+
* @param config - Caplyr configuration
|
|
117
|
+
* @returns A proxied client with cost control applied
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* import Anthropic from "@anthropic-ai/sdk"
|
|
122
|
+
* import { protect } from "caplyr"
|
|
123
|
+
*
|
|
124
|
+
* const client = protect(new Anthropic(), {
|
|
125
|
+
* apiKey: "caplyr_...",
|
|
126
|
+
* budget: 500,
|
|
127
|
+
* })
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
declare function protect<T>(client: T, config: CaplyrConfig): T;
|
|
131
|
+
/**
|
|
132
|
+
* Get the current protection status for a given API key.
|
|
133
|
+
*/
|
|
134
|
+
declare function getStatus(apiKey: string): ProtectionStatus;
|
|
135
|
+
/**
|
|
136
|
+
* Get the full SDK state for a given API key.
|
|
137
|
+
*/
|
|
138
|
+
declare function getState(apiKey: string): CaplyrState | null;
|
|
139
|
+
/**
|
|
140
|
+
* Flush all pending logs and stop background tasks.
|
|
141
|
+
* Call this during application shutdown.
|
|
142
|
+
*/
|
|
41
143
|
declare function shutdown(apiKey?: string): Promise<void>;
|
|
42
144
|
|
|
43
|
-
/** Per-million-token pricing: { input, output } */
|
|
44
145
|
interface ModelPricing {
|
|
45
146
|
input: number;
|
|
46
147
|
output: number;
|
|
47
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Calculate the cost of a single API request.
|
|
151
|
+
* Returns cost in dollars.
|
|
152
|
+
*/
|
|
48
153
|
declare function calculateCost(model: string, inputTokens: number, outputTokens: number): number;
|
|
154
|
+
/**
|
|
155
|
+
* Register a custom model with pricing at runtime.
|
|
156
|
+
* Useful for new models not yet in the built-in table.
|
|
157
|
+
*/
|
|
49
158
|
declare function registerModel(model: string, pricing: ModelPricing, fallback?: string): void;
|
|
159
|
+
/**
|
|
160
|
+
* Check if a model is known to the pricing table.
|
|
161
|
+
*/
|
|
50
162
|
declare function isKnownModel(model: string): boolean;
|
|
163
|
+
/**
|
|
164
|
+
* Get pricing for a model. Returns null if unknown.
|
|
165
|
+
*/
|
|
51
166
|
declare function getModelPricing(model: string): ModelPricing | null;
|
|
52
167
|
|
|
53
|
-
export { type CaplyrConfig, type
|
|
168
|
+
export { type BudgetStatus, type CaplyrBlockedError, type CaplyrConfig, type CaplyrMode, type CaplyrState, type EnforcementEvent, type ProtectionStatus, type Provider, type RequestLog, calculateCost, getModelPricing, getState, getStatus, isKnownModel, protect, registerModel, shutdown };
|