@dianshuv/copilot-api 0.8.0 → 0.8.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.
Files changed (2) hide show
  1. package/dist/main.mjs +56 -11
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -1348,7 +1348,7 @@ const patchClaude = defineCommand({
1348
1348
 
1349
1349
  //#endregion
1350
1350
  //#region package.json
1351
- var version = "0.8.0";
1351
+ var version = "0.8.1";
1352
1352
 
1353
1353
  //#endregion
1354
1354
  //#region src/lib/adaptive-rate-limiter.ts
@@ -3448,13 +3448,39 @@ function isOneMillionSuffixedClaudeId(modelId) {
3448
3448
  }
3449
3449
 
3450
3450
  //#endregion
3451
- //#region src/services/copilot/create-chat-completions.ts
3452
- const GPT_MODEL_PATTERN = /^gpt-/i;
3451
+ //#region src/lib/headers.ts
3452
+ /**
3453
+ * Vendor-neutral header-bag helpers.
3454
+ *
3455
+ * HTTP header names are case-insensitive, but a plain-object header bag is
3456
+ * case-sensitive on its keys. Code that wants to look up "anthropic-beta"
3457
+ * without knowing whether some other producer wrote "Anthropic-Beta" needs
3458
+ * `findHeaderKey`. Code that wants to set a header without creating a
3459
+ * second case variant of the same name needs `setHeader`.
3460
+ */
3453
3461
  /** Case-insensitive lookup of a header key in a plain-object header bag. */
3454
3462
  function findHeaderKey(headers, name) {
3455
3463
  const lower = name.toLowerCase();
3456
3464
  return Object.keys(headers).find((k) => k.toLowerCase() === lower);
3457
3465
  }
3466
+ /** Case-insensitive read of a header value. */
3467
+ function getHeader(headers, name) {
3468
+ const key = findHeaderKey(headers, name);
3469
+ return key === void 0 ? void 0 : headers[key];
3470
+ }
3471
+ /**
3472
+ * Set a header value at the existing case variant if one is present, else at
3473
+ * the supplied canonical name. Prevents a second key (different case) from
3474
+ * being added for the same logical header.
3475
+ */
3476
+ function setHeader(headers, name, value) {
3477
+ const key = findHeaderKey(headers, name) ?? name;
3478
+ headers[key] = value;
3479
+ }
3480
+
3481
+ //#endregion
3482
+ //#region src/services/copilot/create-chat-completions.ts
3483
+ const GPT_MODEL_PATTERN = /^gpt-/i;
3458
3484
  const createChatCompletions = async (payload, options) => {
3459
3485
  if (!state.copilotToken) throw new Error("Copilot token not found");
3460
3486
  const vendor = options?.resolvedModel?.vendor;
@@ -7121,15 +7147,18 @@ async function createAnthropicMessages(payload, options) {
7121
7147
  const headers = {
7122
7148
  ...copilotHeaders(state, {
7123
7149
  vision: enableVision,
7124
- intent: isAgentCall ? "conversation-agent" : "conversation-panel"
7150
+ intent: isAgentCall ? "conversation-agent" : "conversation-panel",
7151
+ modelRequestHeaders: resolvedModel?.request_headers
7125
7152
  }),
7126
7153
  "X-Initiator": options?.initiator ?? (isAgentCall ? "agent" : "user"),
7127
7154
  "anthropic-version": "2023-06-01"
7128
7155
  };
7129
- const betaHeaders = buildAnthropicBetaHeaders(filteredPayload.model, resolvedModel);
7130
- Object.assign(headers, betaHeaders);
7131
- if (options?.injectContext1mBeta) headers["anthropic-beta"] = appendContext1mBeta(headers["anthropic-beta"]);
7132
- if (isContextEditingEnabled(filteredPayload.model)) {
7156
+ const proxyBeta = buildAnthropicBetaHeaders(filteredPayload.model, resolvedModel)["anthropic-beta"];
7157
+ let mergedBeta = mergeBetaFeatures(getHeader(headers, "anthropic-beta"), proxyBeta);
7158
+ if (options?.injectContext1mBeta) mergedBeta = appendContext1mBeta(mergedBeta);
7159
+ if (options?.clientAnthropicBetaHeader) mergedBeta = mergeBetaFeatures(mergedBeta, options.clientAnthropicBetaHeader);
7160
+ if (mergedBeta.length > 0) setHeader(headers, "anthropic-beta", mergedBeta);
7161
+ if (!("context_management" in filteredPayload) && isContextEditingEnabled(filteredPayload.model)) {
7133
7162
  const hasThinking = filteredPayload.thinking?.type === "enabled";
7134
7163
  const cm = buildContextManagement(state.contextEditingMode, hasThinking);
7135
7164
  if (cm) {
@@ -7178,7 +7207,11 @@ function stripServerToolsFromPayload(tools) {
7178
7207
  }
7179
7208
  return result.length > 0 ? result : void 0;
7180
7209
  }
7181
- /** Context window unlocked by the context-1m-2025-08-07 beta header. */
7210
+ /**
7211
+ * Effective 1M context window. Two ways a request lands on this size:
7212
+ * (a) base model id + context-1m-2025-08-07 beta header (e.g. claude-opus-4.8),
7213
+ * (b) a distinct upstream "-1m-internal" model id (e.g. claude-opus-4.7-1m-internal).
7214
+ */
7182
7215
  const ONE_MILLION_CONTEXT_WINDOW_TOKENS = 1e6;
7183
7216
  /**
7184
7217
  * Convert a Claude model id from the client-facing dash convention to the
@@ -7212,7 +7245,17 @@ function resolveAnthropicModelForDirectPath(modelId) {
7212
7245
  }
7213
7246
  if (modelId.endsWith("-1m")) {
7214
7247
  const baseId = modelId.slice(0, -3);
7215
- for (const candidateId of [baseId, dashToDotClaudeId(baseId)]) {
7248
+ const dottedBaseId = dashToDotClaudeId(baseId);
7249
+ for (const candidateId of [`${baseId}-1m-internal`, `${dottedBaseId}-1m-internal`]) {
7250
+ const internal = findModelById(candidateId);
7251
+ if (internal?.vendor === "Anthropic") return {
7252
+ model: internal,
7253
+ baseModelId: candidateId,
7254
+ oneMillionFallback: false,
7255
+ effectiveContextWindowTokens: ONE_MILLION_CONTEXT_WINDOW_TOKENS
7256
+ };
7257
+ }
7258
+ for (const candidateId of [baseId, dottedBaseId]) {
7216
7259
  const base = findModelById(candidateId);
7217
7260
  if (base?.vendor === "Anthropic") return {
7218
7261
  model: base,
@@ -7928,11 +7971,13 @@ async function handleDirectAnthropicCompletion(c, anthropicPayload, ctx, initiat
7928
7971
  }
7929
7972
  } else if (state.autoTruncate && !selectedModel) consola.debug(`[Anthropic] Model '${anthropicPayload.model}' not found, skipping auto-truncate`);
7930
7973
  if (state.manualApprove) await awaitApproval();
7974
+ const clientAnthropicBetaHeader = c.req.header("anthropic-beta");
7931
7975
  try {
7932
7976
  const { result: response, queueWaitMs } = await executeWithAdaptiveRateLimit(() => createAnthropicMessages(effectivePayload, {
7933
7977
  initiator: initiatorOverride,
7934
7978
  injectContext1mBeta: needsContext1mBeta,
7935
- errorModelIdOverride: needsContext1mBeta ? originalModelId : void 0
7979
+ errorModelIdOverride: needsContext1mBeta ? originalModelId : void 0,
7980
+ clientAnthropicBetaHeader
7936
7981
  }));
7937
7982
  ctx.queueWaitMs = queueWaitMs;
7938
7983
  if (Symbol.asyncIterator in response) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dianshuv/copilot-api",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Turn GitHub Copilot into OpenAI/Anthropic API compatible server. Usable with Claude Code!",
5
5
  "author": "dianshuv",
6
6
  "type": "module",