github-router 0.3.6 → 0.3.7

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 CHANGED
@@ -4,7 +4,7 @@ import consola from "consola";
4
4
  import fs from "node:fs/promises";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
- import { randomUUID } from "node:crypto";
7
+ import { randomBytes, randomUUID } from "node:crypto";
8
8
  import clipboard from "clipboardy";
9
9
  import { serve } from "srvx";
10
10
  import invariant from "tiny-invariant";
@@ -13,7 +13,6 @@ import { Agent, ProxyAgent, setGlobalDispatcher } from "undici";
13
13
  import process$1 from "node:process";
14
14
  import { Hono } from "hono";
15
15
  import { cors } from "hono/cors";
16
- import { logger } from "hono/logger";
17
16
  import { streamSSE } from "hono/streaming";
18
17
  import { events } from "fetch-event-stream";
19
18
 
@@ -40,12 +39,12 @@ async function ensureFile(filePath) {
40
39
  //#endregion
41
40
  //#region src/lib/state.ts
42
41
  const state = {
43
- accountType: "individual",
42
+ accountType: "enterprise",
44
43
  manualApprove: false,
45
44
  rateLimitWait: false,
46
45
  showToken: false,
47
46
  sessionId: randomUUID(),
48
- machineId: randomUUID()
47
+ machineId: randomBytes(32).toString("hex")
49
48
  };
50
49
 
51
50
  //#endregion
@@ -57,8 +56,8 @@ const standardHeaders = () => ({
57
56
  const COPILOT_VERSION = "0.38.2026021302";
58
57
  const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
59
58
  const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
60
- const API_VERSION = "2025-05-01";
61
- const copilotBaseUrl = (state$1) => state$1.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${state$1.accountType}.githubcopilot.com`;
59
+ const API_VERSION = "2025-10-01";
60
+ const copilotBaseUrl = (state$1) => state$1.copilotApiUrl ?? "https://api.githubcopilot.com";
62
61
  const copilotHeaders = (state$1, vision = false, integrationId = "vscode-chat") => {
63
62
  const headers = {
64
63
  Authorization: `Bearer ${state$1.copilotToken}`,
@@ -139,7 +138,9 @@ function resolveErrorMessage(errorJson, fallback) {
139
138
  const getCopilotToken = async () => {
140
139
  const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/v2/token`, { headers: githubHeaders(state) });
141
140
  if (!response.ok) throw new HTTPError("Failed to get Copilot token", response);
142
- return await response.json();
141
+ const data = await response.json();
142
+ if (data.endpoints?.api) state.copilotApiUrl = data.endpoints.api;
143
+ return data;
143
144
  };
144
145
 
145
146
  //#endregion
@@ -221,6 +222,20 @@ const ALLOWED_BETA_PREFIXES = [
221
222
  function filterBetaHeader(value) {
222
223
  return value.split(",").map((v) => v.trim()).filter((v) => v && ALLOWED_BETA_PREFIXES.some((prefix) => v.startsWith(prefix))).join(",") || void 0;
223
224
  }
225
+ /**
226
+ * Resolve a model name to the best available variant in the Copilot model list.
227
+ * Prefers the 1M context variant for opus models.
228
+ */
229
+ function resolveModel(modelId) {
230
+ const models = state.models?.data;
231
+ if (!models) return modelId;
232
+ if (models.some((m) => m.id === modelId)) return modelId;
233
+ if (modelId.toLowerCase().includes("opus")) {
234
+ const oneM = models.find((m) => m.id.includes("opus") && m.id.endsWith("-1m"));
235
+ if (oneM) return oneM.id;
236
+ }
237
+ return modelId;
238
+ }
224
239
  async function cacheModels() {
225
240
  state.models = await getModels();
226
241
  }
@@ -613,6 +628,52 @@ async function checkRateLimit(state$1) {
613
628
  consola.info("Rate limit wait completed, proceeding with request");
614
629
  }
615
630
 
631
+ //#endregion
632
+ //#region src/lib/request-log.ts
633
+ /**
634
+ * Format a number with K/M suffix for compact display.
635
+ */
636
+ function formatTokens(n) {
637
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
638
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
639
+ return String(n);
640
+ }
641
+ /**
642
+ * Build a context window summary: "in:1.2K out:50 ctx:1.2K/1M (0.1%)"
643
+ */
644
+ function formatTokenInfo(inputTokens, outputTokens, model) {
645
+ if (inputTokens === void 0) return void 0;
646
+ const parts = [];
647
+ const maxPrompt = model?.capabilities.limits.max_prompt_tokens;
648
+ if (maxPrompt) {
649
+ const pct = (inputTokens / maxPrompt * 100).toFixed(1);
650
+ parts.push(`in:${formatTokens(inputTokens)}/${formatTokens(maxPrompt)} (${pct}%)`);
651
+ } else parts.push(`in:${formatTokens(inputTokens)}`);
652
+ if (outputTokens !== void 0) parts.push(`out:${formatTokens(outputTokens)}`);
653
+ return parts.join(" ");
654
+ }
655
+ /**
656
+ * Print a single summary line for a completed request.
657
+ *
658
+ * Examples:
659
+ * POST /v1/messages claude-opus-4.6-1m in:1.2K/1M (0.1%) out:50 200 2.3s
660
+ * POST /v1/messages claude-opus-4-6→claude-opus-4.6-1m in:743/1M (0.1%) 200 198ms
661
+ * POST /v1/chat/completions claude-sonnet-4 in:15 out:16 200 2.1s stream
662
+ */
663
+ function logRequest(info, model, startTime) {
664
+ const parts = [];
665
+ parts.push(`${info.method} ${info.path}`);
666
+ if (info.resolvedModel && info.resolvedModel !== info.model) parts.push(`${info.model}→${info.resolvedModel}`);
667
+ else if (info.resolvedModel ?? info.model) parts.push(info.resolvedModel ?? info.model);
668
+ const tokenInfo = formatTokenInfo(info.inputTokens, info.outputTokens, model);
669
+ if (tokenInfo) parts.push(tokenInfo);
670
+ if (info.status !== void 0) parts.push(String(info.status));
671
+ const elapsed = Date.now() - startTime;
672
+ const duration = elapsed >= 1e3 ? `${(elapsed / 1e3).toFixed(1)}s` : `${elapsed}ms`;
673
+ parts.push(info.streaming ? `${duration} stream` : duration);
674
+ consola.info(parts.join(" "));
675
+ }
676
+
616
677
  //#endregion
617
678
  //#region src/lib/tokenizer.ts
618
679
  const ENCODING_MAP = {
@@ -914,21 +975,21 @@ async function searchWeb(query) {
914
975
  //#endregion
915
976
  //#region src/routes/chat-completions/handler.ts
916
977
  async function handleCompletion$1(c) {
978
+ const startTime = Date.now();
917
979
  await checkRateLimit(state);
918
980
  let payload = await c.req.json();
919
981
  const debugEnabled = consola.level >= 4;
920
982
  if (debugEnabled) consola.debug("Request payload:", JSON.stringify(payload).slice(-400));
921
983
  if (state.manualApprove) await awaitApproval();
922
984
  await injectWebSearchIfNeeded$1(payload);
985
+ const originalModel = payload.model;
986
+ const resolvedModel = resolveModel(payload.model);
987
+ if (resolvedModel !== payload.model) payload.model = resolvedModel;
923
988
  const selectedModel = state.models?.data.find((model) => model.id === payload.model);
989
+ let inputTokens;
924
990
  try {
925
- if (selectedModel) {
926
- const tokenCount = await getTokenCount(payload, selectedModel);
927
- consola.info("Current token count:", tokenCount);
928
- } else consola.warn("No model selected, skipping token count calculation");
929
- } catch (error) {
930
- consola.warn("Failed to calculate token count:", error);
931
- }
991
+ if (selectedModel) inputTokens = (await getTokenCount(payload, selectedModel)).input;
992
+ } catch {}
932
993
  if (isNullish(payload.max_tokens)) {
933
994
  payload = {
934
995
  ...payload,
@@ -937,11 +998,22 @@ async function handleCompletion$1(c) {
937
998
  if (debugEnabled) consola.debug("Set max_tokens to:", JSON.stringify(payload.max_tokens));
938
999
  }
939
1000
  const response = await createChatCompletions(payload);
940
- if (isNonStreaming$1(response)) {
1001
+ const isStreaming = !isNonStreaming$1(response);
1002
+ const outputTokens = !isStreaming ? response.usage?.completion_tokens : void 0;
1003
+ logRequest({
1004
+ method: "POST",
1005
+ path: c.req.path,
1006
+ model: originalModel,
1007
+ resolvedModel,
1008
+ inputTokens,
1009
+ outputTokens,
1010
+ status: 200,
1011
+ streaming: isStreaming
1012
+ }, selectedModel, startTime);
1013
+ if (!isStreaming) {
941
1014
  if (debugEnabled) consola.debug("Non-streaming response:", JSON.stringify(response));
942
1015
  return c.json(response);
943
1016
  }
944
- consola.debug("Streaming response");
945
1017
  return streamSSE(c, async (stream) => {
946
1018
  for await (const chunk of response) {
947
1019
  if (debugEnabled) consola.debug("Streaming chunk:", JSON.stringify(chunk));
@@ -1052,6 +1124,7 @@ embeddingRoutes.post("/", async (c) => {
1052
1124
  function buildHeaders(extraHeaders) {
1053
1125
  return {
1054
1126
  ...copilotHeaders(state),
1127
+ accept: "application/json",
1055
1128
  "X-Initiator": "agent",
1056
1129
  "anthropic-version": "2023-06-01",
1057
1130
  "X-Interaction-Id": randomUUID(),
@@ -1152,16 +1225,55 @@ function stripWebSearchFromBody(rawBody) {
1152
1225
  * native /v1/messages/count_tokens endpoint.
1153
1226
  */
1154
1227
  async function handleCountTokens(c) {
1155
- const finalBody = stripWebSearchFromBody(await c.req.text());
1228
+ const startTime = Date.now();
1229
+ const { body: finalBody, originalModel, resolvedModel } = resolveModelInBody$1(stripWebSearchFromBody(await c.req.text()));
1156
1230
  const extraHeaders = {};
1157
1231
  const anthropicBeta = c.req.header("anthropic-beta");
1158
1232
  if (anthropicBeta) {
1159
1233
  const filtered = filterBetaHeader(anthropicBeta);
1160
1234
  if (filtered) extraHeaders["anthropic-beta"] = filtered;
1161
1235
  }
1162
- const body = await (await countTokens(finalBody, extraHeaders)).json();
1163
- consola.info("Token count:", JSON.stringify(body));
1164
- return c.json(body);
1236
+ const response = await countTokens(finalBody, extraHeaders);
1237
+ const responseBody = await response.json();
1238
+ const modelId = resolvedModel ?? originalModel;
1239
+ const selectedModel = state.models?.data.find((m) => m.id === modelId);
1240
+ logRequest({
1241
+ method: "POST",
1242
+ path: c.req.path,
1243
+ model: originalModel,
1244
+ resolvedModel,
1245
+ inputTokens: responseBody.input_tokens,
1246
+ status: response.status
1247
+ }, selectedModel, startTime);
1248
+ return c.json(responseBody);
1249
+ }
1250
+ /**
1251
+ * Parse the JSON body, resolve the model name, and re-serialize.
1252
+ */
1253
+ function resolveModelInBody$1(rawBody) {
1254
+ let parsed;
1255
+ try {
1256
+ parsed = JSON.parse(rawBody);
1257
+ } catch {
1258
+ return { body: rawBody };
1259
+ }
1260
+ const originalModel = typeof parsed.model === "string" ? parsed.model : void 0;
1261
+ if (!originalModel) return {
1262
+ body: rawBody,
1263
+ originalModel
1264
+ };
1265
+ const resolved = resolveModel(originalModel);
1266
+ if (resolved === originalModel) return {
1267
+ body: rawBody,
1268
+ originalModel,
1269
+ resolvedModel: originalModel
1270
+ };
1271
+ parsed.model = resolved;
1272
+ return {
1273
+ body: JSON.stringify(parsed),
1274
+ originalModel,
1275
+ resolvedModel: resolved
1276
+ };
1165
1277
  }
1166
1278
 
1167
1279
  //#endregion
@@ -1266,14 +1378,25 @@ async function processWebSearch(rawBody) {
1266
1378
  return JSON.stringify(body);
1267
1379
  }
1268
1380
  async function handleCompletion(c) {
1381
+ const startTime = Date.now();
1269
1382
  await checkRateLimit(state);
1270
1383
  const rawBody = await c.req.text();
1271
1384
  const debugEnabled = consola.level >= 4;
1272
1385
  if (debugEnabled) consola.debug("Anthropic request body:", rawBody.slice(0, 2e3));
1273
1386
  if (state.manualApprove) await awaitApproval();
1274
1387
  const betaHeaders = extractBetaHeaders(c);
1275
- const response = await createMessages(await processWebSearch(rawBody), betaHeaders);
1388
+ const { body: resolvedBody, originalModel, resolvedModel } = resolveModelInBody(await processWebSearch(rawBody));
1389
+ const selectedModel = state.models?.data.find((m) => m.id === (resolvedModel ?? originalModel));
1390
+ const response = await createMessages(resolvedBody, betaHeaders);
1276
1391
  if ((response.headers.get("content-type") ?? "").includes("text/event-stream")) {
1392
+ logRequest({
1393
+ method: "POST",
1394
+ path: c.req.path,
1395
+ model: originalModel,
1396
+ resolvedModel,
1397
+ status: response.status,
1398
+ streaming: true
1399
+ }, selectedModel, startTime);
1277
1400
  if (debugEnabled) consola.debug("Streaming response from Copilot /v1/messages");
1278
1401
  return new Response(response.body, {
1279
1402
  status: response.status,
@@ -1285,9 +1408,47 @@ async function handleCompletion(c) {
1285
1408
  });
1286
1409
  }
1287
1410
  const responseBody = await response.json();
1411
+ logRequest({
1412
+ method: "POST",
1413
+ path: c.req.path,
1414
+ model: originalModel,
1415
+ resolvedModel,
1416
+ inputTokens: responseBody.usage?.input_tokens,
1417
+ outputTokens: responseBody.usage?.output_tokens,
1418
+ status: response.status
1419
+ }, selectedModel, startTime);
1288
1420
  if (debugEnabled) consola.debug("Non-streaming response from Copilot /v1/messages:", JSON.stringify(responseBody).slice(0, 2e3));
1289
1421
  return c.json(responseBody, response.status);
1290
1422
  }
1423
+ /**
1424
+ * Parse the JSON body, resolve the model name, and re-serialize.
1425
+ * Returns the body string plus the original and resolved model names.
1426
+ */
1427
+ function resolveModelInBody(rawBody) {
1428
+ let parsed;
1429
+ try {
1430
+ parsed = JSON.parse(rawBody);
1431
+ } catch {
1432
+ return { body: rawBody };
1433
+ }
1434
+ const originalModel = typeof parsed.model === "string" ? parsed.model : void 0;
1435
+ if (!originalModel) return {
1436
+ body: rawBody,
1437
+ originalModel
1438
+ };
1439
+ const resolved = resolveModel(originalModel);
1440
+ if (resolved === originalModel) return {
1441
+ body: rawBody,
1442
+ originalModel,
1443
+ resolvedModel: originalModel
1444
+ };
1445
+ parsed.model = resolved;
1446
+ return {
1447
+ body: JSON.stringify(parsed),
1448
+ originalModel,
1449
+ resolvedModel: resolved
1450
+ };
1451
+ }
1291
1452
 
1292
1453
  //#endregion
1293
1454
  //#region src/routes/messages/route.ts
@@ -1401,12 +1562,15 @@ function getToolChoiceName(toolChoice) {
1401
1562
  //#endregion
1402
1563
  //#region src/routes/responses/handler.ts
1403
1564
  async function handleResponses(c) {
1565
+ const startTime = Date.now();
1404
1566
  await checkRateLimit(state);
1405
1567
  const payload = await c.req.json();
1406
1568
  const debugEnabled = consola.level >= 4;
1407
1569
  if (debugEnabled) consola.debug("Responses request payload:", JSON.stringify(payload).slice(-400));
1570
+ const originalModel = payload.model;
1571
+ const resolvedModel = resolveModel(payload.model);
1572
+ if (resolvedModel !== payload.model) payload.model = resolvedModel;
1408
1573
  const selectedModel = state.models?.data.find((model) => model.id === payload.model);
1409
- consola.info("Token counting not yet supported for /responses endpoint");
1410
1574
  if (state.manualApprove) await awaitApproval();
1411
1575
  await injectWebSearchIfNeeded(payload);
1412
1576
  if (isNullish(payload.max_output_tokens)) {
@@ -1414,11 +1578,19 @@ async function handleResponses(c) {
1414
1578
  if (debugEnabled) consola.debug("Set max_output_tokens to:", JSON.stringify(payload.max_output_tokens));
1415
1579
  }
1416
1580
  const response = await createResponses(payload);
1417
- if (isNonStreaming(response)) {
1581
+ const isStreaming = !isNonStreaming(response);
1582
+ logRequest({
1583
+ method: "POST",
1584
+ path: c.req.path,
1585
+ model: originalModel,
1586
+ resolvedModel,
1587
+ status: 200,
1588
+ streaming: isStreaming
1589
+ }, selectedModel, startTime);
1590
+ if (!isStreaming) {
1418
1591
  if (debugEnabled) consola.debug("Non-streaming response:", JSON.stringify(response));
1419
1592
  return c.json(response);
1420
1593
  }
1421
- consola.debug("Streaming response");
1422
1594
  return streamSSE(c, async (stream) => {
1423
1595
  for await (const chunk of response) {
1424
1596
  if (debugEnabled) consola.debug("Streaming chunk:", JSON.stringify(chunk));
@@ -1521,7 +1693,6 @@ usageRoute.get("/", async (c) => {
1521
1693
  //#endregion
1522
1694
  //#region src/server.ts
1523
1695
  const server = new Hono();
1524
- server.use(logger());
1525
1696
  server.use(cors());
1526
1697
  server.get("/", (c) => c.text("Server running"));
1527
1698
  server.route("/chat/completions", completionRoutes);
@@ -1668,7 +1839,7 @@ const start = defineCommand({
1668
1839
  "account-type": {
1669
1840
  alias: "a",
1670
1841
  type: "string",
1671
- default: "individual",
1842
+ default: "enterprise",
1672
1843
  description: "Account type to use (individual, business, enterprise)"
1673
1844
  },
1674
1845
  manual: {
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":["state: State","state","headers: Record<string, string>","errorJson: unknown","token","process","commandBlock: string","state","x","headers: Record<string, string>","searchTimestamps: Array<number>","references: Array<{ title: string; url: string }>","handleCompletion","injectWebSearchIfNeeded","isNonStreaming","extractUserQuery","handleCompletion","isWebSearchTool","body: AnyRecord","extraHeaders: Record<string, string>","headers: Record<string, string>","extractUserQuery","body: AnyRecord","headers: Record<string, string>","rateLimit: number | undefined"],"sources":["../src/lib/paths.ts","../src/lib/state.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/copilot/get-models.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts","../src/services/github/poll-access-token.ts","../src/lib/token.ts","../src/auth.ts","../src/services/github/get-copilot-usage.ts","../src/check-usage.ts","../src/debug.ts","../src/lib/proxy.ts","../src/lib/shell.ts","../src/lib/approval.ts","../src/lib/rate-limit.ts","../src/lib/tokenizer.ts","../src/services/copilot/create-chat-completions.ts","../src/services/copilot/web-search.ts","../src/routes/chat-completions/handler.ts","../src/routes/chat-completions/route.ts","../src/services/copilot/create-embeddings.ts","../src/routes/embeddings/route.ts","../src/services/copilot/create-messages.ts","../src/routes/messages/count-tokens-handler.ts","../src/routes/messages/handler.ts","../src/routes/messages/route.ts","../src/routes/models/route.ts","../src/services/copilot/create-responses.ts","../src/routes/responses/handler.ts","../src/routes/responses/route.ts","../src/routes/search/route.ts","../src/routes/token/route.ts","../src/routes/usage/route.ts","../src/server.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nconst APP_DIR = path.join(os.homedir(), \".local\", \"share\", \"github-router\")\n\nconst GITHUB_TOKEN_PATH = path.join(APP_DIR, \"github_token\")\n\nexport const PATHS = {\n APP_DIR,\n GITHUB_TOKEN_PATH,\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n}\n\nasync function ensureFile(filePath: string): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n accountType: string\n models?: ModelsResponse\n vsCodeVersion?: string\n\n manualApprove: boolean\n rateLimitWait: boolean\n showToken: boolean\n\n // Rate limiting configuration\n rateLimitSeconds?: number\n lastRequestTimestamp?: number\n\n // Persistent session identifiers to match VS Code fingerprint\n sessionId: string\n machineId: string\n}\n\nexport const state: State = {\n accountType: \"individual\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n sessionId: randomUUID(),\n machineId: randomUUID(),\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { State } from \"./state\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst COPILOT_VERSION = \"0.38.2026021302\"\nconst EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`\nconst USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`\n\nconst API_VERSION = \"2025-05-01\"\n\nexport const copilotBaseUrl = (state: State) =>\n state.accountType === \"individual\" ?\n \"https://api.githubcopilot.com\"\n : `https://api.${state.accountType}.githubcopilot.com`\nexport const copilotHeaders = (\n state: State,\n vision: boolean = false,\n integrationId: string = \"vscode-chat\",\n) => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${state.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": integrationId,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"conversation-panel\",\n \"x-interaction-type\": \"conversation-panel\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": randomUUID(),\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n \"VScode-SessionId\": state.sessionId,\n \"VScode-MachineId\": state.machineId,\n }\n\n if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n return headers\n}\n\nexport const GITHUB_API_BASE_URL = \"https://api.github.com\"\nexport const githubHeaders = (state: State) => ({\n ...standardHeaders(),\n authorization: `token ${state.githubToken}`,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"x-github-api-version\": API_VERSION,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nexport class HTTPError extends Error {\n response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.response = response\n }\n}\n\nexport async function forwardError(c: Context, error: unknown) {\n consola.error(\"Error occurred:\", error)\n\n if (error instanceof HTTPError) {\n const errorText = await error.response.text()\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = undefined\n }\n const message = resolveErrorMessage(errorJson, errorText)\n consola.error(\"HTTP error:\", errorJson ?? errorText)\n return c.json(\n {\n error: {\n message,\n type: \"error\",\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n error: {\n message: error instanceof Error ? error.message : String(error),\n type: \"error\",\n },\n },\n 500,\n )\n}\n\n// Extracts error message from { message } or { error: { message } } payloads.\nfunction resolveErrorMessage(errorJson: unknown, fallback: string): string {\n if (typeof errorJson !== \"object\" || errorJson === null) return fallback\n\n const errorRecord = errorJson as Record<string, unknown>\n if (errorRecord.message !== undefined) return String(errorRecord.message)\n\n if (typeof errorRecord.error === \"object\" && errorRecord.error !== null) {\n const nestedRecord = errorRecord.error as Record<string, unknown>\n if (nestedRecord.message !== undefined) return String(nestedRecord.message)\n }\n\n return fallback\n}\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotToken = async () => {\n const response = await fetch(\n `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(state),\n },\n )\n\n if (!response.ok) throw new HTTPError(\"Failed to get Copilot token\", response)\n\n return (await response.json()) as GetCopilotTokenResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n}\n","import {\n GITHUB_APP_SCOPES,\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\n const response = await fetch(`${GITHUB_BASE_URL}/login/device/code`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n scope: GITHUB_APP_SCOPES,\n }),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\n}\n\nexport interface DeviceCodeResponse {\n device_code: string\n user_code: string\n verification_uri: string\n expires_in: number\n interval: number\n}\n","import { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${state.githubToken}`,\n ...standardHeaders(),\n },\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n login: string\n}\n","import { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getModels = async () => {\n const response = await fetch(`${copilotBaseUrl(state)}/models`, {\n headers: copilotHeaders(state),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n return (await response.json()) as ModelsResponse\n}\n\nexport interface ModelsResponse {\n data: Array<Model>\n object: string\n}\n\ninterface ModelLimits {\n max_context_window_tokens?: number\n max_output_tokens?: number\n max_prompt_tokens?: number\n max_inputs?: number\n}\n\ninterface ModelSupports {\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n}\n\ninterface ModelCapabilities {\n family: string\n limits: ModelLimits\n object: string\n supports: ModelSupports\n tokenizer: string\n type: string\n}\n\nexport interface Model {\n capabilities: ModelCapabilities\n id: string\n model_picker_enabled: boolean\n name: string\n object: string\n preview: boolean\n vendor: string\n version: string\n supported_endpoints?: Array<string>\n policy?: {\n state: string\n terms: string\n }\n}\n","const FALLBACK = \"1.104.3\"\n\nexport async function getVSCodeVersion() {\n const controller = new AbortController()\n const timeout = setTimeout(() => {\n controller.abort()\n }, 5000)\n\n try {\n const response = await fetch(\n \"https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin\",\n {\n signal: controller.signal,\n },\n )\n\n const pkgbuild = await response.text()\n const pkgverRegex = /pkgver=([0-9.]+)/\n const match = pkgbuild.match(pkgverRegex)\n\n if (match) {\n return match[1]\n }\n\n return FALLBACK\n } catch {\n return FALLBACK\n } finally {\n clearTimeout(timeout)\n }\n}\n\nawait getVSCodeVersion()\n","import consola from \"consola\"\n\nimport { getModels } from \"~/services/copilot/get-models\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined\n\n/**\n * Beta values that VS Code Copilot Chat actually sends to the Copilot API.\n * Only these are forwarded; everything else (e.g. context-1m-*) is stripped\n * so our requests match what VS Code produces.\n */\nconst ALLOWED_BETA_PREFIXES = [\n \"interleaved-thinking-\",\n \"context-management-\",\n \"advanced-tool-use-\",\n \"token-counting-\",\n]\n\n/**\n * Filter an `anthropic-beta` header value, keeping only beta flags that\n * VS Code Copilot is known to send. Returns the filtered comma-separated\n * string, or undefined if nothing remains.\n */\nexport function filterBetaHeader(value: string): string | undefined {\n const filtered = value\n .split(\",\")\n .map((v) => v.trim())\n .filter(\n (v) =>\n v && ALLOWED_BETA_PREFIXES.some((prefix) => v.startsWith(prefix)),\n )\n .join(\",\")\n return filtered || undefined\n}\n\nexport async function cacheModels(): Promise<void> {\n const models = await getModels()\n state.models = models\n}\n\nexport const cacheVSCodeVersion = async () => {\n const response = await getVSCodeVersion()\n state.vsCodeVersion = response\n\n consola.info(`Using VSCode version: ${response}`)\n}\n","import consola from \"consola\"\n\nimport {\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport async function pollAccessToken(\n deviceCode: DeviceCodeResponse,\n): Promise<string> {\n // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n // I'm also adding another second, just to be safe\n const sleepDuration = (deviceCode.interval + 1) * 1000\n consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n const expiresAt = Date.now() + deviceCode.expires_in * 1000\n\n while (Date.now() < expiresAt) {\n const response = await fetch(\n `${GITHUB_BASE_URL}/login/oauth/access_token`,\n {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to poll access token:\", await response.text())\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n continue\n }\n\n const json = await response.json()\n consola.debug(\"Polling access token response:\", json)\n\n const { access_token } = json as AccessTokenResponse\n\n if (access_token) {\n return access_token\n }\n\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n }\n\n throw new Error(\"Device code expired. Please run auth again.\")\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport { PATHS } from \"~/lib/paths\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getDeviceCode } from \"~/services/github/get-device-code\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\nimport { pollAccessToken } from \"~/services/github/poll-access-token\"\n\nimport { HTTPError } from \"./error\"\nimport { state } from \"./state\"\n\nconst readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n\nconst writeGithubToken = (token: string) =>\n fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token)\n\nexport const setupCopilotToken = async () => {\n const { token, refresh_in } = await getCopilotToken()\n state.copilotToken = token\n\n // Display the Copilot token to the screen\n consola.debug(\"GitHub Copilot Token fetched successfully!\")\n if (state.showToken) {\n consola.info(\"Copilot token:\", token)\n }\n\n const refreshInterval = Math.max((refresh_in - 60) * 1000, 1000)\n setInterval(async () => {\n consola.debug(\"Refreshing Copilot token\")\n try {\n const { token } = await getCopilotToken()\n state.copilotToken = token\n consola.debug(\"Copilot token refreshed\")\n if (state.showToken) {\n consola.info(\"Refreshed Copilot token:\", token)\n }\n } catch (error) {\n consola.error(\"Failed to refresh Copilot token:\", error)\n }\n }, refreshInterval)\n}\n\ninterface SetupGitHubTokenOptions {\n force?: boolean\n}\n\nexport async function setupGitHubToken(\n options?: SetupGitHubTokenOptions,\n): Promise<void> {\n try {\n const githubToken = await readGithubToken()\n\n if (githubToken && !options?.force) {\n state.githubToken = githubToken\n if (state.showToken) {\n consola.info(\"GitHub token:\", githubToken)\n }\n await logUser()\n\n return\n }\n\n consola.info(\"Not logged in, getting new access token\")\n const response = await getDeviceCode()\n consola.debug(\"Device code response:\", response)\n\n consola.info(\n `Please enter the code \"${response.user_code}\" in ${response.verification_uri}`,\n )\n\n const token = await pollAccessToken(response)\n await writeGithubToken(token)\n state.githubToken = token\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n await logUser()\n } catch (error) {\n if (error instanceof HTTPError) {\n consola.error(\"Failed to get GitHub token:\", await error.response.json())\n throw error\n }\n\n consola.error(\"Failed to get GitHub token:\", error)\n throw error\n }\n}\n\nasync function logUser() {\n const user = await getGitHubUser()\n consola.info(`Logged in as ${user.login}`)\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n verbose: boolean\n showToken: boolean\n}\n\nexport async function runAuth(options: RunAuthOptions): Promise<void> {\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n}\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub auth flow without running the server\",\n },\n args: {\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub token on auth\",\n },\n },\n run({ args }) {\n return runAuth({\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (): Promise<CopilotUsageResponse> => {\n const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, {\n headers: githubHeaders(state),\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot usage\", response)\n }\n\n return (await response.json()) as CopilotUsageResponse\n}\n\nexport interface QuotaDetail {\n entitlement: number\n overage_count: number\n overage_permitted: boolean\n percent_remaining: number\n quota_id: string\n quota_remaining: number\n remaining: number\n unlimited: boolean\n}\n\ninterface QuotaSnapshots {\n chat: QuotaDetail\n completions: QuotaDetail\n premium_interactions: QuotaDetail\n}\n\ninterface CopilotUsageResponse {\n access_type_sku: string\n analytics_tracking_id: string\n assigned_date: string\n can_signup_for_limited: boolean\n chat_enabled: boolean\n copilot_plan: string\n organization_login_list: Array<unknown>\n organization_list: Array<unknown>\n quota_reset_date: string\n quota_snapshots: QuotaSnapshots\n}\n","import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupGitHubToken } from \"./lib/token\"\nimport {\n getCopilotUsage,\n type QuotaDetail,\n} from \"./services/github/get-copilot-usage\"\n\nexport const checkUsage = defineCommand({\n meta: {\n name: \"check-usage\",\n description: \"Show current GitHub Copilot usage/quota information\",\n },\n async run() {\n await ensurePaths()\n await setupGitHubToken()\n try {\n const usage = await getCopilotUsage()\n const premium = usage.quota_snapshots.premium_interactions\n const premiumTotal = premium.entitlement\n const premiumUsed = premiumTotal - premium.remaining\n const premiumPercentUsed =\n premiumTotal > 0 ? (premiumUsed / premiumTotal) * 100 : 0\n const premiumPercentRemaining = premium.percent_remaining\n\n // Helper to summarize a quota snapshot\n function summarizeQuota(name: string, snap: QuotaDetail | undefined) {\n if (!snap) return `${name}: N/A`\n const total = snap.entitlement\n const used = total - snap.remaining\n const percentUsed = total > 0 ? (used / total) * 100 : 0\n const percentRemaining = snap.percent_remaining\n return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`\n }\n\n const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`\n const chatLine = summarizeQuota(\"Chat\", usage.quota_snapshots.chat)\n const completionsLine = summarizeQuota(\n \"Completions\",\n usage.quota_snapshots.completions,\n )\n\n consola.box(\n `Copilot Usage (plan: ${usage.copilot_plan})\\n`\n + `Quota resets: ${usage.quota_reset_date}\\n`\n + `\\nQuotas:\\n`\n + ` ${premiumLine}\\n`\n + ` ${chatLine}\\n`\n + ` ${completionsLine}`,\n )\n } catch (err) {\n consola.error(\"Failed to fetch Copilot usage:\", err)\n process.exit(1)\n }\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\n\nimport { PATHS } from \"./lib/paths\"\n\ninterface DebugInfo {\n version: string\n runtime: {\n name: string\n version: string\n platform: string\n arch: string\n }\n paths: {\n APP_DIR: string\n GITHUB_TOKEN_PATH: string\n }\n tokenExists: boolean\n}\n\ninterface RunDebugOptions {\n json: boolean\n}\n\nasync function getPackageVersion(): Promise<string> {\n try {\n const packageJsonPath = new URL(\"../package.json\", import.meta.url).pathname\n // @ts-expect-error https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/rules/prefer-json-parse-buffer.md\n // JSON.parse() can actually parse buffers\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath)) as {\n version: string\n }\n return packageJson.version\n } catch {\n return \"unknown\"\n }\n}\n\nfunction getRuntimeInfo() {\n const isBun = typeof Bun !== \"undefined\"\n\n return {\n name: isBun ? \"bun\" : \"node\",\n version: isBun ? Bun.version : process.version.slice(1),\n platform: os.platform(),\n arch: os.arch(),\n }\n}\n\nasync function checkTokenExists(): Promise<boolean> {\n try {\n const stats = await fs.stat(PATHS.GITHUB_TOKEN_PATH)\n if (!stats.isFile()) return false\n\n const content = await fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n return content.trim().length > 0\n } catch {\n return false\n }\n}\n\nasync function getDebugInfo(): Promise<DebugInfo> {\n const [version, tokenExists] = await Promise.all([\n getPackageVersion(),\n checkTokenExists(),\n ])\n\n return {\n version,\n runtime: getRuntimeInfo(),\n paths: {\n APP_DIR: PATHS.APP_DIR,\n GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,\n },\n tokenExists,\n }\n}\n\nfunction printDebugInfoPlain(info: DebugInfo): void {\n consola.info(`github-router debug\n\nVersion: ${info.version}\nRuntime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})\n\nPaths:\n- APP_DIR: ${info.paths.APP_DIR}\n- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}\n\nToken exists: ${info.tokenExists ? \"Yes\" : \"No\"}`)\n}\n\nfunction printDebugInfoJson(info: DebugInfo): void {\n console.log(JSON.stringify(info, null, 2))\n}\n\nexport async function runDebug(options: RunDebugOptions): Promise<void> {\n const debugInfo = await getDebugInfo()\n\n if (options.json) {\n printDebugInfoJson(debugInfo)\n } else {\n printDebugInfoPlain(debugInfo)\n }\n}\n\nexport const debug = defineCommand({\n meta: {\n name: \"debug\",\n description: \"Print debug information about the application\",\n },\n args: {\n json: {\n type: \"boolean\",\n default: false,\n description: \"Output debug information as JSON\",\n },\n },\n run({ args }) {\n return runDebug({\n json: args.json,\n })\n },\n})\n","import consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nexport function initProxyFromEnv(): void {\n if (typeof Bun !== \"undefined\") return\n\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return (agent as unknown as Dispatcher).dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n setGlobalDispatcher(dispatcher as unknown as Dispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\n }\n}\n","import process from \"node:process\"\n\ntype ShellName = \"bash\" | \"zsh\" | \"fish\" | \"powershell\" | \"cmd\" | \"sh\"\ntype EnvVars = Record<string, string | undefined>\n\nfunction getShell(): ShellName {\n const { platform, env } = process\n\n if (platform === \"win32\") {\n // Git Bash / MSYS2 / Cygwin set SHELL even on Windows\n if (env.SHELL) {\n if (env.SHELL.endsWith(\"zsh\")) return \"zsh\"\n if (env.SHELL.endsWith(\"fish\")) return \"fish\"\n if (env.SHELL.endsWith(\"bash\")) return \"bash\"\n return \"sh\"\n }\n\n // Windows PowerShell 5.x sets this\n if (env.POWERSHELL_DISTRIBUTION_CHANNEL) return \"powershell\"\n\n // PowerShell (both 5.x and 7+/pwsh) adds user-scoped module paths\n // at runtime. The system-level PSModulePath in CMD lacks these paths.\n if (env.PSModulePath) {\n const lower = env.PSModulePath.toLowerCase()\n if (\n lower.includes(\"documents\\\\powershell\")\n || lower.includes(\"documents\\\\windowspowershell\")\n ) {\n return \"powershell\"\n }\n }\n\n return \"cmd\"\n }\n\n const shellPath = env.SHELL\n if (shellPath) {\n if (shellPath.endsWith(\"zsh\")) return \"zsh\"\n if (shellPath.endsWith(\"fish\")) return \"fish\"\n if (shellPath.endsWith(\"bash\")) return \"bash\"\n }\n\n return \"sh\"\n}\n\nfunction quotePosixValue(value: string): string {\n return `'${value.replace(/'/g, \"'\\\\''\")}'`\n}\n\nfunction quotePowerShellValue(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`\n}\n\n/**\n * Generates a copy-pasteable script to set multiple environment variables\n * and run a subsequent command.\n * @param {EnvVars} envVars - An object of environment variables to set.\n * @param {string} commandToRun - The command to run after setting the variables.\n * @returns {string} The formatted script string.\n */\nexport function generateEnvScript(\n envVars: EnvVars,\n commandToRun: string = \"\",\n): string {\n const shell = getShell()\n const filteredEnvVars = Object.entries(envVars).filter(\n ([, value]) => value !== undefined,\n ) as Array<[string, string]>\n\n let commandBlock: string\n\n switch (shell) {\n case \"powershell\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `$env:${key} = ${quotePowerShellValue(value)}`)\n .join(\"; \")\n break\n }\n case \"cmd\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set \"${key}=${value}\"`)\n .join(\" & \")\n break\n }\n case \"fish\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set -gx ${key} ${quotePosixValue(value)}`)\n .join(\"; \")\n break\n }\n default: {\n // bash, zsh, sh\n const assignments = filteredEnvVars\n .map(([key, value]) => `${key}=${quotePosixValue(value)}`)\n .join(\" \")\n commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : \"\"\n break\n }\n }\n\n if (commandBlock && commandToRun) {\n const separator =\n shell === \"cmd\" ? \" & \" : shell === \"powershell\" ? \"; \" : \" && \"\n return `${commandBlock}${separator}${commandToRun}`\n }\n\n return commandBlock || commandToRun\n}\n","import consola from \"consola\"\n\nimport { HTTPError } from \"./error\"\n\nexport const awaitApproval = async () => {\n const response = await consola.prompt(`Accept incoming request?`, {\n type: \"confirm\",\n })\n\n if (!response)\n throw new HTTPError(\n \"Request rejected by user\",\n Response.json({ message: \"Request rejected by user\" }, { status: 403 }),\n )\n}\n","import consola from \"consola\"\n\nimport type { State } from \"./state\"\n\nimport { HTTPError } from \"./error\"\nimport { sleep } from \"./utils\"\n\nexport async function checkRateLimit(state: State) {\n if (state.rateLimitSeconds === undefined) return\n\n const now = Date.now()\n\n if (!state.lastRequestTimestamp) {\n state.lastRequestTimestamp = now\n return\n }\n\n const elapsedSeconds = (now - state.lastRequestTimestamp) / 1000\n\n if (elapsedSeconds > state.rateLimitSeconds) {\n state.lastRequestTimestamp = now\n return\n }\n\n const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds)\n\n if (!state.rateLimitWait) {\n consola.warn(\n `Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,\n )\n throw new HTTPError(\n \"Rate limit exceeded\",\n Response.json({ message: \"Rate limit exceeded\" }, { status: 429 }),\n )\n }\n\n const waitTimeMs = waitTimeSeconds * 1000\n consola.warn(\n `Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`,\n )\n await sleep(waitTimeMs)\n state.lastRequestTimestamp = Date.now()\n consola.info(\"Rate limit wait completed, proceeding with request\")\n return\n}\n","import type {\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\n// Encoder type mapping\nconst ENCODING_MAP = {\n o200k_base: () => import(\"gpt-tokenizer/encoding/o200k_base\"),\n cl100k_base: () => import(\"gpt-tokenizer/encoding/cl100k_base\"),\n p50k_base: () => import(\"gpt-tokenizer/encoding/p50k_base\"),\n p50k_edit: () => import(\"gpt-tokenizer/encoding/p50k_edit\"),\n r50k_base: () => import(\"gpt-tokenizer/encoding/r50k_base\"),\n} as const\n\ntype SupportedEncoding = keyof typeof ENCODING_MAP\n\n// Define encoder interface\ninterface Encoder {\n encode: (text: string) => Array<number>\n}\n\n// Cache loaded encoders to avoid repeated imports\nconst encodingCache = new Map<string, Encoder>()\n\n/**\n * Calculate tokens for tool calls\n */\nconst calculateToolCallsTokens = (\n toolCalls: Array<ToolCall>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = 0\n for (const toolCall of toolCalls) {\n tokens += constants.funcInit\n tokens += encoder.encode(JSON.stringify(toolCall)).length\n }\n tokens += constants.funcEnd\n return tokens\n}\n\n/**\n * Calculate tokens for content parts\n */\nconst calculateContentPartsTokens = (\n contentParts: Array<ContentPart>,\n encoder: Encoder,\n): number => {\n let tokens = 0\n for (const part of contentParts) {\n if (part.type === \"image_url\") {\n tokens += encoder.encode(part.image_url.url).length + 85\n } else if (part.text) {\n tokens += encoder.encode(part.text).length\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens for a single message\n */\nconst calculateMessageTokens = (\n message: Message,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n const tokensPerMessage = 3\n const tokensPerName = 1\n let tokens = tokensPerMessage\n for (const [key, value] of Object.entries(message)) {\n if (typeof value === \"string\") {\n tokens += encoder.encode(value).length\n }\n if (key === \"name\") {\n tokens += tokensPerName\n }\n if (key === \"tool_calls\") {\n tokens += calculateToolCallsTokens(\n value as Array<ToolCall>,\n encoder,\n constants,\n )\n }\n if (key === \"content\" && Array.isArray(value)) {\n tokens += calculateContentPartsTokens(\n value as Array<ContentPart>,\n encoder,\n )\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens using custom algorithm\n */\nconst calculateTokens = (\n messages: Array<Message>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (messages.length === 0) {\n return 0\n }\n let numTokens = 0\n for (const message of messages) {\n numTokens += calculateMessageTokens(message, encoder, constants)\n }\n // every reply is primed with <|start|>assistant<|message|>\n numTokens += 3\n return numTokens\n}\n\n/**\n * Get the corresponding encoder module based on encoding type\n */\nconst getEncodeChatFunction = async (encoding: string): Promise<Encoder> => {\n if (encodingCache.has(encoding)) {\n const cached = encodingCache.get(encoding)\n if (cached) {\n return cached\n }\n }\n\n const supportedEncoding = encoding as SupportedEncoding\n if (!(supportedEncoding in ENCODING_MAP)) {\n const fallbackModule = (await ENCODING_MAP.o200k_base()) as Encoder\n encodingCache.set(encoding, fallbackModule)\n return fallbackModule\n }\n\n const encodingModule = (await ENCODING_MAP[supportedEncoding]()) as Encoder\n encodingCache.set(encoding, encodingModule)\n return encodingModule\n}\n\n/**\n * Get tokenizer type from model information\n */\nexport const getTokenizerFromModel = (model: Model): string => {\n return model.capabilities.tokenizer || \"o200k_base\"\n}\n\n/**\n * Get model-specific constants for token calculation\n */\nconst getModelConstants = (model: Model) => {\n return model.id === \"gpt-3.5-turbo\" || model.id === \"gpt-4\" ?\n {\n funcInit: 10,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n : {\n funcInit: 7,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n}\n\n/**\n * Calculate tokens for a single parameter\n */\nconst calculateParameterTokens = (\n key: string,\n prop: unknown,\n context: {\n encoder: Encoder\n constants: ReturnType<typeof getModelConstants>\n },\n): number => {\n const { encoder, constants } = context\n let tokens = constants.propKey\n\n // Early return if prop is not an object\n if (typeof prop !== \"object\" || prop === null) {\n return tokens\n }\n\n // Type assertion for parameter properties\n const param = prop as {\n type?: string\n description?: string\n enum?: Array<unknown>\n [key: string]: unknown\n }\n\n const paramName = key\n const paramType = param.type || \"string\"\n let paramDesc = param.description || \"\"\n\n // Handle enum values\n if (param.enum && Array.isArray(param.enum)) {\n tokens += constants.enumInit\n for (const item of param.enum) {\n tokens += constants.enumItem\n tokens += encoder.encode(String(item)).length\n }\n }\n\n // Clean up description\n if (paramDesc.endsWith(\".\")) {\n paramDesc = paramDesc.slice(0, -1)\n }\n\n // Encode the main parameter line\n const line = `${paramName}:${paramType}:${paramDesc}`\n tokens += encoder.encode(line).length\n\n // Handle additional properties (excluding standard ones)\n const excludedKeys = new Set([\"type\", \"description\", \"enum\"])\n for (const propertyName of Object.keys(param)) {\n if (!excludedKeys.has(propertyName)) {\n const propertyValue = param[propertyName]\n const propertyText =\n typeof propertyValue === \"string\" ? propertyValue : (\n JSON.stringify(propertyValue)\n )\n tokens += encoder.encode(`${propertyName}:${propertyText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for function parameters\n */\nconst calculateParametersTokens = (\n parameters: unknown,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (!parameters || typeof parameters !== \"object\") {\n return 0\n }\n\n const params = parameters as Record<string, unknown>\n let tokens = 0\n\n for (const [key, value] of Object.entries(params)) {\n if (key === \"properties\") {\n const properties = value as Record<string, unknown>\n if (Object.keys(properties).length > 0) {\n tokens += constants.propInit\n for (const propKey of Object.keys(properties)) {\n tokens += calculateParameterTokens(propKey, properties[propKey], {\n encoder,\n constants,\n })\n }\n }\n } else {\n const paramText =\n typeof value === \"string\" ? value : JSON.stringify(value)\n tokens += encoder.encode(`${key}:${paramText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for a single tool\n */\nconst calculateToolTokens = (\n tool: Tool,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = constants.funcInit\n const func = tool.function\n const fName = func.name\n let fDesc = func.description || \"\"\n if (fDesc.endsWith(\".\")) {\n fDesc = fDesc.slice(0, -1)\n }\n const line = fName + \":\" + fDesc\n tokens += encoder.encode(line).length\n if (\n typeof func.parameters === \"object\" \n && func.parameters !== null\n ) {\n tokens += calculateParametersTokens(func.parameters, encoder, constants)\n }\n return tokens\n}\n\n/**\n * Calculate token count for tools based on model\n */\nexport const numTokensForTools = (\n tools: Array<Tool>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let funcTokenCount = 0\n for (const tool of tools) {\n funcTokenCount += calculateToolTokens(tool, encoder, constants)\n }\n funcTokenCount += constants.funcEnd\n return funcTokenCount\n}\n\n/**\n * Calculate the token count of messages, supporting multiple GPT encoders\n */\nexport const getTokenCount = async (\n payload: ChatCompletionsPayload,\n model: Model,\n): Promise<{ input: number; output: number }> => {\n // Get tokenizer string\n const tokenizer = getTokenizerFromModel(model)\n\n // Get corresponding encoder module\n const encoder = await getEncodeChatFunction(tokenizer)\n\n const simplifiedMessages = payload.messages\n const inputMessages = simplifiedMessages.filter(\n (msg) => msg.role !== \"assistant\",\n )\n const outputMessages = simplifiedMessages.filter(\n (msg) => msg.role === \"assistant\",\n )\n\n const constants = getModelConstants(model)\n let inputTokens = calculateTokens(inputMessages, encoder, constants)\n if (payload.tools && payload.tools.length > 0) {\n inputTokens += numTokensForTools(payload.tools, encoder, constants)\n }\n const outputTokens = calculateTokens(outputMessages, encoder, constants)\n\n return {\n input: inputTokens,\n output: outputTokens,\n }\n}\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createChatCompletions = async (\n payload: ChatCompletionsPayload,\n) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = payload.messages.some(\n (x) =>\n typeof x.content !== \"string\"\n && x.content?.some((x) => x.type === \"image_url\"),\n )\n\n // Agent/user check for X-Initiator header\n // Determine if any message is from an agent (\"assistant\" or \"tool\")\n const isAgentCall = payload.messages.some((msg) =>\n [\"assistant\", \"tool\"].includes(msg.role),\n )\n\n // Build headers and add X-Initiator\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n \"Openai-Organization\": \"github-copilot\",\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n const claudeModels = state.models?.data\n .filter((m) => m.id.startsWith(\"claude\"))\n .map((m) => m.id)\n .join(\", \") ?? \"(models not loaded)\"\n consola.error(\n `Copilot rejected model \"${payload.model}\": ${response.status} ${errorBody} (available Claude models: ${claudeModels})`,\n )\n // Re-create the response so downstream error handlers can still read the body\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Failed to create chat completions\", reconstructed)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ChatCompletionResponse\n}\n\n// Streaming types\n\nexport interface ChatCompletionChunk {\n id: string\n object: \"chat.completion.chunk\"\n created: number\n model: string\n choices: Array<Choice>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n completion_tokens_details?: {\n accepted_prediction_tokens: number\n rejected_prediction_tokens: number\n }\n }\n}\n\ninterface Delta {\n content?: string | null\n role?: \"user\" | \"assistant\" | \"system\" | \"tool\"\n tool_calls?: Array<{\n index: number\n id?: string\n type?: \"function\"\n function?: {\n name?: string\n arguments?: string\n }\n }>\n}\n\ninterface Choice {\n index: number\n delta: Delta\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null\n logprobs: object | null\n}\n\n// Non-streaming types\n\nexport interface ChatCompletionResponse {\n id: string\n object: \"chat.completion\"\n created: number\n model: string\n choices: Array<ChoiceNonStreaming>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n }\n}\n\ninterface ResponseMessage {\n role: \"assistant\"\n content: string | null\n tool_calls?: Array<ToolCall>\n}\n\ninterface ChoiceNonStreaming {\n index: number\n message: ResponseMessage\n logprobs: object | null\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\"\n}\n\n// Payload types\n\nexport interface ChatCompletionsPayload {\n messages: Array<Message>\n model: string\n temperature?: number | null\n top_p?: number | null\n max_tokens?: number | null\n stop?: string | Array<string> | null\n n?: number | null\n stream?: boolean | null\n\n frequency_penalty?: number | null\n presence_penalty?: number | null\n logit_bias?: Record<string, number> | null\n logprobs?: boolean | null\n response_format?: { type: \"json_object\" } | null\n seed?: number | null\n tools?: Array<Tool> | null\n tool_choice?:\n | \"none\"\n | \"auto\"\n | \"required\"\n | { type: \"function\"; function: { name: string } }\n | null\n user?: string | null\n}\n\nexport interface Tool {\n type: \"function\"\n function: {\n name: string\n description?: string\n parameters: Record<string, unknown>\n }\n}\n\nexport interface Message {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\" | \"developer\"\n content: string | Array<ContentPart> | null\n\n name?: string\n tool_calls?: Array<ToolCall>\n tool_call_id?: string\n}\n\nexport interface ToolCall {\n id: string\n type: \"function\"\n function: {\n name: string\n arguments: string\n }\n}\n\nexport type ContentPart = TextPart | ImagePart\n\nexport interface TextPart {\n type: \"text\"\n text: string\n}\n\nexport interface ImagePart {\n type: \"image_url\"\n image_url: {\n url: string\n detail?: \"low\" | \"high\" | \"auto\"\n }\n}\n","import consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { state } from \"~/lib/state\"\nimport { sleep } from \"~/lib/utils\"\n\nexport interface WebSearchResult {\n content: string\n references: Array<{ title: string; url: string }>\n}\n\ninterface ThreadsResponse {\n thread_id: string\n}\n\ninterface ThreadsMessageResponse {\n message: {\n content: string\n references: Array<{\n query?: string\n results?: Array<{\n title: string\n url: string\n reference_type: string\n }>\n }>\n }\n}\n\nconst MAX_SEARCHES_PER_SECOND = 3\nlet searchTimestamps: Array<number> = []\n\nasync function throttleSearch(): Promise<void> {\n const now = Date.now()\n searchTimestamps = searchTimestamps.filter((t) => now - t < 1000)\n if (searchTimestamps.length >= MAX_SEARCHES_PER_SECOND) {\n const waitMs = 1000 - (now - searchTimestamps[0])\n if (waitMs > 0) {\n consola.debug(`Web search rate limited, waiting ${waitMs}ms`)\n await sleep(waitMs)\n }\n }\n searchTimestamps.push(Date.now())\n}\n\nfunction threadsHeaders(): Record<string, string> {\n return copilotHeaders(state, false, \"copilot-chat\")\n}\n\nasync function createThread(): Promise<string> {\n const response = await fetch(`${copilotBaseUrl(state)}/github/chat/threads`, {\n method: \"POST\",\n headers: threadsHeaders(),\n body: JSON.stringify({}),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create chat thread\", response.status)\n throw new Error(`Failed to create chat thread: ${response.status}`)\n }\n\n const data = (await response.json()) as ThreadsResponse\n return data.thread_id\n}\n\nasync function sendThreadMessage(\n threadId: string,\n query: string,\n): Promise<ThreadsMessageResponse> {\n const response = await fetch(\n `${copilotBaseUrl(state)}/github/chat/threads/${threadId}/messages`,\n {\n method: \"POST\",\n headers: threadsHeaders(),\n body: JSON.stringify({\n content: query,\n intent: \"conversation\",\n skills: [\"web-search\"],\n references: [],\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to send thread message\", response.status)\n throw new Error(`Failed to send thread message: ${response.status}`)\n }\n\n return (await response.json()) as ThreadsMessageResponse\n}\n\nexport async function searchWeb(query: string): Promise<WebSearchResult> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n await throttleSearch()\n\n consola.info(`Web search: \"${query.slice(0, 80)}\"`)\n\n const threadId = await createThread()\n const response = await sendThreadMessage(threadId, query)\n\n const references: Array<{ title: string; url: string }> = []\n for (const ref of response.message.references ?? []) {\n if (ref.results) {\n for (const result of ref.results) {\n if (result.url && result.reference_type !== \"bing_search\") {\n references.push({ title: result.title, url: result.url })\n }\n }\n }\n }\n\n consola.debug(`Web search returned ${references.length} references`)\n\n return {\n content: response.message.content,\n references,\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE, type SSEMessage } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\nimport { isNullish } from \"~/lib/utils\"\nimport {\n createChatCompletions,\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n type Message,\n} from \"~/services/copilot/create-chat-completions\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleCompletion(c: Context) {\n await checkRateLimit(state)\n\n let payload = await c.req.json<ChatCompletionsPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Request payload:\", JSON.stringify(payload).slice(-400))\n }\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n // Find the selected model\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n // Calculate and display token count\n try {\n if (selectedModel) {\n const tokenCount = await getTokenCount(payload, selectedModel)\n consola.info(\"Current token count:\", tokenCount)\n } else {\n consola.warn(\"No model selected, skipping token count calculation\")\n }\n } catch (error) {\n consola.warn(\"Failed to calculate token count:\", error)\n }\n\n if (isNullish(payload.max_tokens)) {\n payload = {\n ...payload,\n max_tokens: selectedModel?.capabilities.limits.max_output_tokens,\n }\n if (debugEnabled) {\n consola.debug(\"Set max_tokens to:\", JSON.stringify(payload.max_tokens))\n }\n }\n\n const response = await createChatCompletions(payload)\n\n if (isNonStreaming(response)) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n consola.debug(\"Streaming response\")\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n await stream.writeSSE(chunk as SSEMessage)\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n\nasync function injectWebSearchIfNeeded(\n payload: ChatCompletionsPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some(\n (t) =>\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\",\n )\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = payload.messages.some((msg) => msg.role === \"tool\")\n const query = hasToolResult ? undefined : extractUserQuery(payload.messages)\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n // Prepend to existing system message or inject a new one\n const systemMsg = payload.messages.find((msg) => msg.role === \"system\")\n if (systemMsg) {\n const existingContent =\n typeof systemMsg.content === \"string\" ? systemMsg.content\n : Array.isArray(systemMsg.content) ?\n systemMsg.content\n .filter((p) => p.type === \"text\")\n .map((p) => (\"text\" in p ? p.text : \"\"))\n .join(\"\\n\")\n : \"\"\n systemMsg.content = `${searchContext}\\n\\n${existingContent}`\n } else {\n payload.messages.unshift({\n role: \"system\",\n content: searchContext,\n })\n }\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Remove web_search from tools before forwarding\n payload.tools = payload.tools?.filter(\n (t) =>\n !(\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\"\n ),\n ) as typeof payload.tools\n if (payload.tools?.length === 0) {\n payload.tools = undefined\n }\n if (!payload.tools) {\n payload.tool_choice = undefined\n } else if (\n payload.tool_choice\n && typeof payload.tool_choice === \"object\"\n && \"type\" in payload.tool_choice\n && payload.tool_choice.type === \"function\"\n ) {\n const toolChoiceName = payload.tool_choice.function?.name\n if (\n toolChoiceName\n && !payload.tools.some((tool) => tool.function.name === toolChoiceName)\n ) {\n payload.tool_choice = undefined\n }\n }\n}\n\nfunction extractUserQuery(messages: Array<Message>): string | undefined {\n // Find the last user message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const text = msg.content.find((p) => p.type === \"text\")\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const completionRoutes = new Hono()\n\ncompletionRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createEmbeddings = async (payload: EmbeddingRequest) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const response = await fetch(`${copilotBaseUrl(state)}/embeddings`, {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to create embeddings\", response)\n\n return (await response.json()) as EmbeddingResponse\n}\n\nexport interface EmbeddingRequest {\n input: string | Array<string>\n model: string\n}\n\nexport interface Embedding {\n object: string\n embedding: Array<number>\n index: number\n}\n\nexport interface EmbeddingResponse {\n object: string\n data: Array<Embedding>\n model: string\n usage: {\n prompt_tokens: number\n total_tokens: number\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport {\n createEmbeddings,\n type EmbeddingRequest,\n} from \"~/services/copilot/create-embeddings\"\n\nexport const embeddingRoutes = new Hono()\n\nembeddingRoutes.post(\"/\", async (c) => {\n try {\n const payload = await c.req.json<EmbeddingRequest>()\n const response = await createEmbeddings(payload)\n\n return c.json(response)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { randomUUID } from \"node:crypto\"\n\nimport consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\n/**\n * Build headers that match what VS Code Copilot Chat sends to the Copilot API.\n *\n * copilotHeaders() provides: Authorization, content-type, copilot-integration-id,\n * editor-version, editor-plugin-version, user-agent, openai-intent,\n * x-github-api-version, x-request-id, x-vscode-user-agent-library-version.\n *\n * We add the remaining headers VS Code sends for /v1/messages:\n * - X-Initiator (VS Code sets dynamically; \"agent\" is safe for CLI use)\n * - anthropic-version (VS Code's Anthropic SDK sends this)\n * - X-Interaction-Id (VS Code sends a session-scoped UUID)\n *\n * We intentionally omit copilot-vision-request — VS Code only sends it when\n * images are present, and the native /v1/messages endpoint handles vision\n * without requiring the header.\n *\n * extraHeaders allows callers to forward client-supplied beta headers\n * (anthropic-beta) so Copilot enables extended features.\n */\nfunction buildHeaders(\n extraHeaders?: Record<string, string>,\n): Record<string, string> {\n return {\n ...copilotHeaders(state),\n \"X-Initiator\": \"agent\",\n \"anthropic-version\": \"2023-06-01\",\n \"X-Interaction-Id\": randomUUID(),\n ...extraHeaders,\n }\n}\n\n/**\n * Forward an Anthropic Messages API request to Copilot's native /v1/messages endpoint.\n * Returns the raw Response so callers can handle streaming vs non-streaming.\n */\nexport async function createMessages(\n body: string,\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders(extraHeaders)\n const url = `${copilotBaseUrl(state)}/v1/messages?beta=true`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot /v1/messages error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot messages request failed\", reconstructed)\n }\n\n return response\n}\n\n/**\n * Forward an Anthropic count_tokens request to Copilot's native endpoint.\n * Returns the raw Response.\n */\nexport async function countTokens(\n body: string,\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders(extraHeaders)\n const url = `${copilotBaseUrl(state)}/v1/messages/count_tokens?beta=true`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot count_tokens error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot count_tokens request failed\", reconstructed)\n }\n\n return response\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { filterBetaHeader } from \"~/lib/utils\"\nimport { countTokens } from \"~/services/copilot/create-messages\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Strip web_search tools from the request body before forwarding\n * to Copilot's count_tokens endpoint, which rejects unknown tool types.\n * Returns the original raw body if no web_search tools are present.\n */\nfunction stripWebSearchFromBody(rawBody: string): string {\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n\n return JSON.stringify(body)\n}\n\n/**\n * Passthrough handler for Anthropic token counting.\n * Strips web_search tools and forwards beta headers to Copilot's\n * native /v1/messages/count_tokens endpoint.\n */\nexport async function handleCountTokens(c: Context) {\n const rawBody = await c.req.text()\n const finalBody = stripWebSearchFromBody(rawBody)\n\n const extraHeaders: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) extraHeaders[\"anthropic-beta\"] = filtered\n }\n\n const response = await countTokens(finalBody, extraHeaders)\n const body = await response.json()\n\n consola.info(\"Token count:\", JSON.stringify(body))\n\n return c.json(body)\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { filterBetaHeader } from \"~/lib/utils\"\nimport { createMessages } from \"~/services/copilot/create-messages\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Extract whitelisted beta headers from the incoming request to forward\n * to the Copilot API. VS Code sends these to enable extended features\n * like thinking, context management, and advanced tool use.\n */\nfunction extractBetaHeaders(c: Context): Record<string, string> {\n const headers: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) headers[\"anthropic-beta\"] = filtered\n }\n return headers\n}\n\n/**\n * Extract the text content from the last user message for web search.\n * Handles both string content and content block arrays (multimodal).\n */\nfunction extractUserQuery(\n messages: Array<AnyRecord>,\n): string | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const textBlock = msg.content.find(\n (block: AnyRecord) => block.type === \"text\",\n )\n if (textBlock?.text) return textBlock.text as string\n }\n }\n }\n return undefined\n}\n\n/**\n * Check if any user message contains tool_result content blocks,\n * indicating a follow-up turn where we should skip web search.\n * In Anthropic format, tool results are content blocks inside user messages,\n * NOT separate role: \"tool\" messages like in OpenAI format.\n */\nfunction hasToolResultContent(messages: Array<AnyRecord>): boolean {\n return messages.some(\n (msg) =>\n Array.isArray(msg.content) &&\n msg.content.some(\n (block: AnyRecord) => block.type === \"tool_result\",\n ),\n )\n}\n\n/**\n * Inject web search results into the Anthropic system field.\n * Handles three cases: absent, string, or array of content blocks.\n * When array, prepends without cache_control to preserve existing directives.\n */\nfunction injectSearchResults(\n body: AnyRecord,\n searchContext: string,\n): void {\n if (body.system === undefined || body.system === null) {\n body.system = searchContext\n } else if (typeof body.system === \"string\") {\n body.system = `${searchContext}\\n\\n${body.system}`\n } else if (Array.isArray(body.system)) {\n body.system = [\n { type: \"text\", text: searchContext },\n ...body.system,\n ]\n }\n}\n\n/**\n * Strip web_search tools from the request and clean up tool_choice.\n * Returns the modified body object.\n */\nfunction stripWebSearchTool(body: AnyRecord): void {\n if (!body.tools) return\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n // If tool_choice forced the removed web_search tool, fall back to auto\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n}\n\n/**\n * Process web search if the request contains a web_search tool.\n * Performs the search, injects results into system, and strips the tool.\n * Returns the (possibly modified) body string to forward.\n */\nasync function processWebSearch(rawBody: string): Promise<string> {\n // Fast path: skip parsing if no web_search tool present\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = hasToolResultContent(body.messages ?? [])\n const query = hasToolResult ? undefined : extractUserQuery(body.messages ?? [])\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n injectSearchResults(body, searchContext)\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Always strip web_search tool regardless of whether search succeeded\n stripWebSearchTool(body)\n\n return JSON.stringify(body)\n}\n\nexport async function handleCompletion(c: Context) {\n await checkRateLimit(state)\n\n const rawBody = await c.req.text()\n\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Anthropic request body:\", rawBody.slice(0, 2000))\n }\n\n if (state.manualApprove) {\n await awaitApproval()\n }\n\n const betaHeaders = extractBetaHeaders(c)\n const finalBody = await processWebSearch(rawBody)\n\n const response = await createMessages(finalBody, betaHeaders)\n\n const contentType = response.headers.get(\"content-type\") ?? \"\"\n\n // Streaming: pipe the upstream SSE response body directly\n if (contentType.includes(\"text/event-stream\")) {\n if (debugEnabled) {\n consola.debug(\"Streaming response from Copilot /v1/messages\")\n }\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n },\n })\n }\n\n // Non-streaming: forward JSON response\n const responseBody = await response.json()\n if (debugEnabled) {\n consola.debug(\n \"Non-streaming response from Copilot /v1/messages:\",\n JSON.stringify(responseBody).slice(0, 2000),\n )\n }\n return c.json(responseBody, response.status as 200)\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCountTokens } from \"./count-tokens-handler\"\nimport { handleCompletion } from \"./handler\"\n\nexport const messageRoutes = new Hono()\n\nmessageRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\nmessageRoutes.post(\"/count_tokens\", async (c) => {\n try {\n return await handleCountTokens(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport { cacheModels } from \"~/lib/utils\"\n\nexport const modelRoutes = new Hono()\n\nmodelRoutes.get(\"/\", async (c) => {\n try {\n if (!state.models) {\n // This should be handled by startup logic, but as a fallback.\n await cacheModels()\n }\n\n const models = state.models?.data.map((model) => ({\n id: model.id,\n object: \"model\",\n type: \"model\",\n created: 0, // No date available from source\n created_at: new Date(0).toISOString(), // No date available from source\n owned_by: model.vendor,\n display_name: model.name,\n }))\n\n return c.json({\n object: \"list\",\n data: models,\n has_more: false,\n })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createResponses = async (payload: ResponsesPayload) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = detectVision(payload.input)\n\n const isAgentCall = detectAgentCall(payload.input)\n\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const filteredPayload = filterUnsupportedTools(payload)\n\n const response = await fetch(`${copilotBaseUrl(state)}/responses`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(filteredPayload),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create responses\", response)\n throw new HTTPError(\"Failed to create responses\", response)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ResponsesApiResponse\n}\n\nfunction detectVision(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"content\" in item && Array.isArray(item.content)) {\n return item.content.some(\n (part: Record<string, unknown>) => part.type === \"input_image\",\n )\n }\n return false\n })\n}\n\nfunction detectAgentCall(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"role\" in item && item.role === \"assistant\") return true\n if (\n \"type\" in item\n && (item.type === \"function_call\" || item.type === \"function_call_output\")\n ) {\n return true\n }\n return false\n })\n}\n\nfunction filterUnsupportedTools(payload: ResponsesPayload): ResponsesPayload {\n if (!payload.tools || !Array.isArray(payload.tools)) return payload\n\n const supported = payload.tools.filter((tool) => {\n const isSupported = tool.type === \"function\"\n if (!isSupported) {\n consola.debug(`Stripping unsupported tool type: ${tool.type}`)\n }\n return isSupported\n })\n\n let toolChoice = payload.tool_choice\n if (supported.length === 0) {\n toolChoice = undefined\n } else if (\n toolChoice\n && typeof toolChoice === \"object\"\n ) {\n const supportedNames = new Set(\n supported.map((tool) => tool.name).filter(Boolean),\n )\n const toolChoiceName = getToolChoiceName(toolChoice)\n if (toolChoiceName && !supportedNames.has(toolChoiceName)) {\n toolChoice = undefined\n }\n }\n\n return {\n ...payload,\n tools: supported.length > 0 ? supported : undefined,\n tool_choice: toolChoice,\n }\n}\n\nfunction getToolChoiceName(\n toolChoice: NonNullable<ResponsesPayload[\"tool_choice\"]>,\n): string | undefined {\n if (typeof toolChoice !== \"object\") return undefined\n if (\n \"function\" in toolChoice\n && toolChoice.function\n && typeof toolChoice.function === \"object\"\n ) {\n return (toolChoice.function as { name?: string }).name\n }\n if (\"name\" in toolChoice) {\n return toolChoice.name\n }\n return undefined\n}\n\n// Types\n\nexport interface ResponsesInputItem {\n role?: \"user\" | \"assistant\" | \"system\"\n type?: \"message\" | \"function_call\" | \"function_call_output\"\n content?: string | Array<Record<string, unknown>>\n name?: string\n call_id?: string\n arguments?: string\n output?: string\n [key: string]: unknown\n}\n\nexport interface ResponsesTool {\n type: string\n name?: string\n description?: string\n parameters?: Record<string, unknown>\n [key: string]: unknown\n}\n\nexport interface ResponsesPayload {\n model: string\n input: string | Array<ResponsesInputItem>\n instructions?: string\n tools?: Array<ResponsesTool>\n tool_choice?:\n | string\n | { type: string; name?: string; function?: { name?: string } }\n max_output_tokens?: number\n temperature?: number\n top_p?: number\n stream?: boolean\n store?: boolean\n metadata?: Record<string, string>\n previous_response_id?: string\n reasoning?: { effort?: string; summary?: string }\n [key: string]: unknown\n}\n\nexport interface ResponsesApiResponse {\n id: string\n object: \"response\"\n status: string\n output: Array<unknown>\n [key: string]: unknown\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { state } from \"~/lib/state\"\nimport { isNullish } from \"~/lib/utils\"\nimport {\n createResponses,\n type ResponsesApiResponse,\n type ResponsesInputItem,\n type ResponsesPayload,\n} from \"~/services/copilot/create-responses\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleResponses(c: Context) {\n await checkRateLimit(state)\n\n const payload = await c.req.json<ResponsesPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\n \"Responses request payload:\",\n JSON.stringify(payload).slice(-400),\n )\n }\n\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n consola.info(\"Token counting not yet supported for /responses endpoint\")\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n if (isNullish(payload.max_output_tokens)) {\n payload.max_output_tokens =\n selectedModel?.capabilities.limits.max_output_tokens\n if (debugEnabled) {\n consola.debug(\n \"Set max_output_tokens to:\",\n JSON.stringify(payload.max_output_tokens),\n )\n }\n }\n\n const response = await createResponses(payload)\n\n if (isNonStreaming(response)) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n consola.debug(\"Streaming response\")\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n\n if (chunk.data === \"[DONE]\") {\n break\n }\n\n if (!chunk.data) {\n continue\n }\n\n await stream.writeSSE({\n data: chunk.data,\n event: chunk.event,\n id: chunk.id?.toString(),\n })\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createResponses>>,\n): response is ResponsesApiResponse => Object.hasOwn(response, \"output\")\n\nasync function injectWebSearchIfNeeded(\n payload: ResponsesPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some((t) => t.type === \"web_search\")\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (function call results)\n if (Array.isArray(payload.input)) {\n const hasFollowUp = payload.input.some(\n (item: ResponsesInputItem) => item.type === \"function_call_output\",\n )\n if (hasFollowUp) return\n }\n\n const query = extractUserQuery(payload.input)\n if (!query) return\n\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n payload.instructions =\n payload.instructions ?\n `${searchContext}\\n\\n${payload.instructions}`\n : searchContext\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n}\n\nfunction extractUserQuery(\n input: ResponsesPayload[\"input\"],\n): string | undefined {\n if (typeof input === \"string\") return input\n if (!Array.isArray(input)) return undefined\n\n // Find the last user message\n for (let i = input.length - 1; i >= 0; i--) {\n const item = input[i]\n if (\"role\" in item && item.role === \"user\") {\n if (typeof item.content === \"string\") return item.content\n if (Array.isArray(item.content)) {\n const text = item.content.find(\n (p: Record<string, unknown>) => p.type === \"input_text\",\n )\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleResponses } from \"./handler\"\n\nexport const responsesRoutes = new Hono()\n\nresponsesRoutes.post(\"/\", async (c) => {\n try {\n return await handleResponses(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport const searchRoutes = new Hono()\n\nsearchRoutes.post(\"/\", async (c) => {\n try {\n const { query } = await c.req.json<{ query: string }>()\n\n if (!query || typeof query !== \"string\") {\n return c.json(\n { error: { message: \"Missing required field: query\" } },\n 400,\n )\n }\n\n const results = await searchWeb(query)\n return c.json({ results })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { state } from \"~/lib/state\"\n\nexport const tokenRoute = new Hono()\n\ntokenRoute.get(\"/\", (c) => {\n if (!state.showToken) {\n return c.json(\n { error: { message: \"Token endpoint disabled\", type: \"error\" } },\n 403,\n )\n }\n\n return c.json({\n token: state.copilotToken,\n })\n})\n","import { Hono } from \"hono\"\nimport consola from \"consola\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\n\nexport const usageRoute = new Hono()\n\nusageRoute.get(\"/\", async (c) => {\n try {\n const usage = await getCopilotUsage()\n return c.json(usage)\n } catch (error) {\n consola.error(\"Error fetching Copilot usage:\", error)\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\nimport { logger } from \"hono/logger\"\n\nimport { completionRoutes } from \"./routes/chat-completions/route\"\nimport { embeddingRoutes } from \"./routes/embeddings/route\"\nimport { messageRoutes } from \"./routes/messages/route\"\nimport { modelRoutes } from \"./routes/models/route\"\nimport { responsesRoutes } from \"./routes/responses/route\"\nimport { searchRoutes } from \"./routes/search/route\"\nimport { tokenRoute } from \"./routes/token/route\"\nimport { usageRoute } from \"./routes/usage/route\"\n\nexport const server = new Hono()\n\nserver.use(logger())\nserver.use(cors())\n\nserver.get(\"/\", (c) => c.text(\"Server running\"))\n\nserver.route(\"/chat/completions\", completionRoutes)\nserver.route(\"/responses\", responsesRoutes)\nserver.route(\"/models\", modelRoutes)\nserver.route(\"/embeddings\", embeddingRoutes)\nserver.route(\"/search\", searchRoutes)\nserver.route(\"/usage\", usageRoute)\nserver.route(\"/token\", tokenRoute)\n\n// Compatibility with tools that expect v1/ prefix\nserver.route(\"/v1/chat/completions\", completionRoutes)\nserver.route(\"/v1/responses\", responsesRoutes)\nserver.route(\"/v1/models\", modelRoutes)\nserver.route(\"/v1/embeddings\", embeddingRoutes)\nserver.route(\"/v1/search\", searchRoutes)\n\n// Anthropic compatible endpoints\nserver.route(\"/v1/messages\", messageRoutes)\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport invariant from \"tiny-invariant\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { initProxyFromEnv } from \"./lib/proxy\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\nimport { setupCopilotToken, setupGitHubToken } from \"./lib/token\"\nimport { cacheModels, cacheVSCodeVersion } from \"./lib/utils\"\nimport type { Model } from \"./services/copilot/get-models\"\nimport { server } from \"./server\"\n\ninterface RunServerOptions {\n port: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n claudeCode: boolean\n codex: boolean\n showToken: boolean\n proxyEnv: boolean\n}\n\nconst allowedAccountTypes = new Set([\"individual\", \"business\", \"enterprise\"])\n\nfunction printAndCopyCommand(command: string, label: string): void {\n consola.box(`${label}\\n\\n${command}`)\n try {\n clipboard.writeSync(command)\n consola.success(`Copied ${label} command to clipboard!`)\n } catch {\n consola.warn(\"Failed to copy to clipboard. Copy the command above manually.\")\n }\n}\n\nfunction filterModelsByEndpoint(\n models: Array<Model>,\n endpoint: string,\n): Array<Model> {\n const filtered = models.filter((model) => {\n const endpoints = model.supported_endpoints\n // Some deployments omit supported_endpoints; keep those models visible.\n if (!endpoints || endpoints.length === 0) return true\n return endpoints.some((entry) => {\n const normalized = entry.replace(/^\\/?v1\\//, \"\").replace(/^\\//, \"\")\n return normalized === endpoint\n })\n })\n\n return filtered.length > 0 ? filtered : models\n}\n\nasync function generateClaudeCodeCommand(serverUrl: string) {\n invariant(state.models, \"Models should be loaded by now\")\n\n const claudeModels = state.models.data.filter((model) =>\n model.id.toLowerCase().startsWith(\"claude\"),\n )\n\n if (claudeModels.length === 0) {\n consola.error(\"No Claude models available from Copilot API\")\n return\n }\n\n // Pick the best main model: prefer opus, then sonnet, then first available\n const mainModel =\n claudeModels.find((m) => m.id.includes(\"opus\")) ??\n claudeModels.find((m) => m.id.includes(\"sonnet\")) ??\n claudeModels[0]\n\n // Pick the best small model: prefer haiku, then sonnet, then first available\n const smallModel =\n claudeModels.find((m) => m.id.includes(\"haiku\")) ??\n claudeModels.find((m) => m.id.includes(\"sonnet\")) ??\n claudeModels[0]\n\n // Only prompt if there are multiple options and the user might want to override\n let selectedModel = mainModel.id\n let selectedSmallModel = smallModel.id\n\n if (claudeModels.length > 1) {\n consola.info(\n `Using ${mainModel.id} as main model and ${smallModel.id} as small model`,\n )\n const override = await consola.prompt(\"Override model selection?\", {\n type: \"confirm\",\n initial: false,\n })\n\n if (override) {\n selectedModel = await consola.prompt(\n \"Select a main model for Claude Code\",\n {\n type: \"select\",\n options: claudeModels.map((model) => model.id),\n },\n )\n selectedSmallModel = await consola.prompt(\n \"Select a small/fast model for Claude Code\",\n {\n type: \"select\",\n options: claudeModels.map((model) => model.id),\n },\n )\n }\n }\n\n const command = generateEnvScript(\n {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n ANTHROPIC_MODEL: selectedModel,\n ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,\n ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,\n ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n },\n \"claude --dangerously-skip-permissions\",\n )\n\n printAndCopyCommand(command, \"Claude Code\")\n}\n\nasync function generateCodexCommand(serverUrl: string) {\n invariant(state.models, \"Models should be loaded by now\")\n\n const supportedModels = filterModelsByEndpoint(\n state.models.data,\n \"responses\",\n )\n\n const defaultCodexModel = supportedModels.find(\n (model) => model.id === \"gpt5.2-codex\",\n )\n\n const selectedModel =\n defaultCodexModel ?\n defaultCodexModel.id\n : await consola.prompt(\"Select a model to use with Codex CLI\", {\n type: \"select\",\n options: supportedModels.map((model) => model.id),\n })\n\n const quotedModel = JSON.stringify(selectedModel)\n const command = generateEnvScript(\n {\n OPENAI_BASE_URL: `${serverUrl}/v1`,\n OPENAI_API_KEY: \"dummy\",\n },\n `codex -m ${quotedModel}`,\n )\n\n printAndCopyCommand(command, \"Codex CLI\")\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n if (options.proxyEnv) {\n initProxyFromEnv()\n }\n\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.accountType = options.accountType\n if (options.accountType !== \"individual\") {\n consola.info(`Using ${options.accountType} plan GitHub account`)\n }\n\n state.manualApprove = options.manual\n state.rateLimitSeconds = options.rateLimit\n state.rateLimitWait = options.rateLimitWait\n state.showToken = options.showToken\n\n await ensurePaths()\n await cacheVSCodeVersion()\n\n if (options.githubToken) {\n state.githubToken = options.githubToken\n consola.info(\"Using provided GitHub token\")\n } else {\n await setupGitHubToken()\n }\n\n await setupCopilotToken()\n await cacheModels()\n\n consola.info(\n `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n )\n\n const serverUrl = `http://localhost:${options.port}`\n\n if (options.claudeCode) await generateClaudeCodeCommand(serverUrl)\n if (options.codex) await generateCodexCommand(serverUrl)\n\n consola.box(\n `🌐 Usage Viewer: https://animeshkundu.github.io/github-router/dashboard.html?endpoint=${serverUrl}/usage`,\n )\n\n serve({\n fetch: server.fetch as ServerHandler,\n hostname: \"127.0.0.1\",\n port: options.port,\n })\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the github-router server\",\n },\n args: {\n port: {\n alias: \"p\",\n type: \"string\",\n default: \"8787\",\n description: \"Port to listen on\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"individual\",\n description: \"Account type to use (individual, business, enterprise)\",\n },\n manual: {\n type: \"boolean\",\n default: false,\n description: \"Enable manual request approval\",\n },\n \"rate-limit\": {\n alias: \"r\",\n type: \"string\",\n description: \"Rate limit in seconds between requests\",\n },\n wait: {\n alias: \"w\",\n type: \"boolean\",\n default: false,\n description:\n \"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set\",\n },\n \"github-token\": {\n alias: \"g\",\n type: \"string\",\n description:\n \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n },\n \"claude-code\": {\n alias: \"c\",\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Claude Code with Copilot API config\",\n },\n codex: {\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Codex CLI with Copilot API config\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n \"proxy-env\": {\n type: \"boolean\",\n default: false,\n description: \"Initialize proxy from environment variables\",\n },\n },\n run({ args }) {\n const rateLimitRaw = args[\"rate-limit\"]\n let rateLimit: number | undefined\n if (rateLimitRaw !== undefined) {\n rateLimit = Number.parseInt(rateLimitRaw, 10)\n if (Number.isNaN(rateLimit) || rateLimit <= 0) {\n throw new Error(\"Invalid rate limit. Must be a positive integer.\")\n }\n }\n\n const port = Number.parseInt(args.port, 10)\n if (Number.isNaN(port) || port <= 0 || port > 65535) {\n throw new Error(\"Invalid port. Must be between 1 and 65535.\")\n }\n\n const accountType = args[\"account-type\"]\n if (!allowedAccountTypes.has(accountType)) {\n throw new Error(\n \"Invalid account type. Must be individual, business, or enterprise.\",\n )\n }\n\n const rateLimitWait = args.wait && rateLimit !== undefined\n if (args.wait && rateLimit === undefined) {\n consola.warn(\"Rate limit wait ignored because no rate limit was set.\")\n }\n\n const githubToken = args[\"github-token\"] ?? process.env.GH_TOKEN\n\n return runServer({\n port,\n verbose: args.verbose,\n accountType,\n manual: args.manual,\n rateLimit,\n rateLimitWait,\n githubToken,\n claudeCode: args[\"claude-code\"],\n codex: args.codex,\n showToken: args[\"show-token\"],\n proxyEnv: args[\"proxy-env\"],\n })\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from \"citty\"\n\nimport { auth } from \"./auth\"\nimport { checkUsage } from \"./check-usage\"\nimport { debug } from \"./debug\"\nimport { start } from \"./start\"\n\nconst main = defineCommand({\n meta: {\n name: \"github-router\",\n description:\n \"A reverse proxy that exposes GitHub Copilot as OpenAI and Anthropic compatible API endpoints.\",\n },\n subCommands: { auth, start, \"check-usage\": checkUsage, debug },\n})\n\nawait runMain(main)\n"],"mappings":"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"}
1
+ {"version":3,"file":"main.js","names":["state: State","state","headers: Record<string, string>","errorJson: unknown","token","process","commandBlock: string","state","parts: Array<string>","x","headers: Record<string, string>","searchTimestamps: Array<number>","references: Array<{ title: string; url: string }>","handleCompletion","injectWebSearchIfNeeded","inputTokens: number | undefined","isNonStreaming","extractUserQuery","handleCompletion","isWebSearchTool","body: AnyRecord","resolveModelInBody","extraHeaders: Record<string, string>","parsed: AnyRecord","headers: Record<string, string>","extractUserQuery","body: AnyRecord","parsed: AnyRecord","headers: Record<string, string>","rateLimit: number | undefined"],"sources":["../src/lib/paths.ts","../src/lib/state.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/copilot/get-models.ts","../src/services/get-vscode-version.ts","../src/lib/utils.ts","../src/services/github/poll-access-token.ts","../src/lib/token.ts","../src/auth.ts","../src/services/github/get-copilot-usage.ts","../src/check-usage.ts","../src/debug.ts","../src/lib/proxy.ts","../src/lib/shell.ts","../src/lib/approval.ts","../src/lib/rate-limit.ts","../src/lib/request-log.ts","../src/lib/tokenizer.ts","../src/services/copilot/create-chat-completions.ts","../src/services/copilot/web-search.ts","../src/routes/chat-completions/handler.ts","../src/routes/chat-completions/route.ts","../src/services/copilot/create-embeddings.ts","../src/routes/embeddings/route.ts","../src/services/copilot/create-messages.ts","../src/routes/messages/count-tokens-handler.ts","../src/routes/messages/handler.ts","../src/routes/messages/route.ts","../src/routes/models/route.ts","../src/services/copilot/create-responses.ts","../src/routes/responses/handler.ts","../src/routes/responses/route.ts","../src/routes/search/route.ts","../src/routes/token/route.ts","../src/routes/usage/route.ts","../src/server.ts","../src/start.ts","../src/main.ts"],"sourcesContent":["import fs from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\n\nconst APP_DIR = path.join(os.homedir(), \".local\", \"share\", \"github-router\")\n\nconst GITHUB_TOKEN_PATH = path.join(APP_DIR, \"github_token\")\n\nexport const PATHS = {\n APP_DIR,\n GITHUB_TOKEN_PATH,\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n}\n\nasync function ensureFile(filePath: string): Promise<void> {\n try {\n await fs.access(filePath, fs.constants.W_OK)\n } catch {\n await fs.writeFile(filePath, \"\")\n await fs.chmod(filePath, 0o600)\n }\n}\n","import { randomBytes, randomUUID } from \"node:crypto\"\n\nimport type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n accountType: string\n copilotApiUrl?: string\n models?: ModelsResponse\n vsCodeVersion?: string\n\n manualApprove: boolean\n rateLimitWait: boolean\n showToken: boolean\n\n // Rate limiting configuration\n rateLimitSeconds?: number\n lastRequestTimestamp?: number\n\n // Persistent session identifiers to match VS Code fingerprint\n sessionId: string\n machineId: string\n}\n\nexport const state: State = {\n accountType: \"enterprise\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n sessionId: randomUUID(),\n machineId: randomBytes(32).toString(\"hex\"),\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { State } from \"./state\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst COPILOT_VERSION = \"0.38.2026021302\"\nconst EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`\nconst USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`\n\nconst API_VERSION = \"2025-10-01\"\n\nexport const copilotBaseUrl = (state: State) =>\n state.copilotApiUrl ?? \"https://api.githubcopilot.com\"\nexport const copilotHeaders = (\n state: State,\n vision: boolean = false,\n integrationId: string = \"vscode-chat\",\n) => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${state.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": integrationId,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"conversation-panel\",\n \"x-interaction-type\": \"conversation-panel\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": randomUUID(),\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n \"VScode-SessionId\": state.sessionId,\n \"VScode-MachineId\": state.machineId,\n }\n\n if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n return headers\n}\n\nexport const GITHUB_API_BASE_URL = \"https://api.github.com\"\nexport const githubHeaders = (state: State) => ({\n ...standardHeaders(),\n authorization: `token ${state.githubToken}`,\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"x-github-api-version\": API_VERSION,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n})\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nexport class HTTPError extends Error {\n response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.response = response\n }\n}\n\nexport async function forwardError(c: Context, error: unknown) {\n consola.error(\"Error occurred:\", error)\n\n if (error instanceof HTTPError) {\n const errorText = await error.response.text()\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = undefined\n }\n const message = resolveErrorMessage(errorJson, errorText)\n consola.error(\"HTTP error:\", errorJson ?? errorText)\n return c.json(\n {\n error: {\n message,\n type: \"error\",\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n error: {\n message: error instanceof Error ? error.message : String(error),\n type: \"error\",\n },\n },\n 500,\n )\n}\n\n// Extracts error message from { message } or { error: { message } } payloads.\nfunction resolveErrorMessage(errorJson: unknown, fallback: string): string {\n if (typeof errorJson !== \"object\" || errorJson === null) return fallback\n\n const errorRecord = errorJson as Record<string, unknown>\n if (errorRecord.message !== undefined) return String(errorRecord.message)\n\n if (typeof errorRecord.error === \"object\" && errorRecord.error !== null) {\n const nestedRecord = errorRecord.error as Record<string, unknown>\n if (nestedRecord.message !== undefined) return String(nestedRecord.message)\n }\n\n return fallback\n}\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotToken = async () => {\n const response = await fetch(\n `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(state),\n },\n )\n\n if (!response.ok) throw new HTTPError(\"Failed to get Copilot token\", response)\n\n const data = (await response.json()) as GetCopilotTokenResponse\n\n // Use the API base URL from the token response if available,\n // matching how VS Code determines the CAPI endpoint dynamically.\n if (data.endpoints?.api) {\n state.copilotApiUrl = data.endpoints.api\n }\n\n return data\n}\n\ninterface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n endpoints?: {\n api?: string\n proxy?: string\n telemetry?: string\n \"origin-tracker\"?: string\n }\n}\n","import {\n GITHUB_APP_SCOPES,\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\n\nexport async function getDeviceCode(): Promise<DeviceCodeResponse> {\n const response = await fetch(`${GITHUB_BASE_URL}/login/device/code`, {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n scope: GITHUB_APP_SCOPES,\n }),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\n}\n\nexport interface DeviceCodeResponse {\n device_code: string\n user_code: string\n verification_uri: string\n expires_in: number\n interval: number\n}\n","import { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${state.githubToken}`,\n ...standardHeaders(),\n },\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n}\n\n// Trimmed for the sake of simplicity\ninterface GithubUserResponse {\n login: string\n}\n","import { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getModels = async () => {\n const response = await fetch(`${copilotBaseUrl(state)}/models`, {\n headers: copilotHeaders(state),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n return (await response.json()) as ModelsResponse\n}\n\nexport interface ModelsResponse {\n data: Array<Model>\n object: string\n}\n\ninterface ModelLimits {\n max_context_window_tokens?: number\n max_output_tokens?: number\n max_prompt_tokens?: number\n max_inputs?: number\n}\n\ninterface ModelSupports {\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n}\n\ninterface ModelCapabilities {\n family: string\n limits: ModelLimits\n object: string\n supports: ModelSupports\n tokenizer: string\n type: string\n}\n\nexport interface Model {\n capabilities: ModelCapabilities\n id: string\n model_picker_enabled: boolean\n name: string\n object: string\n preview: boolean\n vendor: string\n version: string\n supported_endpoints?: Array<string>\n policy?: {\n state: string\n terms: string\n }\n}\n","const FALLBACK = \"1.104.3\"\n\nexport async function getVSCodeVersion() {\n const controller = new AbortController()\n const timeout = setTimeout(() => {\n controller.abort()\n }, 5000)\n\n try {\n const response = await fetch(\n \"https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin\",\n {\n signal: controller.signal,\n },\n )\n\n const pkgbuild = await response.text()\n const pkgverRegex = /pkgver=([0-9.]+)/\n const match = pkgbuild.match(pkgverRegex)\n\n if (match) {\n return match[1]\n }\n\n return FALLBACK\n } catch {\n return FALLBACK\n } finally {\n clearTimeout(timeout)\n }\n}\n\nawait getVSCodeVersion()\n","import consola from \"consola\"\n\nimport { getModels } from \"~/services/copilot/get-models\"\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined\n\n/**\n * Beta values that VS Code Copilot Chat actually sends to the Copilot API.\n * Only these are forwarded; everything else (e.g. context-1m-*) is stripped\n * so our requests match what VS Code produces.\n */\nconst ALLOWED_BETA_PREFIXES = [\n \"interleaved-thinking-\",\n \"context-management-\",\n \"advanced-tool-use-\",\n \"token-counting-\",\n]\n\n/**\n * Filter an `anthropic-beta` header value, keeping only beta flags that\n * VS Code Copilot is known to send. Returns the filtered comma-separated\n * string, or undefined if nothing remains.\n */\nexport function filterBetaHeader(value: string): string | undefined {\n const filtered = value\n .split(\",\")\n .map((v) => v.trim())\n .filter(\n (v) =>\n v && ALLOWED_BETA_PREFIXES.some((prefix) => v.startsWith(prefix)),\n )\n .join(\",\")\n return filtered || undefined\n}\n\n/**\n * Resolve a model name to the best available variant in the Copilot model list.\n * Prefers the 1M context variant for opus models.\n */\nexport function resolveModel(modelId: string): string {\n const models = state.models?.data\n if (!models) return modelId\n\n // Exact match — no remapping needed\n if (models.some((m) => m.id === modelId)) return modelId\n\n // For opus models, prefer the 1m variant\n if (modelId.toLowerCase().includes(\"opus\")) {\n const oneM = models.find((m) => m.id.includes(\"opus\") && m.id.endsWith(\"-1m\"))\n if (oneM) return oneM.id\n }\n\n return modelId\n}\n\nexport async function cacheModels(): Promise<void> {\n const models = await getModels()\n state.models = models\n}\n\nexport const cacheVSCodeVersion = async () => {\n const response = await getVSCodeVersion()\n state.vsCodeVersion = response\n\n consola.info(`Using VSCode version: ${response}`)\n}\n","import consola from \"consola\"\n\nimport {\n GITHUB_BASE_URL,\n GITHUB_CLIENT_ID,\n standardHeaders,\n} from \"~/lib/api-config\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport async function pollAccessToken(\n deviceCode: DeviceCodeResponse,\n): Promise<string> {\n // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n // I'm also adding another second, just to be safe\n const sleepDuration = (deviceCode.interval + 1) * 1000\n consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n const expiresAt = Date.now() + deviceCode.expires_in * 1000\n\n while (Date.now() < expiresAt) {\n const response = await fetch(\n `${GITHUB_BASE_URL}/login/oauth/access_token`,\n {\n method: \"POST\",\n headers: standardHeaders(),\n body: JSON.stringify({\n client_id: GITHUB_CLIENT_ID,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to poll access token:\", await response.text())\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n continue\n }\n\n const json = await response.json()\n consola.debug(\"Polling access token response:\", json)\n\n const { access_token } = json as AccessTokenResponse\n\n if (access_token) {\n return access_token\n }\n\n if (Date.now() >= expiresAt) break\n await sleep(sleepDuration)\n }\n\n throw new Error(\"Device code expired. Please run auth again.\")\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs/promises\"\n\nimport { PATHS } from \"~/lib/paths\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getDeviceCode } from \"~/services/github/get-device-code\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\nimport { pollAccessToken } from \"~/services/github/poll-access-token\"\n\nimport { HTTPError } from \"./error\"\nimport { state } from \"./state\"\n\nconst readGithubToken = () => fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n\nconst writeGithubToken = (token: string) =>\n fs.writeFile(PATHS.GITHUB_TOKEN_PATH, token)\n\nexport const setupCopilotToken = async () => {\n const { token, refresh_in } = await getCopilotToken()\n state.copilotToken = token\n\n // Display the Copilot token to the screen\n consola.debug(\"GitHub Copilot Token fetched successfully!\")\n if (state.showToken) {\n consola.info(\"Copilot token:\", token)\n }\n\n const refreshInterval = Math.max((refresh_in - 60) * 1000, 1000)\n setInterval(async () => {\n consola.debug(\"Refreshing Copilot token\")\n try {\n const { token } = await getCopilotToken()\n state.copilotToken = token\n consola.debug(\"Copilot token refreshed\")\n if (state.showToken) {\n consola.info(\"Refreshed Copilot token:\", token)\n }\n } catch (error) {\n consola.error(\"Failed to refresh Copilot token:\", error)\n }\n }, refreshInterval)\n}\n\ninterface SetupGitHubTokenOptions {\n force?: boolean\n}\n\nexport async function setupGitHubToken(\n options?: SetupGitHubTokenOptions,\n): Promise<void> {\n try {\n const githubToken = await readGithubToken()\n\n if (githubToken && !options?.force) {\n state.githubToken = githubToken\n if (state.showToken) {\n consola.info(\"GitHub token:\", githubToken)\n }\n await logUser()\n\n return\n }\n\n consola.info(\"Not logged in, getting new access token\")\n const response = await getDeviceCode()\n consola.debug(\"Device code response:\", response)\n\n consola.info(\n `Please enter the code \"${response.user_code}\" in ${response.verification_uri}`,\n )\n\n const token = await pollAccessToken(response)\n await writeGithubToken(token)\n state.githubToken = token\n\n if (state.showToken) {\n consola.info(\"GitHub token:\", token)\n }\n await logUser()\n } catch (error) {\n if (error instanceof HTTPError) {\n consola.error(\"Failed to get GitHub token:\", await error.response.json())\n throw error\n }\n\n consola.error(\"Failed to get GitHub token:\", error)\n throw error\n }\n}\n\nasync function logUser() {\n const user = await getGitHubUser()\n consola.info(`Logged in as ${user.login}`)\n}\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n verbose: boolean\n showToken: boolean\n}\n\nexport async function runAuth(options: RunAuthOptions): Promise<void> {\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n}\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub auth flow without running the server\",\n },\n args: {\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub token on auth\",\n },\n },\n run({ args }) {\n return runAuth({\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n","import { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (): Promise<CopilotUsageResponse> => {\n const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, {\n headers: githubHeaders(state),\n })\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot usage\", response)\n }\n\n return (await response.json()) as CopilotUsageResponse\n}\n\nexport interface QuotaDetail {\n entitlement: number\n overage_count: number\n overage_permitted: boolean\n percent_remaining: number\n quota_id: string\n quota_remaining: number\n remaining: number\n unlimited: boolean\n}\n\ninterface QuotaSnapshots {\n chat: QuotaDetail\n completions: QuotaDetail\n premium_interactions: QuotaDetail\n}\n\ninterface CopilotUsageResponse {\n access_type_sku: string\n analytics_tracking_id: string\n assigned_date: string\n can_signup_for_limited: boolean\n chat_enabled: boolean\n copilot_plan: string\n organization_login_list: Array<unknown>\n organization_list: Array<unknown>\n quota_reset_date: string\n quota_snapshots: QuotaSnapshots\n}\n","import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupGitHubToken } from \"./lib/token\"\nimport {\n getCopilotUsage,\n type QuotaDetail,\n} from \"./services/github/get-copilot-usage\"\n\nexport const checkUsage = defineCommand({\n meta: {\n name: \"check-usage\",\n description: \"Show current GitHub Copilot usage/quota information\",\n },\n async run() {\n await ensurePaths()\n await setupGitHubToken()\n try {\n const usage = await getCopilotUsage()\n const premium = usage.quota_snapshots.premium_interactions\n const premiumTotal = premium.entitlement\n const premiumUsed = premiumTotal - premium.remaining\n const premiumPercentUsed =\n premiumTotal > 0 ? (premiumUsed / premiumTotal) * 100 : 0\n const premiumPercentRemaining = premium.percent_remaining\n\n // Helper to summarize a quota snapshot\n function summarizeQuota(name: string, snap: QuotaDetail | undefined) {\n if (!snap) return `${name}: N/A`\n const total = snap.entitlement\n const used = total - snap.remaining\n const percentUsed = total > 0 ? (used / total) * 100 : 0\n const percentRemaining = snap.percent_remaining\n return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`\n }\n\n const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`\n const chatLine = summarizeQuota(\"Chat\", usage.quota_snapshots.chat)\n const completionsLine = summarizeQuota(\n \"Completions\",\n usage.quota_snapshots.completions,\n )\n\n consola.box(\n `Copilot Usage (plan: ${usage.copilot_plan})\\n`\n + `Quota resets: ${usage.quota_reset_date}\\n`\n + `\\nQuotas:\\n`\n + ` ${premiumLine}\\n`\n + ` ${chatLine}\\n`\n + ` ${completionsLine}`,\n )\n } catch (err) {\n consola.error(\"Failed to fetch Copilot usage:\", err)\n process.exit(1)\n }\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\nimport fs from \"node:fs/promises\"\nimport os from \"node:os\"\n\nimport { PATHS } from \"./lib/paths\"\n\ninterface DebugInfo {\n version: string\n runtime: {\n name: string\n version: string\n platform: string\n arch: string\n }\n paths: {\n APP_DIR: string\n GITHUB_TOKEN_PATH: string\n }\n tokenExists: boolean\n}\n\ninterface RunDebugOptions {\n json: boolean\n}\n\nasync function getPackageVersion(): Promise<string> {\n try {\n const packageJsonPath = new URL(\"../package.json\", import.meta.url).pathname\n // @ts-expect-error https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v59.0.1/docs/rules/prefer-json-parse-buffer.md\n // JSON.parse() can actually parse buffers\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath)) as {\n version: string\n }\n return packageJson.version\n } catch {\n return \"unknown\"\n }\n}\n\nfunction getRuntimeInfo() {\n const isBun = typeof Bun !== \"undefined\"\n\n return {\n name: isBun ? \"bun\" : \"node\",\n version: isBun ? Bun.version : process.version.slice(1),\n platform: os.platform(),\n arch: os.arch(),\n }\n}\n\nasync function checkTokenExists(): Promise<boolean> {\n try {\n const stats = await fs.stat(PATHS.GITHUB_TOKEN_PATH)\n if (!stats.isFile()) return false\n\n const content = await fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n return content.trim().length > 0\n } catch {\n return false\n }\n}\n\nasync function getDebugInfo(): Promise<DebugInfo> {\n const [version, tokenExists] = await Promise.all([\n getPackageVersion(),\n checkTokenExists(),\n ])\n\n return {\n version,\n runtime: getRuntimeInfo(),\n paths: {\n APP_DIR: PATHS.APP_DIR,\n GITHUB_TOKEN_PATH: PATHS.GITHUB_TOKEN_PATH,\n },\n tokenExists,\n }\n}\n\nfunction printDebugInfoPlain(info: DebugInfo): void {\n consola.info(`github-router debug\n\nVersion: ${info.version}\nRuntime: ${info.runtime.name} ${info.runtime.version} (${info.runtime.platform} ${info.runtime.arch})\n\nPaths:\n- APP_DIR: ${info.paths.APP_DIR}\n- GITHUB_TOKEN_PATH: ${info.paths.GITHUB_TOKEN_PATH}\n\nToken exists: ${info.tokenExists ? \"Yes\" : \"No\"}`)\n}\n\nfunction printDebugInfoJson(info: DebugInfo): void {\n console.log(JSON.stringify(info, null, 2))\n}\n\nexport async function runDebug(options: RunDebugOptions): Promise<void> {\n const debugInfo = await getDebugInfo()\n\n if (options.json) {\n printDebugInfoJson(debugInfo)\n } else {\n printDebugInfoPlain(debugInfo)\n }\n}\n\nexport const debug = defineCommand({\n meta: {\n name: \"debug\",\n description: \"Print debug information about the application\",\n },\n args: {\n json: {\n type: \"boolean\",\n default: false,\n description: \"Output debug information as JSON\",\n },\n },\n run({ args }) {\n return runDebug({\n json: args.json,\n })\n },\n})\n","import consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nexport function initProxyFromEnv(): void {\n if (typeof Bun !== \"undefined\") return\n\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return (agent as unknown as Dispatcher).dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n setGlobalDispatcher(dispatcher as unknown as Dispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\n }\n}\n","import process from \"node:process\"\n\ntype ShellName = \"bash\" | \"zsh\" | \"fish\" | \"powershell\" | \"cmd\" | \"sh\"\ntype EnvVars = Record<string, string | undefined>\n\nfunction getShell(): ShellName {\n const { platform, env } = process\n\n if (platform === \"win32\") {\n // Git Bash / MSYS2 / Cygwin set SHELL even on Windows\n if (env.SHELL) {\n if (env.SHELL.endsWith(\"zsh\")) return \"zsh\"\n if (env.SHELL.endsWith(\"fish\")) return \"fish\"\n if (env.SHELL.endsWith(\"bash\")) return \"bash\"\n return \"sh\"\n }\n\n // Windows PowerShell 5.x sets this\n if (env.POWERSHELL_DISTRIBUTION_CHANNEL) return \"powershell\"\n\n // PowerShell (both 5.x and 7+/pwsh) adds user-scoped module paths\n // at runtime. The system-level PSModulePath in CMD lacks these paths.\n if (env.PSModulePath) {\n const lower = env.PSModulePath.toLowerCase()\n if (\n lower.includes(\"documents\\\\powershell\")\n || lower.includes(\"documents\\\\windowspowershell\")\n ) {\n return \"powershell\"\n }\n }\n\n return \"cmd\"\n }\n\n const shellPath = env.SHELL\n if (shellPath) {\n if (shellPath.endsWith(\"zsh\")) return \"zsh\"\n if (shellPath.endsWith(\"fish\")) return \"fish\"\n if (shellPath.endsWith(\"bash\")) return \"bash\"\n }\n\n return \"sh\"\n}\n\nfunction quotePosixValue(value: string): string {\n return `'${value.replace(/'/g, \"'\\\\''\")}'`\n}\n\nfunction quotePowerShellValue(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`\n}\n\n/**\n * Generates a copy-pasteable script to set multiple environment variables\n * and run a subsequent command.\n * @param {EnvVars} envVars - An object of environment variables to set.\n * @param {string} commandToRun - The command to run after setting the variables.\n * @returns {string} The formatted script string.\n */\nexport function generateEnvScript(\n envVars: EnvVars,\n commandToRun: string = \"\",\n): string {\n const shell = getShell()\n const filteredEnvVars = Object.entries(envVars).filter(\n ([, value]) => value !== undefined,\n ) as Array<[string, string]>\n\n let commandBlock: string\n\n switch (shell) {\n case \"powershell\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `$env:${key} = ${quotePowerShellValue(value)}`)\n .join(\"; \")\n break\n }\n case \"cmd\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set \"${key}=${value}\"`)\n .join(\" & \")\n break\n }\n case \"fish\": {\n commandBlock = filteredEnvVars\n .map(([key, value]) => `set -gx ${key} ${quotePosixValue(value)}`)\n .join(\"; \")\n break\n }\n default: {\n // bash, zsh, sh\n const assignments = filteredEnvVars\n .map(([key, value]) => `${key}=${quotePosixValue(value)}`)\n .join(\" \")\n commandBlock = filteredEnvVars.length > 0 ? `export ${assignments}` : \"\"\n break\n }\n }\n\n if (commandBlock && commandToRun) {\n const separator =\n shell === \"cmd\" ? \" & \" : shell === \"powershell\" ? \"; \" : \" && \"\n return `${commandBlock}${separator}${commandToRun}`\n }\n\n return commandBlock || commandToRun\n}\n","import consola from \"consola\"\n\nimport { HTTPError } from \"./error\"\n\nexport const awaitApproval = async () => {\n const response = await consola.prompt(`Accept incoming request?`, {\n type: \"confirm\",\n })\n\n if (!response)\n throw new HTTPError(\n \"Request rejected by user\",\n Response.json({ message: \"Request rejected by user\" }, { status: 403 }),\n )\n}\n","import consola from \"consola\"\n\nimport type { State } from \"./state\"\n\nimport { HTTPError } from \"./error\"\nimport { sleep } from \"./utils\"\n\nexport async function checkRateLimit(state: State) {\n if (state.rateLimitSeconds === undefined) return\n\n const now = Date.now()\n\n if (!state.lastRequestTimestamp) {\n state.lastRequestTimestamp = now\n return\n }\n\n const elapsedSeconds = (now - state.lastRequestTimestamp) / 1000\n\n if (elapsedSeconds > state.rateLimitSeconds) {\n state.lastRequestTimestamp = now\n return\n }\n\n const waitTimeSeconds = Math.ceil(state.rateLimitSeconds - elapsedSeconds)\n\n if (!state.rateLimitWait) {\n consola.warn(\n `Rate limit exceeded. Need to wait ${waitTimeSeconds} more seconds.`,\n )\n throw new HTTPError(\n \"Rate limit exceeded\",\n Response.json({ message: \"Rate limit exceeded\" }, { status: 429 }),\n )\n }\n\n const waitTimeMs = waitTimeSeconds * 1000\n consola.warn(\n `Rate limit reached. Waiting ${waitTimeSeconds} seconds before proceeding...`,\n )\n await sleep(waitTimeMs)\n state.lastRequestTimestamp = Date.now()\n consola.info(\"Rate limit wait completed, proceeding with request\")\n return\n}\n","import consola from \"consola\"\n\nimport type { Model } from \"~/services/copilot/get-models\"\n\nexport interface RequestLogInfo {\n method: string\n path: string\n model?: string\n resolvedModel?: string\n inputTokens?: number\n outputTokens?: number\n status?: number\n streaming?: boolean\n}\n\n/**\n * Format a number with K/M suffix for compact display.\n */\nfunction formatTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`\n return String(n)\n}\n\n/**\n * Build a context window summary: \"in:1.2K out:50 ctx:1.2K/1M (0.1%)\"\n */\nfunction formatTokenInfo(\n inputTokens: number | undefined,\n outputTokens: number | undefined,\n model: Model | undefined,\n): string | undefined {\n if (inputTokens === undefined) return undefined\n\n const parts: Array<string> = []\n const maxPrompt = model?.capabilities.limits.max_prompt_tokens\n\n if (maxPrompt) {\n const pct = ((inputTokens / maxPrompt) * 100).toFixed(1)\n parts.push(`in:${formatTokens(inputTokens)}/${formatTokens(maxPrompt)} (${pct}%)`)\n } else {\n parts.push(`in:${formatTokens(inputTokens)}`)\n }\n\n if (outputTokens !== undefined) {\n parts.push(`out:${formatTokens(outputTokens)}`)\n }\n\n return parts.join(\" \")\n}\n\n/**\n * Print a single summary line for a completed request.\n *\n * Examples:\n * POST /v1/messages claude-opus-4.6-1m in:1.2K/1M (0.1%) out:50 200 2.3s\n * POST /v1/messages claude-opus-4-6→claude-opus-4.6-1m in:743/1M (0.1%) 200 198ms\n * POST /v1/chat/completions claude-sonnet-4 in:15 out:16 200 2.1s stream\n */\nexport function logRequest(\n info: RequestLogInfo,\n model: Model | undefined,\n startTime: number,\n): void {\n const parts: Array<string> = []\n\n parts.push(`${info.method} ${info.path}`)\n\n // Model (show resolution arrow if remapped)\n if (info.resolvedModel && info.resolvedModel !== info.model) {\n parts.push(`${info.model}→${info.resolvedModel}`)\n } else if (info.resolvedModel ?? info.model) {\n parts.push((info.resolvedModel ?? info.model)!)\n }\n\n // Token info with context window fill\n const tokenInfo = formatTokenInfo(info.inputTokens, info.outputTokens, model)\n if (tokenInfo) {\n parts.push(tokenInfo)\n }\n\n // Status\n if (info.status !== undefined) {\n parts.push(String(info.status))\n }\n\n // Duration + streaming flag\n const elapsed = Date.now() - startTime\n const duration =\n elapsed >= 1000 ? `${(elapsed / 1000).toFixed(1)}s` : `${elapsed}ms`\n parts.push(info.streaming ? `${duration} stream` : duration)\n\n consola.info(parts.join(\" \"))\n}\n","import type {\n ChatCompletionsPayload,\n ContentPart,\n Message,\n Tool,\n ToolCall,\n} from \"~/services/copilot/create-chat-completions\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\n// Encoder type mapping\nconst ENCODING_MAP = {\n o200k_base: () => import(\"gpt-tokenizer/encoding/o200k_base\"),\n cl100k_base: () => import(\"gpt-tokenizer/encoding/cl100k_base\"),\n p50k_base: () => import(\"gpt-tokenizer/encoding/p50k_base\"),\n p50k_edit: () => import(\"gpt-tokenizer/encoding/p50k_edit\"),\n r50k_base: () => import(\"gpt-tokenizer/encoding/r50k_base\"),\n} as const\n\ntype SupportedEncoding = keyof typeof ENCODING_MAP\n\n// Define encoder interface\ninterface Encoder {\n encode: (text: string) => Array<number>\n}\n\n// Cache loaded encoders to avoid repeated imports\nconst encodingCache = new Map<string, Encoder>()\n\n/**\n * Calculate tokens for tool calls\n */\nconst calculateToolCallsTokens = (\n toolCalls: Array<ToolCall>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = 0\n for (const toolCall of toolCalls) {\n tokens += constants.funcInit\n tokens += encoder.encode(JSON.stringify(toolCall)).length\n }\n tokens += constants.funcEnd\n return tokens\n}\n\n/**\n * Calculate tokens for content parts\n */\nconst calculateContentPartsTokens = (\n contentParts: Array<ContentPart>,\n encoder: Encoder,\n): number => {\n let tokens = 0\n for (const part of contentParts) {\n if (part.type === \"image_url\") {\n tokens += encoder.encode(part.image_url.url).length + 85\n } else if (part.text) {\n tokens += encoder.encode(part.text).length\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens for a single message\n */\nconst calculateMessageTokens = (\n message: Message,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n const tokensPerMessage = 3\n const tokensPerName = 1\n let tokens = tokensPerMessage\n for (const [key, value] of Object.entries(message)) {\n if (typeof value === \"string\") {\n tokens += encoder.encode(value).length\n }\n if (key === \"name\") {\n tokens += tokensPerName\n }\n if (key === \"tool_calls\") {\n tokens += calculateToolCallsTokens(\n value as Array<ToolCall>,\n encoder,\n constants,\n )\n }\n if (key === \"content\" && Array.isArray(value)) {\n tokens += calculateContentPartsTokens(\n value as Array<ContentPart>,\n encoder,\n )\n }\n }\n return tokens\n}\n\n/**\n * Calculate tokens using custom algorithm\n */\nconst calculateTokens = (\n messages: Array<Message>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (messages.length === 0) {\n return 0\n }\n let numTokens = 0\n for (const message of messages) {\n numTokens += calculateMessageTokens(message, encoder, constants)\n }\n // every reply is primed with <|start|>assistant<|message|>\n numTokens += 3\n return numTokens\n}\n\n/**\n * Get the corresponding encoder module based on encoding type\n */\nconst getEncodeChatFunction = async (encoding: string): Promise<Encoder> => {\n if (encodingCache.has(encoding)) {\n const cached = encodingCache.get(encoding)\n if (cached) {\n return cached\n }\n }\n\n const supportedEncoding = encoding as SupportedEncoding\n if (!(supportedEncoding in ENCODING_MAP)) {\n const fallbackModule = (await ENCODING_MAP.o200k_base()) as Encoder\n encodingCache.set(encoding, fallbackModule)\n return fallbackModule\n }\n\n const encodingModule = (await ENCODING_MAP[supportedEncoding]()) as Encoder\n encodingCache.set(encoding, encodingModule)\n return encodingModule\n}\n\n/**\n * Get tokenizer type from model information\n */\nexport const getTokenizerFromModel = (model: Model): string => {\n return model.capabilities.tokenizer || \"o200k_base\"\n}\n\n/**\n * Get model-specific constants for token calculation\n */\nconst getModelConstants = (model: Model) => {\n return model.id === \"gpt-3.5-turbo\" || model.id === \"gpt-4\" ?\n {\n funcInit: 10,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n : {\n funcInit: 7,\n propInit: 3,\n propKey: 3,\n enumInit: -3,\n enumItem: 3,\n funcEnd: 12,\n }\n}\n\n/**\n * Calculate tokens for a single parameter\n */\nconst calculateParameterTokens = (\n key: string,\n prop: unknown,\n context: {\n encoder: Encoder\n constants: ReturnType<typeof getModelConstants>\n },\n): number => {\n const { encoder, constants } = context\n let tokens = constants.propKey\n\n // Early return if prop is not an object\n if (typeof prop !== \"object\" || prop === null) {\n return tokens\n }\n\n // Type assertion for parameter properties\n const param = prop as {\n type?: string\n description?: string\n enum?: Array<unknown>\n [key: string]: unknown\n }\n\n const paramName = key\n const paramType = param.type || \"string\"\n let paramDesc = param.description || \"\"\n\n // Handle enum values\n if (param.enum && Array.isArray(param.enum)) {\n tokens += constants.enumInit\n for (const item of param.enum) {\n tokens += constants.enumItem\n tokens += encoder.encode(String(item)).length\n }\n }\n\n // Clean up description\n if (paramDesc.endsWith(\".\")) {\n paramDesc = paramDesc.slice(0, -1)\n }\n\n // Encode the main parameter line\n const line = `${paramName}:${paramType}:${paramDesc}`\n tokens += encoder.encode(line).length\n\n // Handle additional properties (excluding standard ones)\n const excludedKeys = new Set([\"type\", \"description\", \"enum\"])\n for (const propertyName of Object.keys(param)) {\n if (!excludedKeys.has(propertyName)) {\n const propertyValue = param[propertyName]\n const propertyText =\n typeof propertyValue === \"string\" ? propertyValue : (\n JSON.stringify(propertyValue)\n )\n tokens += encoder.encode(`${propertyName}:${propertyText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for function parameters\n */\nconst calculateParametersTokens = (\n parameters: unknown,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n if (!parameters || typeof parameters !== \"object\") {\n return 0\n }\n\n const params = parameters as Record<string, unknown>\n let tokens = 0\n\n for (const [key, value] of Object.entries(params)) {\n if (key === \"properties\") {\n const properties = value as Record<string, unknown>\n if (Object.keys(properties).length > 0) {\n tokens += constants.propInit\n for (const propKey of Object.keys(properties)) {\n tokens += calculateParameterTokens(propKey, properties[propKey], {\n encoder,\n constants,\n })\n }\n }\n } else {\n const paramText =\n typeof value === \"string\" ? value : JSON.stringify(value)\n tokens += encoder.encode(`${key}:${paramText}`).length\n }\n }\n\n return tokens\n}\n\n/**\n * Calculate tokens for a single tool\n */\nconst calculateToolTokens = (\n tool: Tool,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let tokens = constants.funcInit\n const func = tool.function\n const fName = func.name\n let fDesc = func.description || \"\"\n if (fDesc.endsWith(\".\")) {\n fDesc = fDesc.slice(0, -1)\n }\n const line = fName + \":\" + fDesc\n tokens += encoder.encode(line).length\n if (\n typeof func.parameters === \"object\" \n && func.parameters !== null\n ) {\n tokens += calculateParametersTokens(func.parameters, encoder, constants)\n }\n return tokens\n}\n\n/**\n * Calculate token count for tools based on model\n */\nexport const numTokensForTools = (\n tools: Array<Tool>,\n encoder: Encoder,\n constants: ReturnType<typeof getModelConstants>,\n): number => {\n let funcTokenCount = 0\n for (const tool of tools) {\n funcTokenCount += calculateToolTokens(tool, encoder, constants)\n }\n funcTokenCount += constants.funcEnd\n return funcTokenCount\n}\n\n/**\n * Calculate the token count of messages, supporting multiple GPT encoders\n */\nexport const getTokenCount = async (\n payload: ChatCompletionsPayload,\n model: Model,\n): Promise<{ input: number; output: number }> => {\n // Get tokenizer string\n const tokenizer = getTokenizerFromModel(model)\n\n // Get corresponding encoder module\n const encoder = await getEncodeChatFunction(tokenizer)\n\n const simplifiedMessages = payload.messages\n const inputMessages = simplifiedMessages.filter(\n (msg) => msg.role !== \"assistant\",\n )\n const outputMessages = simplifiedMessages.filter(\n (msg) => msg.role === \"assistant\",\n )\n\n const constants = getModelConstants(model)\n let inputTokens = calculateTokens(inputMessages, encoder, constants)\n if (payload.tools && payload.tools.length > 0) {\n inputTokens += numTokensForTools(payload.tools, encoder, constants)\n }\n const outputTokens = calculateTokens(outputMessages, encoder, constants)\n\n return {\n input: inputTokens,\n output: outputTokens,\n }\n}\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createChatCompletions = async (\n payload: ChatCompletionsPayload,\n) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = payload.messages.some(\n (x) =>\n typeof x.content !== \"string\"\n && x.content?.some((x) => x.type === \"image_url\"),\n )\n\n // Agent/user check for X-Initiator header\n // Determine if any message is from an agent (\"assistant\" or \"tool\")\n const isAgentCall = payload.messages.some((msg) =>\n [\"assistant\", \"tool\"].includes(msg.role),\n )\n\n // Build headers and add X-Initiator\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n \"Openai-Organization\": \"github-copilot\",\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n const claudeModels = state.models?.data\n .filter((m) => m.id.startsWith(\"claude\"))\n .map((m) => m.id)\n .join(\", \") ?? \"(models not loaded)\"\n consola.error(\n `Copilot rejected model \"${payload.model}\": ${response.status} ${errorBody} (available Claude models: ${claudeModels})`,\n )\n // Re-create the response so downstream error handlers can still read the body\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Failed to create chat completions\", reconstructed)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ChatCompletionResponse\n}\n\n// Streaming types\n\nexport interface ChatCompletionChunk {\n id: string\n object: \"chat.completion.chunk\"\n created: number\n model: string\n choices: Array<Choice>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n completion_tokens_details?: {\n accepted_prediction_tokens: number\n rejected_prediction_tokens: number\n }\n }\n}\n\ninterface Delta {\n content?: string | null\n role?: \"user\" | \"assistant\" | \"system\" | \"tool\"\n tool_calls?: Array<{\n index: number\n id?: string\n type?: \"function\"\n function?: {\n name?: string\n arguments?: string\n }\n }>\n}\n\ninterface Choice {\n index: number\n delta: Delta\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\" | null\n logprobs: object | null\n}\n\n// Non-streaming types\n\nexport interface ChatCompletionResponse {\n id: string\n object: \"chat.completion\"\n created: number\n model: string\n choices: Array<ChoiceNonStreaming>\n system_fingerprint?: string\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n prompt_tokens_details?: {\n cached_tokens: number\n }\n }\n}\n\ninterface ResponseMessage {\n role: \"assistant\"\n content: string | null\n tool_calls?: Array<ToolCall>\n}\n\ninterface ChoiceNonStreaming {\n index: number\n message: ResponseMessage\n logprobs: object | null\n finish_reason: \"stop\" | \"length\" | \"tool_calls\" | \"content_filter\"\n}\n\n// Payload types\n\nexport interface ChatCompletionsPayload {\n messages: Array<Message>\n model: string\n temperature?: number | null\n top_p?: number | null\n max_tokens?: number | null\n stop?: string | Array<string> | null\n n?: number | null\n stream?: boolean | null\n\n frequency_penalty?: number | null\n presence_penalty?: number | null\n logit_bias?: Record<string, number> | null\n logprobs?: boolean | null\n response_format?: { type: \"json_object\" } | null\n seed?: number | null\n tools?: Array<Tool> | null\n tool_choice?:\n | \"none\"\n | \"auto\"\n | \"required\"\n | { type: \"function\"; function: { name: string } }\n | null\n user?: string | null\n}\n\nexport interface Tool {\n type: \"function\"\n function: {\n name: string\n description?: string\n parameters: Record<string, unknown>\n }\n}\n\nexport interface Message {\n role: \"user\" | \"assistant\" | \"system\" | \"tool\" | \"developer\"\n content: string | Array<ContentPart> | null\n\n name?: string\n tool_calls?: Array<ToolCall>\n tool_call_id?: string\n}\n\nexport interface ToolCall {\n id: string\n type: \"function\"\n function: {\n name: string\n arguments: string\n }\n}\n\nexport type ContentPart = TextPart | ImagePart\n\nexport interface TextPart {\n type: \"text\"\n text: string\n}\n\nexport interface ImagePart {\n type: \"image_url\"\n image_url: {\n url: string\n detail?: \"low\" | \"high\" | \"auto\"\n }\n}\n","import consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { state } from \"~/lib/state\"\nimport { sleep } from \"~/lib/utils\"\n\nexport interface WebSearchResult {\n content: string\n references: Array<{ title: string; url: string }>\n}\n\ninterface ThreadsResponse {\n thread_id: string\n}\n\ninterface ThreadsMessageResponse {\n message: {\n content: string\n references: Array<{\n query?: string\n results?: Array<{\n title: string\n url: string\n reference_type: string\n }>\n }>\n }\n}\n\nconst MAX_SEARCHES_PER_SECOND = 3\nlet searchTimestamps: Array<number> = []\n\nasync function throttleSearch(): Promise<void> {\n const now = Date.now()\n searchTimestamps = searchTimestamps.filter((t) => now - t < 1000)\n if (searchTimestamps.length >= MAX_SEARCHES_PER_SECOND) {\n const waitMs = 1000 - (now - searchTimestamps[0])\n if (waitMs > 0) {\n consola.debug(`Web search rate limited, waiting ${waitMs}ms`)\n await sleep(waitMs)\n }\n }\n searchTimestamps.push(Date.now())\n}\n\nfunction threadsHeaders(): Record<string, string> {\n return copilotHeaders(state, false, \"copilot-chat\")\n}\n\nasync function createThread(): Promise<string> {\n const response = await fetch(`${copilotBaseUrl(state)}/github/chat/threads`, {\n method: \"POST\",\n headers: threadsHeaders(),\n body: JSON.stringify({}),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create chat thread\", response.status)\n throw new Error(`Failed to create chat thread: ${response.status}`)\n }\n\n const data = (await response.json()) as ThreadsResponse\n return data.thread_id\n}\n\nasync function sendThreadMessage(\n threadId: string,\n query: string,\n): Promise<ThreadsMessageResponse> {\n const response = await fetch(\n `${copilotBaseUrl(state)}/github/chat/threads/${threadId}/messages`,\n {\n method: \"POST\",\n headers: threadsHeaders(),\n body: JSON.stringify({\n content: query,\n intent: \"conversation\",\n skills: [\"web-search\"],\n references: [],\n }),\n },\n )\n\n if (!response.ok) {\n consola.error(\"Failed to send thread message\", response.status)\n throw new Error(`Failed to send thread message: ${response.status}`)\n }\n\n return (await response.json()) as ThreadsMessageResponse\n}\n\nexport async function searchWeb(query: string): Promise<WebSearchResult> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n await throttleSearch()\n\n consola.info(`Web search: \"${query.slice(0, 80)}\"`)\n\n const threadId = await createThread()\n const response = await sendThreadMessage(threadId, query)\n\n const references: Array<{ title: string; url: string }> = []\n for (const ref of response.message.references ?? []) {\n if (ref.results) {\n for (const result of ref.results) {\n if (result.url && result.reference_type !== \"bing_search\") {\n references.push({ title: result.title, url: result.url })\n }\n }\n }\n }\n\n consola.debug(`Web search returned ${references.length} references`)\n\n return {\n content: response.message.content,\n references,\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE, type SSEMessage } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { state } from \"~/lib/state\"\nimport { getTokenCount } from \"~/lib/tokenizer\"\nimport { isNullish, resolveModel } from \"~/lib/utils\"\nimport {\n createChatCompletions,\n type ChatCompletionResponse,\n type ChatCompletionsPayload,\n type Message,\n} from \"~/services/copilot/create-chat-completions\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleCompletion(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n let payload = await c.req.json<ChatCompletionsPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Request payload:\", JSON.stringify(payload).slice(-400))\n }\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n // Resolve model name (e.g. opus → opus-1m variant)\n const originalModel = payload.model\n const resolvedModel = resolveModel(payload.model)\n if (resolvedModel !== payload.model) {\n payload.model = resolvedModel\n }\n\n // Find the selected model\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n // Calculate token count\n let inputTokens: number | undefined\n try {\n if (selectedModel) {\n const tokenCount = await getTokenCount(payload, selectedModel)\n inputTokens = tokenCount.input\n }\n } catch {\n // Token counting is best-effort\n }\n\n if (isNullish(payload.max_tokens)) {\n payload = {\n ...payload,\n max_tokens: selectedModel?.capabilities.limits.max_output_tokens,\n }\n if (debugEnabled) {\n consola.debug(\"Set max_tokens to:\", JSON.stringify(payload.max_tokens))\n }\n }\n\n const response = await createChatCompletions(payload)\n const isStreaming = !isNonStreaming(response)\n\n // Extract output tokens from non-streaming response (no extra call)\n const outputTokens = !isStreaming\n ? (response as ChatCompletionResponse).usage?.completion_tokens\n : undefined\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens,\n outputTokens,\n status: 200,\n streaming: isStreaming,\n },\n selectedModel,\n startTime,\n )\n\n if (!isStreaming) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n await stream.writeSSE(chunk as SSEMessage)\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createChatCompletions>>,\n): response is ChatCompletionResponse => Object.hasOwn(response, \"choices\")\n\nasync function injectWebSearchIfNeeded(\n payload: ChatCompletionsPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some(\n (t) =>\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\",\n )\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = payload.messages.some((msg) => msg.role === \"tool\")\n const query = hasToolResult ? undefined : extractUserQuery(payload.messages)\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n // Prepend to existing system message or inject a new one\n const systemMsg = payload.messages.find((msg) => msg.role === \"system\")\n if (systemMsg) {\n const existingContent =\n typeof systemMsg.content === \"string\" ? systemMsg.content\n : Array.isArray(systemMsg.content) ?\n systemMsg.content\n .filter((p) => p.type === \"text\")\n .map((p) => (\"text\" in p ? p.text : \"\"))\n .join(\"\\n\")\n : \"\"\n systemMsg.content = `${searchContext}\\n\\n${existingContent}`\n } else {\n payload.messages.unshift({\n role: \"system\",\n content: searchContext,\n })\n }\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Remove web_search from tools before forwarding\n payload.tools = payload.tools?.filter(\n (t) =>\n !(\n (\"type\" in t && (t as unknown as Record<string, unknown>).type === \"web_search\")\n || t.function?.name === \"web_search\"\n ),\n ) as typeof payload.tools\n if (payload.tools?.length === 0) {\n payload.tools = undefined\n }\n if (!payload.tools) {\n payload.tool_choice = undefined\n } else if (\n payload.tool_choice\n && typeof payload.tool_choice === \"object\"\n && \"type\" in payload.tool_choice\n && payload.tool_choice.type === \"function\"\n ) {\n const toolChoiceName = payload.tool_choice.function?.name\n if (\n toolChoiceName\n && !payload.tools.some((tool) => tool.function.name === toolChoiceName)\n ) {\n payload.tool_choice = undefined\n }\n }\n}\n\nfunction extractUserQuery(messages: Array<Message>): string | undefined {\n // Find the last user message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const text = msg.content.find((p) => p.type === \"text\")\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCompletion } from \"./handler\"\n\nexport const completionRoutes = new Hono()\n\ncompletionRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createEmbeddings = async (payload: EmbeddingRequest) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const response = await fetch(`${copilotBaseUrl(state)}/embeddings`, {\n method: \"POST\",\n headers: copilotHeaders(state),\n body: JSON.stringify(payload),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to create embeddings\", response)\n\n return (await response.json()) as EmbeddingResponse\n}\n\nexport interface EmbeddingRequest {\n input: string | Array<string>\n model: string\n}\n\nexport interface Embedding {\n object: string\n embedding: Array<number>\n index: number\n}\n\nexport interface EmbeddingResponse {\n object: string\n data: Array<Embedding>\n model: string\n usage: {\n prompt_tokens: number\n total_tokens: number\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport {\n createEmbeddings,\n type EmbeddingRequest,\n} from \"~/services/copilot/create-embeddings\"\n\nexport const embeddingRoutes = new Hono()\n\nembeddingRoutes.post(\"/\", async (c) => {\n try {\n const payload = await c.req.json<EmbeddingRequest>()\n const response = await createEmbeddings(payload)\n\n return c.json(response)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { randomUUID } from \"node:crypto\"\n\nimport consola from \"consola\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\n/**\n * Build headers that match what VS Code Copilot Chat sends to the Copilot API.\n *\n * copilotHeaders() provides: Authorization, content-type, copilot-integration-id,\n * editor-version, editor-plugin-version, user-agent, openai-intent,\n * x-github-api-version, x-request-id, x-vscode-user-agent-library-version.\n *\n * We add the remaining headers VS Code sends for /v1/messages:\n * - X-Initiator (VS Code sets dynamically; \"agent\" is safe for CLI use)\n * - anthropic-version (VS Code's Anthropic SDK sends this)\n * - X-Interaction-Id (VS Code sends a session-scoped UUID)\n *\n * We intentionally omit copilot-vision-request — VS Code only sends it when\n * images are present, and the native /v1/messages endpoint handles vision\n * without requiring the header.\n *\n * extraHeaders allows callers to forward client-supplied beta headers\n * (anthropic-beta) so Copilot enables extended features.\n */\nfunction buildHeaders(\n extraHeaders?: Record<string, string>,\n): Record<string, string> {\n return {\n ...copilotHeaders(state),\n accept: \"application/json\",\n \"X-Initiator\": \"agent\",\n \"anthropic-version\": \"2023-06-01\",\n \"X-Interaction-Id\": randomUUID(),\n ...extraHeaders,\n }\n}\n\n/**\n * Forward an Anthropic Messages API request to Copilot's native /v1/messages endpoint.\n * Returns the raw Response so callers can handle streaming vs non-streaming.\n */\nexport async function createMessages(\n body: string,\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders(extraHeaders)\n const url = `${copilotBaseUrl(state)}/v1/messages?beta=true`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot /v1/messages error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot messages request failed\", reconstructed)\n }\n\n return response\n}\n\n/**\n * Forward an Anthropic count_tokens request to Copilot's native endpoint.\n * Returns the raw Response.\n */\nexport async function countTokens(\n body: string,\n extraHeaders?: Record<string, string>,\n): Promise<Response> {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const headers = buildHeaders(extraHeaders)\n const url = `${copilotBaseUrl(state)}/v1/messages/count_tokens?beta=true`\n consola.debug(`Forwarding to ${url}`)\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n })\n\n if (!response.ok) {\n let errorBody = \"\"\n try {\n errorBody = await response.text()\n } catch {\n errorBody = \"(could not read error body)\"\n }\n consola.error(\n `Copilot count_tokens error: ${response.status} ${errorBody}`,\n )\n const reconstructed = new Response(errorBody, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n throw new HTTPError(\"Copilot count_tokens request failed\", reconstructed)\n }\n\n return response\n}\n","import type { Context } from \"hono\"\n\nimport { logRequest } from \"~/lib/request-log\"\nimport { filterBetaHeader, resolveModel } from \"~/lib/utils\"\nimport { state } from \"~/lib/state\"\nimport { countTokens } from \"~/services/copilot/create-messages\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Strip web_search tools from the request body before forwarding\n * to Copilot's count_tokens endpoint, which rejects unknown tool types.\n * Returns the original raw body if no web_search tools are present.\n */\nfunction stripWebSearchFromBody(rawBody: string): string {\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n\n return JSON.stringify(body)\n}\n\n/**\n * Passthrough handler for Anthropic token counting.\n * Strips web_search tools and forwards beta headers to Copilot's\n * native /v1/messages/count_tokens endpoint.\n */\nexport async function handleCountTokens(c: Context) {\n const startTime = Date.now()\n const rawBody = await c.req.text()\n const strippedBody = stripWebSearchFromBody(rawBody)\n const { body: finalBody, originalModel, resolvedModel } = resolveModelInBody(strippedBody)\n\n const extraHeaders: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) extraHeaders[\"anthropic-beta\"] = filtered\n }\n\n const response = await countTokens(finalBody, extraHeaders)\n const responseBody = (await response.json()) as { input_tokens?: number }\n\n const modelId = resolvedModel ?? originalModel\n const selectedModel = state.models?.data.find((m) => m.id === modelId)\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens: responseBody.input_tokens,\n status: response.status,\n },\n selectedModel,\n startTime,\n )\n\n return c.json(responseBody)\n}\n\n/**\n * Parse the JSON body, resolve the model name, and re-serialize.\n */\nfunction resolveModelInBody(rawBody: string): {\n body: string\n originalModel?: string\n resolvedModel?: string\n} {\n let parsed: AnyRecord\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return { body: rawBody }\n }\n\n const originalModel =\n typeof parsed.model === \"string\" ? parsed.model : undefined\n if (!originalModel) return { body: rawBody, originalModel }\n\n const resolved = resolveModel(originalModel)\n if (resolved === originalModel)\n return { body: rawBody, originalModel, resolvedModel: originalModel }\n\n parsed.model = resolved\n return {\n body: JSON.stringify(parsed),\n originalModel,\n resolvedModel: resolved,\n }\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { state } from \"~/lib/state\"\nimport { filterBetaHeader, resolveModel } from \"~/lib/utils\"\nimport { createMessages } from \"~/services/copilot/create-messages\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRecord = Record<string, any>\n\nconst isWebSearchTool = (tool: AnyRecord): boolean =>\n (typeof tool.type === \"string\" && tool.type.startsWith(\"web_search\")) ||\n tool.name === \"web_search\"\n\n/**\n * Extract whitelisted beta headers from the incoming request to forward\n * to the Copilot API. VS Code sends these to enable extended features\n * like thinking, context management, and advanced tool use.\n */\nfunction extractBetaHeaders(c: Context): Record<string, string> {\n const headers: Record<string, string> = {}\n const anthropicBeta = c.req.header(\"anthropic-beta\")\n if (anthropicBeta) {\n const filtered = filterBetaHeader(anthropicBeta)\n if (filtered) headers[\"anthropic-beta\"] = filtered\n }\n return headers\n}\n\n/**\n * Extract the text content from the last user message for web search.\n * Handles both string content and content block arrays (multimodal).\n */\nfunction extractUserQuery(\n messages: Array<AnyRecord>,\n): string | undefined {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") return msg.content\n if (Array.isArray(msg.content)) {\n const textBlock = msg.content.find(\n (block: AnyRecord) => block.type === \"text\",\n )\n if (textBlock?.text) return textBlock.text as string\n }\n }\n }\n return undefined\n}\n\n/**\n * Check if any user message contains tool_result content blocks,\n * indicating a follow-up turn where we should skip web search.\n * In Anthropic format, tool results are content blocks inside user messages,\n * NOT separate role: \"tool\" messages like in OpenAI format.\n */\nfunction hasToolResultContent(messages: Array<AnyRecord>): boolean {\n return messages.some(\n (msg) =>\n Array.isArray(msg.content) &&\n msg.content.some(\n (block: AnyRecord) => block.type === \"tool_result\",\n ),\n )\n}\n\n/**\n * Inject web search results into the Anthropic system field.\n * Handles three cases: absent, string, or array of content blocks.\n * When array, prepends without cache_control to preserve existing directives.\n */\nfunction injectSearchResults(\n body: AnyRecord,\n searchContext: string,\n): void {\n if (body.system === undefined || body.system === null) {\n body.system = searchContext\n } else if (typeof body.system === \"string\") {\n body.system = `${searchContext}\\n\\n${body.system}`\n } else if (Array.isArray(body.system)) {\n body.system = [\n { type: \"text\", text: searchContext },\n ...body.system,\n ]\n }\n}\n\n/**\n * Strip web_search tools from the request and clean up tool_choice.\n * Returns the modified body object.\n */\nfunction stripWebSearchTool(body: AnyRecord): void {\n if (!body.tools) return\n\n body.tools = body.tools.filter(\n (tool: AnyRecord) => !isWebSearchTool(tool),\n )\n\n if (body.tools.length === 0) {\n body.tools = undefined\n body.tool_choice = undefined\n } else if (\n body.tool_choice &&\n typeof body.tool_choice === \"object\" &&\n body.tool_choice.type === \"tool\"\n ) {\n // If tool_choice forced the removed web_search tool, fall back to auto\n const choiceName = body.tool_choice.name\n if (\n choiceName &&\n !body.tools.some((tool: AnyRecord) => tool.name === choiceName)\n ) {\n body.tool_choice = { type: \"auto\" }\n }\n }\n}\n\n/**\n * Process web search if the request contains a web_search tool.\n * Performs the search, injects results into system, and strips the tool.\n * Returns the (possibly modified) body string to forward.\n */\nasync function processWebSearch(rawBody: string): Promise<string> {\n // Fast path: skip parsing if no web_search tool present\n if (!rawBody.includes(\"web_search\")) return rawBody\n\n let body: AnyRecord\n try {\n body = JSON.parse(rawBody)\n } catch {\n return rawBody\n }\n\n const hasWebSearch = body.tools?.some(\n (tool: AnyRecord) => isWebSearchTool(tool),\n )\n if (!hasWebSearch) return rawBody\n\n // Skip search on follow-up messages (tool call results)\n const hasToolResult = hasToolResultContent(body.messages ?? [])\n const query = hasToolResult ? undefined : extractUserQuery(body.messages ?? [])\n\n if (query) {\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n injectSearchResults(body, searchContext)\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n }\n\n // Always strip web_search tool regardless of whether search succeeded\n stripWebSearchTool(body)\n\n return JSON.stringify(body)\n}\n\nexport async function handleCompletion(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n const rawBody = await c.req.text()\n\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\"Anthropic request body:\", rawBody.slice(0, 2000))\n }\n\n if (state.manualApprove) {\n await awaitApproval()\n }\n\n const betaHeaders = extractBetaHeaders(c)\n const finalBody = await processWebSearch(rawBody)\n\n // Resolve model name (e.g. opus → opus-1m variant)\n const { body: resolvedBody, originalModel, resolvedModel } = resolveModelInBody(finalBody)\n\n // Look up model metadata for context window info\n const selectedModel = state.models?.data.find(\n (m) => m.id === (resolvedModel ?? originalModel),\n )\n\n const response = await createMessages(resolvedBody, betaHeaders)\n\n const contentType = response.headers.get(\"content-type\") ?? \"\"\n const isStreaming = contentType.includes(\"text/event-stream\")\n\n // Streaming: pipe the upstream SSE response body directly\n if (isStreaming) {\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: response.status,\n streaming: true,\n },\n selectedModel,\n startTime,\n )\n\n if (debugEnabled) {\n consola.debug(\"Streaming response from Copilot /v1/messages\")\n }\n return new Response(response.body, {\n status: response.status,\n headers: {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n },\n })\n }\n\n // Non-streaming: extract usage from response body\n const responseBody = (await response.json()) as AnyRecord\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n inputTokens: responseBody.usage?.input_tokens,\n outputTokens: responseBody.usage?.output_tokens,\n status: response.status,\n },\n selectedModel,\n startTime,\n )\n\n if (debugEnabled) {\n consola.debug(\n \"Non-streaming response from Copilot /v1/messages:\",\n JSON.stringify(responseBody).slice(0, 2000),\n )\n }\n return c.json(responseBody, response.status as 200)\n}\n\n/**\n * Parse the JSON body, resolve the model name, and re-serialize.\n * Returns the body string plus the original and resolved model names.\n */\nfunction resolveModelInBody(rawBody: string): {\n body: string\n originalModel?: string\n resolvedModel?: string\n} {\n let parsed: AnyRecord\n try {\n parsed = JSON.parse(rawBody)\n } catch {\n return { body: rawBody }\n }\n\n const originalModel =\n typeof parsed.model === \"string\" ? parsed.model : undefined\n if (!originalModel) return { body: rawBody, originalModel }\n\n const resolved = resolveModel(originalModel)\n if (resolved === originalModel)\n return { body: rawBody, originalModel, resolvedModel: originalModel }\n\n parsed.model = resolved\n return {\n body: JSON.stringify(parsed),\n originalModel,\n resolvedModel: resolved,\n }\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleCountTokens } from \"./count-tokens-handler\"\nimport { handleCompletion } from \"./handler\"\n\nexport const messageRoutes = new Hono()\n\nmessageRoutes.post(\"/\", async (c) => {\n try {\n return await handleCompletion(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n\nmessageRoutes.post(\"/count_tokens\", async (c) => {\n try {\n return await handleCountTokens(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\nimport { cacheModels } from \"~/lib/utils\"\n\nexport const modelRoutes = new Hono()\n\nmodelRoutes.get(\"/\", async (c) => {\n try {\n if (!state.models) {\n // This should be handled by startup logic, but as a fallback.\n await cacheModels()\n }\n\n const models = state.models?.data.map((model) => ({\n id: model.id,\n object: \"model\",\n type: \"model\",\n created: 0, // No date available from source\n created_at: new Date(0).toISOString(), // No date available from source\n owned_by: model.vendor,\n display_name: model.name,\n }))\n\n return c.json({\n object: \"list\",\n data: models,\n has_more: false,\n })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import consola from \"consola\"\nimport { events } from \"fetch-event-stream\"\n\nimport { copilotHeaders, copilotBaseUrl } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const createResponses = async (payload: ResponsesPayload) => {\n if (!state.copilotToken) throw new Error(\"Copilot token not found\")\n\n const enableVision = detectVision(payload.input)\n\n const isAgentCall = detectAgentCall(payload.input)\n\n const headers: Record<string, string> = {\n ...copilotHeaders(state, enableVision),\n \"X-Initiator\": isAgentCall ? \"agent\" : \"user\",\n }\n\n const filteredPayload = filterUnsupportedTools(payload)\n\n const response = await fetch(`${copilotBaseUrl(state)}/responses`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(filteredPayload),\n })\n\n if (!response.ok) {\n consola.error(\"Failed to create responses\", response)\n throw new HTTPError(\"Failed to create responses\", response)\n }\n\n if (payload.stream) {\n return events(response)\n }\n\n return (await response.json()) as ResponsesApiResponse\n}\n\nfunction detectVision(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"content\" in item && Array.isArray(item.content)) {\n return item.content.some(\n (part: Record<string, unknown>) => part.type === \"input_image\",\n )\n }\n return false\n })\n}\n\nfunction detectAgentCall(input: ResponsesPayload[\"input\"]): boolean {\n if (typeof input === \"string\") return false\n if (!Array.isArray(input)) return false\n\n return input.some((item) => {\n if (\"role\" in item && item.role === \"assistant\") return true\n if (\n \"type\" in item\n && (item.type === \"function_call\" || item.type === \"function_call_output\")\n ) {\n return true\n }\n return false\n })\n}\n\nfunction filterUnsupportedTools(payload: ResponsesPayload): ResponsesPayload {\n if (!payload.tools || !Array.isArray(payload.tools)) return payload\n\n const supported = payload.tools.filter((tool) => {\n const isSupported = tool.type === \"function\"\n if (!isSupported) {\n consola.debug(`Stripping unsupported tool type: ${tool.type}`)\n }\n return isSupported\n })\n\n let toolChoice = payload.tool_choice\n if (supported.length === 0) {\n toolChoice = undefined\n } else if (\n toolChoice\n && typeof toolChoice === \"object\"\n ) {\n const supportedNames = new Set(\n supported.map((tool) => tool.name).filter(Boolean),\n )\n const toolChoiceName = getToolChoiceName(toolChoice)\n if (toolChoiceName && !supportedNames.has(toolChoiceName)) {\n toolChoice = undefined\n }\n }\n\n return {\n ...payload,\n tools: supported.length > 0 ? supported : undefined,\n tool_choice: toolChoice,\n }\n}\n\nfunction getToolChoiceName(\n toolChoice: NonNullable<ResponsesPayload[\"tool_choice\"]>,\n): string | undefined {\n if (typeof toolChoice !== \"object\") return undefined\n if (\n \"function\" in toolChoice\n && toolChoice.function\n && typeof toolChoice.function === \"object\"\n ) {\n return (toolChoice.function as { name?: string }).name\n }\n if (\"name\" in toolChoice) {\n return toolChoice.name\n }\n return undefined\n}\n\n// Types\n\nexport interface ResponsesInputItem {\n role?: \"user\" | \"assistant\" | \"system\"\n type?: \"message\" | \"function_call\" | \"function_call_output\"\n content?: string | Array<Record<string, unknown>>\n name?: string\n call_id?: string\n arguments?: string\n output?: string\n [key: string]: unknown\n}\n\nexport interface ResponsesTool {\n type: string\n name?: string\n description?: string\n parameters?: Record<string, unknown>\n [key: string]: unknown\n}\n\nexport interface ResponsesPayload {\n model: string\n input: string | Array<ResponsesInputItem>\n instructions?: string\n tools?: Array<ResponsesTool>\n tool_choice?:\n | string\n | { type: string; name?: string; function?: { name?: string } }\n max_output_tokens?: number\n temperature?: number\n top_p?: number\n stream?: boolean\n store?: boolean\n metadata?: Record<string, string>\n previous_response_id?: string\n reasoning?: { effort?: string; summary?: string }\n [key: string]: unknown\n}\n\nexport interface ResponsesApiResponse {\n id: string\n object: \"response\"\n status: string\n output: Array<unknown>\n [key: string]: unknown\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { streamSSE } from \"hono/streaming\"\n\nimport { awaitApproval } from \"~/lib/approval\"\nimport { checkRateLimit } from \"~/lib/rate-limit\"\nimport { logRequest } from \"~/lib/request-log\"\nimport { state } from \"~/lib/state\"\nimport { isNullish, resolveModel } from \"~/lib/utils\"\nimport {\n createResponses,\n type ResponsesApiResponse,\n type ResponsesInputItem,\n type ResponsesPayload,\n} from \"~/services/copilot/create-responses\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport async function handleResponses(c: Context) {\n const startTime = Date.now()\n await checkRateLimit(state)\n\n const payload = await c.req.json<ResponsesPayload>()\n const debugEnabled = consola.level >= 4\n if (debugEnabled) {\n consola.debug(\n \"Responses request payload:\",\n JSON.stringify(payload).slice(-400),\n )\n }\n\n // Resolve model name (e.g. opus → opus-1m variant)\n const originalModel = payload.model\n const resolvedModel = resolveModel(payload.model)\n if (resolvedModel !== payload.model) {\n payload.model = resolvedModel\n }\n\n const selectedModel = state.models?.data.find(\n (model) => model.id === payload.model,\n )\n\n if (state.manualApprove) await awaitApproval()\n\n await injectWebSearchIfNeeded(payload)\n\n if (isNullish(payload.max_output_tokens)) {\n payload.max_output_tokens =\n selectedModel?.capabilities.limits.max_output_tokens\n if (debugEnabled) {\n consola.debug(\n \"Set max_output_tokens to:\",\n JSON.stringify(payload.max_output_tokens),\n )\n }\n }\n\n const response = await createResponses(payload)\n const isStreaming = !isNonStreaming(response)\n\n logRequest(\n {\n method: \"POST\",\n path: c.req.path,\n model: originalModel,\n resolvedModel,\n status: 200,\n streaming: isStreaming,\n },\n selectedModel,\n startTime,\n )\n\n if (!isStreaming) {\n if (debugEnabled) {\n consola.debug(\"Non-streaming response:\", JSON.stringify(response))\n }\n return c.json(response)\n }\n\n return streamSSE(c, async (stream) => {\n for await (const chunk of response) {\n if (debugEnabled) {\n consola.debug(\"Streaming chunk:\", JSON.stringify(chunk))\n }\n\n if (chunk.data === \"[DONE]\") {\n break\n }\n\n if (!chunk.data) {\n continue\n }\n\n await stream.writeSSE({\n data: chunk.data,\n event: chunk.event,\n id: chunk.id?.toString(),\n })\n }\n })\n}\n\nconst isNonStreaming = (\n response: Awaited<ReturnType<typeof createResponses>>,\n): response is ResponsesApiResponse => Object.hasOwn(response, \"output\")\n\nasync function injectWebSearchIfNeeded(\n payload: ResponsesPayload,\n): Promise<void> {\n const hasWebSearch = payload.tools?.some((t) => t.type === \"web_search\")\n if (!hasWebSearch) return\n\n // Skip search on follow-up messages (function call results)\n if (Array.isArray(payload.input)) {\n const hasFollowUp = payload.input.some(\n (item: ResponsesInputItem) => item.type === \"function_call_output\",\n )\n if (hasFollowUp) return\n }\n\n const query = extractUserQuery(payload.input)\n if (!query) return\n\n try {\n const results = await searchWeb(query)\n const searchContext = [\n \"[Web Search Results]\",\n results.content,\n \"\",\n results.references.map((r) => `- [${r.title}](${r.url})`).join(\"\\n\"),\n \"[End Web Search Results]\",\n ].join(\"\\n\")\n\n payload.instructions =\n payload.instructions ?\n `${searchContext}\\n\\n${payload.instructions}`\n : searchContext\n } catch (error) {\n consola.warn(\"Web search failed, continuing without results:\", error)\n }\n}\n\nfunction extractUserQuery(\n input: ResponsesPayload[\"input\"],\n): string | undefined {\n if (typeof input === \"string\") return input\n if (!Array.isArray(input)) return undefined\n\n // Find the last user message\n for (let i = input.length - 1; i >= 0; i--) {\n const item = input[i]\n if (\"role\" in item && item.role === \"user\") {\n if (typeof item.content === \"string\") return item.content\n if (Array.isArray(item.content)) {\n const text = item.content.find(\n (p: Record<string, unknown>) => p.type === \"input_text\",\n )\n if (text && \"text\" in text) return text.text as string\n }\n }\n }\n return undefined\n}\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\n\nimport { handleResponses } from \"./handler\"\n\nexport const responsesRoutes = new Hono()\n\nresponsesRoutes.post(\"/\", async (c) => {\n try {\n return await handleResponses(c)\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { searchWeb } from \"~/services/copilot/web-search\"\n\nexport const searchRoutes = new Hono()\n\nsearchRoutes.post(\"/\", async (c) => {\n try {\n const { query } = await c.req.json<{ query: string }>()\n\n if (!query || typeof query !== \"string\") {\n return c.json(\n { error: { message: \"Missing required field: query\" } },\n 400,\n )\n }\n\n const results = await searchWeb(query)\n return c.json({ results })\n } catch (error) {\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\n\nimport { state } from \"~/lib/state\"\n\nexport const tokenRoute = new Hono()\n\ntokenRoute.get(\"/\", (c) => {\n if (!state.showToken) {\n return c.json(\n { error: { message: \"Token endpoint disabled\", type: \"error\" } },\n 403,\n )\n }\n\n return c.json({\n token: state.copilotToken,\n })\n})\n","import { Hono } from \"hono\"\nimport consola from \"consola\"\n\nimport { forwardError } from \"~/lib/error\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\n\nexport const usageRoute = new Hono()\n\nusageRoute.get(\"/\", async (c) => {\n try {\n const usage = await getCopilotUsage()\n return c.json(usage)\n } catch (error) {\n consola.error(\"Error fetching Copilot usage:\", error)\n return await forwardError(c, error)\n }\n})\n","import { Hono } from \"hono\"\nimport { cors } from \"hono/cors\"\n\nimport { completionRoutes } from \"./routes/chat-completions/route\"\nimport { embeddingRoutes } from \"./routes/embeddings/route\"\nimport { messageRoutes } from \"./routes/messages/route\"\nimport { modelRoutes } from \"./routes/models/route\"\nimport { responsesRoutes } from \"./routes/responses/route\"\nimport { searchRoutes } from \"./routes/search/route\"\nimport { tokenRoute } from \"./routes/token/route\"\nimport { usageRoute } from \"./routes/usage/route\"\n\nexport const server = new Hono()\n\nserver.use(cors())\n\nserver.get(\"/\", (c) => c.text(\"Server running\"))\n\nserver.route(\"/chat/completions\", completionRoutes)\nserver.route(\"/responses\", responsesRoutes)\nserver.route(\"/models\", modelRoutes)\nserver.route(\"/embeddings\", embeddingRoutes)\nserver.route(\"/search\", searchRoutes)\nserver.route(\"/usage\", usageRoute)\nserver.route(\"/token\", tokenRoute)\n\n// Compatibility with tools that expect v1/ prefix\nserver.route(\"/v1/chat/completions\", completionRoutes)\nserver.route(\"/v1/responses\", responsesRoutes)\nserver.route(\"/v1/models\", modelRoutes)\nserver.route(\"/v1/embeddings\", embeddingRoutes)\nserver.route(\"/v1/search\", searchRoutes)\n\n// Anthropic compatible endpoints\nserver.route(\"/v1/messages\", messageRoutes)\n","#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport clipboard from \"clipboardy\"\nimport consola from \"consola\"\nimport { serve, type ServerHandler } from \"srvx\"\nimport invariant from \"tiny-invariant\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { initProxyFromEnv } from \"./lib/proxy\"\nimport { generateEnvScript } from \"./lib/shell\"\nimport { state } from \"./lib/state\"\nimport { setupCopilotToken, setupGitHubToken } from \"./lib/token\"\nimport { cacheModels, cacheVSCodeVersion } from \"./lib/utils\"\nimport type { Model } from \"./services/copilot/get-models\"\nimport { server } from \"./server\"\n\ninterface RunServerOptions {\n port: number\n verbose: boolean\n accountType: string\n manual: boolean\n rateLimit?: number\n rateLimitWait: boolean\n githubToken?: string\n claudeCode: boolean\n codex: boolean\n showToken: boolean\n proxyEnv: boolean\n}\n\nconst allowedAccountTypes = new Set([\"individual\", \"business\", \"enterprise\"])\n\nfunction printAndCopyCommand(command: string, label: string): void {\n consola.box(`${label}\\n\\n${command}`)\n try {\n clipboard.writeSync(command)\n consola.success(`Copied ${label} command to clipboard!`)\n } catch {\n consola.warn(\"Failed to copy to clipboard. Copy the command above manually.\")\n }\n}\n\nfunction filterModelsByEndpoint(\n models: Array<Model>,\n endpoint: string,\n): Array<Model> {\n const filtered = models.filter((model) => {\n const endpoints = model.supported_endpoints\n // Some deployments omit supported_endpoints; keep those models visible.\n if (!endpoints || endpoints.length === 0) return true\n return endpoints.some((entry) => {\n const normalized = entry.replace(/^\\/?v1\\//, \"\").replace(/^\\//, \"\")\n return normalized === endpoint\n })\n })\n\n return filtered.length > 0 ? filtered : models\n}\n\nasync function generateClaudeCodeCommand(serverUrl: string) {\n invariant(state.models, \"Models should be loaded by now\")\n\n const claudeModels = state.models.data.filter((model) =>\n model.id.toLowerCase().startsWith(\"claude\"),\n )\n\n if (claudeModels.length === 0) {\n consola.error(\"No Claude models available from Copilot API\")\n return\n }\n\n // Pick the best main model: prefer opus, then sonnet, then first available\n const mainModel =\n claudeModels.find((m) => m.id.includes(\"opus\")) ??\n claudeModels.find((m) => m.id.includes(\"sonnet\")) ??\n claudeModels[0]\n\n // Pick the best small model: prefer haiku, then sonnet, then first available\n const smallModel =\n claudeModels.find((m) => m.id.includes(\"haiku\")) ??\n claudeModels.find((m) => m.id.includes(\"sonnet\")) ??\n claudeModels[0]\n\n // Only prompt if there are multiple options and the user might want to override\n let selectedModel = mainModel.id\n let selectedSmallModel = smallModel.id\n\n if (claudeModels.length > 1) {\n consola.info(\n `Using ${mainModel.id} as main model and ${smallModel.id} as small model`,\n )\n const override = await consola.prompt(\"Override model selection?\", {\n type: \"confirm\",\n initial: false,\n })\n\n if (override) {\n selectedModel = await consola.prompt(\n \"Select a main model for Claude Code\",\n {\n type: \"select\",\n options: claudeModels.map((model) => model.id),\n },\n )\n selectedSmallModel = await consola.prompt(\n \"Select a small/fast model for Claude Code\",\n {\n type: \"select\",\n options: claudeModels.map((model) => model.id),\n },\n )\n }\n }\n\n const command = generateEnvScript(\n {\n ANTHROPIC_BASE_URL: serverUrl,\n ANTHROPIC_AUTH_TOKEN: \"dummy\",\n ANTHROPIC_MODEL: selectedModel,\n ANTHROPIC_DEFAULT_SONNET_MODEL: selectedModel,\n ANTHROPIC_SMALL_FAST_MODEL: selectedSmallModel,\n ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedSmallModel,\n DISABLE_NON_ESSENTIAL_MODEL_CALLS: \"1\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n },\n \"claude --dangerously-skip-permissions\",\n )\n\n printAndCopyCommand(command, \"Claude Code\")\n}\n\nasync function generateCodexCommand(serverUrl: string) {\n invariant(state.models, \"Models should be loaded by now\")\n\n const supportedModels = filterModelsByEndpoint(\n state.models.data,\n \"responses\",\n )\n\n const defaultCodexModel = supportedModels.find(\n (model) => model.id === \"gpt5.2-codex\",\n )\n\n const selectedModel =\n defaultCodexModel ?\n defaultCodexModel.id\n : await consola.prompt(\"Select a model to use with Codex CLI\", {\n type: \"select\",\n options: supportedModels.map((model) => model.id),\n })\n\n const quotedModel = JSON.stringify(selectedModel)\n const command = generateEnvScript(\n {\n OPENAI_BASE_URL: `${serverUrl}/v1`,\n OPENAI_API_KEY: \"dummy\",\n },\n `codex -m ${quotedModel}`,\n )\n\n printAndCopyCommand(command, \"Codex CLI\")\n}\n\nexport async function runServer(options: RunServerOptions): Promise<void> {\n if (options.proxyEnv) {\n initProxyFromEnv()\n }\n\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.accountType = options.accountType\n if (options.accountType !== \"individual\") {\n consola.info(`Using ${options.accountType} plan GitHub account`)\n }\n\n state.manualApprove = options.manual\n state.rateLimitSeconds = options.rateLimit\n state.rateLimitWait = options.rateLimitWait\n state.showToken = options.showToken\n\n await ensurePaths()\n await cacheVSCodeVersion()\n\n if (options.githubToken) {\n state.githubToken = options.githubToken\n consola.info(\"Using provided GitHub token\")\n } else {\n await setupGitHubToken()\n }\n\n await setupCopilotToken()\n await cacheModels()\n\n consola.info(\n `Available models: \\n${state.models?.data.map((model) => `- ${model.id}`).join(\"\\n\")}`,\n )\n\n const serverUrl = `http://localhost:${options.port}`\n\n if (options.claudeCode) await generateClaudeCodeCommand(serverUrl)\n if (options.codex) await generateCodexCommand(serverUrl)\n\n consola.box(\n `🌐 Usage Viewer: https://animeshkundu.github.io/github-router/dashboard.html?endpoint=${serverUrl}/usage`,\n )\n\n serve({\n fetch: server.fetch as ServerHandler,\n hostname: \"127.0.0.1\",\n port: options.port,\n })\n}\n\nexport const start = defineCommand({\n meta: {\n name: \"start\",\n description: \"Start the github-router server\",\n },\n args: {\n port: {\n alias: \"p\",\n type: \"string\",\n default: \"8787\",\n description: \"Port to listen on\",\n },\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"account-type\": {\n alias: \"a\",\n type: \"string\",\n default: \"enterprise\",\n description: \"Account type to use (individual, business, enterprise)\",\n },\n manual: {\n type: \"boolean\",\n default: false,\n description: \"Enable manual request approval\",\n },\n \"rate-limit\": {\n alias: \"r\",\n type: \"string\",\n description: \"Rate limit in seconds between requests\",\n },\n wait: {\n alias: \"w\",\n type: \"boolean\",\n default: false,\n description:\n \"Wait instead of error when rate limit is hit. Has no effect if rate limit is not set\",\n },\n \"github-token\": {\n alias: \"g\",\n type: \"string\",\n description:\n \"Provide GitHub token directly (must be generated using the `auth` subcommand)\",\n },\n \"claude-code\": {\n alias: \"c\",\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Claude Code with Copilot API config\",\n },\n codex: {\n type: \"boolean\",\n default: false,\n description:\n \"Generate a command to launch Codex CLI with Copilot API config\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub and Copilot tokens on fetch and refresh\",\n },\n \"proxy-env\": {\n type: \"boolean\",\n default: false,\n description: \"Initialize proxy from environment variables\",\n },\n },\n run({ args }) {\n const rateLimitRaw = args[\"rate-limit\"]\n let rateLimit: number | undefined\n if (rateLimitRaw !== undefined) {\n rateLimit = Number.parseInt(rateLimitRaw, 10)\n if (Number.isNaN(rateLimit) || rateLimit <= 0) {\n throw new Error(\"Invalid rate limit. Must be a positive integer.\")\n }\n }\n\n const port = Number.parseInt(args.port, 10)\n if (Number.isNaN(port) || port <= 0 || port > 65535) {\n throw new Error(\"Invalid port. Must be between 1 and 65535.\")\n }\n\n const accountType = args[\"account-type\"]\n if (!allowedAccountTypes.has(accountType)) {\n throw new Error(\n \"Invalid account type. Must be individual, business, or enterprise.\",\n )\n }\n\n const rateLimitWait = args.wait && rateLimit !== undefined\n if (args.wait && rateLimit === undefined) {\n consola.warn(\"Rate limit wait ignored because no rate limit was set.\")\n }\n\n const githubToken = args[\"github-token\"] ?? process.env.GH_TOKEN\n\n return runServer({\n port,\n verbose: args.verbose,\n accountType,\n manual: args.manual,\n rateLimit,\n rateLimitWait,\n githubToken,\n claudeCode: args[\"claude-code\"],\n codex: args.codex,\n showToken: args[\"show-token\"],\n proxyEnv: args[\"proxy-env\"],\n })\n },\n})\n","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from \"citty\"\n\nimport { auth } from \"./auth\"\nimport { checkUsage } from \"./check-usage\"\nimport { debug } from \"./debug\"\nimport { start } from \"./start\"\n\nconst main = defineCommand({\n meta: {\n name: \"github-router\",\n description:\n \"A reverse proxy that exposes GitHub Copilot as OpenAI and Anthropic compatible API endpoints.\",\n },\n subCommands: { auth, start, \"check-usage\": checkUsage, debug },\n})\n\nawait runMain(main)\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-router",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "license": "MIT",
5
5
  "description": "A reverse proxy that exposes GitHub Copilot as OpenAI and Anthropic compatible API endpoints.",
6
6
  "keywords": [