heibaiapi 0.6.1 → 0.7.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/LICENSE +21 -21
- package/README.md +351 -348
- package/dist/main.js +31 -1004
- package/dist/main.js.map +1 -1
- package/package.json +68 -68
package/dist/main.js
CHANGED
@@ -5,11 +5,11 @@ import fs from "node:fs/promises";
|
|
5
5
|
import os from "node:os";
|
6
6
|
import path from "node:path";
|
7
7
|
import { randomUUID } from "node:crypto";
|
8
|
-
import { getProxyForUrl } from "proxy-from-env";
|
9
|
-
import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
|
10
8
|
import clipboard from "clipboardy";
|
11
9
|
import { serve } from "srvx";
|
12
10
|
import invariant from "tiny-invariant";
|
11
|
+
import { getProxyForUrl } from "proxy-from-env";
|
12
|
+
import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
|
13
13
|
import { execSync } from "node:child_process";
|
14
14
|
import process$1 from "node:process";
|
15
15
|
import { Hono } from "hono";
|
@@ -19,7 +19,7 @@ import { streamSSE } from "hono/streaming";
|
|
19
19
|
import { events } from "fetch-event-stream";
|
20
20
|
|
21
21
|
//#region src/lib/paths.ts
|
22
|
-
const APP_DIR = path.join(os.homedir(), ".local", "share", "
|
22
|
+
const APP_DIR = path.join(os.homedir(), ".local", "share", "copilot-api");
|
23
23
|
const GITHUB_TOKEN_PATH = path.join(APP_DIR, "github_token");
|
24
24
|
const PATHS = {
|
25
25
|
APP_DIR,
|
@@ -401,7 +401,7 @@ async function getDebugInfo() {
|
|
401
401
|
};
|
402
402
|
}
|
403
403
|
function printDebugInfoPlain(info) {
|
404
|
-
consola.info(`
|
404
|
+
consola.info(`copilot-api debug
|
405
405
|
|
406
406
|
Version: ${info.version}
|
407
407
|
Runtime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})
|
@@ -487,8 +487,7 @@ function getShell() {
|
|
487
487
|
const { platform, ppid, env } = process$1;
|
488
488
|
if (platform === "win32") {
|
489
489
|
try {
|
490
|
-
|
491
|
-
if (execSync(command, { stdio: "pipe" }).toString().toLowerCase().includes("powershell.exe")) return "powershell";
|
490
|
+
if (execSync(`wmic process get ParentProcessId,Name | findstr "${ppid}"`, { stdio: "pipe" }).toString().toLowerCase().includes("powershell.exe")) return "powershell";
|
492
491
|
} catch {
|
493
492
|
return "cmd";
|
494
493
|
}
|
@@ -748,8 +747,7 @@ const numTokensForTools = (tools, encoder, constants) => {
|
|
748
747
|
* Calculate the token count of messages, supporting multiple GPT encoders
|
749
748
|
*/
|
750
749
|
const getTokenCount = async (payload, model) => {
|
751
|
-
const
|
752
|
-
const encoder = await getEncodeChatFunction(tokenizer);
|
750
|
+
const encoder = await getEncodeChatFunction(getTokenizerFromModel(model));
|
753
751
|
const simplifiedMessages = payload.messages;
|
754
752
|
const inputMessages = simplifiedMessages.filter((msg) => msg.role !== "assistant");
|
755
753
|
const outputMessages = simplifiedMessages.filter((msg) => msg.role === "assistant");
|
@@ -794,10 +792,8 @@ async function handleCompletion$1(c) {
|
|
794
792
|
consola.debug("Request payload:", JSON.stringify(payload).slice(-400));
|
795
793
|
const selectedModel = state.models?.data.find((model) => model.id === payload.model);
|
796
794
|
try {
|
797
|
-
if (selectedModel) {
|
798
|
-
|
799
|
-
consola.info("Current token count:", tokenCount);
|
800
|
-
} else consola.warn("No model selected, skipping token count calculation");
|
795
|
+
if (selectedModel) consola.info(`[ModelTranslation_OpenAI] 客户端请求: ${payload.model} -> 服务端使用: ${selectedModel.id}`);
|
796
|
+
else consola.warn("No model selected, skipping token count calculation");
|
801
797
|
} catch (error) {
|
802
798
|
consola.warn("Failed to calculate token count:", error);
|
803
799
|
}
|
@@ -853,8 +849,7 @@ const createEmbeddings = async (payload) => {
|
|
853
849
|
const embeddingRoutes = new Hono();
|
854
850
|
embeddingRoutes.post("/", async (c) => {
|
855
851
|
try {
|
856
|
-
const
|
857
|
-
const response = await createEmbeddings(paylod);
|
852
|
+
const response = await createEmbeddings(await c.req.json());
|
858
853
|
return c.json(response);
|
859
854
|
} catch (error) {
|
860
855
|
return await forwardError(c, error);
|
@@ -890,9 +885,14 @@ function translateToOpenAI(payload) {
|
|
890
885
|
};
|
891
886
|
}
|
892
887
|
function translateModelName(model) {
|
893
|
-
|
894
|
-
|
895
|
-
|
888
|
+
let serverModel;
|
889
|
+
serverModel = model;
|
890
|
+
if (model.includes("claude-3-5")) serverModel = "claude-3.5-sonnet";
|
891
|
+
else if (model.includes("claude-opus")) serverModel = "claude-sonnet-4.5";
|
892
|
+
else if (model.includes("claude-sonnet-4.5")) serverModel = "claude-sonnet-4.5";
|
893
|
+
else if (model.includes("claude-sonnet-4")) serverModel = "claude-sonnet-4";
|
894
|
+
consola.info(`[ModelTranslation] 客户端请求: ${model} -> 服务端使用: ${serverModel}`);
|
895
|
+
return serverModel;
|
896
896
|
}
|
897
897
|
function translateAnthropicMessagesToOpenAI(anthropicMessages, system) {
|
898
898
|
const systemMessages = handleSystemPrompt(system);
|
@@ -1083,7 +1083,6 @@ async function handleCountTokens(c) {
|
|
1083
1083
|
let finalTokenCount = tokenCount.input + tokenCount.output;
|
1084
1084
|
if (anthropicPayload.model.startsWith("claude")) finalTokenCount = Math.round(finalTokenCount * 1.15);
|
1085
1085
|
else if (anthropicPayload.model.startsWith("grok")) finalTokenCount = Math.round(finalTokenCount * 1.03);
|
1086
|
-
consola.info("Token count:", finalTokenCount);
|
1087
1086
|
return c.json({ input_tokens: finalTokenCount });
|
1088
1087
|
} catch (error) {
|
1089
1088
|
consola.error("Error counting tokens:", error);
|
@@ -1091,850 +1090,6 @@ async function handleCountTokens(c) {
|
|
1091
1090
|
}
|
1092
1091
|
}
|
1093
1092
|
|
1094
|
-
//#endregion
|
1095
|
-
//#region src/services/copilot/create-responses.ts
|
1096
|
-
const createResponses = async (payload, { vision, initiator }) => {
|
1097
|
-
if (!state.copilotToken) throw new Error("Copilot token not found");
|
1098
|
-
const headers = {
|
1099
|
-
...copilotHeaders(state, vision),
|
1100
|
-
"X-Initiator": initiator
|
1101
|
-
};
|
1102
|
-
const response = await fetch(`${copilotBaseUrl(state)}/responses`, {
|
1103
|
-
method: "POST",
|
1104
|
-
headers,
|
1105
|
-
body: JSON.stringify(payload)
|
1106
|
-
});
|
1107
|
-
if (!response.ok) {
|
1108
|
-
consola.error("Failed to create responses", response);
|
1109
|
-
throw new HTTPError("Failed to create responses", response);
|
1110
|
-
}
|
1111
|
-
if (payload.stream) return events(response);
|
1112
|
-
return await response.json();
|
1113
|
-
};
|
1114
|
-
|
1115
|
-
//#endregion
|
1116
|
-
//#region src/routes/messages/responses-translation.ts
|
1117
|
-
const MESSAGE_TYPE = "message";
|
1118
|
-
const translateAnthropicMessagesToResponsesPayload = (payload) => {
|
1119
|
-
const input = [];
|
1120
|
-
for (const message of payload.messages) input.push(...translateMessage(message));
|
1121
|
-
const translatedTools = convertAnthropicTools(payload.tools);
|
1122
|
-
const toolChoice = convertAnthropicToolChoice(payload.tool_choice);
|
1123
|
-
const { safetyIdentifier, promptCacheKey } = parseUserId(payload.metadata?.user_id);
|
1124
|
-
return {
|
1125
|
-
model: payload.model,
|
1126
|
-
input,
|
1127
|
-
instructions: translateSystemPrompt(payload.system),
|
1128
|
-
temperature: payload.temperature ?? null,
|
1129
|
-
top_p: payload.top_p ?? null,
|
1130
|
-
max_output_tokens: payload.max_tokens,
|
1131
|
-
tools: translatedTools,
|
1132
|
-
tool_choice: toolChoice,
|
1133
|
-
metadata: payload.metadata ? { ...payload.metadata } : null,
|
1134
|
-
safety_identifier: safetyIdentifier,
|
1135
|
-
prompt_cache_key: promptCacheKey,
|
1136
|
-
stream: payload.stream ?? null,
|
1137
|
-
store: false,
|
1138
|
-
parallel_tool_calls: true,
|
1139
|
-
reasoning: {
|
1140
|
-
effort: "high",
|
1141
|
-
summary: "auto"
|
1142
|
-
},
|
1143
|
-
include: ["reasoning.encrypted_content"]
|
1144
|
-
};
|
1145
|
-
};
|
1146
|
-
const translateMessage = (message) => {
|
1147
|
-
if (message.role === "user") return translateUserMessage(message);
|
1148
|
-
return translateAssistantMessage(message);
|
1149
|
-
};
|
1150
|
-
const translateUserMessage = (message) => {
|
1151
|
-
if (typeof message.content === "string") return [createMessage("user", message.content)];
|
1152
|
-
if (!Array.isArray(message.content)) return [];
|
1153
|
-
const items = [];
|
1154
|
-
const pendingContent = [];
|
1155
|
-
for (const block of message.content) {
|
1156
|
-
if (block.type === "tool_result") {
|
1157
|
-
flushPendingContent("user", pendingContent, items);
|
1158
|
-
items.push(createFunctionCallOutput(block));
|
1159
|
-
continue;
|
1160
|
-
}
|
1161
|
-
const converted = translateUserContentBlock(block);
|
1162
|
-
if (converted) pendingContent.push(converted);
|
1163
|
-
}
|
1164
|
-
flushPendingContent("user", pendingContent, items);
|
1165
|
-
return items;
|
1166
|
-
};
|
1167
|
-
const translateAssistantMessage = (message) => {
|
1168
|
-
if (typeof message.content === "string") return [createMessage("assistant", message.content)];
|
1169
|
-
if (!Array.isArray(message.content)) return [];
|
1170
|
-
const items = [];
|
1171
|
-
const pendingContent = [];
|
1172
|
-
for (const block of message.content) {
|
1173
|
-
if (block.type === "tool_use") {
|
1174
|
-
flushPendingContent("assistant", pendingContent, items);
|
1175
|
-
items.push(createFunctionToolCall(block));
|
1176
|
-
continue;
|
1177
|
-
}
|
1178
|
-
if (block.type === "thinking") {
|
1179
|
-
flushPendingContent("assistant", pendingContent, items);
|
1180
|
-
items.push(createReasoningContent(block));
|
1181
|
-
continue;
|
1182
|
-
}
|
1183
|
-
const converted = translateAssistantContentBlock(block);
|
1184
|
-
if (converted) pendingContent.push(converted);
|
1185
|
-
}
|
1186
|
-
flushPendingContent("assistant", pendingContent, items);
|
1187
|
-
return items;
|
1188
|
-
};
|
1189
|
-
const translateUserContentBlock = (block) => {
|
1190
|
-
switch (block.type) {
|
1191
|
-
case "text": return createTextContent(block.text);
|
1192
|
-
case "image": return createImageContent(block);
|
1193
|
-
default: return;
|
1194
|
-
}
|
1195
|
-
};
|
1196
|
-
const translateAssistantContentBlock = (block) => {
|
1197
|
-
switch (block.type) {
|
1198
|
-
case "text": return createOutPutTextContent(block.text);
|
1199
|
-
default: return;
|
1200
|
-
}
|
1201
|
-
};
|
1202
|
-
const flushPendingContent = (role, pendingContent, target) => {
|
1203
|
-
if (pendingContent.length === 0) return;
|
1204
|
-
const messageContent = pendingContent.length === 1 && isPlainText(pendingContent[0]) ? pendingContent[0].text : [...pendingContent];
|
1205
|
-
target.push(createMessage(role, messageContent));
|
1206
|
-
pendingContent.length = 0;
|
1207
|
-
};
|
1208
|
-
const createMessage = (role, content) => ({
|
1209
|
-
type: MESSAGE_TYPE,
|
1210
|
-
role,
|
1211
|
-
content
|
1212
|
-
});
|
1213
|
-
const createTextContent = (text) => ({
|
1214
|
-
type: "input_text",
|
1215
|
-
text
|
1216
|
-
});
|
1217
|
-
const createOutPutTextContent = (text) => ({
|
1218
|
-
type: "output_text",
|
1219
|
-
text
|
1220
|
-
});
|
1221
|
-
const createImageContent = (block) => ({
|
1222
|
-
type: "input_image",
|
1223
|
-
image_url: `data:${block.source.media_type};base64,${block.source.data}`
|
1224
|
-
});
|
1225
|
-
const createReasoningContent = (block) => ({
|
1226
|
-
type: "reasoning",
|
1227
|
-
summary: [{
|
1228
|
-
type: "summary_text",
|
1229
|
-
text: block.thinking
|
1230
|
-
}],
|
1231
|
-
encrypted_content: block.signature
|
1232
|
-
});
|
1233
|
-
const createFunctionToolCall = (block) => ({
|
1234
|
-
type: "function_call",
|
1235
|
-
call_id: block.id,
|
1236
|
-
name: block.name,
|
1237
|
-
arguments: JSON.stringify(block.input),
|
1238
|
-
status: "completed"
|
1239
|
-
});
|
1240
|
-
const createFunctionCallOutput = (block) => ({
|
1241
|
-
type: "function_call_output",
|
1242
|
-
call_id: block.tool_use_id,
|
1243
|
-
output: convertToolResultContent(block.content),
|
1244
|
-
status: block.is_error ? "incomplete" : "completed"
|
1245
|
-
});
|
1246
|
-
const translateSystemPrompt = (system) => {
|
1247
|
-
if (!system) return null;
|
1248
|
-
const toolUsePrompt = `
|
1249
|
-
## Tool use
|
1250
|
-
- You have access to many tools. If a tool exists to perform a specific task, you MUST use that tool instead of running a terminal command to perform that task.
|
1251
|
-
### Bash tool
|
1252
|
-
When using the Bash tool, follow these rules:
|
1253
|
-
- always run_in_background set to false, unless you are running a long-running command (e.g., a server or a watch command).
|
1254
|
-
### BashOutput tool
|
1255
|
-
When using the BashOutput tool, follow these rules:
|
1256
|
-
- Only Bash Tool run_in_background set to true, Use BashOutput to read the output later
|
1257
|
-
### TodoWrite tool
|
1258
|
-
When using the TodoWrite tool, follow these rules:
|
1259
|
-
- Skip using the TodoWrite tool for simple or straightforward tasks (roughly the easiest 25%).
|
1260
|
-
- Do not make single-step todo lists.
|
1261
|
-
- When you made a todo, update it after having performed one of the sub-tasks that you shared on the todo list.`;
|
1262
|
-
if (typeof system === "string") return system + toolUsePrompt;
|
1263
|
-
const text = system.map((block, index) => {
|
1264
|
-
if (index === 0) return block.text + toolUsePrompt;
|
1265
|
-
return block.text;
|
1266
|
-
}).join(" ");
|
1267
|
-
return text.length > 0 ? text : null;
|
1268
|
-
};
|
1269
|
-
const convertAnthropicTools = (tools) => {
|
1270
|
-
if (!tools || tools.length === 0) return null;
|
1271
|
-
return tools.map((tool) => ({
|
1272
|
-
type: "function",
|
1273
|
-
name: tool.name,
|
1274
|
-
parameters: tool.input_schema,
|
1275
|
-
strict: false,
|
1276
|
-
...tool.description ? { description: tool.description } : {}
|
1277
|
-
}));
|
1278
|
-
};
|
1279
|
-
const convertAnthropicToolChoice = (choice) => {
|
1280
|
-
if (!choice) return;
|
1281
|
-
switch (choice.type) {
|
1282
|
-
case "auto": return "auto";
|
1283
|
-
case "any": return "required";
|
1284
|
-
case "tool": return choice.name ? {
|
1285
|
-
type: "function",
|
1286
|
-
name: choice.name
|
1287
|
-
} : void 0;
|
1288
|
-
case "none": return "none";
|
1289
|
-
default: return;
|
1290
|
-
}
|
1291
|
-
};
|
1292
|
-
const isPlainText = (content) => {
|
1293
|
-
if (typeof content !== "object") return false;
|
1294
|
-
return "text" in content && typeof content.text === "string" && !("image_url" in content);
|
1295
|
-
};
|
1296
|
-
const translateResponsesResultToAnthropic = (response) => {
|
1297
|
-
const contentBlocks = mapOutputToAnthropicContent(response.output);
|
1298
|
-
const usage = mapResponsesUsage(response);
|
1299
|
-
let anthropicContent = fallbackContentBlocks(response.output_text);
|
1300
|
-
if (contentBlocks.length > 0) anthropicContent = contentBlocks;
|
1301
|
-
const stopReason = mapResponsesStopReason(response);
|
1302
|
-
return {
|
1303
|
-
id: response.id,
|
1304
|
-
type: "message",
|
1305
|
-
role: "assistant",
|
1306
|
-
content: anthropicContent,
|
1307
|
-
model: response.model,
|
1308
|
-
stop_reason: stopReason,
|
1309
|
-
stop_sequence: null,
|
1310
|
-
usage
|
1311
|
-
};
|
1312
|
-
};
|
1313
|
-
const mapOutputToAnthropicContent = (output) => {
|
1314
|
-
const contentBlocks = [];
|
1315
|
-
for (const item of output) switch (item.type) {
|
1316
|
-
case "reasoning": {
|
1317
|
-
const thinkingText = extractReasoningText(item);
|
1318
|
-
if (thinkingText.length > 0) contentBlocks.push({
|
1319
|
-
type: "thinking",
|
1320
|
-
thinking: thinkingText,
|
1321
|
-
signature: item.encrypted_content ?? ""
|
1322
|
-
});
|
1323
|
-
break;
|
1324
|
-
}
|
1325
|
-
case "function_call": {
|
1326
|
-
const toolUseBlock = createToolUseContentBlock(item);
|
1327
|
-
if (toolUseBlock) contentBlocks.push(toolUseBlock);
|
1328
|
-
break;
|
1329
|
-
}
|
1330
|
-
case "message": {
|
1331
|
-
const combinedText = combineMessageTextContent(item.content);
|
1332
|
-
if (combinedText.length > 0) contentBlocks.push({
|
1333
|
-
type: "text",
|
1334
|
-
text: combinedText
|
1335
|
-
});
|
1336
|
-
break;
|
1337
|
-
}
|
1338
|
-
default: {
|
1339
|
-
const combinedText = combineMessageTextContent(item.content);
|
1340
|
-
if (combinedText.length > 0) contentBlocks.push({
|
1341
|
-
type: "text",
|
1342
|
-
text: combinedText
|
1343
|
-
});
|
1344
|
-
}
|
1345
|
-
}
|
1346
|
-
return contentBlocks;
|
1347
|
-
};
|
1348
|
-
const combineMessageTextContent = (content) => {
|
1349
|
-
if (!Array.isArray(content)) return "";
|
1350
|
-
let aggregated = "";
|
1351
|
-
for (const block of content) {
|
1352
|
-
if (isResponseOutputText(block)) {
|
1353
|
-
aggregated += block.text;
|
1354
|
-
continue;
|
1355
|
-
}
|
1356
|
-
if (isResponseOutputRefusal(block)) {
|
1357
|
-
aggregated += block.refusal;
|
1358
|
-
continue;
|
1359
|
-
}
|
1360
|
-
if (typeof block.text === "string") {
|
1361
|
-
aggregated += block.text;
|
1362
|
-
continue;
|
1363
|
-
}
|
1364
|
-
if (typeof block.reasoning === "string") {
|
1365
|
-
aggregated += block.reasoning;
|
1366
|
-
continue;
|
1367
|
-
}
|
1368
|
-
}
|
1369
|
-
return aggregated;
|
1370
|
-
};
|
1371
|
-
const extractReasoningText = (item) => {
|
1372
|
-
const segments = [];
|
1373
|
-
const collectFromBlocks = (blocks) => {
|
1374
|
-
if (!Array.isArray(blocks)) return;
|
1375
|
-
for (const block of blocks) if (typeof block.text === "string") {
|
1376
|
-
segments.push(block.text);
|
1377
|
-
continue;
|
1378
|
-
}
|
1379
|
-
};
|
1380
|
-
collectFromBlocks(item.summary);
|
1381
|
-
return segments.join("").trim();
|
1382
|
-
};
|
1383
|
-
const createToolUseContentBlock = (call) => {
|
1384
|
-
const toolId = call.call_id ?? call.id;
|
1385
|
-
if (!call.name || !toolId) return null;
|
1386
|
-
const input = parseFunctionCallArguments(call.arguments);
|
1387
|
-
return {
|
1388
|
-
type: "tool_use",
|
1389
|
-
id: toolId,
|
1390
|
-
name: call.name,
|
1391
|
-
input
|
1392
|
-
};
|
1393
|
-
};
|
1394
|
-
const parseFunctionCallArguments = (rawArguments) => {
|
1395
|
-
if (typeof rawArguments !== "string" || rawArguments.trim().length === 0) return {};
|
1396
|
-
try {
|
1397
|
-
const parsed = JSON.parse(rawArguments);
|
1398
|
-
if (Array.isArray(parsed)) return { arguments: parsed };
|
1399
|
-
if (parsed && typeof parsed === "object") return parsed;
|
1400
|
-
} catch (error) {
|
1401
|
-
consola.warn("Failed to parse function call arguments", {
|
1402
|
-
error,
|
1403
|
-
rawArguments
|
1404
|
-
});
|
1405
|
-
}
|
1406
|
-
return { raw_arguments: rawArguments };
|
1407
|
-
};
|
1408
|
-
const fallbackContentBlocks = (outputText) => {
|
1409
|
-
if (!outputText) return [];
|
1410
|
-
return [{
|
1411
|
-
type: "text",
|
1412
|
-
text: outputText
|
1413
|
-
}];
|
1414
|
-
};
|
1415
|
-
const mapResponsesStopReason = (response) => {
|
1416
|
-
const { status, incomplete_details: incompleteDetails } = response;
|
1417
|
-
if (status === "completed") return "end_turn";
|
1418
|
-
if (status === "incomplete") {
|
1419
|
-
if (incompleteDetails?.reason === "max_output_tokens") return "max_tokens";
|
1420
|
-
if (incompleteDetails?.reason === "content_filter") return "end_turn";
|
1421
|
-
if (incompleteDetails?.reason === "tool_use") return "tool_use";
|
1422
|
-
}
|
1423
|
-
return null;
|
1424
|
-
};
|
1425
|
-
const mapResponsesUsage = (response) => {
|
1426
|
-
const inputTokens = response.usage?.input_tokens ?? 0;
|
1427
|
-
const outputTokens = response.usage?.output_tokens ?? 0;
|
1428
|
-
const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
|
1429
|
-
return {
|
1430
|
-
input_tokens: inputTokens - (inputCachedTokens ?? 0),
|
1431
|
-
output_tokens: outputTokens,
|
1432
|
-
...response.usage?.input_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: response.usage.input_tokens_details.cached_tokens }
|
1433
|
-
};
|
1434
|
-
};
|
1435
|
-
const isRecord$1 = (value) => typeof value === "object" && value !== null;
|
1436
|
-
const isResponseOutputText = (block) => isRecord$1(block) && "type" in block && block.type === "output_text";
|
1437
|
-
const isResponseOutputRefusal = (block) => isRecord$1(block) && "type" in block && block.type === "refusal";
|
1438
|
-
const parseUserId = (userId) => {
|
1439
|
-
if (!userId || typeof userId !== "string") return {
|
1440
|
-
safetyIdentifier: null,
|
1441
|
-
promptCacheKey: null
|
1442
|
-
};
|
1443
|
-
const userMatch = userId.match(/user_([^_]+)_account/);
|
1444
|
-
const safetyIdentifier = userMatch ? userMatch[1] : null;
|
1445
|
-
const sessionMatch = userId.match(/_session_(.+)$/);
|
1446
|
-
const promptCacheKey = sessionMatch ? sessionMatch[1] : null;
|
1447
|
-
return {
|
1448
|
-
safetyIdentifier,
|
1449
|
-
promptCacheKey
|
1450
|
-
};
|
1451
|
-
};
|
1452
|
-
const convertToolResultContent = (content) => {
|
1453
|
-
if (typeof content === "string") return content;
|
1454
|
-
if (Array.isArray(content)) {
|
1455
|
-
const result = [];
|
1456
|
-
for (const block of content) switch (block.type) {
|
1457
|
-
case "text":
|
1458
|
-
result.push(createTextContent(block.text));
|
1459
|
-
break;
|
1460
|
-
case "image":
|
1461
|
-
result.push(createImageContent(block));
|
1462
|
-
break;
|
1463
|
-
default: break;
|
1464
|
-
}
|
1465
|
-
return result;
|
1466
|
-
}
|
1467
|
-
return "";
|
1468
|
-
};
|
1469
|
-
|
1470
|
-
//#endregion
|
1471
|
-
//#region src/routes/messages/responses-stream-translation.ts
|
1472
|
-
const createResponsesStreamState = () => ({
|
1473
|
-
messageStartSent: false,
|
1474
|
-
messageCompleted: false,
|
1475
|
-
nextContentBlockIndex: 0,
|
1476
|
-
blockIndexByKey: /* @__PURE__ */ new Map(),
|
1477
|
-
openBlocks: /* @__PURE__ */ new Set(),
|
1478
|
-
blockHasDelta: /* @__PURE__ */ new Set(),
|
1479
|
-
functionCallStateByOutputIndex: /* @__PURE__ */ new Map(),
|
1480
|
-
functionCallOutputIndexByItemId: /* @__PURE__ */ new Map()
|
1481
|
-
});
|
1482
|
-
const translateResponsesStreamEvent = (rawEvent, state$1) => {
|
1483
|
-
const eventType = typeof rawEvent.type === "string" ? rawEvent.type : void 0;
|
1484
|
-
if (!eventType) return [];
|
1485
|
-
switch (eventType) {
|
1486
|
-
case "response.created": return handleResponseCreated(rawEvent, state$1);
|
1487
|
-
case "response.reasoning_summary_text.delta": return handleReasoningSummaryTextDelta(rawEvent, state$1);
|
1488
|
-
case "response.output_text.delta": return handleOutputTextDelta(rawEvent, state$1);
|
1489
|
-
case "response.reasoning_summary_part.done": return handleReasoningSummaryPartDone(rawEvent, state$1);
|
1490
|
-
case "response.output_text.done": return handleOutputTextDone(rawEvent, state$1);
|
1491
|
-
case "response.output_item.added": return handleOutputItemAdded(rawEvent, state$1);
|
1492
|
-
case "response.output_item.done": return handleOutputItemDone(rawEvent, state$1);
|
1493
|
-
case "response.function_call_arguments.delta": return handleFunctionCallArgumentsDelta(rawEvent, state$1);
|
1494
|
-
case "response.function_call_arguments.done": return handleFunctionCallArgumentsDone(rawEvent, state$1);
|
1495
|
-
case "response.completed":
|
1496
|
-
case "response.incomplete": return handleResponseCompleted(rawEvent, state$1);
|
1497
|
-
case "response.failed": return handleResponseFailed(rawEvent, state$1);
|
1498
|
-
case "error": return handleErrorEvent(rawEvent, state$1);
|
1499
|
-
default: return [];
|
1500
|
-
}
|
1501
|
-
};
|
1502
|
-
const handleResponseCreated = (rawEvent, state$1) => {
|
1503
|
-
const response = toResponsesResult(rawEvent.response);
|
1504
|
-
if (response) cacheResponseMetadata(state$1, response);
|
1505
|
-
return ensureMessageStart(state$1, response);
|
1506
|
-
};
|
1507
|
-
const handleOutputItemAdded = (rawEvent, state$1) => {
|
1508
|
-
const response = toResponsesResult(rawEvent.response);
|
1509
|
-
const events$1 = ensureMessageStart(state$1, response);
|
1510
|
-
const functionCallDetails = extractFunctionCallDetails(rawEvent, state$1);
|
1511
|
-
if (!functionCallDetails) return events$1;
|
1512
|
-
const { outputIndex, toolCallId, name, initialArguments, itemId } = functionCallDetails;
|
1513
|
-
if (itemId) state$1.functionCallOutputIndexByItemId.set(itemId, outputIndex);
|
1514
|
-
const blockIndex = openFunctionCallBlock(state$1, {
|
1515
|
-
outputIndex,
|
1516
|
-
toolCallId,
|
1517
|
-
name,
|
1518
|
-
events: events$1
|
1519
|
-
});
|
1520
|
-
if (initialArguments !== void 0 && initialArguments.length > 0) {
|
1521
|
-
events$1.push({
|
1522
|
-
type: "content_block_delta",
|
1523
|
-
index: blockIndex,
|
1524
|
-
delta: {
|
1525
|
-
type: "input_json_delta",
|
1526
|
-
partial_json: initialArguments
|
1527
|
-
}
|
1528
|
-
});
|
1529
|
-
state$1.blockHasDelta.add(blockIndex);
|
1530
|
-
}
|
1531
|
-
return events$1;
|
1532
|
-
};
|
1533
|
-
const handleOutputItemDone = (rawEvent, state$1) => {
|
1534
|
-
const events$1 = ensureMessageStart(state$1);
|
1535
|
-
const item = isRecord(rawEvent.item) ? rawEvent.item : void 0;
|
1536
|
-
if (!item) return events$1;
|
1537
|
-
if ((typeof item.type === "string" ? item.type : void 0) !== "reasoning") return events$1;
|
1538
|
-
const outputIndex = toNumber(rawEvent.output_index);
|
1539
|
-
const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
|
1540
|
-
const signature = typeof item.encrypted_content === "string" ? item.encrypted_content : "";
|
1541
|
-
if (signature) {
|
1542
|
-
events$1.push({
|
1543
|
-
type: "content_block_delta",
|
1544
|
-
index: blockIndex,
|
1545
|
-
delta: {
|
1546
|
-
type: "signature_delta",
|
1547
|
-
signature
|
1548
|
-
}
|
1549
|
-
});
|
1550
|
-
state$1.blockHasDelta.add(blockIndex);
|
1551
|
-
}
|
1552
|
-
closeBlockIfOpen(state$1, blockIndex, events$1);
|
1553
|
-
return events$1;
|
1554
|
-
};
|
1555
|
-
const handleFunctionCallArgumentsDelta = (rawEvent, state$1) => {
|
1556
|
-
const events$1 = ensureMessageStart(state$1);
|
1557
|
-
const outputIndex = resolveFunctionCallOutputIndex(state$1, rawEvent);
|
1558
|
-
if (outputIndex === void 0) return events$1;
|
1559
|
-
const deltaText = typeof rawEvent.delta === "string" ? rawEvent.delta : "";
|
1560
|
-
if (!deltaText) return events$1;
|
1561
|
-
const blockIndex = openFunctionCallBlock(state$1, {
|
1562
|
-
outputIndex,
|
1563
|
-
events: events$1
|
1564
|
-
});
|
1565
|
-
events$1.push({
|
1566
|
-
type: "content_block_delta",
|
1567
|
-
index: blockIndex,
|
1568
|
-
delta: {
|
1569
|
-
type: "input_json_delta",
|
1570
|
-
partial_json: deltaText
|
1571
|
-
}
|
1572
|
-
});
|
1573
|
-
state$1.blockHasDelta.add(blockIndex);
|
1574
|
-
return events$1;
|
1575
|
-
};
|
1576
|
-
const handleFunctionCallArgumentsDone = (rawEvent, state$1) => {
|
1577
|
-
const events$1 = ensureMessageStart(state$1);
|
1578
|
-
const outputIndex = resolveFunctionCallOutputIndex(state$1, rawEvent);
|
1579
|
-
if (outputIndex === void 0) return events$1;
|
1580
|
-
const blockIndex = openFunctionCallBlock(state$1, {
|
1581
|
-
outputIndex,
|
1582
|
-
events: events$1
|
1583
|
-
});
|
1584
|
-
const finalArguments = typeof rawEvent.arguments === "string" ? rawEvent.arguments : void 0;
|
1585
|
-
if (!state$1.blockHasDelta.has(blockIndex) && finalArguments) {
|
1586
|
-
events$1.push({
|
1587
|
-
type: "content_block_delta",
|
1588
|
-
index: blockIndex,
|
1589
|
-
delta: {
|
1590
|
-
type: "input_json_delta",
|
1591
|
-
partial_json: finalArguments
|
1592
|
-
}
|
1593
|
-
});
|
1594
|
-
state$1.blockHasDelta.add(blockIndex);
|
1595
|
-
}
|
1596
|
-
closeBlockIfOpen(state$1, blockIndex, events$1);
|
1597
|
-
const existingState = state$1.functionCallStateByOutputIndex.get(outputIndex);
|
1598
|
-
if (existingState) state$1.functionCallOutputIndexByItemId.delete(existingState.toolCallId);
|
1599
|
-
state$1.functionCallStateByOutputIndex.delete(outputIndex);
|
1600
|
-
const itemId = toNonEmptyString(rawEvent.item_id);
|
1601
|
-
if (itemId) state$1.functionCallOutputIndexByItemId.delete(itemId);
|
1602
|
-
return events$1;
|
1603
|
-
};
|
1604
|
-
const handleOutputTextDelta = (rawEvent, state$1) => {
|
1605
|
-
const events$1 = ensureMessageStart(state$1);
|
1606
|
-
const outputIndex = toNumber(rawEvent.output_index);
|
1607
|
-
const contentIndex = toNumber(rawEvent.content_index);
|
1608
|
-
const deltaText = typeof rawEvent.delta === "string" ? rawEvent.delta : "";
|
1609
|
-
if (!deltaText) return events$1;
|
1610
|
-
const blockIndex = openTextBlockIfNeeded(state$1, {
|
1611
|
-
outputIndex,
|
1612
|
-
contentIndex,
|
1613
|
-
events: events$1
|
1614
|
-
});
|
1615
|
-
events$1.push({
|
1616
|
-
type: "content_block_delta",
|
1617
|
-
index: blockIndex,
|
1618
|
-
delta: {
|
1619
|
-
type: "text_delta",
|
1620
|
-
text: deltaText
|
1621
|
-
}
|
1622
|
-
});
|
1623
|
-
state$1.blockHasDelta.add(blockIndex);
|
1624
|
-
return events$1;
|
1625
|
-
};
|
1626
|
-
const handleReasoningSummaryTextDelta = (rawEvent, state$1) => {
|
1627
|
-
const events$1 = ensureMessageStart(state$1);
|
1628
|
-
const outputIndex = toNumber(rawEvent.output_index);
|
1629
|
-
const deltaText = typeof rawEvent.delta === "string" ? rawEvent.delta : "";
|
1630
|
-
if (!deltaText) return events$1;
|
1631
|
-
const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
|
1632
|
-
events$1.push({
|
1633
|
-
type: "content_block_delta",
|
1634
|
-
index: blockIndex,
|
1635
|
-
delta: {
|
1636
|
-
type: "thinking_delta",
|
1637
|
-
thinking: deltaText
|
1638
|
-
}
|
1639
|
-
});
|
1640
|
-
state$1.blockHasDelta.add(blockIndex);
|
1641
|
-
return events$1;
|
1642
|
-
};
|
1643
|
-
const handleReasoningSummaryPartDone = (rawEvent, state$1) => {
|
1644
|
-
const events$1 = ensureMessageStart(state$1);
|
1645
|
-
const outputIndex = toNumber(rawEvent.output_index);
|
1646
|
-
const part = isRecord(rawEvent.part) ? rawEvent.part : void 0;
|
1647
|
-
const text = part && typeof part.text === "string" ? part.text : "";
|
1648
|
-
const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
|
1649
|
-
if (text && !state$1.blockHasDelta.has(blockIndex)) events$1.push({
|
1650
|
-
type: "content_block_delta",
|
1651
|
-
index: blockIndex,
|
1652
|
-
delta: {
|
1653
|
-
type: "thinking_delta",
|
1654
|
-
thinking: text
|
1655
|
-
}
|
1656
|
-
});
|
1657
|
-
return events$1;
|
1658
|
-
};
|
1659
|
-
const handleOutputTextDone = (rawEvent, state$1) => {
|
1660
|
-
const events$1 = ensureMessageStart(state$1);
|
1661
|
-
const outputIndex = toNumber(rawEvent.output_index);
|
1662
|
-
const contentIndex = toNumber(rawEvent.content_index);
|
1663
|
-
const text = typeof rawEvent.text === "string" ? rawEvent.text : "";
|
1664
|
-
const blockIndex = openTextBlockIfNeeded(state$1, {
|
1665
|
-
outputIndex,
|
1666
|
-
contentIndex,
|
1667
|
-
events: events$1
|
1668
|
-
});
|
1669
|
-
if (text && !state$1.blockHasDelta.has(blockIndex)) events$1.push({
|
1670
|
-
type: "content_block_delta",
|
1671
|
-
index: blockIndex,
|
1672
|
-
delta: {
|
1673
|
-
type: "text_delta",
|
1674
|
-
text
|
1675
|
-
}
|
1676
|
-
});
|
1677
|
-
closeBlockIfOpen(state$1, blockIndex, events$1);
|
1678
|
-
return events$1;
|
1679
|
-
};
|
1680
|
-
const handleResponseCompleted = (rawEvent, state$1) => {
|
1681
|
-
const response = toResponsesResult(rawEvent.response);
|
1682
|
-
const events$1 = ensureMessageStart(state$1, response);
|
1683
|
-
closeAllOpenBlocks(state$1, events$1);
|
1684
|
-
if (response) {
|
1685
|
-
const anthropic = translateResponsesResultToAnthropic(response);
|
1686
|
-
events$1.push({
|
1687
|
-
type: "message_delta",
|
1688
|
-
delta: {
|
1689
|
-
stop_reason: anthropic.stop_reason,
|
1690
|
-
stop_sequence: anthropic.stop_sequence
|
1691
|
-
},
|
1692
|
-
usage: anthropic.usage
|
1693
|
-
});
|
1694
|
-
} else events$1.push({
|
1695
|
-
type: "message_delta",
|
1696
|
-
delta: {
|
1697
|
-
stop_reason: null,
|
1698
|
-
stop_sequence: null
|
1699
|
-
}
|
1700
|
-
});
|
1701
|
-
events$1.push({ type: "message_stop" });
|
1702
|
-
state$1.messageCompleted = true;
|
1703
|
-
return events$1;
|
1704
|
-
};
|
1705
|
-
const handleResponseFailed = (rawEvent, state$1) => {
|
1706
|
-
const response = toResponsesResult(rawEvent.response);
|
1707
|
-
const events$1 = ensureMessageStart(state$1, response);
|
1708
|
-
closeAllOpenBlocks(state$1, events$1);
|
1709
|
-
const message = typeof rawEvent.error === "string" ? rawEvent.error : "Response generation failed.";
|
1710
|
-
events$1.push(buildErrorEvent(message));
|
1711
|
-
state$1.messageCompleted = true;
|
1712
|
-
return events$1;
|
1713
|
-
};
|
1714
|
-
const handleErrorEvent = (rawEvent, state$1) => {
|
1715
|
-
const message = typeof rawEvent.message === "string" ? rawEvent.message : "An unexpected error occurred during streaming.";
|
1716
|
-
state$1.messageCompleted = true;
|
1717
|
-
return [buildErrorEvent(message)];
|
1718
|
-
};
|
1719
|
-
const ensureMessageStart = (state$1, response) => {
|
1720
|
-
if (state$1.messageStartSent) return [];
|
1721
|
-
if (response) cacheResponseMetadata(state$1, response);
|
1722
|
-
const id = response?.id ?? state$1.currentResponseId ?? "response";
|
1723
|
-
const model = response?.model ?? state$1.currentModel ?? "";
|
1724
|
-
state$1.messageStartSent = true;
|
1725
|
-
const inputTokens = (state$1.initialInputTokens ?? 0) - (state$1.initialInputCachedTokens ?? 0);
|
1726
|
-
return [{
|
1727
|
-
type: "message_start",
|
1728
|
-
message: {
|
1729
|
-
id,
|
1730
|
-
type: "message",
|
1731
|
-
role: "assistant",
|
1732
|
-
content: [],
|
1733
|
-
model,
|
1734
|
-
stop_reason: null,
|
1735
|
-
stop_sequence: null,
|
1736
|
-
usage: {
|
1737
|
-
input_tokens: inputTokens,
|
1738
|
-
output_tokens: 0,
|
1739
|
-
...state$1.initialInputCachedTokens !== void 0 && { cache_creation_input_tokens: state$1.initialInputCachedTokens }
|
1740
|
-
}
|
1741
|
-
}
|
1742
|
-
}];
|
1743
|
-
};
|
1744
|
-
const openTextBlockIfNeeded = (state$1, params) => {
|
1745
|
-
const { outputIndex, contentIndex, events: events$1 } = params;
|
1746
|
-
const key = getBlockKey(outputIndex, contentIndex);
|
1747
|
-
let blockIndex = state$1.blockIndexByKey.get(key);
|
1748
|
-
if (blockIndex === void 0) {
|
1749
|
-
blockIndex = state$1.nextContentBlockIndex;
|
1750
|
-
state$1.nextContentBlockIndex += 1;
|
1751
|
-
state$1.blockIndexByKey.set(key, blockIndex);
|
1752
|
-
}
|
1753
|
-
if (!state$1.openBlocks.has(blockIndex)) {
|
1754
|
-
events$1.push({
|
1755
|
-
type: "content_block_start",
|
1756
|
-
index: blockIndex,
|
1757
|
-
content_block: {
|
1758
|
-
type: "text",
|
1759
|
-
text: ""
|
1760
|
-
}
|
1761
|
-
});
|
1762
|
-
state$1.openBlocks.add(blockIndex);
|
1763
|
-
}
|
1764
|
-
return blockIndex;
|
1765
|
-
};
|
1766
|
-
const openThinkingBlockIfNeeded = (state$1, outputIndex, events$1) => {
|
1767
|
-
const key = getBlockKey(outputIndex, 0);
|
1768
|
-
let blockIndex = state$1.blockIndexByKey.get(key);
|
1769
|
-
if (blockIndex === void 0) {
|
1770
|
-
blockIndex = state$1.nextContentBlockIndex;
|
1771
|
-
state$1.nextContentBlockIndex += 1;
|
1772
|
-
state$1.blockIndexByKey.set(key, blockIndex);
|
1773
|
-
}
|
1774
|
-
if (!state$1.openBlocks.has(blockIndex)) {
|
1775
|
-
events$1.push({
|
1776
|
-
type: "content_block_start",
|
1777
|
-
index: blockIndex,
|
1778
|
-
content_block: {
|
1779
|
-
type: "thinking",
|
1780
|
-
thinking: ""
|
1781
|
-
}
|
1782
|
-
});
|
1783
|
-
state$1.openBlocks.add(blockIndex);
|
1784
|
-
}
|
1785
|
-
return blockIndex;
|
1786
|
-
};
|
1787
|
-
const closeBlockIfOpen = (state$1, blockIndex, events$1) => {
|
1788
|
-
if (!state$1.openBlocks.has(blockIndex)) return;
|
1789
|
-
events$1.push({
|
1790
|
-
type: "content_block_stop",
|
1791
|
-
index: blockIndex
|
1792
|
-
});
|
1793
|
-
state$1.openBlocks.delete(blockIndex);
|
1794
|
-
state$1.blockHasDelta.delete(blockIndex);
|
1795
|
-
};
|
1796
|
-
const closeAllOpenBlocks = (state$1, events$1) => {
|
1797
|
-
for (const blockIndex of state$1.openBlocks) closeBlockIfOpen(state$1, blockIndex, events$1);
|
1798
|
-
state$1.functionCallStateByOutputIndex.clear();
|
1799
|
-
state$1.functionCallOutputIndexByItemId.clear();
|
1800
|
-
};
|
1801
|
-
const cacheResponseMetadata = (state$1, response) => {
|
1802
|
-
state$1.currentResponseId = response.id;
|
1803
|
-
state$1.currentModel = response.model;
|
1804
|
-
state$1.initialInputTokens = response.usage?.input_tokens ?? 0;
|
1805
|
-
state$1.initialInputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
|
1806
|
-
};
|
1807
|
-
const buildErrorEvent = (message) => ({
|
1808
|
-
type: "error",
|
1809
|
-
error: {
|
1810
|
-
type: "api_error",
|
1811
|
-
message
|
1812
|
-
}
|
1813
|
-
});
|
1814
|
-
const getBlockKey = (outputIndex, contentIndex) => `${outputIndex}:${contentIndex}`;
|
1815
|
-
const resolveFunctionCallOutputIndex = (state$1, rawEvent) => {
|
1816
|
-
if (typeof rawEvent.output_index === "number" || typeof rawEvent.output_index === "string" && rawEvent.output_index.length > 0) {
|
1817
|
-
const parsed = toOptionalNumber(rawEvent.output_index);
|
1818
|
-
if (parsed !== void 0) return parsed;
|
1819
|
-
}
|
1820
|
-
const itemId = toNonEmptyString(rawEvent.item_id);
|
1821
|
-
if (itemId) {
|
1822
|
-
const mapped = state$1.functionCallOutputIndexByItemId.get(itemId);
|
1823
|
-
if (mapped !== void 0) return mapped;
|
1824
|
-
}
|
1825
|
-
};
|
1826
|
-
const openFunctionCallBlock = (state$1, params) => {
|
1827
|
-
const { outputIndex, toolCallId, name, events: events$1 } = params;
|
1828
|
-
let functionCallState = state$1.functionCallStateByOutputIndex.get(outputIndex);
|
1829
|
-
if (!functionCallState) {
|
1830
|
-
const blockIndex$1 = state$1.nextContentBlockIndex;
|
1831
|
-
state$1.nextContentBlockIndex += 1;
|
1832
|
-
const resolvedToolCallId = toolCallId ?? `tool_call_${blockIndex$1}`;
|
1833
|
-
functionCallState = {
|
1834
|
-
blockIndex: blockIndex$1,
|
1835
|
-
toolCallId: resolvedToolCallId,
|
1836
|
-
name: name ?? "function"
|
1837
|
-
};
|
1838
|
-
state$1.functionCallStateByOutputIndex.set(outputIndex, functionCallState);
|
1839
|
-
state$1.functionCallOutputIndexByItemId.set(resolvedToolCallId, outputIndex);
|
1840
|
-
}
|
1841
|
-
const { blockIndex } = functionCallState;
|
1842
|
-
if (!state$1.openBlocks.has(blockIndex)) {
|
1843
|
-
events$1.push({
|
1844
|
-
type: "content_block_start",
|
1845
|
-
index: blockIndex,
|
1846
|
-
content_block: {
|
1847
|
-
type: "tool_use",
|
1848
|
-
id: functionCallState.toolCallId,
|
1849
|
-
name: functionCallState.name,
|
1850
|
-
input: {}
|
1851
|
-
}
|
1852
|
-
});
|
1853
|
-
state$1.openBlocks.add(blockIndex);
|
1854
|
-
}
|
1855
|
-
return blockIndex;
|
1856
|
-
};
|
1857
|
-
const extractFunctionCallDetails = (rawEvent, state$1) => {
|
1858
|
-
const item = isRecord(rawEvent.item) ? rawEvent.item : void 0;
|
1859
|
-
if (!item) return;
|
1860
|
-
if ((typeof item.type === "string" ? item.type : void 0) !== "function_call") return;
|
1861
|
-
const outputIndex = resolveFunctionCallOutputIndex(state$1, rawEvent);
|
1862
|
-
if (outputIndex === void 0) return;
|
1863
|
-
const callId = toNonEmptyString(item.call_id);
|
1864
|
-
const itemId = toNonEmptyString(item.id);
|
1865
|
-
const name = toNonEmptyString(item.name) ?? "function";
|
1866
|
-
const toolCallId = callId ?? itemId ?? `tool_call_${outputIndex}`;
|
1867
|
-
const initialArguments = typeof item.arguments === "string" ? item.arguments : void 0;
|
1868
|
-
return {
|
1869
|
-
outputIndex,
|
1870
|
-
toolCallId,
|
1871
|
-
name,
|
1872
|
-
initialArguments,
|
1873
|
-
itemId
|
1874
|
-
};
|
1875
|
-
};
|
1876
|
-
const toResponsesResult = (value) => isResponsesResult(value) ? value : void 0;
|
1877
|
-
const toOptionalNumber = (value) => {
|
1878
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
1879
|
-
if (typeof value === "string" && value.length > 0) {
|
1880
|
-
const parsed = Number(value);
|
1881
|
-
if (Number.isFinite(parsed)) return parsed;
|
1882
|
-
}
|
1883
|
-
};
|
1884
|
-
const toNonEmptyString = (value) => {
|
1885
|
-
if (typeof value === "string" && value.length > 0) return value;
|
1886
|
-
};
|
1887
|
-
const toNumber = (value) => {
|
1888
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
1889
|
-
if (typeof value === "string") {
|
1890
|
-
const parsed = Number(value);
|
1891
|
-
if (Number.isFinite(parsed)) return parsed;
|
1892
|
-
}
|
1893
|
-
return 0;
|
1894
|
-
};
|
1895
|
-
const isResponsesResult = (value) => {
|
1896
|
-
if (!isRecord(value)) return false;
|
1897
|
-
if (typeof value.id !== "string") return false;
|
1898
|
-
if (typeof value.model !== "string") return false;
|
1899
|
-
if (!Array.isArray(value.output)) return false;
|
1900
|
-
if (typeof value.object !== "string") return false;
|
1901
|
-
return true;
|
1902
|
-
};
|
1903
|
-
const isRecord = (value) => typeof value === "object" && value !== null;
|
1904
|
-
|
1905
|
-
//#endregion
|
1906
|
-
//#region src/routes/responses/utils.ts
|
1907
|
-
const getResponsesRequestOptions = (payload) => {
|
1908
|
-
const vision = hasVisionInput(payload);
|
1909
|
-
const initiator = hasAgentInitiator(payload) ? "agent" : "user";
|
1910
|
-
return {
|
1911
|
-
vision,
|
1912
|
-
initiator
|
1913
|
-
};
|
1914
|
-
};
|
1915
|
-
const hasAgentInitiator = (payload) => getPayloadItems(payload).some((item) => {
|
1916
|
-
if (!("role" in item) || !item.role) return true;
|
1917
|
-
return (typeof item.role === "string" ? item.role.toLowerCase() : "") === "assistant";
|
1918
|
-
});
|
1919
|
-
const hasVisionInput = (payload) => {
|
1920
|
-
return getPayloadItems(payload).some((item) => containsVisionContent(item));
|
1921
|
-
};
|
1922
|
-
const getPayloadItems = (payload) => {
|
1923
|
-
const result = [];
|
1924
|
-
const { input } = payload;
|
1925
|
-
if (Array.isArray(input)) result.push(...input);
|
1926
|
-
return result;
|
1927
|
-
};
|
1928
|
-
const containsVisionContent = (value) => {
|
1929
|
-
if (!value) return false;
|
1930
|
-
if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
|
1931
|
-
if (typeof value !== "object") return false;
|
1932
|
-
const record = value;
|
1933
|
-
if ((typeof record.type === "string" ? record.type.toLowerCase() : void 0) === "input_image") return true;
|
1934
|
-
if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
|
1935
|
-
return false;
|
1936
|
-
};
|
1937
|
-
|
1938
1093
|
//#endregion
|
1939
1094
|
//#region src/routes/messages/stream-translation.ts
|
1940
1095
|
function isToolBlockOpen(state$1) {
|
@@ -2065,15 +1220,9 @@ async function handleCompletion(c) {
|
|
2065
1220
|
await checkRateLimit(state);
|
2066
1221
|
const anthropicPayload = await c.req.json();
|
2067
1222
|
consola.debug("Anthropic request payload:", JSON.stringify(anthropicPayload));
|
2068
|
-
const useResponsesApi = shouldUseResponsesApi(anthropicPayload.model);
|
2069
|
-
if (state.manualApprove) await awaitApproval();
|
2070
|
-
if (useResponsesApi) return await handleWithResponsesApi(c, anthropicPayload);
|
2071
|
-
return await handleWithChatCompletions(c, anthropicPayload);
|
2072
|
-
}
|
2073
|
-
const RESPONSES_ENDPOINT$1 = "/responses";
|
2074
|
-
const handleWithChatCompletions = async (c, anthropicPayload) => {
|
2075
1223
|
const openAIPayload = translateToOpenAI(anthropicPayload);
|
2076
1224
|
consola.debug("Translated OpenAI request payload:", JSON.stringify(openAIPayload));
|
1225
|
+
if (state.manualApprove) await awaitApproval();
|
2077
1226
|
const response = await createChatCompletions(openAIPayload);
|
2078
1227
|
if (isNonStreaming(response)) {
|
2079
1228
|
consola.debug("Non-streaming response from Copilot:", JSON.stringify(response).slice(-400));
|
@@ -2093,8 +1242,7 @@ const handleWithChatCompletions = async (c, anthropicPayload) => {
|
|
2093
1242
|
consola.debug("Copilot raw stream event:", JSON.stringify(rawEvent));
|
2094
1243
|
if (rawEvent.data === "[DONE]") break;
|
2095
1244
|
if (!rawEvent.data) continue;
|
2096
|
-
const
|
2097
|
-
const events$1 = translateChunkToAnthropicEvents(chunk, streamState);
|
1245
|
+
const events$1 = translateChunkToAnthropicEvents(JSON.parse(rawEvent.data), streamState);
|
2098
1246
|
for (const event of events$1) {
|
2099
1247
|
consola.debug("Translated Anthropic event:", JSON.stringify(event));
|
2100
1248
|
await stream.writeSSE({
|
@@ -2104,70 +1252,8 @@ const handleWithChatCompletions = async (c, anthropicPayload) => {
|
|
2104
1252
|
}
|
2105
1253
|
}
|
2106
1254
|
});
|
2107
|
-
}
|
2108
|
-
const handleWithResponsesApi = async (c, anthropicPayload) => {
|
2109
|
-
const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload);
|
2110
|
-
consola.debug("Translated Responses payload:", JSON.stringify(responsesPayload));
|
2111
|
-
const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
|
2112
|
-
const response = await createResponses(responsesPayload, {
|
2113
|
-
vision,
|
2114
|
-
initiator
|
2115
|
-
});
|
2116
|
-
if (responsesPayload.stream && isAsyncIterable$1(response)) {
|
2117
|
-
consola.debug("Streaming response from Copilot (Responses API)");
|
2118
|
-
return streamSSE(c, async (stream) => {
|
2119
|
-
const streamState = createResponsesStreamState();
|
2120
|
-
for await (const chunk of response) {
|
2121
|
-
consola.debug("Responses raw stream event:", JSON.stringify(chunk));
|
2122
|
-
if (chunk.event === "ping") {
|
2123
|
-
await stream.writeSSE({
|
2124
|
-
event: "ping",
|
2125
|
-
data: ""
|
2126
|
-
});
|
2127
|
-
continue;
|
2128
|
-
}
|
2129
|
-
const data = chunk.data;
|
2130
|
-
if (!data) continue;
|
2131
|
-
if (data === "[DONE]") break;
|
2132
|
-
const parsed = safeJsonParse(data);
|
2133
|
-
if (!parsed) continue;
|
2134
|
-
const events$1 = translateResponsesStreamEvent(parsed, streamState);
|
2135
|
-
for (const event of events$1) {
|
2136
|
-
consola.debug("Translated Anthropic event:", JSON.stringify(event));
|
2137
|
-
await stream.writeSSE({
|
2138
|
-
event: event.type,
|
2139
|
-
data: JSON.stringify(event)
|
2140
|
-
});
|
2141
|
-
}
|
2142
|
-
}
|
2143
|
-
if (!streamState.messageCompleted) {
|
2144
|
-
consola.warn("Responses stream ended without completion; sending fallback message_stop");
|
2145
|
-
const fallback = { type: "message_stop" };
|
2146
|
-
await stream.writeSSE({
|
2147
|
-
event: fallback.type,
|
2148
|
-
data: JSON.stringify(fallback)
|
2149
|
-
});
|
2150
|
-
}
|
2151
|
-
});
|
2152
|
-
}
|
2153
|
-
consola.debug("Non-streaming Responses result:", JSON.stringify(response).slice(-400));
|
2154
|
-
const anthropicResponse = translateResponsesResultToAnthropic(response);
|
2155
|
-
consola.debug("Translated Anthropic response:", JSON.stringify(anthropicResponse));
|
2156
|
-
return c.json(anthropicResponse);
|
2157
|
-
};
|
2158
|
-
const shouldUseResponsesApi = (modelId) => {
|
2159
|
-
return (state.models?.data.find((model) => model.id === modelId))?.supported_endpoints?.includes(RESPONSES_ENDPOINT$1) ?? false;
|
2160
|
-
};
|
1255
|
+
}
|
2161
1256
|
const isNonStreaming = (response) => Object.hasOwn(response, "choices");
|
2162
|
-
const isAsyncIterable$1 = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
|
2163
|
-
const safeJsonParse = (value) => {
|
2164
|
-
try {
|
2165
|
-
return JSON.parse(value);
|
2166
|
-
} catch (error) {
|
2167
|
-
consola.warn("Failed to parse Responses stream chunk:", value, error);
|
2168
|
-
return;
|
2169
|
-
}
|
2170
|
-
};
|
2171
1257
|
|
2172
1258
|
//#endregion
|
2173
1259
|
//#region src/routes/messages/route.ts
|
@@ -2212,68 +1298,6 @@ modelRoutes.get("/", async (c) => {
|
|
2212
1298
|
}
|
2213
1299
|
});
|
2214
1300
|
|
2215
|
-
//#endregion
|
2216
|
-
//#region src/routes/responses/handler.ts
|
2217
|
-
const RESPONSES_ENDPOINT = "/responses";
|
2218
|
-
const handleResponses = async (c) => {
|
2219
|
-
await checkRateLimit(state);
|
2220
|
-
const payload = await c.req.json();
|
2221
|
-
consola.debug("Responses request payload:", JSON.stringify(payload));
|
2222
|
-
if (!((state.models?.data.find((model) => model.id === payload.model))?.supported_endpoints?.includes(RESPONSES_ENDPOINT) ?? false)) return c.json({ error: {
|
2223
|
-
message: "This model does not support the responses endpoint. Please choose a different model.",
|
2224
|
-
type: "invalid_request_error"
|
2225
|
-
} }, 400);
|
2226
|
-
const { vision, initiator } = getResponsesRequestOptions(payload);
|
2227
|
-
if (state.manualApprove) await awaitApproval();
|
2228
|
-
const response = await createResponses(payload, {
|
2229
|
-
vision,
|
2230
|
-
initiator
|
2231
|
-
});
|
2232
|
-
if (isStreamingRequested(payload) && isAsyncIterable(response)) {
|
2233
|
-
consola.debug("Forwarding native Responses stream");
|
2234
|
-
return streamSSE(c, async (stream) => {
|
2235
|
-
const pingInterval = setInterval(async () => {
|
2236
|
-
try {
|
2237
|
-
await stream.writeSSE({
|
2238
|
-
event: "ping",
|
2239
|
-
data: JSON.stringify({ timestamp: Date.now() })
|
2240
|
-
});
|
2241
|
-
} catch (error) {
|
2242
|
-
consola.warn("Failed to send ping:", error);
|
2243
|
-
clearInterval(pingInterval);
|
2244
|
-
}
|
2245
|
-
}, 3e3);
|
2246
|
-
try {
|
2247
|
-
for await (const chunk of response) {
|
2248
|
-
consola.debug("Responses stream chunk:", JSON.stringify(chunk));
|
2249
|
-
await stream.writeSSE({
|
2250
|
-
id: chunk.id,
|
2251
|
-
event: chunk.event,
|
2252
|
-
data: chunk.data ?? ""
|
2253
|
-
});
|
2254
|
-
}
|
2255
|
-
} finally {
|
2256
|
-
clearInterval(pingInterval);
|
2257
|
-
}
|
2258
|
-
});
|
2259
|
-
}
|
2260
|
-
consola.debug("Forwarding native Responses result:", JSON.stringify(response).slice(-400));
|
2261
|
-
return c.json(response);
|
2262
|
-
};
|
2263
|
-
const isAsyncIterable = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
|
2264
|
-
const isStreamingRequested = (payload) => Boolean(payload.stream);
|
2265
|
-
|
2266
|
-
//#endregion
|
2267
|
-
//#region src/routes/responses/route.ts
|
2268
|
-
const responsesRoutes = new Hono();
|
2269
|
-
responsesRoutes.post("/", async (c) => {
|
2270
|
-
try {
|
2271
|
-
return await handleResponses(c);
|
2272
|
-
} catch (error) {
|
2273
|
-
return await forwardError(c, error);
|
2274
|
-
}
|
2275
|
-
});
|
2276
|
-
|
2277
1301
|
//#endregion
|
2278
1302
|
//#region src/routes/token/route.ts
|
2279
1303
|
const tokenRoute = new Hono();
|
@@ -2313,16 +1337,15 @@ server.route("/models", modelRoutes);
|
|
2313
1337
|
server.route("/embeddings", embeddingRoutes);
|
2314
1338
|
server.route("/usage", usageRoute);
|
2315
1339
|
server.route("/token", tokenRoute);
|
2316
|
-
server.route("/responses", responsesRoutes);
|
2317
1340
|
server.route("/v1/chat/completions", completionRoutes);
|
2318
1341
|
server.route("/v1/models", modelRoutes);
|
2319
1342
|
server.route("/v1/embeddings", embeddingRoutes);
|
2320
|
-
server.route("/v1/responses", responsesRoutes);
|
2321
1343
|
server.route("/v1/messages", messageRoutes);
|
2322
1344
|
|
2323
1345
|
//#endregion
|
2324
1346
|
//#region src/start.ts
|
2325
1347
|
async function runServer(options) {
|
1348
|
+
if (options.proxyEnv) initProxyFromEnv();
|
2326
1349
|
if (options.verbose) {
|
2327
1350
|
consola.level = 5;
|
2328
1351
|
consola.info("Verbose logging enabled");
|
@@ -2432,6 +1455,11 @@ const start = defineCommand({
|
|
2432
1455
|
type: "boolean",
|
2433
1456
|
default: false,
|
2434
1457
|
description: "Show GitHub and Copilot tokens on fetch and refresh"
|
1458
|
+
},
|
1459
|
+
"proxy-env": {
|
1460
|
+
type: "boolean",
|
1461
|
+
default: false,
|
1462
|
+
description: "Initialize proxy from environment variables"
|
2435
1463
|
}
|
2436
1464
|
},
|
2437
1465
|
run({ args }) {
|
@@ -2446,16 +1474,17 @@ const start = defineCommand({
|
|
2446
1474
|
rateLimitWait: args.wait,
|
2447
1475
|
githubToken: args["github-token"],
|
2448
1476
|
claudeCode: args["claude-code"],
|
2449
|
-
showToken: args["show-token"]
|
1477
|
+
showToken: args["show-token"],
|
1478
|
+
proxyEnv: args["proxy-env"]
|
2450
1479
|
});
|
2451
1480
|
}
|
2452
1481
|
});
|
2453
1482
|
|
2454
1483
|
//#endregion
|
2455
1484
|
//#region src/main.ts
|
2456
|
-
|
1485
|
+
await runMain(defineCommand({
|
2457
1486
|
meta: {
|
2458
|
-
name: "
|
1487
|
+
name: "copilot-api",
|
2459
1488
|
description: "A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools."
|
2460
1489
|
},
|
2461
1490
|
subCommands: {
|
@@ -2464,9 +1493,7 @@ const main = defineCommand({
|
|
2464
1493
|
"check-usage": checkUsage,
|
2465
1494
|
debug
|
2466
1495
|
}
|
2467
|
-
});
|
2468
|
-
initProxyFromEnv();
|
2469
|
-
await runMain(main);
|
1496
|
+
}));
|
2470
1497
|
|
2471
1498
|
//#endregion
|
2472
1499
|
export { };
|