@nick3/copilot-api 1.10.9 → 1.10.30
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 +140 -45
- package/README.zh-CN.md +140 -45
- package/dist/{account-COtMmvzU.js → account-DpW8RaT6.js} +3 -3
- package/dist/{account-COtMmvzU.js.map → account-DpW8RaT6.js.map} +1 -1
- package/dist/admin/AGENTS.md +19 -0
- package/dist/admin/assets/{index-BAh4eOwM.js → index-BGmG-ckX.js} +34 -34
- package/dist/admin/index.html +1 -1
- package/dist/auth-CnwhQOu6.js +327 -0
- package/dist/auth-CnwhQOu6.js.map +1 -0
- package/dist/{check-usage-DdevqHE5.js → check-usage-CseltoFJ.js} +4 -42
- package/dist/check-usage-CseltoFJ.js.map +1 -0
- package/dist/config-XZv75uoU.js +591 -0
- package/dist/config-XZv75uoU.js.map +1 -0
- package/dist/{debug-BMo6ltbp.js → debug-D8xHblDV.js} +18 -7
- package/dist/debug-D8xHblDV.js.map +1 -0
- package/dist/main.js +5 -10
- package/dist/main.js.map +1 -1
- package/dist/mcp-http-BhELuvog.js +2 -0
- package/dist/mcp-http-DI4Vz01p.js +82 -0
- package/dist/mcp-http-DI4Vz01p.js.map +1 -0
- package/dist/mcp-http-config-DMdUDz1D.js +39 -0
- package/dist/mcp-http-config-DMdUDz1D.js.map +1 -0
- package/dist/mcp-pLTPS0tO.js +79 -0
- package/dist/mcp-pLTPS0tO.js.map +1 -0
- package/dist/{tool-search-BrN7M0Dd.js → mcp-server-DEqHrXFq.js} +25 -2
- package/dist/mcp-server-DEqHrXFq.js.map +1 -0
- package/dist/{paths-CclKwouX.js → paths-Bpsb62LK.js} +3 -1
- package/dist/paths-Bpsb62LK.js.map +1 -0
- package/dist/{poll-access-token-BAgM2-7k.js → poll-access-token-GzVkiTH8.js} +71 -4
- package/dist/poll-access-token-GzVkiTH8.js.map +1 -0
- package/dist/{request-outbound-BJjWS_jF.js → request-outbound-BkEA8Wgb.js} +1 -1
- package/dist/{request-outbound-Pu1kp2x8.js → request-outbound-DZTxxtcx.js} +3 -3
- package/dist/{request-outbound-Pu1kp2x8.js.map → request-outbound-DZTxxtcx.js.map} +1 -1
- package/dist/{proxy-_U-hgwIn.js → responses-bridge-registry-JjUvTCST.js} +127 -581
- package/dist/responses-bridge-registry-JjUvTCST.js.map +1 -0
- package/dist/{server-GxNB5Syq.js → server-BYKxAFro.js} +678 -249
- package/dist/server-BYKxAFro.js.map +1 -0
- package/dist/start-DVlCJ0Ma.js +526 -0
- package/dist/start-DVlCJ0Ma.js.map +1 -0
- package/dist/token-9O2KJcF5.js +946 -0
- package/dist/token-9O2KJcF5.js.map +1 -0
- package/package.json +2 -2
- package/dist/auth-B0y-2njL.js +0 -226
- package/dist/auth-B0y-2njL.js.map +0 -1
- package/dist/check-usage-DdevqHE5.js.map +0 -1
- package/dist/debug-BMo6ltbp.js.map +0 -1
- package/dist/get-copilot-token-8Rm-rVsp.js +0 -17
- package/dist/get-copilot-token-8Rm-rVsp.js.map +0 -1
- package/dist/mcp-9Hgepkc5.js +0 -37
- package/dist/mcp-9Hgepkc5.js.map +0 -1
- package/dist/paths-CclKwouX.js.map +0 -1
- package/dist/poll-access-token-BAgM2-7k.js.map +0 -1
- package/dist/proxy-_U-hgwIn.js.map +0 -1
- package/dist/server-GxNB5Syq.js.map +0 -1
- package/dist/start-DdrurmQ3.js +0 -274
- package/dist/start-DdrurmQ3.js.map +0 -1
- package/dist/tool-search-BrN7M0Dd.js.map +0 -1
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
import { t as PATHS } from "./paths-Bpsb62LK.js";
|
|
2
|
+
import consola from "consola";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
//#region src/lib/config.ts
|
|
5
|
+
const PROVIDER_TYPE_ANTHROPIC = "anthropic";
|
|
6
|
+
const gpt5ExplorationPrompt = `## Exploration and reading files
|
|
7
|
+
- **Think first.** Before any tool call, decide ALL files/resources you will need.
|
|
8
|
+
- **Batch everything.** If you need multiple files (even from different places), read them together.
|
|
9
|
+
- **multi_tool_use.parallel** Use multi_tool_use.parallel to parallelize tool calls and only this.
|
|
10
|
+
- **Only make sequential calls if you truly cannot know the next file without seeing a result first.**
|
|
11
|
+
- **Workflow:** (a) plan all needed reads → (b) issue one parallel batch → (c) analyze results → (d) repeat if new, unpredictable reads arise.`;
|
|
12
|
+
const DEFAULT_QUOTA_REFRESH_CONFIG = {
|
|
13
|
+
enabled: true,
|
|
14
|
+
intervalMinutes: 360,
|
|
15
|
+
startupDelaySeconds: 60,
|
|
16
|
+
staggerMinSeconds: 2,
|
|
17
|
+
staggerMaxSeconds: 5
|
|
18
|
+
};
|
|
19
|
+
const MIN_QUOTA_REFRESH_INTERVAL_MINUTES = 30;
|
|
20
|
+
const gpt5CommentaryPrompt = `# Working with the user
|
|
21
|
+
|
|
22
|
+
You interact with the user through a terminal. You have 2 ways of communicating with the users:
|
|
23
|
+
- Share intermediary updates in \`commentary\` channel.
|
|
24
|
+
- After you have completed all your work, send a message to the \`final\` channel.
|
|
25
|
+
|
|
26
|
+
## Intermediary updates
|
|
27
|
+
|
|
28
|
+
- Intermediary updates go to the \`commentary\` channel.
|
|
29
|
+
- User updates are short updates while you are working, they are NOT final answers.
|
|
30
|
+
- You use 1-2 sentence user updates to communicate progress and new information to the user as you are doing work.
|
|
31
|
+
- Do not begin responses with conversational interjections or meta commentary. Avoid openers such as acknowledgements (“Done —”, “Got it”, “Great question, ”) or framing phrases.
|
|
32
|
+
- You provide user updates frequently, every 20s.
|
|
33
|
+
- 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.
|
|
34
|
+
- 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.
|
|
35
|
+
- 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).
|
|
36
|
+
- Before performing file edits of any kind, you provide updates explaining what edits you are making.
|
|
37
|
+
- 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.
|
|
38
|
+
- Tone of your updates MUST match your personality.`;
|
|
39
|
+
const defaultConfig = {
|
|
40
|
+
auth: { apiKeys: [] },
|
|
41
|
+
providers: {},
|
|
42
|
+
extraPrompts: {
|
|
43
|
+
"gpt-5-mini": gpt5ExplorationPrompt,
|
|
44
|
+
"gpt-5.3-codex": gpt5CommentaryPrompt,
|
|
45
|
+
"gpt-5.4-mini": gpt5CommentaryPrompt,
|
|
46
|
+
"gpt-5.4": gpt5CommentaryPrompt,
|
|
47
|
+
"gpt-5.5": gpt5CommentaryPrompt
|
|
48
|
+
},
|
|
49
|
+
smallModel: "gpt-5-mini",
|
|
50
|
+
accountAffinity: true,
|
|
51
|
+
useResponsesApiContextManagement: true,
|
|
52
|
+
modelReasoningEfforts: {
|
|
53
|
+
"gpt-5-mini": "low",
|
|
54
|
+
"gpt-5.3-codex": "xhigh",
|
|
55
|
+
"gpt-5.4-mini": "xhigh",
|
|
56
|
+
"gpt-5.4": "xhigh",
|
|
57
|
+
"gpt-5.5": "xhigh"
|
|
58
|
+
},
|
|
59
|
+
allowOriginalModelNamesForAliases: false,
|
|
60
|
+
modelMappings: {},
|
|
61
|
+
forceAgent: false,
|
|
62
|
+
compactUseSmallModel: true,
|
|
63
|
+
messageStartInputTokensFallback: false,
|
|
64
|
+
modelRefreshIntervalHours: 24,
|
|
65
|
+
sessionAffinityRetentionDays: 7,
|
|
66
|
+
useMessagesApi: true,
|
|
67
|
+
useResponsesApiWebSocket: true,
|
|
68
|
+
useResponsesApiWebSearch: true,
|
|
69
|
+
logLevel: "info",
|
|
70
|
+
devMode: {
|
|
71
|
+
enabled: false,
|
|
72
|
+
capture4xx: false,
|
|
73
|
+
capture5xx: false,
|
|
74
|
+
captureOther: false
|
|
75
|
+
},
|
|
76
|
+
quotaRefresh: DEFAULT_QUOTA_REFRESH_CONFIG
|
|
77
|
+
};
|
|
78
|
+
let cachedConfig = null;
|
|
79
|
+
function isPlainObject(value) {
|
|
80
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
81
|
+
}
|
|
82
|
+
function normalizeAuthApiKeys(value) {
|
|
83
|
+
if (!Array.isArray(value)) return [];
|
|
84
|
+
return [...new Set(value.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0))];
|
|
85
|
+
}
|
|
86
|
+
function normalizeNonNegativeNumber(value) {
|
|
87
|
+
if (typeof value !== "number") return void 0;
|
|
88
|
+
if (!Number.isFinite(value)) return void 0;
|
|
89
|
+
if (value < 0) return void 0;
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
function normalizeQuotaRefreshIntervalMinutes(value) {
|
|
93
|
+
const minutes = normalizeNonNegativeNumber(value) ?? DEFAULT_QUOTA_REFRESH_CONFIG.intervalMinutes;
|
|
94
|
+
if (minutes > 0 && minutes < MIN_QUOTA_REFRESH_INTERVAL_MINUTES) return MIN_QUOTA_REFRESH_INTERVAL_MINUTES;
|
|
95
|
+
return minutes;
|
|
96
|
+
}
|
|
97
|
+
function normalizeQuotaRefreshConfig(value) {
|
|
98
|
+
const raw = isPlainObject(value) ? value : {};
|
|
99
|
+
const staggerMinSeconds = normalizeNonNegativeNumber(raw.staggerMinSeconds) ?? DEFAULT_QUOTA_REFRESH_CONFIG.staggerMinSeconds;
|
|
100
|
+
const rawStaggerMaxSeconds = normalizeNonNegativeNumber(raw.staggerMaxSeconds) ?? DEFAULT_QUOTA_REFRESH_CONFIG.staggerMaxSeconds;
|
|
101
|
+
return {
|
|
102
|
+
enabled: typeof raw.enabled === "boolean" ? raw.enabled : DEFAULT_QUOTA_REFRESH_CONFIG.enabled,
|
|
103
|
+
intervalMinutes: normalizeQuotaRefreshIntervalMinutes(raw.intervalMinutes),
|
|
104
|
+
startupDelaySeconds: normalizeNonNegativeNumber(raw.startupDelaySeconds) ?? DEFAULT_QUOTA_REFRESH_CONFIG.startupDelaySeconds,
|
|
105
|
+
staggerMinSeconds,
|
|
106
|
+
staggerMaxSeconds: Math.max(staggerMinSeconds, rawStaggerMaxSeconds)
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const LOG_LEVELS = new Set([
|
|
110
|
+
"error",
|
|
111
|
+
"warn",
|
|
112
|
+
"info",
|
|
113
|
+
"debug"
|
|
114
|
+
]);
|
|
115
|
+
function normalizeLogLevel(value) {
|
|
116
|
+
if (typeof value !== "string") return void 0;
|
|
117
|
+
return LOG_LEVELS.has(value) ? value : void 0;
|
|
118
|
+
}
|
|
119
|
+
function ensureConfigFile() {
|
|
120
|
+
try {
|
|
121
|
+
fs.accessSync(PATHS.CONFIG_PATH, fs.constants.R_OK);
|
|
122
|
+
return;
|
|
123
|
+
} catch {}
|
|
124
|
+
try {
|
|
125
|
+
fs.mkdirSync(PATHS.APP_DIR, { recursive: true });
|
|
126
|
+
fs.writeFileSync(PATHS.CONFIG_PATH, `${JSON.stringify(defaultConfig, null, 2)}\n`, "utf8");
|
|
127
|
+
try {
|
|
128
|
+
fs.chmodSync(PATHS.CONFIG_PATH, 384);
|
|
129
|
+
} catch {}
|
|
130
|
+
} catch {}
|
|
131
|
+
}
|
|
132
|
+
function readConfigFromDisk() {
|
|
133
|
+
ensureConfigFile();
|
|
134
|
+
try {
|
|
135
|
+
const raw = fs.readFileSync(PATHS.CONFIG_PATH, "utf8");
|
|
136
|
+
if (!raw.trim()) {
|
|
137
|
+
fs.writeFileSync(PATHS.CONFIG_PATH, `${JSON.stringify(defaultConfig, null, 2)}\n`, "utf8");
|
|
138
|
+
return defaultConfig;
|
|
139
|
+
}
|
|
140
|
+
return JSON.parse(raw);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
consola.error("Failed to read config file, using default config", error);
|
|
143
|
+
return defaultConfig;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function writeConfigToDisk(config) {
|
|
147
|
+
fs.mkdirSync(PATHS.APP_DIR, { recursive: true });
|
|
148
|
+
fs.writeFileSync(PATHS.CONFIG_PATH, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
149
|
+
}
|
|
150
|
+
function reloadConfig() {
|
|
151
|
+
return mergeConfigWithDefaults();
|
|
152
|
+
}
|
|
153
|
+
function mergeDefaultConfig(config) {
|
|
154
|
+
const extraPrompts = config.extraPrompts ?? {};
|
|
155
|
+
const defaultExtraPrompts = defaultConfig.extraPrompts ?? {};
|
|
156
|
+
const modelReasoningEfforts = config.modelReasoningEfforts ?? {};
|
|
157
|
+
const defaultModelReasoningEfforts = defaultConfig.modelReasoningEfforts ?? {};
|
|
158
|
+
const hasForceAgent = typeof config.forceAgent === "boolean";
|
|
159
|
+
const defaultForceAgent = defaultConfig.forceAgent ?? false;
|
|
160
|
+
const missingExtraPromptModels = Object.keys(defaultExtraPrompts).filter((model) => !Object.hasOwn(extraPrompts, model));
|
|
161
|
+
const missingReasoningEffortModels = Object.keys(defaultModelReasoningEfforts).filter((model) => !Object.hasOwn(modelReasoningEfforts, model));
|
|
162
|
+
const hasExtraPromptChanges = missingExtraPromptModels.length > 0;
|
|
163
|
+
const hasReasoningEffortChanges = missingReasoningEffortModels.length > 0;
|
|
164
|
+
if (!hasExtraPromptChanges && !hasReasoningEffortChanges && !!hasForceAgent) return {
|
|
165
|
+
mergedConfig: config,
|
|
166
|
+
changed: false
|
|
167
|
+
};
|
|
168
|
+
return {
|
|
169
|
+
mergedConfig: {
|
|
170
|
+
...config,
|
|
171
|
+
extraPrompts: {
|
|
172
|
+
...defaultExtraPrompts,
|
|
173
|
+
...extraPrompts
|
|
174
|
+
},
|
|
175
|
+
modelReasoningEfforts: {
|
|
176
|
+
...defaultModelReasoningEfforts,
|
|
177
|
+
...modelReasoningEfforts
|
|
178
|
+
},
|
|
179
|
+
forceAgent: hasForceAgent ? config.forceAgent : defaultForceAgent
|
|
180
|
+
},
|
|
181
|
+
changed: true
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function mergeDefaultAuth(config) {
|
|
185
|
+
const authConfig = isPlainObject(config.auth) ? config.auth : void 0;
|
|
186
|
+
const nextAuth = { apiKeys: normalizeAuthApiKeys(Array.isArray(authConfig?.apiKeys) ? authConfig.apiKeys : void 0) };
|
|
187
|
+
if (authConfig && JSON.stringify(authConfig) === JSON.stringify(nextAuth)) return {
|
|
188
|
+
mergedConfig: config,
|
|
189
|
+
changed: false
|
|
190
|
+
};
|
|
191
|
+
return {
|
|
192
|
+
mergedConfig: {
|
|
193
|
+
...config,
|
|
194
|
+
auth: nextAuth
|
|
195
|
+
},
|
|
196
|
+
changed: true
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function mergeDefaultAccountAffinity(config) {
|
|
200
|
+
const raw = config;
|
|
201
|
+
const hasOld = typeof raw.freeModelLoadBalancing === "boolean";
|
|
202
|
+
const hasNew = typeof config.accountAffinity === "boolean";
|
|
203
|
+
if (hasOld) {
|
|
204
|
+
const next = { ...config };
|
|
205
|
+
if (!hasNew) next.accountAffinity = raw.freeModelLoadBalancing;
|
|
206
|
+
delete next.freeModelLoadBalancing;
|
|
207
|
+
return {
|
|
208
|
+
mergedConfig: next,
|
|
209
|
+
changed: true
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
if (hasNew) return {
|
|
213
|
+
mergedConfig: config,
|
|
214
|
+
changed: false
|
|
215
|
+
};
|
|
216
|
+
return {
|
|
217
|
+
mergedConfig: {
|
|
218
|
+
...config,
|
|
219
|
+
accountAffinity: defaultConfig.accountAffinity ?? true
|
|
220
|
+
},
|
|
221
|
+
changed: true
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function mergeDefaultModelRefreshInterval(config) {
|
|
225
|
+
if (normalizeNonNegativeNumber(config.modelRefreshIntervalHours) !== void 0) return {
|
|
226
|
+
mergedConfig: config,
|
|
227
|
+
changed: false
|
|
228
|
+
};
|
|
229
|
+
return {
|
|
230
|
+
mergedConfig: {
|
|
231
|
+
...config,
|
|
232
|
+
modelRefreshIntervalHours: defaultConfig.modelRefreshIntervalHours ?? 24
|
|
233
|
+
},
|
|
234
|
+
changed: true
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function mergeDefaultSessionAffinityRetention(config) {
|
|
238
|
+
if (normalizeNonNegativeNumber(config.sessionAffinityRetentionDays) !== void 0) return {
|
|
239
|
+
mergedConfig: config,
|
|
240
|
+
changed: false
|
|
241
|
+
};
|
|
242
|
+
return {
|
|
243
|
+
mergedConfig: {
|
|
244
|
+
...config,
|
|
245
|
+
sessionAffinityRetentionDays: defaultConfig.sessionAffinityRetentionDays ?? 7
|
|
246
|
+
},
|
|
247
|
+
changed: true
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function mergeDefaultLogLevel(config) {
|
|
251
|
+
if (normalizeLogLevel(config.logLevel) !== void 0) return {
|
|
252
|
+
mergedConfig: config,
|
|
253
|
+
changed: false
|
|
254
|
+
};
|
|
255
|
+
return {
|
|
256
|
+
mergedConfig: {
|
|
257
|
+
...config,
|
|
258
|
+
logLevel: defaultConfig.logLevel ?? "info"
|
|
259
|
+
},
|
|
260
|
+
changed: true
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function mergeDefaultDevMode(config) {
|
|
264
|
+
const current = config.devMode;
|
|
265
|
+
if (current && typeof current.enabled === "boolean" && typeof current.capture4xx === "boolean" && typeof current.capture5xx === "boolean" && typeof current.captureOther === "boolean") return {
|
|
266
|
+
mergedConfig: config,
|
|
267
|
+
changed: false
|
|
268
|
+
};
|
|
269
|
+
return {
|
|
270
|
+
mergedConfig: {
|
|
271
|
+
...config,
|
|
272
|
+
devMode: {
|
|
273
|
+
enabled: current?.enabled === true,
|
|
274
|
+
capture4xx: current?.capture4xx === true,
|
|
275
|
+
capture5xx: current?.capture5xx === true,
|
|
276
|
+
captureOther: current?.captureOther === true
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
changed: true
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
function mergeDefaultQuotaRefresh(config) {
|
|
283
|
+
const quotaRefresh = normalizeQuotaRefreshConfig(config.quotaRefresh);
|
|
284
|
+
if (JSON.stringify(config.quotaRefresh) === JSON.stringify(quotaRefresh)) return {
|
|
285
|
+
mergedConfig: config,
|
|
286
|
+
changed: false
|
|
287
|
+
};
|
|
288
|
+
return {
|
|
289
|
+
mergedConfig: {
|
|
290
|
+
...config,
|
|
291
|
+
quotaRefresh
|
|
292
|
+
},
|
|
293
|
+
changed: true
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function applyConfigMerges(config, mergeFns) {
|
|
297
|
+
return mergeFns.reduce((acc, mergeFn) => {
|
|
298
|
+
const result = mergeFn(acc.mergedConfig);
|
|
299
|
+
return {
|
|
300
|
+
mergedConfig: result.mergedConfig,
|
|
301
|
+
changed: acc.changed || result.changed
|
|
302
|
+
};
|
|
303
|
+
}, {
|
|
304
|
+
mergedConfig: config,
|
|
305
|
+
changed: false
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
function mergeConfigWithDefaults() {
|
|
309
|
+
const { mergedConfig, changed } = applyConfigMerges(readConfigFromDisk(), [
|
|
310
|
+
mergeDefaultAuth,
|
|
311
|
+
mergeDefaultConfig,
|
|
312
|
+
mergeDefaultAccountAffinity,
|
|
313
|
+
mergeDefaultModelRefreshInterval,
|
|
314
|
+
mergeDefaultSessionAffinityRetention,
|
|
315
|
+
mergeDefaultLogLevel,
|
|
316
|
+
mergeDefaultDevMode,
|
|
317
|
+
mergeDefaultQuotaRefresh
|
|
318
|
+
]);
|
|
319
|
+
if (changed) try {
|
|
320
|
+
fs.writeFileSync(PATHS.CONFIG_PATH, `${JSON.stringify(mergedConfig, null, 2)}\n`, "utf8");
|
|
321
|
+
} catch (writeError) {
|
|
322
|
+
consola.warn("Failed to write merged config defaults", writeError);
|
|
323
|
+
}
|
|
324
|
+
cachedConfig = mergedConfig;
|
|
325
|
+
return mergedConfig;
|
|
326
|
+
}
|
|
327
|
+
function getConfig() {
|
|
328
|
+
cachedConfig ??= mergeDefaultConfig(readConfigFromDisk()).mergedConfig;
|
|
329
|
+
return cachedConfig;
|
|
330
|
+
}
|
|
331
|
+
function normalizeAliasKey(value) {
|
|
332
|
+
const trimmed = value.trim().toLowerCase();
|
|
333
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
334
|
+
}
|
|
335
|
+
function normalizeAliasTarget(value) {
|
|
336
|
+
const trimmed = value.trim();
|
|
337
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
338
|
+
}
|
|
339
|
+
function normalizeAliasSpec(value) {
|
|
340
|
+
if (typeof value === "string") {
|
|
341
|
+
const normalizedTarget = normalizeAliasTarget(value);
|
|
342
|
+
return normalizedTarget ? { target: normalizedTarget } : null;
|
|
343
|
+
}
|
|
344
|
+
if (!value || typeof value !== "object") return null;
|
|
345
|
+
const targetValue = value.target;
|
|
346
|
+
if (typeof targetValue !== "string") return null;
|
|
347
|
+
const normalizedTarget = normalizeAliasTarget(targetValue);
|
|
348
|
+
if (!normalizedTarget) return null;
|
|
349
|
+
const allowOriginalValue = value.allowOriginal;
|
|
350
|
+
return {
|
|
351
|
+
target: normalizedTarget,
|
|
352
|
+
allowOriginal: typeof allowOriginalValue === "boolean" ? allowOriginalValue : void 0
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
function getModelAliasesInfo() {
|
|
356
|
+
const raw = getConfig().modelAliases ?? {};
|
|
357
|
+
const normalized = {};
|
|
358
|
+
for (const [alias, rawSpec] of Object.entries(raw)) {
|
|
359
|
+
const normalizedAlias = normalizeAliasKey(alias);
|
|
360
|
+
const normalizedSpec = normalizeAliasSpec(rawSpec);
|
|
361
|
+
if (!normalizedAlias || !normalizedSpec) continue;
|
|
362
|
+
if (!Object.hasOwn(normalized, normalizedAlias)) normalized[normalizedAlias] = normalizedSpec;
|
|
363
|
+
}
|
|
364
|
+
return normalized;
|
|
365
|
+
}
|
|
366
|
+
function getModelAliases() {
|
|
367
|
+
const info = getModelAliasesInfo();
|
|
368
|
+
const normalized = {};
|
|
369
|
+
for (const [alias, spec] of Object.entries(info)) normalized[alias] = spec.target;
|
|
370
|
+
return normalized;
|
|
371
|
+
}
|
|
372
|
+
function resolveModelAlias(modelId) {
|
|
373
|
+
const normalized = normalizeAliasKey(modelId);
|
|
374
|
+
if (!normalized) return modelId;
|
|
375
|
+
return getModelAliases()[normalized] ?? modelId;
|
|
376
|
+
}
|
|
377
|
+
function isOriginalModelNameAllowedForAliases() {
|
|
378
|
+
return getConfig().allowOriginalModelNamesForAliases ?? false;
|
|
379
|
+
}
|
|
380
|
+
function getAliasTargetSet() {
|
|
381
|
+
const aliases = getModelAliasesInfo();
|
|
382
|
+
const allowOriginalDefault = isOriginalModelNameAllowedForAliases();
|
|
383
|
+
const targetAllowMap = /* @__PURE__ */ new Map();
|
|
384
|
+
for (const { target, allowOriginal } of Object.values(aliases)) {
|
|
385
|
+
const normalizedTarget = target.toLowerCase();
|
|
386
|
+
const effectiveAllow = allowOriginal ?? allowOriginalDefault;
|
|
387
|
+
const currentAllow = targetAllowMap.get(normalizedTarget);
|
|
388
|
+
if (currentAllow === true) continue;
|
|
389
|
+
if (effectiveAllow) targetAllowMap.set(normalizedTarget, true);
|
|
390
|
+
else if (currentAllow === void 0) targetAllowMap.set(normalizedTarget, false);
|
|
391
|
+
}
|
|
392
|
+
const blockedTargets = /* @__PURE__ */ new Set();
|
|
393
|
+
for (const [target, allowed] of targetAllowMap.entries()) if (!allowed) blockedTargets.add(target);
|
|
394
|
+
return blockedTargets;
|
|
395
|
+
}
|
|
396
|
+
function isOriginalModelNameAllowedForTarget(modelId) {
|
|
397
|
+
const normalized = normalizeAliasKey(modelId);
|
|
398
|
+
if (!normalized) return true;
|
|
399
|
+
return !getAliasTargetSet().has(normalized);
|
|
400
|
+
}
|
|
401
|
+
function getPreferredAliasForTarget(modelId) {
|
|
402
|
+
return getAliasKeysForTarget(modelId, getModelAliases())[0] ?? null;
|
|
403
|
+
}
|
|
404
|
+
function getAliasKeysForTarget(target, aliases) {
|
|
405
|
+
const normalizedTarget = target.toLowerCase();
|
|
406
|
+
return Object.entries(aliases).filter(([, model]) => model.toLowerCase() === normalizedTarget).map(([alias]) => alias).sort();
|
|
407
|
+
}
|
|
408
|
+
function getAliasFallbackValue(record, modelId, aliases) {
|
|
409
|
+
if (!record) return void 0;
|
|
410
|
+
const aliasKeys = getAliasKeysForTarget(modelId, aliases);
|
|
411
|
+
if (aliasKeys.length === 0) return void 0;
|
|
412
|
+
const recordByAlias = /* @__PURE__ */ new Map();
|
|
413
|
+
for (const [key, value] of Object.entries(record)) {
|
|
414
|
+
const normalized = normalizeAliasKey(key);
|
|
415
|
+
if (normalized) recordByAlias.set(normalized, value);
|
|
416
|
+
}
|
|
417
|
+
for (const alias of aliasKeys) {
|
|
418
|
+
const value = recordByAlias.get(alias);
|
|
419
|
+
if (value !== void 0) return value;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
function getExtraPromptForModel(model) {
|
|
423
|
+
const config = getConfig();
|
|
424
|
+
const direct = config.extraPrompts?.[model];
|
|
425
|
+
if (direct !== void 0) return direct;
|
|
426
|
+
const aliases = getModelAliases();
|
|
427
|
+
return getAliasFallbackValue(config.extraPrompts, model, aliases) ?? "";
|
|
428
|
+
}
|
|
429
|
+
function getModelMappings() {
|
|
430
|
+
const modelMappings = getConfig().modelMappings;
|
|
431
|
+
if (!modelMappings) return { ...defaultConfig.modelMappings };
|
|
432
|
+
const validMappings = {};
|
|
433
|
+
for (const [sourceModel, targetModel] of Object.entries(modelMappings)) {
|
|
434
|
+
if (!sourceModel || typeof targetModel !== "string" || targetModel.length === 0) continue;
|
|
435
|
+
validMappings[sourceModel] = targetModel;
|
|
436
|
+
}
|
|
437
|
+
return validMappings;
|
|
438
|
+
}
|
|
439
|
+
function resolveMappedModel(model) {
|
|
440
|
+
return getModelMappings()[model] ?? model;
|
|
441
|
+
}
|
|
442
|
+
function getSmallModel() {
|
|
443
|
+
const model = getConfig().smallModel ?? "gpt-5-mini";
|
|
444
|
+
if (isOriginalModelNameAllowedForTarget(model)) return model;
|
|
445
|
+
return getPreferredAliasForTarget(model) ?? model;
|
|
446
|
+
}
|
|
447
|
+
function getLogLevel() {
|
|
448
|
+
return normalizeLogLevel(getConfig().logLevel) ?? defaultConfig.logLevel ?? "info";
|
|
449
|
+
}
|
|
450
|
+
function isAccountAffinityEnabled() {
|
|
451
|
+
return getConfig().accountAffinity ?? true;
|
|
452
|
+
}
|
|
453
|
+
function getModelRefreshIntervalHours() {
|
|
454
|
+
return normalizeNonNegativeNumber(getConfig().modelRefreshIntervalHours) ?? defaultConfig.modelRefreshIntervalHours ?? 24;
|
|
455
|
+
}
|
|
456
|
+
function getModelRefreshIntervalMs() {
|
|
457
|
+
const hours = getModelRefreshIntervalHours();
|
|
458
|
+
if (!Number.isFinite(hours) || hours <= 0) return 0;
|
|
459
|
+
return hours * 60 * 60 * 1e3;
|
|
460
|
+
}
|
|
461
|
+
function getQuotaRefreshConfig() {
|
|
462
|
+
return normalizeQuotaRefreshConfig(getConfig().quotaRefresh);
|
|
463
|
+
}
|
|
464
|
+
function getSessionAffinityRetentionDays() {
|
|
465
|
+
return normalizeNonNegativeNumber(getConfig().sessionAffinityRetentionDays) ?? defaultConfig.sessionAffinityRetentionDays ?? 7;
|
|
466
|
+
}
|
|
467
|
+
function getSessionAffinityRetentionMs() {
|
|
468
|
+
const days = getSessionAffinityRetentionDays();
|
|
469
|
+
if (!Number.isFinite(days) || days <= 0) return 0;
|
|
470
|
+
return days * 24 * 60 * 60 * 1e3;
|
|
471
|
+
}
|
|
472
|
+
function isMessageStartInputTokensFallbackEnabled() {
|
|
473
|
+
return getConfig().messageStartInputTokensFallback ?? false;
|
|
474
|
+
}
|
|
475
|
+
function shouldCompactUseSmallModel() {
|
|
476
|
+
return getConfig().compactUseSmallModel ?? true;
|
|
477
|
+
}
|
|
478
|
+
function isResponsesApiContextManagementEnabled() {
|
|
479
|
+
return getConfig().useResponsesApiContextManagement ?? true;
|
|
480
|
+
}
|
|
481
|
+
function getReasoningEffortForModel(model) {
|
|
482
|
+
const config = getConfig();
|
|
483
|
+
const direct = config.modelReasoningEfforts?.[model];
|
|
484
|
+
if (direct !== void 0) return direct;
|
|
485
|
+
const aliases = getModelAliases();
|
|
486
|
+
return getAliasFallbackValue(config.modelReasoningEfforts, model, aliases) ?? "high";
|
|
487
|
+
}
|
|
488
|
+
function isForceAgentEnabled() {
|
|
489
|
+
return getConfig().forceAgent ?? false;
|
|
490
|
+
}
|
|
491
|
+
function normalizeProviderBaseUrl(url) {
|
|
492
|
+
return url.trim().replace(/\/+$/u, "");
|
|
493
|
+
}
|
|
494
|
+
function getDefaultProviderAuthType(providerType) {
|
|
495
|
+
return providerType === "anthropic" ? "x-api-key" : "authorization";
|
|
496
|
+
}
|
|
497
|
+
function resolveProviderAuthType(providerName, authType, providerType) {
|
|
498
|
+
const defaultAuthType = getDefaultProviderAuthType(providerType);
|
|
499
|
+
if (authType === void 0) return defaultAuthType;
|
|
500
|
+
if (authType === "x-api-key") return "x-api-key";
|
|
501
|
+
if (authType === "oauth2") {
|
|
502
|
+
if (providerName === "codex") return authType;
|
|
503
|
+
consola.warn(`Provider ${providerName} has authType 'oauth2', which is only supported by the builtin codex provider, falling back to ${defaultAuthType}`);
|
|
504
|
+
return defaultAuthType;
|
|
505
|
+
}
|
|
506
|
+
if (authType === "authorization") return authType;
|
|
507
|
+
consola.warn(`Provider ${providerName} has invalid authType '${authType}', falling back to ${defaultAuthType}`);
|
|
508
|
+
return defaultAuthType;
|
|
509
|
+
}
|
|
510
|
+
function isProviderApiKeyRequired(providerName, authType) {
|
|
511
|
+
return !(providerName === "codex" && authType === "oauth2");
|
|
512
|
+
}
|
|
513
|
+
function getRawProviderConfig(name) {
|
|
514
|
+
const providerName = name.trim();
|
|
515
|
+
if (!providerName) return null;
|
|
516
|
+
return getConfig().providers?.[providerName] ?? null;
|
|
517
|
+
}
|
|
518
|
+
function setProviderConfig(name, provider) {
|
|
519
|
+
const providerName = name.trim();
|
|
520
|
+
if (!providerName) throw new Error("Provider name must be a non-empty string");
|
|
521
|
+
if (isReservedProviderName(providerName)) throw new Error(`Provider ${providerName} is reserved and cannot be configured in config.providers`);
|
|
522
|
+
const editableConfig = readConfigFromDisk();
|
|
523
|
+
writeConfigToDisk({
|
|
524
|
+
...editableConfig,
|
|
525
|
+
providers: {
|
|
526
|
+
...editableConfig.providers,
|
|
527
|
+
[providerName]: provider
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
cachedConfig = reloadConfig();
|
|
531
|
+
return getRawProviderConfig(providerName) ?? provider;
|
|
532
|
+
}
|
|
533
|
+
function getProviderConfig(name) {
|
|
534
|
+
const providerName = name.trim();
|
|
535
|
+
if (!providerName) return null;
|
|
536
|
+
if (isReservedProviderName(providerName)) {
|
|
537
|
+
consola.warn(`Provider ${providerName} is reserved and cannot be configured in config.providers`);
|
|
538
|
+
return null;
|
|
539
|
+
}
|
|
540
|
+
const provider = getRawProviderConfig(providerName);
|
|
541
|
+
if (!provider) return null;
|
|
542
|
+
if (provider.enabled === false) return null;
|
|
543
|
+
const type = provider.type ?? "anthropic";
|
|
544
|
+
if (type !== "anthropic" && type !== "openai-compatible" && type !== "openai-responses") {
|
|
545
|
+
consola.warn(`Provider ${providerName} is ignored because type '${type}' is not supported`);
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
const baseUrl = normalizeProviderBaseUrl(provider.baseUrl ?? "");
|
|
549
|
+
const authType = resolveProviderAuthType(providerName, provider.authType, type);
|
|
550
|
+
const apiKey = (provider.apiKey ?? "").trim();
|
|
551
|
+
const missingFields = [...!baseUrl ? ["baseUrl"] : [], ...isProviderApiKeyRequired(providerName, authType) && !apiKey ? ["apiKey"] : []];
|
|
552
|
+
if (missingFields.length > 0) {
|
|
553
|
+
consola.warn(`Provider ${providerName} is enabled but missing ${missingFields.join(" or ")}`);
|
|
554
|
+
return null;
|
|
555
|
+
}
|
|
556
|
+
return {
|
|
557
|
+
name: providerName,
|
|
558
|
+
type,
|
|
559
|
+
baseUrl,
|
|
560
|
+
apiKey,
|
|
561
|
+
authType,
|
|
562
|
+
models: provider.models,
|
|
563
|
+
adjustInputTokens: provider.adjustInputTokens
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
function listEnabledProviders() {
|
|
567
|
+
const config = getConfig();
|
|
568
|
+
return Object.keys(config.providers ?? {}).filter((name) => getProviderConfig(name) !== null);
|
|
569
|
+
}
|
|
570
|
+
function isReservedProviderName(name) {
|
|
571
|
+
return name.trim() === "copilot";
|
|
572
|
+
}
|
|
573
|
+
function isMessagesApiEnabled() {
|
|
574
|
+
return getConfig().useMessagesApi ?? true;
|
|
575
|
+
}
|
|
576
|
+
function isResponsesApiWebSocketEnabled() {
|
|
577
|
+
return getConfig().useResponsesApiWebSocket ?? true;
|
|
578
|
+
}
|
|
579
|
+
function getAnthropicApiKey() {
|
|
580
|
+
return getConfig().anthropicApiKey ?? process.env.ANTHROPIC_API_KEY ?? void 0;
|
|
581
|
+
}
|
|
582
|
+
function isResponsesApiWebSearchEnabled() {
|
|
583
|
+
return getConfig().useResponsesApiWebSearch ?? true;
|
|
584
|
+
}
|
|
585
|
+
function getClaudeTokenMultiplier() {
|
|
586
|
+
return getConfig().claudeTokenMultiplier ?? 1.15;
|
|
587
|
+
}
|
|
588
|
+
//#endregion
|
|
589
|
+
export { isResponsesApiWebSocketEnabled as C, resolveModelAlias as D, resolveMappedModel as E, setProviderConfig as O, isResponsesApiWebSearchEnabled as S, mergeConfigWithDefaults as T, isAccountAffinityEnabled as _, getConfig as a, isMessagesApiEnabled as b, getModelAliases as c, getProviderConfig as d, getQuotaRefreshConfig as f, getSmallModel as g, getSessionAffinityRetentionMs as h, getClaudeTokenMultiplier as i, shouldCompactUseSmallModel as k, getModelAliasesInfo as l, getReasoningEffortForModel as m, getAliasTargetSet as n, getExtraPromptForModel as o, getRawProviderConfig as p, getAnthropicApiKey as r, getLogLevel as s, PROVIDER_TYPE_ANTHROPIC as t, getModelRefreshIntervalMs as u, isForceAgentEnabled as v, listEnabledProviders as w, isResponsesApiContextManagementEnabled as x, isMessageStartInputTokensFallbackEnabled as y };
|
|
590
|
+
|
|
591
|
+
//# sourceMappingURL=config-XZv75uoU.js.map
|