gsd-pi 2.76.0-dev.4100bd590 → 2.76.0-dev.82e249f7b
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/dist/resources/extensions/gsd/auto/phases.js +4 -1
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto-model-selection.js +13 -2
- package/dist/resources/extensions/gsd/auto-start.js +12 -7
- package/dist/resources/extensions/gsd/auto.js +4 -1
- package/dist/resources/extensions/gsd/complexity-classifier.js +5 -3
- package/dist/resources/extensions/gsd/prompt-loader.js +22 -7
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +19 -19
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +19 -19
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +60 -15
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/think-tag-parser.d.ts +17 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.js +75 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.js.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.js +41 -0
- package/packages/pi-ai/dist/providers/think-tag-parser.test.js.map +1 -0
- package/packages/pi-ai/src/providers/openai-completions.ts +57 -16
- package/packages/pi-ai/src/providers/think-tag-parser.test.ts +44 -0
- package/packages/pi-ai/src/providers/think-tag-parser.ts +94 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.js +92 -12
- package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js +16 -1
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +61 -1
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +76 -10
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +13 -7
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/src/core/model-discovery.test.ts +19 -0
- package/packages/pi-coding-agent/src/core/model-discovery.ts +99 -12
- package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +75 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +86 -10
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -7
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/scripts/link-workspace-packages.cjs +1 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/phases.ts +4 -0
- package/src/resources/extensions/gsd/auto/session.ts +7 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +16 -1
- package/src/resources/extensions/gsd/auto-start.ts +12 -7
- package/src/resources/extensions/gsd/auto.ts +4 -1
- package/src/resources/extensions/gsd/complexity-classifier.ts +5 -3
- package/src/resources/extensions/gsd/prompt-loader.ts +30 -7
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +33 -3
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/complexity-classifier.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +49 -0
- /package/dist/web/standalone/.next/static/{YnUwu2WWaT0_hyTLUF4nq → ecSsu49rxxcpbNmVP4mLD}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{YnUwu2WWaT0_hyTLUF4nq → ecSsu49rxxcpbNmVP4mLD}/_ssgManifest.js +0 -0
|
@@ -27,9 +27,11 @@ export interface ProviderDiscoveryAdapter {
|
|
|
27
27
|
supportsDiscovery: boolean;
|
|
28
28
|
fetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]>;
|
|
29
29
|
}
|
|
30
|
+
export declare const OPENAI_COMPAT_DISCOVERY_APIS: Set<string>;
|
|
30
31
|
/** Per-provider TTLs in milliseconds */
|
|
31
32
|
export declare const DISCOVERY_TTLS: Record<string, number>;
|
|
32
33
|
export declare function getDefaultTTL(provider: string): number;
|
|
33
|
-
export declare function
|
|
34
|
+
export declare function supportsDiscoveryForApi(api: string | undefined): boolean;
|
|
35
|
+
export declare function getDiscoveryAdapter(provider: string, providerApis?: Iterable<string>): ProviderDiscoveryAdapter;
|
|
34
36
|
export declare function getDiscoverableProviders(): string[];
|
|
35
37
|
//# sourceMappingURL=model-discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-discovery.d.ts","sourceRoot":"","sources":["../../src/core/model-discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAC7B,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAChF;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CAC1E;AAED,wCAAwC;AACxC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMjD,CAAC;AAEF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;
|
|
1
|
+
{"version":3,"file":"model-discovery.d.ts","sourceRoot":"","sources":["../../src/core/model-discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAC7B,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAChF;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;CAC1E;AAED,eAAO,MAAM,4BAA4B,aAMvC,CAAC;AAEH,wCAAwC;AACxC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMjD,CAAC;AAEF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAsPD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAGxE;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,wBAAwB,CAa/G;AAED,wBAAgB,wBAAwB,IAAI,MAAM,EAAE,CAInD"}
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
* Provider discovery adapters for runtime model enumeration.
|
|
3
3
|
* Each adapter implements ProviderDiscoveryAdapter to fetch models from provider APIs.
|
|
4
4
|
*/
|
|
5
|
+
export const OPENAI_COMPAT_DISCOVERY_APIS = new Set([
|
|
6
|
+
"openai",
|
|
7
|
+
"openai-completions",
|
|
8
|
+
"openai-responses",
|
|
9
|
+
"openai-codex-responses",
|
|
10
|
+
"azure-openai-responses",
|
|
11
|
+
]);
|
|
5
12
|
/** Per-provider TTLs in milliseconds */
|
|
6
13
|
export const DISCOVERY_TTLS = {
|
|
7
14
|
ollama: 5 * 60 * 1000, // 5 minutes (local, models change often)
|
|
@@ -25,10 +32,72 @@ async function fetchWithTimeout(url, options = {}, timeoutMs = 5000) {
|
|
|
25
32
|
}
|
|
26
33
|
// ─── OpenAI Adapter ──────────────────────────────────────────────────────────
|
|
27
34
|
const OPENAI_EXCLUDED_PREFIXES = ["embedding", "tts", "dall-e", "whisper", "text-embedding", "davinci", "babbage"];
|
|
35
|
+
function asPositiveNumber(value) {
|
|
36
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0)
|
|
37
|
+
return value;
|
|
38
|
+
if (typeof value === "string") {
|
|
39
|
+
const n = Number.parseFloat(value);
|
|
40
|
+
if (Number.isFinite(n) && n > 0)
|
|
41
|
+
return n;
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
function pickFirstPositiveNumber(record, keys) {
|
|
46
|
+
for (const key of keys) {
|
|
47
|
+
const value = asPositiveNumber(record[key]);
|
|
48
|
+
if (value !== undefined)
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
function discoverInputModalities(rawModel, id) {
|
|
54
|
+
const directModalities = rawModel.input_modalities;
|
|
55
|
+
const capabilitiesModalities = rawModel.capabilities?.input_modalities;
|
|
56
|
+
const source = Array.isArray(directModalities)
|
|
57
|
+
? directModalities
|
|
58
|
+
: Array.isArray(capabilitiesModalities)
|
|
59
|
+
? capabilitiesModalities
|
|
60
|
+
: [];
|
|
61
|
+
const supportsImage = source.some((m) => typeof m === "string" && /image|vision/i.test(m))
|
|
62
|
+
|| /vision|image|omni|multimodal/i.test(id);
|
|
63
|
+
return supportsImage ? ["text", "image"] : ["text"];
|
|
64
|
+
}
|
|
65
|
+
function parseOpenAICompatibleModel(rawModel) {
|
|
66
|
+
const id = typeof rawModel.id === "string" ? rawModel.id : "";
|
|
67
|
+
if (!id)
|
|
68
|
+
return undefined;
|
|
69
|
+
if (OPENAI_EXCLUDED_PREFIXES.some((prefix) => id.startsWith(prefix)))
|
|
70
|
+
return undefined;
|
|
71
|
+
const contextWindow = pickFirstPositiveNumber(rawModel, [
|
|
72
|
+
"context_window",
|
|
73
|
+
"context_length",
|
|
74
|
+
"max_context_length",
|
|
75
|
+
"max_input_tokens",
|
|
76
|
+
"input_token_limit",
|
|
77
|
+
"max_model_len",
|
|
78
|
+
]);
|
|
79
|
+
const maxTokens = pickFirstPositiveNumber(rawModel, [
|
|
80
|
+
"max_output_tokens",
|
|
81
|
+
"output_token_limit",
|
|
82
|
+
"max_completion_tokens",
|
|
83
|
+
"max_tokens",
|
|
84
|
+
]);
|
|
85
|
+
const reasoning = rawModel.reasoning === true
|
|
86
|
+
|| rawModel.supports_reasoning === true
|
|
87
|
+
|| (rawModel.capabilities?.reasoning === true);
|
|
88
|
+
return {
|
|
89
|
+
id,
|
|
90
|
+
name: typeof rawModel.name === "string" && rawModel.name.length > 0 ? rawModel.name : id,
|
|
91
|
+
contextWindow,
|
|
92
|
+
maxTokens,
|
|
93
|
+
reasoning,
|
|
94
|
+
input: discoverInputModalities(rawModel, id),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
28
97
|
class OpenAIDiscoveryAdapter {
|
|
29
|
-
constructor() {
|
|
30
|
-
this.provider = "openai";
|
|
98
|
+
constructor(provider) {
|
|
31
99
|
this.supportsDiscovery = true;
|
|
100
|
+
this.provider = provider;
|
|
32
101
|
}
|
|
33
102
|
async fetchModels(apiKey, baseUrl) {
|
|
34
103
|
const url = `${baseUrl ?? "https://api.openai.com"}/v1/models`;
|
|
@@ -39,13 +108,9 @@ class OpenAIDiscoveryAdapter {
|
|
|
39
108
|
throw new Error(`OpenAI models API returned ${response.status}: ${response.statusText}`);
|
|
40
109
|
}
|
|
41
110
|
const data = (await response.json());
|
|
42
|
-
return data.data
|
|
43
|
-
.
|
|
44
|
-
.
|
|
45
|
-
id: m.id,
|
|
46
|
-
name: m.id,
|
|
47
|
-
input: ["text", "image"],
|
|
48
|
-
}));
|
|
111
|
+
return (data.data ?? [])
|
|
112
|
+
.map((m) => parseOpenAICompatibleModel(m))
|
|
113
|
+
.filter((m) => !!m);
|
|
49
114
|
}
|
|
50
115
|
}
|
|
51
116
|
// ─── Ollama Adapter ──────────────────────────────────────────────────────────
|
|
@@ -139,7 +204,7 @@ class StaticDiscoveryAdapter {
|
|
|
139
204
|
}
|
|
140
205
|
// ─── Registry ────────────────────────────────────────────────────────────────
|
|
141
206
|
const adapters = {
|
|
142
|
-
openai: new OpenAIDiscoveryAdapter(),
|
|
207
|
+
openai: new OpenAIDiscoveryAdapter("openai"),
|
|
143
208
|
ollama: new OllamaDiscoveryAdapter(),
|
|
144
209
|
openrouter: new OpenRouterDiscoveryAdapter(),
|
|
145
210
|
google: new GoogleDiscoveryAdapter(),
|
|
@@ -151,8 +216,23 @@ const adapters = {
|
|
|
151
216
|
xai: new StaticDiscoveryAdapter("xai"),
|
|
152
217
|
mistral: new StaticDiscoveryAdapter("mistral"),
|
|
153
218
|
};
|
|
154
|
-
export function
|
|
155
|
-
|
|
219
|
+
export function supportsDiscoveryForApi(api) {
|
|
220
|
+
if (!api)
|
|
221
|
+
return false;
|
|
222
|
+
return OPENAI_COMPAT_DISCOVERY_APIS.has(api);
|
|
223
|
+
}
|
|
224
|
+
export function getDiscoveryAdapter(provider, providerApis) {
|
|
225
|
+
const known = adapters[provider];
|
|
226
|
+
if (known)
|
|
227
|
+
return known;
|
|
228
|
+
if (providerApis) {
|
|
229
|
+
for (const api of providerApis) {
|
|
230
|
+
if (supportsDiscoveryForApi(api)) {
|
|
231
|
+
return new OpenAIDiscoveryAdapter(provider);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return new StaticDiscoveryAdapter(provider);
|
|
156
236
|
}
|
|
157
237
|
export function getDiscoverableProviders() {
|
|
158
238
|
return Object.entries(adapters)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-discovery.js","sourceRoot":"","sources":["../../src/core/model-discovery.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Provider discovery adapters for runtime model enumeration.\n * Each adapter implements ProviderDiscoveryAdapter to fetch models from provider APIs.\n */\n\nexport interface DiscoveredModel {\n\tid: string;\n\tname?: string;\n\tcontextWindow?: number;\n\tmaxTokens?: number;\n\treasoning?: boolean;\n\tinput?: (\"text\" | \"image\")[];\n\tcost?: { input: number; output: number; cacheRead: number; cacheWrite: number };\n}\n\nexport interface DiscoveryResult {\n\tprovider: string;\n\tmodels: DiscoveredModel[];\n\tfetchedAt: number;\n\terror?: string;\n}\n\nexport interface ProviderDiscoveryAdapter {\n\tprovider: string;\n\tsupportsDiscovery: boolean;\n\tfetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]>;\n}\n\n/** Per-provider TTLs in milliseconds */\nexport const DISCOVERY_TTLS: Record<string, number> = {\n\tollama: 5 * 60 * 1000, // 5 minutes (local, models change often)\n\topenai: 60 * 60 * 1000, // 1 hour\n\tgoogle: 60 * 60 * 1000, // 1 hour\n\topenrouter: 60 * 60 * 1000, // 1 hour\n\tdefault: 24 * 60 * 60 * 1000, // 24 hours\n};\n\nexport function getDefaultTTL(provider: string): number {\n\treturn DISCOVERY_TTLS[provider] ?? DISCOVERY_TTLS.default;\n}\n\nasync function fetchWithTimeout(url: string, options: RequestInit = {}, timeoutMs = 5000): Promise<Response> {\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), timeoutMs);\n\ttry {\n\t\treturn await fetch(url, { ...options, signal: controller.signal });\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n}\n\n// ─── OpenAI Adapter ──────────────────────────────────────────────────────────\n\nconst OPENAI_EXCLUDED_PREFIXES = [\"embedding\", \"tts\", \"dall-e\", \"whisper\", \"text-embedding\", \"davinci\", \"babbage\"];\n\nclass OpenAIDiscoveryAdapter implements ProviderDiscoveryAdapter {\n\tprovider = \"openai\";\n\tsupportsDiscovery = true;\n\n\tasync fetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]> {\n\t\tconst url = `${baseUrl ?? \"https://api.openai.com\"}/v1/models`;\n\t\tconst response = await fetchWithTimeout(url, {\n\t\t\theaders: { Authorization: `Bearer ${apiKey}` },\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`OpenAI models API returned ${response.status}: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as { data: Array<{ id: string; owned_by?: string }> };\n\t\treturn data.data\n\t\t\t.filter((m) => !OPENAI_EXCLUDED_PREFIXES.some((prefix) => m.id.startsWith(prefix)))\n\t\t\t.map((m) => ({\n\t\t\t\tid: m.id,\n\t\t\t\tname: m.id,\n\t\t\t\tinput: [\"text\" as const, \"image\" as const],\n\t\t\t}));\n\t}\n}\n\n// ─── Ollama Adapter ──────────────────────────────────────────────────────────\n\nclass OllamaDiscoveryAdapter implements ProviderDiscoveryAdapter {\n\tprovider = \"ollama\";\n\tsupportsDiscovery = true;\n\n\tasync fetchModels(_apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]> {\n\t\tconst url = `${baseUrl ?? \"http://localhost:11434\"}/api/tags`;\n\t\tconst response = await fetchWithTimeout(url);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Ollama tags API returned ${response.status}: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as {\n\t\t\tmodels: Array<{ name: string; size: number; details?: { parameter_size?: string } }>;\n\t\t};\n\n\t\treturn (data.models ?? []).map((m) => ({\n\t\t\tid: m.name,\n\t\t\tname: m.name,\n\t\t\tinput: [\"text\" as const],\n\t\t}));\n\t}\n}\n\n// ─── OpenRouter Adapter ──────────────────────────────────────────────────────\n\nclass OpenRouterDiscoveryAdapter implements ProviderDiscoveryAdapter {\n\tprovider = \"openrouter\";\n\tsupportsDiscovery = true;\n\n\tasync fetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]> {\n\t\tconst url = `${baseUrl ?? \"https://openrouter.ai\"}/api/v1/models`;\n\t\tconst response = await fetchWithTimeout(url, {\n\t\t\theaders: { Authorization: `Bearer ${apiKey}` },\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`OpenRouter models API returned ${response.status}: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as {\n\t\t\tdata: Array<{\n\t\t\t\tid: string;\n\t\t\t\tname: string;\n\t\t\t\tcontext_length?: number;\n\t\t\t\ttop_provider?: { max_completion_tokens?: number };\n\t\t\t\tpricing?: { prompt: string; completion: string };\n\t\t\t}>;\n\t\t};\n\n\t\treturn (data.data ?? []).map((m) => {\n\t\t\tconst cost =\n\t\t\t\tm.pricing?.prompt !== undefined && m.pricing?.completion !== undefined\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tinput: parseFloat(m.pricing.prompt) * 1_000_000,\n\t\t\t\t\t\t\toutput: parseFloat(m.pricing.completion) * 1_000_000,\n\t\t\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined;\n\n\t\t\treturn {\n\t\t\t\tid: m.id,\n\t\t\t\tname: m.name,\n\t\t\t\tcontextWindow: m.context_length,\n\t\t\t\tmaxTokens: m.top_provider?.max_completion_tokens,\n\t\t\t\tcost,\n\t\t\t\tinput: [\"text\" as const, \"image\" as const],\n\t\t\t};\n\t\t});\n\t}\n}\n\n// ─── Google/Gemini Adapter ───────────────────────────────────────────────────\n\nclass GoogleDiscoveryAdapter implements ProviderDiscoveryAdapter {\n\tprovider = \"google\";\n\tsupportsDiscovery = true;\n\n\tasync fetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]> {\n\t\tconst url = `${baseUrl ?? \"https://generativelanguage.googleapis.com\"}/v1beta/models?key=${apiKey}`;\n\t\tconst response = await fetchWithTimeout(url);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Google models API returned ${response.status}: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as {\n\t\t\tmodels: Array<{\n\t\t\t\tname: string;\n\t\t\t\tdisplayName: string;\n\t\t\t\tsupportedGenerationMethods?: string[];\n\t\t\t\tinputTokenLimit?: number;\n\t\t\t\toutputTokenLimit?: number;\n\t\t\t}>;\n\t\t};\n\n\t\treturn (data.models ?? [])\n\t\t\t.filter((m) => m.supportedGenerationMethods?.includes(\"generateContent\"))\n\t\t\t.map((m) => ({\n\t\t\t\tid: m.name.replace(\"models/\", \"\"),\n\t\t\t\tname: m.displayName,\n\t\t\t\tcontextWindow: m.inputTokenLimit,\n\t\t\t\tmaxTokens: m.outputTokenLimit,\n\t\t\t\tinput: [\"text\" as const, \"image\" as const],\n\t\t\t}));\n\t}\n}\n\n// ─── Static Adapter (no discovery) ───────────────────────────────────────────\n\nclass StaticDiscoveryAdapter implements ProviderDiscoveryAdapter {\n\tprovider: string;\n\tsupportsDiscovery = false;\n\n\tconstructor(provider: string) {\n\t\tthis.provider = provider;\n\t}\n\n\tasync fetchModels(): Promise<DiscoveredModel[]> {\n\t\treturn [];\n\t}\n}\n\n// ─── Registry ────────────────────────────────────────────────────────────────\n\nconst adapters: Record<string, ProviderDiscoveryAdapter> = {\n\topenai: new OpenAIDiscoveryAdapter(),\n\tollama: new OllamaDiscoveryAdapter(),\n\topenrouter: new OpenRouterDiscoveryAdapter(),\n\tgoogle: new GoogleDiscoveryAdapter(),\n\tanthropic: new StaticDiscoveryAdapter(\"anthropic\"),\n\tbedrock: new StaticDiscoveryAdapter(\"bedrock\"),\n\t\"azure-openai\": new StaticDiscoveryAdapter(\"azure-openai\"),\n\tgroq: new StaticDiscoveryAdapter(\"groq\"),\n\tcerebras: new StaticDiscoveryAdapter(\"cerebras\"),\n\txai: new StaticDiscoveryAdapter(\"xai\"),\n\tmistral: new StaticDiscoveryAdapter(\"mistral\"),\n};\n\nexport function getDiscoveryAdapter(provider: string): ProviderDiscoveryAdapter {\n\treturn adapters[provider] ?? new StaticDiscoveryAdapter(provider);\n}\n\nexport function getDiscoverableProviders(): string[] {\n\treturn Object.entries(adapters)\n\t\t.filter(([, adapter]) => adapter.supportsDiscovery)\n\t\t.map(([name]) => name);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model-discovery.js","sourceRoot":"","sources":["../../src/core/model-discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyBH,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,GAAG,CAAC;IACnD,QAAQ;IACR,oBAAoB;IACpB,kBAAkB;IAClB,wBAAwB;IACxB,wBAAwB;CACxB,CAAC,CAAC;AAEH,wCAAwC;AACxC,MAAM,CAAC,MAAM,cAAc,GAA2B;IACrD,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,yCAAyC;IAChE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,SAAS;IACjC,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,SAAS;IACjC,UAAU,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,SAAS;IACrC,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,WAAW;CACzC,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC7C,OAAO,cAAc,CAAC,QAAQ,CAAC,IAAI,cAAc,CAAC,OAAO,CAAC;AAC3D,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,UAAuB,EAAE,EAAE,SAAS,GAAG,IAAI;IACvF,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAChE,IAAI,CAAC;QACJ,OAAO,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;YAAS,CAAC;QACV,YAAY,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;AACF,CAAC;AAED,gFAAgF;AAEhF,MAAM,wBAAwB,GAAG,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AAEnH,SAAS,gBAAgB,CAAC,KAAc;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACnF,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,SAAS,uBAAuB,CAAC,MAA+B,EAAE,IAAc;IAC/E,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5C,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;IACvC,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,SAAS,uBAAuB,CAAC,QAAiC,EAAE,EAAU;IAC7E,MAAM,gBAAgB,GAAG,QAAQ,CAAC,gBAAgB,CAAC;IACnD,MAAM,sBAAsB,GAAI,QAAQ,CAAC,YAAoD,EAAE,gBAAgB,CAAC;IAChH,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC;QAC7C,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,sBAAsB,CAAC;YACtC,CAAC,CAAC,sBAAsB;YACxB,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;WACtF,+BAA+B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7C,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,0BAA0B,CAAC,QAAiC;IACpE,MAAM,EAAE,GAAG,OAAO,QAAQ,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,IAAI,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAC1B,IAAI,wBAAwB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAEvF,MAAM,aAAa,GAAG,uBAAuB,CAAC,QAAQ,EAAE;QACvD,gBAAgB;QAChB,gBAAgB;QAChB,oBAAoB;QACpB,kBAAkB;QAClB,mBAAmB;QACnB,eAAe;KACf,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,uBAAuB,CAAC,QAAQ,EAAE;QACnD,mBAAmB;QACnB,oBAAoB;QACpB,uBAAuB;QACvB,YAAY;KACZ,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,KAAK,IAAI;WACzC,QAAQ,CAAC,kBAAkB,KAAK,IAAI;WACpC,CAAE,QAAQ,CAAC,YAAoD,EAAE,SAAS,KAAK,IAAI,CAAC,CAAC;IAEzF,OAAO;QACN,EAAE;QACF,IAAI,EAAE,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;QACxF,aAAa;QACb,SAAS;QACT,SAAS;QACT,KAAK,EAAE,uBAAuB,CAAC,QAAQ,EAAE,EAAE,CAAC;KAC5C,CAAC;AACH,CAAC;AAED,MAAM,sBAAsB;IAI3B,YAAY,QAAgB;QAF5B,sBAAiB,GAAG,IAAI,CAAC;QAGxB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAAc,EAAE,OAAgB;QACjD,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,wBAAwB,YAAY,CAAC;QAC/D,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE;YAC5C,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE;SAC9C,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QAC1F,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA8C,CAAC;QAClF,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;aACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC;aACzC,MAAM,CAAC,CAAC,CAAC,EAAwB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;CACD;AAED,gFAAgF;AAEhF,MAAM,sBAAsB;IAA5B;QACC,aAAQ,GAAG,QAAQ,CAAC;QACpB,sBAAiB,GAAG,IAAI,CAAC;IAoB1B,CAAC;IAlBA,KAAK,CAAC,WAAW,CAAC,OAAe,EAAE,OAAgB;QAClD,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,wBAAwB,WAAW,CAAC;QAC9D,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAE7C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACxF,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAElC,CAAC;QAEF,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtC,EAAE,EAAE,CAAC,CAAC,IAAI;YACV,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,KAAK,EAAE,CAAC,MAAe,CAAC;SACxB,CAAC,CAAC,CAAC;IACL,CAAC;CACD;AAED,gFAAgF;AAEhF,MAAM,0BAA0B;IAAhC;QACC,aAAQ,GAAG,YAAY,CAAC;QACxB,sBAAiB,GAAG,IAAI,CAAC;IA2C1B,CAAC;IAzCA,KAAK,CAAC,WAAW,CAAC,MAAc,EAAE,OAAgB;QACjD,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,uBAAuB,gBAAgB,CAAC;QAClE,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE;YAC5C,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE;SAC9C,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,kCAAkC,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QAC9F,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAQlC,CAAC;QAEF,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAClC,MAAM,IAAI,GACT,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,EAAE,UAAU,KAAK,SAAS;gBACrE,CAAC,CAAC;oBACA,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS;oBAC/C,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,SAAS;oBACpD,SAAS,EAAE,CAAC;oBACZ,UAAU,EAAE,CAAC;iBACb;gBACF,CAAC,CAAC,SAAS,CAAC;YAEd,OAAO;gBACN,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,aAAa,EAAE,CAAC,CAAC,cAAc;gBAC/B,SAAS,EAAE,CAAC,CAAC,YAAY,EAAE,qBAAqB;gBAChD,IAAI;gBACJ,KAAK,EAAE,CAAC,MAAe,EAAE,OAAgB,CAAC;aAC1C,CAAC;QACH,CAAC,CAAC,CAAC;IACJ,CAAC;CACD;AAED,gFAAgF;AAEhF,MAAM,sBAAsB;IAA5B;QACC,aAAQ,GAAG,QAAQ,CAAC;QACpB,sBAAiB,GAAG,IAAI,CAAC;IA8B1B,CAAC;IA5BA,KAAK,CAAC,WAAW,CAAC,MAAc,EAAE,OAAgB;QACjD,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,2CAA2C,sBAAsB,MAAM,EAAE,CAAC;QACpG,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAE7C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QAC1F,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAQlC,CAAC;QAEF,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;aACxB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,0BAA0B,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC;aACxE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACZ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;YACjC,IAAI,EAAE,CAAC,CAAC,WAAW;YACnB,aAAa,EAAE,CAAC,CAAC,eAAe;YAChC,SAAS,EAAE,CAAC,CAAC,gBAAgB;YAC7B,KAAK,EAAE,CAAC,MAAe,EAAE,OAAgB,CAAC;SAC1C,CAAC,CAAC,CAAC;IACN,CAAC;CACD;AAED,gFAAgF;AAEhF,MAAM,sBAAsB;IAI3B,YAAY,QAAgB;QAF5B,sBAAiB,GAAG,KAAK,CAAC;QAGzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,WAAW;QAChB,OAAO,EAAE,CAAC;IACX,CAAC;CACD;AAED,gFAAgF;AAEhF,MAAM,QAAQ,GAA6C;IAC1D,MAAM,EAAE,IAAI,sBAAsB,CAAC,QAAQ,CAAC;IAC5C,MAAM,EAAE,IAAI,sBAAsB,EAAE;IACpC,UAAU,EAAE,IAAI,0BAA0B,EAAE;IAC5C,MAAM,EAAE,IAAI,sBAAsB,EAAE;IACpC,SAAS,EAAE,IAAI,sBAAsB,CAAC,WAAW,CAAC;IAClD,OAAO,EAAE,IAAI,sBAAsB,CAAC,SAAS,CAAC;IAC9C,cAAc,EAAE,IAAI,sBAAsB,CAAC,cAAc,CAAC;IAC1D,IAAI,EAAE,IAAI,sBAAsB,CAAC,MAAM,CAAC;IACxC,QAAQ,EAAE,IAAI,sBAAsB,CAAC,UAAU,CAAC;IAChD,GAAG,EAAE,IAAI,sBAAsB,CAAC,KAAK,CAAC;IACtC,OAAO,EAAE,IAAI,sBAAsB,CAAC,SAAS,CAAC;CAC9C,CAAC;AAEF,MAAM,UAAU,uBAAuB,CAAC,GAAuB;IAC9D,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,OAAO,4BAA4B,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,YAA+B;IACpF,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAExB,IAAI,YAAY,EAAE,CAAC;QAClB,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;YAChC,IAAI,uBAAuB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClC,OAAO,IAAI,sBAAsB,CAAC,QAAQ,CAAC,CAAC;YAC7C,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,IAAI,sBAAsB,CAAC,QAAQ,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,wBAAwB;IACvC,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;SAC7B,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,iBAAiB,CAAC;SAClD,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC","sourcesContent":["/**\n * Provider discovery adapters for runtime model enumeration.\n * Each adapter implements ProviderDiscoveryAdapter to fetch models from provider APIs.\n */\n\nexport interface DiscoveredModel {\n\tid: string;\n\tname?: string;\n\tcontextWindow?: number;\n\tmaxTokens?: number;\n\treasoning?: boolean;\n\tinput?: (\"text\" | \"image\")[];\n\tcost?: { input: number; output: number; cacheRead: number; cacheWrite: number };\n}\n\nexport interface DiscoveryResult {\n\tprovider: string;\n\tmodels: DiscoveredModel[];\n\tfetchedAt: number;\n\terror?: string;\n}\n\nexport interface ProviderDiscoveryAdapter {\n\tprovider: string;\n\tsupportsDiscovery: boolean;\n\tfetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]>;\n}\n\nexport const OPENAI_COMPAT_DISCOVERY_APIS = new Set([\n\t\"openai\",\n\t\"openai-completions\",\n\t\"openai-responses\",\n\t\"openai-codex-responses\",\n\t\"azure-openai-responses\",\n]);\n\n/** Per-provider TTLs in milliseconds */\nexport const DISCOVERY_TTLS: Record<string, number> = {\n\tollama: 5 * 60 * 1000, // 5 minutes (local, models change often)\n\topenai: 60 * 60 * 1000, // 1 hour\n\tgoogle: 60 * 60 * 1000, // 1 hour\n\topenrouter: 60 * 60 * 1000, // 1 hour\n\tdefault: 24 * 60 * 60 * 1000, // 24 hours\n};\n\nexport function getDefaultTTL(provider: string): number {\n\treturn DISCOVERY_TTLS[provider] ?? DISCOVERY_TTLS.default;\n}\n\nasync function fetchWithTimeout(url: string, options: RequestInit = {}, timeoutMs = 5000): Promise<Response> {\n\tconst controller = new AbortController();\n\tconst timeout = setTimeout(() => controller.abort(), timeoutMs);\n\ttry {\n\t\treturn await fetch(url, { ...options, signal: controller.signal });\n\t} finally {\n\t\tclearTimeout(timeout);\n\t}\n}\n\n// ─── OpenAI Adapter ──────────────────────────────────────────────────────────\n\nconst OPENAI_EXCLUDED_PREFIXES = [\"embedding\", \"tts\", \"dall-e\", \"whisper\", \"text-embedding\", \"davinci\", \"babbage\"];\n\nfunction asPositiveNumber(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value) && value > 0) return value;\n\tif (typeof value === \"string\") {\n\t\tconst n = Number.parseFloat(value);\n\t\tif (Number.isFinite(n) && n > 0) return n;\n\t}\n\treturn undefined;\n}\n\nfunction pickFirstPositiveNumber(record: Record<string, unknown>, keys: string[]): number | undefined {\n\tfor (const key of keys) {\n\t\tconst value = asPositiveNumber(record[key]);\n\t\tif (value !== undefined) return value;\n\t}\n\treturn undefined;\n}\n\nfunction discoverInputModalities(rawModel: Record<string, unknown>, id: string): Array<\"text\" | \"image\"> {\n\tconst directModalities = rawModel.input_modalities;\n\tconst capabilitiesModalities = (rawModel.capabilities as Record<string, unknown> | undefined)?.input_modalities;\n\tconst source = Array.isArray(directModalities)\n\t\t? directModalities\n\t\t: Array.isArray(capabilitiesModalities)\n\t\t\t? capabilitiesModalities\n\t\t\t: [];\n\tconst supportsImage = source.some((m) => typeof m === \"string\" && /image|vision/i.test(m))\n\t\t|| /vision|image|omni|multimodal/i.test(id);\n\treturn supportsImage ? [\"text\", \"image\"] : [\"text\"];\n}\n\nfunction parseOpenAICompatibleModel(rawModel: Record<string, unknown>): DiscoveredModel | undefined {\n\tconst id = typeof rawModel.id === \"string\" ? rawModel.id : \"\";\n\tif (!id) return undefined;\n\tif (OPENAI_EXCLUDED_PREFIXES.some((prefix) => id.startsWith(prefix))) return undefined;\n\n\tconst contextWindow = pickFirstPositiveNumber(rawModel, [\n\t\t\"context_window\",\n\t\t\"context_length\",\n\t\t\"max_context_length\",\n\t\t\"max_input_tokens\",\n\t\t\"input_token_limit\",\n\t\t\"max_model_len\",\n\t]);\n\tconst maxTokens = pickFirstPositiveNumber(rawModel, [\n\t\t\"max_output_tokens\",\n\t\t\"output_token_limit\",\n\t\t\"max_completion_tokens\",\n\t\t\"max_tokens\",\n\t]);\n\tconst reasoning = rawModel.reasoning === true\n\t\t|| rawModel.supports_reasoning === true\n\t\t|| ((rawModel.capabilities as Record<string, unknown> | undefined)?.reasoning === true);\n\n\treturn {\n\t\tid,\n\t\tname: typeof rawModel.name === \"string\" && rawModel.name.length > 0 ? rawModel.name : id,\n\t\tcontextWindow,\n\t\tmaxTokens,\n\t\treasoning,\n\t\tinput: discoverInputModalities(rawModel, id),\n\t};\n}\n\nclass OpenAIDiscoveryAdapter implements ProviderDiscoveryAdapter {\n\tprovider: string;\n\tsupportsDiscovery = true;\n\n\tconstructor(provider: string) {\n\t\tthis.provider = provider;\n\t}\n\n\tasync fetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]> {\n\t\tconst url = `${baseUrl ?? \"https://api.openai.com\"}/v1/models`;\n\t\tconst response = await fetchWithTimeout(url, {\n\t\t\theaders: { Authorization: `Bearer ${apiKey}` },\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`OpenAI models API returned ${response.status}: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as { data?: Array<Record<string, unknown>> };\n\t\treturn (data.data ?? [])\n\t\t\t.map((m) => parseOpenAICompatibleModel(m))\n\t\t\t.filter((m): m is DiscoveredModel => !!m);\n\t}\n}\n\n// ─── Ollama Adapter ──────────────────────────────────────────────────────────\n\nclass OllamaDiscoveryAdapter implements ProviderDiscoveryAdapter {\n\tprovider = \"ollama\";\n\tsupportsDiscovery = true;\n\n\tasync fetchModels(_apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]> {\n\t\tconst url = `${baseUrl ?? \"http://localhost:11434\"}/api/tags`;\n\t\tconst response = await fetchWithTimeout(url);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Ollama tags API returned ${response.status}: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as {\n\t\t\tmodels: Array<{ name: string; size: number; details?: { parameter_size?: string } }>;\n\t\t};\n\n\t\treturn (data.models ?? []).map((m) => ({\n\t\t\tid: m.name,\n\t\t\tname: m.name,\n\t\t\tinput: [\"text\" as const],\n\t\t}));\n\t}\n}\n\n// ─── OpenRouter Adapter ──────────────────────────────────────────────────────\n\nclass OpenRouterDiscoveryAdapter implements ProviderDiscoveryAdapter {\n\tprovider = \"openrouter\";\n\tsupportsDiscovery = true;\n\n\tasync fetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]> {\n\t\tconst url = `${baseUrl ?? \"https://openrouter.ai\"}/api/v1/models`;\n\t\tconst response = await fetchWithTimeout(url, {\n\t\t\theaders: { Authorization: `Bearer ${apiKey}` },\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`OpenRouter models API returned ${response.status}: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as {\n\t\t\tdata: Array<{\n\t\t\t\tid: string;\n\t\t\t\tname: string;\n\t\t\t\tcontext_length?: number;\n\t\t\t\ttop_provider?: { max_completion_tokens?: number };\n\t\t\t\tpricing?: { prompt: string; completion: string };\n\t\t\t}>;\n\t\t};\n\n\t\treturn (data.data ?? []).map((m) => {\n\t\t\tconst cost =\n\t\t\t\tm.pricing?.prompt !== undefined && m.pricing?.completion !== undefined\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tinput: parseFloat(m.pricing.prompt) * 1_000_000,\n\t\t\t\t\t\t\toutput: parseFloat(m.pricing.completion) * 1_000_000,\n\t\t\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined;\n\n\t\t\treturn {\n\t\t\t\tid: m.id,\n\t\t\t\tname: m.name,\n\t\t\t\tcontextWindow: m.context_length,\n\t\t\t\tmaxTokens: m.top_provider?.max_completion_tokens,\n\t\t\t\tcost,\n\t\t\t\tinput: [\"text\" as const, \"image\" as const],\n\t\t\t};\n\t\t});\n\t}\n}\n\n// ─── Google/Gemini Adapter ───────────────────────────────────────────────────\n\nclass GoogleDiscoveryAdapter implements ProviderDiscoveryAdapter {\n\tprovider = \"google\";\n\tsupportsDiscovery = true;\n\n\tasync fetchModels(apiKey: string, baseUrl?: string): Promise<DiscoveredModel[]> {\n\t\tconst url = `${baseUrl ?? \"https://generativelanguage.googleapis.com\"}/v1beta/models?key=${apiKey}`;\n\t\tconst response = await fetchWithTimeout(url);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Google models API returned ${response.status}: ${response.statusText}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as {\n\t\t\tmodels: Array<{\n\t\t\t\tname: string;\n\t\t\t\tdisplayName: string;\n\t\t\t\tsupportedGenerationMethods?: string[];\n\t\t\t\tinputTokenLimit?: number;\n\t\t\t\toutputTokenLimit?: number;\n\t\t\t}>;\n\t\t};\n\n\t\treturn (data.models ?? [])\n\t\t\t.filter((m) => m.supportedGenerationMethods?.includes(\"generateContent\"))\n\t\t\t.map((m) => ({\n\t\t\t\tid: m.name.replace(\"models/\", \"\"),\n\t\t\t\tname: m.displayName,\n\t\t\t\tcontextWindow: m.inputTokenLimit,\n\t\t\t\tmaxTokens: m.outputTokenLimit,\n\t\t\t\tinput: [\"text\" as const, \"image\" as const],\n\t\t\t}));\n\t}\n}\n\n// ─── Static Adapter (no discovery) ───────────────────────────────────────────\n\nclass StaticDiscoveryAdapter implements ProviderDiscoveryAdapter {\n\tprovider: string;\n\tsupportsDiscovery = false;\n\n\tconstructor(provider: string) {\n\t\tthis.provider = provider;\n\t}\n\n\tasync fetchModels(): Promise<DiscoveredModel[]> {\n\t\treturn [];\n\t}\n}\n\n// ─── Registry ────────────────────────────────────────────────────────────────\n\nconst adapters: Record<string, ProviderDiscoveryAdapter> = {\n\topenai: new OpenAIDiscoveryAdapter(\"openai\"),\n\tollama: new OllamaDiscoveryAdapter(),\n\topenrouter: new OpenRouterDiscoveryAdapter(),\n\tgoogle: new GoogleDiscoveryAdapter(),\n\tanthropic: new StaticDiscoveryAdapter(\"anthropic\"),\n\tbedrock: new StaticDiscoveryAdapter(\"bedrock\"),\n\t\"azure-openai\": new StaticDiscoveryAdapter(\"azure-openai\"),\n\tgroq: new StaticDiscoveryAdapter(\"groq\"),\n\tcerebras: new StaticDiscoveryAdapter(\"cerebras\"),\n\txai: new StaticDiscoveryAdapter(\"xai\"),\n\tmistral: new StaticDiscoveryAdapter(\"mistral\"),\n};\n\nexport function supportsDiscoveryForApi(api: string | undefined): boolean {\n\tif (!api) return false;\n\treturn OPENAI_COMPAT_DISCOVERY_APIS.has(api);\n}\n\nexport function getDiscoveryAdapter(provider: string, providerApis?: Iterable<string>): ProviderDiscoveryAdapter {\n\tconst known = adapters[provider];\n\tif (known) return known;\n\n\tif (providerApis) {\n\t\tfor (const api of providerApis) {\n\t\t\tif (supportsDiscoveryForApi(api)) {\n\t\t\t\treturn new OpenAIDiscoveryAdapter(provider);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn new StaticDiscoveryAdapter(provider);\n}\n\nexport function getDiscoverableProviders(): string[] {\n\treturn Object.entries(adapters)\n\t\t.filter(([, adapter]) => adapter.supportsDiscovery)\n\t\t.map(([name]) => name);\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { describe, it } from "node:test";
|
|
3
|
-
import { DISCOVERY_TTLS, getDefaultTTL, getDiscoverableProviders, getDiscoveryAdapter, } from "./model-discovery.js";
|
|
3
|
+
import { DISCOVERY_TTLS, getDefaultTTL, getDiscoverableProviders, getDiscoveryAdapter, supportsDiscoveryForApi, } from "./model-discovery.js";
|
|
4
4
|
// ─── getDiscoveryAdapter ─────────────────────────────────────────────────────
|
|
5
5
|
describe("getDiscoveryAdapter", () => {
|
|
6
6
|
it("returns an adapter for openai", () => {
|
|
@@ -38,6 +38,11 @@ describe("getDiscoveryAdapter", () => {
|
|
|
38
38
|
assert.equal(adapter.provider, "unknown-provider");
|
|
39
39
|
assert.equal(adapter.supportsDiscovery, false);
|
|
40
40
|
});
|
|
41
|
+
it("returns OpenAI-style adapter for unknown provider with OpenAI-compatible API", () => {
|
|
42
|
+
const adapter = getDiscoveryAdapter("my-proxy", ["openai-completions"]);
|
|
43
|
+
assert.equal(adapter.provider, "my-proxy");
|
|
44
|
+
assert.equal(adapter.supportsDiscovery, true);
|
|
45
|
+
});
|
|
41
46
|
it("static adapter fetchModels returns empty array", async () => {
|
|
42
47
|
const adapter = getDiscoveryAdapter("anthropic");
|
|
43
48
|
const models = await adapter.fetchModels("key");
|
|
@@ -97,4 +102,14 @@ describe("DISCOVERY_TTLS", () => {
|
|
|
97
102
|
}
|
|
98
103
|
});
|
|
99
104
|
});
|
|
105
|
+
describe("supportsDiscoveryForApi", () => {
|
|
106
|
+
it("returns true for OpenAI-compatible APIs", () => {
|
|
107
|
+
assert.equal(supportsDiscoveryForApi("openai-completions"), true);
|
|
108
|
+
assert.equal(supportsDiscoveryForApi("openai-responses"), true);
|
|
109
|
+
});
|
|
110
|
+
it("returns false for non-discoverable APIs", () => {
|
|
111
|
+
assert.equal(supportsDiscoveryForApi("anthropic-messages"), false);
|
|
112
|
+
assert.equal(supportsDiscoveryForApi(undefined), false);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
100
115
|
//# sourceMappingURL=model-discovery.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-discovery.test.js","sourceRoot":"","sources":["../../src/core/model-discovery.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport { describe, it } from \"node:test\";\nimport {\n\tDISCOVERY_TTLS,\n\tgetDefaultTTL,\n\tgetDiscoverableProviders,\n\tgetDiscoveryAdapter,\n} from \"./model-discovery.js\";\n\n// ─── getDiscoveryAdapter ─────────────────────────────────────────────────────\n\ndescribe(\"getDiscoveryAdapter\", () => {\n\tit(\"returns an adapter for openai\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"openai\");\n\t\tassert.equal(adapter.provider, \"openai\");\n\t\tassert.equal(adapter.supportsDiscovery, true);\n\t});\n\n\tit(\"returns an adapter for ollama\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"ollama\");\n\t\tassert.equal(adapter.provider, \"ollama\");\n\t\tassert.equal(adapter.supportsDiscovery, true);\n\t});\n\n\tit(\"returns an adapter for openrouter\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"openrouter\");\n\t\tassert.equal(adapter.provider, \"openrouter\");\n\t\tassert.equal(adapter.supportsDiscovery, true);\n\t});\n\n\tit(\"returns an adapter for google\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"google\");\n\t\tassert.equal(adapter.provider, \"google\");\n\t\tassert.equal(adapter.supportsDiscovery, true);\n\t});\n\n\tit(\"returns a static adapter for anthropic\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"anthropic\");\n\t\tassert.equal(adapter.provider, \"anthropic\");\n\t\tassert.equal(adapter.supportsDiscovery, false);\n\t});\n\n\tit(\"returns a static adapter for bedrock\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"bedrock\");\n\t\tassert.equal(adapter.provider, \"bedrock\");\n\t\tassert.equal(adapter.supportsDiscovery, false);\n\t});\n\n\tit(\"returns a static adapter for unknown providers\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"unknown-provider\");\n\t\tassert.equal(adapter.provider, \"unknown-provider\");\n\t\tassert.equal(adapter.supportsDiscovery, false);\n\t});\n\n\tit(\"static adapter fetchModels returns empty array\", async () => {\n\t\tconst adapter = getDiscoveryAdapter(\"anthropic\");\n\t\tconst models = await adapter.fetchModels(\"key\");\n\t\tassert.deepEqual(models, []);\n\t});\n});\n\n// ─── getDiscoverableProviders ────────────────────────────────────────────────\n\ndescribe(\"getDiscoverableProviders\", () => {\n\tit(\"returns only providers that support discovery\", () => {\n\t\tconst providers = getDiscoverableProviders();\n\t\tassert.ok(providers.includes(\"openai\"));\n\t\tassert.ok(providers.includes(\"ollama\"));\n\t\tassert.ok(providers.includes(\"openrouter\"));\n\t\tassert.ok(providers.includes(\"google\"));\n\t\tassert.ok(!providers.includes(\"anthropic\"));\n\t\tassert.ok(!providers.includes(\"bedrock\"));\n\t});\n\n\tit(\"returns an array of strings\", () => {\n\t\tconst providers = getDiscoverableProviders();\n\t\tassert.ok(Array.isArray(providers));\n\t\tfor (const p of providers) {\n\t\t\tassert.equal(typeof p, \"string\");\n\t\t}\n\t});\n});\n\n// ─── getDefaultTTL ───────────────────────────────────────────────────────────\n\ndescribe(\"getDefaultTTL\", () => {\n\tit(\"returns 5 minutes for ollama\", () => {\n\t\tassert.equal(getDefaultTTL(\"ollama\"), 5 * 60 * 1000);\n\t});\n\n\tit(\"returns 1 hour for openai\", () => {\n\t\tassert.equal(getDefaultTTL(\"openai\"), 60 * 60 * 1000);\n\t});\n\n\tit(\"returns 1 hour for google\", () => {\n\t\tassert.equal(getDefaultTTL(\"google\"), 60 * 60 * 1000);\n\t});\n\n\tit(\"returns 1 hour for openrouter\", () => {\n\t\tassert.equal(getDefaultTTL(\"openrouter\"), 60 * 60 * 1000);\n\t});\n\n\tit(\"returns 24 hours for unknown providers\", () => {\n\t\tassert.equal(getDefaultTTL(\"some-custom\"), 24 * 60 * 60 * 1000);\n\t});\n});\n\n// ─── DISCOVERY_TTLS ──────────────────────────────────────────────────────────\n\ndescribe(\"DISCOVERY_TTLS\", () => {\n\tit(\"has expected keys\", () => {\n\t\tassert.ok(\"ollama\" in DISCOVERY_TTLS);\n\t\tassert.ok(\"openai\" in DISCOVERY_TTLS);\n\t\tassert.ok(\"google\" in DISCOVERY_TTLS);\n\t\tassert.ok(\"openrouter\" in DISCOVERY_TTLS);\n\t\tassert.ok(\"default\" in DISCOVERY_TTLS);\n\t});\n\n\tit(\"all values are positive numbers\", () => {\n\t\tfor (const [, value] of Object.entries(DISCOVERY_TTLS)) {\n\t\t\tassert.equal(typeof value, \"number\");\n\t\t\tassert.ok(value > 0);\n\t\t}\n\t});\n});\n"]}
|
|
1
|
+
{"version":3,"file":"model-discovery.test.js","sourceRoot":"","sources":["../../src/core/model-discovery.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport { describe, it } from \"node:test\";\nimport {\n\tDISCOVERY_TTLS,\n\tgetDefaultTTL,\n\tgetDiscoverableProviders,\n\tgetDiscoveryAdapter,\n\tsupportsDiscoveryForApi,\n} from \"./model-discovery.js\";\n\n// ─── getDiscoveryAdapter ─────────────────────────────────────────────────────\n\ndescribe(\"getDiscoveryAdapter\", () => {\n\tit(\"returns an adapter for openai\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"openai\");\n\t\tassert.equal(adapter.provider, \"openai\");\n\t\tassert.equal(adapter.supportsDiscovery, true);\n\t});\n\n\tit(\"returns an adapter for ollama\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"ollama\");\n\t\tassert.equal(adapter.provider, \"ollama\");\n\t\tassert.equal(adapter.supportsDiscovery, true);\n\t});\n\n\tit(\"returns an adapter for openrouter\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"openrouter\");\n\t\tassert.equal(adapter.provider, \"openrouter\");\n\t\tassert.equal(adapter.supportsDiscovery, true);\n\t});\n\n\tit(\"returns an adapter for google\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"google\");\n\t\tassert.equal(adapter.provider, \"google\");\n\t\tassert.equal(adapter.supportsDiscovery, true);\n\t});\n\n\tit(\"returns a static adapter for anthropic\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"anthropic\");\n\t\tassert.equal(adapter.provider, \"anthropic\");\n\t\tassert.equal(adapter.supportsDiscovery, false);\n\t});\n\n\tit(\"returns a static adapter for bedrock\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"bedrock\");\n\t\tassert.equal(adapter.provider, \"bedrock\");\n\t\tassert.equal(adapter.supportsDiscovery, false);\n\t});\n\n\tit(\"returns a static adapter for unknown providers\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"unknown-provider\");\n\t\tassert.equal(adapter.provider, \"unknown-provider\");\n\t\tassert.equal(adapter.supportsDiscovery, false);\n\t});\n\n\tit(\"returns OpenAI-style adapter for unknown provider with OpenAI-compatible API\", () => {\n\t\tconst adapter = getDiscoveryAdapter(\"my-proxy\", [\"openai-completions\"]);\n\t\tassert.equal(adapter.provider, \"my-proxy\");\n\t\tassert.equal(adapter.supportsDiscovery, true);\n\t});\n\n\tit(\"static adapter fetchModels returns empty array\", async () => {\n\t\tconst adapter = getDiscoveryAdapter(\"anthropic\");\n\t\tconst models = await adapter.fetchModels(\"key\");\n\t\tassert.deepEqual(models, []);\n\t});\n});\n\n// ─── getDiscoverableProviders ────────────────────────────────────────────────\n\ndescribe(\"getDiscoverableProviders\", () => {\n\tit(\"returns only providers that support discovery\", () => {\n\t\tconst providers = getDiscoverableProviders();\n\t\tassert.ok(providers.includes(\"openai\"));\n\t\tassert.ok(providers.includes(\"ollama\"));\n\t\tassert.ok(providers.includes(\"openrouter\"));\n\t\tassert.ok(providers.includes(\"google\"));\n\t\tassert.ok(!providers.includes(\"anthropic\"));\n\t\tassert.ok(!providers.includes(\"bedrock\"));\n\t});\n\n\tit(\"returns an array of strings\", () => {\n\t\tconst providers = getDiscoverableProviders();\n\t\tassert.ok(Array.isArray(providers));\n\t\tfor (const p of providers) {\n\t\t\tassert.equal(typeof p, \"string\");\n\t\t}\n\t});\n});\n\n// ─── getDefaultTTL ───────────────────────────────────────────────────────────\n\ndescribe(\"getDefaultTTL\", () => {\n\tit(\"returns 5 minutes for ollama\", () => {\n\t\tassert.equal(getDefaultTTL(\"ollama\"), 5 * 60 * 1000);\n\t});\n\n\tit(\"returns 1 hour for openai\", () => {\n\t\tassert.equal(getDefaultTTL(\"openai\"), 60 * 60 * 1000);\n\t});\n\n\tit(\"returns 1 hour for google\", () => {\n\t\tassert.equal(getDefaultTTL(\"google\"), 60 * 60 * 1000);\n\t});\n\n\tit(\"returns 1 hour for openrouter\", () => {\n\t\tassert.equal(getDefaultTTL(\"openrouter\"), 60 * 60 * 1000);\n\t});\n\n\tit(\"returns 24 hours for unknown providers\", () => {\n\t\tassert.equal(getDefaultTTL(\"some-custom\"), 24 * 60 * 60 * 1000);\n\t});\n});\n\n// ─── DISCOVERY_TTLS ──────────────────────────────────────────────────────────\n\ndescribe(\"DISCOVERY_TTLS\", () => {\n\tit(\"has expected keys\", () => {\n\t\tassert.ok(\"ollama\" in DISCOVERY_TTLS);\n\t\tassert.ok(\"openai\" in DISCOVERY_TTLS);\n\t\tassert.ok(\"google\" in DISCOVERY_TTLS);\n\t\tassert.ok(\"openrouter\" in DISCOVERY_TTLS);\n\t\tassert.ok(\"default\" in DISCOVERY_TTLS);\n\t});\n\n\tit(\"all values are positive numbers\", () => {\n\t\tfor (const [, value] of Object.entries(DISCOVERY_TTLS)) {\n\t\t\tassert.equal(typeof value, \"number\");\n\t\t\tassert.ok(value > 0);\n\t\t}\n\t});\n});\n\ndescribe(\"supportsDiscoveryForApi\", () => {\n\tit(\"returns true for OpenAI-compatible APIs\", () => {\n\t\tassert.equal(supportsDiscoveryForApi(\"openai-completions\"), true);\n\t\tassert.equal(supportsDiscoveryForApi(\"openai-responses\"), true);\n\t});\n\n\tit(\"returns false for non-discoverable APIs\", () => {\n\t\tassert.equal(supportsDiscoveryForApi(\"anthropic-messages\"), false);\n\t\tassert.equal(supportsDiscoveryForApi(undefined), false);\n\t});\n});\n"]}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdirSync, rmSync } from "node:fs";
|
|
2
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
6
6
|
import { AuthStorage } from "./auth-storage.js";
|
|
7
7
|
import { ModelDiscoveryCache } from "./discovery-cache.js";
|
|
8
8
|
import { getDefaultTTL, getDiscoverableProviders, getDiscoveryAdapter } from "./model-discovery.js";
|
|
9
|
+
import { ModelRegistry } from "./model-registry.js";
|
|
9
10
|
let testDir;
|
|
10
11
|
beforeEach(() => {
|
|
11
12
|
testDir = join(tmpdir(), `model-registry-discovery-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
@@ -110,4 +111,63 @@ describe("Discovery TTL configuration", () => {
|
|
|
110
111
|
assert.equal(customTTL, defaultTTL);
|
|
111
112
|
});
|
|
112
113
|
});
|
|
114
|
+
describe("ModelRegistry discovery — OpenAI-compatible custom providers", () => {
|
|
115
|
+
it("discovers custom OpenAI-compatible providers and maps capability metadata", async () => {
|
|
116
|
+
const providerName = `minimax-openai-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
117
|
+
const modelsPath = join(testDir, "models.json");
|
|
118
|
+
writeFileSync(modelsPath, JSON.stringify({
|
|
119
|
+
providers: {
|
|
120
|
+
[providerName]: {
|
|
121
|
+
baseUrl: "https://api.minimax.example",
|
|
122
|
+
apiKey: "minimax-test-key",
|
|
123
|
+
api: "openai-completions",
|
|
124
|
+
models: [{ id: "bootstrap-model" }],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
}, null, 2), "utf-8");
|
|
128
|
+
const prevFetch = globalThis.fetch;
|
|
129
|
+
let requestedUrl = "";
|
|
130
|
+
globalThis.fetch = (async (input) => {
|
|
131
|
+
requestedUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
132
|
+
return new Response(JSON.stringify({
|
|
133
|
+
data: [
|
|
134
|
+
{
|
|
135
|
+
id: "MiniMax-M2.7-highspeed",
|
|
136
|
+
name: "MiniMax M2.7 Highspeed",
|
|
137
|
+
context_window: 165000,
|
|
138
|
+
max_output_tokens: 32768,
|
|
139
|
+
supports_reasoning: true,
|
|
140
|
+
input_modalities: ["text", "image"],
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
}), {
|
|
144
|
+
status: 200,
|
|
145
|
+
headers: { "content-type": "application/json" },
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
try {
|
|
149
|
+
const registry = new ModelRegistry(AuthStorage.inMemory({}), modelsPath);
|
|
150
|
+
// Guard against global cache leakage from prior test runs.
|
|
151
|
+
registry.getDiscoveryCache().clear(providerName);
|
|
152
|
+
const results = await registry.discoverModels([providerName]);
|
|
153
|
+
const discovery = results.find((r) => r.provider === providerName);
|
|
154
|
+
assert.ok(discovery, "discovery result should include custom provider");
|
|
155
|
+
assert.equal(discovery?.error, undefined, "custom provider discovery should succeed");
|
|
156
|
+
assert.equal(requestedUrl, "https://api.minimax.example/v1/models");
|
|
157
|
+
const discovered = registry
|
|
158
|
+
.getAllWithDiscovered()
|
|
159
|
+
.find((m) => m.provider === providerName && m.id === "MiniMax-M2.7-highspeed");
|
|
160
|
+
assert.ok(discovered, "discovered model should be merged into model list");
|
|
161
|
+
assert.equal(discovered?.api, "openai-completions");
|
|
162
|
+
assert.equal(discovered?.baseUrl, "https://api.minimax.example");
|
|
163
|
+
assert.equal(discovered?.contextWindow, 165000);
|
|
164
|
+
assert.equal(discovered?.maxTokens, 32768);
|
|
165
|
+
assert.equal(discovered?.reasoning, true);
|
|
166
|
+
assert.deepEqual(discovered?.input, ["text", "image"]);
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
globalThis.fetch = prevFetch;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
});
|
|
113
173
|
//# sourceMappingURL=model-registry-discovery.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-registry-discovery.test.js","sourceRoot":"","sources":["../../src/core/model-registry-discovery.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport { mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { afterEach, beforeEach, describe, it } from \"node:test\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport { ModelDiscoveryCache } from \"./discovery-cache.js\";\nimport { getDefaultTTL, getDiscoverableProviders, getDiscoveryAdapter } from \"./model-discovery.js\";\n\nlet testDir: string;\n\nbeforeEach(() => {\n\ttestDir = join(tmpdir(), `model-registry-discovery-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);\n\tmkdirSync(testDir, { recursive: true });\n});\n\nafterEach(() => {\n\ttry {\n\t\trmSync(testDir, { recursive: true, force: true });\n\t} catch {\n\t\t// Cleanup best-effort\n\t}\n});\n\n// ─── discovery cache integration ─────────────────────────────────────────────\n\ndescribe(\"ModelDiscoveryCache — integration with discovery\", () => {\n\tit(\"cache respects provider-specific TTLs\", () => {\n\t\tconst cachePath = join(testDir, \"cache.json\");\n\t\tconst cache = new ModelDiscoveryCache(cachePath);\n\n\t\tcache.set(\"ollama\", [{ id: \"llama2\" }]);\n\t\tconst entry = cache.get(\"ollama\");\n\t\tassert.ok(entry);\n\t\tassert.equal(entry.ttlMs, getDefaultTTL(\"ollama\"));\n\t});\n\n\tit(\"cache uses custom TTL when provided\", () => {\n\t\tconst cachePath = join(testDir, \"cache.json\");\n\t\tconst cache = new ModelDiscoveryCache(cachePath);\n\n\t\tcache.set(\"openai\", [{ id: \"gpt-4o\" }], 999);\n\t\tconst entry = cache.get(\"openai\");\n\t\tassert.ok(entry);\n\t\tassert.equal(entry.ttlMs, 999);\n\t});\n});\n\n// ─── adapter resolution ─────────────────────────────────────────────────────\n\ndescribe(\"Discovery adapter resolution\", () => {\n\tit(\"all discoverable providers have adapters\", () => {\n\t\tconst providers = getDiscoverableProviders();\n\t\tfor (const provider of providers) {\n\t\t\tconst adapter = getDiscoveryAdapter(provider);\n\t\t\tassert.equal(adapter.supportsDiscovery, true, `${provider} should support discovery`);\n\t\t}\n\t});\n\n\tit(\"static adapters return empty model lists\", async () => {\n\t\tconst staticProviders = [\"anthropic\", \"bedrock\", \"azure-openai\", \"groq\", \"cerebras\"];\n\t\tfor (const provider of staticProviders) {\n\t\t\tconst adapter = getDiscoveryAdapter(provider);\n\t\t\tassert.equal(adapter.supportsDiscovery, false, `${provider} should not support discovery`);\n\t\t\tconst models = await adapter.fetchModels(\"dummy-key\");\n\t\t\tassert.deepEqual(models, [], `${provider} should return empty models`);\n\t\t}\n\t});\n});\n\n// ─── AuthStorage hasAuth for discovery ───────────────────────────────────────\n\ndescribe(\"AuthStorage — hasAuth for discovery providers\", () => {\n\tit(\"returns false for providers without auth\", () => {\n\t\tconst storage = AuthStorage.inMemory({});\n\t\tassert.equal(storage.hasAuth(\"openai\"), false);\n\t\tassert.equal(storage.hasAuth(\"ollama\"), false);\n\t});\n\n\tit(\"returns true for providers with stored keys\", () => {\n\t\tconst storage = AuthStorage.inMemory({\n\t\t\topenai: { type: \"api_key\" as const, key: \"sk-test\" },\n\t\t});\n\t\tassert.equal(storage.hasAuth(\"openai\"), true);\n\t\tassert.equal(storage.hasAuth(\"ollama\"), false);\n\t});\n});\n\n// ─── cache persistence across instances ──────────────────────────────────────\n\ndescribe(\"ModelDiscoveryCache — persistence\", () => {\n\tit(\"data survives across cache instances\", () => {\n\t\tconst cachePath = join(testDir, \"persist.json\");\n\n\t\tconst cache1 = new ModelDiscoveryCache(cachePath);\n\t\tcache1.set(\"openai\", [\n\t\t\t{ id: \"gpt-4o\", name: \"GPT-4o\", contextWindow: 128000 },\n\t\t\t{ id: \"gpt-4o-mini\", name: \"GPT-4o Mini\" },\n\t\t]);\n\n\t\tconst cache2 = new ModelDiscoveryCache(cachePath);\n\t\tconst entry = cache2.get(\"openai\");\n\t\tassert.ok(entry);\n\t\tassert.equal(entry.models.length, 2);\n\t\tassert.equal(entry.models[0].contextWindow, 128000);\n\t});\n\n\tit(\"clear persists across instances\", () => {\n\t\tconst cachePath = join(testDir, \"clear.json\");\n\n\t\tconst cache1 = new ModelDiscoveryCache(cachePath);\n\t\tcache1.set(\"openai\", [{ id: \"gpt-4o\" }]);\n\t\tcache1.clear(\"openai\");\n\n\t\tconst cache2 = new ModelDiscoveryCache(cachePath);\n\t\tassert.equal(cache2.get(\"openai\"), undefined);\n\t});\n});\n\n// ─── discovery TTL values ────────────────────────────────────────────────────\n\ndescribe(\"Discovery TTL configuration\", () => {\n\tit(\"ollama has shortest TTL (local models change often)\", () => {\n\t\tconst ollamaTTL = getDefaultTTL(\"ollama\");\n\t\tconst openaiTTL = getDefaultTTL(\"openai\");\n\t\tassert.ok(ollamaTTL < openaiTTL, \"ollama TTL should be shorter than openai\");\n\t});\n\n\tit(\"unknown providers get default TTL\", () => {\n\t\tconst customTTL = getDefaultTTL(\"my-custom-provider\");\n\t\tconst defaultTTL = getDefaultTTL(\"default\");\n\t\t// Unknown providers should get the same TTL as the explicit \"default\" key\n\t\tassert.equal(customTTL, defaultTTL);\n\t});\n});\n"]}
|
|
1
|
+
{"version":3,"file":"model-registry-discovery.test.js","sourceRoot":"","sources":["../../src/core/model-registry-discovery.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport { mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { afterEach, beforeEach, describe, it } from \"node:test\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport { ModelDiscoveryCache } from \"./discovery-cache.js\";\nimport { getDefaultTTL, getDiscoverableProviders, getDiscoveryAdapter } from \"./model-discovery.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\n\nlet testDir: string;\n\nbeforeEach(() => {\n\ttestDir = join(tmpdir(), `model-registry-discovery-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);\n\tmkdirSync(testDir, { recursive: true });\n});\n\nafterEach(() => {\n\ttry {\n\t\trmSync(testDir, { recursive: true, force: true });\n\t} catch {\n\t\t// Cleanup best-effort\n\t}\n});\n\n// ─── discovery cache integration ─────────────────────────────────────────────\n\ndescribe(\"ModelDiscoveryCache — integration with discovery\", () => {\n\tit(\"cache respects provider-specific TTLs\", () => {\n\t\tconst cachePath = join(testDir, \"cache.json\");\n\t\tconst cache = new ModelDiscoveryCache(cachePath);\n\n\t\tcache.set(\"ollama\", [{ id: \"llama2\" }]);\n\t\tconst entry = cache.get(\"ollama\");\n\t\tassert.ok(entry);\n\t\tassert.equal(entry.ttlMs, getDefaultTTL(\"ollama\"));\n\t});\n\n\tit(\"cache uses custom TTL when provided\", () => {\n\t\tconst cachePath = join(testDir, \"cache.json\");\n\t\tconst cache = new ModelDiscoveryCache(cachePath);\n\n\t\tcache.set(\"openai\", [{ id: \"gpt-4o\" }], 999);\n\t\tconst entry = cache.get(\"openai\");\n\t\tassert.ok(entry);\n\t\tassert.equal(entry.ttlMs, 999);\n\t});\n});\n\n// ─── adapter resolution ─────────────────────────────────────────────────────\n\ndescribe(\"Discovery adapter resolution\", () => {\n\tit(\"all discoverable providers have adapters\", () => {\n\t\tconst providers = getDiscoverableProviders();\n\t\tfor (const provider of providers) {\n\t\t\tconst adapter = getDiscoveryAdapter(provider);\n\t\t\tassert.equal(adapter.supportsDiscovery, true, `${provider} should support discovery`);\n\t\t}\n\t});\n\n\tit(\"static adapters return empty model lists\", async () => {\n\t\tconst staticProviders = [\"anthropic\", \"bedrock\", \"azure-openai\", \"groq\", \"cerebras\"];\n\t\tfor (const provider of staticProviders) {\n\t\t\tconst adapter = getDiscoveryAdapter(provider);\n\t\t\tassert.equal(adapter.supportsDiscovery, false, `${provider} should not support discovery`);\n\t\t\tconst models = await adapter.fetchModels(\"dummy-key\");\n\t\t\tassert.deepEqual(models, [], `${provider} should return empty models`);\n\t\t}\n\t});\n});\n\n// ─── AuthStorage hasAuth for discovery ───────────────────────────────────────\n\ndescribe(\"AuthStorage — hasAuth for discovery providers\", () => {\n\tit(\"returns false for providers without auth\", () => {\n\t\tconst storage = AuthStorage.inMemory({});\n\t\tassert.equal(storage.hasAuth(\"openai\"), false);\n\t\tassert.equal(storage.hasAuth(\"ollama\"), false);\n\t});\n\n\tit(\"returns true for providers with stored keys\", () => {\n\t\tconst storage = AuthStorage.inMemory({\n\t\t\topenai: { type: \"api_key\" as const, key: \"sk-test\" },\n\t\t});\n\t\tassert.equal(storage.hasAuth(\"openai\"), true);\n\t\tassert.equal(storage.hasAuth(\"ollama\"), false);\n\t});\n});\n\n// ─── cache persistence across instances ──────────────────────────────────────\n\ndescribe(\"ModelDiscoveryCache — persistence\", () => {\n\tit(\"data survives across cache instances\", () => {\n\t\tconst cachePath = join(testDir, \"persist.json\");\n\n\t\tconst cache1 = new ModelDiscoveryCache(cachePath);\n\t\tcache1.set(\"openai\", [\n\t\t\t{ id: \"gpt-4o\", name: \"GPT-4o\", contextWindow: 128000 },\n\t\t\t{ id: \"gpt-4o-mini\", name: \"GPT-4o Mini\" },\n\t\t]);\n\n\t\tconst cache2 = new ModelDiscoveryCache(cachePath);\n\t\tconst entry = cache2.get(\"openai\");\n\t\tassert.ok(entry);\n\t\tassert.equal(entry.models.length, 2);\n\t\tassert.equal(entry.models[0].contextWindow, 128000);\n\t});\n\n\tit(\"clear persists across instances\", () => {\n\t\tconst cachePath = join(testDir, \"clear.json\");\n\n\t\tconst cache1 = new ModelDiscoveryCache(cachePath);\n\t\tcache1.set(\"openai\", [{ id: \"gpt-4o\" }]);\n\t\tcache1.clear(\"openai\");\n\n\t\tconst cache2 = new ModelDiscoveryCache(cachePath);\n\t\tassert.equal(cache2.get(\"openai\"), undefined);\n\t});\n});\n\n// ─── discovery TTL values ────────────────────────────────────────────────────\n\ndescribe(\"Discovery TTL configuration\", () => {\n\tit(\"ollama has shortest TTL (local models change often)\", () => {\n\t\tconst ollamaTTL = getDefaultTTL(\"ollama\");\n\t\tconst openaiTTL = getDefaultTTL(\"openai\");\n\t\tassert.ok(ollamaTTL < openaiTTL, \"ollama TTL should be shorter than openai\");\n\t});\n\n\tit(\"unknown providers get default TTL\", () => {\n\t\tconst customTTL = getDefaultTTL(\"my-custom-provider\");\n\t\tconst defaultTTL = getDefaultTTL(\"default\");\n\t\t// Unknown providers should get the same TTL as the explicit \"default\" key\n\t\tassert.equal(customTTL, defaultTTL);\n\t});\n});\n\ndescribe(\"ModelRegistry discovery — OpenAI-compatible custom providers\", () => {\n\tit(\"discovers custom OpenAI-compatible providers and maps capability metadata\", async () => {\n\t\tconst providerName = `minimax-openai-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\t\tconst modelsPath = join(testDir, \"models.json\");\n\t\twriteFileSync(\n\t\t\tmodelsPath,\n\t\t\tJSON.stringify(\n\t\t\t\t{\n\t\t\t\t\tproviders: {\n\t\t\t\t\t\t[providerName]: {\n\t\t\t\t\t\t\tbaseUrl: \"https://api.minimax.example\",\n\t\t\t\t\t\t\tapiKey: \"minimax-test-key\",\n\t\t\t\t\t\t\tapi: \"openai-completions\",\n\t\t\t\t\t\t\tmodels: [{ id: \"bootstrap-model\" }],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tnull,\n\t\t\t\t2,\n\t\t\t),\n\t\t\t\"utf-8\",\n\t\t);\n\n\t\tconst prevFetch = globalThis.fetch;\n\t\tlet requestedUrl = \"\";\n\t\tglobalThis.fetch = (async (input: string | URL | Request) => {\n\t\t\trequestedUrl = typeof input === \"string\" ? input : input instanceof URL ? input.toString() : input.url;\n\t\t\treturn new Response(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tdata: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"MiniMax-M2.7-highspeed\",\n\t\t\t\t\t\t\tname: \"MiniMax M2.7 Highspeed\",\n\t\t\t\t\t\t\tcontext_window: 165000,\n\t\t\t\t\t\t\tmax_output_tokens: 32768,\n\t\t\t\t\t\t\tsupports_reasoning: true,\n\t\t\t\t\t\t\tinput_modalities: [\"text\", \"image\"],\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t}),\n\t\t\t\t{\n\t\t\t\t\tstatus: 200,\n\t\t\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\t\t},\n\t\t\t);\n\t\t}) as typeof globalThis.fetch;\n\n\t\ttry {\n\t\t\tconst registry = new ModelRegistry(AuthStorage.inMemory({}), modelsPath);\n\t\t\t// Guard against global cache leakage from prior test runs.\n\t\t\tregistry.getDiscoveryCache().clear(providerName);\n\t\t\tconst results = await registry.discoverModels([providerName]);\n\n\t\t\tconst discovery = results.find((r) => r.provider === providerName);\n\t\t\tassert.ok(discovery, \"discovery result should include custom provider\");\n\t\t\tassert.equal(discovery?.error, undefined, \"custom provider discovery should succeed\");\n\t\t\tassert.equal(requestedUrl, \"https://api.minimax.example/v1/models\");\n\n\t\t\tconst discovered = registry\n\t\t\t\t.getAllWithDiscovered()\n\t\t\t\t.find((m) => m.provider === providerName && m.id === \"MiniMax-M2.7-highspeed\");\n\t\t\tassert.ok(discovered, \"discovered model should be merged into model list\");\n\t\t\tassert.equal(discovered?.api, \"openai-completions\");\n\t\t\tassert.equal(discovered?.baseUrl, \"https://api.minimax.example\");\n\t\t\tassert.equal(discovered?.contextWindow, 165000);\n\t\t\tassert.equal(discovered?.maxTokens, 32768);\n\t\t\tassert.equal(discovered?.reasoning, true);\n\t\t\tassert.deepEqual(discovered?.input, [\"text\", \"image\"]);\n\t\t} finally {\n\t\t\tglobalThis.fetch = prevFetch;\n\t\t}\n\t});\n});\n"]}
|
|
@@ -115,6 +115,11 @@ export declare class ModelRegistry {
|
|
|
115
115
|
* Convert DiscoveryResult[] into Model<Api>[] with default values.
|
|
116
116
|
*/
|
|
117
117
|
private convertDiscoveredModels;
|
|
118
|
+
private getProviderApis;
|
|
119
|
+
private getAutoDiscoverableProviders;
|
|
120
|
+
private getProviderBaseUrl;
|
|
121
|
+
private getDiscoveryProviderDefaults;
|
|
122
|
+
private getDiscoveryTtl;
|
|
118
123
|
/**
|
|
119
124
|
* Check if a model's baseUrl points to a local endpoint.
|
|
120
125
|
* Delegates to standalone isLocalModel() function.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-registry.d.ts","sourceRoot":"","sources":["../../src/core/model-registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACN,KAAK,GAAG,EAER,KAAK,2BAA2B,EAChC,KAAK,OAAO,EAMZ,KAAK,KAAK,EACV,KAAK,sBAAsB,EAK3B,KAAK,mBAAmB,EACxB,MAAM,YAAY,CAAC;AAOpB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAmB,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAwG7E,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,OAAO,GAAG,aAAa,GAAG,MAAM,CAAC;AA2F3E;;GAEG;AACH,qBAAa,aAAa;IASxB,QAAQ,CAAC,WAAW,EAAE,WAAW;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS;IAT5C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,qBAAqB,CAAkC;IAC/D,OAAO,CAAC,mBAAmB,CAA+C;IAC1E,OAAO,CAAC,SAAS,CAAiC;gBAGxC,WAAW,EAAE,WAAW,EACxB,cAAc,GAAE,MAAM,GAAG,SAA8C;IAoBjF;;OAEG;IACH,OAAO,IAAI,IAAI;IAef;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,OAAO,CAAC,UAAU;IA+BlB,8DAA8D;IAC9D,OAAO,CAAC,iBAAiB;IAiCzB,wFAAwF;IACxF,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,gBAAgB;IAuDxB,OAAO,CAAC,cAAc;IAyCtB,OAAO,CAAC,WAAW;IAiEnB;;;OAGG;IACH,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE;IAItB;;;OAGG;IACH,YAAY,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE;IAI5B;;;OAGG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB;IASvD;;OAEG;IACH,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQjD;;OAEG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS;IAI/D;;;;OAIG;IACG,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAMnF;;;;OAIG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAM7F;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO;IAKxC;;;;;;OAMG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI;IAKzE;;;;;;;;OAQG;IACH,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAO9C,OAAO,CAAC,mBAAmB;IA6J3B;;;OAGG;IACG,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"model-registry.d.ts","sourceRoot":"","sources":["../../src/core/model-registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACN,KAAK,GAAG,EAER,KAAK,2BAA2B,EAChC,KAAK,OAAO,EAMZ,KAAK,KAAK,EACV,KAAK,sBAAsB,EAK3B,KAAK,mBAAmB,EACxB,MAAM,YAAY,CAAC;AAOpB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAmB,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAwG7E,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,OAAO,GAAG,aAAa,GAAG,MAAM,CAAC;AA2F3E;;GAEG;AACH,qBAAa,aAAa;IASxB,QAAQ,CAAC,WAAW,EAAE,WAAW;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS;IAT5C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,qBAAqB,CAAkC;IAC/D,OAAO,CAAC,mBAAmB,CAA+C;IAC1E,OAAO,CAAC,SAAS,CAAiC;gBAGxC,WAAW,EAAE,WAAW,EACxB,cAAc,GAAE,MAAM,GAAG,SAA8C;IAoBjF;;OAEG;IACH,OAAO,IAAI,IAAI;IAef;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,OAAO,CAAC,UAAU;IA+BlB,8DAA8D;IAC9D,OAAO,CAAC,iBAAiB;IAiCzB,wFAAwF;IACxF,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,gBAAgB;IAuDxB,OAAO,CAAC,cAAc;IAyCtB,OAAO,CAAC,WAAW;IAiEnB;;;OAGG;IACH,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE;IAItB;;;OAGG;IACH,YAAY,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE;IAI5B;;;OAGG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB;IASvD;;OAEG;IACH,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQjD;;OAEG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS;IAI/D;;;;OAIG;IACG,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAMnF;;;;OAIG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAM7F;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO;IAKxC;;;;;;OAMG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI;IAKzE;;;;;;;;OAQG;IACH,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAO9C,OAAO,CAAC,mBAAmB;IA6J3B;;;OAGG;IACG,cAAc,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAkDtE;;;OAGG;IACH,oBAAoB,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE;IAMpC;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO;IAIxC;;OAEG;IACH,iBAAiB,IAAI,mBAAmB;IAIxC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAuB/B,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,4BAA4B;IAcpC,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,4BAA4B;IA2BpC,OAAO,CAAC,eAAe;IASvB;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO;IAI/C;;;;OAIG;IACH,eAAe,IAAI,OAAO;CAK1B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B;yGACqG;IACrG,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,KAAK,2BAA2B,CAAC;IACnH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wCAAwC;IACxC,KAAK,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;IAC3C,MAAM,CAAC,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,GAAG,CAAC;QACV,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,OAAO,CAAC;QACnB,KAAK,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;QAC5B,IAAI,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/E,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC9B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC1C,CAAC,CAAC;CACH"}
|