@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.
Files changed (40) hide show
  1. package/README.md +131 -32
  2. package/dist/endpoints/chat-completions/converters.d.ts +4 -21
  3. package/dist/endpoints/chat-completions/converters.js +23 -160
  4. package/dist/endpoints/chat-completions/handler.js +2 -2
  5. package/dist/endpoints/chat-completions/schema.d.ts +45 -101
  6. package/dist/endpoints/chat-completions/schema.js +13 -69
  7. package/dist/endpoints/conversations/converters.js +2 -3
  8. package/dist/endpoints/conversations/schema.d.ts +506 -644
  9. package/dist/endpoints/conversations/schema.js +8 -159
  10. package/dist/endpoints/conversations/storage/dialects/greptime.js +4 -2
  11. package/dist/endpoints/conversations/storage/dialects/mysql.js +3 -1
  12. package/dist/endpoints/conversations/storage/dialects/postgres.js +6 -3
  13. package/dist/endpoints/conversations/storage/dialects/sqlite.js +3 -1
  14. package/dist/endpoints/conversations/storage/sql.js +11 -6
  15. package/dist/endpoints/embeddings/handler.js +1 -1
  16. package/dist/endpoints/responses/converters.d.ts +17 -0
  17. package/dist/endpoints/responses/converters.js +1034 -0
  18. package/dist/endpoints/responses/handler.d.ts +2 -0
  19. package/dist/endpoints/responses/handler.js +137 -0
  20. package/dist/endpoints/responses/index.d.ts +4 -0
  21. package/dist/endpoints/responses/index.js +4 -0
  22. package/dist/endpoints/responses/otel.d.ts +6 -0
  23. package/dist/endpoints/responses/otel.js +221 -0
  24. package/dist/endpoints/responses/schema.d.ts +2109 -0
  25. package/dist/endpoints/responses/schema.js +314 -0
  26. package/dist/endpoints/shared/converters.d.ts +55 -0
  27. package/dist/endpoints/shared/converters.js +179 -0
  28. package/dist/endpoints/shared/schema.d.ts +70 -0
  29. package/dist/endpoints/shared/schema.js +46 -0
  30. package/dist/gateway.d.ts +1 -0
  31. package/dist/gateway.js +2 -0
  32. package/dist/index.d.ts +0 -4
  33. package/dist/index.js +0 -4
  34. package/dist/lifecycle.js +46 -29
  35. package/dist/models/anthropic/middleware.d.ts +1 -1
  36. package/dist/models/google/middleware.d.ts +1 -1
  37. package/dist/providers/registry.d.ts +1 -1
  38. package/dist/types.d.ts +18 -6
  39. package/dist/utils/preset.js +0 -1
  40. 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
@@ -6,5 +6,6 @@ export declare function gateway(config: GatewayConfig): {
6
6
  readonly "/embeddings": Endpoint;
7
7
  readonly "/models": Endpoint;
8
8
  readonly "/conversations": Endpoint;
9
+ readonly "/responses": Endpoint;
9
10
  };
10
11
  };
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) => {