@nick3/copilot-api 1.2.7 → 1.3.1

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
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { HTTPError, PATHS, accountsManager, addAccountToRegistry, cacheMacMachineId, cacheVSCodeVersion, cacheVsCodeSessionId, ensurePaths, getCopilotUsage, getGitHubUser, getModelRefreshIntervalMs, getOauthAppConfig, getOauthUrls, isFreeModelLoadBalancingEnabled, listAccountsFromRegistry, loadAccountToken, mergeConfigWithDefaults, removeAccountFromRegistry, removeAccountToken, saveAccountToken, saveRegistry, sleep, state } from "./accounts-manager-iJwqQUkM.js";
2
+ import { HTTPError, PATHS, accountsManager, addAccountToRegistry, cacheMacMachineId, cacheVSCodeVersion, cacheVsCodeSessionId, ensurePaths, getCopilotUsage, getGitHubUser, getModelRefreshIntervalMs, getOauthAppConfig, getOauthUrls, isFreeModelLoadBalancingEnabled, listAccountsFromRegistry, loadAccountToken, mergeConfigWithDefaults, removeAccountFromRegistry, removeAccountToken, saveAccountToken, saveRegistry, sleep, state } from "./accounts-manager-BeKvbv0T.js";
3
3
  import { defineCommand, runMain } from "citty";
4
4
  import consola from "consola";
5
5
  import fs from "node:fs/promises";
@@ -639,7 +639,7 @@ async function runServer(options) {
639
639
  }
640
640
  }
641
641
  consola.box(`🌐 Admin UI: ${serverUrl}/admin`);
642
- const { server } = await import("./server-BgJ8vqcw.js");
642
+ const { server } = await import("./server-D3A61KAx.js");
643
643
  serve({
644
644
  fetch: server.fetch,
645
645
  port: options.port,
@@ -1,4 +1,4 @@
1
- import { HTTPError, PATHS, accountFromState, accountsManager, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getAliasTargetSet, getConfig, getCopilotUsage, getExtraPromptForModel, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getProviderConfig, getReasoningEffortForModel, getRootSessionId, getSmallModel, getUUID, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isNullish, isResponsesApiContextManagementModel, listAccountsFromRegistry, mergeConfigWithDefaults, prepareInteractionHeaders, shouldCompactUseSmallModel, sleep, state } from "./accounts-manager-iJwqQUkM.js";
1
+ import { HTTPError, PATHS, accountFromState, accountsManager, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getAliasTargetSet, getConfig, getCopilotUsage, getExtraPromptForModel, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getProviderConfig, getReasoningEffortForModel, getRootSessionId, getSmallModel, getUUID, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isNullish, isResponsesApiContextManagementModel, listAccountsFromRegistry, mergeConfigWithDefaults, prepareInteractionHeaders, shouldCompactUseSmallModel, sleep, state } from "./accounts-manager-BeKvbv0T.js";
2
2
  import consola from "consola";
3
3
  import fs, { readFile } from "node:fs/promises";
4
4
  import * as path$1 from "node:path";
@@ -3314,6 +3314,57 @@ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, s
3314
3314
  }
3315
3315
  }
3316
3316
 
3317
+ //#endregion
3318
+ //#region src/lib/models.ts
3319
+ const findEndpointModel = (sdkModelId) => {
3320
+ const models = state.models?.data ?? [];
3321
+ const exactMatch = models.find((m) => m.id === sdkModelId);
3322
+ if (exactMatch) return exactMatch;
3323
+ const normalized = _normalizeSdkModelId(sdkModelId);
3324
+ if (!normalized) return;
3325
+ const modelName = `claude-${normalized.family}-${normalized.version}`;
3326
+ const model = models.find((m) => m.id === modelName);
3327
+ if (model) return model;
3328
+ };
3329
+ /**
3330
+ * Normalizes an SDK model ID to extract the model family and version.
3331
+ * this method from github copilot extension
3332
+ * Examples:
3333
+ * - "claude-opus-4-5-20251101" -> { family: "opus", version: "4.5" }
3334
+ * - "claude-3-5-sonnet-20241022" -> { family: "sonnet", version: "3.5" }
3335
+ * - "claude-sonnet-4-20250514" -> { family: "sonnet", version: "4" }
3336
+ * - "claude-haiku-3-5-20250514" -> { family: "haiku", version: "3.5" }
3337
+ * - "claude-haiku-4.5" -> { family: "haiku", version: "4.5" }
3338
+ */
3339
+ const _normalizeSdkModelId = (sdkModelId) => {
3340
+ const withoutDate = sdkModelId.toLowerCase().replace(/-\d{8}$/, "");
3341
+ const pattern1 = withoutDate.match(/^claude-(\w+)-(\d+)-(\d+)$/);
3342
+ if (pattern1) return {
3343
+ family: pattern1[1],
3344
+ version: `${pattern1[2]}.${pattern1[3]}`
3345
+ };
3346
+ const pattern2 = withoutDate.match(/^claude-(\d+)-(\d+)-(\w+)$/);
3347
+ if (pattern2) return {
3348
+ family: pattern2[3],
3349
+ version: `${pattern2[1]}.${pattern2[2]}`
3350
+ };
3351
+ const pattern3 = withoutDate.match(/^claude-(\w+)-(\d+)\.(\d+)$/);
3352
+ if (pattern3) return {
3353
+ family: pattern3[1],
3354
+ version: `${pattern3[2]}.${pattern3[3]}`
3355
+ };
3356
+ const pattern4 = withoutDate.match(/^claude-(\w+)-(\d+)$/);
3357
+ if (pattern4) return {
3358
+ family: pattern4[1],
3359
+ version: pattern4[2]
3360
+ };
3361
+ const pattern5 = withoutDate.match(/^claude-(\d+)-(\w+)$/);
3362
+ if (pattern5) return {
3363
+ family: pattern5[2],
3364
+ version: pattern5[1]
3365
+ };
3366
+ };
3367
+
3317
3368
  //#endregion
3318
3369
  //#region src/routes/messages/utils.ts
3319
3370
  function mapOpenAIStopReasonToAnthropic(finishReason) {
@@ -3438,7 +3489,7 @@ const maybeBlockOriginalModelName = (context) => {
3438
3489
  //#region src/routes/messages/non-stream-translation.ts
3439
3490
  const THINKING_TEXT = "Thinking...";
3440
3491
  function translateToOpenAI(payload) {
3441
- const modelId = translateModelName(payload.model);
3492
+ const modelId = payload.model;
3442
3493
  const model = state.models?.data.find((m) => m.id === modelId);
3443
3494
  const thinkingBudget = getThinkingBudget(payload, model);
3444
3495
  return {
@@ -3459,56 +3510,27 @@ function getThinkingBudget(payload, model) {
3459
3510
  const thinking = payload.thinking;
3460
3511
  if (model && thinking) {
3461
3512
  const maxThinkingBudget = Math.min(model.capabilities.supports.max_thinking_budget ?? 0, (model.capabilities.limits.max_output_tokens ?? 0) - 1);
3462
- if (maxThinkingBudget > 0 && thinking.budget_tokens !== void 0) {
3513
+ thinking.budget_tokens ??= maxThinkingBudget;
3514
+ if (maxThinkingBudget > 0) {
3463
3515
  const budgetTokens = Math.min(thinking.budget_tokens, maxThinkingBudget);
3464
3516
  return Math.max(budgetTokens, model.capabilities.supports.min_thinking_budget ?? 1024);
3465
3517
  }
3466
3518
  }
3467
3519
  }
3468
- function translateModelName(model) {
3469
- if (model.startsWith("claude-sonnet-4-")) return model.replace(/^claude-sonnet-4-.*/, "claude-sonnet-4");
3470
- else if (model.startsWith("claude-opus-4-")) return model.replace(/^claude-opus-4-.*/, "claude-opus-4");
3471
- return model;
3472
- }
3473
- function translateAnthropicMessagesToOpenAI(payload, modelId, thinkingBudget) {
3474
- const systemMessages = handleSystemPrompt(payload.system, modelId, thinkingBudget);
3520
+ function translateAnthropicMessagesToOpenAI(payload, modelId, _thinkingBudget) {
3521
+ const systemMessages = handleSystemPrompt(payload.system);
3475
3522
  const otherMessages = payload.messages.flatMap((message) => message.role === "user" ? handleUserMessage(message) : handleAssistantMessage(message, modelId));
3476
- if (modelId.startsWith("claude") && thinkingBudget) {
3477
- const reminder = "<system-reminder>you MUST follow interleaved_thinking_protocol</system-reminder>";
3478
- const firstUserIndex = otherMessages.findIndex((m) => m.role === "user");
3479
- if (firstUserIndex !== -1) {
3480
- const userMessage = otherMessages[firstUserIndex];
3481
- if (typeof userMessage.content === "string") userMessage.content = reminder + "\n\n" + userMessage.content;
3482
- else if (Array.isArray(userMessage.content)) userMessage.content = [{
3483
- type: "text",
3484
- text: reminder
3485
- }, ...userMessage.content];
3486
- }
3487
- }
3488
3523
  return [...systemMessages, ...otherMessages];
3489
3524
  }
3490
- function handleSystemPrompt(system, modelId, thinkingBudget) {
3525
+ function handleSystemPrompt(system) {
3491
3526
  if (!system) return [];
3492
- let extraPrompt = "";
3493
- if (modelId.startsWith("claude") && thinkingBudget) extraPrompt = `
3494
- <interleaved_thinking_protocol>
3495
- ABSOLUTE REQUIREMENT - NON-NEGOTIABLE:
3496
- The current thinking_mode is interleaved, Whenever you have the result of a function call, think carefully , MUST output a thinking block
3497
- RULES:
3498
- Tool result → thinking block (ALWAYS, no exceptions)
3499
- This is NOT optional - it is a hard requirement
3500
- The thinking block must contain substantive reasoning (minimum 3-5 sentences)
3501
- Think about: what the results mean, what to do next, how to answer the user
3502
- NEVER skip this step, even if the result seems simple or obvious
3503
- </interleaved_thinking_protocol>`;
3504
3527
  if (typeof system === "string") return [{
3505
3528
  role: "system",
3506
- content: system + extraPrompt
3529
+ content: system
3507
3530
  }];
3508
3531
  else return [{
3509
3532
  role: "system",
3510
- content: system.map((block, index) => {
3511
- if (index === 0) return block.text + extraPrompt;
3533
+ content: system.map((block) => {
3512
3534
  return block.text;
3513
3535
  }).join("\n\n")
3514
3536
  }];
@@ -3680,7 +3702,8 @@ async function handleCountTokens(c) {
3680
3702
  const anthropicBeta = c.req.header("anthropic-beta");
3681
3703
  const anthropicPayload = await c.req.json();
3682
3704
  const openAIPayload = translateToOpenAI(anthropicPayload);
3683
- const selectedModel = state.models?.data.find((model) => model.id === anthropicPayload.model);
3705
+ const selectedModel = findEndpointModel(anthropicPayload.model);
3706
+ anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
3684
3707
  if (!selectedModel) {
3685
3708
  consola.warn("Model not found, returning default token count");
3686
3709
  return c.json({ input_tokens: 1 });
@@ -4618,17 +4641,19 @@ async function handleCompletion(c) {
4618
4641
  if (blockedResponse) return blockedResponse;
4619
4642
  const openAIPayload = translateToOpenAI(anthropicPayload);
4620
4643
  const fallbackInitiator = initiatorOverride ?? getChatInitiator(openAIPayload.messages);
4644
+ const endpointModel = findEndpointModel(clientModel);
4645
+ const resolvedClientModel = endpointModel?.id ?? clientModel;
4621
4646
  const selection = await accountsManager.selectAccountForRequest([
4622
4647
  {
4623
- modelId: clientModel,
4648
+ modelId: resolvedClientModel,
4624
4649
  endpoint: MESSAGES_ENDPOINT
4625
4650
  },
4626
4651
  {
4627
- modelId: clientModel,
4652
+ modelId: resolvedClientModel,
4628
4653
  endpoint: RESPONSES_ENDPOINT$1
4629
4654
  },
4630
4655
  {
4631
- modelId: openAIPayload.model,
4656
+ modelId: endpointModel?.id ?? openAIPayload.model,
4632
4657
  endpoint: CHAT_COMPLETIONS_ENDPOINT
4633
4658
  }
4634
4659
  ]);
@@ -5396,6 +5421,18 @@ const FORWARDABLE_HEADERS = [
5396
5421
  "accept",
5397
5422
  "user-agent"
5398
5423
  ];
5424
+ const STRIPPED_RESPONSE_HEADERS = [
5425
+ "connection",
5426
+ "content-encoding",
5427
+ "content-length",
5428
+ "keep-alive",
5429
+ "proxy-authenticate",
5430
+ "proxy-authorization",
5431
+ "te",
5432
+ "trailer",
5433
+ "transfer-encoding",
5434
+ "upgrade"
5435
+ ];
5399
5436
  function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
5400
5437
  const headers = {
5401
5438
  "content-type": "application/json",
@@ -5408,6 +5445,15 @@ function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
5408
5445
  }
5409
5446
  return headers;
5410
5447
  }
5448
+ function createProviderProxyResponse(upstreamResponse) {
5449
+ const headers = new Headers(upstreamResponse.headers);
5450
+ for (const headerName of STRIPPED_RESPONSE_HEADERS) headers.delete(headerName);
5451
+ return new Response(upstreamResponse.body, {
5452
+ headers,
5453
+ status: upstreamResponse.status,
5454
+ statusText: upstreamResponse.statusText
5455
+ });
5456
+ }
5411
5457
  async function forwardProviderMessages(providerConfig, payload, requestHeaders) {
5412
5458
  return await fetch(`${providerConfig.baseUrl}/v1/messages`, {
5413
5459
  method: "POST",
@@ -5434,9 +5480,10 @@ async function handleProviderMessages(c) {
5434
5480
  } }, 404);
5435
5481
  try {
5436
5482
  const payload = await c.req.json();
5437
- payload.temperature ??= providerConfig.defaultTemperature;
5438
- payload.top_p ??= providerConfig.defaultTopP;
5439
- payload.top_k ??= providerConfig.defaultTopK;
5483
+ const modelConfig = providerConfig.models?.[payload.model];
5484
+ payload.temperature ??= modelConfig?.temperature;
5485
+ payload.top_p ??= modelConfig?.topP;
5486
+ payload.top_k ??= modelConfig?.topK;
5440
5487
  logger$3.debug("provider.messages.request", JSON.stringify({
5441
5488
  payload,
5442
5489
  provider
@@ -5457,7 +5504,7 @@ async function handleProviderMessages(c) {
5457
5504
  }
5458
5505
  });
5459
5506
  }
5460
- return upstreamResponse;
5507
+ return createProviderProxyResponse(upstreamResponse);
5461
5508
  } catch (error) {
5462
5509
  logger$3.error("provider.messages.error", {
5463
5510
  provider,
@@ -5502,7 +5549,7 @@ providerModelRoutes.get("/", async (c) => {
5502
5549
  provider,
5503
5550
  statusCode: upstreamResponse.status
5504
5551
  });
5505
- return upstreamResponse;
5552
+ return createProviderProxyResponse(upstreamResponse);
5506
5553
  } catch (error) {
5507
5554
  logger$2.error("provider.models.error", {
5508
5555
  provider,
@@ -6097,4 +6144,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
6097
6144
 
6098
6145
  //#endregion
6099
6146
  export { server };
6100
- //# sourceMappingURL=server-BgJ8vqcw.js.map
6147
+ //# sourceMappingURL=server-D3A61KAx.js.map