copilot-api-plus 1.0.50 → 1.0.52
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 +31 -0
- package/dist/error-DNWWcl_s.js +3 -0
- package/dist/{error-CvU5otz-.js → error-SzJ4KHd8.js} +7 -2
- package/dist/error-SzJ4KHd8.js.map +1 -0
- package/dist/get-models-uEbEgq0L.js.map +1 -1
- package/dist/{get-user-BzIEATcF.js → get-user-DEDD9jIs.js} +2 -2
- package/dist/get-user-DEDD9jIs.js.map +1 -0
- package/dist/get-user-HhhC3uQr.js +5 -0
- package/dist/main.js +216 -345
- package/dist/main.js.map +1 -1
- package/dist/{token-B777vbx8.js → token-CpxbiiIw.js} +31 -9
- package/dist/token-CpxbiiIw.js.map +1 -0
- package/dist/token-DkNaoDp7.js +7 -0
- package/package.json +1 -1
- package/dist/error-CsShqJjE.js +0 -3
- package/dist/error-CvU5otz-.js.map +0 -1
- package/dist/get-user-BzIEATcF.js.map +0 -1
- package/dist/get-user-CsQCc3Qx.js +0 -5
- package/dist/token-B777vbx8.js.map +0 -1
- package/dist/token-CCg0yU7a.js +0 -7
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Copilot API Plus
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/copilot-api-plus)
|
|
4
|
+
[](https://github.com/imbuxiangnan-cyber/copilot-api-plus/blob/main/LICENSE)
|
|
5
|
+
|
|
6
|
+
> A proxy that converts GitHub Copilot, OpenCode Zen, and Google Antigravity into OpenAI & Anthropic compatible APIs. Works with Claude Code, opencode, and more.
|
|
7
|
+
|
|
3
8
|
将 GitHub Copilot、OpenCode Zen、Google Antigravity 等 AI 服务转换为 **OpenAI** 和 **Anthropic** 兼容 API,支持与 [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview)、[opencode](https://github.com/sst/opencode) 等工具无缝集成。
|
|
4
9
|
|
|
5
10
|
---
|
|
@@ -673,6 +678,32 @@ Google Antigravity 模式内置了可靠性保障:
|
|
|
673
678
|
- **按模型族速率追踪**:分别追踪 Gemini 和 Claude 模型族的速率限制状态
|
|
674
679
|
- **指数退避重试**:429/503 等限流错误自动退避重试,短间隔走同端点,长间隔切换端点
|
|
675
680
|
|
|
681
|
+
### 请求日志
|
|
682
|
+
|
|
683
|
+
每次 API 请求会输出一行日志,包含模型名、耗时和 token 用量:
|
|
684
|
+
|
|
685
|
+
```
|
|
686
|
+
[claude-opus-4-6] 13:13:39 --> POST /v1/messages?beta=true 200 20.1s [in:87356 out:171 cache_read:13016]
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
- `in` — 输入 token 数(不含缓存命中部分)
|
|
690
|
+
- `out` — 输出 token 数
|
|
691
|
+
- `cache_read` — 缓存命中的 token 数(仅在有缓存时显示)
|
|
692
|
+
|
|
693
|
+
触发上下文压缩时会额外输出一行:
|
|
694
|
+
|
|
695
|
+
```
|
|
696
|
+
Truncated: 190385 -> 117537 tokens (-59 msgs)
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
### 网络重试
|
|
700
|
+
|
|
701
|
+
对上游 API 的请求内置了瞬时网络错误重试(TLS 断开、连接重置等):
|
|
702
|
+
|
|
703
|
+
- 最多重试 2 次(共 3 次尝试)
|
|
704
|
+
- 退避间隔:1s、2s
|
|
705
|
+
- 仅重试网络层错误,HTTP 错误码(如 400/500)不重试
|
|
706
|
+
|
|
676
707
|
---
|
|
677
708
|
|
|
678
709
|
## 🐳 Docker 部署
|
|
@@ -11,7 +11,12 @@ var HTTPError = class extends Error {
|
|
|
11
11
|
async function forwardError(c, error) {
|
|
12
12
|
consola.error("Error occurred:", error);
|
|
13
13
|
if (error instanceof HTTPError) {
|
|
14
|
-
|
|
14
|
+
let errorText;
|
|
15
|
+
try {
|
|
16
|
+
errorText = await error.response.text();
|
|
17
|
+
} catch {
|
|
18
|
+
errorText = error.message;
|
|
19
|
+
}
|
|
15
20
|
let errorJson;
|
|
16
21
|
try {
|
|
17
22
|
errorJson = JSON.parse(errorText);
|
|
@@ -32,4 +37,4 @@ async function forwardError(c, error) {
|
|
|
32
37
|
|
|
33
38
|
//#endregion
|
|
34
39
|
export { HTTPError, forwardError };
|
|
35
|
-
//# sourceMappingURL=error-
|
|
40
|
+
//# sourceMappingURL=error-SzJ4KHd8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-SzJ4KHd8.js","names":["errorText: string","errorJson: unknown"],"sources":["../src/lib/error.ts"],"sourcesContent":["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 // Try to read error body, but it may already be consumed by the caller\n let errorText: string\n try {\n errorText = await error.response.text()\n } catch {\n // Body already read — fall back to the error message\n errorText = error.message\n }\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"],"mappings":";;;AAKA,IAAa,YAAb,cAA+B,MAAM;CACnC;CAEA,YAAY,SAAiB,UAAoB;AAC/C,QAAM,QAAQ;AACd,OAAK,WAAW;;;AAIpB,eAAsB,aAAa,GAAY,OAAgB;AAC7D,SAAQ,MAAM,mBAAmB,MAAM;AAEvC,KAAI,iBAAiB,WAAW;EAE9B,IAAIA;AACJ,MAAI;AACF,eAAY,MAAM,MAAM,SAAS,MAAM;UACjC;AAEN,eAAY,MAAM;;EAEpB,IAAIC;AACJ,MAAI;AACF,eAAY,KAAK,MAAM,UAAU;UAC3B;AACN,eAAY;;AAEd,UAAQ,MAAM,eAAe,UAAU;AACvC,SAAO,EAAE,KACP,EACE,OAAO;GACL,SAAS;GACT,MAAM;GACP,EACF,EACD,MAAM,SAAS,OAChB;;AAGH,QAAO,EAAE,KACP,EACE,OAAO;EACL,SAAU,MAAgB;EAC1B,MAAM;EACP,EACF,EACD,IACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-models-uEbEgq0L.js","names":["FALLBACK_MODELS: Array<AntigravityModel>","cachedModels: Array<AntigravityModel> | null","cacheTimestamp: number","models: Array<AntigravityModel>","modelsQuota: Record<string, {\r\n remaining_fraction: number\r\n reset_time: string\r\n percent_remaining: number\r\n }>"],"sources":["../src/services/antigravity/get-models.ts"],"sourcesContent":["/**\r\n * Google Antigravity Models\r\n *\r\n * Provides list of available models from Antigravity.\r\n * Based on: https://github.com/liuw1535/antigravity2api-nodejs\r\n */\r\n\r\n/* eslint-disable require-atomic-updates */\r\n\r\nimport consola from \"consola\"\r\n\r\nimport { getValidAccessToken } from \"./auth\"\r\n\r\n// Antigravity API endpoints\r\nconst ANTIGRAVITY_API_HOST = \"daily-cloudcode-pa.sandbox.googleapis.com\"\r\nconst ANTIGRAVITY_MODELS_URL = `https://${ANTIGRAVITY_API_HOST}/v1internal:fetchAvailableModels`\r\nconst ANTIGRAVITY_USER_AGENT = \"antigravity/1.11.3 windows/amd64\"\r\n\r\nexport interface AntigravityQuotaInfo {\r\n remainingFraction: number\r\n resetTime: string\r\n}\r\n\r\nexport interface AntigravityModel {\r\n id: string\r\n object: string\r\n created: number\r\n owned_by: string\r\n quotaInfo?: AntigravityQuotaInfo\r\n}\r\n\r\nexport interface AntigravityModelsResponse {\r\n object: string\r\n data: Array<AntigravityModel>\r\n}\r\n\r\n/**\r\n * Fallback Antigravity models when API is unavailable\r\n * Updated based on actual API response (December 2024)\r\n */\r\nconst FALLBACK_MODELS: Array<AntigravityModel> = [\r\n // Gemini models\r\n {\r\n id: \"gemini-2.5-pro\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"google\",\r\n },\r\n {\r\n id: \"gemini-2.5-flash\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"google\",\r\n },\r\n {\r\n id: \"gemini-2.5-flash-lite\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"google\",\r\n },\r\n {\r\n id: \"gemini-2.5-flash-thinking\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"google\",\r\n },\r\n {\r\n id: \"gemini-3-pro-low\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"google\",\r\n },\r\n {\r\n id: \"gemini-3-pro-high\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"google\",\r\n },\r\n {\r\n id: \"gemini-3-pro-image\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"google\",\r\n },\r\n {\r\n id: \"gemini-3-flash\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"google\",\r\n },\r\n\r\n // Claude models (via Antigravity)\r\n {\r\n id: \"claude-sonnet-4-5\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"anthropic\",\r\n },\r\n {\r\n id: \"claude-sonnet-4-5-thinking\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"anthropic\",\r\n },\r\n {\r\n id: \"claude-opus-4-5-thinking\",\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: \"anthropic\",\r\n },\r\n]\r\n\r\n// Cache for fetched models\r\nlet cachedModels: Array<AntigravityModel> | null = null\r\nlet cacheTimestamp: number = 0\r\nconst CACHE_TTL = 5 * 60 * 1000 // 5 minutes\r\n\r\n/**\r\n * Fetch models from Antigravity API\r\n */\r\nasync function fetchModelsFromApi(): Promise<Array<AntigravityModel> | null> {\r\n const accessToken = await getValidAccessToken()\r\n\r\n if (!accessToken) {\r\n consola.debug(\"No access token available, using fallback models\")\r\n return null\r\n }\r\n\r\n try {\r\n const response = await fetch(ANTIGRAVITY_MODELS_URL, {\r\n method: \"POST\",\r\n headers: {\r\n Host: ANTIGRAVITY_API_HOST,\r\n \"User-Agent\": ANTIGRAVITY_USER_AGENT,\r\n Authorization: `Bearer ${accessToken}`,\r\n \"Content-Type\": \"application/json\",\r\n \"Accept-Encoding\": \"gzip\",\r\n },\r\n body: JSON.stringify({}),\r\n })\r\n\r\n if (!response.ok) {\r\n consola.warn(`Failed to fetch Antigravity models: ${response.status}`)\r\n return null\r\n }\r\n\r\n // API returns models as object (dictionary), not array\r\n // Format: { \"models\": { \"model-id\": { \"quotaInfo\": {...}, \"apiProvider\": \"...\", ... }, ... } }\r\n const data = (await response.json()) as {\r\n models?: Record<string, {\r\n displayName?: string\r\n maxTokens?: number\r\n apiProvider?: string\r\n model?: string\r\n quotaInfo?: {\r\n remainingFraction?: number\r\n resetTime?: string\r\n }\r\n }>\r\n }\r\n\r\n if (!data.models || typeof data.models !== \"object\") {\r\n consola.warn(\"No models object in response\")\r\n return null\r\n }\r\n\r\n // Convert object to array format\r\n const modelEntries = Object.entries(data.models)\r\n consola.debug(`Antigravity API returned ${modelEntries.length} models`)\r\n\r\n // Filter to only include Gemini and Claude models (skip internal models like chat_20706)\r\n const models: Array<AntigravityModel> = modelEntries\r\n .filter(([modelId, info]) => {\r\n // Only include gemini, learnlm, and claude models\r\n const isPublicModel = modelId.startsWith(\"gemini\") ||\r\n modelId.startsWith(\"learnlm\") ||\r\n modelId.startsWith(\"claude\")\r\n // Filter out models with no remaining quota\r\n const remaining = info.quotaInfo?.remainingFraction ?? 1\r\n return isPublicModel && remaining > 0\r\n })\r\n .map(([modelId, info]) => {\r\n const isGoogle = modelId.startsWith(\"gemini\") || modelId.startsWith(\"learnlm\")\r\n\r\n return {\r\n id: modelId,\r\n object: \"model\",\r\n created: 1700000000,\r\n owned_by: isGoogle ? \"google\" : \"anthropic\",\r\n quotaInfo: info.quotaInfo ? {\r\n remainingFraction: info.quotaInfo.remainingFraction ?? 1,\r\n resetTime: info.quotaInfo.resetTime ?? \"\",\r\n } : undefined,\r\n }\r\n })\r\n\r\n consola.debug(`Fetched ${models.length} models from Antigravity API`)\r\n return models\r\n } catch (error) {\r\n consola.warn(\"Error fetching Antigravity models:\", error)\r\n return null\r\n }\r\n}\r\n\r\n/**\r\n * Get available Antigravity models\r\n */\r\nexport async function getAntigravityModels(): Promise<AntigravityModelsResponse> {\r\n // Check cache\r\n if (cachedModels && Date.now() - cacheTimestamp < CACHE_TTL) {\r\n consola.debug(`Returning ${cachedModels.length} cached Antigravity models`)\r\n return {\r\n object: \"list\",\r\n data: cachedModels,\r\n }\r\n }\r\n\r\n // Try to fetch from API\r\n const apiModels = await fetchModelsFromApi()\r\n\r\n if (apiModels && apiModels.length > 0) {\r\n cachedModels = apiModels\r\n cacheTimestamp = Date.now()\r\n\r\n return {\r\n object: \"list\",\r\n data: apiModels,\r\n }\r\n }\r\n\r\n // Use fallback models\r\n consola.debug(\r\n `Returning ${FALLBACK_MODELS.length} fallback Antigravity models`,\r\n )\r\n\r\n return {\r\n object: \"list\",\r\n data: FALLBACK_MODELS,\r\n }\r\n}\r\n\r\n/**\r\n * Antigravity usage response format (compatible with Copilot usage viewer)\r\n */\r\nexport interface AntigravityUsageResponse {\r\n copilot_plan: string\r\n quota_reset_date: string\r\n quota_snapshots: {\r\n models: Record<string, {\r\n remaining_fraction: number\r\n reset_time: string\r\n percent_remaining: number\r\n }>\r\n }\r\n}\r\n\r\n/**\r\n * Get Antigravity usage/quota information\r\n */\r\nexport async function getAntigravityUsage(): Promise<AntigravityUsageResponse> {\r\n // Force refresh models to get latest quota\r\n cachedModels = null\r\n cacheTimestamp = 0\r\n\r\n const modelsResponse = await getAntigravityModels()\r\n\r\n // Find earliest reset time\r\n let earliestResetTime = \"\"\r\n const modelsQuota: Record<string, {\r\n remaining_fraction: number\r\n reset_time: string\r\n percent_remaining: number\r\n }> = {}\r\n\r\n let modelsWithQuota = 0\r\n for (const model of modelsResponse.data) {\r\n if (model.quotaInfo) {\r\n modelsWithQuota++\r\n const resetTime = model.quotaInfo.resetTime\r\n if (!earliestResetTime || (resetTime && resetTime < earliestResetTime)) {\r\n earliestResetTime = resetTime\r\n }\r\n\r\n modelsQuota[model.id] = {\r\n remaining_fraction: model.quotaInfo.remainingFraction,\r\n reset_time: model.quotaInfo.resetTime,\r\n percent_remaining: Math.round(model.quotaInfo.remainingFraction * 100),\r\n }\r\n }\r\n }\r\n\r\n consola.debug(`Antigravity usage: ${modelsWithQuota}/${modelsResponse.data.length} models have quota info`)\r\n\r\n return {\r\n copilot_plan: \"antigravity\",\r\n quota_reset_date: earliestResetTime,\r\n quota_snapshots: {\r\n models: modelsQuota,\r\n },\r\n }\r\n}\r\n\r\n/**\r\n * Check if a model is a Claude model\r\n */\r\nexport function isClaudeModel(modelId: string): boolean {\r\n return modelId.startsWith(\"claude-\")\r\n}\r\n\r\n/**\r\n * Check if a model is a thinking/reasoning model\r\n */\r\nexport function isThinkingModel(modelId: string): boolean {\r\n return modelId.includes(\"thinking\")\r\n}\r\n\r\n/**\r\n * Check if a model is an image generation model\r\n */\r\nexport function isImageModel(modelId: string): boolean {\r\n return modelId.includes(\"image\")\r\n}\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"get-models-uEbEgq0L.js","names":["FALLBACK_MODELS: Array<AntigravityModel>","cachedModels: Array<AntigravityModel> | null","cacheTimestamp: number","models: Array<AntigravityModel>","modelsQuota: Record<\n string,\n {\n remaining_fraction: number\n reset_time: string\n percent_remaining: number\n }\n >"],"sources":["../src/services/antigravity/get-models.ts"],"sourcesContent":["/**\n * Google Antigravity Models\n *\n * Provides list of available models from Antigravity.\n * Based on: https://github.com/liuw1535/antigravity2api-nodejs\n */\n\n/* eslint-disable require-atomic-updates */\n\nimport consola from \"consola\"\n\nimport { getValidAccessToken } from \"./auth\"\n\n// Antigravity API endpoints\nconst ANTIGRAVITY_API_HOST = \"daily-cloudcode-pa.sandbox.googleapis.com\"\nconst ANTIGRAVITY_MODELS_URL = `https://${ANTIGRAVITY_API_HOST}/v1internal:fetchAvailableModels`\nconst ANTIGRAVITY_USER_AGENT = \"antigravity/1.11.3 windows/amd64\"\n\nexport interface AntigravityQuotaInfo {\n remainingFraction: number\n resetTime: string\n}\n\nexport interface AntigravityModel {\n id: string\n object: string\n created: number\n owned_by: string\n quotaInfo?: AntigravityQuotaInfo\n}\n\nexport interface AntigravityModelsResponse {\n object: string\n data: Array<AntigravityModel>\n}\n\n/**\n * Fallback Antigravity models when API is unavailable\n * Updated based on actual API response (December 2024)\n */\nconst FALLBACK_MODELS: Array<AntigravityModel> = [\n // Gemini models\n {\n id: \"gemini-2.5-pro\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.5-flash\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.5-flash-lite\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-2.5-flash-thinking\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-3-pro-low\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-3-pro-high\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-3-pro-image\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n {\n id: \"gemini-3-flash\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"google\",\n },\n\n // Claude models (via Antigravity)\n {\n id: \"claude-sonnet-4-5\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-sonnet-4-5-thinking\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n {\n id: \"claude-opus-4-5-thinking\",\n object: \"model\",\n created: 1700000000,\n owned_by: \"anthropic\",\n },\n]\n\n// Cache for fetched models\nlet cachedModels: Array<AntigravityModel> | null = null\nlet cacheTimestamp: number = 0\nconst CACHE_TTL = 5 * 60 * 1000 // 5 minutes\n\n/**\n * Fetch models from Antigravity API\n */\nasync function fetchModelsFromApi(): Promise<Array<AntigravityModel> | null> {\n const accessToken = await getValidAccessToken()\n\n if (!accessToken) {\n consola.debug(\"No access token available, using fallback models\")\n return null\n }\n\n try {\n const response = await fetch(ANTIGRAVITY_MODELS_URL, {\n method: \"POST\",\n headers: {\n Host: ANTIGRAVITY_API_HOST,\n \"User-Agent\": ANTIGRAVITY_USER_AGENT,\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n \"Accept-Encoding\": \"gzip\",\n },\n body: JSON.stringify({}),\n })\n\n if (!response.ok) {\n consola.warn(`Failed to fetch Antigravity models: ${response.status}`)\n return null\n }\n\n // API returns models as object (dictionary), not array\n // Format: { \"models\": { \"model-id\": { \"quotaInfo\": {...}, \"apiProvider\": \"...\", ... }, ... } }\n const data = (await response.json()) as {\n models?: Record<\n string,\n {\n displayName?: string\n maxTokens?: number\n apiProvider?: string\n model?: string\n quotaInfo?: {\n remainingFraction?: number\n resetTime?: string\n }\n }\n >\n }\n\n if (!data.models || typeof data.models !== \"object\") {\n consola.warn(\"No models object in response\")\n return null\n }\n\n // Convert object to array format\n const modelEntries = Object.entries(data.models)\n consola.debug(`Antigravity API returned ${modelEntries.length} models`)\n\n // Filter to only include Gemini and Claude models (skip internal models like chat_20706)\n const models: Array<AntigravityModel> = modelEntries\n .filter(([modelId, info]) => {\n // Only include gemini, learnlm, and claude models\n const isPublicModel =\n modelId.startsWith(\"gemini\")\n || modelId.startsWith(\"learnlm\")\n || modelId.startsWith(\"claude\")\n // Filter out models with no remaining quota\n const remaining = info.quotaInfo?.remainingFraction ?? 1\n return isPublicModel && remaining > 0\n })\n .map(([modelId, info]) => {\n const isGoogle =\n modelId.startsWith(\"gemini\") || modelId.startsWith(\"learnlm\")\n\n return {\n id: modelId,\n object: \"model\",\n created: 1700000000,\n owned_by: isGoogle ? \"google\" : \"anthropic\",\n quotaInfo:\n info.quotaInfo ?\n {\n remainingFraction: info.quotaInfo.remainingFraction ?? 1,\n resetTime: info.quotaInfo.resetTime ?? \"\",\n }\n : undefined,\n }\n })\n\n consola.debug(`Fetched ${models.length} models from Antigravity API`)\n return models\n } catch (error) {\n consola.warn(\"Error fetching Antigravity models:\", error)\n return null\n }\n}\n\n/**\n * Get available Antigravity models\n */\nexport async function getAntigravityModels(): Promise<AntigravityModelsResponse> {\n // Check cache\n if (cachedModels && Date.now() - cacheTimestamp < CACHE_TTL) {\n consola.debug(`Returning ${cachedModels.length} cached Antigravity models`)\n return {\n object: \"list\",\n data: cachedModels,\n }\n }\n\n // Try to fetch from API\n const apiModels = await fetchModelsFromApi()\n\n if (apiModels && apiModels.length > 0) {\n cachedModels = apiModels\n cacheTimestamp = Date.now()\n\n return {\n object: \"list\",\n data: apiModels,\n }\n }\n\n // Use fallback models\n consola.debug(\n `Returning ${FALLBACK_MODELS.length} fallback Antigravity models`,\n )\n\n return {\n object: \"list\",\n data: FALLBACK_MODELS,\n }\n}\n\n/**\n * Antigravity usage response format (compatible with Copilot usage viewer)\n */\nexport interface AntigravityUsageResponse {\n copilot_plan: string\n quota_reset_date: string\n quota_snapshots: {\n models: Record<\n string,\n {\n remaining_fraction: number\n reset_time: string\n percent_remaining: number\n }\n >\n }\n}\n\n/**\n * Get Antigravity usage/quota information\n */\nexport async function getAntigravityUsage(): Promise<AntigravityUsageResponse> {\n // Force refresh models to get latest quota\n cachedModels = null\n cacheTimestamp = 0\n\n const modelsResponse = await getAntigravityModels()\n\n // Find earliest reset time\n let earliestResetTime = \"\"\n const modelsQuota: Record<\n string,\n {\n remaining_fraction: number\n reset_time: string\n percent_remaining: number\n }\n > = {}\n\n let modelsWithQuota = 0\n for (const model of modelsResponse.data) {\n if (model.quotaInfo) {\n modelsWithQuota++\n const resetTime = model.quotaInfo.resetTime\n if (!earliestResetTime || (resetTime && resetTime < earliestResetTime)) {\n earliestResetTime = resetTime\n }\n\n modelsQuota[model.id] = {\n remaining_fraction: model.quotaInfo.remainingFraction,\n reset_time: model.quotaInfo.resetTime,\n percent_remaining: Math.round(model.quotaInfo.remainingFraction * 100),\n }\n }\n }\n\n consola.debug(\n `Antigravity usage: ${modelsWithQuota}/${modelsResponse.data.length} models have quota info`,\n )\n\n return {\n copilot_plan: \"antigravity\",\n quota_reset_date: earliestResetTime,\n quota_snapshots: {\n models: modelsQuota,\n },\n }\n}\n\n/**\n * Check if a model is a Claude model\n */\nexport function isClaudeModel(modelId: string): boolean {\n return modelId.startsWith(\"claude-\")\n}\n\n/**\n * Check if a model is a thinking/reasoning model\n */\nexport function isThinkingModel(modelId: string): boolean {\n return modelId.includes(\"thinking\")\n}\n\n/**\n * Check if a model is an image generation model\n */\nexport function isImageModel(modelId: string): boolean {\n return modelId.includes(\"image\")\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { state } from "./state-CcLGr8VN.js";
|
|
2
|
-
import { HTTPError } from "./error-
|
|
2
|
+
import { HTTPError } from "./error-SzJ4KHd8.js";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
|
|
5
5
|
//#region src/lib/api-config.ts
|
|
@@ -58,4 +58,4 @@ async function getGitHubUser() {
|
|
|
58
58
|
|
|
59
59
|
//#endregion
|
|
60
60
|
export { GITHUB_API_BASE_URL, GITHUB_APP_SCOPES, GITHUB_BASE_URL, GITHUB_CLIENT_ID, copilotBaseUrl, copilotHeaders, getGitHubUser, githubHeaders, standardHeaders };
|
|
61
|
-
//# sourceMappingURL=get-user-
|
|
61
|
+
//# sourceMappingURL=get-user-DEDD9jIs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-user-DEDD9jIs.js","names":["state","headers: Record<string, string>"],"sources":["../src/lib/api-config.ts","../src/services/github/get-user.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\"\n\nimport type { State } from \"./state\"\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nconst COPILOT_VERSION = \"0.26.7\"\nconst EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`\nconst USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`\n\n// Updated to match latest Zed implementation - 2025-05-01 returns Claude models\nconst API_VERSION = \"2025-05-01\"\n\n// Use the API endpoint from token response if available, otherwise fall back to default\nexport const copilotBaseUrl = (state: State) => {\n if (state.copilotApiEndpoint) {\n return state.copilotApiEndpoint\n }\n return state.accountType === \"individual\" ?\n \"https://api.githubcopilot.com\"\n : `https://api.${state.accountType}.githubcopilot.com`\n}\nexport const copilotHeaders = (state: State, vision: boolean = false) => {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${state.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": \"vscode-chat\",\n \"editor-version\": `vscode/${state.vsCodeVersion}`,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"conversation-panel\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": randomUUID(),\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 = (state: State) => ({\n ...standardHeaders(),\n authorization: `token ${state.githubToken}`,\n \"editor-version\": `vscode/${state.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 { GITHUB_API_BASE_URL, standardHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport async function getGitHubUser() {\n const response = await fetch(`${GITHUB_API_BASE_URL}/user`, {\n headers: {\n authorization: `token ${state.githubToken}`,\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\ninterface GithubUserResponse {\n login: string\n}\n"],"mappings":";;;;;AAIA,MAAa,yBAAyB;CACpC,gBAAgB;CAChB,QAAQ;CACT;AAED,MAAM,kBAAkB;AACxB,MAAM,wBAAwB,gBAAgB;AAC9C,MAAM,aAAa,qBAAqB;AAGxC,MAAM,cAAc;AAGpB,MAAa,kBAAkB,YAAiB;AAC9C,KAAIA,QAAM,mBACR,QAAOA,QAAM;AAEf,QAAOA,QAAM,gBAAgB,eACzB,kCACA,eAAeA,QAAM,YAAY;;AAEvC,MAAa,kBAAkB,SAAc,SAAkB,UAAU;CACvE,MAAMC,UAAkC;EACtC,eAAe,UAAUD,QAAM;EAC/B,gBAAgB,iBAAiB,CAAC;EAClC,0BAA0B;EAC1B,kBAAkB,UAAUA,QAAM;EAClC,yBAAyB;EACzB,cAAc;EACd,iBAAiB;EACjB,wBAAwB;EACxB,gBAAgB,YAAY;EAC5B,uCAAuC;EACxC;AAED,KAAI,OAAQ,SAAQ,4BAA4B;AAEhD,QAAO;;AAGT,MAAa,sBAAsB;AACnC,MAAa,iBAAiB,aAAkB;CAC9C,GAAG,iBAAiB;CACpB,eAAe,SAASA,QAAM;CAC9B,kBAAkB,UAAUA,QAAM;CAClC,yBAAyB;CACzB,cAAc;CACd,wBAAwB;CACxB,uCAAuC;CACxC;AAED,MAAa,kBAAkB;AAC/B,MAAa,mBAAmB;AAChC,MAAa,oBAAoB,CAAC,YAAY,CAAC,KAAK,IAAI;;;;ACrDxD,eAAsB,gBAAgB;CACpC,MAAM,WAAW,MAAM,MAAM,GAAG,oBAAoB,QAAQ,EAC1D,SAAS;EACP,eAAe,SAAS,MAAM;EAC9B,GAAG,iBAAiB;EACrB,EACF,CAAC;AAEF,KAAI,CAAC,SAAS,GAAI,OAAM,IAAI,UAAU,6BAA6B,SAAS;AAE5E,QAAQ,MAAM,SAAS,MAAM"}
|