@jeffreycao/copilot-api 1.3.5 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/{auth-PjO-EXxs.js → auth-DteTbqnM.js} +3 -3
- package/dist/{auth-PjO-EXxs.js.map → auth-DteTbqnM.js.map} +1 -1
- package/dist/{check-usage-C9abXGdq.js → check-usage-Z8fnzZQt.js} +4 -4
- package/dist/{check-usage-C9abXGdq.js.map → check-usage-Z8fnzZQt.js.map} +1 -1
- package/dist/{config-D3COstcJ.js → config-DYOE_-p1.js} +4 -7
- package/dist/config-DYOE_-p1.js.map +1 -0
- package/dist/{get-copilot-usage-xj7WA78o.js → get-copilot-usage-CuVET98U.js} +2 -2
- package/dist/{get-copilot-usage-xj7WA78o.js.map → get-copilot-usage-CuVET98U.js.map} +1 -1
- package/dist/main.js +3 -3
- package/dist/{server-DJvut6rC.js → server-BBSm2bHY.js} +100 -24
- package/dist/server-BBSm2bHY.js.map +1 -0
- package/dist/{start-CiUssY8j.js → start-BaeeWbdc.js} +5 -5
- package/dist/{start-CiUssY8j.js.map → start-BaeeWbdc.js.map} +1 -1
- package/dist/{token-G21yvpKv.js → token-8AyBHdsS.js} +2 -2
- package/dist/{token-G21yvpKv.js.map → token-8AyBHdsS.js.map} +1 -1
- package/dist/{utils-artyYmCm.js → utils-DKqD66k9.js} +5 -2
- package/dist/utils-DKqD66k9.js.map +1 -0
- package/package.json +1 -1
- package/dist/config-D3COstcJ.js.map +0 -1
- package/dist/server-DJvut6rC.js.map +0 -1
- package/dist/utils-artyYmCm.js.map +0 -1
package/README.md
CHANGED
|
@@ -254,6 +254,7 @@ The following command line options are available for the `start` command:
|
|
|
254
254
|
"enabled": true,
|
|
255
255
|
"baseUrl": "your-base-url",
|
|
256
256
|
"apiKey": "sk-your-provider-key",
|
|
257
|
+
"adjustInputTokens": false,
|
|
257
258
|
"models": {
|
|
258
259
|
"kimi-k2.5": {
|
|
259
260
|
"temperature": 1,
|
|
@@ -275,7 +276,6 @@ The following command line options are available for the `start` command:
|
|
|
275
276
|
"gpt-5.4": "xhigh"
|
|
276
277
|
},
|
|
277
278
|
"useFunctionApplyPatch": true,
|
|
278
|
-
"compactUseSmallModel": true,
|
|
279
279
|
"useMessagesApi": true
|
|
280
280
|
}
|
|
281
281
|
```
|
|
@@ -285,6 +285,7 @@ The following command line options are available for the `start` command:
|
|
|
285
285
|
- `enabled` defaults to `true` if omitted.
|
|
286
286
|
- `baseUrl` should be provider API base URL without trailing `/v1/messages`.
|
|
287
287
|
- `apiKey` is used as upstream `x-api-key`.
|
|
288
|
+
- `adjustInputTokens` (optional): When `true`, the proxy will adjust the `input_tokens` in the usage response by subtracting `cache_read_input_tokens` and `cache_creation_input_tokens`.
|
|
288
289
|
- `models` (optional): Per-model configuration map. Each key is a model ID (matching the model name in requests), and the value is:
|
|
289
290
|
- `temperature` (optional): Default temperature value used when the request does not specify one.
|
|
290
291
|
- `topP` (optional): Default top_p value used when the request does not specify one.
|
|
@@ -293,7 +294,6 @@ The following command line options are available for the `start` command:
|
|
|
293
294
|
- **responsesApiContextManagementModels:** List of model IDs that should receive Responses API `context_management` compaction instructions. Use this when a model supports server-side context management and you want the proxy to keep only the latest compaction carrier on follow-up turns.
|
|
294
295
|
- **modelReasoningEfforts:** Per-model `reasoning.effort` sent to the Copilot Responses API. Allowed values are `none`, `minimal`, `low`, `medium`, `high`, and `xhigh`. If a model isn’t listed, `high` is used by default.
|
|
295
296
|
- **useFunctionApplyPatch:** When `true`, the server will convert any custom tool named `apply_patch` in Responses payloads into an OpenAI-style function tool (`type: "function"`) with a parameter schema so assistants can call it using function-calling semantics to edit files. Set to `false` to leave tools unchanged. Defaults to `true`.
|
|
296
|
-
- **compactUseSmallModel:** When `true`, detected "compact" requests (e.g., from Claude Code or Opencode compact mode) will automatically use the configured `smallModel` to avoid consuming premium model usage for short/background tasks. Defaults to `true`.
|
|
297
297
|
- **useMessagesApi:** When `true`, Claude-family models that support Copilot's native `/v1/messages` endpoint will use the Messages API; otherwise they fall back to `/chat/completions`. Set to `false` to disable Messages API routing and always use `/chat/completions`. Defaults to `true`.
|
|
298
298
|
|
|
299
299
|
Edit this file to customize prompts or swap in your own fast model. Restart the server (or rerun the command) after changes so the cached config is refreshed.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PATHS, ensurePaths } from "./paths-Cla6y5eD.js";
|
|
2
|
-
import { state } from "./utils-
|
|
3
|
-
import { setupGitHubToken } from "./token-
|
|
2
|
+
import { state } from "./utils-DKqD66k9.js";
|
|
3
|
+
import { setupGitHubToken } from "./token-8AyBHdsS.js";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
import consola from "consola";
|
|
6
6
|
|
|
@@ -43,4 +43,4 @@ const auth = defineCommand({
|
|
|
43
43
|
|
|
44
44
|
//#endregion
|
|
45
45
|
export { auth };
|
|
46
|
-
//# sourceMappingURL=auth-
|
|
46
|
+
//# sourceMappingURL=auth-DteTbqnM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-
|
|
1
|
+
{"version":3,"file":"auth-DteTbqnM.js","names":[],"sources":["../src/auth.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { PATHS, ensurePaths } from \"./lib/paths\"\nimport { state } from \"./lib/state\"\nimport { setupGitHubToken } from \"./lib/token\"\n\ninterface RunAuthOptions {\n verbose: boolean\n showToken: boolean\n}\n\nexport async function runAuth(options: RunAuthOptions): Promise<void> {\n if (options.verbose) {\n consola.level = 5\n consola.info(\"Verbose logging enabled\")\n }\n\n state.showToken = options.showToken\n\n await ensurePaths()\n await setupGitHubToken({ force: true })\n consola.success(\"GitHub token written to\", PATHS.GITHUB_TOKEN_PATH)\n}\n\nexport const auth = defineCommand({\n meta: {\n name: \"auth\",\n description: \"Run GitHub auth flow without running the server\",\n },\n args: {\n verbose: {\n alias: \"v\",\n type: \"boolean\",\n default: false,\n description: \"Enable verbose logging\",\n },\n \"show-token\": {\n type: \"boolean\",\n default: false,\n description: \"Show GitHub token on auth\",\n },\n },\n run({ args }) {\n return runAuth({\n verbose: args.verbose,\n showToken: args[\"show-token\"],\n })\n },\n})\n"],"mappings":";;;;;;;AAcA,eAAsB,QAAQ,SAAwC;AACpE,KAAI,QAAQ,SAAS;AACnB,UAAQ,QAAQ;AAChB,UAAQ,KAAK,0BAA0B;;AAGzC,OAAM,YAAY,QAAQ;AAE1B,OAAM,aAAa;AACnB,OAAM,iBAAiB,EAAE,OAAO,MAAM,CAAC;AACvC,SAAQ,QAAQ,2BAA2B,MAAM,kBAAkB;;AAGrE,MAAa,OAAO,cAAc;CAChC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,SAAS;GACP,OAAO;GACP,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACD,cAAc;GACZ,MAAM;GACN,SAAS;GACT,aAAa;GACd;EACF;CACD,IAAI,EAAE,QAAQ;AACZ,SAAO,QAAQ;GACb,SAAS,KAAK;GACd,WAAW,KAAK;GACjB,CAAC;;CAEL,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ensurePaths } from "./paths-Cla6y5eD.js";
|
|
2
|
-
import "./utils-
|
|
3
|
-
import { setupGitHubToken } from "./token-
|
|
4
|
-
import { getCopilotUsage } from "./get-copilot-usage-
|
|
2
|
+
import "./utils-DKqD66k9.js";
|
|
3
|
+
import { setupGitHubToken } from "./token-8AyBHdsS.js";
|
|
4
|
+
import { getCopilotUsage } from "./get-copilot-usage-CuVET98U.js";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
6
|
import consola from "consola";
|
|
7
7
|
|
|
@@ -42,4 +42,4 @@ const checkUsage = defineCommand({
|
|
|
42
42
|
|
|
43
43
|
//#endregion
|
|
44
44
|
export { checkUsage };
|
|
45
|
-
//# sourceMappingURL=check-usage-
|
|
45
|
+
//# sourceMappingURL=check-usage-Z8fnzZQt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-usage-
|
|
1
|
+
{"version":3,"file":"check-usage-Z8fnzZQt.js","names":[],"sources":["../src/check-usage.ts"],"sourcesContent":["import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupGitHubToken } from \"./lib/token\"\nimport {\n getCopilotUsage,\n type QuotaDetail,\n} from \"./services/github/get-copilot-usage\"\n\nexport const checkUsage = defineCommand({\n meta: {\n name: \"check-usage\",\n description: \"Show current GitHub Copilot usage/quota information\",\n },\n async run() {\n await ensurePaths()\n await setupGitHubToken()\n try {\n const usage = await getCopilotUsage()\n const premium = usage.quota_snapshots.premium_interactions\n const premiumTotal = premium.entitlement\n const premiumUsed = premiumTotal - premium.remaining\n const premiumPercentUsed =\n premiumTotal > 0 ? (premiumUsed / premiumTotal) * 100 : 0\n const premiumPercentRemaining = premium.percent_remaining\n\n // Helper to summarize a quota snapshot\n function summarizeQuota(name: string, snap: QuotaDetail | undefined) {\n if (!snap) return `${name}: N/A`\n const total = snap.entitlement\n const used = total - snap.remaining\n const percentUsed = total > 0 ? (used / total) * 100 : 0\n const percentRemaining = snap.percent_remaining\n return `${name}: ${used}/${total} used (${percentUsed.toFixed(1)}% used, ${percentRemaining.toFixed(1)}% remaining)`\n }\n\n const premiumLine = `Premium: ${premiumUsed}/${premiumTotal} used (${premiumPercentUsed.toFixed(1)}% used, ${premiumPercentRemaining.toFixed(1)}% remaining)`\n const chatLine = summarizeQuota(\"Chat\", usage.quota_snapshots.chat)\n const completionsLine = summarizeQuota(\n \"Completions\",\n usage.quota_snapshots.completions,\n )\n\n consola.box(\n `Copilot Usage (plan: ${usage.copilot_plan})\\n`\n + `Quota resets: ${usage.quota_reset_date}\\n`\n + `\\nQuotas:\\n`\n + ` ${premiumLine}\\n`\n + ` ${chatLine}\\n`\n + ` ${completionsLine}`,\n )\n } catch (err) {\n consola.error(\"Failed to fetch Copilot usage:\", err)\n process.exit(1)\n }\n },\n})\n"],"mappings":";;;;;;;;AAUA,MAAa,aAAa,cAAc;CACtC,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM,MAAM;AACV,QAAM,aAAa;AACnB,QAAM,kBAAkB;AACxB,MAAI;GACF,MAAM,QAAQ,MAAM,iBAAiB;GACrC,MAAM,UAAU,MAAM,gBAAgB;GACtC,MAAM,eAAe,QAAQ;GAC7B,MAAM,cAAc,eAAe,QAAQ;GAC3C,MAAM,qBACJ,eAAe,IAAK,cAAc,eAAgB,MAAM;GAC1D,MAAM,0BAA0B,QAAQ;GAGxC,SAAS,eAAe,MAAc,MAA+B;AACnE,QAAI,CAAC,KAAM,QAAO,GAAG,KAAK;IAC1B,MAAM,QAAQ,KAAK;IACnB,MAAM,OAAO,QAAQ,KAAK;IAC1B,MAAM,cAAc,QAAQ,IAAK,OAAO,QAAS,MAAM;IACvD,MAAM,mBAAmB,KAAK;AAC9B,WAAO,GAAG,KAAK,IAAI,KAAK,GAAG,MAAM,SAAS,YAAY,QAAQ,EAAE,CAAC,UAAU,iBAAiB,QAAQ,EAAE,CAAC;;GAGzG,MAAM,cAAc,YAAY,YAAY,GAAG,aAAa,SAAS,mBAAmB,QAAQ,EAAE,CAAC,UAAU,wBAAwB,QAAQ,EAAE,CAAC;GAChJ,MAAM,WAAW,eAAe,QAAQ,MAAM,gBAAgB,KAAK;GACnE,MAAM,kBAAkB,eACtB,eACA,MAAM,gBAAgB,YACvB;AAED,WAAQ,IACN,wBAAwB,MAAM,aAAa,mBACtB,MAAM,iBAAiB,iBAEnC,YAAY,MACZ,SAAS,MACT,kBACV;WACM,KAAK;AACZ,WAAQ,MAAM,kCAAkC,IAAI;AACpD,WAAQ,KAAK,EAAE;;;CAGpB,CAAC"}
|
|
@@ -44,7 +44,6 @@ const defaultConfig = {
|
|
|
44
44
|
"gpt-5.4": "xhigh"
|
|
45
45
|
},
|
|
46
46
|
useFunctionApplyPatch: true,
|
|
47
|
-
compactUseSmallModel: true,
|
|
48
47
|
useMessagesApi: true
|
|
49
48
|
};
|
|
50
49
|
let cachedConfig = null;
|
|
@@ -133,9 +132,6 @@ function isResponsesApiContextManagementModel(model) {
|
|
|
133
132
|
function getReasoningEffortForModel(model) {
|
|
134
133
|
return getConfig().modelReasoningEfforts?.[model] ?? "high";
|
|
135
134
|
}
|
|
136
|
-
function shouldCompactUseSmallModel() {
|
|
137
|
-
return getConfig().compactUseSmallModel ?? true;
|
|
138
|
-
}
|
|
139
135
|
function normalizeProviderBaseUrl(url) {
|
|
140
136
|
return url.trim().replace(/\/+$/u, "");
|
|
141
137
|
}
|
|
@@ -161,7 +157,8 @@ function getProviderConfig(name) {
|
|
|
161
157
|
type,
|
|
162
158
|
baseUrl,
|
|
163
159
|
apiKey,
|
|
164
|
-
models: provider.models
|
|
160
|
+
models: provider.models,
|
|
161
|
+
adjustInputTokens: provider.adjustInputTokens
|
|
165
162
|
};
|
|
166
163
|
}
|
|
167
164
|
function isMessagesApiEnabled() {
|
|
@@ -169,5 +166,5 @@ function isMessagesApiEnabled() {
|
|
|
169
166
|
}
|
|
170
167
|
|
|
171
168
|
//#endregion
|
|
172
|
-
export { getConfig, getExtraPromptForModel, getProviderConfig, getReasoningEffortForModel, getSmallModel, isMessagesApiEnabled, isResponsesApiContextManagementModel, mergeConfigWithDefaults
|
|
173
|
-
//# sourceMappingURL=config-
|
|
169
|
+
export { getConfig, getExtraPromptForModel, getProviderConfig, getReasoningEffortForModel, getSmallModel, isMessagesApiEnabled, isResponsesApiContextManagementModel, mergeConfigWithDefaults };
|
|
170
|
+
//# sourceMappingURL=config-DYOE_-p1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-DYOE_-p1.js","names":["defaultConfig: AppConfig","cachedConfig: AppConfig | null"],"sources":["../src/lib/config.ts"],"sourcesContent":["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 providers?: Record<string, ProviderConfig>\n extraPrompts?: Record<string, string>\n smallModel?: string\n responsesApiContextManagementModels?: Array<string>\n modelReasoningEfforts?: Record<\n string,\n \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"\n >\n useFunctionApplyPatch?: boolean\n useMessagesApi?: boolean\n}\n\nexport interface ModelConfig {\n temperature?: number\n topP?: number\n topK?: number\n}\n\nexport interface ProviderConfig {\n type?: string\n enabled?: boolean\n baseUrl?: string\n apiKey?: string\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\n}\n\nexport interface ResolvedProviderConfig {\n name: string\n type: \"anthropic\"\n baseUrl: string\n apiKey: string\n models?: Record<string, ModelConfig>\n adjustInputTokens?: boolean\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 providers: {},\n extraPrompts: {\n \"gpt-5-mini\": gpt5ExplorationPrompt,\n \"gpt-5.3-codex\": gpt5CommentaryPrompt,\n \"gpt-5.4\": gpt5CommentaryPrompt,\n },\n smallModel: \"gpt-5-mini\",\n responsesApiContextManagementModels: [],\n modelReasoningEfforts: {\n \"gpt-5-mini\": \"low\",\n \"gpt-5.3-codex\": \"xhigh\",\n \"gpt-5.4\": \"xhigh\",\n },\n useFunctionApplyPatch: true,\n useMessagesApi: true,\n}\n\nlet cachedConfig: AppConfig | null = null\n\nfunction ensureConfigFile(): void {\n try {\n fs.accessSync(PATHS.CONFIG_PATH, fs.constants.R_OK | fs.constants.W_OK)\n } catch {\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 return\n }\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 mergeDefaultConfig(config: AppConfig): {\n mergedConfig: AppConfig\n changed: boolean\n} {\n const extraPrompts = config.extraPrompts ?? {}\n const defaultExtraPrompts = defaultConfig.extraPrompts ?? {}\n const modelReasoningEfforts = config.modelReasoningEfforts ?? {}\n const defaultModelReasoningEfforts = defaultConfig.modelReasoningEfforts ?? {}\n\n const missingExtraPromptModels = Object.keys(defaultExtraPrompts).filter(\n (model) => !Object.hasOwn(extraPrompts, model),\n )\n\n const missingReasoningEffortModels = Object.keys(\n defaultModelReasoningEfforts,\n ).filter((model) => !Object.hasOwn(modelReasoningEfforts, model))\n\n const hasExtraPromptChanges = missingExtraPromptModels.length > 0\n const hasReasoningEffortChanges = missingReasoningEffortModels.length > 0\n\n if (!hasExtraPromptChanges && !hasReasoningEffortChanges) {\n return { mergedConfig: config, changed: false }\n }\n\n return {\n mergedConfig: {\n ...config,\n extraPrompts: {\n ...defaultExtraPrompts,\n ...extraPrompts,\n },\n modelReasoningEfforts: {\n ...defaultModelReasoningEfforts,\n ...modelReasoningEfforts,\n },\n },\n changed: true,\n }\n}\n\nexport function mergeConfigWithDefaults(): AppConfig {\n const config = readConfigFromDisk()\n const { mergedConfig, changed } = mergeDefaultConfig(config)\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(\n \"Failed to write merged extraPrompts to config file\",\n writeError,\n )\n }\n }\n\n cachedConfig = mergedConfig\n return mergedConfig\n}\n\nexport function getConfig(): AppConfig {\n cachedConfig ??= readConfigFromDisk()\n return cachedConfig\n}\n\nexport function getExtraPromptForModel(model: string): string {\n const config = getConfig()\n return config.extraPrompts?.[model] ?? \"\"\n}\n\nexport function getSmallModel(): string {\n const config = getConfig()\n return config.smallModel ?? \"gpt-5-mini\"\n}\n\nexport function getResponsesApiContextManagementModels(): Array<string> {\n const config = getConfig()\n return (\n config.responsesApiContextManagementModels\n ?? defaultConfig.responsesApiContextManagementModels\n ?? []\n )\n}\n\nexport function isResponsesApiContextManagementModel(model: string): boolean {\n return getResponsesApiContextManagementModels().includes(model)\n}\n\nexport function getReasoningEffortForModel(\n model: string,\n): \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" {\n const config = getConfig()\n return config.modelReasoningEfforts?.[model] ?? \"high\"\n}\n\nexport function normalizeProviderBaseUrl(url: string): string {\n return url.trim().replace(/\\/+$/u, \"\")\n}\n\nexport function getProviderConfig(name: string): ResolvedProviderConfig | null {\n const providerName = name.trim()\n if (!providerName) {\n return null\n }\n\n const config = getConfig()\n const provider = config.providers?.[providerName]\n if (!provider) {\n return null\n }\n\n if (provider.enabled === false) {\n return null\n }\n\n const type = provider.type ?? \"anthropic\"\n if (type !== \"anthropic\") {\n consola.warn(\n `Provider ${providerName} is ignored because only anthropic type is supported`,\n )\n return null\n }\n\n const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? \"\")\n const apiKey = (provider.apiKey ?? \"\").trim()\n if (!baseUrl || !apiKey) {\n consola.warn(\n `Provider ${providerName} is enabled but missing baseUrl or apiKey`,\n )\n return null\n }\n\n return {\n name: providerName,\n type,\n baseUrl,\n apiKey,\n models: provider.models,\n adjustInputTokens: provider.adjustInputTokens,\n }\n}\n\nexport function listEnabledProviders(): Array<string> {\n const config = getConfig()\n const providerNames = Object.keys(config.providers ?? {})\n return providerNames.filter((name) => getProviderConfig(name) !== null)\n}\n\nexport function isMessagesApiEnabled(): boolean {\n const config = getConfig()\n return config.useMessagesApi ?? true\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HTTPError, getGitHubApiBaseUrl, githubHeaders, state } from "./utils-
|
|
1
|
+
import { HTTPError, getGitHubApiBaseUrl, githubHeaders, state } from "./utils-DKqD66k9.js";
|
|
2
2
|
|
|
3
3
|
//#region src/services/github/get-copilot-usage.ts
|
|
4
4
|
const getCopilotUsage = async () => {
|
|
@@ -9,4 +9,4 @@ const getCopilotUsage = async () => {
|
|
|
9
9
|
|
|
10
10
|
//#endregion
|
|
11
11
|
export { getCopilotUsage };
|
|
12
|
-
//# sourceMappingURL=get-copilot-usage-
|
|
12
|
+
//# sourceMappingURL=get-copilot-usage-CuVET98U.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-copilot-usage-
|
|
1
|
+
{"version":3,"file":"get-copilot-usage-CuVET98U.js","names":[],"sources":["../src/services/github/get-copilot-usage.ts"],"sourcesContent":["import { getGitHubApiBaseUrl, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { state } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (): Promise<CopilotUsageResponse> => {\n const response = await fetch(\n `${getGitHubApiBaseUrl()}/copilot_internal/user`,\n {\n headers: githubHeaders(state),\n },\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"],"mappings":";;;AAIA,MAAa,kBAAkB,YAA2C;CACxE,MAAM,WAAW,MAAM,MACrB,GAAG,qBAAqB,CAAC,yBACzB,EACE,SAAS,cAAc,MAAM,EAC9B,CACF;AAED,KAAI,CAAC,SAAS,GACZ,OAAM,IAAI,UAAU,+BAA+B,SAAS;AAG9D,QAAQ,MAAM,SAAS,MAAM"}
|
package/dist/main.js
CHANGED
|
@@ -20,10 +20,10 @@ const args = parseArgs(process.argv, cliArgs);
|
|
|
20
20
|
if (typeof args["api-home"] === "string") process.env.COPILOT_API_HOME = args["api-home"];
|
|
21
21
|
if (typeof args["oauth-app"] === "string") process.env.COPILOT_API_OAUTH_APP = args["oauth-app"];
|
|
22
22
|
if (typeof args["enterprise-url"] === "string") process.env.COPILOT_API_ENTERPRISE_URL = args["enterprise-url"];
|
|
23
|
-
const { auth } = await import("./auth-
|
|
24
|
-
const { checkUsage } = await import("./check-usage-
|
|
23
|
+
const { auth } = await import("./auth-DteTbqnM.js");
|
|
24
|
+
const { checkUsage } = await import("./check-usage-Z8fnzZQt.js");
|
|
25
25
|
const { debug } = await import("./debug-Dx1S6uWG.js");
|
|
26
|
-
const { start } = await import("./start-
|
|
26
|
+
const { start } = await import("./start-BaeeWbdc.js");
|
|
27
27
|
const main = defineCommand({
|
|
28
28
|
meta: {
|
|
29
29
|
name: "copilot-api",
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { PATHS } from "./paths-Cla6y5eD.js";
|
|
2
|
-
import { HTTPError, cacheModels, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getRootSessionId, getUUID, isNullish, prepareInteractionHeaders, sleep, state } from "./utils-
|
|
3
|
-
import { getCopilotUsage } from "./get-copilot-usage-
|
|
4
|
-
import { getConfig, getExtraPromptForModel, getProviderConfig, getReasoningEffortForModel, getSmallModel, isMessagesApiEnabled, isResponsesApiContextManagementModel
|
|
2
|
+
import { HTTPError, cacheModels, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getRootSessionId, getUUID, isNullish, prepareForCompact, prepareInteractionHeaders, sleep, state } from "./utils-DKqD66k9.js";
|
|
3
|
+
import { getCopilotUsage } from "./get-copilot-usage-CuVET98U.js";
|
|
4
|
+
import { getConfig, getExtraPromptForModel, getProviderConfig, getReasoningEffortForModel, getSmallModel, isMessagesApiEnabled, isResponsesApiContextManagementModel } from "./config-DYOE_-p1.js";
|
|
5
5
|
import consola from "consola";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { Hono } from "hono";
|
|
8
8
|
import { cors } from "hono/cors";
|
|
9
9
|
import { logger } from "hono/logger";
|
|
10
10
|
import fs, { readFileSync } from "node:fs";
|
|
11
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
11
12
|
import { streamSSE } from "hono/streaming";
|
|
12
13
|
import util from "node:util";
|
|
13
14
|
import { events } from "fetch-event-stream";
|
|
@@ -57,6 +58,40 @@ function createAuthMiddleware(options = {}) {
|
|
|
57
58
|
};
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/lib/request-context.ts
|
|
63
|
+
const TRACE_ID_MAX_LENGTH = 64;
|
|
64
|
+
const TRACE_ID_PATTERN = /^\w[\w.-]*$/;
|
|
65
|
+
const asyncLocalStorage = new AsyncLocalStorage();
|
|
66
|
+
const requestContext = {
|
|
67
|
+
getStore: () => asyncLocalStorage.getStore(),
|
|
68
|
+
run: (context, callback) => asyncLocalStorage.run(context, callback)
|
|
69
|
+
};
|
|
70
|
+
function generateTraceId() {
|
|
71
|
+
const timestamp = Date.now().toString(36);
|
|
72
|
+
const random = Math.random().toString(36).slice(2, 8);
|
|
73
|
+
return `${timestamp}-${random}`;
|
|
74
|
+
}
|
|
75
|
+
function resolveTraceId(traceId) {
|
|
76
|
+
const candidate = traceId?.trim();
|
|
77
|
+
if (!candidate || candidate.length > TRACE_ID_MAX_LENGTH || !TRACE_ID_PATTERN.test(candidate)) return generateTraceId();
|
|
78
|
+
return candidate;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/lib/trace.ts
|
|
83
|
+
const traceIdMiddleware = async (c, next) => {
|
|
84
|
+
const traceId = resolveTraceId(c.req.header("x-trace-id"));
|
|
85
|
+
c.header("x-trace-id", traceId);
|
|
86
|
+
const context = {
|
|
87
|
+
traceId,
|
|
88
|
+
startTime: Date.now()
|
|
89
|
+
};
|
|
90
|
+
await requestContext.run(context, async () => {
|
|
91
|
+
await next();
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
60
95
|
//#endregion
|
|
61
96
|
//#region src/lib/approval.ts
|
|
62
97
|
const awaitApproval = async () => {
|
|
@@ -165,12 +200,14 @@ const createHandlerLogger = (name) => {
|
|
|
165
200
|
cleanupOldLogs();
|
|
166
201
|
lastCleanup = Date.now();
|
|
167
202
|
}
|
|
203
|
+
const traceId = requestContext.getStore()?.traceId;
|
|
168
204
|
const date = logObj.date;
|
|
169
205
|
const dateKey = date.toLocaleDateString("sv-SE");
|
|
170
206
|
const timestamp = date.toLocaleString("sv-SE", { hour12: false });
|
|
171
207
|
const filePath = path.join(LOG_DIR, `${sanitizedName}-${dateKey}.log`);
|
|
172
208
|
const message = formatArgs(logObj.args);
|
|
173
|
-
const
|
|
209
|
+
const traceIdStr = traceId ? ` [${traceId}]` : "";
|
|
210
|
+
const line = `[${timestamp}] [${logObj.type}] [${logObj.tag || name}]${traceIdStr}${message ? ` ${message}` : ""}`;
|
|
174
211
|
appendLine(filePath, line);
|
|
175
212
|
} });
|
|
176
213
|
return instance;
|
|
@@ -433,6 +470,7 @@ const createChatCompletions = async (payload, options) => {
|
|
|
433
470
|
"x-initiator": isAgentCall ? "agent" : "user"
|
|
434
471
|
};
|
|
435
472
|
prepareInteractionHeaders(options.sessionId, Boolean(options.subagentMarker), headers);
|
|
473
|
+
prepareForCompact(headers, options.isCompact);
|
|
436
474
|
const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {
|
|
437
475
|
method: "POST",
|
|
438
476
|
headers,
|
|
@@ -839,13 +877,14 @@ async function handleCountTokens(c) {
|
|
|
839
877
|
|
|
840
878
|
//#endregion
|
|
841
879
|
//#region src/services/copilot/create-responses.ts
|
|
842
|
-
const createResponses = async (payload, { vision, initiator, subagentMarker, requestId, sessionId }) => {
|
|
880
|
+
const createResponses = async (payload, { vision, initiator, subagentMarker, requestId, sessionId, isCompact }) => {
|
|
843
881
|
if (!state.copilotToken) throw new Error("Copilot token not found");
|
|
844
882
|
const headers = {
|
|
845
883
|
...copilotHeaders(state, requestId, vision),
|
|
846
884
|
"x-initiator": initiator
|
|
847
885
|
};
|
|
848
886
|
prepareInteractionHeaders(sessionId, Boolean(subagentMarker), headers);
|
|
887
|
+
prepareForCompact(headers, isCompact);
|
|
849
888
|
payload.service_tier = null;
|
|
850
889
|
const response = await fetch(`${copilotBaseUrl(state)}/responses`, {
|
|
851
890
|
method: "POST",
|
|
@@ -1816,6 +1855,7 @@ const createMessages = async (payload, anthropicBetaHeader, options) => {
|
|
|
1816
1855
|
"x-initiator": isInitiateRequest ? "user" : "agent"
|
|
1817
1856
|
};
|
|
1818
1857
|
prepareInteractionHeaders(options.sessionId, Boolean(options.subagentMarker), headers);
|
|
1858
|
+
prepareForCompact(headers, options.isCompact);
|
|
1819
1859
|
const anthropicBeta = buildAnthropicBetaHeader(anthropicBetaHeader, payload.thinking);
|
|
1820
1860
|
if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
|
|
1821
1861
|
const response = await fetch(`${copilotBaseUrl(state)}/v1/messages`, {
|
|
@@ -2143,10 +2183,8 @@ async function handleCompletion(c) {
|
|
|
2143
2183
|
logger$5.debug("Anthropic Beta header:", anthropicBeta);
|
|
2144
2184
|
const noTools = !anthropicPayload.tools || anthropicPayload.tools.length === 0;
|
|
2145
2185
|
if (anthropicBeta && noTools && !isCompact) anthropicPayload.model = getSmallModel();
|
|
2146
|
-
if (isCompact)
|
|
2147
|
-
|
|
2148
|
-
if (shouldCompactUseSmallModel()) anthropicPayload.model = getSmallModel();
|
|
2149
|
-
} else mergeToolResultForClaude(anthropicPayload);
|
|
2186
|
+
if (isCompact) logger$5.debug("Is compact request:", isCompact);
|
|
2187
|
+
else mergeToolResultForClaude(anthropicPayload);
|
|
2150
2188
|
const requestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
|
|
2151
2189
|
logger$5.debug("Generated request ID:", requestId);
|
|
2152
2190
|
if (state.manualApprove) await awaitApproval();
|
|
@@ -2157,30 +2195,34 @@ async function handleCompletion(c) {
|
|
|
2157
2195
|
subagentMarker,
|
|
2158
2196
|
selectedModel,
|
|
2159
2197
|
requestId,
|
|
2160
|
-
sessionId
|
|
2198
|
+
sessionId,
|
|
2199
|
+
isCompact
|
|
2161
2200
|
});
|
|
2162
2201
|
if (shouldUseResponsesApi(selectedModel)) return await handleWithResponsesApi(c, anthropicPayload, {
|
|
2163
2202
|
subagentMarker,
|
|
2164
2203
|
selectedModel,
|
|
2165
2204
|
requestId,
|
|
2166
|
-
sessionId
|
|
2205
|
+
sessionId,
|
|
2206
|
+
isCompact
|
|
2167
2207
|
});
|
|
2168
2208
|
return await handleWithChatCompletions(c, anthropicPayload, {
|
|
2169
2209
|
subagentMarker,
|
|
2170
2210
|
requestId,
|
|
2171
|
-
sessionId
|
|
2211
|
+
sessionId,
|
|
2212
|
+
isCompact
|
|
2172
2213
|
});
|
|
2173
2214
|
}
|
|
2174
2215
|
const RESPONSES_ENDPOINT$1 = "/responses";
|
|
2175
2216
|
const MESSAGES_ENDPOINT = "/v1/messages";
|
|
2176
2217
|
const handleWithChatCompletions = async (c, anthropicPayload, options) => {
|
|
2177
|
-
const { subagentMarker, requestId, sessionId } = options;
|
|
2218
|
+
const { subagentMarker, requestId, sessionId, isCompact } = options;
|
|
2178
2219
|
const openAIPayload = translateToOpenAI(anthropicPayload);
|
|
2179
2220
|
logger$5.debug("Translated OpenAI request payload:", JSON.stringify(openAIPayload));
|
|
2180
2221
|
const response = await createChatCompletions(openAIPayload, {
|
|
2181
2222
|
subagentMarker,
|
|
2182
2223
|
requestId,
|
|
2183
|
-
sessionId
|
|
2224
|
+
sessionId,
|
|
2225
|
+
isCompact
|
|
2184
2226
|
});
|
|
2185
2227
|
if (isNonStreaming(response)) {
|
|
2186
2228
|
logger$5.debug("Non-streaming response from Copilot:", JSON.stringify(response));
|
|
@@ -2214,7 +2256,7 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
|
|
|
2214
2256
|
});
|
|
2215
2257
|
};
|
|
2216
2258
|
const handleWithResponsesApi = async (c, anthropicPayload, options) => {
|
|
2217
|
-
const { subagentMarker, selectedModel, requestId, sessionId } = options;
|
|
2259
|
+
const { subagentMarker, selectedModel, requestId, sessionId, isCompact } = options;
|
|
2218
2260
|
const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload);
|
|
2219
2261
|
applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
|
|
2220
2262
|
compactInputByLatestCompaction(responsesPayload);
|
|
@@ -2225,7 +2267,8 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
|
|
|
2225
2267
|
initiator,
|
|
2226
2268
|
subagentMarker,
|
|
2227
2269
|
requestId,
|
|
2228
|
-
sessionId
|
|
2270
|
+
sessionId,
|
|
2271
|
+
isCompact
|
|
2229
2272
|
});
|
|
2230
2273
|
if (responsesPayload.stream && isAsyncIterable$1(response)) {
|
|
2231
2274
|
logger$5.debug("Streaming response from Copilot (Responses API)");
|
|
@@ -2272,7 +2315,7 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
|
|
|
2272
2315
|
return c.json(anthropicResponse);
|
|
2273
2316
|
};
|
|
2274
2317
|
const handleWithMessagesApi = async (c, anthropicPayload, options) => {
|
|
2275
|
-
const { anthropicBetaHeader, subagentMarker, selectedModel, requestId, sessionId } = options;
|
|
2318
|
+
const { anthropicBetaHeader, subagentMarker, selectedModel, requestId, sessionId, isCompact } = options;
|
|
2276
2319
|
for (const msg of anthropicPayload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
|
|
2277
2320
|
if (block.type !== "thinking") return true;
|
|
2278
2321
|
return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
|
|
@@ -2287,7 +2330,8 @@ const handleWithMessagesApi = async (c, anthropicPayload, options) => {
|
|
|
2287
2330
|
const response = await createMessages(anthropicPayload, anthropicBetaHeader, {
|
|
2288
2331
|
subagentMarker,
|
|
2289
2332
|
requestId,
|
|
2290
|
-
sessionId
|
|
2333
|
+
sessionId,
|
|
2334
|
+
isCompact
|
|
2291
2335
|
});
|
|
2292
2336
|
if (isAsyncIterable$1(response)) {
|
|
2293
2337
|
logger$5.debug("Streaming response from Copilot (Messages API)");
|
|
@@ -2544,14 +2588,37 @@ async function handleProviderMessages(c) {
|
|
|
2544
2588
|
provider
|
|
2545
2589
|
}));
|
|
2546
2590
|
const upstreamResponse = await forwardProviderMessages(providerConfig, payload, c.req.raw.headers);
|
|
2591
|
+
if (!upstreamResponse.ok) {
|
|
2592
|
+
logger$3.error("Failed to create responses", upstreamResponse);
|
|
2593
|
+
throw new HTTPError("Failed to create responses", upstreamResponse);
|
|
2594
|
+
}
|
|
2547
2595
|
const contentType = upstreamResponse.headers.get("content-type") ?? "";
|
|
2548
2596
|
if (Boolean(payload.stream) && contentType.includes("text/event-stream")) {
|
|
2549
2597
|
logger$3.debug("provider.messages.streaming");
|
|
2550
2598
|
return streamSSE(c, async (stream) => {
|
|
2551
|
-
for await (const
|
|
2552
|
-
|
|
2553
|
-
const
|
|
2554
|
-
|
|
2599
|
+
for await (const chunk of events(upstreamResponse)) {
|
|
2600
|
+
logger$3.debug("provider.messages.raw_stream_event:", chunk.data);
|
|
2601
|
+
const eventName = chunk.event;
|
|
2602
|
+
if (eventName === "ping") {
|
|
2603
|
+
await stream.writeSSE({
|
|
2604
|
+
event: "ping",
|
|
2605
|
+
data: "{\"type\":\"ping\"}"
|
|
2606
|
+
});
|
|
2607
|
+
continue;
|
|
2608
|
+
}
|
|
2609
|
+
let data = chunk.data;
|
|
2610
|
+
if (!data) continue;
|
|
2611
|
+
try {
|
|
2612
|
+
const parsed = JSON.parse(data);
|
|
2613
|
+
if (parsed.type === "message_start") adjustInputTokens(providerConfig, parsed.message.usage);
|
|
2614
|
+
else if (parsed.type === "message_delta") adjustInputTokens(providerConfig, parsed.usage);
|
|
2615
|
+
data = JSON.stringify(parsed);
|
|
2616
|
+
} catch (error) {
|
|
2617
|
+
logger$3.error("provider.messages.streaming.adjust_tokens_error", {
|
|
2618
|
+
error,
|
|
2619
|
+
originalData: data
|
|
2620
|
+
});
|
|
2621
|
+
}
|
|
2555
2622
|
await stream.writeSSE({
|
|
2556
2623
|
event: eventName,
|
|
2557
2624
|
data
|
|
@@ -2559,7 +2626,10 @@ async function handleProviderMessages(c) {
|
|
|
2559
2626
|
}
|
|
2560
2627
|
});
|
|
2561
2628
|
}
|
|
2562
|
-
|
|
2629
|
+
const jsonBody = await upstreamResponse.json();
|
|
2630
|
+
adjustInputTokens(providerConfig, jsonBody.usage);
|
|
2631
|
+
logger$3.debug("provider.messages.no_stream result:", JSON.stringify(jsonBody));
|
|
2632
|
+
return c.json(jsonBody);
|
|
2563
2633
|
} catch (error) {
|
|
2564
2634
|
logger$3.error("provider.messages.error", {
|
|
2565
2635
|
provider,
|
|
@@ -2568,6 +2638,11 @@ async function handleProviderMessages(c) {
|
|
|
2568
2638
|
throw error;
|
|
2569
2639
|
}
|
|
2570
2640
|
}
|
|
2641
|
+
const adjustInputTokens = (providerConfig, usage) => {
|
|
2642
|
+
if (!providerConfig.adjustInputTokens || !usage) return;
|
|
2643
|
+
usage.input_tokens = Math.max(0, (usage.input_tokens ?? 0) - (usage.cache_read_input_tokens ?? 0) - (usage.cache_creation_input_tokens ?? 0));
|
|
2644
|
+
logger$3.debug("provider.messages.adjusted_usage:", JSON.stringify(usage));
|
|
2645
|
+
};
|
|
2571
2646
|
|
|
2572
2647
|
//#endregion
|
|
2573
2648
|
//#region src/routes/provider/messages/route.ts
|
|
@@ -2775,6 +2850,7 @@ usageRoute.get("/", async (c) => {
|
|
|
2775
2850
|
//#endregion
|
|
2776
2851
|
//#region src/server.ts
|
|
2777
2852
|
const server = new Hono();
|
|
2853
|
+
server.use(traceIdMiddleware);
|
|
2778
2854
|
server.use(logger());
|
|
2779
2855
|
server.use(cors());
|
|
2780
2856
|
server.use("*", createAuthMiddleware({ allowUnauthenticatedPaths: [
|
|
@@ -2804,4 +2880,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
|
|
|
2804
2880
|
|
|
2805
2881
|
//#endregion
|
|
2806
2882
|
export { server };
|
|
2807
|
-
//# sourceMappingURL=server-
|
|
2883
|
+
//# sourceMappingURL=server-BBSm2bHY.js.map
|