heibaiapi 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +168 -223
- package/dist/main.js.map +1 -1
- package/package.json +2 -2
package/dist/main.js
CHANGED
@@ -17,17 +17,21 @@ import { cors } from "hono/cors";
|
|
17
17
|
import { logger } from "hono/logger";
|
18
18
|
import { streamSSE } from "hono/streaming";
|
19
19
|
import { events } from "fetch-event-stream";
|
20
|
+
import fs$1 from "node:fs";
|
20
21
|
|
21
22
|
//#region src/lib/paths.ts
|
22
|
-
const APP_DIR = path.join(os.homedir(), ".local", "share", "
|
23
|
+
const APP_DIR = path.join(os.homedir(), ".local", "share", "copilot-api");
|
23
24
|
const GITHUB_TOKEN_PATH = path.join(APP_DIR, "github_token");
|
25
|
+
const CONFIG_PATH = path.join(APP_DIR, "config.json");
|
24
26
|
const PATHS = {
|
25
27
|
APP_DIR,
|
26
|
-
GITHUB_TOKEN_PATH
|
28
|
+
GITHUB_TOKEN_PATH,
|
29
|
+
CONFIG_PATH
|
27
30
|
};
|
28
31
|
async function ensurePaths() {
|
29
32
|
await fs.mkdir(PATHS.APP_DIR, { recursive: true });
|
30
33
|
await ensureFile(PATHS.GITHUB_TOKEN_PATH);
|
34
|
+
await ensureFile(PATHS.CONFIG_PATH);
|
31
35
|
}
|
32
36
|
async function ensureFile(filePath) {
|
33
37
|
try {
|
@@ -401,7 +405,7 @@ async function getDebugInfo() {
|
|
401
405
|
};
|
402
406
|
}
|
403
407
|
function printDebugInfoPlain(info) {
|
404
|
-
consola.info(`
|
408
|
+
consola.info(`copilot-api debug
|
405
409
|
|
406
410
|
Version: ${info.version}
|
407
411
|
Runtime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})
|
@@ -487,8 +491,7 @@ function getShell() {
|
|
487
491
|
const { platform, ppid, env } = process$1;
|
488
492
|
if (platform === "win32") {
|
489
493
|
try {
|
490
|
-
|
491
|
-
if (execSync(command, { stdio: "pipe" }).toString().toLowerCase().includes("powershell.exe")) return "powershell";
|
494
|
+
if (execSync(`wmic process get ParentProcessId,Name | findstr "${ppid}"`, { stdio: "pipe" }).toString().toLowerCase().includes("powershell.exe")) return "powershell";
|
492
495
|
} catch {
|
493
496
|
return "cmd";
|
494
497
|
}
|
@@ -748,8 +751,7 @@ const numTokensForTools = (tools, encoder, constants) => {
|
|
748
751
|
* Calculate the token count of messages, supporting multiple GPT encoders
|
749
752
|
*/
|
750
753
|
const getTokenCount = async (payload, model) => {
|
751
|
-
const
|
752
|
-
const encoder = await getEncodeChatFunction(tokenizer);
|
754
|
+
const encoder = await getEncodeChatFunction(getTokenizerFromModel(model));
|
753
755
|
const simplifiedMessages = payload.messages;
|
754
756
|
const inputMessages = simplifiedMessages.filter((msg) => msg.role !== "assistant");
|
755
757
|
const outputMessages = simplifiedMessages.filter((msg) => msg.role === "assistant");
|
@@ -853,8 +855,7 @@ const createEmbeddings = async (payload) => {
|
|
853
855
|
const embeddingRoutes = new Hono();
|
854
856
|
embeddingRoutes.post("/", async (c) => {
|
855
857
|
try {
|
856
|
-
const
|
857
|
-
const response = await createEmbeddings(paylod);
|
858
|
+
const response = await createEmbeddings(await c.req.json());
|
858
859
|
return c.json(response);
|
859
860
|
} catch (error) {
|
860
861
|
return await forwardError(c, error);
|
@@ -1112,6 +1113,60 @@ const createResponses = async (payload, { vision, initiator }) => {
|
|
1112
1113
|
return await response.json();
|
1113
1114
|
};
|
1114
1115
|
|
1116
|
+
//#endregion
|
1117
|
+
//#region src/lib/config.ts
|
1118
|
+
const defaultConfig = { extraPrompts: { "gpt-5-codex": `
|
1119
|
+
## Tool use
|
1120
|
+
- 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.
|
1121
|
+
### Bash tool
|
1122
|
+
When using the Bash tool, follow these rules:
|
1123
|
+
- always run_in_background set to false, unless you are running a long-running command (e.g., a server or a watch command).
|
1124
|
+
### BashOutput tool
|
1125
|
+
When using the BashOutput tool, follow these rules:
|
1126
|
+
- Only Bash Tool run_in_background set to true, Use BashOutput to read the output later
|
1127
|
+
### TodoWrite tool
|
1128
|
+
When using the TodoWrite tool, follow these rules:
|
1129
|
+
- Skip using the TodoWrite tool for tasks with three or fewer steps.
|
1130
|
+
- Do not make single-step todo lists.
|
1131
|
+
- When you made a todo, update it after having performed one of the sub-tasks that you shared on the todo list.
|
1132
|
+
## Special user requests
|
1133
|
+
- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as 'date'), you should do so.
|
1134
|
+
` } };
|
1135
|
+
let cachedConfig = null;
|
1136
|
+
function ensureConfigFile() {
|
1137
|
+
try {
|
1138
|
+
fs$1.accessSync(PATHS.CONFIG_PATH, fs$1.constants.R_OK | fs$1.constants.W_OK);
|
1139
|
+
} catch {
|
1140
|
+
fs$1.writeFileSync(PATHS.CONFIG_PATH, `${JSON.stringify(defaultConfig, null, 2)}\n`, "utf8");
|
1141
|
+
try {
|
1142
|
+
fs$1.chmodSync(PATHS.CONFIG_PATH, 384);
|
1143
|
+
} catch {
|
1144
|
+
return;
|
1145
|
+
}
|
1146
|
+
}
|
1147
|
+
}
|
1148
|
+
function readConfigFromDisk() {
|
1149
|
+
ensureConfigFile();
|
1150
|
+
try {
|
1151
|
+
const raw = fs$1.readFileSync(PATHS.CONFIG_PATH, "utf8");
|
1152
|
+
if (!raw.trim()) {
|
1153
|
+
fs$1.writeFileSync(PATHS.CONFIG_PATH, `${JSON.stringify(defaultConfig, null, 2)}\n`, "utf8");
|
1154
|
+
return defaultConfig;
|
1155
|
+
}
|
1156
|
+
return JSON.parse(raw);
|
1157
|
+
} catch (error) {
|
1158
|
+
consola.error("Failed to read config file, using default config", error);
|
1159
|
+
return defaultConfig;
|
1160
|
+
}
|
1161
|
+
}
|
1162
|
+
function getConfig() {
|
1163
|
+
if (!cachedConfig) cachedConfig = readConfigFromDisk();
|
1164
|
+
return cachedConfig;
|
1165
|
+
}
|
1166
|
+
function getExtraPromptForModel(model) {
|
1167
|
+
return getConfig().extraPrompts?.[model] ?? "";
|
1168
|
+
}
|
1169
|
+
|
1115
1170
|
//#endregion
|
1116
1171
|
//#region src/routes/messages/responses-translation.ts
|
1117
1172
|
const MESSAGE_TYPE = "message";
|
@@ -1124,7 +1179,7 @@ const translateAnthropicMessagesToResponsesPayload = (payload) => {
|
|
1124
1179
|
return {
|
1125
1180
|
model: payload.model,
|
1126
1181
|
input,
|
1127
|
-
instructions: translateSystemPrompt(payload.system),
|
1182
|
+
instructions: translateSystemPrompt(payload.system, payload.model),
|
1128
1183
|
temperature: payload.temperature ?? null,
|
1129
1184
|
top_p: payload.top_p ?? null,
|
1130
1185
|
max_output_tokens: payload.max_tokens,
|
@@ -1138,7 +1193,7 @@ const translateAnthropicMessagesToResponsesPayload = (payload) => {
|
|
1138
1193
|
parallel_tool_calls: true,
|
1139
1194
|
reasoning: {
|
1140
1195
|
effort: "high",
|
1141
|
-
summary: "
|
1196
|
+
summary: "detailed"
|
1142
1197
|
},
|
1143
1198
|
include: ["reasoning.encrypted_content"]
|
1144
1199
|
};
|
@@ -1175,7 +1230,7 @@ const translateAssistantMessage = (message) => {
|
|
1175
1230
|
items.push(createFunctionToolCall(block));
|
1176
1231
|
continue;
|
1177
1232
|
}
|
1178
|
-
if (block.type === "thinking") {
|
1233
|
+
if (block.type === "thinking" && block.signature && block.signature.includes("@")) {
|
1179
1234
|
flushPendingContent("assistant", pendingContent, items);
|
1180
1235
|
items.push(createReasoningContent(block));
|
1181
1236
|
continue;
|
@@ -1201,7 +1256,7 @@ const translateAssistantContentBlock = (block) => {
|
|
1201
1256
|
};
|
1202
1257
|
const flushPendingContent = (role, pendingContent, target) => {
|
1203
1258
|
if (pendingContent.length === 0) return;
|
1204
|
-
const messageContent =
|
1259
|
+
const messageContent = [...pendingContent];
|
1205
1260
|
target.push(createMessage(role, messageContent));
|
1206
1261
|
pendingContent.length = 0;
|
1207
1262
|
};
|
@@ -1220,16 +1275,22 @@ const createOutPutTextContent = (text) => ({
|
|
1220
1275
|
});
|
1221
1276
|
const createImageContent = (block) => ({
|
1222
1277
|
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
|
1278
|
+
image_url: `data:${block.source.media_type};base64,${block.source.data}`,
|
1279
|
+
detail: "auto"
|
1232
1280
|
});
|
1281
|
+
const createReasoningContent = (block) => {
|
1282
|
+
const array = block.signature.split("@");
|
1283
|
+
const signature = array[0];
|
1284
|
+
return {
|
1285
|
+
id: array[1],
|
1286
|
+
type: "reasoning",
|
1287
|
+
summary: [{
|
1288
|
+
type: "summary_text",
|
1289
|
+
text: block.thinking
|
1290
|
+
}],
|
1291
|
+
encrypted_content: signature
|
1292
|
+
};
|
1293
|
+
};
|
1233
1294
|
const createFunctionToolCall = (block) => ({
|
1234
1295
|
type: "function_call",
|
1235
1296
|
call_id: block.id,
|
@@ -1243,25 +1304,12 @@ const createFunctionCallOutput = (block) => ({
|
|
1243
1304
|
output: convertToolResultContent(block.content),
|
1244
1305
|
status: block.is_error ? "incomplete" : "completed"
|
1245
1306
|
});
|
1246
|
-
const translateSystemPrompt = (system) => {
|
1307
|
+
const translateSystemPrompt = (system, model) => {
|
1247
1308
|
if (!system) return null;
|
1248
|
-
const
|
1249
|
-
|
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;
|
1309
|
+
const extraPrompt = getExtraPromptForModel(model);
|
1310
|
+
if (typeof system === "string") return system + extraPrompt;
|
1263
1311
|
const text = system.map((block, index) => {
|
1264
|
-
if (index === 0) return block.text +
|
1312
|
+
if (index === 0) return block.text + extraPrompt;
|
1265
1313
|
return block.text;
|
1266
1314
|
}).join(" ");
|
1267
1315
|
return text.length > 0 ? text : null;
|
@@ -1277,22 +1325,18 @@ const convertAnthropicTools = (tools) => {
|
|
1277
1325
|
}));
|
1278
1326
|
};
|
1279
1327
|
const convertAnthropicToolChoice = (choice) => {
|
1280
|
-
if (!choice) return;
|
1328
|
+
if (!choice) return "auto";
|
1281
1329
|
switch (choice.type) {
|
1282
1330
|
case "auto": return "auto";
|
1283
1331
|
case "any": return "required";
|
1284
1332
|
case "tool": return choice.name ? {
|
1285
1333
|
type: "function",
|
1286
1334
|
name: choice.name
|
1287
|
-
} :
|
1335
|
+
} : "auto";
|
1288
1336
|
case "none": return "none";
|
1289
|
-
default: return;
|
1337
|
+
default: return "auto";
|
1290
1338
|
}
|
1291
1339
|
};
|
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
1340
|
const translateResponsesResultToAnthropic = (response) => {
|
1297
1341
|
const contentBlocks = mapOutputToAnthropicContent(response.output);
|
1298
1342
|
const usage = mapResponsesUsage(response);
|
@@ -1318,7 +1362,7 @@ const mapOutputToAnthropicContent = (output) => {
|
|
1318
1362
|
if (thinkingText.length > 0) contentBlocks.push({
|
1319
1363
|
type: "thinking",
|
1320
1364
|
thinking: thinkingText,
|
1321
|
-
signature: item.encrypted_content ?? ""
|
1365
|
+
signature: (item.encrypted_content ?? "") + "@" + item.id
|
1322
1366
|
});
|
1323
1367
|
break;
|
1324
1368
|
}
|
@@ -1381,7 +1425,7 @@ const extractReasoningText = (item) => {
|
|
1381
1425
|
return segments.join("").trim();
|
1382
1426
|
};
|
1383
1427
|
const createToolUseContentBlock = (call) => {
|
1384
|
-
const toolId = call.call_id
|
1428
|
+
const toolId = call.call_id;
|
1385
1429
|
if (!call.name || !toolId) return null;
|
1386
1430
|
const input = parseFunctionCallArguments(call.arguments);
|
1387
1431
|
return {
|
@@ -1418,23 +1462,21 @@ const mapResponsesStopReason = (response) => {
|
|
1418
1462
|
if (status === "incomplete") {
|
1419
1463
|
if (incompleteDetails?.reason === "max_output_tokens") return "max_tokens";
|
1420
1464
|
if (incompleteDetails?.reason === "content_filter") return "end_turn";
|
1421
|
-
if (incompleteDetails?.reason === "tool_use") return "tool_use";
|
1422
1465
|
}
|
1423
1466
|
return null;
|
1424
1467
|
};
|
1425
1468
|
const mapResponsesUsage = (response) => {
|
1426
1469
|
const inputTokens = response.usage?.input_tokens ?? 0;
|
1427
1470
|
const outputTokens = response.usage?.output_tokens ?? 0;
|
1428
|
-
const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
|
1429
1471
|
return {
|
1430
|
-
input_tokens: inputTokens - (
|
1472
|
+
input_tokens: inputTokens - (response.usage?.input_tokens_details?.cached_tokens ?? 0),
|
1431
1473
|
output_tokens: outputTokens,
|
1432
1474
|
...response.usage?.input_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: response.usage.input_tokens_details.cached_tokens }
|
1433
1475
|
};
|
1434
1476
|
};
|
1435
|
-
const isRecord
|
1436
|
-
const isResponseOutputText = (block) => isRecord
|
1437
|
-
const isResponseOutputRefusal = (block) => isRecord
|
1477
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
1478
|
+
const isResponseOutputText = (block) => isRecord(block) && "type" in block && block.type === "output_text";
|
1479
|
+
const isResponseOutputRefusal = (block) => isRecord(block) && "type" in block && block.type === "refusal";
|
1438
1480
|
const parseUserId = (userId) => {
|
1439
1481
|
if (!userId || typeof userId !== "string") return {
|
1440
1482
|
safetyIdentifier: null,
|
@@ -1443,10 +1485,9 @@ const parseUserId = (userId) => {
|
|
1443
1485
|
const userMatch = userId.match(/user_([^_]+)_account/);
|
1444
1486
|
const safetyIdentifier = userMatch ? userMatch[1] : null;
|
1445
1487
|
const sessionMatch = userId.match(/_session_(.+)$/);
|
1446
|
-
const promptCacheKey = sessionMatch ? sessionMatch[1] : null;
|
1447
1488
|
return {
|
1448
1489
|
safetyIdentifier,
|
1449
|
-
promptCacheKey
|
1490
|
+
promptCacheKey: sessionMatch ? sessionMatch[1] : null
|
1450
1491
|
};
|
1451
1492
|
};
|
1452
1493
|
const convertToolResultContent = (content) => {
|
@@ -1476,19 +1517,17 @@ const createResponsesStreamState = () => ({
|
|
1476
1517
|
blockIndexByKey: /* @__PURE__ */ new Map(),
|
1477
1518
|
openBlocks: /* @__PURE__ */ new Set(),
|
1478
1519
|
blockHasDelta: /* @__PURE__ */ new Set(),
|
1479
|
-
functionCallStateByOutputIndex: /* @__PURE__ */ new Map()
|
1480
|
-
functionCallOutputIndexByItemId: /* @__PURE__ */ new Map()
|
1520
|
+
functionCallStateByOutputIndex: /* @__PURE__ */ new Map()
|
1481
1521
|
});
|
1482
1522
|
const translateResponsesStreamEvent = (rawEvent, state$1) => {
|
1483
|
-
const eventType =
|
1484
|
-
if (!eventType) return [];
|
1523
|
+
const eventType = rawEvent.type;
|
1485
1524
|
switch (eventType) {
|
1486
1525
|
case "response.created": return handleResponseCreated(rawEvent, state$1);
|
1526
|
+
case "response.output_item.added": return handleOutputItemAdded(rawEvent, state$1);
|
1487
1527
|
case "response.reasoning_summary_text.delta": return handleReasoningSummaryTextDelta(rawEvent, state$1);
|
1488
1528
|
case "response.output_text.delta": return handleOutputTextDelta(rawEvent, state$1);
|
1489
|
-
case "response.
|
1529
|
+
case "response.reasoning_summary_text.done": return handleReasoningSummaryTextDone(rawEvent, state$1);
|
1490
1530
|
case "response.output_text.done": return handleOutputTextDone(rawEvent, state$1);
|
1491
|
-
case "response.output_item.added": return handleOutputItemAdded(rawEvent, state$1);
|
1492
1531
|
case "response.output_item.done": return handleOutputItemDone(rawEvent, state$1);
|
1493
1532
|
case "response.function_call_arguments.delta": return handleFunctionCallArgumentsDelta(rawEvent, state$1);
|
1494
1533
|
case "response.function_call_arguments.done": return handleFunctionCallArgumentsDone(rawEvent, state$1);
|
@@ -1496,21 +1535,19 @@ const translateResponsesStreamEvent = (rawEvent, state$1) => {
|
|
1496
1535
|
case "response.incomplete": return handleResponseCompleted(rawEvent, state$1);
|
1497
1536
|
case "response.failed": return handleResponseFailed(rawEvent, state$1);
|
1498
1537
|
case "error": return handleErrorEvent(rawEvent, state$1);
|
1499
|
-
default:
|
1538
|
+
default:
|
1539
|
+
consola.debug("Unknown Responses stream event type:", eventType);
|
1540
|
+
return [];
|
1500
1541
|
}
|
1501
1542
|
};
|
1502
1543
|
const handleResponseCreated = (rawEvent, state$1) => {
|
1503
|
-
|
1504
|
-
if (response) cacheResponseMetadata(state$1, response);
|
1505
|
-
return ensureMessageStart(state$1, response);
|
1544
|
+
return messageStart(state$1, rawEvent.response);
|
1506
1545
|
};
|
1507
1546
|
const handleOutputItemAdded = (rawEvent, state$1) => {
|
1508
|
-
const
|
1509
|
-
const
|
1510
|
-
const functionCallDetails = extractFunctionCallDetails(rawEvent, state$1);
|
1547
|
+
const events$1 = new Array();
|
1548
|
+
const functionCallDetails = extractFunctionCallDetails(rawEvent);
|
1511
1549
|
if (!functionCallDetails) return events$1;
|
1512
|
-
const { outputIndex, toolCallId, name, initialArguments
|
1513
|
-
if (itemId) state$1.functionCallOutputIndexByItemId.set(itemId, outputIndex);
|
1550
|
+
const { outputIndex, toolCallId, name, initialArguments } = functionCallDetails;
|
1514
1551
|
const blockIndex = openFunctionCallBlock(state$1, {
|
1515
1552
|
outputIndex,
|
1516
1553
|
toolCallId,
|
@@ -1531,13 +1568,12 @@ const handleOutputItemAdded = (rawEvent, state$1) => {
|
|
1531
1568
|
return events$1;
|
1532
1569
|
};
|
1533
1570
|
const handleOutputItemDone = (rawEvent, state$1) => {
|
1534
|
-
const events$1 =
|
1535
|
-
const item =
|
1536
|
-
if (
|
1537
|
-
|
1538
|
-
const outputIndex = toNumber(rawEvent.output_index);
|
1571
|
+
const events$1 = new Array();
|
1572
|
+
const item = rawEvent.item;
|
1573
|
+
if (item.type !== "reasoning") return events$1;
|
1574
|
+
const outputIndex = rawEvent.output_index;
|
1539
1575
|
const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
|
1540
|
-
const signature =
|
1576
|
+
const signature = (item.encrypted_content ?? "") + "@" + item.id;
|
1541
1577
|
if (signature) {
|
1542
1578
|
events$1.push({
|
1543
1579
|
type: "content_block_delta",
|
@@ -1553,11 +1589,9 @@ const handleOutputItemDone = (rawEvent, state$1) => {
|
|
1553
1589
|
return events$1;
|
1554
1590
|
};
|
1555
1591
|
const handleFunctionCallArgumentsDelta = (rawEvent, state$1) => {
|
1556
|
-
const events$1 =
|
1557
|
-
const outputIndex =
|
1558
|
-
|
1559
|
-
const deltaText = typeof rawEvent.delta === "string" ? rawEvent.delta : "";
|
1560
|
-
if (!deltaText) return events$1;
|
1592
|
+
const events$1 = new Array();
|
1593
|
+
const outputIndex = rawEvent.output_index;
|
1594
|
+
const deltaText = rawEvent.delta;
|
1561
1595
|
const blockIndex = openFunctionCallBlock(state$1, {
|
1562
1596
|
outputIndex,
|
1563
1597
|
events: events$1
|
@@ -1574,9 +1608,8 @@ const handleFunctionCallArgumentsDelta = (rawEvent, state$1) => {
|
|
1574
1608
|
return events$1;
|
1575
1609
|
};
|
1576
1610
|
const handleFunctionCallArgumentsDone = (rawEvent, state$1) => {
|
1577
|
-
const events$1 =
|
1578
|
-
const outputIndex =
|
1579
|
-
if (outputIndex === void 0) return events$1;
|
1611
|
+
const events$1 = new Array();
|
1612
|
+
const outputIndex = rawEvent.output_index;
|
1580
1613
|
const blockIndex = openFunctionCallBlock(state$1, {
|
1581
1614
|
outputIndex,
|
1582
1615
|
events: events$1
|
@@ -1594,18 +1627,14 @@ const handleFunctionCallArgumentsDone = (rawEvent, state$1) => {
|
|
1594
1627
|
state$1.blockHasDelta.add(blockIndex);
|
1595
1628
|
}
|
1596
1629
|
closeBlockIfOpen(state$1, blockIndex, events$1);
|
1597
|
-
const existingState = state$1.functionCallStateByOutputIndex.get(outputIndex);
|
1598
|
-
if (existingState) state$1.functionCallOutputIndexByItemId.delete(existingState.toolCallId);
|
1599
1630
|
state$1.functionCallStateByOutputIndex.delete(outputIndex);
|
1600
|
-
const itemId = toNonEmptyString(rawEvent.item_id);
|
1601
|
-
if (itemId) state$1.functionCallOutputIndexByItemId.delete(itemId);
|
1602
1631
|
return events$1;
|
1603
1632
|
};
|
1604
1633
|
const handleOutputTextDelta = (rawEvent, state$1) => {
|
1605
|
-
const events$1 =
|
1606
|
-
const outputIndex =
|
1607
|
-
const contentIndex =
|
1608
|
-
const deltaText =
|
1634
|
+
const events$1 = new Array();
|
1635
|
+
const outputIndex = rawEvent.output_index;
|
1636
|
+
const contentIndex = rawEvent.content_index;
|
1637
|
+
const deltaText = rawEvent.delta;
|
1609
1638
|
if (!deltaText) return events$1;
|
1610
1639
|
const blockIndex = openTextBlockIfNeeded(state$1, {
|
1611
1640
|
outputIndex,
|
@@ -1624,10 +1653,9 @@ const handleOutputTextDelta = (rawEvent, state$1) => {
|
|
1624
1653
|
return events$1;
|
1625
1654
|
};
|
1626
1655
|
const handleReasoningSummaryTextDelta = (rawEvent, state$1) => {
|
1627
|
-
const
|
1628
|
-
const
|
1629
|
-
const
|
1630
|
-
if (!deltaText) return events$1;
|
1656
|
+
const outputIndex = rawEvent.output_index;
|
1657
|
+
const deltaText = rawEvent.delta;
|
1658
|
+
const events$1 = new Array();
|
1631
1659
|
const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
|
1632
1660
|
events$1.push({
|
1633
1661
|
type: "content_block_delta",
|
@@ -1640,11 +1668,10 @@ const handleReasoningSummaryTextDelta = (rawEvent, state$1) => {
|
|
1640
1668
|
state$1.blockHasDelta.add(blockIndex);
|
1641
1669
|
return events$1;
|
1642
1670
|
};
|
1643
|
-
const
|
1644
|
-
const
|
1645
|
-
const
|
1646
|
-
const
|
1647
|
-
const text = part && typeof part.text === "string" ? part.text : "";
|
1671
|
+
const handleReasoningSummaryTextDone = (rawEvent, state$1) => {
|
1672
|
+
const outputIndex = rawEvent.output_index;
|
1673
|
+
const text = rawEvent.text;
|
1674
|
+
const events$1 = new Array();
|
1648
1675
|
const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
|
1649
1676
|
if (text && !state$1.blockHasDelta.has(blockIndex)) events$1.push({
|
1650
1677
|
type: "content_block_delta",
|
@@ -1657,10 +1684,10 @@ const handleReasoningSummaryPartDone = (rawEvent, state$1) => {
|
|
1657
1684
|
return events$1;
|
1658
1685
|
};
|
1659
1686
|
const handleOutputTextDone = (rawEvent, state$1) => {
|
1660
|
-
const events$1 =
|
1661
|
-
const outputIndex =
|
1662
|
-
const contentIndex =
|
1663
|
-
const text =
|
1687
|
+
const events$1 = new Array();
|
1688
|
+
const outputIndex = rawEvent.output_index;
|
1689
|
+
const contentIndex = rawEvent.content_index;
|
1690
|
+
const text = rawEvent.text;
|
1664
1691
|
const blockIndex = openTextBlockIfNeeded(state$1, {
|
1665
1692
|
outputIndex,
|
1666
1693
|
contentIndex,
|
@@ -1678,35 +1705,26 @@ const handleOutputTextDone = (rawEvent, state$1) => {
|
|
1678
1705
|
return events$1;
|
1679
1706
|
};
|
1680
1707
|
const handleResponseCompleted = (rawEvent, state$1) => {
|
1681
|
-
const response =
|
1682
|
-
const events$1 =
|
1708
|
+
const response = rawEvent.response;
|
1709
|
+
const events$1 = new Array();
|
1683
1710
|
closeAllOpenBlocks(state$1, events$1);
|
1684
|
-
|
1685
|
-
|
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({
|
1711
|
+
const anthropic = translateResponsesResultToAnthropic(response);
|
1712
|
+
events$1.push({
|
1695
1713
|
type: "message_delta",
|
1696
1714
|
delta: {
|
1697
|
-
stop_reason:
|
1698
|
-
stop_sequence:
|
1699
|
-
}
|
1700
|
-
|
1701
|
-
|
1715
|
+
stop_reason: anthropic.stop_reason,
|
1716
|
+
stop_sequence: anthropic.stop_sequence
|
1717
|
+
},
|
1718
|
+
usage: anthropic.usage
|
1719
|
+
}, { type: "message_stop" });
|
1702
1720
|
state$1.messageCompleted = true;
|
1703
1721
|
return events$1;
|
1704
1722
|
};
|
1705
1723
|
const handleResponseFailed = (rawEvent, state$1) => {
|
1706
|
-
const response =
|
1707
|
-
const events$1 =
|
1724
|
+
const response = rawEvent.response;
|
1725
|
+
const events$1 = new Array();
|
1708
1726
|
closeAllOpenBlocks(state$1, events$1);
|
1709
|
-
const message =
|
1727
|
+
const message = response.error?.message ?? "The response failed due to an unknown error.";
|
1710
1728
|
events$1.push(buildErrorEvent(message));
|
1711
1729
|
state$1.messageCompleted = true;
|
1712
1730
|
return events$1;
|
@@ -1716,27 +1734,24 @@ const handleErrorEvent = (rawEvent, state$1) => {
|
|
1716
1734
|
state$1.messageCompleted = true;
|
1717
1735
|
return [buildErrorEvent(message)];
|
1718
1736
|
};
|
1719
|
-
const
|
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 ?? "";
|
1737
|
+
const messageStart = (state$1, response) => {
|
1724
1738
|
state$1.messageStartSent = true;
|
1725
|
-
const
|
1739
|
+
const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
|
1740
|
+
const inputTokens = (response.usage?.input_tokens ?? 0) - (inputCachedTokens ?? 0);
|
1726
1741
|
return [{
|
1727
1742
|
type: "message_start",
|
1728
1743
|
message: {
|
1729
|
-
id,
|
1744
|
+
id: response.id,
|
1730
1745
|
type: "message",
|
1731
1746
|
role: "assistant",
|
1732
1747
|
content: [],
|
1733
|
-
model,
|
1748
|
+
model: response.model,
|
1734
1749
|
stop_reason: null,
|
1735
1750
|
stop_sequence: null,
|
1736
1751
|
usage: {
|
1737
1752
|
input_tokens: inputTokens,
|
1738
1753
|
output_tokens: 0,
|
1739
|
-
...
|
1754
|
+
...inputCachedTokens !== void 0 && { cache_creation_input_tokens: inputCachedTokens }
|
1740
1755
|
}
|
1741
1756
|
}
|
1742
1757
|
}];
|
@@ -1796,13 +1811,6 @@ const closeBlockIfOpen = (state$1, blockIndex, events$1) => {
|
|
1796
1811
|
const closeAllOpenBlocks = (state$1, events$1) => {
|
1797
1812
|
for (const blockIndex of state$1.openBlocks) closeBlockIfOpen(state$1, blockIndex, events$1);
|
1798
1813
|
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
1814
|
};
|
1807
1815
|
const buildErrorEvent = (message) => ({
|
1808
1816
|
type: "error",
|
@@ -1812,31 +1820,18 @@ const buildErrorEvent = (message) => ({
|
|
1812
1820
|
}
|
1813
1821
|
});
|
1814
1822
|
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
1823
|
const openFunctionCallBlock = (state$1, params) => {
|
1827
1824
|
const { outputIndex, toolCallId, name, events: events$1 } = params;
|
1828
1825
|
let functionCallState = state$1.functionCallStateByOutputIndex.get(outputIndex);
|
1829
1826
|
if (!functionCallState) {
|
1830
1827
|
const blockIndex$1 = state$1.nextContentBlockIndex;
|
1831
1828
|
state$1.nextContentBlockIndex += 1;
|
1832
|
-
const resolvedToolCallId = toolCallId ?? `tool_call_${blockIndex$1}`;
|
1833
1829
|
functionCallState = {
|
1834
1830
|
blockIndex: blockIndex$1,
|
1835
|
-
toolCallId:
|
1831
|
+
toolCallId: toolCallId ?? `tool_call_${blockIndex$1}`,
|
1836
1832
|
name: name ?? "function"
|
1837
1833
|
};
|
1838
1834
|
state$1.functionCallStateByOutputIndex.set(outputIndex, functionCallState);
|
1839
|
-
state$1.functionCallOutputIndexByItemId.set(resolvedToolCallId, outputIndex);
|
1840
1835
|
}
|
1841
1836
|
const { blockIndex } = functionCallState;
|
1842
1837
|
if (!state$1.openBlocks.has(blockIndex)) {
|
@@ -1854,62 +1849,23 @@ const openFunctionCallBlock = (state$1, params) => {
|
|
1854
1849
|
}
|
1855
1850
|
return blockIndex;
|
1856
1851
|
};
|
1857
|
-
const extractFunctionCallDetails = (rawEvent
|
1858
|
-
const item =
|
1859
|
-
if (
|
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;
|
1852
|
+
const extractFunctionCallDetails = (rawEvent) => {
|
1853
|
+
const item = rawEvent.item;
|
1854
|
+
if (item.type !== "function_call") return;
|
1868
1855
|
return {
|
1869
|
-
outputIndex,
|
1870
|
-
toolCallId,
|
1871
|
-
name,
|
1872
|
-
initialArguments
|
1873
|
-
itemId
|
1856
|
+
outputIndex: rawEvent.output_index,
|
1857
|
+
toolCallId: item.call_id,
|
1858
|
+
name: item.name,
|
1859
|
+
initialArguments: item.arguments
|
1874
1860
|
};
|
1875
1861
|
};
|
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
1862
|
|
1905
1863
|
//#endregion
|
1906
1864
|
//#region src/routes/responses/utils.ts
|
1907
1865
|
const getResponsesRequestOptions = (payload) => {
|
1908
|
-
const vision = hasVisionInput(payload);
|
1909
|
-
const initiator = hasAgentInitiator(payload) ? "agent" : "user";
|
1910
1866
|
return {
|
1911
|
-
vision,
|
1912
|
-
initiator
|
1867
|
+
vision: hasVisionInput(payload),
|
1868
|
+
initiator: hasAgentInitiator(payload) ? "agent" : "user"
|
1913
1869
|
};
|
1914
1870
|
};
|
1915
1871
|
const hasAgentInitiator = (payload) => getPayloadItems(payload).some((item) => {
|
@@ -2093,8 +2049,7 @@ const handleWithChatCompletions = async (c, anthropicPayload) => {
|
|
2093
2049
|
consola.debug("Copilot raw stream event:", JSON.stringify(rawEvent));
|
2094
2050
|
if (rawEvent.data === "[DONE]") break;
|
2095
2051
|
if (!rawEvent.data) continue;
|
2096
|
-
const
|
2097
|
-
const events$1 = translateChunkToAnthropicEvents(chunk, streamState);
|
2052
|
+
const events$1 = translateChunkToAnthropicEvents(JSON.parse(rawEvent.data), streamState);
|
2098
2053
|
for (const event of events$1) {
|
2099
2054
|
consola.debug("Translated Anthropic event:", JSON.stringify(event));
|
2100
2055
|
await stream.writeSSE({
|
@@ -2118,7 +2073,6 @@ const handleWithResponsesApi = async (c, anthropicPayload) => {
|
|
2118
2073
|
return streamSSE(c, async (stream) => {
|
2119
2074
|
const streamState = createResponsesStreamState();
|
2120
2075
|
for await (const chunk of response) {
|
2121
|
-
consola.debug("Responses raw stream event:", JSON.stringify(chunk));
|
2122
2076
|
if (chunk.event === "ping") {
|
2123
2077
|
await stream.writeSSE({
|
2124
2078
|
event: "ping",
|
@@ -2128,15 +2082,14 @@ const handleWithResponsesApi = async (c, anthropicPayload) => {
|
|
2128
2082
|
}
|
2129
2083
|
const data = chunk.data;
|
2130
2084
|
if (!data) continue;
|
2131
|
-
|
2132
|
-
const
|
2133
|
-
if (!parsed) continue;
|
2134
|
-
const events$1 = translateResponsesStreamEvent(parsed, streamState);
|
2085
|
+
consola.debug("Responses raw stream event:", data);
|
2086
|
+
const events$1 = translateResponsesStreamEvent(JSON.parse(data), streamState);
|
2135
2087
|
for (const event of events$1) {
|
2136
|
-
|
2088
|
+
const eventData = JSON.stringify(event);
|
2089
|
+
consola.debug("Translated Anthropic event:", eventData);
|
2137
2090
|
await stream.writeSSE({
|
2138
2091
|
event: event.type,
|
2139
|
-
data:
|
2092
|
+
data: eventData
|
2140
2093
|
});
|
2141
2094
|
}
|
2142
2095
|
}
|
@@ -2160,14 +2113,6 @@ const shouldUseResponsesApi = (modelId) => {
|
|
2160
2113
|
};
|
2161
2114
|
const isNonStreaming = (response) => Object.hasOwn(response, "choices");
|
2162
2115
|
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
2116
|
|
2172
2117
|
//#endregion
|
2173
2118
|
//#region src/routes/messages/route.ts
|
@@ -2455,7 +2400,7 @@ const start = defineCommand({
|
|
2455
2400
|
//#region src/main.ts
|
2456
2401
|
const main = defineCommand({
|
2457
2402
|
meta: {
|
2458
|
-
name: "
|
2403
|
+
name: "copilot-api",
|
2459
2404
|
description: "A wrapper around GitHub Copilot API to make it OpenAI compatible, making it usable for other tools."
|
2460
2405
|
},
|
2461
2406
|
subCommands: {
|