@hebo-ai/gateway 0.1.2 → 0.2.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 +172 -67
- package/dist/config.js +2 -12
- package/dist/endpoints/chat-completions/converters.d.ts +28 -24
- package/dist/endpoints/chat-completions/converters.js +99 -73
- package/dist/endpoints/chat-completions/handler.js +36 -30
- package/dist/endpoints/chat-completions/schema.d.ts +394 -272
- package/dist/endpoints/chat-completions/schema.js +124 -57
- package/dist/endpoints/embeddings/converters.d.ts +4 -4
- package/dist/endpoints/embeddings/converters.js +8 -9
- package/dist/endpoints/embeddings/handler.js +32 -26
- package/dist/endpoints/embeddings/schema.d.ts +28 -38
- package/dist/endpoints/embeddings/schema.js +10 -10
- package/dist/endpoints/models/converters.d.ts +2 -2
- package/dist/endpoints/models/converters.js +9 -12
- package/dist/endpoints/models/handler.js +8 -9
- package/dist/endpoints/models/schema.d.ts +37 -31
- package/dist/endpoints/models/schema.js +23 -12
- package/dist/gateway.d.ts +8 -9
- package/dist/gateway.js +7 -10
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/lifecycle.d.ts +2 -0
- package/dist/{utils/hooks.js → lifecycle.js} +16 -8
- package/dist/middleware/common.d.ts +4 -0
- package/dist/middleware/common.js +44 -0
- package/dist/middleware/matcher.d.ts +18 -0
- package/dist/middleware/matcher.js +83 -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 +2 -0
- package/dist/models/amazon/middleware.js +20 -0
- package/dist/models/amazon/presets.d.ts +2390 -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 +67 -0
- package/dist/models/anthropic/presets.d.ts +4106 -0
- package/dist/models/anthropic/presets.js +113 -0
- package/dist/models/catalog.d.ts +3 -1
- package/dist/models/catalog.js +3 -2
- package/dist/models/cohere/index.d.ts +2 -0
- package/dist/models/cohere/index.js +2 -0
- package/dist/models/cohere/middleware.d.ts +2 -0
- package/dist/models/cohere/middleware.js +18 -0
- package/dist/models/cohere/presets.d.ts +2918 -0
- package/dist/models/cohere/presets.js +129 -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 +2 -0
- package/dist/models/google/middleware.js +20 -0
- package/dist/models/{presets/gemini.d.ts → google/presets.d.ts} +400 -174
- package/dist/models/{presets/gemini.js → google/presets.js} +20 -5
- package/dist/models/meta/index.d.ts +1 -0
- package/dist/models/meta/index.js +1 -0
- package/dist/models/meta/presets.d.ts +3254 -0
- package/dist/models/{presets/llama.js → meta/presets.js} +44 -7
- package/dist/models/openai/index.d.ts +2 -0
- package/dist/models/openai/index.js +2 -0
- package/dist/models/openai/middleware.d.ts +2 -0
- package/dist/models/openai/middleware.js +20 -0
- package/dist/models/openai/presets.d.ts +6252 -0
- package/dist/models/openai/presets.js +206 -0
- package/dist/models/types.d.ts +3 -3
- package/dist/models/types.js +27 -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 +18 -0
- package/dist/models/{presets/voyage.d.ts → voyage/presets.d.ts} +322 -323
- 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 +15 -0
- package/dist/providers/{canonical/bedrock.js → bedrock/canonical.js} +13 -15
- package/dist/providers/bedrock/index.d.ts +1 -0
- package/dist/providers/bedrock/index.js +1 -0
- package/dist/providers/cohere/canonical.d.ts +3 -0
- package/dist/providers/{canonical/cohere.js → cohere/canonical.js} +6 -6
- 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 +1 -0
- package/dist/providers/groq/index.js +1 -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 +16 -26
- package/dist/providers/registry.js +19 -26
- package/dist/providers/types.d.ts +1 -1
- package/dist/providers/types.js +1 -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 +1 -0
- package/dist/providers/vertex/index.js +1 -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/types.d.ts +60 -30
- package/dist/utils/errors.js +2 -0
- package/dist/utils/preset.d.ts +1 -7
- package/dist/utils/preset.js +1 -1
- package/dist/utils/response.d.ts +1 -0
- package/dist/utils/response.js +10 -0
- package/package.json +79 -70
- package/src/config.ts +2 -18
- package/src/endpoints/chat-completions/converters.test.ts +39 -0
- package/src/endpoints/chat-completions/converters.ts +191 -112
- package/src/endpoints/chat-completions/handler.test.ts +47 -18
- package/src/endpoints/chat-completions/handler.ts +40 -34
- package/src/endpoints/chat-completions/schema.ts +161 -88
- package/src/endpoints/embeddings/converters.ts +15 -11
- package/src/endpoints/embeddings/handler.test.ts +27 -30
- package/src/endpoints/embeddings/handler.ts +34 -28
- package/src/endpoints/embeddings/schema.ts +10 -10
- package/src/endpoints/models/converters.ts +22 -14
- package/src/endpoints/models/handler.test.ts +26 -29
- package/src/endpoints/models/handler.ts +10 -12
- package/src/endpoints/models/schema.ts +26 -20
- package/src/gateway.ts +10 -24
- package/src/index.ts +3 -0
- package/src/{utils/hooks.ts → lifecycle.ts} +21 -11
- package/src/middleware/common.ts +68 -0
- package/src/middleware/matcher.ts +117 -0
- package/src/models/amazon/index.ts +2 -0
- package/src/models/amazon/middleware.ts +25 -0
- package/src/models/amazon/presets.ts +104 -0
- package/src/models/anthropic/index.ts +2 -0
- package/src/models/anthropic/middleware.test.ts +184 -0
- package/src/models/anthropic/middleware.ts +75 -0
- package/src/models/anthropic/presets.ts +161 -0
- package/src/models/catalog.ts +10 -2
- package/src/models/cohere/index.ts +2 -0
- package/src/models/cohere/middleware.ts +23 -0
- package/src/models/cohere/presets.ts +181 -0
- package/src/models/google/index.ts +2 -0
- package/src/models/google/middleware.ts +25 -0
- package/src/models/{presets/gemini.ts → google/presets.ts} +25 -5
- package/src/models/meta/index.ts +1 -0
- package/src/models/{presets/llama.ts → meta/presets.ts} +68 -7
- package/src/models/openai/index.ts +2 -0
- package/src/models/openai/middleware.ts +25 -0
- package/src/models/openai/presets.ts +269 -0
- package/src/models/types.ts +29 -2
- package/src/models/voyage/index.ts +2 -0
- package/src/models/voyage/middleware.ts +23 -0
- package/src/providers/anthropic/canonical.ts +17 -0
- package/src/providers/anthropic/index.ts +1 -0
- package/src/providers/{canonical/bedrock.ts → bedrock/canonical.ts} +22 -32
- package/src/providers/bedrock/index.ts +1 -0
- package/src/providers/cohere/canonical.ts +26 -0
- package/src/providers/cohere/index.ts +1 -0
- package/src/providers/groq/canonical.ts +21 -0
- package/src/providers/groq/index.ts +1 -0
- package/src/providers/openai/canonical.ts +16 -0
- package/src/providers/openai/index.ts +1 -0
- package/src/providers/registry.test.ts +12 -10
- package/src/providers/registry.ts +43 -43
- package/src/providers/types.ts +1 -0
- package/src/providers/vertex/canonical.ts +17 -0
- package/src/providers/vertex/index.ts +1 -0
- package/src/providers/voyage/canonical.ts +16 -0
- package/src/providers/voyage/index.ts +1 -0
- package/src/types.ts +64 -28
- package/src/utils/errors.ts +2 -0
- package/src/utils/preset.ts +2 -6
- package/src/utils/response.ts +15 -0
- package/dist/models/presets/claude.d.ts +0 -1165
- package/dist/models/presets/claude.js +0 -40
- package/dist/models/presets/cohere.d.ts +0 -383
- package/dist/models/presets/cohere.js +0 -26
- package/dist/models/presets/gpt-oss.d.ts +0 -779
- package/dist/models/presets/gpt-oss.js +0 -40
- package/dist/models/presets/llama.d.ts +0 -1400
- package/dist/providers/canonical/anthropic.d.ts +0 -25
- package/dist/providers/canonical/anthropic.js +0 -14
- package/dist/providers/canonical/bedrock.d.ts +0 -26
- package/dist/providers/canonical/cohere.d.ts +0 -17
- package/dist/providers/canonical/groq.d.ts +0 -17
- package/dist/providers/canonical/groq.js +0 -10
- package/dist/providers/canonical/openai.d.ts +0 -17
- package/dist/providers/canonical/openai.js +0 -8
- package/dist/providers/canonical/vertex.d.ts +0 -17
- package/dist/providers/canonical/vertex.js +0 -10
- package/dist/providers/canonical/voyage.d.ts +0 -17
- package/dist/providers/canonical/voyage.js +0 -8
- package/dist/utils/hooks.d.ts +0 -2
- package/src/models/presets/claude.ts +0 -59
- package/src/models/presets/cohere.ts +0 -37
- package/src/models/presets/gpt-oss.ts +0 -55
- package/src/providers/canonical/anthropic.ts +0 -32
- package/src/providers/canonical/cohere.ts +0 -36
- package/src/providers/canonical/groq.ts +0 -25
- package/src/providers/canonical/openai.ts +0 -16
- package/src/providers/canonical/vertex.ts +0 -18
- package/src/providers/canonical/voyage.ts +0 -16
- package/dist/models/{presets/voyage.js → voyage/presets.js} +10 -10
- package/src/models/{presets/voyage.ts → voyage/presets.ts} +10 -10
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
import { jsonSchema, tool } from "ai";
|
|
1
|
+
import { jsonSchema, JsonToSseTransformStream, tool } from "ai";
|
|
2
2
|
import { OpenAIError } from "../../utils/errors";
|
|
3
|
+
import { mergeResponseInit } from "../../utils/response";
|
|
3
4
|
// --- Request Flow ---
|
|
4
|
-
export function
|
|
5
|
-
const { messages, tools, tool_choice, temperature
|
|
5
|
+
export function convertToTextCallOptions(params) {
|
|
6
|
+
const { messages, tools, tool_choice, temperature, max_tokens, max_completion_tokens, reasoning_effort, reasoning, frequency_penalty, presence_penalty, seed, stop, top_p, ...rest } = params;
|
|
6
7
|
return {
|
|
7
|
-
messages:
|
|
8
|
-
tools:
|
|
9
|
-
toolChoice:
|
|
8
|
+
messages: convertToModelMessages(messages),
|
|
9
|
+
tools: convertToToolSet(tools),
|
|
10
|
+
toolChoice: convertToToolChoice(tool_choice),
|
|
10
11
|
temperature,
|
|
12
|
+
maxOutputTokens: max_completion_tokens ?? max_tokens,
|
|
13
|
+
frequencyPenalty: frequency_penalty,
|
|
14
|
+
presencePenalty: presence_penalty,
|
|
15
|
+
seed,
|
|
16
|
+
stopSequences: stop ? (Array.isArray(stop) ? stop : [stop]) : undefined,
|
|
17
|
+
topP: top_p,
|
|
11
18
|
providerOptions: {
|
|
12
|
-
|
|
19
|
+
unknown: {
|
|
20
|
+
...rest,
|
|
21
|
+
...parseReasoningOptions(reasoning_effort, reasoning),
|
|
22
|
+
},
|
|
13
23
|
},
|
|
14
24
|
};
|
|
15
25
|
}
|
|
16
|
-
export function
|
|
26
|
+
export function convertToModelMessages(messages) {
|
|
17
27
|
const modelMessages = [];
|
|
18
28
|
const toolById = indexToolMessages(messages);
|
|
19
29
|
for (const message of messages) {
|
|
@@ -24,11 +34,11 @@ export function fromCompletionsMessages(messages) {
|
|
|
24
34
|
continue;
|
|
25
35
|
}
|
|
26
36
|
if (message.role === "user") {
|
|
27
|
-
modelMessages.push(
|
|
37
|
+
modelMessages.push(fromChatCompletionsUserMessage(message));
|
|
28
38
|
continue;
|
|
29
39
|
}
|
|
30
|
-
modelMessages.push(
|
|
31
|
-
const toolResult =
|
|
40
|
+
modelMessages.push(fromChatCompletionsAssistantMessage(message));
|
|
41
|
+
const toolResult = fromChatCompletionsToolResultMessage(message, toolById);
|
|
32
42
|
if (toolResult)
|
|
33
43
|
modelMessages.push(toolResult);
|
|
34
44
|
}
|
|
@@ -42,15 +52,15 @@ function indexToolMessages(messages) {
|
|
|
42
52
|
}
|
|
43
53
|
return map;
|
|
44
54
|
}
|
|
45
|
-
export function
|
|
55
|
+
export function fromChatCompletionsUserMessage(message) {
|
|
46
56
|
return {
|
|
47
57
|
role: "user",
|
|
48
58
|
content: Array.isArray(message.content)
|
|
49
|
-
?
|
|
59
|
+
? fromChatCompletionsContent(message.content)
|
|
50
60
|
: message.content,
|
|
51
61
|
};
|
|
52
62
|
}
|
|
53
|
-
export function
|
|
63
|
+
export function fromChatCompletionsAssistantMessage(message) {
|
|
54
64
|
const { tool_calls, role, content } = message;
|
|
55
65
|
if (!tool_calls || tool_calls.length === 0) {
|
|
56
66
|
return {
|
|
@@ -71,7 +81,7 @@ export function fromCompletionsAssistantMessage(message) {
|
|
|
71
81
|
}),
|
|
72
82
|
};
|
|
73
83
|
}
|
|
74
|
-
export function
|
|
84
|
+
export function fromChatCompletionsToolResultMessage(message, toolById) {
|
|
75
85
|
const toolCalls = message.tool_calls ?? [];
|
|
76
86
|
if (toolCalls.length === 0)
|
|
77
87
|
return undefined;
|
|
@@ -89,7 +99,7 @@ export function fromCompletionsToolResultMessage(message, toolById) {
|
|
|
89
99
|
}
|
|
90
100
|
return toolResultParts.length > 0 ? { role: "tool", content: toolResultParts } : undefined;
|
|
91
101
|
}
|
|
92
|
-
export function
|
|
102
|
+
export function fromChatCompletionsContent(content) {
|
|
93
103
|
return content.map((part) => {
|
|
94
104
|
if (part.type === "image_url") {
|
|
95
105
|
const url = part.image_url.url;
|
|
@@ -126,7 +136,7 @@ export function fromCompletionsContent(content) {
|
|
|
126
136
|
};
|
|
127
137
|
}
|
|
128
138
|
if (part.type === "file") {
|
|
129
|
-
|
|
139
|
+
let { data, media_type, filename } = part.file;
|
|
130
140
|
return media_type.startsWith("image/")
|
|
131
141
|
? {
|
|
132
142
|
type: "image",
|
|
@@ -136,13 +146,14 @@ export function fromCompletionsContent(content) {
|
|
|
136
146
|
: {
|
|
137
147
|
type: "file",
|
|
138
148
|
data: Buffer.from(data, "base64"),
|
|
149
|
+
filename,
|
|
139
150
|
mediaType: media_type,
|
|
140
151
|
};
|
|
141
152
|
}
|
|
142
153
|
return part;
|
|
143
154
|
});
|
|
144
155
|
}
|
|
145
|
-
export const
|
|
156
|
+
export const convertToToolSet = (tools) => {
|
|
146
157
|
if (!tools) {
|
|
147
158
|
return;
|
|
148
159
|
}
|
|
@@ -155,7 +166,7 @@ export const fromCompletionsTools = (tools) => {
|
|
|
155
166
|
}
|
|
156
167
|
return toolSet;
|
|
157
168
|
};
|
|
158
|
-
export const
|
|
169
|
+
export const convertToToolChoice = (toolChoice) => {
|
|
159
170
|
if (!toolChoice) {
|
|
160
171
|
return undefined;
|
|
161
172
|
}
|
|
@@ -175,9 +186,19 @@ function parseToolOutput(content) {
|
|
|
175
186
|
return { type: "text", value: content };
|
|
176
187
|
}
|
|
177
188
|
}
|
|
189
|
+
function parseReasoningOptions(reasoning_effort, reasoning) {
|
|
190
|
+
const reasoningOptions = {};
|
|
191
|
+
if (reasoning)
|
|
192
|
+
reasoningOptions["reasoning"] = reasoning;
|
|
193
|
+
if (reasoning_effort !== undefined) {
|
|
194
|
+
(reasoningOptions["reasoning"] ??= {})["effort"] = reasoning_effort;
|
|
195
|
+
reasoningOptions["reasoningEffort"] = reasoning_effort;
|
|
196
|
+
}
|
|
197
|
+
return reasoningOptions;
|
|
198
|
+
}
|
|
178
199
|
// --- Response Flow ---
|
|
179
|
-
export function
|
|
180
|
-
const finish_reason =
|
|
200
|
+
export function toChatCompletions(result, model) {
|
|
201
|
+
const finish_reason = toChatCompletionsFinishReason(result.finishReason);
|
|
181
202
|
return {
|
|
182
203
|
id: "chatcmpl-" + crypto.randomUUID(),
|
|
183
204
|
object: "chat.completion",
|
|
@@ -186,49 +207,56 @@ export function toCompletions(result, model) {
|
|
|
186
207
|
choices: [
|
|
187
208
|
{
|
|
188
209
|
index: 0,
|
|
189
|
-
message:
|
|
210
|
+
message: toChatCompletionsAssistantMessage(result),
|
|
190
211
|
finish_reason,
|
|
191
212
|
},
|
|
192
213
|
],
|
|
193
|
-
usage: result.
|
|
194
|
-
|
|
214
|
+
usage: result.totalUsage ? toChatCompletionsUsage(result.totalUsage) : null,
|
|
215
|
+
provider_metadata: result.providerMetadata,
|
|
195
216
|
};
|
|
196
217
|
}
|
|
197
|
-
export function
|
|
198
|
-
return new Response(JSON.stringify(
|
|
199
|
-
headers: { "Content-Type": "application/json" },
|
|
200
|
-
});
|
|
218
|
+
export function toChatCompletionsResponse(result, model, responseInit) {
|
|
219
|
+
return new Response(JSON.stringify(toChatCompletions(result, model)), mergeResponseInit({ "Content-Type": "application/json" }, responseInit));
|
|
201
220
|
}
|
|
202
|
-
export function
|
|
221
|
+
export function toChatCompletionsStream(result, model) {
|
|
203
222
|
return result.fullStream
|
|
204
|
-
.pipeThrough(new
|
|
205
|
-
.pipeThrough(new
|
|
223
|
+
.pipeThrough(new ChatCompletionsStream(model))
|
|
224
|
+
.pipeThrough(new JsonToSseTransformStream())
|
|
206
225
|
.pipeThrough(new TextEncoderStream());
|
|
207
226
|
}
|
|
208
|
-
export function
|
|
209
|
-
return new Response(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
},
|
|
215
|
-
});
|
|
227
|
+
export function toChatCompletionsStreamResponse(result, model, responseInit) {
|
|
228
|
+
return new Response(toChatCompletionsStream(result, model), mergeResponseInit({
|
|
229
|
+
"Content-Type": "text/event-stream",
|
|
230
|
+
"Cache-Control": "no-cache",
|
|
231
|
+
Connection: "keep-alive",
|
|
232
|
+
}, responseInit));
|
|
216
233
|
}
|
|
217
|
-
export class
|
|
234
|
+
export class ChatCompletionsStream extends TransformStream {
|
|
218
235
|
constructor(model) {
|
|
219
236
|
const streamId = `chatcmpl-${crypto.randomUUID()}`;
|
|
220
237
|
const creationTime = Math.floor(Date.now() / 1000);
|
|
221
238
|
let toolCallIndexCounter = 0;
|
|
222
|
-
|
|
239
|
+
let lastProviderMetadata;
|
|
240
|
+
const createChunk = (delta, finish_reason, usage, provider_metadata) => ({
|
|
223
241
|
id: streamId,
|
|
224
242
|
object: "chat.completion.chunk",
|
|
225
243
|
created: creationTime,
|
|
226
244
|
model,
|
|
227
|
-
choices: [
|
|
228
|
-
|
|
245
|
+
choices: [
|
|
246
|
+
{
|
|
247
|
+
index: 0,
|
|
248
|
+
delta,
|
|
249
|
+
finish_reason: finish_reason ?? null,
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
...(usage ? { usage } : { usage: null }),
|
|
253
|
+
...(provider_metadata === undefined ? {} : { provider_metadata }),
|
|
229
254
|
});
|
|
230
255
|
super({
|
|
231
256
|
transform(part, controller) {
|
|
257
|
+
if ("providerMetadata" in part && part.providerMetadata !== undefined) {
|
|
258
|
+
lastProviderMetadata = part.providerMetadata;
|
|
259
|
+
}
|
|
232
260
|
switch (part.type) {
|
|
233
261
|
case "text-delta": {
|
|
234
262
|
controller.enqueue(createChunk({ role: "assistant", content: part.text }));
|
|
@@ -242,7 +270,7 @@ export class CompletionsStream extends TransformStream {
|
|
|
242
270
|
controller.enqueue(createChunk({
|
|
243
271
|
tool_calls: [
|
|
244
272
|
{
|
|
245
|
-
...
|
|
273
|
+
...toChatCompletionsToolCall(part.toolCallId, part.toolName, part.input),
|
|
246
274
|
index: toolCallIndexCounter++,
|
|
247
275
|
},
|
|
248
276
|
],
|
|
@@ -250,7 +278,7 @@ export class CompletionsStream extends TransformStream {
|
|
|
250
278
|
break;
|
|
251
279
|
}
|
|
252
280
|
case "finish": {
|
|
253
|
-
controller.enqueue(createChunk({},
|
|
281
|
+
controller.enqueue(createChunk({}, toChatCompletionsFinishReason(part.finishReason), toChatCompletionsUsage(part.totalUsage), lastProviderMetadata));
|
|
254
282
|
break;
|
|
255
283
|
}
|
|
256
284
|
case "error": {
|
|
@@ -265,25 +293,13 @@ export class CompletionsStream extends TransformStream {
|
|
|
265
293
|
});
|
|
266
294
|
}
|
|
267
295
|
}
|
|
268
|
-
export
|
|
269
|
-
constructor() {
|
|
270
|
-
super({
|
|
271
|
-
transform(chunk, controller) {
|
|
272
|
-
controller.enqueue(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
273
|
-
},
|
|
274
|
-
flush(controller) {
|
|
275
|
-
controller.enqueue("data: [DONE]\n\n");
|
|
276
|
-
},
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
export const toCompletionsMessage = (result) => {
|
|
296
|
+
export const toChatCompletionsAssistantMessage = (result) => {
|
|
281
297
|
const message = {
|
|
282
298
|
role: "assistant",
|
|
283
299
|
content: null,
|
|
284
300
|
};
|
|
285
301
|
if (result.toolCalls && result.toolCalls.length > 0) {
|
|
286
|
-
message.tool_calls = result.toolCalls.map((toolCall) =>
|
|
302
|
+
message.tool_calls = result.toolCalls.map((toolCall) => toChatCompletionsToolCall(toolCall.toolCallId, toolCall.toolName, toolCall.input));
|
|
287
303
|
}
|
|
288
304
|
for (const part of result.content) {
|
|
289
305
|
if (part.type === "text") {
|
|
@@ -296,22 +312,32 @@ export const toCompletionsMessage = (result) => {
|
|
|
296
312
|
}
|
|
297
313
|
return message;
|
|
298
314
|
};
|
|
299
|
-
export function
|
|
300
|
-
if (!usage)
|
|
301
|
-
return undefined;
|
|
315
|
+
export function toChatCompletionsUsage(usage) {
|
|
302
316
|
return {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
},
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
317
|
+
...(usage.inputTokens !== undefined && {
|
|
318
|
+
prompt_tokens: usage.inputTokens,
|
|
319
|
+
}),
|
|
320
|
+
...(usage.outputTokens !== undefined && {
|
|
321
|
+
completion_tokens: usage.outputTokens,
|
|
322
|
+
}),
|
|
323
|
+
...((usage.totalTokens !== undefined ||
|
|
324
|
+
usage.inputTokens !== undefined ||
|
|
325
|
+
usage.outputTokens !== undefined) && {
|
|
326
|
+
total_tokens: usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0),
|
|
327
|
+
}),
|
|
328
|
+
...(usage.outputTokenDetails?.reasoningTokens !== undefined && {
|
|
329
|
+
completion_tokens_details: {
|
|
330
|
+
reasoning_tokens: usage.outputTokenDetails.reasoningTokens,
|
|
331
|
+
},
|
|
332
|
+
}),
|
|
333
|
+
...(usage.inputTokenDetails?.cacheReadTokens !== undefined && {
|
|
334
|
+
prompt_tokens_details: {
|
|
335
|
+
cached_tokens: usage.inputTokenDetails.cacheReadTokens,
|
|
336
|
+
},
|
|
337
|
+
}),
|
|
312
338
|
};
|
|
313
339
|
}
|
|
314
|
-
export function
|
|
340
|
+
export function toChatCompletionsToolCall(id, name, args) {
|
|
315
341
|
return {
|
|
316
342
|
id,
|
|
317
343
|
type: "function",
|
|
@@ -321,7 +347,7 @@ export function toCompletionsToolCall(id, name, args) {
|
|
|
321
347
|
},
|
|
322
348
|
};
|
|
323
349
|
}
|
|
324
|
-
export const
|
|
350
|
+
export const toChatCompletionsFinishReason = (finishReason) => {
|
|
325
351
|
if (finishReason === "error" || finishReason === "other") {
|
|
326
352
|
return "stop";
|
|
327
353
|
}
|
|
@@ -1,82 +1,88 @@
|
|
|
1
|
-
import { generateText, streamText } from "ai";
|
|
1
|
+
import { generateText, streamText, wrapLanguageModel } from "ai";
|
|
2
2
|
import * as z from "zod/mini";
|
|
3
|
-
import {
|
|
3
|
+
import { withLifecycle } from "../../lifecycle";
|
|
4
|
+
import { modelMiddlewareMatcher } from "../../middleware/matcher";
|
|
4
5
|
import { resolveProvider } from "../../providers/registry";
|
|
5
6
|
import { createErrorResponse } from "../../utils/errors";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { CompletionsBodySchema } from "./schema";
|
|
7
|
+
import { convertToTextCallOptions, toChatCompletionsResponse, toChatCompletionsStreamResponse, } from "./converters";
|
|
8
|
+
import { ChatCompletionsBodySchema } from "./schema";
|
|
9
9
|
export const chatCompletions = (config) => {
|
|
10
|
-
const
|
|
11
|
-
const handler = async (
|
|
12
|
-
if (
|
|
10
|
+
const hooks = config.hooks;
|
|
11
|
+
const handler = async (ctx) => {
|
|
12
|
+
if (!ctx.request || ctx.request.method !== "POST") {
|
|
13
13
|
return createErrorResponse("METHOD_NOT_ALLOWED", "Method Not Allowed", 405);
|
|
14
14
|
}
|
|
15
15
|
let body;
|
|
16
16
|
try {
|
|
17
|
-
body = await
|
|
17
|
+
body = await ctx.request.json();
|
|
18
18
|
}
|
|
19
19
|
catch {
|
|
20
20
|
return createErrorResponse("BAD_REQUEST", "Invalid JSON", 400);
|
|
21
21
|
}
|
|
22
|
-
const parsed =
|
|
22
|
+
const parsed = ChatCompletionsBodySchema.safeParse(body);
|
|
23
23
|
if (!parsed.success) {
|
|
24
24
|
return createErrorResponse("UNPROCESSABLE_ENTITY", "Validation error", 422, z.prettifyError(parsed.error));
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
let
|
|
26
|
+
ctx.body = parsed.data;
|
|
27
|
+
let stream, inputs;
|
|
28
|
+
({ model: ctx.modelId, stream, ...inputs } = parsed.data);
|
|
28
29
|
try {
|
|
29
|
-
resolvedModelId = (await hooks?.resolveModelId?.(
|
|
30
|
+
ctx.resolvedModelId = (await hooks?.resolveModelId?.(ctx)) ?? ctx.modelId;
|
|
30
31
|
}
|
|
31
32
|
catch (error) {
|
|
32
33
|
return createErrorResponse("BAD_REQUEST", error, 400);
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
+
ctx.operation = "text";
|
|
35
36
|
try {
|
|
36
|
-
|
|
37
|
+
const override = await hooks?.resolveProvider?.(ctx);
|
|
38
|
+
ctx.provider =
|
|
39
|
+
override ??
|
|
40
|
+
resolveProvider({
|
|
41
|
+
providers: ctx.providers,
|
|
42
|
+
models: ctx.models,
|
|
43
|
+
modelId: ctx.resolvedModelId,
|
|
44
|
+
operation: ctx.operation,
|
|
45
|
+
});
|
|
37
46
|
}
|
|
38
47
|
catch (error) {
|
|
39
48
|
return createErrorResponse("BAD_REQUEST", error, 400);
|
|
40
49
|
}
|
|
41
|
-
|
|
50
|
+
const languageModel = ctx.provider.languageModel(ctx.resolvedModelId);
|
|
51
|
+
let textOptions;
|
|
42
52
|
try {
|
|
43
|
-
|
|
44
|
-
providers,
|
|
45
|
-
models,
|
|
46
|
-
modelId: resolvedModelId,
|
|
47
|
-
operation: "text",
|
|
48
|
-
};
|
|
49
|
-
const override = await hooks?.resolveProvider?.(args);
|
|
50
|
-
provider = override ?? resolveProvider(args);
|
|
53
|
+
textOptions = convertToTextCallOptions(inputs);
|
|
51
54
|
}
|
|
52
55
|
catch (error) {
|
|
53
56
|
return createErrorResponse("BAD_REQUEST", error, 400);
|
|
54
57
|
}
|
|
55
|
-
const
|
|
58
|
+
const languageModelWithMiddleware = wrapLanguageModel({
|
|
59
|
+
model: languageModel,
|
|
60
|
+
middleware: modelMiddlewareMatcher.for(ctx.resolvedModelId, languageModel.provider),
|
|
61
|
+
});
|
|
56
62
|
if (stream) {
|
|
57
63
|
let result;
|
|
58
64
|
try {
|
|
59
65
|
result = streamText({
|
|
60
|
-
model:
|
|
66
|
+
model: languageModelWithMiddleware,
|
|
61
67
|
...textOptions,
|
|
62
68
|
});
|
|
63
69
|
}
|
|
64
70
|
catch (error) {
|
|
65
71
|
return createErrorResponse("INTERNAL_SERVER_ERROR", error, 500);
|
|
66
72
|
}
|
|
67
|
-
return
|
|
73
|
+
return toChatCompletionsStreamResponse(result, ctx.modelId);
|
|
68
74
|
}
|
|
69
75
|
let result;
|
|
70
76
|
try {
|
|
71
77
|
result = await generateText({
|
|
72
|
-
model:
|
|
78
|
+
model: languageModelWithMiddleware,
|
|
73
79
|
...textOptions,
|
|
74
80
|
});
|
|
75
81
|
}
|
|
76
82
|
catch (error) {
|
|
77
83
|
return createErrorResponse("INTERNAL_SERVER_ERROR", error, 500);
|
|
78
84
|
}
|
|
79
|
-
return
|
|
85
|
+
return toChatCompletionsResponse(result, ctx.modelId);
|
|
80
86
|
};
|
|
81
|
-
return { handler:
|
|
87
|
+
return { handler: withLifecycle(handler, config) };
|
|
82
88
|
};
|