@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 +68 -5
- package/dist/{accounts-manager-DellX80M.js → accounts-manager-iJwqQUkM.js} +221 -13
- package/dist/accounts-manager-iJwqQUkM.js.map +1 -0
- package/dist/main.js +15 -9
- package/dist/main.js.map +1 -1
- package/dist/{server-dAi_n8ee.js → server-BgJ8vqcw.js} +410 -80
- package/dist/server-BgJ8vqcw.js.map +1 -0
- package/package.json +1 -1
- package/dist/accounts-manager-DellX80M.js.map +0 -1
- package/dist/server-dAi_n8ee.js.map +0 -1
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 `
|
|
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 `
|
|
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
|
-
|
|
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
|
-
-
|
|
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
|
-
|
|
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.
|
|
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) =>
|
|
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(`${
|
|
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
|
-
|
|
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.
|
|
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(`${
|
|
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 {
|
|
1514
|
-
//# sourceMappingURL=accounts-manager-
|
|
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
|