@jeffreycao/copilot-api 2.6.11 → 2.6.13
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 +12 -6
- package/README.zh-CN.md +13 -7
- package/dist/auth-B0w9MzMB.js +2 -0
- package/dist/{auth-aGQ_vPFn.js → auth-B1iccyyN.js} +47 -9
- package/dist/auth-B1iccyyN.js.map +1 -0
- package/dist/{config-g8kEbc0j.js → config-B_pC8QXv.js} +421 -10
- package/dist/config-B_pC8QXv.js.map +1 -0
- package/dist/{debug-DXGZGaoU.js → debug-C4rsL806.js} +2 -2
- package/dist/{debug-DXGZGaoU.js.map → debug-C4rsL806.js.map} +1 -1
- package/dist/main.js +3 -3
- package/dist/{models-C1H-ahM4.js → models-NNzBeGzA.js} +2 -2
- package/dist/{models-C1H-ahM4.js.map → models-NNzBeGzA.js.map} +1 -1
- package/dist/{server-Biyjjk2W.js → server-w3-DhBM0.js} +119 -297
- package/dist/server-w3-DhBM0.js.map +1 -0
- package/dist/{start-CYq2v7cu.js → start-B2vhz_qK.js} +7 -6
- package/dist/{start-CYq2v7cu.js.map → start-B2vhz_qK.js.map} +1 -1
- package/dist/{token-SzcMtW4G.js → token-3SWNt25T.js} +2 -2
- package/dist/{token-SzcMtW4G.js.map → token-3SWNt25T.js.map} +1 -1
- package/package.json +2 -1
- package/dist/auth-BTdaexGw.js +0 -2
- package/dist/auth-aGQ_vPFn.js.map +0 -1
- package/dist/config-g8kEbc0j.js.map +0 -1
- package/dist/server-Biyjjk2W.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import consola from "consola";
|
|
2
|
-
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import fs$1 from "node:fs/promises";
|
|
@@ -98,7 +98,10 @@ const defaultConfig = {
|
|
|
98
98
|
auth: { apiKeys: [] },
|
|
99
99
|
providers: {},
|
|
100
100
|
modelMappings: {},
|
|
101
|
-
|
|
101
|
+
smallModels: {
|
|
102
|
+
codex: "gpt-6-luna",
|
|
103
|
+
copilot: "gpt-6-luna"
|
|
104
|
+
},
|
|
102
105
|
contextManagement: defaultContextManagement,
|
|
103
106
|
modelResponsesApiCompactThresholds,
|
|
104
107
|
useMessagesApi: true,
|
|
@@ -421,7 +424,13 @@ function resolveMappedModel(model) {
|
|
|
421
424
|
return getModelMappings()[model] ?? model;
|
|
422
425
|
}
|
|
423
426
|
function getSmallModel() {
|
|
424
|
-
return
|
|
427
|
+
return getSmallModelForProvider("copilot") ?? "gpt-6-luna";
|
|
428
|
+
}
|
|
429
|
+
function getSmallModelForProvider(provider) {
|
|
430
|
+
const providerName = provider.trim();
|
|
431
|
+
const configuredModels = getConfig().smallModels;
|
|
432
|
+
const model = configuredModels && Object.hasOwn(configuredModels, providerName) ? configuredModels[providerName] : defaultConfig.smallModels?.[providerName];
|
|
433
|
+
return typeof model === "string" ? model.trim() || void 0 : void 0;
|
|
425
434
|
}
|
|
426
435
|
function isContextManagementEnabledForMessages() {
|
|
427
436
|
return getConfig().contextManagement?.messages ?? defaultContextManagement.messages;
|
|
@@ -440,9 +449,386 @@ function getReasoningEffortForModel(model) {
|
|
|
440
449
|
return isGpt53OrAbove(model) ? "xhigh" : "high";
|
|
441
450
|
}
|
|
442
451
|
//#endregion
|
|
452
|
+
//#region src/lib/models-dev-cache.ts
|
|
453
|
+
const MODELS_DEV_URL = "https://models.dev/api.json";
|
|
454
|
+
const REFRESH_INTERVAL_MS = 3e5;
|
|
455
|
+
const FETCH_TIMEOUT_MS = 15e3;
|
|
456
|
+
const OPENCODE_GO = "opencode-go";
|
|
457
|
+
const REASONING_EFFORTS = /* @__PURE__ */ new Set([
|
|
458
|
+
"none",
|
|
459
|
+
"minimal",
|
|
460
|
+
"low",
|
|
461
|
+
"medium",
|
|
462
|
+
"high",
|
|
463
|
+
"xhigh",
|
|
464
|
+
"max",
|
|
465
|
+
"ultra"
|
|
466
|
+
]);
|
|
467
|
+
let snapshot = null;
|
|
468
|
+
let refreshTimer = null;
|
|
469
|
+
let refreshGeneration = 0;
|
|
470
|
+
let responseValidator = null;
|
|
471
|
+
let cachedBodyHash = null;
|
|
472
|
+
let activeCachePath = null;
|
|
473
|
+
let refreshAbortController = null;
|
|
474
|
+
let activeRefresh = null;
|
|
475
|
+
function isRecord(value) {
|
|
476
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
477
|
+
}
|
|
478
|
+
function getMetadataPath(cachePath) {
|
|
479
|
+
const extension = path.extname(cachePath);
|
|
480
|
+
return path.join(path.dirname(cachePath), `${path.basename(cachePath, extension)}.meta.json`);
|
|
481
|
+
}
|
|
482
|
+
function hashBody(body) {
|
|
483
|
+
return createHash("sha256").update(body).digest("hex");
|
|
484
|
+
}
|
|
485
|
+
function nonNegativeNumber(value) {
|
|
486
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
487
|
+
}
|
|
488
|
+
function positiveNumber(value) {
|
|
489
|
+
const number = nonNegativeNumber(value);
|
|
490
|
+
return number && number > 0 ? number : void 0;
|
|
491
|
+
}
|
|
492
|
+
function mapPriceTier(value) {
|
|
493
|
+
const input = nonNegativeNumber(value.input);
|
|
494
|
+
const output = nonNegativeNumber(value.output);
|
|
495
|
+
const cachedInput = nonNegativeNumber(value.cache_read);
|
|
496
|
+
const cacheCreationInput = nonNegativeNumber(value.cache_write);
|
|
497
|
+
return {
|
|
498
|
+
...input !== void 0 && { input },
|
|
499
|
+
...output !== void 0 && { output },
|
|
500
|
+
...cachedInput !== void 0 && { cachedInput },
|
|
501
|
+
...cacheCreationInput !== void 0 && { cacheCreationInput }
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function mapPricing(value) {
|
|
505
|
+
if (!isRecord(value)) return void 0;
|
|
506
|
+
const base = mapPriceTier(value);
|
|
507
|
+
const higherTiers = (Array.isArray(value.tiers) ? value.tiers : []).flatMap((tier) => {
|
|
508
|
+
const threshold = positiveNumber(tier?.tier?.size);
|
|
509
|
+
return threshold && threshold >= 1 && tier.tier.type === "context" ? [{
|
|
510
|
+
threshold,
|
|
511
|
+
price: mapPriceTier(tier)
|
|
512
|
+
}] : [];
|
|
513
|
+
}).sort((a, b) => a.threshold - b.threshold);
|
|
514
|
+
if (higherTiers.length === 0) return base;
|
|
515
|
+
const firstTierMax = Math.ceil(higherTiers[0].threshold) - 1;
|
|
516
|
+
return { tiers: [...firstTierMax > 0 ? [{
|
|
517
|
+
...base,
|
|
518
|
+
maxInputTokens: firstTierMax
|
|
519
|
+
}] : [], ...higherTiers.map((tier, index) => ({
|
|
520
|
+
...tier.price,
|
|
521
|
+
...higherTiers[index + 1] && { maxInputTokens: Math.ceil(higherTiers[index + 1].threshold) - 1 }
|
|
522
|
+
}))] };
|
|
523
|
+
}
|
|
524
|
+
function mapReasoningEfforts(value) {
|
|
525
|
+
if (!Array.isArray(value)) return [];
|
|
526
|
+
const efforts = [];
|
|
527
|
+
for (const option of value) if (option?.type === "effort" && Array.isArray(option.values)) efforts.push(...option.values);
|
|
528
|
+
return [...new Set(efforts.filter((effort) => typeof effort === "string" && REASONING_EFFORTS.has(effort)))];
|
|
529
|
+
}
|
|
530
|
+
function mapInputModalities(value) {
|
|
531
|
+
if (!isRecord(value) || !Array.isArray(value.input)) return [];
|
|
532
|
+
return [...new Set(value.input.filter((modality) => modality === "text" || modality === "image"))];
|
|
533
|
+
}
|
|
534
|
+
function mapReasoningField(model) {
|
|
535
|
+
const interleaved = model.interleaved;
|
|
536
|
+
const field = isRecord(interleaved) ? interleaved.field : interleaved;
|
|
537
|
+
if (field === "reasoning_content") return field;
|
|
538
|
+
if (model.family === "Hy") return "reasoning";
|
|
539
|
+
}
|
|
540
|
+
function mapModelConfig(model) {
|
|
541
|
+
const contextWindow = positiveNumber(model.limit?.context);
|
|
542
|
+
const maxOutputTokens = positiveNumber(model.limit?.output);
|
|
543
|
+
const reasoningEfforts = mapReasoningEfforts(model.reasoning_options);
|
|
544
|
+
const inputModalities = mapInputModalities(model.modalities);
|
|
545
|
+
const reasoningField = mapReasoningField(model);
|
|
546
|
+
const pricing = mapPricing(model.cost);
|
|
547
|
+
const defaultReasoningEffort = (model.family === "Hy" || model.family === "grok") && reasoningEfforts.includes("high") ? "high" : void 0;
|
|
548
|
+
return {
|
|
549
|
+
...contextWindow && { contextWindow },
|
|
550
|
+
...maxOutputTokens && { maxOutputTokens },
|
|
551
|
+
...inputModalities.length > 0 && { inputModalities },
|
|
552
|
+
...reasoningEfforts.length > 0 && { reasoningEfforts },
|
|
553
|
+
...defaultReasoningEffort && { defaultReasoningEffort },
|
|
554
|
+
...reasoningField && { reasoningField },
|
|
555
|
+
...pricing && { pricing }
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function mapProviderType(model, providerNpm) {
|
|
559
|
+
switch (model.provider?.npm || providerNpm) {
|
|
560
|
+
case "@ai-sdk/anthropic": return "anthropic";
|
|
561
|
+
case "@ai-sdk/openai": return model.provider?.shape === "completions" ? "openai-compatible" : "openai-responses";
|
|
562
|
+
default: return "openai-compatible";
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
function normalizeCatalogApi(value) {
|
|
566
|
+
if (typeof value !== "string" || value.includes("${")) return void 0;
|
|
567
|
+
const api = value.trim().replace(/\/+$/u, "");
|
|
568
|
+
let url;
|
|
569
|
+
try {
|
|
570
|
+
url = new URL(api);
|
|
571
|
+
} catch {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
if (url.protocol !== "https:" && url.protocol !== "http:" || url.username || url.password || url.search || url.hash) return;
|
|
575
|
+
return api;
|
|
576
|
+
}
|
|
577
|
+
function parseSelectableProviders(data) {
|
|
578
|
+
const selectableProviders = [];
|
|
579
|
+
const selectableProviderModelTypes = Object.create(null);
|
|
580
|
+
const selectableProviderModelApis = Object.create(null);
|
|
581
|
+
const selectableProviderModelPricing = Object.create(null);
|
|
582
|
+
for (const [id, value] of Object.entries(data)) {
|
|
583
|
+
if (id === "openrouter" || id === "github-copilot" || id === "opencode-go" || id === "copilot" || id === "codex" || !/^[A-Za-z0-9][A-Za-z0-9_-]*$/u.test(id) || !isRecord(value) || value.npm !== "@ai-sdk/openai-compatible" && value.npm !== "@ai-sdk/openai" && value.npm !== "@ai-sdk/anthropic") continue;
|
|
584
|
+
const api = normalizeCatalogApi(value.api);
|
|
585
|
+
if (!api) continue;
|
|
586
|
+
selectableProviders.push({
|
|
587
|
+
id,
|
|
588
|
+
name: typeof value.name === "string" && value.name.trim() ? value.name.trim() : id,
|
|
589
|
+
api,
|
|
590
|
+
type: value.npm === "@ai-sdk/openai" ? "openai-responses" : value.npm === "@ai-sdk/anthropic" ? "anthropic" : "openai-compatible"
|
|
591
|
+
});
|
|
592
|
+
const modelTypes = Object.create(null);
|
|
593
|
+
const modelApis = Object.create(null);
|
|
594
|
+
const modelPricing = Object.create(null);
|
|
595
|
+
if (isRecord(value.models)) for (const [modelId, model] of Object.entries(value.models)) {
|
|
596
|
+
if (!isRecord(model) || model.status === "deprecated") continue;
|
|
597
|
+
const modelProvider = isRecord(model.provider) ? model.provider : null;
|
|
598
|
+
const modelNpm = modelProvider?.npm ?? value.npm;
|
|
599
|
+
if (modelNpm !== "@ai-sdk/openai-compatible" && modelNpm !== "@ai-sdk/openai" && modelNpm !== "@ai-sdk/anthropic") continue;
|
|
600
|
+
modelTypes[modelId] = mapProviderType(model, value.npm);
|
|
601
|
+
const modelApi = normalizeCatalogApi(modelProvider?.api);
|
|
602
|
+
if (modelApi) modelApis[modelId] = modelApi;
|
|
603
|
+
const pricing = mapPricing(model.cost);
|
|
604
|
+
if (pricing) modelPricing[modelId] = pricing;
|
|
605
|
+
}
|
|
606
|
+
selectableProviderModelTypes[id] = modelTypes;
|
|
607
|
+
selectableProviderModelApis[id] = modelApis;
|
|
608
|
+
selectableProviderModelPricing[id] = modelPricing;
|
|
609
|
+
}
|
|
610
|
+
selectableProviders.sort((a, b) => a.name.localeCompare(b.name, "en") || a.id.localeCompare(b.id, "en"));
|
|
611
|
+
return {
|
|
612
|
+
selectableProviders,
|
|
613
|
+
selectableProviderModelTypes,
|
|
614
|
+
selectableProviderModelApis,
|
|
615
|
+
selectableProviderModelPricing
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function parseCatalog(data) {
|
|
619
|
+
const provider = isRecord(data) ? data[OPENCODE_GO] : void 0;
|
|
620
|
+
const models = isRecord(provider) ? provider.models : void 0;
|
|
621
|
+
if (!isRecord(models)) throw new Error("models.dev response has no opencode-go models");
|
|
622
|
+
const providerNpm = isRecord(provider) && typeof provider.npm === "string" ? provider.npm : void 0;
|
|
623
|
+
const configs = Object.create(null);
|
|
624
|
+
const providerTypes = Object.create(null);
|
|
625
|
+
const records = [];
|
|
626
|
+
const typedModels = models;
|
|
627
|
+
for (const id of Object.keys(typedModels).sort()) {
|
|
628
|
+
const value = typedModels[id];
|
|
629
|
+
if (!id.trim() || !isRecord(value) || value.id !== id || value.status === "deprecated") continue;
|
|
630
|
+
const config = mapModelConfig(value);
|
|
631
|
+
configs[id] = config;
|
|
632
|
+
providerTypes[id] = mapProviderType(value, providerNpm);
|
|
633
|
+
records.push({
|
|
634
|
+
id,
|
|
635
|
+
name: typeof value.name === "string" && value.name.trim() ? value.name : id,
|
|
636
|
+
object: "model",
|
|
637
|
+
created: 0,
|
|
638
|
+
owned_by: OPENCODE_GO,
|
|
639
|
+
...config.contextWindow && { context_window: config.contextWindow },
|
|
640
|
+
...config.maxOutputTokens && { max_output_tokens: config.maxOutputTokens },
|
|
641
|
+
...config.inputModalities && { input_modalities: config.inputModalities },
|
|
642
|
+
...config.reasoningEfforts && { reasoning_efforts: config.reasoningEfforts }
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
if (records.length === 0) throw new Error("models.dev response has no valid opencode-go models");
|
|
646
|
+
return {
|
|
647
|
+
configs,
|
|
648
|
+
providerTypes,
|
|
649
|
+
records,
|
|
650
|
+
...parseSelectableProviders(data)
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function installModelsDevCatalog(data) {
|
|
654
|
+
snapshot = parseCatalog(data);
|
|
655
|
+
return snapshot.records.length;
|
|
656
|
+
}
|
|
657
|
+
function getOpencodeGoModelIds() {
|
|
658
|
+
return snapshot?.records.map((model) => model.id) ?? [];
|
|
659
|
+
}
|
|
660
|
+
function getOpencodeGoModelConfig(modelId) {
|
|
661
|
+
return snapshot?.configs[modelId.trim()] ?? snapshot?.configs[modelId.trim().toLowerCase()];
|
|
662
|
+
}
|
|
663
|
+
function getOpencodeGoModelProviderType(modelId) {
|
|
664
|
+
const id = modelId.trim();
|
|
665
|
+
return snapshot?.providerTypes[id] ?? snapshot?.providerTypes[id.toLowerCase()] ?? "openai-compatible";
|
|
666
|
+
}
|
|
667
|
+
function getOpencodeGoModelRecords() {
|
|
668
|
+
return snapshot?.records ?? [];
|
|
669
|
+
}
|
|
670
|
+
function getModelsDevProviderOptions() {
|
|
671
|
+
return snapshot?.selectableProviders ?? [];
|
|
672
|
+
}
|
|
673
|
+
function getModelsDevProviderApi(providerId) {
|
|
674
|
+
return snapshot?.selectableProviders.find((provider) => provider.id === providerId)?.api;
|
|
675
|
+
}
|
|
676
|
+
function getModelsDevModelProviderType(providerId, modelId) {
|
|
677
|
+
return snapshot?.selectableProviderModelTypes[providerId]?.[modelId];
|
|
678
|
+
}
|
|
679
|
+
function getModelsDevModelApi(providerId, modelId) {
|
|
680
|
+
return snapshot?.selectableProviderModelApis[providerId]?.[modelId];
|
|
681
|
+
}
|
|
682
|
+
function getModelsDevModelPricing(providerId, modelId) {
|
|
683
|
+
return snapshot?.selectableProviderModelPricing[providerId]?.[modelId];
|
|
684
|
+
}
|
|
685
|
+
async function loadModelsDevProviderOptions() {
|
|
686
|
+
if (!snapshot) {
|
|
687
|
+
const cachePath = activeCachePath ?? path.join(PATHS.APP_DIR, "models-dev-api.json");
|
|
688
|
+
await loadDiskCache(cachePath);
|
|
689
|
+
if (!snapshot) {
|
|
690
|
+
await refreshCatalog(cachePath, fetch, new AbortController().signal, refreshGeneration);
|
|
691
|
+
activeCachePath = cachePath;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return getModelsDevProviderOptions();
|
|
695
|
+
}
|
|
696
|
+
async function stopModelsDevRefreshLoop() {
|
|
697
|
+
refreshGeneration += 1;
|
|
698
|
+
if (refreshTimer) clearTimeout(refreshTimer);
|
|
699
|
+
refreshTimer = null;
|
|
700
|
+
refreshAbortController?.abort();
|
|
701
|
+
await activeRefresh?.catch(() => void 0);
|
|
702
|
+
activeRefresh = null;
|
|
703
|
+
}
|
|
704
|
+
async function loadDiskCache(cachePath) {
|
|
705
|
+
let body;
|
|
706
|
+
try {
|
|
707
|
+
body = await fs$1.readFile(cachePath, "utf8");
|
|
708
|
+
installModelsDevCatalog(JSON.parse(body));
|
|
709
|
+
cachedBodyHash = hashBody(body);
|
|
710
|
+
} catch (error) {
|
|
711
|
+
if (isRecord(error) && error.code === "ENOENT") return;
|
|
712
|
+
consola.warn("Failed to load models.dev disk cache.", error);
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
try {
|
|
716
|
+
const metadata = JSON.parse(await fs$1.readFile(getMetadataPath(cachePath), "utf8"));
|
|
717
|
+
if (isRecord(metadata) && metadata.sha256 === cachedBodyHash) responseValidator = {
|
|
718
|
+
etag: typeof metadata.etag === "string" && metadata.etag.trim() ? metadata.etag : void 0,
|
|
719
|
+
lastModified: typeof metadata.lastModified === "string" && metadata.lastModified.trim() ? metadata.lastModified : void 0
|
|
720
|
+
};
|
|
721
|
+
} catch (error) {
|
|
722
|
+
if (isRecord(error) && error.code === "ENOENT") return;
|
|
723
|
+
consola.warn("Failed to load models.dev cache metadata.", error);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
async function persistMetadata(cachePath, sha256, validator) {
|
|
727
|
+
const metadataPath = getMetadataPath(cachePath);
|
|
728
|
+
const temporaryPath = `${metadataPath}.${randomUUID()}.tmp`;
|
|
729
|
+
try {
|
|
730
|
+
await fs$1.writeFile(temporaryPath, JSON.stringify({
|
|
731
|
+
sha256,
|
|
732
|
+
...validator
|
|
733
|
+
}), { mode: 384 });
|
|
734
|
+
await fs$1.rename(temporaryPath, metadataPath);
|
|
735
|
+
} finally {
|
|
736
|
+
await fs$1.rm(temporaryPath, { force: true });
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
async function persistCache(cachePath, body, sha256, validator) {
|
|
740
|
+
await fs$1.mkdir(path.dirname(cachePath), { recursive: true });
|
|
741
|
+
const temporaryPath = `${cachePath}.${randomUUID()}.tmp`;
|
|
742
|
+
try {
|
|
743
|
+
await fs$1.writeFile(temporaryPath, body, { mode: 384 });
|
|
744
|
+
await fs$1.rename(temporaryPath, cachePath);
|
|
745
|
+
await persistMetadata(cachePath, sha256, validator);
|
|
746
|
+
} finally {
|
|
747
|
+
await fs$1.rm(temporaryPath, { force: true });
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
async function refreshCatalog(cachePath, fetcher, signal, generation) {
|
|
751
|
+
const headers = new Headers({ accept: "application/json" });
|
|
752
|
+
if (snapshot && responseValidator?.etag) headers.set("if-none-match", responseValidator.etag);
|
|
753
|
+
else if (snapshot && responseValidator?.lastModified) headers.set("if-modified-since", responseValidator.lastModified);
|
|
754
|
+
const response = await fetcher(MODELS_DEV_URL, {
|
|
755
|
+
headers,
|
|
756
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(FETCH_TIMEOUT_MS)])
|
|
757
|
+
});
|
|
758
|
+
if (signal.aborted || generation !== refreshGeneration) return;
|
|
759
|
+
if (response.status === 304) {
|
|
760
|
+
if (!snapshot) throw new Error("models.dev returned HTTP 304 without a cached catalog");
|
|
761
|
+
responseValidator = {
|
|
762
|
+
etag: response.headers.get("etag") ?? responseValidator?.etag,
|
|
763
|
+
lastModified: response.headers.get("last-modified") ?? responseValidator?.lastModified
|
|
764
|
+
};
|
|
765
|
+
if (cachedBodyHash) try {
|
|
766
|
+
await persistMetadata(cachePath, cachedBodyHash, responseValidator);
|
|
767
|
+
} catch (error) {
|
|
768
|
+
consola.warn("Failed to save models.dev cache metadata.", error);
|
|
769
|
+
}
|
|
770
|
+
consola.debug("models.dev catalog is unchanged");
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
if (!response.ok) throw new Error(`models.dev returned HTTP ${response.status}`);
|
|
774
|
+
const body = await response.text();
|
|
775
|
+
if (signal.aborted || generation !== refreshGeneration) return;
|
|
776
|
+
const nextSnapshot = parseCatalog(JSON.parse(body));
|
|
777
|
+
snapshot = nextSnapshot;
|
|
778
|
+
cachedBodyHash = hashBody(body);
|
|
779
|
+
responseValidator = {
|
|
780
|
+
etag: response.headers.get("etag") ?? void 0,
|
|
781
|
+
lastModified: response.headers.get("last-modified") ?? void 0
|
|
782
|
+
};
|
|
783
|
+
try {
|
|
784
|
+
await persistCache(cachePath, body, cachedBodyHash, responseValidator);
|
|
785
|
+
} catch (error) {
|
|
786
|
+
consola.warn("Failed to save models.dev disk cache.", error);
|
|
787
|
+
}
|
|
788
|
+
consola.debug(`Loaded ${nextSnapshot.records.length} OpenCode Go models from models.dev`);
|
|
789
|
+
}
|
|
790
|
+
function scheduleRefresh(cachePath, fetcher, intervalMs, generation) {
|
|
791
|
+
refreshTimer = setTimeout(() => {
|
|
792
|
+
refreshTimer = null;
|
|
793
|
+
activeRefresh = runRefresh(cachePath, fetcher, intervalMs, generation, false);
|
|
794
|
+
}, intervalMs);
|
|
795
|
+
}
|
|
796
|
+
async function runRefresh(cachePath, fetcher, intervalMs, generation, required) {
|
|
797
|
+
const controller = new AbortController();
|
|
798
|
+
refreshAbortController = controller;
|
|
799
|
+
let refreshed = false;
|
|
800
|
+
try {
|
|
801
|
+
await refreshCatalog(cachePath, fetcher, controller.signal, generation);
|
|
802
|
+
refreshed = true;
|
|
803
|
+
} catch (error) {
|
|
804
|
+
if (required) throw new Error(`Failed to fetch initial models.dev catalog: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
805
|
+
if (generation === refreshGeneration && !controller.signal.aborted) consola.warn("Failed to refresh models.dev catalog; keeping cached models.", error);
|
|
806
|
+
} finally {
|
|
807
|
+
if (refreshAbortController === controller) refreshAbortController = null;
|
|
808
|
+
if (generation === refreshGeneration && (!required || refreshed)) scheduleRefresh(cachePath, fetcher, intervalMs, generation);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
async function startModelsDevCache(options = {}) {
|
|
812
|
+
await stopModelsDevRefreshLoop();
|
|
813
|
+
responseValidator = null;
|
|
814
|
+
const generation = refreshGeneration;
|
|
815
|
+
const cachePath = options.cachePath ?? path.join(PATHS.APP_DIR, "models-dev-api.json");
|
|
816
|
+
if (activeCachePath !== cachePath) {
|
|
817
|
+
snapshot = null;
|
|
818
|
+
cachedBodyHash = null;
|
|
819
|
+
}
|
|
820
|
+
activeCachePath = cachePath;
|
|
821
|
+
const fetcher = options.fetcher ?? fetch;
|
|
822
|
+
const intervalMs = options.intervalMs ?? REFRESH_INTERVAL_MS;
|
|
823
|
+
await loadDiskCache(cachePath);
|
|
824
|
+
if (generation === refreshGeneration) {
|
|
825
|
+
const required = snapshot === null;
|
|
826
|
+
activeRefresh = runRefresh(cachePath, fetcher, intervalMs, generation, required);
|
|
827
|
+
if (required) await activeRefresh;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
//#endregion
|
|
443
831
|
//#region src/lib/provider-config.ts
|
|
444
|
-
const OPENCODE_ANTHROPIC_MODEL_PATTERN = /^(?:qwen|minimax)/iu;
|
|
445
|
-
const OPENCODE_RESPONSES_MODEL_PATTERN = /^(?:gpt|grok|muse-spark)(?:[-_.]|$)/iu;
|
|
446
832
|
function normalizeProviderBaseUrl(url) {
|
|
447
833
|
return url.trim().replace(/\/+$/u, "");
|
|
448
834
|
}
|
|
@@ -515,8 +901,10 @@ function getProviderConfig(name) {
|
|
|
515
901
|
name: providerName,
|
|
516
902
|
type,
|
|
517
903
|
baseUrl,
|
|
904
|
+
modelsDevProviderId: provider.modelsDevProviderId,
|
|
518
905
|
apiKey,
|
|
519
906
|
authType,
|
|
907
|
+
authTypeExplicit: provider.authType !== void 0,
|
|
520
908
|
pricingCurrency: normalizePricingCurrency(provider.pricingCurrency),
|
|
521
909
|
models: provider.models
|
|
522
910
|
};
|
|
@@ -524,15 +912,38 @@ function getProviderConfig(name) {
|
|
|
524
912
|
function resolveEffectiveProviderType(providerConfig, model) {
|
|
525
913
|
const modelConfig = providerConfig.models?.[model];
|
|
526
914
|
if (modelConfig?.type && isSupportedProviderType(modelConfig.type)) return modelConfig.type;
|
|
527
|
-
if (providerConfig.name === "opencode-go")
|
|
528
|
-
|
|
529
|
-
|
|
915
|
+
if (providerConfig.name === "opencode-go") return getOpencodeGoModelProviderType(model);
|
|
916
|
+
if (providerConfig.modelsDevProviderId) {
|
|
917
|
+
const catalogType = getModelsDevModelProviderType(providerConfig.modelsDevProviderId, model);
|
|
918
|
+
if (catalogType) return catalogType;
|
|
530
919
|
}
|
|
531
920
|
if (providerConfig.name === "openrouter") {
|
|
532
921
|
if (model.includes("gpt-")) return "openai-responses";
|
|
533
922
|
}
|
|
534
923
|
return providerConfig.type;
|
|
535
924
|
}
|
|
925
|
+
function resolveProviderConfigForModel(providerConfig, model) {
|
|
926
|
+
const type = resolveEffectiveProviderType(providerConfig, model);
|
|
927
|
+
const modelApi = providerConfig.modelsDevProviderId && providerConfig.baseUrl === getModelsDevProviderApi(providerConfig.modelsDevProviderId) ? getModelsDevModelApi(providerConfig.modelsDevProviderId, model) : void 0;
|
|
928
|
+
const configuredModel = providerConfig.models?.[model];
|
|
929
|
+
const catalogPricing = providerConfig.modelsDevProviderId ? getModelsDevModelPricing(providerConfig.modelsDevProviderId, model) : void 0;
|
|
930
|
+
const useCatalogPricing = catalogPricing !== void 0 && configuredModel?.pricing === void 0;
|
|
931
|
+
if (type === providerConfig.type && !modelApi && !useCatalogPricing) return providerConfig;
|
|
932
|
+
return {
|
|
933
|
+
...providerConfig,
|
|
934
|
+
type,
|
|
935
|
+
baseUrl: modelApi ?? providerConfig.baseUrl,
|
|
936
|
+
models: useCatalogPricing ? {
|
|
937
|
+
...providerConfig.models,
|
|
938
|
+
[model]: {
|
|
939
|
+
...configuredModel,
|
|
940
|
+
pricing: catalogPricing
|
|
941
|
+
}
|
|
942
|
+
} : providerConfig.models,
|
|
943
|
+
pricingCurrency: useCatalogPricing ? "USD" : providerConfig.pricingCurrency,
|
|
944
|
+
authType: type !== providerConfig.type && !providerConfig.authTypeExplicit && providerConfig.authType !== "azure-entra" && providerConfig.authType !== "oauth2" ? resolveProviderAuthType(providerConfig.name, void 0, type) : providerConfig.authType
|
|
945
|
+
};
|
|
946
|
+
}
|
|
536
947
|
function normalizePricingCurrency(value) {
|
|
537
948
|
return value?.trim().toUpperCase() || void 0;
|
|
538
949
|
}
|
|
@@ -544,6 +955,6 @@ function isReservedProviderName(name) {
|
|
|
544
955
|
return name.trim() === "copilot";
|
|
545
956
|
}
|
|
546
957
|
//#endregion
|
|
547
|
-
export {
|
|
958
|
+
export { getConfig as A, PATHS as B, resolveMappedModel as C, getAnthropicApiKey as D, getAlphaSearchModel as E, isResponsesApiWebSearchEnabled as F, writeFileAtomically as H, isResponsesApiWebSocketEnabled as I, mergeConfigWithDefaults as L, getUpstreamTransportConfig as M, isAlphaSearchCodexPriorityEnabled as N, getClaudeAutoModel as O, isMessagesApiEnabled as P, readEditableConfigFromDisk as R, isGpt56OrAbove as S, SUPPORTED_PROVIDER_TYPES as T, ensurePaths as V, getReasoningEffortForModel as _, normalizeProviderBaseUrl as a, isContextManagementEnabledForMessages as b, setProviderConfig as c, getOpencodeGoModelRecords as d, loadModelsDevProviderOptions as f, getModelResponsesApiCompactThreshold as g, getModelMappings as h, listEnabledProviders as i, getMessageApiWebSearchModel as j, getClaudeTokenMultiplier as k, getOpencodeGoModelConfig as l, getExtraPromptForModel as m, getRawProviderConfig as n, resolveEffectiveProviderType as o, startModelsDevCache as p, isSupportedProviderType as r, resolveProviderConfigForModel as s, getProviderConfig as t, getOpencodeGoModelIds as u, getSmallModel as v, setModelMappings as w, isContextManagementEnabledForResponses as x, getSmallModelForProvider as y, setConfiguredApiKeys as z };
|
|
548
959
|
|
|
549
|
-
//# sourceMappingURL=config-
|
|
960
|
+
//# sourceMappingURL=config-B_pC8QXv.js.map
|