@hebo-ai/gateway 0.8.2 → 0.9.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 +131 -32
- package/dist/endpoints/chat-completions/converters.d.ts +4 -21
- package/dist/endpoints/chat-completions/converters.js +23 -160
- package/dist/endpoints/chat-completions/handler.js +2 -2
- package/dist/endpoints/chat-completions/schema.d.ts +45 -101
- package/dist/endpoints/chat-completions/schema.js +13 -69
- package/dist/endpoints/conversations/converters.js +2 -3
- package/dist/endpoints/conversations/schema.d.ts +506 -644
- package/dist/endpoints/conversations/schema.js +8 -159
- package/dist/endpoints/conversations/storage/dialects/greptime.js +4 -2
- package/dist/endpoints/conversations/storage/dialects/mysql.js +3 -1
- package/dist/endpoints/conversations/storage/dialects/postgres.js +6 -3
- package/dist/endpoints/conversations/storage/dialects/sqlite.js +3 -1
- package/dist/endpoints/conversations/storage/sql.js +11 -6
- package/dist/endpoints/embeddings/handler.js +1 -1
- package/dist/endpoints/responses/converters.d.ts +17 -0
- package/dist/endpoints/responses/converters.js +1034 -0
- package/dist/endpoints/responses/handler.d.ts +2 -0
- package/dist/endpoints/responses/handler.js +137 -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 +221 -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 +55 -0
- package/dist/endpoints/shared/converters.js +179 -0
- package/dist/endpoints/shared/schema.d.ts +70 -0
- package/dist/endpoints/shared/schema.js +46 -0
- package/dist/gateway.d.ts +1 -0
- package/dist/gateway.js +2 -0
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -4
- package/dist/lifecycle.js +46 -29
- package/dist/models/anthropic/middleware.d.ts +1 -1
- package/dist/models/google/middleware.d.ts +1 -1
- package/dist/providers/registry.d.ts +1 -1
- package/dist/types.d.ts +18 -6
- package/dist/utils/preset.js +0 -1
- package/package.json +5 -1
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
export const ResponsesMetadataSchema = z
|
|
3
|
+
.record(z.string().min(1).max(64), z.string().max(512))
|
|
4
|
+
.nullable()
|
|
5
|
+
.optional();
|
|
6
|
+
export const ResponsesItemStatusSchema = z.enum(["in_progress", "completed", "incomplete"]);
|
|
7
|
+
export const ResponsesImageDetailSchema = z.enum(["low", "high", "auto"]);
|
|
8
|
+
/**
|
|
9
|
+
* --- Messaging Content & Items ---
|
|
10
|
+
*/
|
|
11
|
+
// Content Parts
|
|
12
|
+
export const ResponsesInputTextSchema = z.object({
|
|
13
|
+
type: z.literal("input_text"),
|
|
14
|
+
text: z.string(),
|
|
15
|
+
});
|
|
16
|
+
const ResponsesInputImageURLSchema = z.object({
|
|
17
|
+
type: z.literal("input_image"),
|
|
18
|
+
image_url: z.string(),
|
|
19
|
+
file_id: z.string().optional(),
|
|
20
|
+
detail: ResponsesImageDetailSchema.optional(),
|
|
21
|
+
});
|
|
22
|
+
const ResponsesInputImageIDSchema = z.object({
|
|
23
|
+
type: z.literal("input_image"),
|
|
24
|
+
file_id: z.string(),
|
|
25
|
+
image_url: z.string().optional(),
|
|
26
|
+
detail: ResponsesImageDetailSchema.optional(),
|
|
27
|
+
});
|
|
28
|
+
export const ResponsesInputImageSchema = z.union([
|
|
29
|
+
ResponsesInputImageURLSchema,
|
|
30
|
+
ResponsesInputImageIDSchema,
|
|
31
|
+
]);
|
|
32
|
+
const ResponsesInputFileDataSchema = z.object({
|
|
33
|
+
type: z.literal("input_file"),
|
|
34
|
+
file_data: z.string(),
|
|
35
|
+
file_id: z.string().optional(),
|
|
36
|
+
file_url: z.string().optional(),
|
|
37
|
+
filename: z.string().optional(),
|
|
38
|
+
});
|
|
39
|
+
const ResponsesInputFileIDSchema = z.object({
|
|
40
|
+
type: z.literal("input_file"),
|
|
41
|
+
file_id: z.string(),
|
|
42
|
+
file_data: z.string().optional(),
|
|
43
|
+
file_url: z.string().optional(),
|
|
44
|
+
filename: z.string().optional(),
|
|
45
|
+
});
|
|
46
|
+
const ResponsesInputFileURLSchema = z.object({
|
|
47
|
+
type: z.literal("input_file"),
|
|
48
|
+
file_url: z.string(),
|
|
49
|
+
file_data: z.string().optional(),
|
|
50
|
+
file_id: z.string().optional(),
|
|
51
|
+
filename: z.string().optional(),
|
|
52
|
+
});
|
|
53
|
+
export const ResponsesInputFileSchema = z.union([
|
|
54
|
+
ResponsesInputFileDataSchema,
|
|
55
|
+
ResponsesInputFileIDSchema,
|
|
56
|
+
ResponsesInputFileURLSchema,
|
|
57
|
+
]);
|
|
58
|
+
export const ResponsesInputContentSchema = z.union([
|
|
59
|
+
ResponsesInputTextSchema,
|
|
60
|
+
ResponsesInputImageURLSchema,
|
|
61
|
+
ResponsesInputImageIDSchema,
|
|
62
|
+
ResponsesInputFileDataSchema,
|
|
63
|
+
ResponsesInputFileIDSchema,
|
|
64
|
+
ResponsesInputFileURLSchema,
|
|
65
|
+
ResponsesInputAudioSchema,
|
|
66
|
+
]);
|
|
67
|
+
export const ResponsesOutputTextSchema = z.object({
|
|
68
|
+
type: z.literal("output_text"),
|
|
69
|
+
text: z.string(),
|
|
70
|
+
annotations: z.array(z.unknown()).optional(),
|
|
71
|
+
});
|
|
72
|
+
// Message Items
|
|
73
|
+
const ResponsesMessageItemBaseSchema = z.object({
|
|
74
|
+
type: z.literal("message"),
|
|
75
|
+
id: z.string().optional(),
|
|
76
|
+
status: ResponsesItemStatusSchema.optional(),
|
|
77
|
+
// Extension origin: Gemini
|
|
78
|
+
extra_content: ResponsesProviderMetadataSchema.optional().meta({ extension: true }),
|
|
79
|
+
// Extension origin: Anthropic/OpenRouter/Vercel
|
|
80
|
+
cache_control: ResponsesCacheControlSchema.optional().meta({ extension: true }),
|
|
81
|
+
});
|
|
82
|
+
const ResponsesUserMessageSchema = ResponsesMessageItemBaseSchema.extend({
|
|
83
|
+
role: z.literal("user"),
|
|
84
|
+
content: z.union([z.string(), z.array(ResponsesInputContentSchema)]),
|
|
85
|
+
});
|
|
86
|
+
const ResponsesAssistantMessageSchema = ResponsesMessageItemBaseSchema.extend({
|
|
87
|
+
role: z.literal("assistant"),
|
|
88
|
+
content: z.union([z.string(), z.array(ResponsesOutputTextSchema)]),
|
|
89
|
+
});
|
|
90
|
+
const ResponsesSystemMessageSchema = ResponsesMessageItemBaseSchema.extend({
|
|
91
|
+
role: z.literal("system"),
|
|
92
|
+
content: z.union([z.string(), z.array(ResponsesInputContentSchema)]),
|
|
93
|
+
});
|
|
94
|
+
const ResponsesDeveloperMessageSchema = ResponsesMessageItemBaseSchema.extend({
|
|
95
|
+
role: z.literal("developer"),
|
|
96
|
+
content: z.union([z.string(), z.array(ResponsesInputContentSchema)]),
|
|
97
|
+
});
|
|
98
|
+
export const ResponsesMessageItemSchema = z.discriminatedUnion("role", [
|
|
99
|
+
ResponsesUserMessageSchema,
|
|
100
|
+
ResponsesAssistantMessageSchema,
|
|
101
|
+
ResponsesSystemMessageSchema,
|
|
102
|
+
ResponsesDeveloperMessageSchema,
|
|
103
|
+
]);
|
|
104
|
+
/**
|
|
105
|
+
* --- Function ---
|
|
106
|
+
*/
|
|
107
|
+
export const ResponsesFunctionCallSchema = z.object({
|
|
108
|
+
type: z.literal("function_call"),
|
|
109
|
+
id: z.string().optional(),
|
|
110
|
+
call_id: z.string(),
|
|
111
|
+
name: z.string(),
|
|
112
|
+
arguments: z.string(),
|
|
113
|
+
status: ResponsesItemStatusSchema.optional(),
|
|
114
|
+
// Extension origin: Gemini
|
|
115
|
+
extra_content: ResponsesProviderMetadataSchema.optional().meta({ extension: true }),
|
|
116
|
+
// Extension origin: Anthropic/OpenRouter/Vercel
|
|
117
|
+
cache_control: ResponsesCacheControlSchema.optional().meta({ extension: true }),
|
|
118
|
+
});
|
|
119
|
+
export const ResponsesFunctionCallOutputSchema = z.object({
|
|
120
|
+
type: z.literal("function_call_output"),
|
|
121
|
+
id: z.string().optional(),
|
|
122
|
+
call_id: z.string(),
|
|
123
|
+
output: z.union([z.string(), z.array(ResponsesInputContentSchema)]),
|
|
124
|
+
status: ResponsesItemStatusSchema.optional(),
|
|
125
|
+
// Extension origin: Gemini
|
|
126
|
+
extra_content: ResponsesProviderMetadataSchema.optional().meta({ extension: true }),
|
|
127
|
+
// Extension origin: Anthropic/OpenRouter/Vercel
|
|
128
|
+
cache_control: ResponsesCacheControlSchema.optional().meta({ extension: true }),
|
|
129
|
+
});
|
|
130
|
+
/**
|
|
131
|
+
* --- Reasoning ---
|
|
132
|
+
*/
|
|
133
|
+
export const ResponsesSummaryTextSchema = z.object({
|
|
134
|
+
type: z.literal("summary_text"),
|
|
135
|
+
text: z.string(),
|
|
136
|
+
});
|
|
137
|
+
export const ResponsesReasoningTextSchema = z.object({
|
|
138
|
+
type: z.literal("reasoning_text"),
|
|
139
|
+
text: z.string(),
|
|
140
|
+
});
|
|
141
|
+
export const ResponsesReasoningItemSchema = z.object({
|
|
142
|
+
type: z.literal("reasoning"),
|
|
143
|
+
id: z.string().optional(),
|
|
144
|
+
summary: z.array(ResponsesSummaryTextSchema),
|
|
145
|
+
content: z.array(ResponsesReasoningTextSchema).optional(),
|
|
146
|
+
encrypted_content: z.string().optional(),
|
|
147
|
+
status: ResponsesItemStatusSchema.optional(),
|
|
148
|
+
// Extension origin: Gemini
|
|
149
|
+
extra_content: ResponsesProviderMetadataSchema.optional().meta({ extension: true }),
|
|
150
|
+
});
|
|
151
|
+
/**
|
|
152
|
+
* --- Input Items ---
|
|
153
|
+
*/
|
|
154
|
+
export const ResponsesInputItemSchema = z.discriminatedUnion("type", [
|
|
155
|
+
ResponsesMessageItemSchema,
|
|
156
|
+
ResponsesFunctionCallSchema,
|
|
157
|
+
ResponsesFunctionCallOutputSchema,
|
|
158
|
+
ResponsesReasoningItemSchema,
|
|
159
|
+
]);
|
|
160
|
+
import { CacheControlSchema as ResponsesCacheControlSchema, ReasoningEffortSchema as ResponsesReasoningEffortSchema, ReasoningConfigSchema as ResponsesReasoningConfigSchema, ServiceTierSchema as ResponsesServiceTierSchema, ProviderMetadataSchema as ResponsesProviderMetadataSchema, ContentPartAudioSchema as ResponsesInputAudioSchema, } from "../shared/schema";
|
|
161
|
+
export { ResponsesCacheControlSchema, ResponsesReasoningEffortSchema, ResponsesReasoningConfigSchema, ResponsesServiceTierSchema, ResponsesProviderMetadataSchema, ResponsesInputAudioSchema, };
|
|
162
|
+
/**
|
|
163
|
+
* --- Tools ---
|
|
164
|
+
*/
|
|
165
|
+
export const ResponsesToolSchema = z.object({
|
|
166
|
+
type: z.literal("function"),
|
|
167
|
+
name: z.string(),
|
|
168
|
+
description: z.string().optional(),
|
|
169
|
+
parameters: z.record(z.string(), z.unknown()),
|
|
170
|
+
strict: z.boolean().optional(),
|
|
171
|
+
});
|
|
172
|
+
const ResponsesNamedFunctionToolChoiceSchema = z.object({
|
|
173
|
+
type: z.literal("function"),
|
|
174
|
+
name: z.string(),
|
|
175
|
+
});
|
|
176
|
+
const ResponsesAllowedFunctionToolChoiceSchema = z.object({
|
|
177
|
+
type: z.literal("allowed_tools"),
|
|
178
|
+
allowed_tools: z.object({
|
|
179
|
+
mode: z.enum(["none", "auto", "required"]),
|
|
180
|
+
tools: z.array(ResponsesNamedFunctionToolChoiceSchema).nonempty(),
|
|
181
|
+
}),
|
|
182
|
+
});
|
|
183
|
+
export const ResponsesToolChoiceSchema = z.union([
|
|
184
|
+
z.enum(["none", "auto", "required", "validated"]),
|
|
185
|
+
ResponsesNamedFunctionToolChoiceSchema,
|
|
186
|
+
ResponsesAllowedFunctionToolChoiceSchema,
|
|
187
|
+
]);
|
|
188
|
+
/**
|
|
189
|
+
* --- Text Output Config ---
|
|
190
|
+
*/
|
|
191
|
+
export const ResponsesTextFormatJsonSchema = z.object({
|
|
192
|
+
// FUTURE: Consider support for legacy json_object (if demand)
|
|
193
|
+
type: z.literal("json_schema"),
|
|
194
|
+
name: z.string(),
|
|
195
|
+
description: z.string().optional(),
|
|
196
|
+
schema: z.record(z.string(), z.unknown()),
|
|
197
|
+
strict: z.boolean().optional(),
|
|
198
|
+
});
|
|
199
|
+
export const ResponsesTextFormatTextSchema = z.object({
|
|
200
|
+
type: z.literal("text"),
|
|
201
|
+
});
|
|
202
|
+
export const ResponsesTextFormatSchema = z.discriminatedUnion("type", [
|
|
203
|
+
ResponsesTextFormatJsonSchema,
|
|
204
|
+
ResponsesTextFormatTextSchema,
|
|
205
|
+
]);
|
|
206
|
+
export const ResponsesTextConfigSchema = z.object({
|
|
207
|
+
format: ResponsesTextFormatSchema.optional(),
|
|
208
|
+
// FUTURE: Support verbosity configuration
|
|
209
|
+
// verbosity: z.enum(["low", "medium", "high"]).optional(),
|
|
210
|
+
});
|
|
211
|
+
/**
|
|
212
|
+
* --- Request Body ---
|
|
213
|
+
*/
|
|
214
|
+
const ResponsesInputsSchema = z.object({
|
|
215
|
+
input: z.union([z.string(), z.array(ResponsesInputItemSchema)]),
|
|
216
|
+
instructions: z.string().optional(),
|
|
217
|
+
tools: z.array(ResponsesToolSchema).optional(),
|
|
218
|
+
tool_choice: ResponsesToolChoiceSchema.optional(),
|
|
219
|
+
max_tool_calls: z.number().int().nonnegative().optional(),
|
|
220
|
+
text: ResponsesTextConfigSchema.optional(),
|
|
221
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
222
|
+
top_p: z.number().min(0).max(1.0).optional(),
|
|
223
|
+
frequency_penalty: z.number().min(-2.0).max(2.0).optional(),
|
|
224
|
+
presence_penalty: z.number().min(-2.0).max(2.0).optional(),
|
|
225
|
+
max_output_tokens: z.number().int().nonnegative().optional(),
|
|
226
|
+
reasoning: ResponsesReasoningConfigSchema.optional(),
|
|
227
|
+
prompt_cache_key: z.string().optional(),
|
|
228
|
+
metadata: ResponsesMetadataSchema,
|
|
229
|
+
service_tier: ResponsesServiceTierSchema.optional(),
|
|
230
|
+
parallel_tool_calls: z.boolean().optional(),
|
|
231
|
+
// FUTURE: Open Responses API orchestration configurations
|
|
232
|
+
// previous_response_id: z.string().optional(),
|
|
233
|
+
// conversation: z.union([z.string(), z.object({ id: z.string() })]).optional(),
|
|
234
|
+
// context_management: z.array(z.object({ type: z.literal("compaction"), compact_threshold: z.number().optional() })).optional(),
|
|
235
|
+
// prompt: z.object({ id: z.string(), variables: z.record(z.any()).optional(), version: z.string().optional() }).optional(),
|
|
236
|
+
// phase: z.enum(["commentary", "final_answer"]).optional(),
|
|
237
|
+
// safety_identifier: z.string().optional(),
|
|
238
|
+
// truncation: z.enum(["auto", "disabled"]).optional(),
|
|
239
|
+
// store: z.boolean().optional(),
|
|
240
|
+
// background: z.boolean().optional(),
|
|
241
|
+
// top_logprobs: z.number().int().optional(),
|
|
242
|
+
// include: z.array(z.string()).optional(),
|
|
243
|
+
// stream_options: z.object({ include_obfuscation: z.boolean().optional() }).optional(),
|
|
244
|
+
// Extension origin: OpenRouter/Vercel/Anthropic
|
|
245
|
+
cache_control: ResponsesCacheControlSchema.optional().meta({ extension: true }),
|
|
246
|
+
// Extension origin: OpenRouter
|
|
247
|
+
reasoning_effort: ResponsesReasoningEffortSchema.optional().meta({ extension: true }),
|
|
248
|
+
// Extension origin: Gemini extra_body
|
|
249
|
+
extra_body: ResponsesProviderMetadataSchema.optional().meta({ extension: true }),
|
|
250
|
+
});
|
|
251
|
+
export const ResponsesBodySchema = z.object({
|
|
252
|
+
model: z.string(),
|
|
253
|
+
stream: z.boolean().optional(),
|
|
254
|
+
...ResponsesInputsSchema.shape,
|
|
255
|
+
});
|
|
256
|
+
/**
|
|
257
|
+
* --- Output Items ---
|
|
258
|
+
*/
|
|
259
|
+
export const ResponsesOutputMessageSchema = z.object({
|
|
260
|
+
type: z.literal("message"),
|
|
261
|
+
id: z.string(),
|
|
262
|
+
role: z.literal("assistant"),
|
|
263
|
+
status: z.enum(["in_progress", "completed", "incomplete"]),
|
|
264
|
+
content: z.array(ResponsesOutputTextSchema),
|
|
265
|
+
// Extension origin: Gemini
|
|
266
|
+
extra_content: ResponsesProviderMetadataSchema.optional().meta({ extension: true }),
|
|
267
|
+
});
|
|
268
|
+
export const ResponsesOutputItemSchema = z.discriminatedUnion("type", [
|
|
269
|
+
ResponsesOutputMessageSchema,
|
|
270
|
+
ResponsesFunctionCallSchema,
|
|
271
|
+
ResponsesReasoningItemSchema,
|
|
272
|
+
]);
|
|
273
|
+
/**
|
|
274
|
+
* --- Response Usage ---
|
|
275
|
+
*/
|
|
276
|
+
export const ResponsesUsageSchema = z.object({
|
|
277
|
+
input_tokens: z.number().int().nonnegative(),
|
|
278
|
+
output_tokens: z.number().int().nonnegative(),
|
|
279
|
+
total_tokens: z.number().int().nonnegative(),
|
|
280
|
+
input_tokens_details: z
|
|
281
|
+
.object({
|
|
282
|
+
cached_tokens: z.number().int().nonnegative().optional(),
|
|
283
|
+
})
|
|
284
|
+
.optional(),
|
|
285
|
+
output_tokens_details: z
|
|
286
|
+
.object({
|
|
287
|
+
reasoning_tokens: z.number().int().nonnegative().optional(),
|
|
288
|
+
})
|
|
289
|
+
.optional(),
|
|
290
|
+
});
|
|
291
|
+
/**
|
|
292
|
+
* --- Response Object ---
|
|
293
|
+
*/
|
|
294
|
+
export const ResponsesStatusSchema = z.enum(["in_progress", "completed", "failed", "incomplete"]);
|
|
295
|
+
export const ResponsesSchema = z.object({
|
|
296
|
+
id: z.string(),
|
|
297
|
+
object: z.literal("response"),
|
|
298
|
+
status: ResponsesStatusSchema,
|
|
299
|
+
model: z.string(),
|
|
300
|
+
output: z.array(ResponsesOutputItemSchema),
|
|
301
|
+
usage: ResponsesUsageSchema.nullable(),
|
|
302
|
+
incomplete_details: z
|
|
303
|
+
.object({
|
|
304
|
+
reason: z.string(),
|
|
305
|
+
})
|
|
306
|
+
.nullable()
|
|
307
|
+
.optional(),
|
|
308
|
+
created_at: z.number().int(),
|
|
309
|
+
completed_at: z.number().int().nullable(),
|
|
310
|
+
service_tier: ResponsesServiceTierSchema.optional(),
|
|
311
|
+
metadata: ResponsesMetadataSchema,
|
|
312
|
+
// Extension origin: Vercel AI Gateway
|
|
313
|
+
provider_metadata: ResponsesProviderMetadataSchema.optional().meta({ extension: true }),
|
|
314
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { SharedV3ProviderMetadata, SharedV3ProviderOptions } from "@ai-sdk/provider";
|
|
2
|
+
import { type JSONValue, type ToolSet, type ModelMessage, type ToolChoice, type Output, type StopCondition } from "ai";
|
|
3
|
+
import type { ReasoningConfig, ReasoningEffort, CacheControl, ServiceTier } from "./schema";
|
|
4
|
+
export type ToolChoiceOptions = {
|
|
5
|
+
toolChoice?: ToolChoice<ToolSet>;
|
|
6
|
+
activeTools?: string[];
|
|
7
|
+
};
|
|
8
|
+
export type TextCallOptions = {
|
|
9
|
+
messages: ModelMessage[];
|
|
10
|
+
tools?: ToolSet;
|
|
11
|
+
toolChoice?: ToolChoice<ToolSet>;
|
|
12
|
+
activeTools?: string[];
|
|
13
|
+
output?: Output.Output;
|
|
14
|
+
temperature?: number;
|
|
15
|
+
maxOutputTokens?: number;
|
|
16
|
+
frequencyPenalty?: number;
|
|
17
|
+
presencePenalty?: number;
|
|
18
|
+
seed?: number;
|
|
19
|
+
topP?: number;
|
|
20
|
+
stopSequences?: string[];
|
|
21
|
+
stopWhen?: StopCondition<ToolSet> | Array<StopCondition<ToolSet>>;
|
|
22
|
+
providerOptions: SharedV3ProviderOptions;
|
|
23
|
+
};
|
|
24
|
+
export declare function parseJsonOrText(content: string): {
|
|
25
|
+
type: "json";
|
|
26
|
+
value: JSONValue;
|
|
27
|
+
} | {
|
|
28
|
+
type: "text";
|
|
29
|
+
value: string;
|
|
30
|
+
};
|
|
31
|
+
export declare function parseBase64(base64: string): Uint8Array;
|
|
32
|
+
export declare function parseImageInput(url: string): {
|
|
33
|
+
image: string | URL;
|
|
34
|
+
mediaType?: string;
|
|
35
|
+
};
|
|
36
|
+
export declare function parseReasoningOptions(reasoning_effort?: ReasoningEffort, reasoning?: ReasoningConfig): {
|
|
37
|
+
reasoning: ReasoningConfig;
|
|
38
|
+
reasoning_effort?: ReasoningEffort;
|
|
39
|
+
} | {
|
|
40
|
+
reasoning: {
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
};
|
|
43
|
+
reasoning_effort: string;
|
|
44
|
+
} | {
|
|
45
|
+
reasoning?: undefined;
|
|
46
|
+
reasoning_effort?: undefined;
|
|
47
|
+
};
|
|
48
|
+
export declare function parsePromptCachingOptions(prompt_cache_key?: string, prompt_cache_retention?: "in-memory" | "24h", cache_control?: CacheControl): Record<string, unknown>;
|
|
49
|
+
export declare function resolveResponseServiceTier(providerMetadata?: SharedV3ProviderMetadata): ServiceTier | undefined;
|
|
50
|
+
export declare function normalizeToolName(name: string): string;
|
|
51
|
+
export declare function stripEmptyKeys(obj: unknown): unknown;
|
|
52
|
+
export declare function extractReasoningMetadata(providerMetadata?: SharedV3ProviderMetadata): {
|
|
53
|
+
redactedData?: string;
|
|
54
|
+
signature?: string;
|
|
55
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import {} from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { GatewayError } from "../../errors/gateway";
|
|
4
|
+
import { parseDataUrl } from "../../utils/url";
|
|
5
|
+
export function parseJsonOrText(content) {
|
|
6
|
+
try {
|
|
7
|
+
return { type: "json", value: JSON.parse(content) };
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return { type: "text", value: content };
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function parseBase64(base64) {
|
|
14
|
+
try {
|
|
15
|
+
return z.util.base64ToUint8Array(base64);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
throw new GatewayError("Invalid base64 data", 400, undefined, error);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function parseImageInput(url) {
|
|
22
|
+
const dataPrefix = "data:";
|
|
23
|
+
if (url.startsWith(dataPrefix)) {
|
|
24
|
+
const { mimeType, dataStart } = parseDataUrl(url);
|
|
25
|
+
if (!mimeType || dataStart <= dataPrefix.length || dataStart >= url.length) {
|
|
26
|
+
throw new GatewayError("Invalid data URL", 400);
|
|
27
|
+
}
|
|
28
|
+
if (!mimeType.startsWith("image/")) {
|
|
29
|
+
throw new GatewayError(`Unsupported image media type: ${mimeType}`, 400);
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
image: url.slice(dataStart),
|
|
33
|
+
mediaType: mimeType,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
return { image: new URL(url) };
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
throw new GatewayError("Invalid image URL", 400, undefined, error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function parseReasoningOptions(reasoning_effort, reasoning) {
|
|
44
|
+
const effort = reasoning?.effort ?? reasoning_effort;
|
|
45
|
+
const max_tokens = reasoning?.max_tokens;
|
|
46
|
+
if (reasoning?.enabled === false || effort === "none") {
|
|
47
|
+
return { reasoning: { enabled: false }, reasoning_effort: "none" };
|
|
48
|
+
}
|
|
49
|
+
if (!reasoning && effort === undefined)
|
|
50
|
+
return {};
|
|
51
|
+
const out = { reasoning: {} };
|
|
52
|
+
if (effort) {
|
|
53
|
+
out.reasoning.enabled = true;
|
|
54
|
+
out.reasoning.effort = effort;
|
|
55
|
+
out.reasoning_effort = effort;
|
|
56
|
+
}
|
|
57
|
+
if (max_tokens) {
|
|
58
|
+
out.reasoning.enabled = true;
|
|
59
|
+
out.reasoning.max_tokens = max_tokens;
|
|
60
|
+
}
|
|
61
|
+
if (out.reasoning.enabled) {
|
|
62
|
+
out.reasoning.exclude = reasoning?.exclude;
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
export function parsePromptCachingOptions(prompt_cache_key, prompt_cache_retention, cache_control) {
|
|
67
|
+
const out = {};
|
|
68
|
+
let retention = prompt_cache_retention;
|
|
69
|
+
if (!retention && cache_control?.ttl) {
|
|
70
|
+
retention = cache_control.ttl === "24h" ? "24h" : "in-memory";
|
|
71
|
+
}
|
|
72
|
+
let control = cache_control;
|
|
73
|
+
if (!control && retention) {
|
|
74
|
+
control = {
|
|
75
|
+
type: "ephemeral",
|
|
76
|
+
ttl: retention === "24h" ? "24h" : "5m",
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (prompt_cache_key)
|
|
80
|
+
out["prompt_cache_key"] = prompt_cache_key;
|
|
81
|
+
if (retention)
|
|
82
|
+
out["prompt_cache_retention"] = retention;
|
|
83
|
+
if (control)
|
|
84
|
+
out["cache_control"] = control;
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
export function resolveResponseServiceTier(providerMetadata) {
|
|
88
|
+
if (!providerMetadata)
|
|
89
|
+
return;
|
|
90
|
+
for (const metadata of Object.values(providerMetadata)) {
|
|
91
|
+
const tier = parseReturnedServiceTier(metadata["service_tier"] ??
|
|
92
|
+
metadata["usage_metadata"]?.["traffic_type"]);
|
|
93
|
+
if (tier)
|
|
94
|
+
return tier;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function parseReturnedServiceTier(value) {
|
|
98
|
+
if (typeof value !== "string")
|
|
99
|
+
return undefined;
|
|
100
|
+
const n = value.toLowerCase();
|
|
101
|
+
switch (n) {
|
|
102
|
+
case "traffic_type_unspecified":
|
|
103
|
+
case "auto":
|
|
104
|
+
return "auto";
|
|
105
|
+
case "default":
|
|
106
|
+
case "on_demand":
|
|
107
|
+
case "on-demand":
|
|
108
|
+
case "shared":
|
|
109
|
+
return "default";
|
|
110
|
+
case "on_demand_flex":
|
|
111
|
+
case "flex":
|
|
112
|
+
return "flex";
|
|
113
|
+
case "on_demand_priority":
|
|
114
|
+
case "priority":
|
|
115
|
+
case "performance":
|
|
116
|
+
return "priority";
|
|
117
|
+
case "provisioned_throughput":
|
|
118
|
+
case "scale":
|
|
119
|
+
case "reserved":
|
|
120
|
+
case "dedicated":
|
|
121
|
+
case "provisioned":
|
|
122
|
+
case "throughput":
|
|
123
|
+
return "scale";
|
|
124
|
+
default:
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export function normalizeToolName(name) {
|
|
129
|
+
let out = "";
|
|
130
|
+
for (let i = 0; i < name.length; i++) {
|
|
131
|
+
if (out.length === 128)
|
|
132
|
+
break;
|
|
133
|
+
// oxlint-disable-next-line unicorn/prefer-code-point
|
|
134
|
+
const c = name.charCodeAt(i);
|
|
135
|
+
if ((c >= 48 && c <= 57) ||
|
|
136
|
+
(c >= 65 && c <= 90) ||
|
|
137
|
+
(c >= 97 && c <= 122) ||
|
|
138
|
+
c === 95 ||
|
|
139
|
+
c === 45 ||
|
|
140
|
+
c === 46) {
|
|
141
|
+
out += name[i];
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
out += "_";
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
export function stripEmptyKeys(obj) {
|
|
150
|
+
if (!obj || typeof obj !== "object" || Array.isArray(obj))
|
|
151
|
+
return obj;
|
|
152
|
+
if ("" in obj) {
|
|
153
|
+
obj[""] = undefined;
|
|
154
|
+
}
|
|
155
|
+
return obj;
|
|
156
|
+
}
|
|
157
|
+
export function extractReasoningMetadata(providerMetadata) {
|
|
158
|
+
if (!providerMetadata)
|
|
159
|
+
return {};
|
|
160
|
+
for (const metadata of Object.values(providerMetadata)) {
|
|
161
|
+
if (metadata && typeof metadata === "object") {
|
|
162
|
+
let redactedData;
|
|
163
|
+
let signature;
|
|
164
|
+
let found = false;
|
|
165
|
+
if ("redactedData" in metadata && typeof metadata["redactedData"] === "string") {
|
|
166
|
+
redactedData = metadata["redactedData"];
|
|
167
|
+
found = true;
|
|
168
|
+
}
|
|
169
|
+
if ("signature" in metadata && typeof metadata["signature"] === "string") {
|
|
170
|
+
signature = metadata["signature"];
|
|
171
|
+
found = true;
|
|
172
|
+
}
|
|
173
|
+
if (found) {
|
|
174
|
+
return { redactedData, signature };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return {};
|
|
179
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { SharedV3ProviderMetadata } from "@ai-sdk/provider";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Shared Open Responses item schemas used by both /conversations and /responses.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* --- Metadata ---
|
|
8
|
+
*/
|
|
9
|
+
export declare const CacheControlSchema: z.ZodObject<{
|
|
10
|
+
type: z.ZodLiteral<"ephemeral">;
|
|
11
|
+
ttl: z.ZodOptional<z.ZodString>;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
export type CacheControl = z.infer<typeof CacheControlSchema>;
|
|
14
|
+
export declare const ProviderMetadataSchema: z.ZodType<SharedV3ProviderMetadata>;
|
|
15
|
+
export type ProviderMetadata = SharedV3ProviderMetadata;
|
|
16
|
+
export declare const ReasoningEffortSchema: z.ZodEnum<{
|
|
17
|
+
none: "none";
|
|
18
|
+
minimal: "minimal";
|
|
19
|
+
low: "low";
|
|
20
|
+
medium: "medium";
|
|
21
|
+
high: "high";
|
|
22
|
+
xhigh: "xhigh";
|
|
23
|
+
}>;
|
|
24
|
+
export type ReasoningEffort = z.infer<typeof ReasoningEffortSchema>;
|
|
25
|
+
export declare const ReasoningConfigSchema: z.ZodObject<{
|
|
26
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
+
effort: z.ZodOptional<z.ZodEnum<{
|
|
28
|
+
none: "none";
|
|
29
|
+
minimal: "minimal";
|
|
30
|
+
low: "low";
|
|
31
|
+
medium: "medium";
|
|
32
|
+
high: "high";
|
|
33
|
+
xhigh: "xhigh";
|
|
34
|
+
}>>;
|
|
35
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
36
|
+
exclude: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
+
}, z.core.$strip>;
|
|
38
|
+
export type ReasoningConfig = z.infer<typeof ReasoningConfigSchema>;
|
|
39
|
+
export declare const ServiceTierSchema: z.ZodEnum<{
|
|
40
|
+
default: "default";
|
|
41
|
+
auto: "auto";
|
|
42
|
+
flex: "flex";
|
|
43
|
+
scale: "scale";
|
|
44
|
+
priority: "priority";
|
|
45
|
+
}>;
|
|
46
|
+
export type ServiceTier = z.infer<typeof ServiceTierSchema>;
|
|
47
|
+
export declare const ContentPartAudioSchema: z.ZodObject<{
|
|
48
|
+
type: z.ZodLiteral<"input_audio">;
|
|
49
|
+
input_audio: z.ZodObject<{
|
|
50
|
+
data: z.ZodString;
|
|
51
|
+
format: z.ZodEnum<{
|
|
52
|
+
"x-aac": "x-aac";
|
|
53
|
+
flac: "flac";
|
|
54
|
+
mp3: "mp3";
|
|
55
|
+
m4a: "m4a";
|
|
56
|
+
mpeg: "mpeg";
|
|
57
|
+
mpga: "mpga";
|
|
58
|
+
mp4: "mp4";
|
|
59
|
+
ogg: "ogg";
|
|
60
|
+
pcm: "pcm";
|
|
61
|
+
wav: "wav";
|
|
62
|
+
webm: "webm";
|
|
63
|
+
}>;
|
|
64
|
+
}, z.core.$strip>;
|
|
65
|
+
cache_control: z.ZodOptional<z.ZodObject<{
|
|
66
|
+
type: z.ZodLiteral<"ephemeral">;
|
|
67
|
+
ttl: z.ZodOptional<z.ZodString>;
|
|
68
|
+
}, z.core.$strip>>;
|
|
69
|
+
}, z.core.$strip>;
|
|
70
|
+
export type ContentPartAudio = z.infer<typeof ContentPartAudioSchema>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Shared Open Responses item schemas used by both /conversations and /responses.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* --- Metadata ---
|
|
7
|
+
*/
|
|
8
|
+
// Note: The 16-key limit is not currently validated.
|
|
9
|
+
export const CacheControlSchema = z.object({
|
|
10
|
+
type: z.literal("ephemeral"),
|
|
11
|
+
ttl: z.string().optional(),
|
|
12
|
+
});
|
|
13
|
+
export const ProviderMetadataSchema = z.record(z.string(), z.record(z.string(), z.any()));
|
|
14
|
+
export const ReasoningEffortSchema = z.enum(["none", "minimal", "low", "medium", "high", "xhigh"]);
|
|
15
|
+
export const ReasoningConfigSchema = z.object({
|
|
16
|
+
enabled: z.optional(z.boolean()),
|
|
17
|
+
effort: z.optional(ReasoningEffortSchema),
|
|
18
|
+
max_tokens: z.optional(z.number()),
|
|
19
|
+
exclude: z.optional(z.boolean()),
|
|
20
|
+
});
|
|
21
|
+
export const ServiceTierSchema = z.enum(["auto", "default", "flex", "scale", "priority"]);
|
|
22
|
+
const InputAudioFormatSchema = z.enum([
|
|
23
|
+
"x-aac",
|
|
24
|
+
"flac",
|
|
25
|
+
"mp3",
|
|
26
|
+
"m4a",
|
|
27
|
+
"mpeg",
|
|
28
|
+
"mpga",
|
|
29
|
+
"mp4",
|
|
30
|
+
"ogg",
|
|
31
|
+
"pcm",
|
|
32
|
+
"wav",
|
|
33
|
+
"webm",
|
|
34
|
+
]);
|
|
35
|
+
const InputAudioSchema = z.object({
|
|
36
|
+
data: z.string(),
|
|
37
|
+
// only wav and mp3 are official by OpenAI, rest is taken from Gemini support:
|
|
38
|
+
// https://docs.cloud.google.com/vertex-ai/generative-ai/docs/multimodal/audio-understanding
|
|
39
|
+
format: InputAudioFormatSchema,
|
|
40
|
+
});
|
|
41
|
+
export const ContentPartAudioSchema = z.object({
|
|
42
|
+
type: z.literal("input_audio"),
|
|
43
|
+
input_audio: InputAudioSchema,
|
|
44
|
+
// Extension origin: OpenRouter/Vercel/Anthropic
|
|
45
|
+
cache_control: CacheControlSchema.optional().meta({ extension: true }),
|
|
46
|
+
});
|
package/dist/gateway.d.ts
CHANGED
package/dist/gateway.js
CHANGED
|
@@ -3,6 +3,7 @@ import { chatCompletions } from "./endpoints/chat-completions/handler";
|
|
|
3
3
|
import { conversations } from "./endpoints/conversations/handler";
|
|
4
4
|
import { embeddings } from "./endpoints/embeddings/handler";
|
|
5
5
|
import { models } from "./endpoints/models/handler";
|
|
6
|
+
import { responses } from "./endpoints/responses/handler";
|
|
6
7
|
import { GatewayError } from "./errors/gateway";
|
|
7
8
|
import { winterCgHandler } from "./lifecycle";
|
|
8
9
|
import { logger } from "./logger";
|
|
@@ -18,6 +19,7 @@ export function gateway(config) {
|
|
|
18
19
|
["/embeddings"]: embeddings(parsedConfig),
|
|
19
20
|
["/models"]: models(parsedConfig),
|
|
20
21
|
["/conversations"]: conversations(parsedConfig),
|
|
22
|
+
["/responses"]: responses(parsedConfig),
|
|
21
23
|
};
|
|
22
24
|
const routeEntries = Object.entries(routes);
|
|
23
25
|
const handler = (req, state) => {
|