@nick3/copilot-api 1.1.3 → 1.1.6
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 +41 -1
- package/dist/{accounts-manager-CfBWqxBl.js → accounts-manager-MluR5e6y.js} +4 -7
- package/dist/accounts-manager-MluR5e6y.js.map +1 -0
- package/dist/main.js +2 -2
- package/dist/{server-2YTgFCW0.js → server-6hnk3aRJ.js} +73 -15
- package/dist/server-6hnk3aRJ.js.map +1 -0
- package/package.json +1 -1
- package/dist/accounts-manager-CfBWqxBl.js.map +0 -1
- package/dist/server-2YTgFCW0.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Copilot API Proxy
|
|
2
2
|
|
|
3
|
+
English | [中文](./README_CN.md)
|
|
4
|
+
|
|
3
5
|
> [!WARNING]
|
|
4
6
|
> This is a reverse-engineered proxy of GitHub Copilot API. It is not supported by GitHub, and may break unexpectedly. Use at your own risk.
|
|
5
7
|
|
|
@@ -556,7 +558,6 @@ Here is an example `.claude/settings.json` file:
|
|
|
556
558
|
"ANTHROPIC_MODEL": "gpt-5.2",
|
|
557
559
|
"ANTHROPIC_DEFAULT_SONNET_MODEL": "gpt-5.2",
|
|
558
560
|
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "gpt-5-mini",
|
|
559
|
-
"CLAUDE_CODE_SUBAGENT_MODEL": "gpt-5-mini",
|
|
560
561
|
"DISABLE_NON_ESSENTIAL_MODEL_CALLS": "1",
|
|
561
562
|
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
|
|
562
563
|
"BASH_MAX_TIMEOUT_MS": "600000",
|
|
@@ -582,6 +583,45 @@ You can find more options here: [Claude Code settings](https://docs.anthropic.co
|
|
|
582
583
|
|
|
583
584
|
You can also read more about IDE integration here: [Add Claude Code to your IDE](https://docs.anthropic.com/en/docs/claude-code/ide-integrations)
|
|
584
585
|
|
|
586
|
+
### Subagent Marker Integration (Optional)
|
|
587
|
+
|
|
588
|
+
This project supports `X-Initiator: agent` for subagent-originated requests
|
|
589
|
+
|
|
590
|
+
#### Claude Code hook producer
|
|
591
|
+
|
|
592
|
+
Use the included hook script to inject marker context on `SubagentStart`.
|
|
593
|
+
If you place the script under your user Claude directory (`~/.claude/hooks`), use this cross-platform command in `.claude/settings.json`:
|
|
594
|
+
|
|
595
|
+
- `.claude/hooks/subagent-start-marker.js`
|
|
596
|
+
|
|
597
|
+
And enable it from `.claude/settings.json`:
|
|
598
|
+
|
|
599
|
+
```json
|
|
600
|
+
{
|
|
601
|
+
"hooks": {
|
|
602
|
+
"SubagentStart": [
|
|
603
|
+
{
|
|
604
|
+
"matcher": "*",
|
|
605
|
+
"hooks": [
|
|
606
|
+
{
|
|
607
|
+
"type": "command",
|
|
608
|
+
"command": "node --input-type=module -e \"import { homedir } from 'node:os'; import { join } from 'node:path'; import { readFile } from 'node:fs/promises'; const file = join(homedir(), '.claude', 'hooks', 'subagent-start-marker.js'); const source = await readFile(file, 'utf8'); const url = 'data:text/javascript;base64,' + Buffer.from(source).toString('base64'); await import(url);\""
|
|
609
|
+
}
|
|
610
|
+
]
|
|
611
|
+
}
|
|
612
|
+
]
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
#### Opencode plugin producer
|
|
618
|
+
|
|
619
|
+
For opencode, use the plugin implementation at:
|
|
620
|
+
|
|
621
|
+
- `.opencode/plugins/subagent-marker.js`
|
|
622
|
+
|
|
623
|
+
This plugin tracks sub-sessions and prepends a marker system reminder to subagent chat messages.
|
|
624
|
+
|
|
585
625
|
## Running from Source
|
|
586
626
|
|
|
587
627
|
The project can be run from source in several ways:
|
|
@@ -248,7 +248,7 @@ const standardHeaders = () => ({
|
|
|
248
248
|
"content-type": "application/json",
|
|
249
249
|
accept: "application/json"
|
|
250
250
|
});
|
|
251
|
-
const COPILOT_VERSION = "0.37.
|
|
251
|
+
const COPILOT_VERSION = "0.37.6";
|
|
252
252
|
const EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`;
|
|
253
253
|
const USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`;
|
|
254
254
|
const API_VERSION = "2025-10-01";
|
|
@@ -355,7 +355,7 @@ const getModels = async (account) => {
|
|
|
355
355
|
|
|
356
356
|
//#endregion
|
|
357
357
|
//#region src/services/get-vscode-version.ts
|
|
358
|
-
const FALLBACK = "1.109.
|
|
358
|
+
const FALLBACK = "1.109.3";
|
|
359
359
|
async function getVSCodeVersion() {
|
|
360
360
|
const controller = new AbortController();
|
|
361
361
|
const timeout = setTimeout(() => {
|
|
@@ -363,10 +363,7 @@ async function getVSCodeVersion() {
|
|
|
363
363
|
}, 5e3);
|
|
364
364
|
try {
|
|
365
365
|
const match = (await (await fetch("https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=visual-studio-code-bin", { signal: controller.signal })).text()).match(/pkgver=([0-9.]+)/);
|
|
366
|
-
if (match)
|
|
367
|
-
if (match[1] === "1.109.0") return FALLBACK;
|
|
368
|
-
return match[1];
|
|
369
|
-
}
|
|
366
|
+
if (match) return match[1];
|
|
370
367
|
return FALLBACK;
|
|
371
368
|
} catch {
|
|
372
369
|
return FALLBACK;
|
|
@@ -1512,4 +1509,4 @@ const accountsManager = new AccountsManager();
|
|
|
1512
1509
|
|
|
1513
1510
|
//#endregion
|
|
1514
1511
|
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 };
|
|
1515
|
-
//# sourceMappingURL=accounts-manager-
|
|
1512
|
+
//# sourceMappingURL=accounts-manager-MluR5e6y.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts-manager-MluR5e6y.js","names":["parsed: unknown","index: number","state: State","headers: Record<string, string>","errorJson: unknown","defaultConfig: AppConfig","cachedConfig: AppConfig | null","fs","normalizedTarget","normalized: ModelAliasInfoMap","normalized: ModelAliasMap","runtime: AccountRuntime","accounts: Array<AccountRuntime>","overageFallback:\n | {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }\n | undefined","statuses: Array<{\n id: string\n entitlement?: number\n remaining?: number\n unlimited?: boolean\n overagePermitted?: boolean\n failed?: boolean\n failureReason?: string\n }>","allAccounts: Array<AccountRuntime>","fs","added: Array<string>","removed: Array<string>","updated: Array<string>","changes: Array<string>"],"sources":["../src/lib/paths.ts","../src/lib/accounts-registry.ts","../src/lib/state.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/services/github/get-copilot-usage.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/get-copilot-token.ts","../src/lib/config.ts","../src/lib/accounts-manager-auth.ts","../src/lib/accounts-manager-quota.ts","../src/lib/accounts-manager.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\", \"copilot-api\")\n\nconst GITHUB_TOKEN_PATH = path.join(APP_DIR, \"github_token\")\nconst CONFIG_PATH = path.join(APP_DIR, \"config.json\")\nconst MODELS_PATH = path.join(APP_DIR, \"models.json\")\n\n// Multi-account paths\nconst TOKENS_DIR = path.join(APP_DIR, \"tokens\")\nconst ACCOUNTS_REGISTRY_PATH = path.join(APP_DIR, \"accounts-registry.json\")\n\nexport const PATHS = {\n APP_DIR,\n GITHUB_TOKEN_PATH,\n CONFIG_PATH,\n MODELS_PATH,\n TOKENS_DIR,\n ACCOUNTS_REGISTRY_PATH,\n}\n\n/**\n * Get the token file path for a specific account.\n * @param id - The account ID (GitHub login)\n * @returns The absolute path to the account's token file\n */\nexport function accountTokenPath(id: string): string {\n return path.join(TOKENS_DIR, `github_${id}`)\n}\n\nexport async function ensurePaths(): Promise<void> {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await fs.mkdir(PATHS.TOKENS_DIR, { recursive: true })\n await ensureFile(PATHS.GITHUB_TOKEN_PATH)\n await ensureFile(PATHS.CONFIG_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 fs from \"node:fs/promises\"\nimport { z } from \"zod\"\n\nimport type { AccountMeta, AccountRegistry } from \"~/lib/types/account\"\n\nimport { accountTokenPath, PATHS } from \"./paths\"\n\n/**\n * Validate account ID (GitHub login).\n * Rules:\n * - Only alphanumeric characters or single hyphens\n * - 1-39 chars\n * - Cannot begin or end with a hyphen\n * - No consecutive hyphens\n */\nexport function validateAccountId(id: string): boolean {\n if (id.length === 0 || id.length > 39) return false\n if (!/^[a-z0-9-]+$/i.test(id)) return false\n if (id.startsWith(\"-\") || id.endsWith(\"-\")) return false\n if (id.includes(\"--\")) return false\n return true\n}\n\nconst accountMetaSchema = z.object({\n id: z.string().refine(validateAccountId, {\n message:\n \"Invalid account id. Expected a GitHub login (1-39 chars, alphanumeric or single hyphens, no leading/trailing hyphen, no consecutive hyphens).\",\n }),\n accountType: z.enum([\"individual\", \"business\", \"enterprise\"]),\n addedAt: z.number(),\n})\n\nconst accountRegistrySchema = z.object({\n version: z.literal(1),\n accounts: z.array(accountMetaSchema),\n})\n\n/**\n * Create an empty registry with the current schema version.\n */\nfunction createEmptyRegistry(): AccountRegistry {\n return {\n version: 1,\n accounts: [],\n }\n}\n\n/**\n * Load the accounts registry from disk.\n * Returns an empty registry if the file doesn't exist.\n */\nexport async function loadRegistry(): Promise<AccountRegistry> {\n try {\n const content = await fs.readFile(PATHS.ACCOUNTS_REGISTRY_PATH, \"utf8\")\n if (!content.trim()) {\n return createEmptyRegistry()\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(content) as unknown\n } catch (error) {\n throw new Error(\n `Invalid accounts registry JSON at ${PATHS.ACCOUNTS_REGISTRY_PATH}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n }\n\n const result = accountRegistrySchema.safeParse(parsed)\n if (!result.success) {\n const issues = result.error.issues\n .map((issue) => `${issue.path.join(\".\")}: ${issue.message}`)\n .join(\"; \")\n\n throw new Error(\n `Invalid accounts registry at ${PATHS.ACCOUNTS_REGISTRY_PATH}: ${issues}`,\n )\n }\n\n const registry = result.data\n\n const seen = new Set<string>()\n for (const account of registry.accounts) {\n if (seen.has(account.id)) {\n throw new Error(\n `Invalid accounts registry at ${PATHS.ACCOUNTS_REGISTRY_PATH}: duplicate account id \"${account.id}\"`,\n )\n }\n seen.add(account.id)\n }\n\n return registry\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return createEmptyRegistry()\n }\n throw error\n }\n}\n\n/**\n * Save the accounts registry to disk with secure permissions.\n */\nexport async function saveRegistry(registry: AccountRegistry): Promise<void> {\n const content = JSON.stringify(registry, null, 2)\n await fs.writeFile(PATHS.ACCOUNTS_REGISTRY_PATH, content, { mode: 0o600 })\n}\n\n/**\n * Add an account to the registry.\n * The account is appended to the end of the list (lowest priority).\n */\nexport async function addAccountToRegistry(meta: AccountMeta): Promise<void> {\n if (!validateAccountId(meta.id)) {\n throw new Error(`Invalid account ID: ${meta.id}`)\n }\n\n const registry = await loadRegistry()\n\n // Check for duplicate\n if (registry.accounts.some((a) => a.id === meta.id)) {\n throw new Error(`Account already exists: ${meta.id}`)\n }\n\n registry.accounts.push(meta)\n await saveRegistry(registry)\n}\n\n/**\n * Remove an account from the registry by ID or index (1-based).\n * Returns the removed account metadata.\n */\nexport async function removeAccountFromRegistry(\n idOrIndex: string | number,\n): Promise<AccountMeta> {\n const registry = await loadRegistry()\n let index: number\n\n if (typeof idOrIndex === \"number\") {\n // 1-based index\n index = idOrIndex - 1\n if (index < 0 || index >= registry.accounts.length) {\n throw new Error(`Invalid account index: ${idOrIndex}`)\n }\n } else {\n index = registry.accounts.findIndex((a) => a.id === idOrIndex)\n if (index === -1) {\n throw new Error(`Account not found: ${idOrIndex}`)\n }\n }\n\n const [removed] = registry.accounts.splice(index, 1)\n await saveRegistry(registry)\n return removed\n}\n\n/**\n * List all accounts from the registry.\n */\nexport async function listAccountsFromRegistry(): Promise<Array<AccountMeta>> {\n const registry = await loadRegistry()\n return registry.accounts\n}\n\n/**\n * Load the GitHub token for a specific account.\n * Returns null if the token file doesn't exist.\n */\nexport async function loadAccountToken(id: string): Promise<string | null> {\n if (!validateAccountId(id)) {\n throw new Error(`Invalid account ID: ${id}`)\n }\n\n try {\n const tokenPath = accountTokenPath(id)\n const token = await fs.readFile(tokenPath, \"utf8\")\n return token.trim() || null\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null\n }\n throw error\n }\n}\n\n/**\n * Save the GitHub token for a specific account with secure permissions.\n */\nexport async function saveAccountToken(\n id: string,\n token: string,\n): Promise<void> {\n if (!validateAccountId(id)) {\n throw new Error(`Invalid account ID: ${id}`)\n }\n\n const tokenPath = accountTokenPath(id)\n await fs.writeFile(tokenPath, token, { mode: 0o600 })\n}\n\n/**\n * Remove the GitHub token file for a specific account.\n */\nexport async function removeAccountToken(id: string): Promise<void> {\n if (!validateAccountId(id)) {\n throw new Error(`Invalid account ID: ${id}`)\n }\n\n const tokenPath = accountTokenPath(id)\n try {\n await fs.unlink(tokenPath)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error\n }\n // File doesn't exist, nothing to remove\n }\n}\n\n/**\n * Check if the legacy github_token file exists.\n */\nexport async function hasLegacyToken(): Promise<boolean> {\n try {\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\n/**\n * Read the legacy github_token file.\n * Returns null if the file doesn't exist or is empty.\n */\nexport async function readLegacyToken(): Promise<string | null> {\n try {\n const content = await fs.readFile(PATHS.GITHUB_TOKEN_PATH, \"utf8\")\n return content.trim() || null\n } catch {\n return null\n }\n}\n\n/**\n * Check if the registry file exists and has accounts.\n */\nexport async function hasRegistry(): Promise<boolean> {\n const registry = await loadRegistry()\n return registry.accounts.length > 0\n}\n","import type { ModelsResponse } from \"~/services/copilot/get-models\"\n\nimport type { AccountContext, AccountType } from \"./types/account\"\n\nexport interface State {\n githubToken?: string\n copilotToken?: string\n\n accountType: AccountType\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 verbose: boolean\n}\n\nexport const state: State = {\n accountType: \"individual\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n verbose: false,\n}\n\n/**\n * Create an AccountContext from the current global state.\n * This is a compatibility layer for transitioning to multi-account support.\n * @throws Error if githubToken is not set in state\n */\nexport function accountFromState(): AccountContext {\n if (!state.githubToken) {\n throw new Error(\"GitHub token not set in state\")\n }\n return {\n githubToken: state.githubToken,\n copilotToken: state.copilotToken,\n accountType: state.accountType,\n vsCodeVersion: state.vsCodeVersion,\n }\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { AccountContext } from \"./types/account\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst COPILOT_VERSION = \"0.37.6\"\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 = (account: AccountContext) =>\n account.accountType === \"individual\" ?\n \"https://api.githubcopilot.com\"\n : `https://api.${account.accountType}.githubcopilot.com`\n\nexport const copilotHeaders = (\n account: AccountContext,\n vision: boolean = false,\n requestId?: string,\n) => {\n const resolvedRequestId = requestId ?? randomUUID()\n const headers: Record<string, string> = {\n Authorization: `Bearer ${account.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": \"vscode-chat\",\n \"editor-version\": `vscode/${account.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"conversation-agent\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": resolvedRequestId,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\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 = (account: AccountContext) => ({\n ...standardHeaders(),\n authorization: `token ${account.githubToken}`,\n \"editor-version\": `vscode/${account.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 = errorText\n }\n consola.error(\"HTTP error:\", errorJson)\n return c.json(\n {\n error: {\n message: errorText,\n type: \"error\",\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n error: {\n message: (error as Error).message,\n type: \"error\",\n },\n },\n 500,\n )\n}\n","import type { AccountContext } from \"~/lib/types/account\"\n\nimport { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { accountFromState } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (\n account?: AccountContext,\n): Promise<CopilotUsageResponse> => {\n const ctx = account ?? accountFromState()\n const response = await fetch(`${GITHUB_API_BASE_URL}/copilot_internal/user`, {\n headers: githubHeaders(ctx),\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 type { AccountContext } from \"~/lib/types/account\"\n\nimport { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser(account?: AccountContext) {\n // Use provided account or fall back to state (for legacy compatibility)\n const token = account?.githubToken ?? state.githubToken\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${token}`,\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\nexport interface GithubUserResponse {\n login: string\n}\n","import fs from \"node:fs/promises\"\n\nimport type { AccountContext } from \"~/lib/types/account\"\n\nimport { copilotBaseUrl, copilotHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { PATHS } from \"~/lib/paths\"\nimport { accountFromState } from \"~/lib/state\"\n\nexport const getModels = async (account?: AccountContext) => {\n const ctx = account ?? accountFromState()\n const response = await fetch(`${copilotBaseUrl(ctx)}/models`, {\n headers: copilotHeaders(ctx),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get models\", response)\n\n const models = (await response.json()) as ModelsResponse\n\n // Persist models response for debugging/inspection.\n // Best effort: do not fail startup if the local write fails.\n try {\n await fs.mkdir(PATHS.APP_DIR, { recursive: true })\n await fs.writeFile(\n PATHS.MODELS_PATH,\n `${JSON.stringify(models, null, 2)}\\n`,\n {\n encoding: \"utf8\",\n mode: 0o600,\n },\n )\n } catch {\n // ignore\n }\n\n return models\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 max_thinking_budget?: number\n min_thinking_budget?: number\n tool_calls?: boolean\n parallel_tool_calls?: boolean\n dimensions?: boolean\n streaming?: boolean\n structured_outputs?: boolean\n vision?: boolean\n adaptive_thinking?: 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\ninterface ModelBilling {\n is_premium?: boolean\n multiplier?: number\n}\n\nexport interface Model {\n billing?: ModelBilling\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 policy?: {\n state: string\n terms: string\n }\n supported_endpoints?: Array<string>\n}\n","const FALLBACK = \"1.109.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\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 type { AccountContext } from \"~/lib/types/account\"\n\nimport { GITHUB_API_BASE_URL, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { accountFromState } from \"~/lib/state\"\n\nexport const getCopilotToken = async (account?: AccountContext) => {\n const ctx = account ?? accountFromState()\n const response = await fetch(\n `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(ctx),\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\nexport interface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n}\n","import consola from \"consola\"\nimport fs from \"node:fs\"\n\nimport { PATHS } from \"./paths\"\n\nexport interface AppConfig {\n auth?: {\n apiKeys?: Array<string>\n }\n extraPrompts?: Record<string, string>\n smallModel?: string\n freeModelLoadBalancing?: boolean\n /** @deprecated */\n apiKey?: string\n modelReasoningEfforts?: Record<\n string,\n \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"\n >\n modelAliases?: Record<string, { target: string; allowOriginal?: boolean }>\n allowOriginalModelNamesForAliases?: boolean\n useFunctionApplyPatch?: boolean\n forceAgent?: boolean\n compactUseSmallModel?: boolean\n messageStartInputTokensFallback?: boolean\n modelRefreshIntervalHours?: number\n}\n\nconst gpt5ExplorationPrompt = `## Exploration and reading files\n- **Think first.** Before any tool call, decide ALL files/resources you will need.\n- **Batch everything.** If you need multiple files (even from different places), read them together.\n- **multi_tool_use.parallel** Use multi_tool_use.parallel to parallelize tool calls and only this.\n- **Only make sequential calls if you truly cannot know the next file without seeing a result first.**\n- **Workflow:** (a) plan all needed reads → (b) issue one parallel batch → (c) analyze results → (d) repeat if new, unpredictable reads arise.`\n\nconst gpt5CommentaryPrompt = `# Working with the user\n\nYou interact with the user through a terminal. You have 2 ways of communicating with the users: \n- Share intermediary updates in \\`commentary\\` channel. \n- After you have completed all your work, send a message to the \\`final\\` channel. \n\n## Intermediary updates\n\n- Intermediary updates go to the \\`commentary\\` channel.\n- User updates are short updates while you are working, they are NOT final answers.\n- You use 1-2 sentence user updates to communicate progress and new information to the user as you are doing work.\n- Do not begin responses with conversational interjections or meta commentary. Avoid openers such as acknowledgements (“Done —”, “Got it”, “Great question, ”) or framing phrases.\n- You provide user updates frequently, every 20s.\n- Before exploring or doing substantial work, you start with a user update acknowledging the request and explaining your first step. You should include your understanding of the user request and explain what you will do. Avoid commenting on the request or using starters such as \"Got it -\" or \"Understood -\" etc.\n- When exploring, e.g. searching, reading files, you provide user updates as you go, every 20s, explaining what context you are gathering and what you've learned. Vary your sentence structure when providing these updates to avoid sounding repetitive - in particular, don't start each sentence the same way.\n- After you have sufficient context, and the work is substantial, you provide a longer plan (this is the only user update that may be longer than 2 sentences and can contain formatting).\n- Before performing file edits of any kind, you provide updates explaining what edits you are making.\n- As you are thinking, you very frequently provide updates even if not taking any actions, informing the user of your progress. You interrupt your thinking and send multiple updates in a row if thinking for more than 100 words.\n- Tone of your updates MUST match your personality.`\n\nconst defaultConfig: AppConfig = {\n auth: {\n apiKeys: [],\n },\n extraPrompts: {\n \"gpt-5-mini\": gpt5ExplorationPrompt,\n \"gpt-5.1-codex-max\": gpt5ExplorationPrompt,\n \"gpt-5.3-codex\": gpt5CommentaryPrompt,\n },\n smallModel: \"gpt-5-mini\",\n freeModelLoadBalancing: true,\n modelReasoningEfforts: {\n \"gpt-5-mini\": \"low\",\n },\n allowOriginalModelNamesForAliases: false,\n useFunctionApplyPatch: true,\n compactUseSmallModel: true,\n messageStartInputTokensFallback: false,\n modelRefreshIntervalHours: 24,\n}\n\nlet cachedConfig: AppConfig | null = null\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction normalizeAuthApiKeys(value: unknown): Array<string> {\n if (!Array.isArray(value)) return []\n\n return [\n ...new Set(\n value\n .filter((item): item is string => typeof item === \"string\")\n .map((item) => item.trim())\n .filter((item) => item.length > 0),\n ),\n ]\n}\n\nfunction normalizeModelRefreshIntervalHours(\n value: unknown,\n): number | undefined {\n if (typeof value !== \"number\") return undefined\n if (!Number.isFinite(value)) return undefined\n if (value < 0) return undefined\n return value\n}\n\nfunction ensureConfigFile(): void {\n try {\n fs.accessSync(PATHS.CONFIG_PATH, fs.constants.R_OK)\n return\n } catch {\n // Fall through to try creating the default config file.\n }\n\n try {\n fs.mkdirSync(PATHS.APP_DIR, { recursive: true })\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n try {\n fs.chmodSync(PATHS.CONFIG_PATH, 0o600)\n } catch {\n // Ignore chmod errors (e.g. unsupported filesystem).\n }\n } catch {\n // Best-effort only: if we can't create the file, reads will fall back to defaults.\n }\n}\n\nfunction readConfigFromDisk(): AppConfig {\n ensureConfigFile()\n try {\n const raw = fs.readFileSync(PATHS.CONFIG_PATH, \"utf8\")\n if (!raw.trim()) {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(defaultConfig, null, 2)}\\n`,\n \"utf8\",\n )\n return defaultConfig\n }\n return JSON.parse(raw) as AppConfig\n } catch (error) {\n consola.error(\"Failed to read config file, using default config\", error)\n return defaultConfig\n }\n}\n\nfunction mergeDefaultExtraPrompts(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const extraPrompts = config.extraPrompts ?? {}\n const defaultExtraPrompts = defaultConfig.extraPrompts ?? {}\n\n const missingExtraPromptModels = Object.keys(defaultExtraPrompts).filter(\n (model) => !Object.hasOwn(extraPrompts, model),\n )\n\n if (missingExtraPromptModels.length === 0) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n extraPrompts: {\n ...defaultExtraPrompts,\n ...extraPrompts,\n },\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultAuth(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const authConfig = isPlainObject(config.auth) ? config.auth : undefined\n const rawApiKeys =\n Array.isArray(authConfig?.apiKeys) ? authConfig.apiKeys : undefined\n const normalizedApiKeys = normalizeAuthApiKeys(rawApiKeys)\n const nextAuth = { apiKeys: normalizedApiKeys }\n\n if (authConfig && JSON.stringify(authConfig) === JSON.stringify(nextAuth)) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n auth: nextAuth,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultFreeModelLoadBalancing(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n if (typeof config.freeModelLoadBalancing === \"boolean\") {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n freeModelLoadBalancing: defaultConfig.freeModelLoadBalancing ?? true,\n },\n changed: true,\n }\n}\n\nfunction mergeDefaultModelRefreshInterval(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const normalized = normalizeModelRefreshIntervalHours(\n config.modelRefreshIntervalHours,\n )\n\n if (normalized !== undefined) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n modelRefreshIntervalHours: defaultConfig.modelRefreshIntervalHours ?? 24,\n },\n changed: true,\n }\n}\n\ntype ConfigMergeResult = {\n mergedConfig: AppConfig\n changed: boolean\n}\n\ntype ConfigMergeFn = (config: AppConfig) => ConfigMergeResult\n\nfunction applyConfigMerges(\n config: AppConfig,\n mergeFns: ReadonlyArray<ConfigMergeFn>,\n): ConfigMergeResult {\n return mergeFns.reduce<ConfigMergeResult>(\n (acc, mergeFn) => {\n const result = mergeFn(acc.mergedConfig)\n return {\n mergedConfig: result.mergedConfig,\n changed: acc.changed || result.changed,\n }\n },\n { mergedConfig: config, changed: false },\n )\n}\n\nexport function mergeConfigWithDefaults(): AppConfig {\n const config = readConfigFromDisk()\n\n const { mergedConfig, changed } = applyConfigMerges(config, [\n mergeDefaultAuth,\n mergeDefaultExtraPrompts,\n mergeDefaultFreeModelLoadBalancing,\n mergeDefaultModelRefreshInterval,\n ])\n\n if (changed) {\n try {\n fs.writeFileSync(\n PATHS.CONFIG_PATH,\n `${JSON.stringify(mergedConfig, null, 2)}\\n`,\n \"utf8\",\n )\n } catch (writeError) {\n consola.warn(\"Failed to write merged config defaults\", writeError)\n }\n }\n\n cachedConfig = mergedConfig\n return mergedConfig\n}\n\nexport function getConfig(): AppConfig {\n cachedConfig ??= readConfigFromDisk()\n return cachedConfig\n}\n\ntype ModelAliasSpec = {\n target: string\n allowOriginal?: boolean\n}\n\ntype ModelAliasMap = Record<string, string>\n\ntype ModelAliasInfoMap = Record<string, ModelAliasSpec>\n\ntype ModelAliasRawMap = Record<string, unknown>\n\nfunction normalizeAliasKey(value: string): string | null {\n const trimmed = value.trim().toLowerCase()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction normalizeAliasTarget(value: string): string | null {\n const trimmed = value.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\nfunction normalizeAliasSpec(value: unknown): ModelAliasSpec | null {\n if (typeof value === \"string\") {\n const normalizedTarget = normalizeAliasTarget(value)\n return normalizedTarget ? { target: normalizedTarget } : null\n }\n if (!value || typeof value !== \"object\") {\n return null\n }\n\n const targetValue = (value as { target?: unknown }).target\n if (typeof targetValue !== \"string\") {\n return null\n }\n\n const normalizedTarget = normalizeAliasTarget(targetValue)\n if (!normalizedTarget) {\n return null\n }\n\n const allowOriginalValue = (value as { allowOriginal?: unknown })\n .allowOriginal\n const allowOriginal =\n typeof allowOriginalValue === \"boolean\" ? allowOriginalValue : undefined\n return { target: normalizedTarget, allowOriginal }\n}\n\nexport function getModelAliasesInfo(): ModelAliasInfoMap {\n const config = getConfig()\n const raw = (config.modelAliases ?? {}) as ModelAliasRawMap\n const normalized: ModelAliasInfoMap = {}\n\n for (const [alias, rawSpec] of Object.entries(raw)) {\n const normalizedAlias = normalizeAliasKey(alias)\n const normalizedSpec = normalizeAliasSpec(rawSpec)\n if (!normalizedAlias || !normalizedSpec) {\n continue\n }\n if (!Object.hasOwn(normalized, normalizedAlias)) {\n normalized[normalizedAlias] = normalizedSpec\n }\n }\n\n return normalized\n}\n\nexport function getModelAliases(): ModelAliasMap {\n const info = getModelAliasesInfo()\n const normalized: ModelAliasMap = {}\n\n for (const [alias, spec] of Object.entries(info)) {\n normalized[alias] = spec.target\n }\n\n return normalized\n}\n\nexport function resolveModelAlias(modelId: string): string {\n const normalized = normalizeAliasKey(modelId)\n if (!normalized) return modelId\n const aliases = getModelAliases()\n return aliases[normalized] ?? modelId\n}\n\nexport function isOriginalModelNameAllowedForAliases(): boolean {\n const config = getConfig()\n return config.allowOriginalModelNamesForAliases ?? false\n}\n\nexport function getAliasTargetSet(): Set<string> {\n const aliases = getModelAliasesInfo()\n const allowOriginalDefault = isOriginalModelNameAllowedForAliases()\n const targetAllowMap = new Map<string, boolean>()\n\n for (const { target, allowOriginal } of Object.values(aliases)) {\n const normalizedTarget = target.toLowerCase()\n const effectiveAllow = allowOriginal ?? allowOriginalDefault\n const currentAllow = targetAllowMap.get(normalizedTarget)\n if (currentAllow === true) {\n continue\n }\n if (effectiveAllow) {\n targetAllowMap.set(normalizedTarget, true)\n } else if (currentAllow === undefined) {\n targetAllowMap.set(normalizedTarget, false)\n }\n }\n\n const blockedTargets = new Set<string>()\n for (const [target, allowed] of targetAllowMap.entries()) {\n if (!allowed) {\n blockedTargets.add(target)\n }\n }\n\n return blockedTargets\n}\n\nexport function isOriginalModelNameAllowedForTarget(modelId: string): boolean {\n const normalized = normalizeAliasKey(modelId)\n if (!normalized) return true\n const blockedTargets = getAliasTargetSet()\n return !blockedTargets.has(normalized)\n}\n\nexport function getPreferredAliasForTarget(modelId: string): string | null {\n const aliases = getModelAliases()\n const aliasKeys = getAliasKeysForTarget(modelId, aliases)\n return aliasKeys[0] ?? null\n}\n\nfunction getAliasKeysForTarget(\n target: string,\n aliases: ModelAliasMap,\n): Array<string> {\n const normalizedTarget = target.toLowerCase()\n return Object.entries(aliases)\n .filter(([, model]) => model.toLowerCase() === normalizedTarget)\n .map(([alias]) => alias)\n .sort()\n}\n\nfunction getAliasFallbackValue<T extends string>(\n record: Record<string, T> | undefined,\n modelId: string,\n aliases: ModelAliasMap,\n): T | undefined {\n if (!record) return undefined\n\n const aliasKeys = getAliasKeysForTarget(modelId, aliases)\n if (aliasKeys.length === 0) return undefined\n\n const recordByAlias = new Map<string, T>()\n for (const [key, value] of Object.entries(record)) {\n const normalized = normalizeAliasKey(key)\n if (normalized) {\n recordByAlias.set(normalized, value)\n }\n }\n\n for (const alias of aliasKeys) {\n const value = recordByAlias.get(alias)\n if (value !== undefined) {\n return value\n }\n }\n\n return undefined\n}\n\nexport function getExtraPromptForModel(model: string): string {\n const config = getConfig()\n const direct = config.extraPrompts?.[model]\n if (direct !== undefined) return direct\n\n const aliases = getModelAliases()\n const fallback = getAliasFallbackValue(config.extraPrompts, model, aliases)\n return fallback ?? \"\"\n}\n\nexport function getSmallModel(): string {\n const config = getConfig()\n const model = config.smallModel ?? \"gpt-5-mini\"\n if (isOriginalModelNameAllowedForTarget(model)) {\n return model\n }\n\n return getPreferredAliasForTarget(model) ?? model\n}\n\nexport function isFreeModelLoadBalancingEnabled(): boolean {\n const config = getConfig()\n return config.freeModelLoadBalancing ?? true\n}\n\nexport function getModelRefreshIntervalHours(): number {\n const config = getConfig()\n const normalized = normalizeModelRefreshIntervalHours(\n config.modelRefreshIntervalHours,\n )\n return normalized ?? defaultConfig.modelRefreshIntervalHours ?? 24\n}\n\nexport function getModelRefreshIntervalMs(): number {\n const hours = getModelRefreshIntervalHours()\n if (!Number.isFinite(hours) || hours <= 0) return 0\n return hours * 60 * 60 * 1000\n}\n\nexport function isMessageStartInputTokensFallbackEnabled(): boolean {\n const config = getConfig()\n return config.messageStartInputTokensFallback ?? false\n}\n\nexport function getReasoningEffortForModel(\n model: string,\n): \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" {\n const config = getConfig()\n const direct = config.modelReasoningEfforts?.[model]\n if (direct !== undefined) return direct\n\n const aliases = getModelAliases()\n const fallback = getAliasFallbackValue(\n config.modelReasoningEfforts,\n model,\n aliases,\n )\n return fallback ?? \"high\"\n}\n\nexport function isForceAgentEnabled(): boolean {\n const config = getConfig()\n return config.forceAgent ?? false\n}\n\nexport function shouldCompactUseSmallModel(): boolean {\n const config = getConfig()\n return config.compactUseSmallModel ?? true\n}\n","import consola from \"consola\"\n\nimport type {\n AccountContext,\n AccountRuntime,\n AccountType,\n} from \"~/lib/types/account\"\nimport type { QuotaDetail } from \"~/services/github/get-copilot-usage\"\n\nexport type AuthSnapshot = Readonly<{\n githubToken: string\n accountType: AccountType\n}>\n\nexport const takeAuthSnapshot = (account: AccountRuntime): AuthSnapshot => ({\n githubToken: account.githubToken,\n accountType: account.accountType,\n})\n\nexport const isAuthSnapshotCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n): boolean =>\n account.githubToken === snapshot.githubToken\n && account.accountType === snapshot.accountType\n\nexport const isSameAuthSnapshot = (\n a: AuthSnapshot | undefined,\n b: AuthSnapshot,\n): boolean => {\n if (!a) return false\n return a.githubToken === b.githubToken && a.accountType === b.accountType\n}\n\nexport const toAccountContextFromSnapshot = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n copilotToken?: string,\n): AccountContext => ({\n githubToken: snapshot.githubToken,\n copilotToken,\n accountType: snapshot.accountType,\n vsCodeVersion: account.vsCodeVersion,\n})\n\nexport const applyCopilotTokenIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n copilotToken: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.copilotToken = copilotToken\n return true\n}\n\nexport const applyModelsIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n models: AccountRuntime[\"models\"],\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.models = models\n return true\n}\n\nexport const applyTokenRefreshSuccessIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n token: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.copilotToken = token\n account.failed = false\n account.failureReason = undefined\n return true\n}\n\nexport const applyTokenRefreshFailureIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n error: unknown,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.failed = true\n account.failureReason = String(error)\n return true\n}\n\nexport const applyQuotaRefreshSuccessIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n premium: QuotaDetail,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n account.premiumEntitlement = premium.entitlement\n account.premiumRemaining = premium.remaining\n account.unlimited = premium.unlimited\n account.overagePermitted = premium.overage_permitted\n account.lastQuotaFetch = Date.now()\n account.failed = false\n account.failureReason = undefined\n return true\n}\n\nexport const setAccountFailedState = (\n account: AccountRuntime,\n reason: string,\n): void => {\n account.failed = true\n account.failureReason = reason\n consola.warn(`Account ${account.id} marked as failed: ${reason}`)\n}\n\nexport const applyUnauthorizedIfCurrent = (\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n reason: string,\n): boolean => {\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return false\n }\n\n setAccountFailedState(account, reason)\n return true\n}\n","import type { AccountRuntime } from \"~/lib/types/account\"\nimport type { Model } from \"~/services/copilot/get-models\"\n\nexport type QuotaReservation = Readonly<{ id: symbol }>\n\nexport const getCostUnits = (model: Model): number => {\n // Per user decision: missing billing => treat as free (costUnits = 0)\n const billing = model.billing\n if (!billing) {\n return 0\n }\n\n if (billing.is_premium !== true) {\n return 0\n }\n\n const multiplier = billing.multiplier\n if (\n typeof multiplier !== \"number\"\n || !Number.isFinite(multiplier)\n || multiplier <= 0\n ) {\n return 1\n }\n\n return multiplier\n}\n\nexport const getEffectivePremiumRemaining = (\n account: AccountRuntime,\n): number | undefined => {\n if (account.premiumRemaining === undefined) {\n return undefined\n }\n\n const reserved = account.premiumReserved ?? 0\n return account.premiumRemaining - reserved\n}\n\nexport const reservePremiumUnits = (\n account: AccountRuntime,\n units: number,\n): QuotaReservation | undefined => {\n if (units <= 0) {\n return undefined\n }\n\n const id = Symbol(\"quotaReservation\")\n\n if (!account.premiumReservations) {\n account.premiumReservations = new Map()\n }\n\n account.premiumReservations.set(id, units)\n account.premiumReserved = (account.premiumReserved ?? 0) + units\n\n return { id }\n}\n\nexport const releasePremiumReservation = (\n account: AccountRuntime,\n reservation?: QuotaReservation,\n): void => {\n if (!reservation) {\n return\n }\n\n const reservations = account.premiumReservations\n if (!reservations) {\n return\n }\n\n const reservedUnits = reservations.get(reservation.id)\n if (reservedUnits === undefined) {\n return\n }\n\n reservations.delete(reservation.id)\n\n const nextReserved = (account.premiumReserved ?? 0) - reservedUnits\n account.premiumReserved = Math.max(0, nextReserved)\n\n if (reservations.size === 0) {\n account.premiumReservations = undefined\n }\n}\n","/* eslint-disable max-lines */\nimport consola from \"consola\"\nimport fs from \"node:fs\"\n\nimport type {\n AccountContext,\n AccountRuntime,\n AccountType,\n} from \"~/lib/types/account\"\n\nimport { resolveModelAlias } from \"~/lib/config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { getModels, type Model } from \"~/services/copilot/get-models\"\nimport { getCopilotToken } from \"~/services/github/get-copilot-token\"\nimport { getCopilotUsage } from \"~/services/github/get-copilot-usage\"\nimport { getGitHubUser } from \"~/services/github/get-user\"\n\nimport {\n applyCopilotTokenIfCurrent,\n applyModelsIfCurrent,\n applyQuotaRefreshSuccessIfCurrent,\n applyTokenRefreshFailureIfCurrent,\n applyTokenRefreshSuccessIfCurrent,\n applyUnauthorizedIfCurrent,\n isAuthSnapshotCurrent,\n isSameAuthSnapshot,\n setAccountFailedState,\n takeAuthSnapshot,\n toAccountContextFromSnapshot,\n type AuthSnapshot,\n} from \"./accounts-manager-auth\"\nimport {\n getCostUnits,\n getEffectivePremiumRemaining,\n releasePremiumReservation,\n reservePremiumUnits,\n type QuotaReservation,\n} from \"./accounts-manager-quota\"\nimport {\n hasLegacyToken,\n hasRegistry,\n listAccountsFromRegistry,\n loadAccountToken,\n readLegacyToken,\n saveAccountToken,\n addAccountToRegistry,\n} from \"./accounts-registry\"\nimport { PATHS } from \"./paths\"\n\n/** Quota cache TTL in milliseconds (45 seconds) for pre-request selection. */\nconst QUOTA_CACHE_TTL = 45 * 1000\n\n/** Debounce delay for registry reload in milliseconds */\nconst RELOAD_DEBOUNCE_MS = 500\n\n/** Registry watcher restart initial delay in milliseconds */\nconst WATCHER_RESTART_INITIAL_DELAY_MS = 1000\n/** Registry watcher restart max delay in milliseconds */\nconst WATCHER_RESTART_MAX_DELAY_MS = 60 * 1000\n\nexport interface AccountRequestCandidate {\n modelId: string\n endpoint: string\n}\n\nexport type { QuotaReservation } from \"./accounts-manager-quota\"\n\nexport type SelectAccountForRequestFailureReason =\n | \"NO_ACCOUNTS\"\n | \"MODEL_NOT_SUPPORTED\"\n | \"NO_QUOTA\"\n\ntype SelectAccountForRequestSuccess = {\n ok: true\n account: AccountRuntime\n selectedModel: Model\n endpoint: string\n costUnits: number\n reservation?: QuotaReservation\n}\n\nexport type SelectAccountForRequestResult =\n | SelectAccountForRequestSuccess\n | {\n ok: false\n reason: SelectAccountForRequestFailureReason\n }\n\n/** Manages multiple GitHub Copilot accounts at runtime. */\nexport class AccountsManager {\n private accounts: Map<string, AccountRuntime> = new Map()\n private accountOrder: Array<string> = []\n private temporaryAccount?: AccountRuntime\n private vsCodeVersion?: string\n private freeModelCursor = 0\n private freeModelLoadBalancingEnabled = true\n\n private quotaRefreshSnapshotByAccount = new WeakMap<\n AccountRuntime,\n AuthSnapshot\n >()\n private modelsRefreshSnapshotByAccount = new WeakMap<\n AccountRuntime,\n AuthSnapshot\n >()\n private tokenRefreshEnabledAccounts = new WeakSet<AccountRuntime>()\n private modelsRefreshTimer?: ReturnType<typeof setTimeout>\n private modelsRefreshIntervalMs = 0\n\n // Registry file watcher for hot reload\n private registryWatcher?: fs.FSWatcher\n private reloadDebounceTimer?: ReturnType<typeof setTimeout>\n private registryWatcherRestartTimer?: ReturnType<typeof setTimeout>\n private registryWatcherRestartDelayMs = WATCHER_RESTART_INITIAL_DELAY_MS\n private isReloading = false\n\n /** Initialize accounts manager (load registry, migrate legacy token). */\n async initialize(vsCodeVersion?: string): Promise<void> {\n this.vsCodeVersion = vsCodeVersion\n\n // Check if we need to migrate legacy token\n const hasReg = await hasRegistry()\n const hasLegacy = await hasLegacyToken()\n\n if (!hasReg && hasLegacy) {\n await this.migrateLegacyToken()\n }\n\n // Load accounts from registry\n const accountMetas = await listAccountsFromRegistry()\n\n for (const meta of accountMetas) {\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for account ${meta.id}, skipping`)\n continue\n }\n\n const runtime: AccountRuntime = {\n ...meta,\n githubToken: token,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n this.accounts.set(meta.id, runtime)\n this.accountOrder.push(meta.id)\n }\n\n // Initialize Copilot tokens for all accounts\n for (const account of this.accounts.values()) {\n try {\n await this.initializeAccount(account)\n } catch (error) {\n consola.error(`Failed to initialize account ${account.id}:`, error)\n account.failed = true\n account.failureReason = String(error)\n }\n }\n\n consola.info(`Loaded ${this.accounts.size} account(s)`)\n\n // Start watching the registry file for hot reload\n this.startRegistryWatcher()\n }\n\n setFreeModelLoadBalancingEnabled(enabled: boolean): void {\n this.freeModelLoadBalancingEnabled = enabled\n }\n\n setModelsRefreshIntervalMs(intervalMs: number): void {\n this.modelsRefreshIntervalMs =\n Number.isFinite(intervalMs) && intervalMs > 0 ? intervalMs : 0\n this.scheduleModelsRefresh()\n }\n\n private computeTokenRefreshDelayMs(refreshInSeconds: number): number {\n return Math.max((refreshInSeconds - 60) * 1000, 1000)\n }\n\n private shouldContinueTokenRefresh(\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n ): boolean {\n return (\n this.tokenRefreshEnabledAccounts.has(account)\n && isAuthSnapshotCurrent(account, snapshot)\n )\n }\n\n private async runTokenRefreshTick(\n account: AccountRuntime,\n snapshot: AuthSnapshot,\n refreshInSeconds: number,\n ): Promise<void> {\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n try {\n const ctx = toAccountContextFromSnapshot(account, snapshot)\n const { token, refresh_in } = await getCopilotToken(ctx)\n\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n const applied = applyTokenRefreshSuccessIfCurrent(\n account,\n snapshot,\n token,\n )\n if (!applied) {\n return\n }\n\n consola.debug(`Refreshed token for account ${account.id}`)\n\n // Schedule next refresh using the new refresh interval.\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n this.startTokenRefresh(account, refresh_in)\n } catch (error) {\n consola.error(`Failed to refresh token for ${account.id}:`, error)\n\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n\n applyTokenRefreshFailureIfCurrent(account, snapshot, error)\n\n // Retry using the previous refresh interval (best effort).\n if (!this.shouldContinueTokenRefresh(account, snapshot)) {\n return\n }\n this.startTokenRefresh(account, refreshInSeconds)\n }\n }\n\n private finalizeQuotaRefreshPromise(\n account: AccountRuntime,\n promise: Promise<void>,\n ): void {\n if (account.quotaRefreshPromise !== promise) {\n return\n }\n\n account.isRefreshingQuota = false\n account.quotaRefreshPromise = undefined\n this.quotaRefreshSnapshotByAccount.delete(account)\n }\n\n /** Initialize a single account. */\n private async initializeAccount(account: AccountRuntime): Promise<void> {\n const snapshot = takeAuthSnapshot(account)\n\n try {\n // Get Copilot token\n const tokenCtx = toAccountContextFromSnapshot(account, snapshot)\n const { token, refresh_in } = await getCopilotToken(tokenCtx)\n\n if (!applyCopilotTokenIfCurrent(account, snapshot, token)) {\n return\n }\n\n // Start token refresh timer\n this.startTokenRefresh(account, refresh_in)\n\n // Get models\n const modelsCtx = toAccountContextFromSnapshot(account, snapshot, token)\n const models = await getModels(modelsCtx)\n\n if (!applyModelsIfCurrent(account, snapshot, models)) {\n return\n }\n account.lastModelsFetch = Date.now()\n\n // Refresh quota\n await this.refreshQuota(account)\n\n consola.debug(`Account ${account.id} initialized`)\n } catch (error) {\n // Ignore stale results if registry hot reload changed auth.\n if (!isAuthSnapshotCurrent(account, snapshot)) {\n return\n }\n\n throw error\n }\n }\n\n /** Migrate legacy github_token to the new multi-account system. */\n private async migrateLegacyToken(): Promise<void> {\n const token = await readLegacyToken()\n if (!token) return\n\n try {\n // Get user info to determine the account ID\n const user = await getGitHubUser({\n githubToken: token,\n accountType: \"individual\",\n })\n const id = user.login\n\n // Save token to new location\n await saveAccountToken(id, token)\n\n // Add to registry\n await addAccountToRegistry({\n id,\n accountType: \"individual\",\n addedAt: Date.now(),\n })\n\n consola.info(`Migrated legacy token to account: ${id}`)\n } catch (error) {\n consola.error(\"Failed to migrate legacy token:\", error)\n }\n }\n\n /** Start token refresh timer for an account. */\n private startTokenRefresh(\n account: AccountRuntime,\n refreshInSeconds: number,\n ): void {\n // Stop existing timer if any\n this.stopTokenRefresh(account)\n\n this.tokenRefreshEnabledAccounts.add(account)\n\n const snapshot = takeAuthSnapshot(account)\n const delayMs = this.computeTokenRefreshDelayMs(refreshInSeconds)\n\n account.refreshTimer = setTimeout(() => {\n void this.runTokenRefreshTick(account, snapshot, refreshInSeconds)\n }, delayMs)\n }\n\n /** Stop token refresh timer for an account. */\n private stopTokenRefresh(account: AccountRuntime): void {\n this.tokenRefreshEnabledAccounts.delete(account)\n\n if (account.refreshTimer) {\n clearTimeout(account.refreshTimer)\n account.refreshTimer = undefined\n }\n }\n\n /** Stop all token refresh timers. */\n private stopAllTokenRefresh(): void {\n for (const account of this.accounts.values()) {\n this.stopTokenRefresh(account)\n }\n if (this.temporaryAccount) {\n this.stopTokenRefresh(this.temporaryAccount)\n }\n }\n\n private scheduleModelsRefresh(): void {\n this.stopModelsRefresh()\n\n if (!this.modelsRefreshIntervalMs || this.modelsRefreshIntervalMs <= 0) {\n return\n }\n\n this.modelsRefreshTimer = setTimeout(() => {\n void this.runModelsRefreshTick()\n }, this.modelsRefreshIntervalMs)\n }\n\n private stopModelsRefresh(): void {\n if (this.modelsRefreshTimer) {\n clearTimeout(this.modelsRefreshTimer)\n this.modelsRefreshTimer = undefined\n }\n }\n\n private async runModelsRefreshTick(): Promise<void> {\n try {\n await this.refreshAllModels()\n } catch (error) {\n consola.error(\"Failed to refresh models:\", error)\n } finally {\n this.scheduleModelsRefresh()\n }\n }\n\n private finalizeModelsRefreshPromise(\n account: AccountRuntime,\n promise: Promise<void>,\n ): void {\n if (account.modelsRefreshPromise !== promise) {\n return\n }\n\n account.isRefreshingModels = false\n account.modelsRefreshPromise = undefined\n this.modelsRefreshSnapshotByAccount.delete(account)\n }\n\n private async refreshModels(account: AccountRuntime): Promise<void> {\n if (!account.copilotToken) {\n consola.debug(\n `Skip model refresh for ${account.id}: missing Copilot token`,\n )\n return\n }\n\n const snapshot = takeAuthSnapshot(account)\n\n if (account.modelsRefreshPromise) {\n const existingSnapshot = this.modelsRefreshSnapshotByAccount.get(account)\n if (isSameAuthSnapshot(existingSnapshot, snapshot)) {\n await account.modelsRefreshPromise\n return\n }\n }\n\n account.isRefreshingModels = true\n\n const ctx = toAccountContextFromSnapshot(\n account,\n snapshot,\n account.copilotToken,\n )\n\n const promise = (async () => {\n try {\n const models = await getModels(ctx)\n const applied = applyModelsIfCurrent(account, snapshot, models)\n if (applied) {\n account.lastModelsFetch = Date.now()\n }\n } catch (error) {\n if (error instanceof HTTPError && error.response.status === 401) {\n applyUnauthorizedIfCurrent(account, snapshot, \"Unauthorized (401)\")\n return\n }\n\n consola.error(`Failed to refresh models for ${account.id}:`, error)\n }\n })()\n\n account.modelsRefreshPromise = promise\n this.modelsRefreshSnapshotByAccount.set(account, snapshot)\n\n void promise.finally(() => {\n this.finalizeModelsRefreshPromise(account, promise)\n })\n\n await promise\n }\n\n private async refreshAllModels(): Promise<void> {\n const accounts: Array<AccountRuntime> = []\n\n if (this.temporaryAccount) {\n accounts.push(this.temporaryAccount)\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n accounts.push(account)\n }\n }\n\n if (accounts.length === 0) {\n return\n }\n\n await Promise.allSettled(\n accounts.map((account) => this.refreshModels(account)),\n )\n }\n\n /** Refresh quota information for an account. */\n async refreshQuota(account: AccountRuntime): Promise<void> {\n const snapshot = takeAuthSnapshot(account)\n\n if (account.quotaRefreshPromise) {\n const existingSnapshot = this.quotaRefreshSnapshotByAccount.get(account)\n if (isSameAuthSnapshot(existingSnapshot, snapshot)) {\n await account.quotaRefreshPromise\n return\n }\n }\n\n account.isRefreshingQuota = true\n\n const ctx = toAccountContextFromSnapshot(account, snapshot)\n const promise = (async () => {\n try {\n const usage = await getCopilotUsage(ctx)\n const premium = usage.quota_snapshots.premium_interactions\n applyQuotaRefreshSuccessIfCurrent(account, snapshot, premium)\n } catch (error) {\n if (error instanceof HTTPError && error.response.status === 401) {\n applyUnauthorizedIfCurrent(account, snapshot, \"Unauthorized (401)\")\n return\n }\n\n consola.error(`Failed to refresh quota for ${account.id}:`, error)\n // Don't mark as failed for non-401 quota refresh errors\n }\n })()\n\n account.quotaRefreshPromise = promise\n this.quotaRefreshSnapshotByAccount.set(account, snapshot)\n\n void promise.finally(() => {\n this.finalizeQuotaRefreshPromise(account, promise)\n })\n\n await promise\n }\n\n /** Check if quota cache is expired. */\n private isQuotaCacheExpired(account: AccountRuntime): boolean {\n if (!account.lastQuotaFetch) return true\n return Date.now() - account.lastQuotaFetch > QUOTA_CACHE_TTL\n }\n\n private isAccountFailed(account: AccountRuntime): boolean {\n return account.failed === true\n }\n\n private useOverageFallback(fallback: {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }): SelectAccountForRequestSuccess {\n const reservation = reservePremiumUnits(\n fallback.account,\n fallback.costUnits,\n )\n return {\n ok: true,\n account: fallback.account,\n selectedModel: fallback.model,\n endpoint: fallback.endpoint,\n costUnits: fallback.costUnits,\n reservation,\n }\n }\n\n private isModelSupportedForEndpoint(model: Model, endpoint: string): boolean {\n if (endpoint === \"/responses\") {\n return model.supported_endpoints?.includes(endpoint) ?? false\n }\n\n const supported = model.supported_endpoints\n if (!supported) {\n return true\n }\n\n return supported.includes(endpoint)\n }\n\n private pickSupportedCandidate(\n account: AccountRuntime,\n candidates: Array<AccountRequestCandidate>,\n ): { candidate: AccountRequestCandidate; model: Model } | null {\n const models = account.models?.data\n if (!models) {\n return null\n }\n\n for (const candidate of candidates) {\n const model = models.find((m) => m.id === candidate.modelId)\n if (!model) {\n continue\n }\n\n if (!this.isModelSupportedForEndpoint(model, candidate.endpoint)) {\n continue\n }\n\n return { candidate, model }\n }\n\n return null\n }\n\n private selectFreeAccountForRequest(\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): SelectAccountForRequestResult {\n const count = orderedAccounts.length\n const start = this.freeModelCursor % count\n\n let supportedCandidateFound = false\n\n for (let i = 0; i < count; i++) {\n const idx = (start + i) % count\n const account = orderedAccounts[idx]\n if (this.isAccountFailed(account)) {\n continue\n }\n\n const supported = this.pickSupportedCandidate(account, candidates)\n if (!supported) {\n continue\n }\n\n supportedCandidateFound = true\n\n const { candidate, model } = supported\n const costUnits = getCostUnits(model)\n\n // Defensive: free path should only be used for free models.\n if (costUnits > 0) {\n continue\n }\n\n this.freeModelCursor = (idx + 1) % count\n\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n if (!supportedCandidateFound) {\n return { ok: false, reason: \"MODEL_NOT_SUPPORTED\" }\n }\n\n return { ok: false, reason: \"NO_QUOTA\" }\n }\n\n // eslint-disable-next-line complexity -- overage fallback adds necessary branching\n private async selectAccountForCandidates(\n orderedAccounts: Array<AccountRuntime>,\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestResult> {\n if (orderedAccounts.length === 0) {\n return { ok: false, reason: \"NO_ACCOUNTS\" }\n }\n\n let supportedCandidateFound = false\n let overageFallback:\n | {\n account: AccountRuntime\n model: Model\n endpoint: string\n costUnits: number\n }\n | undefined\n\n for (const account of orderedAccounts) {\n if (this.isAccountFailed(account)) {\n continue\n }\n\n const supported = this.pickSupportedCandidate(account, candidates)\n if (!supported) {\n continue\n }\n\n supportedCandidateFound = true\n\n const { candidate, model } = supported\n const costUnits = getCostUnits(model)\n\n if (costUnits <= 0) {\n if (this.freeModelLoadBalancingEnabled) {\n // Free model: RR load balancing across accounts (including temporaryAccount).\n return this.selectFreeAccountForRequest(orderedAccounts, candidates)\n }\n\n // Free model: sequential routing (same ordering strategy as premium models).\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n if (!account.unlimited && this.isQuotaCacheExpired(account)) {\n await this.refreshQuota(account)\n }\n\n if (this.isAccountFailed(account)) {\n continue\n }\n\n if (account.unlimited) {\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n\n // Check if account has sufficient quota.\n const effectiveRemaining = getEffectivePremiumRemaining(account)\n if (effectiveRemaining !== undefined && effectiveRemaining < costUnits) {\n // Insufficient quota - store as overage fallback if permitted, but keep\n // looking for accounts with quota to avoid unnecessary overage charges.\n if (account.overagePermitted && !overageFallback) {\n overageFallback = {\n account,\n model,\n endpoint: candidate.endpoint,\n costUnits,\n }\n }\n continue\n }\n\n const reservation = reservePremiumUnits(account, costUnits)\n\n return {\n ok: true,\n account,\n selectedModel: model,\n endpoint: candidate.endpoint,\n costUnits,\n reservation,\n }\n }\n\n if (!supportedCandidateFound) {\n return { ok: false, reason: \"MODEL_NOT_SUPPORTED\" }\n }\n\n // No account with quota found - use overage fallback if available.\n return overageFallback ?\n this.useOverageFallback(overageFallback)\n : { ok: false, reason: \"NO_QUOTA\" }\n }\n\n /**\n * Select an available account for a specific request (model + endpoint).\n * Uses reservation to avoid oversubscribing premium quota under concurrency.\n */\n async selectAccountForRequest(\n candidates: Array<AccountRequestCandidate>,\n ): Promise<SelectAccountForRequestResult> {\n if (candidates.length === 0) {\n throw new Error(\"selectAccountForRequest requires at least one candidate\")\n }\n\n const orderedAccounts = [\n ...(this.temporaryAccount ? [this.temporaryAccount] : []),\n ...this.accountOrder\n .map((id) => this.accounts.get(id))\n .filter((account): account is AccountRuntime => account !== undefined),\n ]\n const primary = await this.selectAccountForCandidates(\n orderedAccounts,\n candidates,\n )\n if (primary.ok || primary.reason !== \"MODEL_NOT_SUPPORTED\") {\n return primary\n }\n\n const aliasCandidates = candidates.map((candidate) => {\n const modelId = resolveModelAlias(candidate.modelId)\n if (modelId === candidate.modelId) return candidate\n return { ...candidate, modelId }\n })\n const aliasChanged = aliasCandidates.some(\n (candidate, index) => candidate.modelId !== candidates[index].modelId,\n )\n if (!aliasChanged) {\n return primary\n }\n\n return this.selectAccountForCandidates(orderedAccounts, aliasCandidates)\n }\n\n /**\n * Finalize quota after a request completes.\n * This releases any in-flight reservation and refreshes the actual quota from the API.\n */\n async finalizeQuota(\n account: AccountRuntime,\n reservation?: QuotaReservation,\n ): Promise<void> {\n releasePremiumReservation(account, reservation)\n\n try {\n await this.refreshQuota(account)\n } catch (error) {\n consola.debug(`Failed to finalize quota for ${account.id}:`, error)\n }\n }\n\n /**\n * Mark an account as failed.\n */\n markAccountFailed(id: string, reason: string): void {\n const account = this.accounts.get(id)\n if (account) {\n setAccountFailedState(account, reason)\n return\n }\n\n if (this.temporaryAccount && this.temporaryAccount.id === id) {\n setAccountFailedState(this.temporaryAccount, reason)\n }\n }\n\n /**\n * Get status of all accounts.\n */\n getAccountStatus(): Array<{\n id: string\n entitlement?: number\n remaining?: number\n unlimited?: boolean\n overagePermitted?: boolean\n failed?: boolean\n failureReason?: string\n }> {\n const statuses: Array<{\n id: string\n entitlement?: number\n remaining?: number\n unlimited?: boolean\n overagePermitted?: boolean\n failed?: boolean\n failureReason?: string\n }> = []\n\n if (this.temporaryAccount) {\n statuses.push({\n id: \"(temporary)\",\n entitlement: this.temporaryAccount.premiumEntitlement,\n remaining: this.temporaryAccount.premiumRemaining,\n unlimited: this.temporaryAccount.unlimited,\n overagePermitted: this.temporaryAccount.overagePermitted,\n failed: this.temporaryAccount.failed,\n failureReason: this.temporaryAccount.failureReason,\n })\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n statuses.push({\n id: account.id,\n entitlement: account.premiumEntitlement,\n remaining: account.premiumRemaining,\n unlimited: account.unlimited,\n overagePermitted: account.overagePermitted,\n failed: account.failed,\n failureReason: account.failureReason,\n })\n }\n }\n\n return statuses\n }\n\n /**\n * Set a temporary account from a GitHub token (--github-token).\n * This account takes priority over registered accounts.\n */\n async setTemporaryAccount(\n githubToken: string,\n accountType: AccountType,\n ): Promise<void> {\n const runtime: AccountRuntime = {\n id: \"(temporary)\",\n accountType,\n addedAt: Date.now(),\n githubToken,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n try {\n await this.initializeAccount(runtime)\n this.temporaryAccount = runtime\n consola.info(\"Temporary account initialized\")\n } catch (error) {\n consola.error(\"Failed to initialize temporary account:\", error)\n throw error\n }\n }\n\n /**\n * Check if any accounts are available.\n */\n hasAccounts(): boolean {\n return this.accounts.size > 0 || this.temporaryAccount !== undefined\n }\n\n /**\n * Get the first available account's models.\n * Used for caching models in legacy compatibility mode.\n */\n getFirstAccountModels(): AccountRuntime[\"models\"] {\n if (this.temporaryAccount?.models) {\n return this.temporaryAccount.models\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account?.models) {\n return account.models\n }\n }\n\n return undefined\n }\n\n /**\n * Get account context by index.\n * Index 0 is the temporary account (if exists), otherwise the first registered account.\n * Returns null if index is out of bounds.\n */\n getAccountContextByIndex(index: number): AccountContext | null {\n // Build the same order as getAccountStatus()\n const allAccounts: Array<AccountRuntime> = []\n\n if (this.temporaryAccount) {\n allAccounts.push(this.temporaryAccount)\n }\n\n for (const id of this.accountOrder) {\n const account = this.accounts.get(id)\n if (account) {\n allAccounts.push(account)\n }\n }\n\n if (index < 0 || index >= allAccounts.length) {\n return null\n }\n\n return this.toAccountContext(allAccounts[index])\n }\n\n /**\n * Get the total number of accounts (including temporary).\n */\n getAccountCount(): number {\n return (this.temporaryAccount ? 1 : 0) + this.accountOrder.length\n }\n\n /**\n * Convert AccountRuntime to AccountContext for service calls.\n */\n private toAccountContext(account: AccountRuntime): AccountContext {\n return {\n githubToken: account.githubToken,\n copilotToken: account.copilotToken,\n accountType: account.accountType,\n vsCodeVersion: account.vsCodeVersion,\n }\n }\n\n /**\n * Start watching the registry file for changes.\n * Enables hot reload of accounts when the file is modified.\n */\n private startRegistryWatcher(): void {\n // Stop existing watcher if any\n this.stopRegistryWatcher()\n\n try {\n this.registryWatcher = fs.watch(\n PATHS.ACCOUNTS_REGISTRY_PATH,\n (eventType) => {\n // Only react to 'change' events (file content modified)\n if (eventType === \"change\") {\n this.scheduleReload()\n }\n },\n )\n\n // Successful start: reset restart backoff.\n this.registryWatcherRestartDelayMs = WATCHER_RESTART_INITIAL_DELAY_MS\n if (this.registryWatcherRestartTimer) {\n clearTimeout(this.registryWatcherRestartTimer)\n this.registryWatcherRestartTimer = undefined\n }\n\n // Handle watcher errors (e.g., file deleted)\n this.registryWatcher.on(\"error\", (error) => {\n consola.debug(\"Registry watcher error:\", error)\n\n const delayMs = this.registryWatcherRestartDelayMs\n this.registryWatcherRestartDelayMs = Math.min(\n this.registryWatcherRestartDelayMs * 2,\n WATCHER_RESTART_MAX_DELAY_MS,\n )\n\n // Close broken watcher to avoid repeated error events.\n this.stopRegistryWatcher()\n\n // Try to restart the watcher after a delay (with backoff)\n this.registryWatcherRestartTimer = setTimeout(() => {\n this.registryWatcherRestartTimer = undefined\n this.startRegistryWatcher()\n }, delayMs)\n\n consola.debug(`Restarting registry watcher in ${delayMs}ms`)\n })\n\n consola.debug(\"Started registry file watcher\")\n } catch (error) {\n consola.warn(\"Failed to start registry watcher:\", error)\n }\n }\n\n /**\n * Schedule a registry reload with debouncing.\n */\n private scheduleReload(): void {\n // Clear existing timer\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n }\n\n // Schedule reload after debounce delay\n this.reloadDebounceTimer = setTimeout(() => {\n void this.reloadRegistry()\n }, RELOAD_DEBOUNCE_MS)\n }\n\n /**\n * Reload the registry and perform incremental updates.\n * Adds new accounts, removes deleted ones, and reinitializes existing accounts\n * when token/accountType changes.\n */\n private async reloadRegistry(): Promise<void> {\n // Prevent concurrent reloads\n if (this.isReloading) {\n return\n }\n this.isReloading = true\n\n try {\n const newMetas = await listAccountsFromRegistry()\n const newIds = new Set(newMetas.map((m) => m.id))\n const currentIds = new Set(this.accountOrder)\n\n // Track changes for logging\n const added: Array<string> = []\n const removed: Array<string> = []\n const updated: Array<string> = []\n\n this.removeDeletedAccounts(currentIds, newIds, removed)\n\n // Add new accounts (newIds - currentIds)\n for (const meta of newMetas) {\n if (!currentIds.has(meta.id)) {\n await this.addNewAccount(meta, added)\n }\n }\n\n // Update existing accounts when meta/token changed\n await this.reinitializeUpdatedAccounts(newMetas, currentIds, updated)\n\n // Update accountOrder to reflect new order\n this.accountOrder = newMetas\n .map((m) => m.id)\n .filter((id) => this.accounts.has(id))\n\n // Reset free-model RR cursor on account list/order changes.\n this.freeModelCursor = 0\n\n this.logRegistryReloadChanges(added, removed, updated)\n } catch (error) {\n consola.error(\"Failed to reload registry:\", error)\n this.shutdown()\n process.exit(1)\n } finally {\n this.isReloading = false\n }\n }\n\n private removeDeletedAccounts(\n currentIds: Set<string>,\n newIds: Set<string>,\n removed: Array<string>,\n ): void {\n for (const id of currentIds) {\n if (!newIds.has(id)) {\n const account = this.accounts.get(id)\n if (!account) {\n continue\n }\n\n this.stopTokenRefresh(account)\n this.accounts.delete(id)\n removed.push(id)\n }\n }\n }\n\n private async reinitializeUpdatedAccounts(\n newMetas: Array<{ id: string; accountType: AccountType; addedAt: number }>,\n currentIds: Set<string>,\n updated: Array<string>,\n ): Promise<void> {\n for (const meta of newMetas) {\n if (!currentIds.has(meta.id)) {\n continue\n }\n\n const account = this.accounts.get(meta.id)\n if (!account) {\n continue\n }\n\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for account ${meta.id}, skipping update`)\n continue\n }\n\n const accountTypeChanged = account.accountType !== meta.accountType\n const tokenChanged = account.githubToken !== token\n const addedAtChanged = account.addedAt !== meta.addedAt\n\n // Keep runtime metadata in sync with the registry.\n if (accountTypeChanged) {\n account.accountType = meta.accountType\n }\n if (addedAtChanged) {\n account.addedAt = meta.addedAt\n }\n if (tokenChanged) {\n account.githubToken = token\n }\n\n if (!accountTypeChanged && !tokenChanged) {\n continue\n }\n\n try {\n await this.initializeAccount(account)\n updated.push(meta.id)\n } catch (error) {\n consola.error(\n `Failed to reinitialize account ${meta.id} after update:`,\n error,\n )\n account.failed = true\n account.failureReason = String(error)\n updated.push(`${meta.id} (failed)`)\n }\n }\n }\n\n private logRegistryReloadChanges(\n added: Array<string>,\n removed: Array<string>,\n updated: Array<string>,\n ): void {\n if (added.length === 0 && removed.length === 0 && updated.length === 0) {\n return\n }\n\n const changes: Array<string> = []\n if (added.length > 0) {\n changes.push(`added: ${added.join(\", \")}`)\n }\n if (removed.length > 0) {\n changes.push(`removed: ${removed.join(\", \")}`)\n }\n if (updated.length > 0) {\n changes.push(`updated: ${updated.join(\", \")}`)\n }\n\n consola.info(\n `Registry reloaded (${changes.join(\"; \")}). Total: ${this.accounts.size} account(s)`,\n )\n }\n\n /**\n * Helper to add a new account during reload.\n */\n private async addNewAccount(\n meta: { id: string; accountType: AccountType; addedAt: number },\n added: Array<string>,\n ): Promise<void> {\n const token = await loadAccountToken(meta.id)\n if (!token) {\n consola.warn(`No token found for new account ${meta.id}, skipping`)\n return\n }\n\n const runtime: AccountRuntime = {\n ...meta,\n githubToken: token,\n vsCodeVersion: this.vsCodeVersion,\n }\n\n try {\n await this.initializeAccount(runtime)\n this.accounts.set(meta.id, runtime)\n added.push(meta.id)\n } catch (error) {\n consola.error(`Failed to initialize new account ${meta.id}:`, error)\n runtime.failed = true\n runtime.failureReason = String(error)\n this.accounts.set(meta.id, runtime)\n added.push(`${meta.id} (failed)`)\n }\n }\n\n /**\n * Stop the registry file watcher.\n */\n private stopRegistryWatcher(): void {\n if (this.reloadDebounceTimer) {\n clearTimeout(this.reloadDebounceTimer)\n this.reloadDebounceTimer = undefined\n }\n if (this.registryWatcherRestartTimer) {\n clearTimeout(this.registryWatcherRestartTimer)\n this.registryWatcherRestartTimer = undefined\n }\n if (this.registryWatcher) {\n this.registryWatcher.close()\n this.registryWatcher = undefined\n }\n }\n\n /**\n * Shutdown the manager and clean up resources.\n */\n shutdown(): void {\n this.stopRegistryWatcher()\n this.stopAllTokenRefresh()\n this.stopModelsRefresh()\n this.accounts.clear()\n this.accountOrder = []\n this.temporaryAccount = undefined\n }\n}\n\n/** Singleton instance of AccountsManager */\nexport const accountsManager = new AccountsManager()\n"],"mappings":"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"}
|
package/dist/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { GITHUB_APP_SCOPES, GITHUB_BASE_URL, GITHUB_CLIENT_ID, HTTPError, PATHS, accountsManager, addAccountToRegistry, cacheVSCodeVersion, ensurePaths, getCopilotUsage, getGitHubUser, getModelRefreshIntervalMs, isFreeModelLoadBalancingEnabled, listAccountsFromRegistry, loadAccountToken, mergeConfigWithDefaults, removeAccountFromRegistry, removeAccountToken, saveAccountToken, saveRegistry, sleep, standardHeaders, state } from "./accounts-manager-
|
|
2
|
+
import { GITHUB_APP_SCOPES, GITHUB_BASE_URL, GITHUB_CLIENT_ID, HTTPError, PATHS, accountsManager, addAccountToRegistry, cacheVSCodeVersion, ensurePaths, getCopilotUsage, getGitHubUser, getModelRefreshIntervalMs, isFreeModelLoadBalancingEnabled, listAccountsFromRegistry, loadAccountToken, mergeConfigWithDefaults, removeAccountFromRegistry, removeAccountToken, saveAccountToken, saveRegistry, sleep, standardHeaders, state } from "./accounts-manager-MluR5e6y.js";
|
|
3
3
|
import { defineCommand, runMain } from "citty";
|
|
4
4
|
import consola from "consola";
|
|
5
5
|
import fs from "node:fs/promises";
|
|
@@ -633,7 +633,7 @@ async function runServer(options) {
|
|
|
633
633
|
}
|
|
634
634
|
}
|
|
635
635
|
consola.box(`🌐 Usage Viewer: https://ericc-ch.github.io/copilot-api?endpoint=${serverUrl}/usage`);
|
|
636
|
-
const { server } = await import("./server-
|
|
636
|
+
const { server } = await import("./server-6hnk3aRJ.js");
|
|
637
637
|
serve({
|
|
638
638
|
fetch: server.fetch,
|
|
639
639
|
port: options.port,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HTTPError, PATHS, accountFromState, accountsManager, copilotBaseUrl, copilotHeaders, forwardError, getAliasTargetSet, getConfig, getCopilotUsage, getExtraPromptForModel, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getReasoningEffortForModel, getSmallModel, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isNullish, listAccountsFromRegistry, mergeConfigWithDefaults, shouldCompactUseSmallModel, sleep, state } from "./accounts-manager-
|
|
1
|
+
import { HTTPError, PATHS, accountFromState, accountsManager, copilotBaseUrl, copilotHeaders, forwardError, getAliasTargetSet, getConfig, getCopilotUsage, getExtraPromptForModel, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getReasoningEffortForModel, getSmallModel, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isNullish, listAccountsFromRegistry, mergeConfigWithDefaults, shouldCompactUseSmallModel, sleep, state } from "./accounts-manager-MluR5e6y.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";
|
|
@@ -2642,7 +2642,7 @@ const createChatCompletions = async (payload, account, options) => {
|
|
|
2642
2642
|
const ctx = account ?? accountFromState();
|
|
2643
2643
|
if (!ctx.copilotToken) throw new Error("Copilot token not found");
|
|
2644
2644
|
const enableVision = payload.messages.some((x) => typeof x.content !== "string" && x.content?.some((x$1) => x$1.type === "image_url"));
|
|
2645
|
-
const initiator = getChatInitiator(payload.messages);
|
|
2645
|
+
const initiator = options?.initiator ?? getChatInitiator(payload.messages);
|
|
2646
2646
|
const headers = {
|
|
2647
2647
|
...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
|
|
2648
2648
|
"X-Initiator": initiator
|
|
@@ -4091,7 +4091,7 @@ const createMessages = async (payload, account, options) => {
|
|
|
4091
4091
|
const ctx = account ?? accountFromState();
|
|
4092
4092
|
if (!ctx.copilotToken) throw new Error("Copilot token not found");
|
|
4093
4093
|
const enableVision = payload.messages.some((message) => Array.isArray(message.content) && message.content.some((block) => block.type === "image"));
|
|
4094
|
-
const initiator = getMessagesInitiator(payload);
|
|
4094
|
+
const initiator = options?.initiator ?? getMessagesInitiator(payload);
|
|
4095
4095
|
const headers = {
|
|
4096
4096
|
...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
|
|
4097
4097
|
"X-Initiator": initiator
|
|
@@ -4369,6 +4369,51 @@ function closeThinkingBlockIfOpen(state$1, events$1) {
|
|
|
4369
4369
|
}
|
|
4370
4370
|
}
|
|
4371
4371
|
|
|
4372
|
+
//#endregion
|
|
4373
|
+
//#region src/routes/messages/subagent-marker.ts
|
|
4374
|
+
const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
|
|
4375
|
+
const parseSubagentMarkerFromFirstUser = (payload) => {
|
|
4376
|
+
const firstUserMessage = payload.messages.find((msg) => msg.role === "user");
|
|
4377
|
+
if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return null;
|
|
4378
|
+
for (const block of firstUserMessage.content) {
|
|
4379
|
+
if (block.type !== "text") continue;
|
|
4380
|
+
const marker = parseSubagentMarkerFromSystemReminder(block.text);
|
|
4381
|
+
if (marker) return marker;
|
|
4382
|
+
}
|
|
4383
|
+
return null;
|
|
4384
|
+
};
|
|
4385
|
+
const parseSubagentMarkerFromSystemReminder = (text) => {
|
|
4386
|
+
const startTag = "<system-reminder>";
|
|
4387
|
+
const endTag = "</system-reminder>";
|
|
4388
|
+
let searchFrom = 0;
|
|
4389
|
+
while (true) {
|
|
4390
|
+
const reminderStart = text.indexOf(startTag, searchFrom);
|
|
4391
|
+
if (reminderStart === -1) break;
|
|
4392
|
+
const contentStart = reminderStart + 17;
|
|
4393
|
+
const reminderEnd = text.indexOf(endTag, contentStart);
|
|
4394
|
+
if (reminderEnd === -1) break;
|
|
4395
|
+
const reminderContent = text.slice(contentStart, reminderEnd);
|
|
4396
|
+
const markerIndex = reminderContent.indexOf(subagentMarkerPrefix);
|
|
4397
|
+
if (markerIndex === -1) {
|
|
4398
|
+
searchFrom = reminderEnd + 18;
|
|
4399
|
+
continue;
|
|
4400
|
+
}
|
|
4401
|
+
const markerJson = reminderContent.slice(markerIndex + 19).trim();
|
|
4402
|
+
try {
|
|
4403
|
+
const parsed = JSON.parse(markerJson);
|
|
4404
|
+
if (!parsed.session_id || !parsed.agent_id || !parsed.agent_type) {
|
|
4405
|
+
searchFrom = reminderEnd + 18;
|
|
4406
|
+
continue;
|
|
4407
|
+
}
|
|
4408
|
+
return parsed;
|
|
4409
|
+
} catch {
|
|
4410
|
+
searchFrom = reminderEnd + 18;
|
|
4411
|
+
continue;
|
|
4412
|
+
}
|
|
4413
|
+
}
|
|
4414
|
+
return null;
|
|
4415
|
+
};
|
|
4416
|
+
|
|
4372
4417
|
//#endregion
|
|
4373
4418
|
//#region src/routes/messages/handler.ts
|
|
4374
4419
|
const logger$2 = createHandlerLogger("messages-handler");
|
|
@@ -4387,6 +4432,9 @@ async function handleCompletion(c) {
|
|
|
4387
4432
|
const userAgent = c.req.header("user-agent") ?? void 0;
|
|
4388
4433
|
const anthropicPayload = await c.req.json();
|
|
4389
4434
|
logger$2.debug("Anthropic request payload:", JSON.stringify(anthropicPayload));
|
|
4435
|
+
const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
|
|
4436
|
+
const initiatorOverride = subagentMarker ? "agent" : void 0;
|
|
4437
|
+
if (subagentMarker) logger$2.debug("Detected Subagent marker:", JSON.stringify(subagentMarker));
|
|
4390
4438
|
const anthropicBeta = c.req.header("anthropic-beta");
|
|
4391
4439
|
const isCompact = isCompactRequest(anthropicPayload);
|
|
4392
4440
|
if (anthropicBeta && isWarmupProbeRequest(anthropicPayload)) anthropicPayload.model = getSmallModel();
|
|
@@ -4415,11 +4463,12 @@ async function handleCompletion(c) {
|
|
|
4415
4463
|
userAgent,
|
|
4416
4464
|
userId,
|
|
4417
4465
|
safetyIdentifier: normalizedSafetyIdentifier,
|
|
4418
|
-
promptCacheKey: normalizedPromptCacheKey
|
|
4466
|
+
promptCacheKey: normalizedPromptCacheKey,
|
|
4467
|
+
initiator: initiatorOverride
|
|
4419
4468
|
});
|
|
4420
4469
|
if (blockedResponse) return blockedResponse;
|
|
4421
4470
|
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
4422
|
-
const fallbackInitiator = getChatInitiator(openAIPayload.messages);
|
|
4471
|
+
const fallbackInitiator = initiatorOverride ?? getChatInitiator(openAIPayload.messages);
|
|
4423
4472
|
const selection = await accountsManager.selectAccountForRequest([
|
|
4424
4473
|
{
|
|
4425
4474
|
modelId: clientModel,
|
|
@@ -4482,6 +4531,7 @@ async function handleCompletion(c) {
|
|
|
4482
4531
|
c,
|
|
4483
4532
|
anthropicPayload,
|
|
4484
4533
|
anthropicBetaHeader: anthropicBeta ?? void 0,
|
|
4534
|
+
initiatorOverride,
|
|
4485
4535
|
instr,
|
|
4486
4536
|
selectedModel
|
|
4487
4537
|
});
|
|
@@ -4489,27 +4539,32 @@ async function handleCompletion(c) {
|
|
|
4489
4539
|
c,
|
|
4490
4540
|
anthropicPayload,
|
|
4491
4541
|
openAIPayload,
|
|
4542
|
+
initiatorOverride,
|
|
4492
4543
|
selectedModel,
|
|
4493
4544
|
instr
|
|
4494
4545
|
});
|
|
4495
4546
|
return await handleWithChatCompletions({
|
|
4496
4547
|
c,
|
|
4497
4548
|
openAIPayload,
|
|
4549
|
+
initiatorOverride,
|
|
4498
4550
|
selectedModel,
|
|
4499
4551
|
instr
|
|
4500
4552
|
});
|
|
4501
4553
|
}
|
|
4502
4554
|
const handleWithChatCompletions = async (params) => {
|
|
4503
|
-
const { c, openAIPayload, selectedModel, instr } = params;
|
|
4555
|
+
const { c, openAIPayload, initiatorOverride, selectedModel, instr } = params;
|
|
4504
4556
|
logger$2.debug("Translated OpenAI request payload:", JSON.stringify(openAIPayload));
|
|
4505
4557
|
const ctx = toAccountContext(instr.account);
|
|
4506
|
-
const initiator = getChatInitiator(openAIPayload.messages);
|
|
4558
|
+
const initiator = initiatorOverride ?? getChatInitiator(openAIPayload.messages);
|
|
4507
4559
|
const upstreamRequestId = randomUUID();
|
|
4508
4560
|
instr.initiator = initiator;
|
|
4509
4561
|
instr.upstreamRequestId = upstreamRequestId;
|
|
4510
4562
|
let response;
|
|
4511
4563
|
try {
|
|
4512
|
-
response = await createChatCompletions(openAIPayload, ctx, {
|
|
4564
|
+
response = await createChatCompletions(openAIPayload, ctx, {
|
|
4565
|
+
upstreamRequestId,
|
|
4566
|
+
initiator
|
|
4567
|
+
});
|
|
4513
4568
|
} catch (error) {
|
|
4514
4569
|
return await handleChatCompletionsCreateError({
|
|
4515
4570
|
error,
|
|
@@ -4539,19 +4594,20 @@ const handleWithChatCompletions = async (params) => {
|
|
|
4539
4594
|
}));
|
|
4540
4595
|
};
|
|
4541
4596
|
const handleWithResponsesApi = async (params) => {
|
|
4542
|
-
const { c, anthropicPayload, openAIPayload, selectedModel, instr } = params;
|
|
4597
|
+
const { c, anthropicPayload, openAIPayload, initiatorOverride, selectedModel, instr } = params;
|
|
4543
4598
|
const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload, selectedModel.id);
|
|
4544
4599
|
logger$2.debug("Translated Responses payload:", JSON.stringify(responsesPayload));
|
|
4545
4600
|
const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
|
|
4601
|
+
const resolvedInitiator = initiatorOverride ?? initiator;
|
|
4546
4602
|
const ctx = toAccountContext(instr.account);
|
|
4547
4603
|
const upstreamRequestId = randomUUID();
|
|
4548
|
-
instr.initiator =
|
|
4604
|
+
instr.initiator = resolvedInitiator;
|
|
4549
4605
|
instr.upstreamRequestId = upstreamRequestId;
|
|
4550
4606
|
let response;
|
|
4551
4607
|
try {
|
|
4552
4608
|
response = await createResponses(responsesPayload, {
|
|
4553
4609
|
vision,
|
|
4554
|
-
initiator,
|
|
4610
|
+
initiator: resolvedInitiator,
|
|
4555
4611
|
upstreamRequestId
|
|
4556
4612
|
}, ctx);
|
|
4557
4613
|
} catch (error) {
|
|
@@ -5003,7 +5059,7 @@ async function streamMessagesAndLog(params) {
|
|
|
5003
5059
|
}
|
|
5004
5060
|
}
|
|
5005
5061
|
const handleWithMessagesApi = async (params) => {
|
|
5006
|
-
const { c, anthropicPayload, anthropicBetaHeader, instr, selectedModel } = params;
|
|
5062
|
+
const { c, anthropicPayload, anthropicBetaHeader, initiatorOverride, instr, selectedModel } = params;
|
|
5007
5063
|
for (const msg of anthropicPayload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
|
|
5008
5064
|
if (block.type !== "thinking") return true;
|
|
5009
5065
|
return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
|
|
@@ -5015,13 +5071,15 @@ const handleWithMessagesApi = async (params) => {
|
|
|
5015
5071
|
logger$2.debug("Translated Messages payload:", JSON.stringify(anthropicPayload));
|
|
5016
5072
|
const ctx = toAccountContext(instr.account);
|
|
5017
5073
|
const upstreamRequestId = randomUUID();
|
|
5018
|
-
|
|
5074
|
+
const initiator = initiatorOverride ?? getMessagesInitiator(anthropicPayload);
|
|
5075
|
+
instr.initiator = initiator;
|
|
5019
5076
|
instr.upstreamRequestId = upstreamRequestId;
|
|
5020
5077
|
let response;
|
|
5021
5078
|
try {
|
|
5022
5079
|
response = await createMessages(anthropicPayload, ctx, {
|
|
5023
5080
|
anthropicBetaHeader,
|
|
5024
|
-
upstreamRequestId
|
|
5081
|
+
upstreamRequestId,
|
|
5082
|
+
initiator
|
|
5025
5083
|
});
|
|
5026
5084
|
} catch (error) {
|
|
5027
5085
|
return await handleMessagesCreateError({
|
|
@@ -5687,4 +5745,4 @@ server.route("/v1/messages", messageRoutes);
|
|
|
5687
5745
|
|
|
5688
5746
|
//#endregion
|
|
5689
5747
|
export { server };
|
|
5690
|
-
//# sourceMappingURL=server-
|
|
5748
|
+
//# sourceMappingURL=server-6hnk3aRJ.js.map
|