@hebo-ai/gateway 0.2.1 → 0.3.0-rc.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 +133 -16
- package/package.json +16 -7
- package/src/config.ts +43 -7
- package/src/endpoints/chat-completions/converters.test.ts +52 -1
- package/src/endpoints/chat-completions/converters.ts +130 -111
- package/src/endpoints/chat-completions/handler.test.ts +12 -12
- package/src/endpoints/chat-completions/handler.ts +76 -63
- package/src/endpoints/chat-completions/schema.ts +2 -0
- package/src/endpoints/embeddings/converters.ts +2 -5
- package/src/endpoints/embeddings/handler.test.ts +9 -9
- package/src/endpoints/embeddings/handler.ts +47 -48
- package/src/endpoints/models/converters.ts +3 -9
- package/src/endpoints/models/handler.test.ts +2 -2
- package/src/endpoints/models/handler.ts +10 -10
- package/src/errors/ai-sdk.ts +99 -0
- package/src/errors/gateway.ts +15 -0
- package/src/errors/openai.ts +35 -0
- package/src/errors/utils.ts +51 -0
- package/src/gateway.ts +19 -4
- package/src/index.ts +4 -0
- package/src/lifecycle.ts +40 -49
- package/src/logger/default.ts +81 -0
- package/src/logger/index.ts +43 -0
- package/src/middleware/common.test.ts +215 -0
- package/src/middleware/common.ts +125 -36
- package/src/middleware/matcher.ts +15 -2
- package/src/middleware/utils.ts +2 -1
- package/src/models/anthropic/middleware.ts +4 -1
- package/src/models/google/middleware.test.ts +41 -0
- package/src/models/google/middleware.ts +17 -14
- package/src/models/openai/middleware.test.ts +36 -4
- package/src/models/openai/middleware.ts +25 -3
- package/src/providers/registry.test.ts +3 -5
- package/src/providers/registry.ts +30 -7
- package/src/telemetry/access-log.ts +68 -0
- package/src/telemetry/stream.ts +77 -0
- package/src/telemetry/utils.ts +46 -0
- package/src/types.ts +33 -14
- package/src/utils/env.ts +7 -0
- package/src/utils/request.ts +62 -0
- package/src/utils/response.ts +45 -5
- package/dist/config.d.ts +0 -2
- package/dist/config.js +0 -29
- package/dist/endpoints/chat-completions/converters.d.ts +0 -36
- package/dist/endpoints/chat-completions/converters.js +0 -368
- package/dist/endpoints/chat-completions/handler.d.ts +0 -2
- package/dist/endpoints/chat-completions/handler.js +0 -96
- package/dist/endpoints/chat-completions/index.d.ts +0 -3
- package/dist/endpoints/chat-completions/index.js +0 -3
- package/dist/endpoints/chat-completions/schema.d.ts +0 -456
- package/dist/endpoints/chat-completions/schema.js +0 -190
- package/dist/endpoints/embeddings/converters.d.ts +0 -10
- package/dist/endpoints/embeddings/converters.js +0 -31
- package/dist/endpoints/embeddings/handler.d.ts +0 -2
- package/dist/endpoints/embeddings/handler.js +0 -83
- package/dist/endpoints/embeddings/index.d.ts +0 -3
- package/dist/endpoints/embeddings/index.js +0 -3
- package/dist/endpoints/embeddings/schema.d.ts +0 -38
- package/dist/endpoints/embeddings/schema.js +0 -26
- package/dist/endpoints/index.d.ts +0 -1
- package/dist/endpoints/index.js +0 -1
- package/dist/endpoints/models/converters.d.ts +0 -6
- package/dist/endpoints/models/converters.js +0 -42
- package/dist/endpoints/models/handler.d.ts +0 -2
- package/dist/endpoints/models/handler.js +0 -29
- package/dist/endpoints/models/index.d.ts +0 -3
- package/dist/endpoints/models/index.js +0 -3
- package/dist/endpoints/models/schema.d.ts +0 -42
- package/dist/endpoints/models/schema.js +0 -31
- package/dist/gateway.d.ts +0 -9
- package/dist/gateway.js +0 -25
- package/dist/index.d.ts +0 -11
- package/dist/index.js +0 -10
- package/dist/lifecycle.d.ts +0 -2
- package/dist/lifecycle.js +0 -49
- package/dist/middleware/common.d.ts +0 -4
- package/dist/middleware/common.js +0 -50
- package/dist/middleware/matcher.d.ts +0 -19
- package/dist/middleware/matcher.js +0 -82
- package/dist/middleware/utils.d.ts +0 -2
- package/dist/middleware/utils.js +0 -25
- package/dist/models/amazon/index.d.ts +0 -2
- package/dist/models/amazon/index.js +0 -2
- package/dist/models/amazon/middleware.d.ts +0 -3
- package/dist/models/amazon/middleware.js +0 -64
- package/dist/models/amazon/presets.d.ts +0 -2390
- package/dist/models/amazon/presets.js +0 -80
- package/dist/models/anthropic/index.d.ts +0 -2
- package/dist/models/anthropic/index.js +0 -2
- package/dist/models/anthropic/middleware.d.ts +0 -2
- package/dist/models/anthropic/middleware.js +0 -46
- package/dist/models/anthropic/presets.d.ts +0 -4106
- package/dist/models/anthropic/presets.js +0 -113
- package/dist/models/catalog.d.ts +0 -4
- package/dist/models/catalog.js +0 -4
- package/dist/models/cohere/index.d.ts +0 -2
- package/dist/models/cohere/index.js +0 -2
- package/dist/models/cohere/middleware.d.ts +0 -3
- package/dist/models/cohere/middleware.js +0 -60
- package/dist/models/cohere/presets.d.ts +0 -2918
- package/dist/models/cohere/presets.js +0 -134
- package/dist/models/google/index.d.ts +0 -2
- package/dist/models/google/index.js +0 -2
- package/dist/models/google/middleware.d.ts +0 -6
- package/dist/models/google/middleware.js +0 -87
- package/dist/models/google/presets.d.ts +0 -2166
- package/dist/models/google/presets.js +0 -76
- package/dist/models/meta/index.d.ts +0 -1
- package/dist/models/meta/index.js +0 -1
- package/dist/models/meta/presets.d.ts +0 -3254
- package/dist/models/meta/presets.js +0 -95
- package/dist/models/openai/index.d.ts +0 -2
- package/dist/models/openai/index.js +0 -2
- package/dist/models/openai/middleware.d.ts +0 -3
- package/dist/models/openai/middleware.js +0 -45
- package/dist/models/openai/presets.d.ts +0 -6252
- package/dist/models/openai/presets.js +0 -206
- package/dist/models/types.d.ts +0 -20
- package/dist/models/types.js +0 -80
- package/dist/models/voyage/index.d.ts +0 -2
- package/dist/models/voyage/index.js +0 -2
- package/dist/models/voyage/middleware.d.ts +0 -2
- package/dist/models/voyage/middleware.js +0 -18
- package/dist/models/voyage/presets.d.ts +0 -3471
- package/dist/models/voyage/presets.js +0 -85
- package/dist/providers/anthropic/canonical.d.ts +0 -3
- package/dist/providers/anthropic/canonical.js +0 -9
- package/dist/providers/anthropic/index.d.ts +0 -1
- package/dist/providers/anthropic/index.js +0 -1
- package/dist/providers/bedrock/canonical.d.ts +0 -17
- package/dist/providers/bedrock/canonical.js +0 -59
- package/dist/providers/bedrock/index.d.ts +0 -1
- package/dist/providers/bedrock/index.js +0 -1
- package/dist/providers/cohere/canonical.d.ts +0 -3
- package/dist/providers/cohere/canonical.js +0 -17
- package/dist/providers/cohere/index.d.ts +0 -1
- package/dist/providers/cohere/index.js +0 -1
- package/dist/providers/groq/canonical.d.ts +0 -3
- package/dist/providers/groq/canonical.js +0 -12
- package/dist/providers/groq/index.d.ts +0 -1
- package/dist/providers/groq/index.js +0 -1
- package/dist/providers/openai/canonical.d.ts +0 -3
- package/dist/providers/openai/canonical.js +0 -8
- package/dist/providers/openai/index.d.ts +0 -1
- package/dist/providers/openai/index.js +0 -1
- package/dist/providers/registry.d.ts +0 -24
- package/dist/providers/registry.js +0 -85
- package/dist/providers/types.d.ts +0 -7
- package/dist/providers/types.js +0 -11
- package/dist/providers/vertex/canonical.d.ts +0 -3
- package/dist/providers/vertex/canonical.js +0 -8
- package/dist/providers/vertex/index.d.ts +0 -1
- package/dist/providers/vertex/index.js +0 -1
- package/dist/providers/voyage/canonical.d.ts +0 -3
- package/dist/providers/voyage/canonical.js +0 -7
- package/dist/providers/voyage/index.d.ts +0 -1
- package/dist/providers/voyage/index.js +0 -1
- package/dist/types.d.ts +0 -132
- package/dist/types.js +0 -1
- package/dist/utils/errors.d.ts +0 -19
- package/dist/utils/errors.js +0 -25
- package/dist/utils/preset.d.ts +0 -9
- package/dist/utils/preset.js +0 -41
- package/dist/utils/response.d.ts +0 -1
- package/dist/utils/response.js +0 -10
- package/src/endpoints/index.ts +0 -1
- package/src/utils/errors.ts +0 -35
package/README.md
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Roll your own AI gateway for full control over models, providers, routing logic, guardrails, observability and more ...
|
|
4
4
|
|
|
5
|
-
## Overview
|
|
5
|
+
## 🐒 Overview
|
|
6
6
|
|
|
7
7
|
Existing AI gateways like OpenRouter, Vercel AI Gateway, LiteLLM, and Portkey work out of the box, but they’re hard to extend once your needs go beyond configuration.
|
|
8
8
|
|
|
9
9
|
Hebo Gateway is an open-source, embeddable AI gateway framework built to live inside your app. It gives you full control over providers, models, routing, and the request lifecycle.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Learn more in our blog post: [Yet Another AI Gateway?](https://hebo.ai/blog/260127-hebo-gateway/) (`https://hebo.ai/blog/260127-hebo-gateway/`)
|
|
12
|
+
|
|
13
|
+
## 🍌 Features
|
|
12
14
|
|
|
13
15
|
- 🌐 OpenAI-compatible /chat/completions, /embeddings & /models endpoints.
|
|
14
16
|
- 🔌 Integrate into your existing Hono, Elysia, Next.js & TanStack apps.
|
|
@@ -18,13 +20,28 @@ Hebo Gateway is an open-source, embeddable AI gateway framework built to live in
|
|
|
18
20
|
- 🪝 Hook system to customize routing, auth, rate limits, and shape responses.
|
|
19
21
|
- 🧰 Low-level OpenAI-compatible schema, converters, and middleware helpers.
|
|
20
22
|
|
|
21
|
-
## Installation
|
|
23
|
+
## 📦 Installation
|
|
22
24
|
|
|
23
25
|
```bash
|
|
24
26
|
bun install @hebo-ai/gateway
|
|
25
27
|
```
|
|
26
28
|
|
|
27
|
-
##
|
|
29
|
+
## ☰ Table of Contents
|
|
30
|
+
|
|
31
|
+
- Quickstart
|
|
32
|
+
- [Setup A Gateway Instance](#setup-a-gateway-instance) | [Mount Route Handlers](#mount-route-handlers) | [Call the Gateway](#call-the-gateway)
|
|
33
|
+
- Configuration Reference
|
|
34
|
+
- [Providers](#providers) | [Models](#models) | [Hooks](#hooks) | [Logger](#logger-settings)
|
|
35
|
+
- Framework Support
|
|
36
|
+
- [ElysiaJS](#elysiajs) | [Hono](#hono) | [Next.js](#nextjs) | [TanStack Start](#tanstack-start)
|
|
37
|
+
- Runtime Support
|
|
38
|
+
- [Vercel Edge](#vercel-edge) | [Cloudflare Workers](#cloudflare-workers) | [Deno Deploy](#deno-deploy) | [AWS Lambda](#aws-lambda)
|
|
39
|
+
- OpenAI Extensions
|
|
40
|
+
- [Reasoning](#reasoning)
|
|
41
|
+
- Advanced Usage
|
|
42
|
+
- [Passing Framework State to Hooks](#passing-framework-state-to-hooks) | [Selective Route Mounting](#selective-route-mounting) | [Low-level Schemas & Converters](#low-level-schemas--converters)
|
|
43
|
+
|
|
44
|
+
## 🚀 Quickstart
|
|
28
45
|
|
|
29
46
|
### Setup A Gateway Instance
|
|
30
47
|
|
|
@@ -113,7 +130,7 @@ const { text } = await generateText({
|
|
|
113
130
|
console.log(text);
|
|
114
131
|
```
|
|
115
132
|
|
|
116
|
-
## Configuration Reference
|
|
133
|
+
## ⚙️ Configuration Reference
|
|
117
134
|
|
|
118
135
|
### Providers
|
|
119
136
|
|
|
@@ -316,25 +333,27 @@ const gw = gateway({
|
|
|
316
333
|
},
|
|
317
334
|
/**
|
|
318
335
|
* Runs after the endpoint handler.
|
|
319
|
-
* @param ctx.
|
|
320
|
-
* @returns
|
|
336
|
+
* @param ctx.result Result object returned by the handler.
|
|
337
|
+
* @returns Modified result, or undefined to keep original.
|
|
321
338
|
*/
|
|
322
|
-
after: async (ctx: {
|
|
339
|
+
after: async (ctx: {
|
|
340
|
+
result: object | ReadableStream<Uint8Array>
|
|
341
|
+
}): Promise<object | ReadableStream<Uint8Array> | void> => {
|
|
323
342
|
// Example Use Cases:
|
|
324
|
-
// - Transform
|
|
325
|
-
// -
|
|
343
|
+
// - Transform result
|
|
344
|
+
// - Result logging
|
|
326
345
|
return undefined;
|
|
327
346
|
},
|
|
328
347
|
},
|
|
329
348
|
});
|
|
330
349
|
```
|
|
331
350
|
|
|
332
|
-
The `ctx` object is **readonly for core fields**. Use return values to override request /
|
|
351
|
+
The `ctx` object is **readonly for core fields**. Use return values to override request / result and to provide modelId / provider instances.
|
|
333
352
|
|
|
334
353
|
> [!TIP]
|
|
335
354
|
> To pass data between hooks, use `ctx.state`. It’s a per-request mutable bag in which you can stash things like auth info, routing decisions, timers, or trace IDs and read them later again in any of the other hooks.
|
|
336
355
|
|
|
337
|
-
## Framework Support
|
|
356
|
+
## 🧩 Framework Support
|
|
338
357
|
|
|
339
358
|
Hebo Gateway exposes **WinterCG-compatible** handlers that integrate with almost any existing framework.
|
|
340
359
|
|
|
@@ -362,7 +381,9 @@ export default new Hono().mount("/v1/gateway/", gw.handler);
|
|
|
362
381
|
console.log(`🐒 Hebo Gateway is running with Hono framework`);
|
|
363
382
|
```
|
|
364
383
|
|
|
365
|
-
### Next.js
|
|
384
|
+
### Next.js
|
|
385
|
+
|
|
386
|
+
#### App Router
|
|
366
387
|
|
|
367
388
|
`app/api/gateway/[...all]/route.ts`
|
|
368
389
|
|
|
@@ -376,7 +397,7 @@ const gw = gateway({
|
|
|
376
397
|
export const POST = gw.handler, GET = gw.handler;
|
|
377
398
|
```
|
|
378
399
|
|
|
379
|
-
|
|
400
|
+
#### Pages Router
|
|
380
401
|
|
|
381
402
|
`pages/api/gateway/[...all].ts`
|
|
382
403
|
|
|
@@ -416,7 +437,69 @@ export const Route = createFileRoute("/api/$")({
|
|
|
416
437
|
});
|
|
417
438
|
```
|
|
418
439
|
|
|
419
|
-
##
|
|
440
|
+
## 🌍 Runtime Support
|
|
441
|
+
|
|
442
|
+
Hebo Gateway also works directly with runtime-level `Request -> Response` handlers.
|
|
443
|
+
|
|
444
|
+
### Vercel Edge
|
|
445
|
+
|
|
446
|
+
`api/gateway.ts`
|
|
447
|
+
|
|
448
|
+
```ts
|
|
449
|
+
export const runtime = "edge";
|
|
450
|
+
|
|
451
|
+
const gw = gateway({
|
|
452
|
+
// ...
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
export default gw.handler;
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Cloudflare Workers
|
|
459
|
+
|
|
460
|
+
`src/index.ts`
|
|
461
|
+
|
|
462
|
+
```ts
|
|
463
|
+
const gw = gateway({
|
|
464
|
+
// ...
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
export default {
|
|
468
|
+
fetch: gw.handler,
|
|
469
|
+
};
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Deno Deploy
|
|
473
|
+
|
|
474
|
+
`main.ts`
|
|
475
|
+
|
|
476
|
+
```ts
|
|
477
|
+
import { serve } from "https://deno.land/std/http/server.ts";
|
|
478
|
+
|
|
479
|
+
const gw = gateway({
|
|
480
|
+
// ...
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
serve((request: Request) => gw.handler(request));
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### AWS Lambda
|
|
487
|
+
|
|
488
|
+
`src/lambda.ts`
|
|
489
|
+
|
|
490
|
+
```ts
|
|
491
|
+
import { awsLambdaEventHandler } from "@hattip/adapter-aws-lambda";
|
|
492
|
+
|
|
493
|
+
const gw = gateway({
|
|
494
|
+
// ...
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
export const handler = awsLambdaEventHandler({
|
|
498
|
+
handler: gw.handler,
|
|
499
|
+
});
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
## 🧠 OpenAI Extensions
|
|
420
503
|
|
|
421
504
|
### Reasoning
|
|
422
505
|
|
|
@@ -449,7 +532,41 @@ Reasoning output is surfaced as extension to the `completion` object.
|
|
|
449
532
|
|
|
450
533
|
Most SDKs handle these fields out-of-the-box.
|
|
451
534
|
|
|
452
|
-
## Advanced Usage
|
|
535
|
+
## 🧪 Advanced Usage
|
|
536
|
+
|
|
537
|
+
### Logger Settings
|
|
538
|
+
|
|
539
|
+
You can configure logging via the `logger` field in the gateway config. By default, the logger uses `console` and sets the level to `debug` in non-production and `info` in production (based on the `NODE_ENV` environment variable).
|
|
540
|
+
|
|
541
|
+
```ts
|
|
542
|
+
import { gateway } from "@hebo-ai/gateway";
|
|
543
|
+
|
|
544
|
+
const gw = gateway({
|
|
545
|
+
// ...
|
|
546
|
+
logger: {
|
|
547
|
+
level: "debug", // "trace" | "debug" | "info" | "warn" | "error" | "silent"
|
|
548
|
+
},
|
|
549
|
+
});
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
If you provide a custom logger, it must implement `trace`, `debug`, `info`, `warn`, and `error` methods.
|
|
553
|
+
For production workloads, we recommend `pino` for better logging performance and lower overhead.
|
|
554
|
+
|
|
555
|
+
Example with **pino**:
|
|
556
|
+
|
|
557
|
+
```ts
|
|
558
|
+
import pino from "pino";
|
|
559
|
+
import { gateway } from "@hebo-ai/gateway";
|
|
560
|
+
|
|
561
|
+
const gw = gateway({
|
|
562
|
+
// ...
|
|
563
|
+
logger: pino(
|
|
564
|
+
{
|
|
565
|
+
level: "info"
|
|
566
|
+
}
|
|
567
|
+
),
|
|
568
|
+
});
|
|
569
|
+
```
|
|
453
570
|
|
|
454
571
|
### Passing Framework State to Hooks
|
|
455
572
|
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hebo-ai/gateway",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.0-rc.1",
|
|
4
|
+
"description": "AI gateway as a framework. For full control over models, routing & lifecycle. OpenAI-compatible /chat/completions, /embeddings & /models.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
7
|
+
"ai-gateway",
|
|
7
8
|
"anthropic",
|
|
8
9
|
"bedrock",
|
|
9
10
|
"elysiajs",
|
|
@@ -11,10 +12,13 @@
|
|
|
11
12
|
"groq",
|
|
12
13
|
"hono",
|
|
13
14
|
"llm",
|
|
15
|
+
"llm-gateway",
|
|
16
|
+
"llmops",
|
|
14
17
|
"nextjs",
|
|
15
18
|
"openai",
|
|
16
19
|
"tanstack-start",
|
|
17
20
|
"vercel-ai-sdk",
|
|
21
|
+
"vertex",
|
|
18
22
|
"voyage"
|
|
19
23
|
],
|
|
20
24
|
"homepage": "https://hebo.ai/gateway",
|
|
@@ -34,8 +38,10 @@
|
|
|
34
38
|
],
|
|
35
39
|
"type": "module",
|
|
36
40
|
"sideEffects": [
|
|
41
|
+
"./dist/logger/index.js",
|
|
37
42
|
"./dist/providers/**/*.js",
|
|
38
43
|
"./dist/models/**/*.js",
|
|
44
|
+
"./src/logger/index.ts",
|
|
39
45
|
"./src/providers/**/*.ts",
|
|
40
46
|
"./src/models/**/*.ts"
|
|
41
47
|
],
|
|
@@ -45,11 +51,6 @@
|
|
|
45
51
|
"import": "./dist/index.js",
|
|
46
52
|
"dev-source": "./src/index.ts"
|
|
47
53
|
},
|
|
48
|
-
"./endpoints": {
|
|
49
|
-
"types": "./dist/endpoints/index.d.ts",
|
|
50
|
-
"import": "./dist/endpoints/index.js",
|
|
51
|
-
"dev-source": "./src/endpoints/index.ts"
|
|
52
|
-
},
|
|
53
54
|
"./endpoints/chat-completions": {
|
|
54
55
|
"types": "./dist/endpoints/chat-completions/index.d.ts",
|
|
55
56
|
"import": "./dist/endpoints/chat-completions/index.js",
|
|
@@ -65,6 +66,11 @@
|
|
|
65
66
|
"import": "./dist/endpoints/models/index.js",
|
|
66
67
|
"dev-source": "./src/endpoints/models/index.ts"
|
|
67
68
|
},
|
|
69
|
+
"./errors/openai": {
|
|
70
|
+
"types": "./dist/errors/openai.d.ts",
|
|
71
|
+
"import": "./dist/errors/openai.js",
|
|
72
|
+
"dev-source": "./src/errors/openai.ts"
|
|
73
|
+
},
|
|
68
74
|
"./middleware/common": {
|
|
69
75
|
"types": "./dist/middleware/common.d.ts",
|
|
70
76
|
"import": "./dist/middleware/common.js",
|
|
@@ -149,7 +155,9 @@
|
|
|
149
155
|
},
|
|
150
156
|
"dependencies": {
|
|
151
157
|
"@ai-sdk/provider": "^3.0.7",
|
|
158
|
+
"@ai-sdk/provider-utils": "^4.0.13",
|
|
152
159
|
"ai": "^6.0.67",
|
|
160
|
+
"serialize-error": "^13.0.1",
|
|
153
161
|
"zod": "^4.3.6"
|
|
154
162
|
},
|
|
155
163
|
"devDependencies": {
|
|
@@ -172,6 +180,7 @@
|
|
|
172
180
|
"next": "^16.1.6",
|
|
173
181
|
"oxfmt": "^0.24.0",
|
|
174
182
|
"oxlint": "^1.42.0",
|
|
183
|
+
"pino": "^10.3.0",
|
|
175
184
|
"typescript": "^5.9.3",
|
|
176
185
|
"vite": "^7.3.1",
|
|
177
186
|
"vite-tsconfig-paths": "^6.0.5",
|
package/src/config.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isLogger, logger, setLoggerInstance } from "./logger";
|
|
2
|
+
import { createDefaultLogger } from "./logger/default";
|
|
1
3
|
import { kParsed, type GatewayConfig, type GatewayConfigParsed } from "./types";
|
|
2
4
|
|
|
3
5
|
export const parseConfig = (config: GatewayConfig): GatewayConfigParsed => {
|
|
@@ -5,30 +7,64 @@ export const parseConfig = (config: GatewayConfig): GatewayConfigParsed => {
|
|
|
5
7
|
if (kParsed in config) return config as GatewayConfigParsed;
|
|
6
8
|
|
|
7
9
|
const providers = config.providers ?? {};
|
|
10
|
+
const parsedProviders = {} as typeof providers;
|
|
8
11
|
const models = config.models ?? {};
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
// Set the global logger instance
|
|
14
|
+
if (config.logger === undefined) {
|
|
15
|
+
setLoggerInstance(createDefaultLogger({}));
|
|
16
|
+
} else if (config.logger !== null) {
|
|
17
|
+
setLoggerInstance(isLogger(config.logger) ? config.logger : createDefaultLogger(config.logger));
|
|
18
|
+
|
|
19
|
+
logger.info(
|
|
20
|
+
isLogger(config.logger)
|
|
21
|
+
? `[logger] custom logger configured`
|
|
22
|
+
: `[logger] logger configured: level=${config.logger.level}`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Strip providers that are not configured
|
|
27
|
+
for (const id in providers) {
|
|
28
|
+
const provider = providers[id];
|
|
29
|
+
if (provider === undefined) {
|
|
30
|
+
logger.warn(`[config] ${id} provider removed (undefined)`);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
parsedProviders[id] = provider;
|
|
12
34
|
}
|
|
13
35
|
|
|
14
|
-
|
|
36
|
+
if (Object.keys(parsedProviders).length === 0) {
|
|
37
|
+
throw new Error("No providers configured (config.providers is empty)");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Strip providers that are not configured from models
|
|
15
41
|
const parsedModels = {} as typeof models;
|
|
42
|
+
const warnings = new Set<string>();
|
|
16
43
|
for (const id in models) {
|
|
17
44
|
const model = models[id!];
|
|
18
45
|
|
|
19
46
|
const kept: string[] = [];
|
|
20
47
|
|
|
21
48
|
for (const p of model!.providers) {
|
|
22
|
-
if (p in
|
|
23
|
-
else
|
|
49
|
+
if (p in parsedProviders) kept.push(p);
|
|
50
|
+
else warnings.add(p);
|
|
24
51
|
}
|
|
25
52
|
|
|
26
53
|
if (kept.length > 0) parsedModels[id] = { ...model!, providers: kept };
|
|
27
54
|
}
|
|
55
|
+
for (const warning of warnings) {
|
|
56
|
+
logger.warn(`[config] ${warning} provider removed (not configured)`);
|
|
57
|
+
}
|
|
28
58
|
|
|
29
59
|
if (Object.keys(parsedModels).length === 0) {
|
|
30
|
-
throw new Error("
|
|
60
|
+
throw new Error("No models configured (config.models is empty)");
|
|
31
61
|
}
|
|
32
62
|
|
|
33
|
-
return {
|
|
63
|
+
return {
|
|
64
|
+
...config,
|
|
65
|
+
logger: config.logger,
|
|
66
|
+
providers: parsedProviders,
|
|
67
|
+
models: parsedModels,
|
|
68
|
+
[kParsed]: true,
|
|
69
|
+
};
|
|
34
70
|
};
|
|
@@ -1,8 +1,59 @@
|
|
|
1
|
+
import type { GenerateTextResult, ToolSet, Output } from "ai";
|
|
2
|
+
|
|
1
3
|
import { describe, expect, test } from "bun:test";
|
|
2
4
|
|
|
3
|
-
import { convertToTextCallOptions } from "./converters";
|
|
5
|
+
import { convertToTextCallOptions, toChatCompletionsAssistantMessage } from "./converters";
|
|
4
6
|
|
|
5
7
|
describe("Chat Completions Converters", () => {
|
|
8
|
+
describe("toChatCompletionsAssistantMessage", () => {
|
|
9
|
+
test("should pass through providerMetadata to extra_content", () => {
|
|
10
|
+
const mockResult: GenerateTextResult<ToolSet, Output.Output> = {
|
|
11
|
+
content: [
|
|
12
|
+
{
|
|
13
|
+
type: "text",
|
|
14
|
+
text: "hello",
|
|
15
|
+
providerMetadata: {
|
|
16
|
+
vertex: {
|
|
17
|
+
thought_signature: "signature-abc",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
} as any,
|
|
21
|
+
],
|
|
22
|
+
toolCalls: [],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const message = toChatCompletionsAssistantMessage(mockResult);
|
|
26
|
+
|
|
27
|
+
expect(message.extra_content).toEqual({
|
|
28
|
+
vertex: {
|
|
29
|
+
thought_signature: "signature-abc",
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("should pass through providerMetadata to tool calls", () => {
|
|
35
|
+
const mockResult: GenerateTextResult<ToolSet, Output.Output> = {
|
|
36
|
+
content: [],
|
|
37
|
+
toolCalls: [
|
|
38
|
+
{
|
|
39
|
+
toolCallId: "call_123",
|
|
40
|
+
toolName: "get_weather",
|
|
41
|
+
input: { location: "London" },
|
|
42
|
+
providerMetadata: {
|
|
43
|
+
vertex: { thought_signature: "tool-signature" },
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const message = toChatCompletionsAssistantMessage(mockResult);
|
|
50
|
+
|
|
51
|
+
expect(message.tool_calls![0].extra_content).toEqual({
|
|
52
|
+
vertex: { thought_signature: "tool-signature" },
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
6
57
|
describe("convertToTextCallOptions", () => {
|
|
7
58
|
test("should use max_completion_tokens when present", () => {
|
|
8
59
|
const result = convertToTextCallOptions({
|