@hebo-ai/gateway 0.4.1 → 0.5.0-beta.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 +2 -3
- package/dist/endpoints/chat-completions/converters.d.ts +3 -1
- package/dist/endpoints/chat-completions/converters.js +121 -90
- package/dist/endpoints/chat-completions/handler.js +2 -4
- package/dist/endpoints/chat-completions/otel.js +7 -0
- package/dist/endpoints/chat-completions/schema.d.ts +400 -76
- package/dist/endpoints/chat-completions/schema.js +80 -36
- package/dist/endpoints/embeddings/handler.js +2 -4
- package/dist/endpoints/embeddings/schema.d.ts +1 -1
- package/dist/endpoints/embeddings/schema.js +1 -1
- package/dist/errors/gateway.js +1 -0
- package/dist/lifecycle.js +7 -12
- package/dist/logger/default.d.ts +0 -1
- package/dist/logger/default.js +30 -6
- package/dist/middleware/utils.js +1 -0
- package/dist/models/amazon/middleware.js +1 -0
- package/dist/models/anthropic/middleware.d.ts +2 -0
- package/dist/models/anthropic/middleware.js +77 -16
- package/dist/models/google/middleware.js +17 -0
- package/dist/models/google/presets.d.ts +387 -0
- package/dist/models/google/presets.js +9 -2
- package/dist/models/openai/middleware.js +1 -0
- package/dist/models/types.d.ts +1 -1
- package/dist/models/types.js +1 -0
- package/dist/providers/bedrock/index.d.ts +1 -0
- package/dist/providers/bedrock/index.js +1 -0
- package/dist/providers/bedrock/middleware.d.ts +2 -0
- package/dist/providers/bedrock/middleware.js +35 -0
- package/dist/telemetry/http.js +0 -3
- package/dist/types.d.ts +10 -20
- package/dist/utils/request.d.ts +1 -3
- package/dist/utils/request.js +3 -26
- package/dist/utils/response.d.ts +1 -1
- package/dist/utils/response.js +3 -3
- package/package.json +19 -21
- package/src/endpoints/chat-completions/converters.test.ts +219 -0
- package/src/endpoints/chat-completions/converters.ts +144 -104
- package/src/endpoints/chat-completions/handler.test.ts +87 -0
- package/src/endpoints/chat-completions/handler.ts +2 -5
- package/src/endpoints/chat-completions/otel.ts +6 -0
- package/src/endpoints/chat-completions/schema.ts +85 -43
- package/src/endpoints/embeddings/handler.ts +5 -5
- package/src/endpoints/embeddings/schema.ts +1 -1
- package/src/errors/gateway.ts +2 -0
- package/src/lifecycle.ts +7 -11
- package/src/logger/default.ts +34 -8
- package/src/middleware/utils.ts +1 -0
- package/src/models/amazon/middleware.ts +1 -0
- package/src/models/anthropic/middleware.test.ts +332 -1
- package/src/models/anthropic/middleware.ts +83 -19
- package/src/models/google/middleware.test.ts +31 -0
- package/src/models/google/middleware.ts +18 -0
- package/src/models/google/presets.ts +13 -2
- package/src/models/openai/middleware.ts +1 -0
- package/src/models/types.ts +1 -0
- package/src/providers/bedrock/index.ts +1 -0
- package/src/providers/bedrock/middleware.test.ts +73 -0
- package/src/providers/bedrock/middleware.ts +43 -0
- package/src/telemetry/http.ts +0 -3
- package/src/types.ts +19 -23
- package/src/utils/request.ts +5 -33
- package/src/utils/response.ts +3 -3
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { LanguageModelMiddleware } from "ai";
|
|
2
|
+
|
|
3
|
+
import { modelMiddlewareMatcher } from "../../middleware/matcher";
|
|
4
|
+
|
|
5
|
+
export const bedrockAnthropicReasoningMiddleware: LanguageModelMiddleware = {
|
|
6
|
+
specificationVersion: "v3",
|
|
7
|
+
// eslint-disable-next-line require-await
|
|
8
|
+
transformParams: async ({ params, model }) => {
|
|
9
|
+
if (!model.modelId.includes("claude")) return params;
|
|
10
|
+
|
|
11
|
+
const bedrock = params.providerOptions?.["bedrock"];
|
|
12
|
+
if (!bedrock || typeof bedrock !== "object") return params;
|
|
13
|
+
|
|
14
|
+
const bedrockOptions = bedrock as Record<string, unknown>;
|
|
15
|
+
const thinking = bedrockOptions["thinking"];
|
|
16
|
+
const effort = bedrockOptions["effort"];
|
|
17
|
+
|
|
18
|
+
if (!thinking && effort === undefined) return params;
|
|
19
|
+
|
|
20
|
+
const target = (bedrockOptions["reasoningConfig"] ??= {}) as Record<string, unknown>;
|
|
21
|
+
|
|
22
|
+
if (thinking && typeof thinking === "object") {
|
|
23
|
+
const thinkingOptions = thinking as Record<string, unknown>;
|
|
24
|
+
if (thinkingOptions["type"] !== undefined) {
|
|
25
|
+
target["type"] = thinkingOptions["type"];
|
|
26
|
+
}
|
|
27
|
+
if (thinkingOptions["budgetTokens"] !== undefined) {
|
|
28
|
+
target["budgetTokens"] = thinkingOptions["budgetTokens"];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (effort !== undefined) target["maxReasoningEffort"] = effort;
|
|
33
|
+
|
|
34
|
+
delete bedrockOptions["thinking"];
|
|
35
|
+
delete bedrockOptions["effort"];
|
|
36
|
+
|
|
37
|
+
return params;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
modelMiddlewareMatcher.useForProvider("amazon-bedrock", {
|
|
42
|
+
language: [bedrockAnthropicReasoningMiddleware],
|
|
43
|
+
});
|
package/src/telemetry/http.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type TelemetrySignalLevel } from "../types";
|
|
2
|
-
import { resolveRequestId } from "../utils/headers";
|
|
3
2
|
|
|
4
3
|
const headerArr = (h: Headers, k: string) => (h.has(k) ? [h.get(k)!] : undefined);
|
|
5
4
|
|
|
@@ -29,8 +28,6 @@ export const getRequestAttributes = (request: Request, signalLevel?: TelemetrySi
|
|
|
29
28
|
|
|
30
29
|
if (signalLevel !== "required") {
|
|
31
30
|
Object.assign(attrs, {
|
|
32
|
-
// FUTURE: does ElysiaJS and other frameworks attach request id?
|
|
33
|
-
"http.request.id": resolveRequestId(request),
|
|
34
31
|
"user_agent.original": request.headers.get("user-agent") ?? undefined,
|
|
35
32
|
});
|
|
36
33
|
}
|
package/src/types.ts
CHANGED
|
@@ -12,20 +12,6 @@ import type { Logger, LoggerConfig } from "./logger";
|
|
|
12
12
|
import type { ModelCatalog, ModelId } from "./models/types";
|
|
13
13
|
import type { ProviderId, ProviderRegistry } from "./providers/types";
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* Request overrides returned from the `onRequest` hook.
|
|
17
|
-
*/
|
|
18
|
-
export type RequestPatch = {
|
|
19
|
-
/**
|
|
20
|
-
* Headers to merge into the incoming request.
|
|
21
|
-
*/
|
|
22
|
-
headers?: HeadersInit;
|
|
23
|
-
/**
|
|
24
|
-
* Body to replace on the incoming request.
|
|
25
|
-
*/
|
|
26
|
-
body?: BodyInit;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
15
|
/**
|
|
30
16
|
* Per-request context shared across handlers and hooks.
|
|
31
17
|
*/
|
|
@@ -46,6 +32,10 @@ export type GatewayContext = {
|
|
|
46
32
|
* Incoming request for the handler.
|
|
47
33
|
*/
|
|
48
34
|
request: Request;
|
|
35
|
+
/**
|
|
36
|
+
* Resolved request ID for logging and telemetry.
|
|
37
|
+
*/
|
|
38
|
+
requestId: string;
|
|
49
39
|
/**
|
|
50
40
|
* Parsed body from the request.
|
|
51
41
|
*/
|
|
@@ -95,13 +85,22 @@ export type HookContext = Omit<Readonly<GatewayContext>, "state"> & {
|
|
|
95
85
|
type RequiredHookContext<K extends keyof GatewayContext> = Omit<HookContext, K> &
|
|
96
86
|
Required<Pick<HookContext, K>>;
|
|
97
87
|
export type OnRequestHookContext = RequiredHookContext<"request">;
|
|
98
|
-
export type BeforeHookContext = RequiredHookContext<"request" | "
|
|
99
|
-
export type ResolveModelHookContext = RequiredHookContext<
|
|
88
|
+
export type BeforeHookContext = RequiredHookContext<"request" | "operation" | "body">;
|
|
89
|
+
export type ResolveModelHookContext = RequiredHookContext<
|
|
90
|
+
"request" | "operation" | "body" | "modelId"
|
|
91
|
+
>;
|
|
100
92
|
export type ResolveProviderHookContext = RequiredHookContext<
|
|
101
|
-
"request" | "
|
|
93
|
+
"request" | "operation" | "body" | "modelId" | "resolvedModelId"
|
|
102
94
|
>;
|
|
103
95
|
export type AfterHookContext = RequiredHookContext<
|
|
104
|
-
|
|
96
|
+
| "request"
|
|
97
|
+
| "operation"
|
|
98
|
+
| "body"
|
|
99
|
+
| "modelId"
|
|
100
|
+
| "resolvedModelId"
|
|
101
|
+
| "provider"
|
|
102
|
+
| "resolvedProviderId"
|
|
103
|
+
| "result"
|
|
105
104
|
>;
|
|
106
105
|
export type OnResponseHookContext = RequiredHookContext<"request" | "response">;
|
|
107
106
|
|
|
@@ -111,12 +110,9 @@ export type OnResponseHookContext = RequiredHookContext<"request" | "response">;
|
|
|
111
110
|
export type GatewayHooks = {
|
|
112
111
|
/**
|
|
113
112
|
* Runs before any endpoint handler logic.
|
|
114
|
-
* @returns Optional
|
|
115
|
-
* or Response to short-circuit the request.
|
|
113
|
+
* @returns Optional Response to short-circuit the request.
|
|
116
114
|
*/
|
|
117
|
-
onRequest?: (
|
|
118
|
-
ctx: OnRequestHookContext,
|
|
119
|
-
) => void | RequestPatch | Response | Promise<void | RequestPatch | Response>;
|
|
115
|
+
onRequest?: (ctx: OnRequestHookContext) => void | Response | Promise<void | Response>;
|
|
120
116
|
/**
|
|
121
117
|
* Runs after request JSON is parsed and validated for chat completions / embeddings.
|
|
122
118
|
* @returns Replacement parsed body, or undefined to keep original.
|
package/src/utils/request.ts
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
import type { RequestPatch } from "../types";
|
|
2
|
-
|
|
3
1
|
import pkg from "../../package.json" with { type: "json" };
|
|
4
|
-
import {
|
|
2
|
+
import { resolveRequestId } from "./headers";
|
|
5
3
|
|
|
6
4
|
const GATEWAY_VERSION = pkg.version;
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (existingRequestId) return;
|
|
11
|
-
|
|
12
|
-
const requestId =
|
|
13
|
-
"req_" + crypto.getRandomValues(new Uint32Array(2)).reduce((s, n) => s + n.toString(36), "");
|
|
6
|
+
const createRequestId = () =>
|
|
7
|
+
"req_" + crypto.getRandomValues(new Uint32Array(2)).reduce((s, n) => s + n.toString(36), "");
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return headers;
|
|
19
|
-
};
|
|
9
|
+
export const resolveOrCreateRequestId = (request: Request) =>
|
|
10
|
+
resolveRequestId(request) ?? createRequestId();
|
|
20
11
|
|
|
21
12
|
export const prepareForwardHeaders = (request: Request): Record<string, string> => {
|
|
22
13
|
const userAgent = request.headers.get("user-agent");
|
|
@@ -28,22 +19,3 @@ export const prepareForwardHeaders = (request: Request): Record<string, string>
|
|
|
28
19
|
"user-agent": appendedUserAgent,
|
|
29
20
|
};
|
|
30
21
|
};
|
|
31
|
-
|
|
32
|
-
export const maybeApplyRequestPatch = (request: Request, patch: RequestPatch) => {
|
|
33
|
-
if (!patch.headers && patch.body === undefined) return request;
|
|
34
|
-
|
|
35
|
-
if (!patch.headers) {
|
|
36
|
-
// eslint-disable-next-line no-invalid-fetch-options
|
|
37
|
-
return new Request(request, { body: patch.body });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const headers = new Headers(request.headers);
|
|
41
|
-
for (const [key, value] of new Headers(patch.headers)) {
|
|
42
|
-
headers.set(key, value);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const init: RequestInit = { headers };
|
|
46
|
-
if (patch.body !== undefined) init.body = patch.body;
|
|
47
|
-
|
|
48
|
-
return new Request(request, init);
|
|
49
|
-
};
|
package/src/utils/response.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { REQUEST_ID_HEADER
|
|
1
|
+
import { REQUEST_ID_HEADER } from "./headers";
|
|
2
2
|
|
|
3
3
|
const TEXT_ENCODER = new TextEncoder();
|
|
4
4
|
|
|
@@ -15,8 +15,8 @@ class JsonToSseTransformStream extends TransformStream<unknown, string> {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export const prepareResponseInit = (
|
|
19
|
-
headers: { [REQUEST_ID_HEADER]:
|
|
18
|
+
export const prepareResponseInit = (requestId: string): ResponseInit => ({
|
|
19
|
+
headers: { [REQUEST_ID_HEADER]: requestId },
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
export const mergeResponseInit = (
|