@hebo-ai/gateway 0.9.2 → 0.9.3
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/dist/config.d.ts +2 -0
- package/dist/config.js +125 -0
- package/dist/endpoints/chat-completions/converters.d.ts +26 -0
- package/dist/endpoints/chat-completions/converters.js +525 -0
- package/dist/endpoints/chat-completions/handler.d.ts +2 -0
- package/dist/endpoints/chat-completions/handler.js +152 -0
- package/dist/endpoints/chat-completions/index.d.ts +4 -0
- package/dist/endpoints/chat-completions/index.js +4 -0
- package/dist/endpoints/chat-completions/otel.d.ts +5 -0
- package/dist/endpoints/chat-completions/otel.js +178 -0
- package/dist/endpoints/chat-completions/schema.d.ts +1170 -0
- package/dist/endpoints/chat-completions/schema.js +252 -0
- package/dist/endpoints/conversations/converters.d.ts +8 -0
- package/dist/endpoints/conversations/converters.js +29 -0
- package/dist/endpoints/conversations/handler.d.ts +2 -0
- package/dist/endpoints/conversations/handler.js +259 -0
- package/dist/endpoints/conversations/index.d.ts +3 -0
- package/dist/endpoints/conversations/index.js +3 -0
- package/dist/endpoints/conversations/schema.d.ts +1511 -0
- package/dist/endpoints/conversations/schema.js +74 -0
- package/dist/endpoints/conversations/storage/dialects/greptime.d.ts +10 -0
- package/dist/endpoints/conversations/storage/dialects/greptime.js +87 -0
- package/dist/endpoints/conversations/storage/dialects/mysql.d.ts +12 -0
- package/dist/endpoints/conversations/storage/dialects/mysql.js +118 -0
- package/dist/endpoints/conversations/storage/dialects/postgres.d.ts +16 -0
- package/dist/endpoints/conversations/storage/dialects/postgres.js +185 -0
- package/dist/endpoints/conversations/storage/dialects/sqlite.d.ts +11 -0
- package/dist/endpoints/conversations/storage/dialects/sqlite.js +176 -0
- package/dist/endpoints/conversations/storage/dialects/types.d.ts +42 -0
- package/dist/endpoints/conversations/storage/dialects/types.js +0 -0
- package/dist/endpoints/conversations/storage/dialects/utils.d.ts +25 -0
- package/dist/endpoints/conversations/storage/dialects/utils.js +80 -0
- package/dist/endpoints/conversations/storage/memory.d.ts +25 -0
- package/dist/endpoints/conversations/storage/memory.js +200 -0
- package/dist/endpoints/conversations/storage/sql.d.ts +33 -0
- package/dist/endpoints/conversations/storage/sql.js +276 -0
- package/dist/endpoints/conversations/storage/types.d.ts +39 -0
- package/dist/endpoints/conversations/storage/types.js +0 -0
- package/dist/endpoints/embeddings/converters.d.ts +10 -0
- package/dist/endpoints/embeddings/converters.js +31 -0
- package/dist/endpoints/embeddings/handler.d.ts +2 -0
- package/dist/endpoints/embeddings/handler.js +99 -0
- package/dist/endpoints/embeddings/index.d.ts +4 -0
- package/dist/endpoints/embeddings/index.js +4 -0
- package/dist/endpoints/embeddings/otel.d.ts +5 -0
- package/dist/endpoints/embeddings/otel.js +29 -0
- package/dist/endpoints/embeddings/schema.d.ts +44 -0
- package/dist/endpoints/embeddings/schema.js +29 -0
- package/dist/endpoints/models/converters.d.ts +6 -0
- package/dist/endpoints/models/converters.js +42 -0
- package/dist/endpoints/models/handler.d.ts +2 -0
- package/dist/endpoints/models/handler.js +29 -0
- package/dist/endpoints/models/index.d.ts +3 -0
- package/dist/endpoints/models/index.js +3 -0
- package/dist/endpoints/models/schema.d.ts +42 -0
- package/dist/endpoints/models/schema.js +31 -0
- package/dist/endpoints/responses/converters.d.ts +17 -0
- package/dist/endpoints/responses/converters.js +1037 -0
- package/dist/endpoints/responses/handler.d.ts +2 -0
- package/dist/endpoints/responses/handler.js +141 -0
- package/dist/endpoints/responses/index.d.ts +4 -0
- package/dist/endpoints/responses/index.js +4 -0
- package/dist/endpoints/responses/otel.d.ts +6 -0
- package/dist/endpoints/responses/otel.js +226 -0
- package/dist/endpoints/responses/schema.d.ts +2109 -0
- package/dist/endpoints/responses/schema.js +314 -0
- package/dist/endpoints/shared/converters.d.ts +56 -0
- package/dist/endpoints/shared/converters.js +180 -0
- package/dist/endpoints/shared/schema.d.ts +70 -0
- package/dist/endpoints/shared/schema.js +46 -0
- package/dist/errors/ai-sdk.d.ts +2 -0
- package/dist/errors/ai-sdk.js +52 -0
- package/dist/errors/gateway.d.ts +5 -0
- package/dist/errors/gateway.js +13 -0
- package/dist/errors/openai.d.ts +15 -0
- package/dist/errors/openai.js +40 -0
- package/dist/errors/utils.d.ts +24 -0
- package/dist/errors/utils.js +46 -0
- package/dist/gateway.d.ts +11 -0
- package/dist/gateway.js +44 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +10 -0
- package/dist/lifecycle.d.ts +3 -0
- package/dist/lifecycle.js +114 -0
- package/dist/logger/default.d.ts +4 -0
- package/dist/logger/default.js +81 -0
- package/dist/logger/index.d.ts +11 -0
- package/dist/logger/index.js +25 -0
- package/dist/middleware/common.d.ts +12 -0
- package/dist/middleware/common.js +146 -0
- package/dist/middleware/debug.d.ts +3 -0
- package/dist/middleware/debug.js +27 -0
- package/dist/middleware/matcher.d.ts +28 -0
- package/dist/middleware/matcher.js +118 -0
- package/dist/middleware/utils.d.ts +2 -0
- package/dist/middleware/utils.js +24 -0
- package/dist/models/amazon/index.d.ts +2 -0
- package/dist/models/amazon/index.js +2 -0
- package/dist/models/amazon/middleware.d.ts +3 -0
- package/dist/models/amazon/middleware.js +69 -0
- package/dist/models/amazon/presets.d.ts +345 -0
- package/dist/models/amazon/presets.js +80 -0
- package/dist/models/anthropic/index.d.ts +2 -0
- package/dist/models/anthropic/index.js +2 -0
- package/dist/models/anthropic/middleware.d.ts +5 -0
- package/dist/models/anthropic/middleware.js +128 -0
- package/dist/models/anthropic/presets.d.ts +711 -0
- package/dist/models/anthropic/presets.js +140 -0
- package/dist/models/catalog.d.ts +4 -0
- package/dist/models/catalog.js +8 -0
- package/dist/models/cohere/index.d.ts +2 -0
- package/dist/models/cohere/index.js +2 -0
- package/dist/models/cohere/middleware.d.ts +3 -0
- package/dist/models/cohere/middleware.js +62 -0
- package/dist/models/cohere/presets.d.ts +411 -0
- package/dist/models/cohere/presets.js +134 -0
- package/dist/models/google/index.d.ts +2 -0
- package/dist/models/google/index.js +2 -0
- package/dist/models/google/middleware.d.ts +8 -0
- package/dist/models/google/middleware.js +118 -0
- package/dist/models/google/presets.d.ts +815 -0
- package/dist/models/google/presets.js +184 -0
- package/dist/models/meta/index.d.ts +1 -0
- package/dist/models/meta/index.js +1 -0
- package/dist/models/meta/presets.d.ts +483 -0
- package/dist/models/meta/presets.js +105 -0
- package/dist/models/openai/index.d.ts +2 -0
- package/dist/models/openai/index.js +2 -0
- package/dist/models/openai/middleware.d.ts +4 -0
- package/dist/models/openai/middleware.js +89 -0
- package/dist/models/openai/presets.d.ts +1319 -0
- package/dist/models/openai/presets.js +277 -0
- package/dist/models/types.d.ts +20 -0
- package/dist/models/types.js +100 -0
- package/dist/models/voyage/index.d.ts +2 -0
- package/dist/models/voyage/index.js +2 -0
- package/dist/models/voyage/middleware.d.ts +2 -0
- package/dist/models/voyage/middleware.js +19 -0
- package/dist/models/voyage/presets.d.ts +436 -0
- package/dist/models/voyage/presets.js +85 -0
- package/dist/providers/anthropic/canonical.d.ts +3 -0
- package/dist/providers/anthropic/canonical.js +9 -0
- package/dist/providers/anthropic/index.d.ts +1 -0
- package/dist/providers/anthropic/index.js +1 -0
- package/dist/providers/bedrock/canonical.d.ts +17 -0
- package/dist/providers/bedrock/canonical.js +64 -0
- package/dist/providers/bedrock/index.d.ts +2 -0
- package/dist/providers/bedrock/index.js +2 -0
- package/dist/providers/bedrock/middleware.d.ts +5 -0
- package/dist/providers/bedrock/middleware.js +133 -0
- package/dist/providers/cohere/canonical.d.ts +3 -0
- package/dist/providers/cohere/canonical.js +17 -0
- package/dist/providers/cohere/index.d.ts +1 -0
- package/dist/providers/cohere/index.js +1 -0
- package/dist/providers/groq/canonical.d.ts +3 -0
- package/dist/providers/groq/canonical.js +12 -0
- package/dist/providers/groq/index.d.ts +2 -0
- package/dist/providers/groq/index.js +2 -0
- package/dist/providers/groq/middleware.d.ts +2 -0
- package/dist/providers/groq/middleware.js +30 -0
- package/dist/providers/openai/canonical.d.ts +3 -0
- package/dist/providers/openai/canonical.js +8 -0
- package/dist/providers/openai/index.d.ts +1 -0
- package/dist/providers/openai/index.js +1 -0
- package/dist/providers/registry.d.ts +24 -0
- package/dist/providers/registry.js +103 -0
- package/dist/providers/types.d.ts +7 -0
- package/dist/providers/types.js +11 -0
- package/dist/providers/vertex/canonical.d.ts +3 -0
- package/dist/providers/vertex/canonical.js +8 -0
- package/dist/providers/vertex/index.d.ts +2 -0
- package/dist/providers/vertex/index.js +2 -0
- package/dist/providers/vertex/middleware.d.ts +2 -0
- package/dist/providers/vertex/middleware.js +47 -0
- package/dist/providers/voyage/canonical.d.ts +3 -0
- package/dist/providers/voyage/canonical.js +7 -0
- package/dist/providers/voyage/index.d.ts +1 -0
- package/dist/providers/voyage/index.js +1 -0
- package/dist/telemetry/ai-sdk.d.ts +2 -0
- package/dist/telemetry/ai-sdk.js +31 -0
- package/dist/telemetry/baggage.d.ts +1 -0
- package/dist/telemetry/baggage.js +24 -0
- package/dist/telemetry/fetch.d.ts +2 -0
- package/dist/telemetry/fetch.js +49 -0
- package/dist/telemetry/gen-ai.d.ts +7 -0
- package/dist/telemetry/gen-ai.js +108 -0
- package/dist/telemetry/http.d.ts +3 -0
- package/dist/telemetry/http.js +54 -0
- package/dist/telemetry/index.d.ts +1 -0
- package/dist/telemetry/index.js +1 -0
- package/dist/telemetry/memory.d.ts +2 -0
- package/dist/telemetry/memory.js +43 -0
- package/dist/telemetry/span.d.ts +13 -0
- package/dist/telemetry/span.js +60 -0
- package/dist/types.d.ts +231 -0
- package/dist/types.js +2 -0
- package/dist/utils/body.d.ts +19 -0
- package/dist/utils/body.js +99 -0
- package/dist/utils/env.d.ts +2 -0
- package/dist/utils/env.js +7 -0
- package/dist/utils/headers.d.ts +4 -0
- package/dist/utils/headers.js +22 -0
- package/dist/utils/preset.d.ts +10 -0
- package/dist/utils/preset.js +41 -0
- package/dist/utils/request.d.ts +2 -0
- package/dist/utils/request.js +43 -0
- package/dist/utils/response.d.ts +6 -0
- package/dist/utils/response.js +55 -0
- package/dist/utils/stream.d.ts +9 -0
- package/dist/utils/stream.js +100 -0
- package/dist/utils/url.d.ts +4 -0
- package/dist/utils/url.js +21 -0
- package/package.json +1 -1
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { CacheControlSchema as ChatCompletionsCacheControlSchema, ReasoningEffortSchema as ChatCompletionsReasoningEffortSchema, ReasoningConfigSchema as ChatCompletionsReasoningConfigSchema, ServiceTierSchema as ChatCompletionsServiceTierSchema, ProviderMetadataSchema as ChatCompletionsProviderMetadataSchema, ContentPartAudioSchema as ChatCompletionsContentPartAudioSchema, } from "../shared/schema";
|
|
3
|
+
export { ChatCompletionsCacheControlSchema, ChatCompletionsReasoningEffortSchema, ChatCompletionsReasoningConfigSchema, ChatCompletionsServiceTierSchema, ChatCompletionsProviderMetadataSchema, ChatCompletionsContentPartAudioSchema, };
|
|
4
|
+
export const ChatCompletionsContentPartTextSchema = z.object({
|
|
5
|
+
type: z.literal("text"),
|
|
6
|
+
text: z.string(),
|
|
7
|
+
// Extension origin: Anthropic/OpenRouter/Vercel
|
|
8
|
+
cache_control: ChatCompletionsCacheControlSchema.optional().meta({ extension: true }),
|
|
9
|
+
});
|
|
10
|
+
export const ChatCompletionsContentPartImageSchema = z.object({
|
|
11
|
+
type: z.literal("image_url"),
|
|
12
|
+
image_url: z.object({
|
|
13
|
+
url: z.string(),
|
|
14
|
+
detail: z.enum(["low", "high", "auto"]).optional(),
|
|
15
|
+
}),
|
|
16
|
+
// Extension origin: OpenRouter/Vercel/Anthropic
|
|
17
|
+
cache_control: ChatCompletionsCacheControlSchema.optional().meta({ extension: true }),
|
|
18
|
+
});
|
|
19
|
+
export const ChatCompletionsContentPartFileSchema = z.object({
|
|
20
|
+
type: z.literal("file"),
|
|
21
|
+
file: z.object({
|
|
22
|
+
data: z.string(),
|
|
23
|
+
media_type: z.string(),
|
|
24
|
+
filename: z.string().optional(),
|
|
25
|
+
}),
|
|
26
|
+
// Extension origin: OpenRouter/Vercel/Anthropic
|
|
27
|
+
cache_control: ChatCompletionsCacheControlSchema.optional().meta({ extension: true }),
|
|
28
|
+
});
|
|
29
|
+
export const ChatCompletionsContentPartSchema = z.discriminatedUnion("type", [
|
|
30
|
+
ChatCompletionsContentPartTextSchema,
|
|
31
|
+
ChatCompletionsContentPartImageSchema,
|
|
32
|
+
ChatCompletionsContentPartFileSchema,
|
|
33
|
+
ChatCompletionsContentPartAudioSchema,
|
|
34
|
+
]);
|
|
35
|
+
export const ChatCompletionsToolCallSchema = z.object({
|
|
36
|
+
type: z.literal("function"),
|
|
37
|
+
id: z.string(),
|
|
38
|
+
function: z.object({
|
|
39
|
+
arguments: z.string(),
|
|
40
|
+
name: z.string(),
|
|
41
|
+
}),
|
|
42
|
+
// Extension origin: Gemini
|
|
43
|
+
extra_content: ChatCompletionsProviderMetadataSchema.optional().meta({ extension: true }),
|
|
44
|
+
});
|
|
45
|
+
export const ChatCompletionsSystemMessageSchema = z.object({
|
|
46
|
+
role: z.literal("system"),
|
|
47
|
+
content: z.string(),
|
|
48
|
+
name: z.string().optional(),
|
|
49
|
+
// Extension origin: OpenRouter/Vercel/Anthropic
|
|
50
|
+
cache_control: ChatCompletionsCacheControlSchema.optional().meta({ extension: true }),
|
|
51
|
+
});
|
|
52
|
+
export const ChatCompletionsUserMessageSchema = z.object({
|
|
53
|
+
role: z.literal("user"),
|
|
54
|
+
content: z.union([z.string(), z.array(ChatCompletionsContentPartSchema)]),
|
|
55
|
+
name: z.string().optional(),
|
|
56
|
+
// Extension origin: OpenRouter/Vercel/Anthropic
|
|
57
|
+
cache_control: ChatCompletionsCacheControlSchema.optional().meta({ extension: true }),
|
|
58
|
+
});
|
|
59
|
+
export const ChatCompletionsReasoningDetailSchema = z.object({
|
|
60
|
+
id: z.string().optional(),
|
|
61
|
+
index: z.int().nonnegative(),
|
|
62
|
+
type: z.string(),
|
|
63
|
+
text: z.string().optional(),
|
|
64
|
+
signature: z.string().optional(),
|
|
65
|
+
data: z.string().optional(),
|
|
66
|
+
summary: z.string().optional(),
|
|
67
|
+
format: z.string().optional(),
|
|
68
|
+
});
|
|
69
|
+
export const ChatCompletionsAssistantMessageSchema = z.object({
|
|
70
|
+
role: z.literal("assistant"),
|
|
71
|
+
content: z
|
|
72
|
+
.union([z.string(), z.null(), z.array(ChatCompletionsContentPartTextSchema)])
|
|
73
|
+
.optional(),
|
|
74
|
+
name: z.string().optional(),
|
|
75
|
+
// FUTURE: This should also support Custom Tool Calls
|
|
76
|
+
tool_calls: z.array(ChatCompletionsToolCallSchema).optional(),
|
|
77
|
+
// Extension origin: OpenRouter/Vercel
|
|
78
|
+
reasoning: z.string().optional().meta({ extension: true }),
|
|
79
|
+
// Extension origin: OpenRouter/Vercel
|
|
80
|
+
reasoning_details: z
|
|
81
|
+
.array(ChatCompletionsReasoningDetailSchema)
|
|
82
|
+
.optional()
|
|
83
|
+
.meta({ extension: true }),
|
|
84
|
+
// Extension origin: Gemini
|
|
85
|
+
extra_content: ChatCompletionsProviderMetadataSchema.optional().meta({ extension: true }),
|
|
86
|
+
// Extension origin: OpenRouter/Vercel/Anthropic
|
|
87
|
+
cache_control: ChatCompletionsCacheControlSchema.optional().meta({ extension: true }),
|
|
88
|
+
});
|
|
89
|
+
export const ChatCompletionsToolMessageSchema = z.object({
|
|
90
|
+
role: z.literal("tool"),
|
|
91
|
+
content: z.union([z.string(), z.array(ChatCompletionsContentPartTextSchema)]),
|
|
92
|
+
tool_call_id: z.string(),
|
|
93
|
+
});
|
|
94
|
+
export const ChatCompletionsMessageSchema = z.discriminatedUnion("role", [
|
|
95
|
+
ChatCompletionsSystemMessageSchema,
|
|
96
|
+
ChatCompletionsUserMessageSchema,
|
|
97
|
+
ChatCompletionsAssistantMessageSchema,
|
|
98
|
+
ChatCompletionsToolMessageSchema,
|
|
99
|
+
]);
|
|
100
|
+
export const ChatCompletionsToolSchema = z.object({
|
|
101
|
+
type: z.literal("function"),
|
|
102
|
+
function: z.object({
|
|
103
|
+
name: z.string(),
|
|
104
|
+
description: z.string().optional(),
|
|
105
|
+
parameters: z.record(z.string(), z.unknown()),
|
|
106
|
+
strict: z.boolean().optional(),
|
|
107
|
+
}),
|
|
108
|
+
// FUTURE: cache_control support on tools
|
|
109
|
+
});
|
|
110
|
+
const ChatCompletionsNamedFunctionToolChoiceSchema = z.object({
|
|
111
|
+
type: z.literal("function"),
|
|
112
|
+
function: z.object({
|
|
113
|
+
name: z.string(),
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
const ChatCompletionsAllowedFunctionToolChoiceSchema = z.object({
|
|
117
|
+
type: z.literal("allowed_tools"),
|
|
118
|
+
allowed_tools: z.object({
|
|
119
|
+
mode: z.enum(["auto", "required"]),
|
|
120
|
+
tools: z.array(ChatCompletionsNamedFunctionToolChoiceSchema).nonempty(),
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
export const ChatCompletionsToolChoiceSchema = z.union([
|
|
124
|
+
z.enum(["none", "auto", "required", "validated"]),
|
|
125
|
+
z.discriminatedUnion("type", [
|
|
126
|
+
ChatCompletionsNamedFunctionToolChoiceSchema,
|
|
127
|
+
ChatCompletionsAllowedFunctionToolChoiceSchema,
|
|
128
|
+
]),
|
|
129
|
+
// FUTURE: Missing CustomTool
|
|
130
|
+
]);
|
|
131
|
+
export const ChatCompletionsResponseFormatJsonSchema = z.object({
|
|
132
|
+
// FUTURE: consider support for legacy json_object (if demand)
|
|
133
|
+
type: z.literal("json_schema"),
|
|
134
|
+
json_schema: z.object({
|
|
135
|
+
name: z.string(),
|
|
136
|
+
description: z.string().optional(),
|
|
137
|
+
schema: z.record(z.string(), z.unknown()),
|
|
138
|
+
// FUTURE: consider support for non-strict mode (for providers that support it)
|
|
139
|
+
strict: z.boolean().optional(),
|
|
140
|
+
}),
|
|
141
|
+
});
|
|
142
|
+
export const ChatCompletionsResponseFormatTextSchema = z.object({
|
|
143
|
+
type: z.literal("text"),
|
|
144
|
+
});
|
|
145
|
+
export const ChatCompletionsResponseFormatSchema = z.discriminatedUnion("type", [
|
|
146
|
+
ChatCompletionsResponseFormatJsonSchema,
|
|
147
|
+
ChatCompletionsResponseFormatTextSchema,
|
|
148
|
+
]);
|
|
149
|
+
export const ChatCompletionsMetadataSchema = z.record(z.string().min(1).max(64), z.string().max(512));
|
|
150
|
+
const ChatCompletionsInputsSchema = z.object({
|
|
151
|
+
messages: z.array(ChatCompletionsMessageSchema),
|
|
152
|
+
tools: z.array(ChatCompletionsToolSchema).optional(),
|
|
153
|
+
tool_choice: ChatCompletionsToolChoiceSchema.optional(),
|
|
154
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
155
|
+
max_tokens: z.int().nonnegative().optional(),
|
|
156
|
+
max_completion_tokens: z.int().nonnegative().optional(),
|
|
157
|
+
frequency_penalty: z.number().min(-2.0).max(2.0).optional(),
|
|
158
|
+
presence_penalty: z.number().min(-2.0).max(2.0).optional(),
|
|
159
|
+
seed: z.int().optional(),
|
|
160
|
+
stop: z.union([z.string(), z.array(z.string())]).optional(),
|
|
161
|
+
top_p: z.number().min(0).max(1.0).optional(),
|
|
162
|
+
metadata: ChatCompletionsMetadataSchema.optional(),
|
|
163
|
+
response_format: ChatCompletionsResponseFormatSchema.optional(),
|
|
164
|
+
reasoning_effort: ChatCompletionsReasoningEffortSchema.optional(),
|
|
165
|
+
service_tier: ChatCompletionsServiceTierSchema.optional(),
|
|
166
|
+
prompt_cache_key: z.string().optional(),
|
|
167
|
+
prompt_cache_retention: z.enum(["in-memory", "24h"]).optional(),
|
|
168
|
+
parallel_tool_calls: z.boolean().optional(),
|
|
169
|
+
// FUTURE: OpenAI configurations
|
|
170
|
+
// logprobs: z.boolean().optional(),
|
|
171
|
+
// top_logprobs: z.number().int().optional(),
|
|
172
|
+
// user: z.string().optional(),
|
|
173
|
+
// Extension origin: OpenRouter/Vercel/Anthropic
|
|
174
|
+
cache_control: ChatCompletionsCacheControlSchema.optional().meta({ extension: true }),
|
|
175
|
+
// Extension origin: OpenRouter
|
|
176
|
+
reasoning: ChatCompletionsReasoningConfigSchema.optional().meta({ extension: true }),
|
|
177
|
+
// Extension origin: Gemini extra_body
|
|
178
|
+
// https://docs.cloud.google.com/vertex-ai/generative-ai/docs/migrate/openai/overview#extra_body
|
|
179
|
+
extra_body: ChatCompletionsProviderMetadataSchema.optional().meta({ extension: true }),
|
|
180
|
+
});
|
|
181
|
+
export const ChatCompletionsBodySchema = z.looseObject({
|
|
182
|
+
model: z.string(),
|
|
183
|
+
stream: z.boolean().optional(),
|
|
184
|
+
...ChatCompletionsInputsSchema.shape,
|
|
185
|
+
});
|
|
186
|
+
export const ChatCompletionsFinishReasonSchema = z.enum([
|
|
187
|
+
"stop",
|
|
188
|
+
"length",
|
|
189
|
+
"content_filter",
|
|
190
|
+
"tool_calls",
|
|
191
|
+
]);
|
|
192
|
+
export const ChatCompletionsChoiceSchema = z.object({
|
|
193
|
+
index: z.int().nonnegative(),
|
|
194
|
+
message: ChatCompletionsAssistantMessageSchema,
|
|
195
|
+
finish_reason: ChatCompletionsFinishReasonSchema,
|
|
196
|
+
// FUTURE: model this out
|
|
197
|
+
logprobs: z.unknown().optional(),
|
|
198
|
+
});
|
|
199
|
+
export const ChatCompletionsUsageSchema = z.object({
|
|
200
|
+
prompt_tokens: z.int().nonnegative().optional(),
|
|
201
|
+
completion_tokens: z.int().nonnegative().optional(),
|
|
202
|
+
total_tokens: z.int().nonnegative().optional(),
|
|
203
|
+
completion_tokens_details: z
|
|
204
|
+
.object({
|
|
205
|
+
// FUTURE: add missing properties
|
|
206
|
+
reasoning_tokens: z.int().nonnegative().optional(),
|
|
207
|
+
})
|
|
208
|
+
.optional(),
|
|
209
|
+
prompt_tokens_details: z
|
|
210
|
+
.object({
|
|
211
|
+
// FUTURE: add missing properties
|
|
212
|
+
cached_tokens: z.int().nonnegative().optional(),
|
|
213
|
+
// Extension origin: OpenRouter
|
|
214
|
+
cache_write_tokens: z.int().nonnegative().optional().meta({ extension: true }),
|
|
215
|
+
})
|
|
216
|
+
.optional(),
|
|
217
|
+
});
|
|
218
|
+
export const ChatCompletionsSchema = z.object({
|
|
219
|
+
id: z.string(),
|
|
220
|
+
object: z.literal("chat.completion"),
|
|
221
|
+
created: z.int().nonnegative(),
|
|
222
|
+
model: z.string(),
|
|
223
|
+
choices: z.array(ChatCompletionsChoiceSchema),
|
|
224
|
+
usage: ChatCompletionsUsageSchema.nullable(),
|
|
225
|
+
service_tier: ChatCompletionsServiceTierSchema.optional(),
|
|
226
|
+
// Extension origin: Vercel AI Gateway
|
|
227
|
+
provider_metadata: ChatCompletionsProviderMetadataSchema.optional().meta({ extension: true }),
|
|
228
|
+
});
|
|
229
|
+
export const ChatCompletionsToolCallDeltaSchema = ChatCompletionsToolCallSchema.partial().extend({
|
|
230
|
+
index: z.int().nonnegative(),
|
|
231
|
+
});
|
|
232
|
+
export const ChatCompletionsAssistantMessageDeltaSchema = ChatCompletionsAssistantMessageSchema.partial().extend({
|
|
233
|
+
tool_calls: z.array(ChatCompletionsToolCallDeltaSchema).optional(),
|
|
234
|
+
});
|
|
235
|
+
export const ChatCompletionsChoiceDeltaSchema = z.object({
|
|
236
|
+
index: z.int().nonnegative(),
|
|
237
|
+
delta: ChatCompletionsAssistantMessageDeltaSchema,
|
|
238
|
+
finish_reason: ChatCompletionsFinishReasonSchema.nullable(),
|
|
239
|
+
// FUTURE: model this out
|
|
240
|
+
logprobs: z.unknown().optional(),
|
|
241
|
+
});
|
|
242
|
+
export const ChatCompletionsChunkSchema = z.object({
|
|
243
|
+
id: z.string(),
|
|
244
|
+
object: z.literal("chat.completion.chunk"),
|
|
245
|
+
created: z.int().nonnegative(),
|
|
246
|
+
model: z.string(),
|
|
247
|
+
choices: z.array(ChatCompletionsChoiceDeltaSchema),
|
|
248
|
+
usage: ChatCompletionsUsageSchema.nullable(),
|
|
249
|
+
service_tier: ChatCompletionsServiceTierSchema.optional(),
|
|
250
|
+
// Extension origin: Vercel AI Gateway
|
|
251
|
+
provider_metadata: ChatCompletionsProviderMetadataSchema.optional().meta({ extension: true }),
|
|
252
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Conversation, ConversationItem, ConversationDeleted } from "./schema";
|
|
2
|
+
import type { ConversationEntity, ConversationItemEntity } from "./storage/types";
|
|
3
|
+
export declare function toConversation(entity: ConversationEntity): Conversation;
|
|
4
|
+
export declare function toConversationItem(entity: ConversationItemEntity): ConversationItem;
|
|
5
|
+
export declare function toConversationDeleted(result: {
|
|
6
|
+
id: string;
|
|
7
|
+
deleted: boolean;
|
|
8
|
+
}): ConversationDeleted;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function toConversation(entity) {
|
|
2
|
+
return {
|
|
3
|
+
id: entity.id,
|
|
4
|
+
object: "conversation",
|
|
5
|
+
created_at: Math.floor(entity.created_at / 1000),
|
|
6
|
+
metadata: entity.metadata,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function toConversationItem(entity) {
|
|
10
|
+
const item = {};
|
|
11
|
+
for (const key in entity) {
|
|
12
|
+
if (key === "conversation_id")
|
|
13
|
+
continue;
|
|
14
|
+
if (key === "created_at") {
|
|
15
|
+
item["created_at"] = Math.floor(entity["created_at"] / 1000);
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
item[key] = entity[key];
|
|
19
|
+
}
|
|
20
|
+
item["object"] = "conversation.item";
|
|
21
|
+
return item;
|
|
22
|
+
}
|
|
23
|
+
export function toConversationDeleted(result) {
|
|
24
|
+
return {
|
|
25
|
+
id: result.id,
|
|
26
|
+
deleted: result.deleted,
|
|
27
|
+
object: "conversation.deleted",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { parseConfig } from "../../config";
|
|
3
|
+
import { GatewayError } from "../../errors/gateway";
|
|
4
|
+
import { winterCgHandler } from "../../lifecycle";
|
|
5
|
+
import { logger } from "../../logger";
|
|
6
|
+
import { addSpanEvent } from "../../telemetry/span";
|
|
7
|
+
import { parseRequestBody } from "../../utils/body";
|
|
8
|
+
import { toConversation, toConversationItem, toConversationDeleted } from "./converters";
|
|
9
|
+
import { ConversationCreateParamsSchema, ConversationItemsAddBodySchema, ConversationUpdateBodySchema, ConversationItemListParamsSchema, ConversationListParamsSchema, } from "./schema";
|
|
10
|
+
export const conversations = (config) => {
|
|
11
|
+
const parsedConfig = parseConfig(config);
|
|
12
|
+
const storage = parsedConfig.storage;
|
|
13
|
+
async function list(ctx, searchParams) {
|
|
14
|
+
const params = Object.fromEntries(searchParams.entries());
|
|
15
|
+
const parsed = ConversationListParamsSchema.safeParse(params);
|
|
16
|
+
if (!parsed.success) {
|
|
17
|
+
throw new GatewayError(z.prettifyError(parsed.error), 400, undefined, parsed.error);
|
|
18
|
+
}
|
|
19
|
+
const { limit, after, order, metadata } = parsed.data;
|
|
20
|
+
// Treat limit 0 as unlimited (up to 100,000 items)
|
|
21
|
+
const entities = await storage.listConversations({
|
|
22
|
+
limit: limit ? limit + 1 : 100000,
|
|
23
|
+
after,
|
|
24
|
+
order,
|
|
25
|
+
metadata: metadata,
|
|
26
|
+
});
|
|
27
|
+
logger.trace({ requestId: ctx.requestId, count: entities.length }, "[storage] listConversations result");
|
|
28
|
+
const has_more = limit !== 0 && entities.length > limit;
|
|
29
|
+
const targetLength = limit > 0 && entities.length > limit ? limit : entities.length;
|
|
30
|
+
const data = [];
|
|
31
|
+
for (let i = 0; i < targetLength; i++) {
|
|
32
|
+
const entity = entities[i];
|
|
33
|
+
if (entity) {
|
|
34
|
+
data.push(toConversation(entity));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
object: "list",
|
|
39
|
+
data,
|
|
40
|
+
has_more,
|
|
41
|
+
first_id: data[0]?.id,
|
|
42
|
+
last_id: data.at(-1)?.id,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async function create(ctx) {
|
|
46
|
+
const body = await parseRequestBody(ctx.request, parsedConfig.maxBodySize);
|
|
47
|
+
addSpanEvent("hebo.request.deserialized");
|
|
48
|
+
const parsed = ConversationCreateParamsSchema.safeParse(body);
|
|
49
|
+
if (!parsed.success) {
|
|
50
|
+
throw new GatewayError(z.prettifyError(parsed.error), 400, undefined, parsed.error);
|
|
51
|
+
}
|
|
52
|
+
addSpanEvent("hebo.request.parsed");
|
|
53
|
+
const entity = await storage.createConversation({
|
|
54
|
+
metadata: parsed.data.metadata,
|
|
55
|
+
items: parsed.data.items,
|
|
56
|
+
});
|
|
57
|
+
logger.debug(`[conversations] created conversation: ${entity.id}`);
|
|
58
|
+
logger.trace({ requestId: ctx.requestId, entity }, "[storage] createConversation result");
|
|
59
|
+
return toConversation(entity);
|
|
60
|
+
}
|
|
61
|
+
async function retrieve(ctx, conversationId) {
|
|
62
|
+
const entity = await storage.getConversation(conversationId);
|
|
63
|
+
logger.trace({ requestId: ctx.requestId, entity }, "[storage] getConversation result");
|
|
64
|
+
if (!entity) {
|
|
65
|
+
throw new GatewayError("Conversation not found", 404);
|
|
66
|
+
}
|
|
67
|
+
return toConversation(entity);
|
|
68
|
+
}
|
|
69
|
+
async function update(ctx, conversationId) {
|
|
70
|
+
const body = await parseRequestBody(ctx.request, parsedConfig.maxBodySize);
|
|
71
|
+
addSpanEvent("hebo.request.deserialized");
|
|
72
|
+
const parsed = ConversationUpdateBodySchema.safeParse(body);
|
|
73
|
+
if (!parsed.success) {
|
|
74
|
+
throw new GatewayError(z.prettifyError(parsed.error), 400, undefined, parsed.error);
|
|
75
|
+
}
|
|
76
|
+
addSpanEvent("hebo.request.parsed");
|
|
77
|
+
const entity = await storage.updateConversation(conversationId, parsed.data.metadata);
|
|
78
|
+
if (!entity) {
|
|
79
|
+
throw new GatewayError("Conversation not found", 404);
|
|
80
|
+
}
|
|
81
|
+
logger.debug(`[conversations] updated conversation: ${conversationId}`);
|
|
82
|
+
logger.trace({ requestId: ctx.requestId, entity }, "[storage] updateConversation result");
|
|
83
|
+
return toConversation(entity);
|
|
84
|
+
}
|
|
85
|
+
async function remove(ctx, conversationId) {
|
|
86
|
+
const result = await storage.deleteConversation(conversationId);
|
|
87
|
+
logger.debug(`[conversations] deleted conversation: ${conversationId}`);
|
|
88
|
+
logger.trace({ requestId: ctx.requestId, result }, "[storage] deleteConversation result");
|
|
89
|
+
return toConversationDeleted(result);
|
|
90
|
+
}
|
|
91
|
+
async function retrieveItem(ctx, conversationId, itemId) {
|
|
92
|
+
const entity = await storage.getItem(conversationId, itemId);
|
|
93
|
+
logger.trace({ requestId: ctx.requestId, entity }, "[storage] getItem result");
|
|
94
|
+
if (!entity) {
|
|
95
|
+
throw new GatewayError("Item not found", 404);
|
|
96
|
+
}
|
|
97
|
+
return toConversationItem(entity);
|
|
98
|
+
}
|
|
99
|
+
async function deleteItem(ctx, conversationId, itemId) {
|
|
100
|
+
const entity = await storage.deleteItem(conversationId, itemId);
|
|
101
|
+
logger.debug(`[conversations] deleted item ${itemId} from conversation: ${conversationId}`);
|
|
102
|
+
logger.trace({ requestId: ctx.requestId, entity }, "[storage] deleteItem result");
|
|
103
|
+
if (!entity) {
|
|
104
|
+
throw new GatewayError("Conversation not found", 404);
|
|
105
|
+
}
|
|
106
|
+
return toConversation(entity);
|
|
107
|
+
}
|
|
108
|
+
async function listItems(ctx, conversationId, searchParams) {
|
|
109
|
+
const params = Object.fromEntries(searchParams.entries());
|
|
110
|
+
const parsed = ConversationItemListParamsSchema.safeParse(params);
|
|
111
|
+
if (!parsed.success) {
|
|
112
|
+
throw new GatewayError(z.prettifyError(parsed.error), 400, undefined, parsed.error);
|
|
113
|
+
}
|
|
114
|
+
const { limit, after, order } = parsed.data;
|
|
115
|
+
// Treat limit 0 as unlimited (up to 100,000 items)
|
|
116
|
+
const entities = await storage.listItems(conversationId, {
|
|
117
|
+
limit: limit ? limit + 1 : 100000,
|
|
118
|
+
after,
|
|
119
|
+
order,
|
|
120
|
+
});
|
|
121
|
+
logger.trace({ requestId: ctx.requestId, conversationId, itemCount: entities?.length }, "[storage] listItems result");
|
|
122
|
+
if (!entities)
|
|
123
|
+
throw new GatewayError("Conversation not found", 404);
|
|
124
|
+
const has_more = limit !== 0 && entities.length > limit;
|
|
125
|
+
const targetLength = limit > 0 && entities.length > limit ? limit : entities.length;
|
|
126
|
+
const data = [];
|
|
127
|
+
for (let i = 0; i < targetLength; i++) {
|
|
128
|
+
const entity = entities[i];
|
|
129
|
+
if (entity) {
|
|
130
|
+
data.push(toConversationItem(entity));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
object: "list",
|
|
135
|
+
data,
|
|
136
|
+
has_more,
|
|
137
|
+
first_id: data[0]?.id,
|
|
138
|
+
last_id: data.at(-1)?.id,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async function addItems(ctx, conversationId) {
|
|
142
|
+
const body = await parseRequestBody(ctx.request, parsedConfig.maxBodySize);
|
|
143
|
+
addSpanEvent("hebo.request.deserialized");
|
|
144
|
+
const parsed = ConversationItemsAddBodySchema.safeParse(body);
|
|
145
|
+
if (!parsed.success) {
|
|
146
|
+
throw new GatewayError(z.prettifyError(parsed.error), 400, undefined, parsed.error);
|
|
147
|
+
}
|
|
148
|
+
addSpanEvent("hebo.request.parsed");
|
|
149
|
+
const entities = await storage.addItems(conversationId, parsed.data.items);
|
|
150
|
+
if (!entities) {
|
|
151
|
+
throw new GatewayError("Conversation not found", 404);
|
|
152
|
+
}
|
|
153
|
+
logger.debug(`[conversations] added ${entities.length} items to conversation: ${conversationId}`);
|
|
154
|
+
logger.trace({ requestId: ctx.requestId, conversationId, itemCount: entities.length }, "[storage] addItems result");
|
|
155
|
+
const dataLength = entities.length;
|
|
156
|
+
const data = [];
|
|
157
|
+
for (let i = 0; i < dataLength; i++) {
|
|
158
|
+
const entity = entities[i];
|
|
159
|
+
if (entity) {
|
|
160
|
+
data.push(toConversationItem(entity));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
object: "list",
|
|
165
|
+
data,
|
|
166
|
+
has_more: false,
|
|
167
|
+
first_id: data[0]?.id,
|
|
168
|
+
last_id: data.at(-1)?.id,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const handler = async (ctx) => {
|
|
172
|
+
ctx.operation = "conversations";
|
|
173
|
+
addSpanEvent("hebo.handler.started");
|
|
174
|
+
const url = new URL(ctx.request.url);
|
|
175
|
+
const rawSegments = url.pathname.split("/");
|
|
176
|
+
const segments = [];
|
|
177
|
+
for (let i = 0; i < rawSegments.length; i++) {
|
|
178
|
+
const segment = rawSegments[i];
|
|
179
|
+
if (segment) {
|
|
180
|
+
segments.push(segment);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
let rootIndex = -1;
|
|
184
|
+
for (let i = 0; i < segments.length; i++) {
|
|
185
|
+
if (segments[i] === "conversations") {
|
|
186
|
+
rootIndex = i;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (rootIndex === -1) {
|
|
191
|
+
throw new GatewayError("Not Found", 404);
|
|
192
|
+
}
|
|
193
|
+
const len = segments.length - rootIndex;
|
|
194
|
+
let result;
|
|
195
|
+
// GET/POST /conversations (List/Create)
|
|
196
|
+
if (len === 1) {
|
|
197
|
+
if (ctx.request.method === "GET") {
|
|
198
|
+
result = await list(ctx, url.searchParams);
|
|
199
|
+
}
|
|
200
|
+
else if (ctx.request.method === "POST") {
|
|
201
|
+
result = await create(ctx);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
throw new GatewayError("Method Not Allowed", 405);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// GET/POST/DELETE /conversations/{id} (Conversation Instance)
|
|
208
|
+
else if (len === 2) {
|
|
209
|
+
const conversationId = segments[rootIndex + 1];
|
|
210
|
+
logger.debug(`[conversations] resolved conversation ID: ${conversationId}`);
|
|
211
|
+
if (ctx.request.method === "GET") {
|
|
212
|
+
result = await retrieve(ctx, conversationId);
|
|
213
|
+
}
|
|
214
|
+
else if (ctx.request.method === "POST") {
|
|
215
|
+
result = await update(ctx, conversationId);
|
|
216
|
+
}
|
|
217
|
+
else if (ctx.request.method === "DELETE") {
|
|
218
|
+
result = await remove(ctx, conversationId);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
throw new GatewayError("Method Not Allowed", 405);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// GET/POST /conversations/{id}/items
|
|
225
|
+
else if (len === 3 && segments[rootIndex + 2] === "items") {
|
|
226
|
+
const conversationId = segments[rootIndex + 1];
|
|
227
|
+
logger.debug(`[conversations] list/add items for conversation ID: ${conversationId}`);
|
|
228
|
+
if (ctx.request.method === "GET") {
|
|
229
|
+
result = await listItems(ctx, conversationId, url.searchParams);
|
|
230
|
+
}
|
|
231
|
+
else if (ctx.request.method === "POST") {
|
|
232
|
+
result = await addItems(ctx, conversationId);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
throw new GatewayError("Method Not Allowed", 405);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// GET/DELETE /conversations/{id}/items/{item_id}
|
|
239
|
+
else if (len === 4 && segments[rootIndex + 2] === "items") {
|
|
240
|
+
const conversationId = segments[rootIndex + 1];
|
|
241
|
+
const itemId = segments[rootIndex + 3];
|
|
242
|
+
logger.debug(`[conversations] item access: conversation ID=${conversationId}, item ID=${itemId}`);
|
|
243
|
+
if (ctx.request.method === "GET") {
|
|
244
|
+
result = await retrieveItem(ctx, conversationId, itemId);
|
|
245
|
+
}
|
|
246
|
+
else if (ctx.request.method === "DELETE") {
|
|
247
|
+
result = await deleteItem(ctx, conversationId, itemId);
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
throw new GatewayError("Method Not Allowed", 405);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
throw new GatewayError("Not Found", 404);
|
|
255
|
+
}
|
|
256
|
+
return result;
|
|
257
|
+
};
|
|
258
|
+
return { handler: winterCgHandler(handler, parsedConfig) };
|
|
259
|
+
};
|