@careob/llm-gateway 1.0.0 → 1.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/README.md +166 -0
- package/package.json +11 -2
package/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# @careob/llm-gateway
|
|
2
|
+
|
|
3
|
+
Lightweight LLM gateway for Node.js with multi-key rotation, rate-limit handling, provider failover, and spend tracking.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **11+ providers** — OpenAI, Anthropic, Gemini, DeepSeek, Groq, Mistral, Together, Qwen, Zhipu, Moonshot, Yi
|
|
8
|
+
- **Key rotation** — round-robin across multiple API keys per provider
|
|
9
|
+
- **Rate-limit handling** — automatic cooldown and retry on 429s
|
|
10
|
+
- **Provider failover** — falls back to alternate providers when one is exhausted
|
|
11
|
+
- **Spend tracking** — per-request cost estimation and usage logging
|
|
12
|
+
- **Streaming** — SSE streaming support for OpenAI-compatible providers
|
|
13
|
+
- **Express middleware** — drop-in proxy for Express apps
|
|
14
|
+
- **Auto-discovery** — detects API keys from environment variables
|
|
15
|
+
- **Zero dependencies** — only uses `express` as an optional peer dependency
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @careob/llm-gateway
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { LLMGateway } from '@careob/llm-gateway';
|
|
27
|
+
|
|
28
|
+
const gateway = new LLMGateway({
|
|
29
|
+
keys: [
|
|
30
|
+
'sk-proj-your-openai-key',
|
|
31
|
+
{ key: 'sk-ant-your-anthropic-key', provider: 'anthropic' },
|
|
32
|
+
],
|
|
33
|
+
defaultModel: 'gpt-4o',
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const response = await gateway.chat({
|
|
37
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
console.log(response.choices[0].message.content);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Auto-discover keys from environment
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Reads OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, etc.
|
|
47
|
+
const gateway = LLMGateway.fromEnv({ defaultModel: 'gpt-4o' });
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Multi-Key Rotation
|
|
51
|
+
|
|
52
|
+
Pass multiple keys for the same provider to distribute load:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
const gateway = new LLMGateway({
|
|
56
|
+
keys: [
|
|
57
|
+
{ key: 'sk-proj-key-1', provider: 'openai', label: 'prod-1' },
|
|
58
|
+
{ key: 'sk-proj-key-2', provider: 'openai', label: 'prod-2' },
|
|
59
|
+
{ key: 'sk-proj-key-3', provider: 'openai', label: 'prod-3' },
|
|
60
|
+
],
|
|
61
|
+
defaultModel: 'gpt-4o',
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Keys are rotated round-robin. When a key hits a 429, it's automatically cooled down and the next key is used.
|
|
66
|
+
|
|
67
|
+
## Streaming
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
for await (const chunk of gateway.chatStream({
|
|
71
|
+
model: 'gpt-4o',
|
|
72
|
+
messages: [{ role: 'user', content: 'Write a poem' }],
|
|
73
|
+
})) {
|
|
74
|
+
process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Express Proxy
|
|
79
|
+
|
|
80
|
+
Mount the gateway as an API endpoint in your Express app:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import express from 'express';
|
|
84
|
+
import { LLMGateway, createExpressProxy } from '@careob/llm-gateway';
|
|
85
|
+
|
|
86
|
+
const app = express();
|
|
87
|
+
app.use(express.json());
|
|
88
|
+
|
|
89
|
+
const gateway = LLMGateway.fromEnv({ defaultModel: 'gpt-4o' });
|
|
90
|
+
const proxy = createExpressProxy(gateway, {
|
|
91
|
+
authorize: (req) => req.headers['x-api-key'] === 'your-secret',
|
|
92
|
+
extractMetadata: (req) => ({ userId: req.headers['x-user-id'] as string }),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
app.post('/v1/chat/completions', proxy.chatCompletions);
|
|
96
|
+
app.get('/v1/health', proxy.health);
|
|
97
|
+
|
|
98
|
+
app.listen(3000);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Spend Tracking
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
const gateway = new LLMGateway({
|
|
105
|
+
keys: ['sk-proj-...'],
|
|
106
|
+
defaultModel: 'gpt-4o',
|
|
107
|
+
onUsage: (log) => {
|
|
108
|
+
console.log(`${log.model} | ${log.totalTokens} tokens | $${log.estimatedCostUsd.toFixed(6)}`);
|
|
109
|
+
// Save to your database, send to analytics, etc.
|
|
110
|
+
},
|
|
111
|
+
onAllKeysExhausted: (provider) => {
|
|
112
|
+
console.warn(`All ${provider} keys exhausted!`);
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Configuration
|
|
118
|
+
|
|
119
|
+
| Option | Default | Description |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `keys` | *required* | Array of API key strings or `KeyInput` objects |
|
|
122
|
+
| `defaultModel` | — | Model to use when not specified in request |
|
|
123
|
+
| `maxRetries` | `3` | Retries across keys before failing |
|
|
124
|
+
| `cooldownMs` | `60000` | Cooldown duration for rate-limited keys (ms) |
|
|
125
|
+
| `timeoutMs` | `30000` | Request timeout (ms) |
|
|
126
|
+
| `onUsage` | — | Callback for usage/spend logging |
|
|
127
|
+
| `onAllKeysExhausted` | — | Callback when all keys for a provider are exhausted |
|
|
128
|
+
|
|
129
|
+
### KeyInput
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
{
|
|
133
|
+
key: string;
|
|
134
|
+
provider?: string; // Auto-detected from key prefix if omitted
|
|
135
|
+
rpm?: number; // Requests per minute limit
|
|
136
|
+
tpm?: number; // Tokens per minute limit
|
|
137
|
+
label?: string; // Human-readable label (e.g. "prod-key-1")
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Supported Providers
|
|
142
|
+
|
|
143
|
+
| Provider | Format | Models |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| OpenAI | openai | gpt-4o, gpt-4o-mini, o1, o3-mini, o4-mini, ... |
|
|
146
|
+
| Anthropic | anthropic | claude-opus-4, claude-sonnet-4, claude-haiku-3.5 |
|
|
147
|
+
| Google Gemini | gemini | gemini-2.5-pro, gemini-2.5-flash, ... |
|
|
148
|
+
| DeepSeek | openai | deepseek-chat, deepseek-coder, deepseek-reasoner |
|
|
149
|
+
| Groq | openai | llama-3.3-70b, mixtral-8x7b, ... |
|
|
150
|
+
| Mistral | openai | mistral-large, mistral-small, codestral |
|
|
151
|
+
| Together AI | openai | Llama-3.3-70B, DeepSeek-R1, ... |
|
|
152
|
+
| Qwen | openai | qwen-turbo, qwen-plus, qwen-max |
|
|
153
|
+
| Zhipu | openai | glm-4, glm-4-flash, glm-4-plus |
|
|
154
|
+
| Moonshot | openai | moonshot-v1-8k/32k/128k |
|
|
155
|
+
| Yi | openai | yi-large, yi-medium, yi-spark |
|
|
156
|
+
|
|
157
|
+
## Health Check
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const stats = gateway.getStats();
|
|
161
|
+
// [{ provider: 'openai', label: 'prod-1', healthy: true, requestsThisMinute: 12, ... }]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@careob/llm-gateway",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Lightweight LLM gateway with multi-key rotation, rate-limit handling, provider failover, and spend tracking for Node.js/Express apps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,5 +30,14 @@
|
|
|
30
30
|
},
|
|
31
31
|
"files": ["dist", "README.md"],
|
|
32
32
|
"keywords": ["llm", "gateway", "openai", "anthropic", "key-rotation", "rate-limit", "express"],
|
|
33
|
-
"license": "MIT"
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"author": "Careob <gaurav@careob.com>",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/careob/llm-gateway.git"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/careob/llm-gateway#readme",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/careob/llm-gateway/issues"
|
|
42
|
+
}
|
|
34
43
|
}
|