@nick3/copilot-api 1.2.2 → 1.2.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/README.md CHANGED
@@ -43,6 +43,10 @@ A reverse-engineered proxy for the GitHub Copilot API that exposes it as an Open
43
43
  - **Flexible Authentication**: Authenticate interactively or provide a GitHub token directly, suitable for CI/CD environments.
44
44
  - **Support for Different Account Types**: Works with individual, business, and enterprise GitHub Copilot plans.
45
45
  - **Multi-Account Support**: Use multiple GitHub Copilot accounts with automatic routing: premium models use accounts in order and fall back on quota exhaustion; free models are distributed round-robin across accounts by default (configurable in config.json).
46
+ - **Opencode OAuth Support**: Use opencode GitHub Copilot authentication by setting `COPILOT_API_OAUTH_APP=opencode` environment variable.
47
+ - **GitHub Enterprise Support**: Connect to GHE.com by setting `COPILOT_API_ENTERPRISE_URL` environment variable (e.g., `company.ghe.com`).
48
+ - **Custom Data Directory**: Change the default data directory (where tokens and config are stored) by setting `COPILOT_API_HOME` environment variable.
49
+ - **Multi-Provider Anthropic Proxy Routes**: Add global provider configs and call external Anthropic-compatible APIs via `/:provider/v1/messages` and `/:provider/v1/models`.
46
50
 
47
51
  ## Demo
48
52
 
@@ -245,6 +249,17 @@ The `<target>` can be either the account ID (GitHub username) or a 1-based index
245
249
  "auth": {
246
250
  "apiKeys": []
247
251
  },
252
+ "providers": {
253
+ "openrouter": {
254
+ "type": "anthropic",
255
+ "enabled": true,
256
+ "baseUrl": "https://openrouter.ai/api",
257
+ "apiKey": "sk-your-provider-key",
258
+ "defaultTemperature": 0.7,
259
+ "defaultTopP": 0.9,
260
+ "defaultTopK": 20
261
+ }
262
+ },
248
263
  "extraPrompts": {
249
264
  "gpt-5-mini": "<built-in exploration prompt>",
250
265
  "gpt-5.1-codex-max": "<built-in exploration prompt>"
@@ -266,6 +281,13 @@ The `<target>` can be either the account ID (GitHub username) or a 1-based index
266
281
  ```
267
282
  - **auth.apiKeys:** API keys used for request authentication. Supports multiple keys for rotation. Requests can authenticate with either `x-api-key: <key>` or `Authorization: Bearer <key>`. If empty or omitted, authentication is disabled.
268
283
  - **extraPrompts:** Map of `model -> prompt` appended to the first system prompt when translating Anthropic-style requests to Copilot. Use this to inject guardrails or guidance per model. Missing default entries are auto-added without overwriting your custom prompts.
284
+ - **providers:** Global upstream provider map. Each provider key (for example `openrouter`) becomes a route prefix (`/openrouter/v1/messages`). Currently only `type: "anthropic"` is supported.
285
+ - `enabled` defaults to `true` if omitted.
286
+ - `baseUrl` should be provider API base URL without trailing `/v1/messages`.
287
+ - `apiKey` is used as upstream `x-api-key`.
288
+ - `defaultTemperature` (optional): Default temperature value used when the request does not specify one.
289
+ - `defaultTopP` (optional): Default top_p value used when the request does not specify one.
290
+ - `defaultTopK` (optional): Default top_k value used when the request does not specify one.
269
291
  - **smallModel:** Fallback model used for tool-less warmup messages (e.g., Claude Code probe requests) to avoid spending premium requests; defaults to `gpt-5-mini`. If original names are blocked and this points to an aliased target, it resolves to the first alias.
270
292
  - **freeModelLoadBalancing:** Enable round-robin routing for free-model requests across multiple accounts. Defaults to `true`. Set to `false` to route free-model requests sequentially (same ordering strategy as premium models).
271
293
  - **apiKey (deprecated):** Legacy single-key field kept for migration compatibility. Prefer `auth.apiKeys`. When `auth.apiKeys` is empty, the server falls back to `COPILOT_API_KEY` and then `apiKey`.
@@ -319,6 +341,9 @@ These endpoints are designed to be compatible with the Anthropic Messages API.
319
341
  | -------------------------------- | ------ | ------------------------------------------------------------ |
320
342
  | `POST /v1/messages` | `POST` | Creates a model response for a given conversation. |
321
343
  | `POST /v1/messages/count_tokens` | `POST` | Calculates the number of tokens for a given set of messages. |
344
+ | `POST /:provider/v1/messages` | `POST` | Proxies Anthropic Messages API to the configured provider. |
345
+ | `GET /:provider/v1/models` | `GET` | Proxies Anthropic Models API to the configured provider. |
346
+ | `POST /:provider/v1/messages/count_tokens` | `POST` | Calculates tokens locally for provider route requests. |
322
347
 
323
348
  ### Usage Monitoring Endpoints
324
349
 
@@ -445,6 +470,28 @@ npx @nick3/copilot-api@latest debug --json
445
470
 
446
471
  # Initialize proxy from environment variables (HTTP_PROXY, HTTPS_PROXY, etc.)
447
472
  npx @nick3/copilot-api@latest start --proxy-env
473
+
474
+ # Use opencode GitHub Copilot authentication
475
+ COPILOT_API_OAUTH_APP=opencode npx @nick3/copilot-api@latest start
476
+ ```
477
+
478
+ ### Opencode OAuth Authentication
479
+
480
+ You can use opencode GitHub Copilot authentication instead of the default one:
481
+
482
+ ```sh
483
+ # Set environment variable before running any command
484
+ export COPILOT_API_OAUTH_APP=opencode
485
+
486
+ # Then run start or auth commands
487
+ npx @nick3/copilot-api@latest start
488
+ npx @nick3/copilot-api@latest auth
489
+ ```
490
+
491
+ Or use inline environment variable:
492
+
493
+ ```sh
494
+ COPILOT_API_OAUTH_APP=opencode npx @nick3/copilot-api@latest start
448
495
  ```
449
496
 
450
497
  ### Admin API examples
@@ -574,7 +621,7 @@ You can also read more about IDE integration here: [Add Claude Code to your IDE]
574
621
 
575
622
  ### Subagent Marker Integration (Optional)
576
623
 
577
- This project supports `X-Initiator: agent` for subagent-originated requests.
624
+ This project supports `x-initiator: agent` for subagent-originated requests.
578
625
 
579
626
  #### Claude Code plugin producer (marketplace-based)
580
627
 
@@ -595,15 +642,31 @@ Install the plugin from the marketplace:
595
642
  /plugin install claude-plugin@copilot-api-marketplace
596
643
  ```
597
644
 
598
- After installation, the plugin injects `__SUBAGENT_MARKER__...` on `SubagentStart`, and this proxy uses it to infer `X-Initiator: agent`.
645
+ After installation, the plugin injects `__SUBAGENT_MARKER__...` on `SubagentStart`, and this proxy uses it to infer `x-initiator: agent`.
599
646
 
600
647
  #### Opencode plugin producer
601
648
 
602
- For opencode, use the plugin implementation at:
649
+ The marker producer is packaged as an opencode plugin located at `.opencode/plugins/subagent-marker.js`.
650
+
651
+ **Installation:**
652
+
653
+ Copy the plugin file to your opencode plugins directory:
654
+
655
+ ```sh
656
+ # Clone or download this repository, then copy the plugin
657
+ cp .opencode/plugins/subagent-marker.js ~/.config/opencode/plugins/
658
+ ```
659
+
660
+ Or manually create the file at `~/.config/opencode/plugins/subagent-marker.js` with the plugin content.
661
+
662
+ **Features:**
603
663
 
604
- - `.opencode/plugins/subagent-marker.js`
664
+ - Tracks sub-sessions created by subagents
665
+ - Automatically prepends a marker system reminder (`__SUBAGENT_MARKER__...`) to subagent chat messages
666
+ - Sets `x-session-id` header for session tracking
667
+ - Enables this proxy to infer `x-initiator: agent` for subagent-originated requests
605
668
 
606
- This plugin tracks sub-sessions and prepends a marker system reminder to subagent chat messages.
669
+ The plugin hooks into `session.created`, `session.deleted`, `chat.message`, and `chat.headers` events to provide seamless subagent marker functionality.
607
670
 
608
671
  ## Running from Source
609
672
 
@@ -1,15 +1,17 @@
1
1
  import consola from "consola";
2
2
  import fs from "node:fs/promises";
3
3
  import { z } from "zod";
4
- import os from "node:os";
4
+ import os, { networkInterfaces } from "node:os";
5
5
  import path from "node:path";
6
- import { randomUUID } from "node:crypto";
6
+ import { createHash, randomUUID } from "node:crypto";
7
7
  import fs$1 from "node:fs";
8
8
 
9
9
  //#region src/lib/paths.ts
10
+ const AUTH_APP = process.env.COPILOT_API_OAUTH_APP?.trim() || "";
11
+ const ENTERPRISE_PREFIX = process.env.COPILOT_API_ENTERPRISE_URL ? "ent_" : "";
10
12
  const DEFAULT_DIR = path.join(os.homedir(), ".local", "share", "copilot-api");
11
13
  const APP_DIR = process.env.COPILOT_API_HOME || DEFAULT_DIR;
12
- const GITHUB_TOKEN_PATH = path.join(APP_DIR, "github_token");
14
+ const GITHUB_TOKEN_PATH = path.join(APP_DIR, AUTH_APP, ENTERPRISE_PREFIX + "github_token");
13
15
  const CONFIG_PATH = path.join(APP_DIR, "config.json");
14
16
  const MODELS_PATH = path.join(APP_DIR, "models.json");
15
17
  const TOKENS_DIR = path.join(APP_DIR, "tokens");
@@ -32,6 +34,7 @@ function accountTokenPath(id) {
32
34
  }
33
35
  async function ensurePaths() {
34
36
  await fs.mkdir(PATHS.APP_DIR, { recursive: true });
37
+ await fs.mkdir(path.join(PATHS.APP_DIR, AUTH_APP), { recursive: true });
35
38
  await fs.mkdir(PATHS.TOKENS_DIR, { recursive: true });
36
39
  await ensureFile(PATHS.GITHUB_TOKEN_PATH);
37
40
  await ensureFile(PATHS.CONFIG_PATH);
@@ -245,16 +248,82 @@ function accountFromState() {
245
248
 
246
249
  //#endregion
247
250
  //#region src/lib/api-config.ts
251
+ const isOpencodeOauthApp = () => {
252
+ return process.env.COPILOT_API_OAUTH_APP?.trim() === "opencode";
253
+ };
254
+ const normalizeDomain = (input) => {
255
+ return input.trim().replace(/^https?:\/\//u, "").replace(/\/+$/u, "");
256
+ };
257
+ const getEnterpriseDomain = () => {
258
+ const raw = (process.env.COPILOT_API_ENTERPRISE_URL ?? "").trim();
259
+ if (!raw) return null;
260
+ return normalizeDomain(raw) || null;
261
+ };
262
+ const getGitHubBaseUrl = () => {
263
+ const resolvedDomain = getEnterpriseDomain();
264
+ return resolvedDomain ? `https://${resolvedDomain}` : GITHUB_BASE_URL;
265
+ };
266
+ const getGitHubApiBaseUrl = () => {
267
+ const resolvedDomain = getEnterpriseDomain();
268
+ return resolvedDomain ? `https://${resolvedDomain}/api/v3` : GITHUB_API_BASE_URL;
269
+ };
270
+ const getOpencodeOauthHeaders = () => {
271
+ return {
272
+ Accept: "application/json",
273
+ "Content-Type": "application/json",
274
+ "User-Agent": "opencode/1.2.16 ai-sdk/provider-utils/3.0.21 runtime/bun/1.3.10, opencode/1.2.16"
275
+ };
276
+ };
277
+ const getOauthUrls = () => {
278
+ const githubBaseUrl = getGitHubBaseUrl();
279
+ return {
280
+ deviceCodeUrl: `${githubBaseUrl}/login/device/code`,
281
+ accessTokenUrl: `${githubBaseUrl}/login/oauth/access_token`
282
+ };
283
+ };
284
+ const getOauthAppConfig = () => {
285
+ if (isOpencodeOauthApp()) return {
286
+ clientId: OPENCODE_GITHUB_CLIENT_ID,
287
+ headers: getOpencodeOauthHeaders(),
288
+ scope: GITHUB_APP_SCOPES
289
+ };
290
+ return {
291
+ clientId: GITHUB_CLIENT_ID,
292
+ headers: standardHeaders(),
293
+ scope: GITHUB_APP_SCOPES
294
+ };
295
+ };
296
+ const prepareInteractionHeaders = (sessionId, isSubagent, headers) => {
297
+ const sendInteractionHeaders = !isOpencodeOauthApp();
298
+ if (isSubagent) {
299
+ headers["x-initiator"] = "agent";
300
+ if (sendInteractionHeaders) headers["x-interaction-type"] = "conversation-subagent";
301
+ }
302
+ if (sessionId && sendInteractionHeaders) headers["x-interaction-id"] = sessionId;
303
+ };
248
304
  const standardHeaders = () => ({
249
305
  "content-type": "application/json",
250
306
  accept: "application/json"
251
307
  });
252
- const COPILOT_VERSION = "0.37.6";
308
+ const COPILOT_VERSION = "0.38.2";
253
309
  const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
254
310
  const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
255
311
  const API_VERSION = "2025-10-01";
256
- const copilotBaseUrl = (account) => account.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${account.accountType}.githubcopilot.com`;
312
+ const copilotBaseUrl = (account) => {
313
+ const enterpriseDomain = getEnterpriseDomain();
314
+ if (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;
315
+ return account.accountType === "individual" ? "https://api.githubcopilot.com" : `https://api.${account.accountType}.githubcopilot.com`;
316
+ };
257
317
  const copilotHeaders = (account, vision = false, requestId) => {
318
+ if (isOpencodeOauthApp()) {
319
+ const headers$1 = {
320
+ Authorization: `Bearer ${account.copilotToken ?? account.githubToken}`,
321
+ ...getOpencodeOauthHeaders(),
322
+ "Openai-Intent": "conversation-edits"
323
+ };
324
+ if (vision) headers$1["Copilot-Vision-Request"] = "true";
325
+ return headers$1;
326
+ }
258
327
  const resolvedRequestId = requestId ?? randomUUID();
259
328
  const headers = {
260
329
  Authorization: `Bearer ${account.copilotToken}`,
@@ -266,9 +335,13 @@ const copilotHeaders = (account, vision = false, requestId) => {
266
335
  "openai-intent": "conversation-agent",
267
336
  "x-github-api-version": API_VERSION,
268
337
  "x-request-id": resolvedRequestId,
269
- "x-vscode-user-agent-library-version": "electron-fetch"
338
+ "x-vscode-user-agent-library-version": "electron-fetch",
339
+ "x-agent-task-id": resolvedRequestId,
340
+ "x-interaction-type": "conversation-agent"
270
341
  };
271
342
  if (vision) headers["copilot-vision-request"] = "true";
343
+ if (state.macMachineId) headers["vscode-machineid"] = state.macMachineId;
344
+ if (state.vsCodeSessionId) headers["vscode-sessionid"] = state.vsCodeSessionId;
272
345
  return headers;
273
346
  };
274
347
  const GITHUB_API_BASE_URL = "https://api.github.com";
@@ -284,6 +357,7 @@ const githubHeaders = (account) => ({
284
357
  const GITHUB_BASE_URL = "https://github.com";
285
358
  const GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98";
286
359
  const GITHUB_APP_SCOPES = ["read:user"].join(" ");
360
+ const OPENCODE_GITHUB_CLIENT_ID = "Ov23li8tweQw6odWQebz";
287
361
 
288
362
  //#endregion
289
363
  //#region src/lib/error.ts
@@ -320,7 +394,7 @@ async function forwardError(c, error) {
320
394
  //#region src/services/github/get-copilot-usage.ts
321
395
  const getCopilotUsage = async (account) => {
322
396
  const ctx = account ?? accountFromState();
323
- const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, { headers: githubHeaders(ctx) });
397
+ const response = await fetch(`${getGitHubApiBaseUrl()}/copilot_internal/user`, { headers: githubHeaders(ctx) });
324
398
  if (!response.ok) throw new HTTPError("Failed to get Copilot usage", response);
325
399
  return await response.json();
326
400
  };
@@ -329,7 +403,8 @@ const getCopilotUsage = async (account) => {
329
403
  //#region src/services/github/get-user.ts
330
404
  async function getGitHubUser(account) {
331
405
  const token = account?.githubToken ?? state.githubToken;
332
- const response = await fetch(`${GITHUB_API_BASE_URL}/user`, { headers: {
406
+ if (!token) throw new Error("GitHub token not set");
407
+ const response = await fetch(`${getGitHubApiBaseUrl()}/user`, { headers: {
333
408
  authorization: `token ${token}`,
334
409
  ...standardHeaders()
335
410
  } });
@@ -356,7 +431,7 @@ const getModels = async (account) => {
356
431
 
357
432
  //#endregion
358
433
  //#region src/services/get-vscode-version.ts
359
- const FALLBACK = "1.109.3";
434
+ const FALLBACK = "1.110.1";
360
435
  async function getVSCodeVersion() {
361
436
  await Promise.resolve();
362
437
  return FALLBACK;
@@ -373,12 +448,106 @@ const cacheVSCodeVersion = async () => {
373
448
  state.vsCodeVersion = response;
374
449
  consola.info(`Using VSCode version: ${response}`);
375
450
  };
451
+ const invalidMacAddresses = new Set([
452
+ "00:00:00:00:00:00",
453
+ "ff:ff:ff:ff:ff:ff",
454
+ "ac:de:48:00:11:22"
455
+ ]);
456
+ function validateMacAddress(candidate) {
457
+ const tempCandidate = candidate.replaceAll("-", ":").toLowerCase();
458
+ return !invalidMacAddresses.has(tempCandidate);
459
+ }
460
+ function getMac() {
461
+ const ifaces = networkInterfaces();
462
+ for (const name in ifaces) {
463
+ const networkInterface = ifaces[name];
464
+ if (networkInterface) {
465
+ for (const { mac } of networkInterface) if (validateMacAddress(mac)) return mac;
466
+ }
467
+ }
468
+ return null;
469
+ }
470
+ const cacheMacMachineId = () => {
471
+ const macAddress = getMac() ?? randomUUID();
472
+ state.macMachineId = createHash("sha256").update(macAddress, "utf8").digest("hex");
473
+ consola.debug(`Using machine ID: ${state.macMachineId}`);
474
+ };
475
+ const SESSION_REFRESH_BASE_MS = 3600 * 1e3;
476
+ const SESSION_REFRESH_JITTER_MS = 1200 * 1e3;
477
+ let vsCodeSessionRefreshTimer = null;
478
+ const generateSessionId = () => {
479
+ state.vsCodeSessionId = randomUUID() + Date.now().toString();
480
+ consola.debug(`Generated VSCode session ID: ${state.vsCodeSessionId}`);
481
+ };
482
+ const stopVsCodeSessionRefreshLoop = () => {
483
+ if (vsCodeSessionRefreshTimer) {
484
+ clearTimeout(vsCodeSessionRefreshTimer);
485
+ vsCodeSessionRefreshTimer = null;
486
+ }
487
+ };
488
+ const scheduleSessionIdRefresh = () => {
489
+ const randomDelay = Math.floor(Math.random() * SESSION_REFRESH_JITTER_MS);
490
+ const delay = SESSION_REFRESH_BASE_MS + randomDelay;
491
+ consola.debug(`Scheduling next VSCode session ID refresh in ${Math.round(delay / 1e3)} seconds`);
492
+ stopVsCodeSessionRefreshLoop();
493
+ vsCodeSessionRefreshTimer = setTimeout(() => {
494
+ try {
495
+ generateSessionId();
496
+ } catch (error) {
497
+ consola.error("Failed to refresh session ID, rescheduling...", error);
498
+ } finally {
499
+ scheduleSessionIdRefresh();
500
+ }
501
+ }, delay);
502
+ };
503
+ const cacheVsCodeSessionId = () => {
504
+ stopVsCodeSessionRefreshLoop();
505
+ generateSessionId();
506
+ scheduleSessionIdRefresh();
507
+ };
508
+ const findLastUserContent = (messages) => {
509
+ for (let i = messages.length - 1; i >= 0; i--) {
510
+ const msg = messages[i];
511
+ if (msg.role === "user" && msg.content) {
512
+ if (typeof msg.content === "string") return msg.content;
513
+ else if (Array.isArray(msg.content)) {
514
+ const array = msg.content.filter((n) => n.type !== "tool_result").map((n) => ({
515
+ ...n,
516
+ cache_control: void 0
517
+ }));
518
+ if (array.length > 0) return JSON.stringify(array);
519
+ }
520
+ }
521
+ }
522
+ return null;
523
+ };
524
+ const generateRequestIdFromPayload = (payload, sessionId) => {
525
+ const messages = payload.messages;
526
+ if (messages) {
527
+ const lastUserContent = typeof messages === "string" ? messages : findLastUserContent(messages);
528
+ if (lastUserContent) return getUUID((sessionId ?? "") + (state.macMachineId ?? "") + lastUserContent);
529
+ }
530
+ return randomUUID();
531
+ };
532
+ const getRootSessionId = (anthropicPayload, c) => {
533
+ let sessionId;
534
+ if (anthropicPayload.metadata?.user_id) {
535
+ const sessionMatch = (/* @__PURE__ */ new RegExp(/_session_(.+)$/)).exec(anthropicPayload.metadata.user_id);
536
+ sessionId = sessionMatch ? sessionMatch[1] : void 0;
537
+ } else sessionId = c.req.header("x-session-id");
538
+ if (sessionId) return getUUID(sessionId);
539
+ return sessionId;
540
+ };
541
+ const getUUID = (content) => {
542
+ const hash32 = createHash("sha256").update(content).digest("hex").slice(0, 32);
543
+ return `${hash32.slice(0, 8)}-${hash32.slice(8, 12)}-${hash32.slice(12, 16)}-${hash32.slice(16, 20)}-${hash32.slice(20)}`;
544
+ };
376
545
 
377
546
  //#endregion
378
547
  //#region src/services/github/get-copilot-token.ts
379
548
  const getCopilotToken = async (account) => {
380
549
  const ctx = account ?? accountFromState();
381
- const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/v2/token`, { headers: githubHeaders(ctx) });
550
+ const response = await fetch(`${getGitHubApiBaseUrl()}/copilot_internal/v2/token`, { headers: githubHeaders(ctx) });
382
551
  if (!response.ok) throw new HTTPError("Failed to get Copilot token", response);
383
552
  return await response.json();
384
553
  };
@@ -412,6 +581,7 @@ You interact with the user through a terminal. You have 2 ways of communicating
412
581
  - Tone of your updates MUST match your personality.`;
413
582
  const defaultConfig = {
414
583
  auth: { apiKeys: [] },
584
+ providers: {},
415
585
  extraPrompts: {
416
586
  "gpt-5-mini": gpt5ExplorationPrompt,
417
587
  "gpt-5.3-codex": gpt5CommentaryPrompt,
@@ -419,9 +589,11 @@ const defaultConfig = {
419
589
  },
420
590
  smallModel: "gpt-5-mini",
421
591
  freeModelLoadBalancing: true,
592
+ responsesApiContextManagementModels: [],
422
593
  modelReasoningEfforts: {
423
594
  "gpt-5-mini": "low",
424
- "gpt-5.3-codex": "xhigh"
595
+ "gpt-5.3-codex": "xhigh",
596
+ "gpt-5.4": "xhigh"
425
597
  },
426
598
  allowOriginalModelNamesForAliases: false,
427
599
  useFunctionApplyPatch: true,
@@ -691,6 +863,12 @@ function getModelRefreshIntervalMs() {
691
863
  function isMessageStartInputTokensFallbackEnabled() {
692
864
  return getConfig().messageStartInputTokensFallback ?? false;
693
865
  }
866
+ function getResponsesApiContextManagementModels() {
867
+ return getConfig().responsesApiContextManagementModels ?? defaultConfig.responsesApiContextManagementModels ?? [];
868
+ }
869
+ function isResponsesApiContextManagementModel(model) {
870
+ return getResponsesApiContextManagementModels().includes(model);
871
+ }
694
872
  function getReasoningEffortForModel(model) {
695
873
  const config = getConfig();
696
874
  const direct = config.modelReasoningEfforts?.[model];
@@ -704,6 +882,36 @@ function isForceAgentEnabled() {
704
882
  function shouldCompactUseSmallModel() {
705
883
  return getConfig().compactUseSmallModel ?? true;
706
884
  }
885
+ function normalizeProviderBaseUrl(url) {
886
+ return url.trim().replace(/\/+$/u, "");
887
+ }
888
+ function getProviderConfig(name) {
889
+ const providerName = name.trim();
890
+ if (!providerName) return null;
891
+ const provider = getConfig().providers?.[providerName];
892
+ if (!provider) return null;
893
+ if (provider.enabled === false) return null;
894
+ const type = provider.type ?? "anthropic";
895
+ if (type !== "anthropic") {
896
+ consola.warn(`Provider ${providerName} is ignored because only anthropic type is supported`);
897
+ return null;
898
+ }
899
+ const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? "");
900
+ const apiKey = (provider.apiKey ?? "").trim();
901
+ if (!baseUrl || !apiKey) {
902
+ consola.warn(`Provider ${providerName} is enabled but missing baseUrl or apiKey`);
903
+ return null;
904
+ }
905
+ return {
906
+ name: providerName,
907
+ type,
908
+ baseUrl,
909
+ apiKey,
910
+ defaultTemperature: provider.defaultTemperature,
911
+ defaultTopP: provider.defaultTopP,
912
+ defaultTopK: provider.defaultTopK
913
+ };
914
+ }
707
915
 
708
916
  //#endregion
709
917
  //#region src/lib/accounts-manager-auth.ts
@@ -1510,5 +1718,5 @@ var AccountsManager = class {
1510
1718
  const accountsManager = new AccountsManager();
1511
1719
 
1512
1720
  //#endregion
1513
- export { GITHUB_APP_SCOPES, GITHUB_BASE_URL, GITHUB_CLIENT_ID, HTTPError, PATHS, accountFromState, accountsManager, addAccountToRegistry, cacheVSCodeVersion, copilotBaseUrl, copilotHeaders, ensurePaths, forwardError, getAliasTargetSet, getConfig, getCopilotUsage, getExtraPromptForModel, getGitHubUser, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getReasoningEffortForModel, getSmallModel, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isNullish, listAccountsFromRegistry, loadAccountToken, mergeConfigWithDefaults, removeAccountFromRegistry, removeAccountToken, saveAccountToken, saveRegistry, shouldCompactUseSmallModel, sleep, standardHeaders, state };
1514
- //# sourceMappingURL=accounts-manager-DellX80M.js.map
1721
+ export { HTTPError, PATHS, accountFromState, accountsManager, addAccountToRegistry, cacheMacMachineId, cacheVSCodeVersion, cacheVsCodeSessionId, copilotBaseUrl, copilotHeaders, ensurePaths, forwardError, generateRequestIdFromPayload, getAliasTargetSet, getConfig, getCopilotUsage, getExtraPromptForModel, getGitHubUser, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getOauthAppConfig, getOauthUrls, getProviderConfig, getReasoningEffortForModel, getRootSessionId, getSmallModel, getUUID, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isNullish, isResponsesApiContextManagementModel, listAccountsFromRegistry, loadAccountToken, mergeConfigWithDefaults, prepareInteractionHeaders, removeAccountFromRegistry, removeAccountToken, saveAccountToken, saveRegistry, shouldCompactUseSmallModel, sleep, state };
1722
+ //# sourceMappingURL=accounts-manager-iJwqQUkM.js.map