hydra-aidirector 1.4.2 → 1.6.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 +304 -302
- package/dist/index.d.mts +78 -25
- package/dist/index.d.ts +78 -25
- package/dist/index.js +4 -4
- package/dist/index.mjs +4 -4
- package/package.json +88 -88
package/README.md
CHANGED
|
@@ -1,302 +1,304 @@
|
|
|
1
|
-
# hydra-aidirector
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
- `
|
|
284
|
-
- `
|
|
285
|
-
- `
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
1
|
+
# hydra-aidirector
|
|
2
|
+
|
|
3
|
+
The official TypeScript SDK for [Hydra](https://hydrai.dev).
|
|
4
|
+
|
|
5
|
+
Hydra gives your app one stable AI gateway instead of a pile of provider glue. You send one request. Hydra handles routing, failover, cache behavior, JSON recovery, and operational visibility behind the same API.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add hydra-aidirector
|
|
11
|
+
# or
|
|
12
|
+
npm install hydra-aidirector
|
|
13
|
+
# or
|
|
14
|
+
pnpm add hydra-aidirector
|
|
15
|
+
# or
|
|
16
|
+
yarn add hydra-aidirector
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { Hydra } from 'hydra-aidirector';
|
|
23
|
+
|
|
24
|
+
const client = new Hydra({
|
|
25
|
+
secretKey: process.env.HYDRA_SECRET_KEY!, // hyd_sk_...
|
|
26
|
+
baseUrl: 'https://your-hydra-instance.com',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const result = await client.generate({
|
|
30
|
+
chainId: 'support-replies',
|
|
31
|
+
prompt: 'Write 3 concise onboarding emails as JSON',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (result.success) {
|
|
35
|
+
console.log(result.data.valid);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## What You Get
|
|
40
|
+
|
|
41
|
+
- Automatic failover across the models in your chain.
|
|
42
|
+
- JSON extraction and repair when providers return noisy output.
|
|
43
|
+
- User-safe caching with request-level cache controls.
|
|
44
|
+
- Streaming for long responses.
|
|
45
|
+
- Batch generation for parallel prompt execution.
|
|
46
|
+
- Usage, health, and webhook management from the same client.
|
|
47
|
+
|
|
48
|
+
## Generation Modes
|
|
49
|
+
|
|
50
|
+
Hydra uses the optimized 3-step flow by default for simple requests. That keeps the fast path cheap and responsive.
|
|
51
|
+
|
|
52
|
+
When you ask for features that require the full server pipeline, the SDK automatically falls back to the legacy endpoint. That includes:
|
|
53
|
+
|
|
54
|
+
- `schema`
|
|
55
|
+
- `noCache`
|
|
56
|
+
- `cacheScope`
|
|
57
|
+
- `cacheQuality`
|
|
58
|
+
- `strictJson`
|
|
59
|
+
- `maxRetries`
|
|
60
|
+
|
|
61
|
+
You can also force the legacy endpoint yourself:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
await client.generate({
|
|
65
|
+
chainId: 'support-replies',
|
|
66
|
+
prompt: 'Return a fresh answer',
|
|
67
|
+
useOptimized: false,
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Structured Output
|
|
72
|
+
|
|
73
|
+
Use `schema` when you want validated JSON back:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const result = await client.generate({
|
|
77
|
+
chainId: 'invoice-parser',
|
|
78
|
+
prompt: 'Extract invoice fields',
|
|
79
|
+
schema: {
|
|
80
|
+
invoiceNumber: 'string',
|
|
81
|
+
amount: 'number',
|
|
82
|
+
currency: 'string',
|
|
83
|
+
},
|
|
84
|
+
strictJson: true,
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If the provider returns malformed JSON, Hydra will still try to recover it before the request fails.
|
|
89
|
+
|
|
90
|
+
## Cache Control
|
|
91
|
+
|
|
92
|
+
Use request-level cache controls when the prompt should behave differently from the default path:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
await client.generate({
|
|
96
|
+
chainId: 'account-summary',
|
|
97
|
+
prompt: 'Summarize this customer account',
|
|
98
|
+
cacheScope: 'user',
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await client.generate({
|
|
102
|
+
chainId: 'pricing-faq',
|
|
103
|
+
prompt: 'Return the current pricing summary',
|
|
104
|
+
cacheScope: 'global',
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
await client.generate({
|
|
108
|
+
chainId: 'one-off',
|
|
109
|
+
prompt: 'Generate a fresh variant',
|
|
110
|
+
noCache: true,
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
You can also tune cache matching:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
await client.generate({
|
|
118
|
+
chainId: 'reporting',
|
|
119
|
+
prompt: 'Generate the weekly report',
|
|
120
|
+
cacheQuality: 'HIGH',
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Streaming
|
|
125
|
+
|
|
126
|
+
Stream parsed objects as they arrive:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
await client.generateStream(
|
|
130
|
+
{
|
|
131
|
+
chainId: 'catalog-generator',
|
|
132
|
+
prompt: 'Generate 50 product blurbs as JSON',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
onObject: (object, index) => {
|
|
136
|
+
console.log(index, object);
|
|
137
|
+
},
|
|
138
|
+
onComplete: (result) => {
|
|
139
|
+
console.log(result.objectCount);
|
|
140
|
+
},
|
|
141
|
+
onError: (error) => {
|
|
142
|
+
console.error(error);
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Batch Generation
|
|
149
|
+
|
|
150
|
+
Run multiple prompts in one call:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
const batch = await client.generateBatch('catalog-generator', [
|
|
154
|
+
{ id: 'a', prompt: 'Describe product A' },
|
|
155
|
+
{ id: 'b', prompt: 'Describe product B' },
|
|
156
|
+
{ id: 'c', prompt: 'Describe product C' },
|
|
157
|
+
]);
|
|
158
|
+
|
|
159
|
+
console.log(batch.summary);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Files
|
|
163
|
+
|
|
164
|
+
Send file attachments as base64:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import fs from 'node:fs';
|
|
168
|
+
|
|
169
|
+
const file = fs.readFileSync('report.pdf');
|
|
170
|
+
|
|
171
|
+
const result = await client.generate({
|
|
172
|
+
chainId: 'document-analysis',
|
|
173
|
+
prompt: 'Summarize this report',
|
|
174
|
+
files: [
|
|
175
|
+
{
|
|
176
|
+
data: file.toString('base64'),
|
|
177
|
+
filename: 'report.pdf',
|
|
178
|
+
mimeType: 'application/pdf',
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Usage and Health
|
|
185
|
+
|
|
186
|
+
Get normalized usage metrics:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
const usage = await client.getUsage({
|
|
190
|
+
startDate: new Date('2026-03-01T00:00:00.000Z'),
|
|
191
|
+
endDate: new Date('2026-04-01T00:00:00.000Z'),
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
console.log(usage.totalRequests);
|
|
195
|
+
console.log(usage.cachedRequests);
|
|
196
|
+
console.log(usage.byModelList);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Basic health:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
const health = await client.health();
|
|
203
|
+
console.log(health.ok, health.latencyMs);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Detailed health requires an admin key:
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
const detailed = await client.healthDetailed();
|
|
210
|
+
console.log(detailed.status);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Webhooks
|
|
214
|
+
|
|
215
|
+
Register, list, update, and remove webhooks from the SDK:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
await client.registerWebhook({
|
|
219
|
+
requestId: 'req_123',
|
|
220
|
+
url: 'https://example.com/webhooks/hydra',
|
|
221
|
+
secret: 'super-secret-webhook-key',
|
|
222
|
+
retryCount: 3,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const webhooks = await client.listWebhooks();
|
|
226
|
+
|
|
227
|
+
await client.updateWebhook(webhooks[0].id, {
|
|
228
|
+
retryCount: 5,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
await client.unregisterWebhook(webhooks[0].id);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Cancellation
|
|
235
|
+
|
|
236
|
+
Cancel long-running requests with `AbortController`:
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
const controller = new AbortController();
|
|
240
|
+
|
|
241
|
+
setTimeout(() => controller.abort(), 5000);
|
|
242
|
+
|
|
243
|
+
await client.generate({
|
|
244
|
+
chainId: 'long-job',
|
|
245
|
+
prompt: 'Generate a long report',
|
|
246
|
+
signal: controller.signal,
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Error Handling
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
import {
|
|
254
|
+
AuthenticationError,
|
|
255
|
+
QuotaExceededError,
|
|
256
|
+
RateLimitError,
|
|
257
|
+
TimeoutError,
|
|
258
|
+
isRetryableError,
|
|
259
|
+
} from 'hydra-aidirector';
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
await client.generate({
|
|
263
|
+
chainId: 'support-replies',
|
|
264
|
+
prompt: 'Write a response',
|
|
265
|
+
});
|
|
266
|
+
} catch (error) {
|
|
267
|
+
if (error instanceof AuthenticationError) {
|
|
268
|
+
console.error('The Hydra secret key is invalid.');
|
|
269
|
+
} else if (error instanceof QuotaExceededError) {
|
|
270
|
+
console.error(error.tier, error.used, error.limit);
|
|
271
|
+
} else if (error instanceof RateLimitError) {
|
|
272
|
+
console.error(error.retryAfterMs);
|
|
273
|
+
} else if (error instanceof TimeoutError) {
|
|
274
|
+
console.error(error.timeoutMs);
|
|
275
|
+
} else if (isRetryableError(error)) {
|
|
276
|
+
console.error('Safe to retry.');
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## API Surface
|
|
282
|
+
|
|
283
|
+
- `generate(options)`
|
|
284
|
+
- `generateStream(options, callbacks)`
|
|
285
|
+
- `generateBatch(chainId, items, options?)`
|
|
286
|
+
- `listModels()`
|
|
287
|
+
- `listChains()`
|
|
288
|
+
- `getUsage(options?)`
|
|
289
|
+
- `health()`
|
|
290
|
+
- `healthDetailed()`
|
|
291
|
+
- `registerWebhook(config)`
|
|
292
|
+
- `listWebhooks()`
|
|
293
|
+
- `updateWebhook(id, updates)`
|
|
294
|
+
- `unregisterWebhook(id)`
|
|
295
|
+
- `withConfig(overrides)`
|
|
296
|
+
|
|
297
|
+
## Requirements
|
|
298
|
+
|
|
299
|
+
- Node.js 18+
|
|
300
|
+
- TypeScript 5+ for typed projects
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
MIT
|