@ashx-j/lunr 0.2.13 → 0.2.14
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/CHANGELOG.md +10 -1
- package/README.md +6 -3
- package/dist/builtin-extensions/ashxj-tui.d.ts +16 -1
- package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.js +44 -20
- package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +2 -0
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +27 -22
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +5 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +12 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.js +3 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-append.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-append.js +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-append.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-root-attachment.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-root-attachment.js +3 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-root-attachment.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/fleet-view.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/fleet-view.js +3 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/background/fleet-view.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +3 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +7 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +2 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +19 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts +10 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +19 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts +2 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +17 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts +3 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js +14 -3
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +14 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/fleet.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/fleet.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/tui/fleet.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +12 -10
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/catalog/models.json +1 -1
- package/dist/catalog/providers/amazon-bedrock.json +1 -1
- package/dist/catalog/providers/anthropic.json +1 -1
- package/dist/catalog/providers/azure-openai-responses.json +1 -1
- package/dist/catalog/providers/cloudflare-ai-gateway.json +1 -1
- package/dist/catalog/providers/fireworks.json +1 -1
- package/dist/catalog/providers/github-copilot.json +1 -1
- package/dist/catalog/providers/google-vertex.json +1 -1
- package/dist/catalog/providers/google.json +1 -1
- package/dist/catalog/providers/groq.json +1 -1
- package/dist/catalog/providers/huggingface.json +1 -1
- package/dist/catalog/providers/nvidia.json +1 -1
- package/dist/catalog/providers/openai-codex.json +1 -1
- package/dist/catalog/providers/openai.json +1 -1
- package/dist/catalog/providers/opencode-go.json +1 -1
- package/dist/catalog/providers/opencode.json +1 -1
- package/dist/catalog/providers/openrouter.json +1 -1
- package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
- package/dist/catalog/publication.json +131 -3
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +1 -0
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +52 -27
- package/dist/cli.js.map +1 -1
- package/dist/core/catalog-cache-scope.d.ts +3 -0
- package/dist/core/catalog-cache-scope.d.ts.map +1 -0
- package/dist/core/catalog-cache-scope.js +12 -0
- package/dist/core/catalog-cache-scope.js.map +1 -0
- package/dist/core/catalog-merge.d.ts +2 -0
- package/dist/core/catalog-merge.d.ts.map +1 -1
- package/dist/core/catalog-merge.js +29 -2
- package/dist/core/catalog-merge.js.map +1 -1
- package/dist/core/catalog-refresh-polling.d.ts +8 -0
- package/dist/core/catalog-refresh-polling.d.ts.map +1 -0
- package/dist/core/catalog-refresh-polling.js +30 -0
- package/dist/core/catalog-refresh-polling.js.map +1 -0
- package/dist/core/codex-catalog.d.ts +3 -0
- package/dist/core/codex-catalog.d.ts.map +1 -0
- package/dist/core/codex-catalog.js +15 -0
- package/dist/core/codex-catalog.js.map +1 -0
- package/dist/core/customize.d.ts +2 -4
- package/dist/core/customize.d.ts.map +1 -1
- package/dist/core/customize.js +2 -8
- package/dist/core/customize.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +3 -4
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +54 -82
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/live-catalog.d.ts +5 -2
- package/dist/core/live-catalog.d.ts.map +1 -1
- package/dist/core/live-catalog.js +108 -27
- package/dist/core/live-catalog.js.map +1 -1
- package/dist/core/model-runtime.d.ts +8 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +64 -12
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/official-catalog.d.ts +4 -0
- package/dist/core/official-catalog.d.ts.map +1 -1
- package/dist/core/official-catalog.js +86 -21
- package/dist/core/official-catalog.js.map +1 -1
- package/dist/core/settings-manager.d.ts +0 -6
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +0 -17
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +106 -50
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +2 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +14 -4
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +1 -3
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +4 -32
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +2 -1
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +4 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/plan-message.d.ts +1 -3
- package/dist/modes/interactive/components/plan-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/plan-message.js +1 -16
- package/dist/modes/interactive/components/plan-message.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +0 -4
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -30
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +1 -3
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +2 -19
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +12 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +137 -127
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/moon.json +0 -1
- package/dist/modes/interactive/theme/theme-schema.json +3 -3
- package/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +95 -90
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/startup/interactive-view.d.ts +55 -0
- package/dist/startup/interactive-view.d.ts.map +1 -0
- package/dist/startup/interactive-view.js +332 -0
- package/dist/startup/interactive-view.js.map +1 -0
- package/dist/startup/launch-routing.d.ts +8 -0
- package/dist/startup/launch-routing.d.ts.map +1 -0
- package/dist/startup/launch-routing.js +29 -0
- package/dist/startup/launch-routing.js.map +1 -0
- package/dist/startup/startup-milestones.d.ts +4 -0
- package/dist/startup/startup-milestones.d.ts.map +1 -0
- package/dist/startup/startup-milestones.js +14 -0
- package/dist/startup/startup-milestones.js.map +1 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +10 -4
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/docs/features.md +2 -2
- package/docs/interactive-startup.md +58 -0
- package/docs/keybindings.md +1 -1
- package/docs/model-catalog.md +29 -0
- package/docs/quickstart.md +1 -1
- package/docs/settings.md +1 -3
- package/docs/terminal-setup.md +2 -2
- package/docs/usage.md +2 -1
- package/docs/windows.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +16 -16
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Api, type Credential, type Model } from "@ashx-j/lunr-ai";
|
|
2
2
|
export declare const LIVE_CATALOG_TIMEOUT_MS = 4000;
|
|
3
3
|
export declare const INCOMPLETE_PROMPT_CAP = 8;
|
|
4
4
|
export declare const DEFAULT_CONTEXT_WINDOW = 128000;
|
|
5
5
|
export declare const DEFAULT_MAX_TOKENS = 8192;
|
|
6
|
-
export declare const LIVE_LIST_PROVIDER_IDS: readonly ["xai", "openrouter", "qwen-cloud", "qwen-cloud-cn", "groq", "openai", "deepseek"];
|
|
6
|
+
export declare const LIVE_LIST_PROVIDER_IDS: readonly ["openai-codex", "xai", "openrouter", "qwen-cloud", "qwen-cloud-cn", "groq", "openai", "deepseek"];
|
|
7
7
|
export type LiveListProviderId = (typeof LIVE_LIST_PROVIDER_IDS)[number];
|
|
8
8
|
export declare function isLiveListProvider(providerId: string): providerId is LiveListProviderId;
|
|
9
9
|
export interface LiveFieldSupply {
|
|
@@ -28,6 +28,7 @@ export interface IncompleteLiveModel {
|
|
|
28
28
|
}
|
|
29
29
|
export type LiveCatalogStatus = "ok" | "timeout" | "error" | "skipped";
|
|
30
30
|
export interface LiveCatalogResult {
|
|
31
|
+
discoveryClientVersion?: string;
|
|
31
32
|
providerId: string;
|
|
32
33
|
status: LiveCatalogStatus;
|
|
33
34
|
discoveries: LiveModelDiscovery[];
|
|
@@ -41,6 +42,7 @@ export declare function credentialAuthHeaders(credential: Credential | undefined
|
|
|
41
42
|
/** OpenAI `{ data: [{ id, ... }] }` plus a bare array. */
|
|
42
43
|
export declare function parseOpenAIModelsList(value: unknown): Record<string, unknown>[];
|
|
43
44
|
export declare function firstBakedInModel(models: readonly Model<Api>[]): Model<Api> | undefined;
|
|
45
|
+
export declare function selectLiveTemplate(providerId: string, id: string, bakedIn: readonly Model<Api>[]): Model<Api> | undefined;
|
|
44
46
|
export declare function uniqueApis(models: readonly Model<Api>[]): Api[];
|
|
45
47
|
export declare function synthesizeLiveModel(id: string, template: Model<Api>, raw?: Record<string, unknown>): LiveModelDiscovery;
|
|
46
48
|
/** OpenRouter field mapping (tools filter, pricing × 1e6, context) from generate-models. */
|
|
@@ -61,6 +63,7 @@ export interface IncompleteModelAnswers {
|
|
|
61
63
|
}
|
|
62
64
|
export declare function applyIncompleteAnswers(draft: Model<Api>, answers: IncompleteModelAnswers): Model<Api>;
|
|
63
65
|
export interface FetchLiveProviderModelsOptions {
|
|
66
|
+
discoveryClientVersion?: string;
|
|
64
67
|
providerId: string;
|
|
65
68
|
baseUrl: string;
|
|
66
69
|
bakedIn: readonly Model<Api>[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-catalog.d.ts","sourceRoot":"","sources":["../../src/core/live-catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Api, Credential, Model } from \"@ashx-j/lunr-ai\";\nimport { VERSION } from \"../config.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\nimport { modelKey } from \"./official-catalog.ts\";\n\nexport const LIVE_CATALOG_TIMEOUT_MS = 4000;\nexport const INCOMPLETE_PROMPT_CAP = 8;\nexport const DEFAULT_CONTEXT_WINDOW = 128000;\nexport const DEFAULT_MAX_TOKENS = 8192;\n\nexport const LIVE_LIST_PROVIDER_IDS = [\n\t\"xai\",\n\t\"openrouter\",\n\t\"qwen-cloud\",\n\t\"qwen-cloud-cn\",\n\t\"groq\",\n\t\"openai\",\n\t\"deepseek\",\n] as const;\n\nexport type LiveListProviderId = (typeof LIVE_LIST_PROVIDER_IDS)[number];\n\nconst LIVE_LIST_PROVIDER_SET = new Set<string>(LIVE_LIST_PROVIDER_IDS);\n\nexport function isLiveListProvider(providerId: string): providerId is LiveListProviderId {\n\treturn LIVE_LIST_PROVIDER_SET.has(providerId);\n}\n\nexport interface LiveFieldSupply {\n\tcontextWindow: boolean;\n\tmaxTokens: boolean;\n\tinput: boolean;\n\tname: boolean;\n\tcost: boolean;\n\treasoning: boolean;\n}\n\nexport interface LiveModelDiscovery {\n\tmodel: Model<Api>;\n\tsupplied: LiveFieldSupply;\n}\n\nexport interface IncompleteLiveModel {\n\tprovider: string;\n\tid: string;\n\tname: string;\n\tmissing: Array<\"contextWindow\" | \"maxTokens\" | \"input\">;\n\tdraft: Model<Api>;\n\tavailableApis: Api[];\n}\n\nexport type LiveCatalogStatus = \"ok\" | \"timeout\" | \"error\" | \"skipped\";\n\nexport interface LiveCatalogResult {\n\tproviderId: string;\n\tstatus: LiveCatalogStatus;\n\tdiscoveries: LiveModelDiscovery[];\n\tadded: number;\n\ttotal: number;\n\tincomplete: IncompleteLiveModel[];\n\terror?: string;\n}\n\nconst ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\nconst NONE_SUPPLIED: LiveFieldSupply = {\n\tcontextWindow: false,\n\tmaxTokens: false,\n\tinput: false,\n\tname: false,\n\tcost: false,\n\treasoning: false,\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asFiniteNumber(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (typeof value === \"string\" && value.trim()) {\n\t\tconst parsed = Number(value);\n\t\tif (Number.isFinite(parsed)) return parsed;\n\t}\n\treturn undefined;\n}\n\nfunction roundCost(value: number): number {\n\treturn Number(value.toFixed(6));\n}\n\nexport function modelsListUrl(baseUrl: string): string {\n\treturn `${baseUrl.replace(/\\/+$/u, \"\")}/models`;\n}\n\nexport function credentialAuthHeaders(credential: Credential | undefined): Record<string, string> {\n\tif (!credential) return {};\n\tif (credential.type === \"api_key\" && credential.key) {\n\t\treturn { Authorization: `Bearer ${credential.key}` };\n\t}\n\tif (credential.type === \"oauth\" && typeof credential.access === \"string\" && credential.access) {\n\t\treturn { Authorization: `Bearer ${credential.access}` };\n\t}\n\treturn {};\n}\n\n/** OpenAI `{ data: [{ id, ... }] }` plus a bare array. */\nexport function parseOpenAIModelsList(value: unknown): Record<string, unknown>[] {\n\tconst entries = isRecord(value) && Array.isArray(value.data) ? value.data : Array.isArray(value) ? value : [];\n\tconst rows: Record<string, unknown>[] = [];\n\tfor (const entry of entries) {\n\t\tif (typeof entry === \"string\" && entry.trim()) {\n\t\t\trows.push({ id: entry.trim() });\n\t\t\tcontinue;\n\t\t}\n\t\tif (isRecord(entry) && typeof entry.id === \"string\" && entry.id.trim()) rows.push(entry);\n\t}\n\treturn rows;\n}\n\nexport function firstBakedInModel(models: readonly Model<Api>[]): Model<Api> | undefined {\n\treturn models[0];\n}\n\nexport function uniqueApis(models: readonly Model<Api>[]): Api[] {\n\tconst seen = new Set<Api>();\n\tconst apis: Api[] = [];\n\tfor (const model of models) {\n\t\tif (seen.has(model.api)) continue;\n\t\tseen.add(model.api);\n\t\tapis.push(model.api);\n\t}\n\treturn apis;\n}\n\nexport function synthesizeLiveModel(\n\tid: string,\n\ttemplate: Model<Api>,\n\traw: Record<string, unknown> = {},\n): LiveModelDiscovery {\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\treturn {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: template.reasoning,\n\t\t\tinput: template.input ?? [\"text\"],\n\t\t\tcost: ZERO_COST,\n\t\t\tcontextWindow: DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: template.thinkingLevelMap,\n\t\t},\n\t\tsupplied: {\n\t\t\t...NONE_SUPPLIED,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t},\n\t};\n}\n\n/** OpenRouter field mapping (tools filter, pricing × 1e6, context) from generate-models. */\nexport function mapOpenRouterModel(raw: Record<string, unknown>, template: Model<Api>): LiveModelDiscovery | undefined {\n\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\tif (!id) return undefined;\n\tconst supported = Array.isArray(raw.supported_parameters) ? raw.supported_parameters : [];\n\tif (!supported.includes(\"tools\")) return undefined;\n\n\tconst architecture = isRecord(raw.architecture) ? raw.architecture : undefined;\n\tconst modality = typeof architecture?.modality === \"string\" ? architecture.modality : \"\";\n\tconst input: (\"text\" | \"image\")[] = [\"text\"];\n\tif (modality.includes(\"image\")) input.push(\"image\");\n\n\tconst pricing = isRecord(raw.pricing) ? raw.pricing : undefined;\n\tconst inputCost = roundCost((asFiniteNumber(pricing?.prompt) ?? 0) * 1_000_000);\n\tconst outputCost = roundCost((asFiniteNumber(pricing?.completion) ?? 0) * 1_000_000);\n\tconst cacheReadCost = roundCost((asFiniteNumber(pricing?.input_cache_read) ?? 0) * 1_000_000);\n\tconst cacheWriteCost = roundCost((asFiniteNumber(pricing?.input_cache_write) ?? 0) * 1_000_000);\n\n\tconst topProvider = isRecord(raw.top_provider) ? raw.top_provider : undefined;\n\tconst contextWindow = asFiniteNumber(topProvider?.context_length) ?? asFiniteNumber(raw.context_length);\n\tconst maxTokens = asFiniteNumber(topProvider?.max_completion_tokens) ?? asFiniteNumber(raw.max_completion_tokens);\n\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\treturn {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: supported.includes(\"reasoning\") || template.reasoning,\n\t\t\tinput,\n\t\t\tcost: {\n\t\t\t\tinput: inputCost,\n\t\t\t\toutput: outputCost,\n\t\t\t\tcacheRead: cacheReadCost,\n\t\t\t\tcacheWrite: cacheWriteCost,\n\t\t\t},\n\t\t\tcontextWindow: contextWindow ?? DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: maxTokens ?? DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: template.thinkingLevelMap,\n\t\t},\n\t\tsupplied: {\n\t\t\tcontextWindow: contextWindow !== undefined,\n\t\t\tmaxTokens: maxTokens !== undefined,\n\t\t\tinput: true,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t\tcost: pricing !== undefined,\n\t\t\treasoning: supported.includes(\"reasoning\"),\n\t\t},\n\t};\n}\n\nexport function discoverLiveModels(\n\tproviderId: string,\n\tpayload: unknown,\n\tbakedIn: readonly Model<Api>[],\n): LiveModelDiscovery[] {\n\tconst template = firstBakedInModel(bakedIn);\n\tif (!template) return [];\n\tconst rows = parseOpenAIModelsList(payload);\n\tconst discoveries: LiveModelDiscovery[] = [];\n\tfor (const raw of rows) {\n\t\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\t\tif (!id) continue;\n\t\tif (providerId === \"openrouter\") {\n\t\t\tconst mapped = mapOpenRouterModel(raw, { ...template, provider: providerId });\n\t\t\tif (mapped) discoveries.push(mapped);\n\t\t\tcontinue;\n\t\t}\n\t\tdiscoveries.push(synthesizeLiveModel(id, { ...template, provider: providerId }, raw));\n\t}\n\treturn discoveries;\n}\n\nexport function missingLiveFields(supplied: LiveFieldSupply): Array<\"contextWindow\" | \"maxTokens\" | \"input\"> {\n\tconst missing: Array<\"contextWindow\" | \"maxTokens\" | \"input\"> = [];\n\tif (!supplied.contextWindow) missing.push(\"contextWindow\");\n\tif (!supplied.maxTokens) missing.push(\"maxTokens\");\n\tif (!supplied.input) missing.push(\"input\");\n\treturn missing;\n}\n\nexport function isLiveModelIncomplete(discovery: LiveModelDiscovery, knownKeys: Set<string>): boolean {\n\tif (knownKeys.has(modelKey(discovery.model.provider, discovery.model.id))) return false;\n\treturn missingLiveFields(discovery.supplied).length > 0;\n}\n\nexport function collectIncompleteLiveModels(\n\tdiscoveries: readonly LiveModelDiscovery[],\n\tbakedIn: readonly Model<Api>[],\n\tknownKeys: Set<string>,\n): IncompleteLiveModel[] {\n\tconst apis = uniqueApis(bakedIn);\n\tconst incomplete: IncompleteLiveModel[] = [];\n\tfor (const discovery of discoveries) {\n\t\tif (!isLiveModelIncomplete(discovery, knownKeys)) continue;\n\t\tincomplete.push({\n\t\t\tprovider: discovery.model.provider,\n\t\t\tid: discovery.model.id,\n\t\t\tname: discovery.model.name,\n\t\t\tmissing: missingLiveFields(discovery.supplied),\n\t\t\tdraft: discovery.model,\n\t\t\tavailableApis: apis,\n\t\t});\n\t}\n\treturn incomplete;\n}\n\nexport function buildLiveOverlay(\n\tbakedIn: readonly Model<Api>[],\n\tdiscoveries: readonly LiveModelDiscovery[],\n): Model<Api>[] {\n\tconst bakedById = new Map(bakedIn.map((model) => [model.id, model]));\n\tconst overlay: Model<Api>[] = [];\n\tfor (const discovery of discoveries) {\n\t\tconst baked = bakedById.get(discovery.model.id);\n\t\tif (!baked) {\n\t\t\toverlay.push(discovery.model);\n\t\t\tcontinue;\n\t\t}\n\t\toverlay.push({\n\t\t\t...baked,\n\t\t\tname: discovery.supplied.name ? discovery.model.name : baked.name,\n\t\t\tcontextWindow: discovery.supplied.contextWindow ? discovery.model.contextWindow : baked.contextWindow,\n\t\t\tmaxTokens: discovery.supplied.maxTokens ? discovery.model.maxTokens : baked.maxTokens,\n\t\t\tinput: discovery.supplied.input ? discovery.model.input : baked.input,\n\t\t\tcost: discovery.supplied.cost ? discovery.model.cost : baked.cost,\n\t\t\treasoning: discovery.supplied.reasoning ? discovery.model.reasoning : baked.reasoning,\n\t\t});\n\t}\n\treturn overlay;\n}\n\nexport function describeIncomplete(model: IncompleteLiveModel): string {\n\tconst labels: string[] = [];\n\tfor (const field of model.missing) {\n\t\tif (field === \"contextWindow\") labels.push(\"context window\");\n\t\telse if (field === \"maxTokens\") labels.push(\"max tokens\");\n\t\telse labels.push(\"input types\");\n\t}\n\tlet missingText = \"metadata\";\n\tif (labels.length === 1) missingText = labels[0] ?? missingText;\n\telse if (labels.length === 2) missingText = `${labels[0]} and ${labels[1]}`;\n\telse if (labels.length > 2) missingText = `${labels.slice(0, -1).join(\", \")}, and ${labels[labels.length - 1]}`;\n\treturn `New model ${model.provider}/${model.id} — missing ${missingText}.`;\n}\n\nexport function parsePositiveInt(value: string | undefined, fallback: number): number {\n\tif (!value?.trim()) return fallback;\n\tconst parsed = Number(value.trim());\n\tif (!Number.isInteger(parsed) || parsed <= 0) return fallback;\n\treturn parsed;\n}\n\nexport interface IncompleteModelAnswers {\n\tcontextWindow?: number;\n\tmaxTokens?: number;\n\tinput?: (\"text\" | \"image\")[];\n\treasoning?: boolean;\n\tapi?: Api;\n}\n\nexport function applyIncompleteAnswers(draft: Model<Api>, answers: IncompleteModelAnswers): Model<Api> {\n\treturn {\n\t\t...draft,\n\t\tcontextWindow: answers.contextWindow ?? draft.contextWindow,\n\t\tmaxTokens: answers.maxTokens ?? draft.maxTokens,\n\t\tinput: answers.input ?? draft.input,\n\t\treasoning: answers.reasoning ?? draft.reasoning,\n\t\tapi: answers.api ?? draft.api,\n\t};\n}\n\nexport interface FetchLiveProviderModelsOptions {\n\tproviderId: string;\n\tbaseUrl: string;\n\tbakedIn: readonly Model<Api>[];\n\tcredential?: Credential;\n\tknownKeys: Set<string>;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n\tfetchImpl?: typeof fetch;\n}\n\nexport async function fetchLiveProviderModels(options: FetchLiveProviderModelsOptions): Promise<LiveCatalogResult> {\n\tconst empty: LiveCatalogResult = {\n\t\tproviderId: options.providerId,\n\t\tstatus: \"skipped\",\n\t\tdiscoveries: [],\n\t\tadded: 0,\n\t\ttotal: 0,\n\t\tincomplete: [],\n\t};\n\tconst template = firstBakedInModel(options.bakedIn);\n\tif (!template || !options.baseUrl) return empty;\n\n\tconst timeoutMs = options.timeoutMs ?? LIVE_CATALOG_TIMEOUT_MS;\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst timer = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\tconst onParentAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onParentAbort, { once: true });\n\tif (options.signal?.aborted) controller.abort();\n\n\ttry {\n\t\tconst fetchImpl = options.fetchImpl ?? fetch;\n\t\tconst response = await Promise.race([\n\t\t\tfetchImpl(modelsListUrl(options.baseUrl), {\n\t\t\t\theaders: {\n\t\t\t\t\taccept: \"application/json\",\n\t\t\t\t\t\"User-Agent\": getPiUserAgent(VERSION),\n\t\t\t\t\t...credentialAuthHeaders(options.credential),\n\t\t\t\t},\n\t\t\t\tsignal: controller.signal,\n\t\t\t}),\n\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\tconst abortError = new Error(\"The operation was aborted\");\n\t\t\t\tabortError.name = \"AbortError\";\n\t\t\t\tcontroller.signal.addEventListener(\"abort\", () => reject(abortError), { once: true });\n\t\t\t\tif (controller.signal.aborted) reject(abortError);\n\t\t\t}),\n\t\t]);\n\t\tif (!response.ok) {\n\t\t\treturn {\n\t\t\t\t...empty,\n\t\t\t\tstatus: \"error\",\n\t\t\t\terror: `HTTP ${response.status}`,\n\t\t\t};\n\t\t}\n\t\tconst discoveries = discoverLiveModels(options.providerId, await response.json(), options.bakedIn);\n\t\tconst bakedIds = new Set(options.bakedIn.map((model) => model.id));\n\t\tconst added = discoveries.filter((discovery) => !bakedIds.has(discovery.model.id)).length;\n\t\treturn {\n\t\t\tproviderId: options.providerId,\n\t\t\tstatus: \"ok\",\n\t\t\tdiscoveries,\n\t\t\tadded,\n\t\t\ttotal: discoveries.length,\n\t\t\tincomplete: collectIncompleteLiveModels(discoveries, options.bakedIn, options.knownKeys),\n\t\t};\n\t} catch (error) {\n\t\tif (options.signal?.aborted && !timedOut) return { ...empty, status: \"skipped\", error: \"aborted\" };\n\t\tif (timedOut || (error instanceof Error && error.name === \"AbortError\")) {\n\t\t\treturn { ...empty, status: \"timeout\", error: \"timed out\" };\n\t\t}\n\t\treturn {\n\t\t\t...empty,\n\t\t\tstatus: \"error\",\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t} finally {\n\t\tclearTimeout(timer);\n\t\toptions.signal?.removeEventListener(\"abort\", onParentAbort);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"live-catalog.d.ts","sourceRoot":"","sources":["../../src/core/live-catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Api, type Credential, isOpenAiChatModel, type Model, parseOpenAiGptVersion } from \"@ashx-j/lunr-ai\";\nimport { codexModelsUrl, resolveCodexCatalogVersion } from \"@ashx-j/lunr-ai/catalog/codex\";\nimport { normalizeCatalogPricing } from \"@ashx-j/lunr-ai/catalog/metadata\";\nimport { VERSION } from \"../config.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\nimport { discoverCodexModels } from \"./codex-catalog.ts\";\nimport { modelKey } from \"./official-catalog.ts\";\n\nexport const LIVE_CATALOG_TIMEOUT_MS = 4000;\nexport const INCOMPLETE_PROMPT_CAP = 8;\nexport const DEFAULT_CONTEXT_WINDOW = 128000;\nexport const DEFAULT_MAX_TOKENS = 8192;\n\nexport const LIVE_LIST_PROVIDER_IDS = [\n\t\"openai-codex\",\n\t\"xai\",\n\t\"openrouter\",\n\t\"qwen-cloud\",\n\t\"qwen-cloud-cn\",\n\t\"groq\",\n\t\"openai\",\n\t\"deepseek\",\n] as const;\n\nexport type LiveListProviderId = (typeof LIVE_LIST_PROVIDER_IDS)[number];\n\nconst LIVE_LIST_PROVIDER_SET = new Set<string>(LIVE_LIST_PROVIDER_IDS);\n\nexport function isLiveListProvider(providerId: string): providerId is LiveListProviderId {\n\treturn LIVE_LIST_PROVIDER_SET.has(providerId);\n}\n\nexport interface LiveFieldSupply {\n\tcontextWindow: boolean;\n\tmaxTokens: boolean;\n\tinput: boolean;\n\tname: boolean;\n\tcost: boolean;\n\treasoning: boolean;\n}\n\nexport interface LiveModelDiscovery {\n\tmodel: Model<Api>;\n\tsupplied: LiveFieldSupply;\n}\n\nexport interface IncompleteLiveModel {\n\tprovider: string;\n\tid: string;\n\tname: string;\n\tmissing: Array<\"contextWindow\" | \"maxTokens\" | \"input\">;\n\tdraft: Model<Api>;\n\tavailableApis: Api[];\n}\n\nexport type LiveCatalogStatus = \"ok\" | \"timeout\" | \"error\" | \"skipped\";\n\nexport interface LiveCatalogResult {\n\tdiscoveryClientVersion?: string;\n\tproviderId: string;\n\tstatus: LiveCatalogStatus;\n\tdiscoveries: LiveModelDiscovery[];\n\tadded: number;\n\ttotal: number;\n\tincomplete: IncompleteLiveModel[];\n\terror?: string;\n}\n\nconst ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\nconst NONE_SUPPLIED: LiveFieldSupply = {\n\tcontextWindow: false,\n\tmaxTokens: false,\n\tinput: false,\n\tname: false,\n\tcost: false,\n\treasoning: false,\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asFiniteNumber(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (typeof value === \"string\" && value.trim()) {\n\t\tconst parsed = Number(value);\n\t\tif (Number.isFinite(parsed)) return parsed;\n\t}\n\treturn undefined;\n}\n\nfunction roundCost(value: number): number {\n\treturn Number(value.toFixed(6));\n}\n\nexport function modelsListUrl(baseUrl: string): string {\n\treturn `${baseUrl.replace(/\\/+$/u, \"\")}/models`;\n}\n\nexport function credentialAuthHeaders(credential: Credential | undefined): Record<string, string> {\n\tif (!credential) return {};\n\tif (credential.type === \"api_key\" && credential.key) {\n\t\treturn { Authorization: `Bearer ${credential.key}` };\n\t}\n\tif (credential.type === \"oauth\" && typeof credential.access === \"string\" && credential.access) {\n\t\treturn { Authorization: `Bearer ${credential.access}` };\n\t}\n\treturn {};\n}\n\n/** OpenAI `{ data: [{ id, ... }] }` plus a bare array. */\nexport function parseOpenAIModelsList(value: unknown): Record<string, unknown>[] {\n\tconst entries = isRecord(value) && Array.isArray(value.data) ? value.data : Array.isArray(value) ? value : [];\n\tconst rows: Record<string, unknown>[] = [];\n\tfor (const entry of entries) {\n\t\tif (typeof entry === \"string\" && entry.trim()) {\n\t\t\trows.push({ id: entry.trim() });\n\t\t\tcontinue;\n\t\t}\n\t\tif (isRecord(entry) && typeof entry.id === \"string\" && entry.id.trim()) rows.push(entry);\n\t}\n\treturn rows;\n}\n\nexport function firstBakedInModel(models: readonly Model<Api>[]): Model<Api> | undefined {\n\treturn models[0];\n}\n\nexport function selectLiveTemplate(\n\tproviderId: string,\n\tid: string,\n\tbakedIn: readonly Model<Api>[],\n): Model<Api> | undefined {\n\tconst exact = bakedIn.find((model) => model.id === id);\n\tif (exact) return exact;\n\tconst version = parseOpenAiGptVersion(id);\n\tif (providerId !== \"openai\" || !version || version.major < 5 || isOpenAiChatModel(id)) {\n\t\treturn firstBakedInModel(bakedIn);\n\t}\n\tlet reasoning: Model<Api> | undefined;\n\tfor (const model of bakedIn) {\n\t\tif (model.reasoning && parseOpenAiGptVersion(model.id)) reasoning = model;\n\t}\n\treturn reasoning ?? firstBakedInModel(bakedIn);\n}\n\nexport function uniqueApis(models: readonly Model<Api>[]): Api[] {\n\tconst seen = new Set<Api>();\n\tconst apis: Api[] = [];\n\tfor (const model of models) {\n\t\tif (seen.has(model.api)) continue;\n\t\tseen.add(model.api);\n\t\tapis.push(model.api);\n\t}\n\treturn apis;\n}\n\nexport function synthesizeLiveModel(\n\tid: string,\n\ttemplate: Model<Api>,\n\traw: Record<string, unknown> = {},\n): LiveModelDiscovery {\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\tconst exact = id === template.id;\n\tconst discovery: LiveModelDiscovery = {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: template.reasoning,\n\t\t\tinput: exact ? template.input : [\"text\"],\n\t\t\tcost: ZERO_COST,\n\t\t\tcontextWindow: DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: exact ? template.thinkingLevelMap : undefined,\n\t\t\tcatalog: { source: \"provider\", supplied: typeof raw.name === \"string\" ? [\"name\"] : [], pricing: \"unknown\" },\n\t\t},\n\t\tsupplied: {\n\t\t\t...NONE_SUPPLIED,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t},\n\t};\n\tconst context = asFiniteNumber(raw.context_window ?? raw.context_length ?? raw.max_context_length);\n\tconst output = asFiniteNumber(raw.max_output_tokens ?? raw.max_completion_tokens);\n\tif (context && context > 0) {\n\t\tdiscovery.model.contextWindow = context;\n\t\tdiscovery.supplied.contextWindow = true;\n\t}\n\tif (output && output > 0) {\n\t\tdiscovery.model.maxTokens = output;\n\t\tdiscovery.supplied.maxTokens = true;\n\t}\n\tif (typeof raw.reasoning === \"boolean\") {\n\t\tdiscovery.model.reasoning = raw.reasoning;\n\t\tdiscovery.supplied.reasoning = true;\n\t}\n\tif (Array.isArray(raw.input_modalities)) {\n\t\tconst input = raw.input_modalities.filter(\n\t\t\t(value): value is \"text\" | \"image\" => value === \"text\" || value === \"image\",\n\t\t);\n\t\tif (input.length) {\n\t\t\tdiscovery.model.input = input;\n\t\t\tdiscovery.supplied.input = true;\n\t\t}\n\t}\n\tdiscovery.model.catalog!.supplied = Object.entries(discovery.supplied)\n\t\t.filter(([, value]) => value)\n\t\t.map(([field]) => field) as NonNullable<Model<Api>[\"catalog\"]>[\"supplied\"];\n\treturn discovery;\n}\n\n/** OpenRouter field mapping (tools filter, pricing × 1e6, context) from generate-models. */\nexport function mapOpenRouterModel(raw: Record<string, unknown>, template: Model<Api>): LiveModelDiscovery | undefined {\n\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\tif (!id) return undefined;\n\tconst supported = Array.isArray(raw.supported_parameters) ? raw.supported_parameters : [];\n\tif (!supported.includes(\"tools\")) return undefined;\n\n\tconst architecture = isRecord(raw.architecture) ? raw.architecture : undefined;\n\tconst modality = typeof architecture?.modality === \"string\" ? architecture.modality : \"\";\n\tconst input: (\"text\" | \"image\")[] = [\"text\"];\n\tif (modality.includes(\"image\")) input.push(\"image\");\n\n\tconst pricing = isRecord(raw.pricing) ? raw.pricing : undefined;\n\tconst inputCost = roundCost((asFiniteNumber(pricing?.prompt) ?? 0) * 1_000_000);\n\tconst outputCost = roundCost((asFiniteNumber(pricing?.completion) ?? 0) * 1_000_000);\n\tconst cacheReadCost = roundCost((asFiniteNumber(pricing?.input_cache_read) ?? 0) * 1_000_000);\n\tconst cacheWriteCost = roundCost((asFiniteNumber(pricing?.input_cache_write) ?? 0) * 1_000_000);\n\n\tconst topProvider = isRecord(raw.top_provider) ? raw.top_provider : undefined;\n\tconst contextWindow = asFiniteNumber(topProvider?.context_length) ?? asFiniteNumber(raw.context_length);\n\tconst maxTokens = asFiniteNumber(topProvider?.max_completion_tokens) ?? asFiniteNumber(raw.max_completion_tokens);\n\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\treturn {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: supported.includes(\"reasoning\") || template.reasoning,\n\t\t\tinput,\n\t\t\tcost: {\n\t\t\t\tinput: inputCost,\n\t\t\t\toutput: outputCost,\n\t\t\t\tcacheRead: cacheReadCost,\n\t\t\t\tcacheWrite: cacheWriteCost,\n\t\t\t},\n\t\t\tcontextWindow: contextWindow ?? DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: maxTokens ?? DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: template.thinkingLevelMap,\n\t\t},\n\t\tsupplied: {\n\t\t\tcontextWindow: contextWindow !== undefined,\n\t\t\tmaxTokens: maxTokens !== undefined,\n\t\t\tinput: true,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t\tcost: asFiniteNumber(pricing?.prompt) !== undefined && asFiniteNumber(pricing?.completion) !== undefined,\n\t\t\treasoning: supported.includes(\"reasoning\"),\n\t\t},\n\t};\n}\n\nexport function discoverLiveModels(\n\tproviderId: string,\n\tpayload: unknown,\n\tbakedIn: readonly Model<Api>[],\n): LiveModelDiscovery[] {\n\tif (providerId === \"openai-codex\")\n\t\treturn discoverCodexModels(payload, bakedIn[0]?.baseUrl ?? \"https://chatgpt.com/backend-api\");\n\tconst fallback = firstBakedInModel(bakedIn);\n\tif (!fallback) return [];\n\tconst rows = parseOpenAIModelsList(payload);\n\tconst discoveries: LiveModelDiscovery[] = [];\n\tfor (const raw of rows) {\n\t\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\t\tif (!id) continue;\n\t\tif (\n\t\t\traw.tool_call === false ||\n\t\t\traw.type === \"embedding\" ||\n\t\t\t(providerId === \"openai\" &&\n\t\t\t\t/^(?:text-embedding-|tts-|whisper-|dall-e-|gpt-image-|gpt-audio|gpt-realtime|sora-|.*moderation)/i.test(id))\n\t\t)\n\t\t\tcontinue;\n\t\tconst template = { ...(selectLiveTemplate(providerId, id, bakedIn) ?? fallback), provider: providerId };\n\t\tif (providerId === \"openrouter\") {\n\t\t\tconst mapped = mapOpenRouterModel(raw, template);\n\t\t\tif (mapped) {\n\t\t\t\tmapped.model.catalog = {\n\t\t\t\t\tsource: \"provider\",\n\t\t\t\t\t...(!mapped.supplied.cost ? { pricing: \"unknown\" as const } : {}),\n\t\t\t\t\tsupplied: Object.entries(mapped.supplied)\n\t\t\t\t\t\t.filter(([, supplied]) => supplied)\n\t\t\t\t\t\t.map(([key]) => key) as NonNullable<Model<Api>[\"catalog\"]>[\"supplied\"],\n\t\t\t\t};\n\t\t\t\tmapped.model = normalizeCatalogPricing(mapped.model);\n\t\t\t\tif (mapped.model.catalog?.pricing === \"unknown\") mapped.supplied.cost = false;\n\t\t\t\tdiscoveries.push(mapped);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tdiscoveries.push(synthesizeLiveModel(id, template, raw));\n\t}\n\treturn discoveries;\n}\n\nexport function missingLiveFields(supplied: LiveFieldSupply): Array<\"contextWindow\" | \"maxTokens\" | \"input\"> {\n\tconst missing: Array<\"contextWindow\" | \"maxTokens\" | \"input\"> = [];\n\tif (!supplied.contextWindow) missing.push(\"contextWindow\");\n\tif (!supplied.maxTokens) missing.push(\"maxTokens\");\n\tif (!supplied.input) missing.push(\"input\");\n\treturn missing;\n}\n\nexport function isLiveModelIncomplete(discovery: LiveModelDiscovery, knownKeys: Set<string>): boolean {\n\tif (knownKeys.has(modelKey(discovery.model.provider, discovery.model.id))) return false;\n\treturn missingLiveFields(discovery.supplied).length > 0;\n}\n\nexport function collectIncompleteLiveModels(\n\tdiscoveries: readonly LiveModelDiscovery[],\n\tbakedIn: readonly Model<Api>[],\n\tknownKeys: Set<string>,\n): IncompleteLiveModel[] {\n\tconst apis = uniqueApis(bakedIn);\n\tconst incomplete: IncompleteLiveModel[] = [];\n\tfor (const discovery of discoveries) {\n\t\tif (!isLiveModelIncomplete(discovery, knownKeys)) continue;\n\t\tincomplete.push({\n\t\t\tprovider: discovery.model.provider,\n\t\t\tid: discovery.model.id,\n\t\t\tname: discovery.model.name,\n\t\t\tmissing: missingLiveFields(discovery.supplied),\n\t\t\tdraft: discovery.model,\n\t\t\tavailableApis: apis,\n\t\t});\n\t}\n\treturn incomplete;\n}\n\nexport function buildLiveOverlay(\n\tbakedIn: readonly Model<Api>[],\n\tdiscoveries: readonly LiveModelDiscovery[],\n): Model<Api>[] {\n\tconst bakedById = new Map(bakedIn.map((model) => [model.id, model]));\n\tconst overlay: Model<Api>[] = [];\n\tfor (const discovery of discoveries) {\n\t\tconst baked = bakedById.get(discovery.model.id);\n\t\tif (!baked) {\n\t\t\toverlay.push(discovery.model);\n\t\t\tcontinue;\n\t\t}\n\t\toverlay.push({\n\t\t\t...baked,\n\t\t\tcatalog: discovery.model.catalog,\n\t\t\tthinkingLevelMap: discovery.model.catalog?.supplied.includes(\"thinkingLevelMap\")\n\t\t\t\t? discovery.model.thinkingLevelMap\n\t\t\t\t: baked.thinkingLevelMap,\n\t\t\tname: discovery.supplied.name ? discovery.model.name : baked.name,\n\t\t\tcontextWindow: discovery.supplied.contextWindow ? discovery.model.contextWindow : baked.contextWindow,\n\t\t\tmaxTokens: discovery.supplied.maxTokens ? discovery.model.maxTokens : baked.maxTokens,\n\t\t\tinput: discovery.supplied.input ? discovery.model.input : baked.input,\n\t\t\tcost: discovery.supplied.cost ? discovery.model.cost : baked.cost,\n\t\t\treasoning: discovery.supplied.reasoning ? discovery.model.reasoning : baked.reasoning,\n\t\t});\n\t}\n\treturn overlay;\n}\n\nexport function describeIncomplete(model: IncompleteLiveModel): string {\n\tconst labels: string[] = [];\n\tfor (const field of model.missing) {\n\t\tif (field === \"contextWindow\") labels.push(\"context window\");\n\t\telse if (field === \"maxTokens\") labels.push(\"max tokens\");\n\t\telse labels.push(\"input types\");\n\t}\n\tlet missingText = \"metadata\";\n\tif (labels.length === 1) missingText = labels[0] ?? missingText;\n\telse if (labels.length === 2) missingText = `${labels[0]} and ${labels[1]}`;\n\telse if (labels.length > 2) missingText = `${labels.slice(0, -1).join(\", \")}, and ${labels[labels.length - 1]}`;\n\treturn `New model ${model.provider}/${model.id} — missing ${missingText}.`;\n}\n\nexport function parsePositiveInt(value: string | undefined, fallback: number): number {\n\tif (!value?.trim()) return fallback;\n\tconst parsed = Number(value.trim());\n\tif (!Number.isInteger(parsed) || parsed <= 0) return fallback;\n\treturn parsed;\n}\n\nexport interface IncompleteModelAnswers {\n\tcontextWindow?: number;\n\tmaxTokens?: number;\n\tinput?: (\"text\" | \"image\")[];\n\treasoning?: boolean;\n\tapi?: Api;\n}\n\nexport function applyIncompleteAnswers(draft: Model<Api>, answers: IncompleteModelAnswers): Model<Api> {\n\treturn {\n\t\t...draft,\n\t\tcontextWindow: answers.contextWindow ?? draft.contextWindow,\n\t\tmaxTokens: answers.maxTokens ?? draft.maxTokens,\n\t\tinput: answers.input ?? draft.input,\n\t\treasoning: answers.reasoning ?? draft.reasoning,\n\t\tapi: answers.api ?? draft.api,\n\t};\n}\n\nexport interface FetchLiveProviderModelsOptions {\n\tdiscoveryClientVersion?: string;\n\tproviderId: string;\n\tbaseUrl: string;\n\tbakedIn: readonly Model<Api>[];\n\tcredential?: Credential;\n\tknownKeys: Set<string>;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n\tfetchImpl?: typeof fetch;\n}\n\nexport async function fetchLiveProviderModels(options: FetchLiveProviderModelsOptions): Promise<LiveCatalogResult> {\n\tconst empty: LiveCatalogResult = {\n\t\tproviderId: options.providerId,\n\t\tstatus: \"skipped\",\n\t\tdiscoveries: [],\n\t\tadded: 0,\n\t\ttotal: 0,\n\t\tincomplete: [],\n\t};\n\tconst template = firstBakedInModel(options.bakedIn);\n\tif ((!template && options.providerId !== \"openai-codex\") || !options.baseUrl) return empty;\n\n\tconst timeoutMs = options.timeoutMs ?? LIVE_CATALOG_TIMEOUT_MS;\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst timer = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\tconst onParentAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onParentAbort, { once: true });\n\tif (options.signal?.aborted) controller.abort();\n\n\ttry {\n\t\tconst fetchImpl = options.fetchImpl ?? fetch;\n\t\tconst codex = options.providerId === \"openai-codex\";\n\t\tconst accountId =\n\t\t\toptions.credential?.type === \"oauth\" && typeof options.credential.accountId === \"string\"\n\t\t\t\t? options.credential.accountId\n\t\t\t\t: undefined;\n\t\tlet discoveryClientVersion = options.discoveryClientVersion;\n\t\tconst payload = await Promise.race([\n\t\t\t(async () => {\n\t\t\t\tif (codex)\n\t\t\t\t\tdiscoveryClientVersion = await resolveCodexCatalogVersion(\n\t\t\t\t\t\tfetchImpl,\n\t\t\t\t\t\tcontroller.signal,\n\t\t\t\t\t\tdiscoveryClientVersion,\n\t\t\t\t\t);\n\t\t\t\tconst response = await fetchImpl(\n\t\t\t\t\tcodex ? codexModelsUrl(options.baseUrl, discoveryClientVersion) : modelsListUrl(options.baseUrl),\n\t\t\t\t\t{\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\taccept: \"application/json\",\n\t\t\t\t\t\t\t\"User-Agent\": getPiUserAgent(VERSION),\n\t\t\t\t\t\t\t...credentialAuthHeaders(options.credential),\n\t\t\t\t\t\t\t...(accountId ? { \"ChatGPT-Account-ID\": accountId } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tif (!response.ok) throw new Error(`HTTP ${response.status}`);\n\t\t\t\treturn response.json();\n\t\t\t})(),\n\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\tconst abortError = new Error(\"The operation was aborted\");\n\t\t\t\tabortError.name = \"AbortError\";\n\t\t\t\tcontroller.signal.addEventListener(\"abort\", () => reject(abortError), { once: true });\n\t\t\t\tif (controller.signal.aborted) reject(abortError);\n\t\t\t}),\n\t\t]);\n\t\tconst discoveries = codex\n\t\t\t? discoverCodexModels(payload, options.baseUrl)\n\t\t\t: discoverLiveModels(options.providerId, payload, options.bakedIn);\n\t\tif (!discoveries.length) throw new Error(\"No usable models returned; retaining cached models\");\n\t\tconst bakedIds = new Set(options.bakedIn.map((model) => model.id));\n\t\tconst added = discoveries.filter((discovery) => !bakedIds.has(discovery.model.id)).length;\n\t\treturn {\n\t\t\tproviderId: options.providerId,\n\t\t\tdiscoveryClientVersion,\n\t\t\tstatus: \"ok\",\n\t\t\tdiscoveries,\n\t\t\tadded,\n\t\t\ttotal: discoveries.length,\n\t\t\tincomplete: collectIncompleteLiveModels(discoveries, options.bakedIn, options.knownKeys),\n\t\t};\n\t} catch (error) {\n\t\tif (options.signal?.aborted && !timedOut) return { ...empty, status: \"skipped\", error: \"aborted\" };\n\t\tif (timedOut || (error instanceof Error && error.name === \"AbortError\")) {\n\t\t\treturn { ...empty, status: \"timeout\", error: \"timed out\" };\n\t\t}\n\t\treturn {\n\t\t\t...empty,\n\t\t\tstatus: \"error\",\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t} finally {\n\t\tclearTimeout(timer);\n\t\toptions.signal?.removeEventListener(\"abort\", onParentAbort);\n\t}\n}\n"]}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import { isOpenAiChatModel, parseOpenAiGptVersion } from "@ashx-j/lunr-ai";
|
|
2
|
+
import { codexModelsUrl, resolveCodexCatalogVersion } from "@ashx-j/lunr-ai/catalog/codex";
|
|
3
|
+
import { normalizeCatalogPricing } from "@ashx-j/lunr-ai/catalog/metadata";
|
|
1
4
|
import { VERSION } from "../config.js";
|
|
2
5
|
import { getPiUserAgent } from "../utils/pi-user-agent.js";
|
|
6
|
+
import { discoverCodexModels } from "./codex-catalog.js";
|
|
3
7
|
import { modelKey } from "./official-catalog.js";
|
|
4
8
|
export const LIVE_CATALOG_TIMEOUT_MS = 4000;
|
|
5
9
|
export const INCOMPLETE_PROMPT_CAP = 8;
|
|
6
10
|
export const DEFAULT_CONTEXT_WINDOW = 128000;
|
|
7
11
|
export const DEFAULT_MAX_TOKENS = 8192;
|
|
8
12
|
export const LIVE_LIST_PROVIDER_IDS = [
|
|
13
|
+
"openai-codex",
|
|
9
14
|
"xai",
|
|
10
15
|
"openrouter",
|
|
11
16
|
"qwen-cloud",
|
|
@@ -74,6 +79,21 @@ export function parseOpenAIModelsList(value) {
|
|
|
74
79
|
export function firstBakedInModel(models) {
|
|
75
80
|
return models[0];
|
|
76
81
|
}
|
|
82
|
+
export function selectLiveTemplate(providerId, id, bakedIn) {
|
|
83
|
+
const exact = bakedIn.find((model) => model.id === id);
|
|
84
|
+
if (exact)
|
|
85
|
+
return exact;
|
|
86
|
+
const version = parseOpenAiGptVersion(id);
|
|
87
|
+
if (providerId !== "openai" || !version || version.major < 5 || isOpenAiChatModel(id)) {
|
|
88
|
+
return firstBakedInModel(bakedIn);
|
|
89
|
+
}
|
|
90
|
+
let reasoning;
|
|
91
|
+
for (const model of bakedIn) {
|
|
92
|
+
if (model.reasoning && parseOpenAiGptVersion(model.id))
|
|
93
|
+
reasoning = model;
|
|
94
|
+
}
|
|
95
|
+
return reasoning ?? firstBakedInModel(bakedIn);
|
|
96
|
+
}
|
|
77
97
|
export function uniqueApis(models) {
|
|
78
98
|
const seen = new Set();
|
|
79
99
|
const apis = [];
|
|
@@ -87,7 +107,8 @@ export function uniqueApis(models) {
|
|
|
87
107
|
}
|
|
88
108
|
export function synthesizeLiveModel(id, template, raw = {}) {
|
|
89
109
|
const name = typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : id;
|
|
90
|
-
|
|
110
|
+
const exact = id === template.id;
|
|
111
|
+
const discovery = {
|
|
91
112
|
model: {
|
|
92
113
|
id,
|
|
93
114
|
name,
|
|
@@ -95,18 +116,44 @@ export function synthesizeLiveModel(id, template, raw = {}) {
|
|
|
95
116
|
provider: template.provider,
|
|
96
117
|
baseUrl: template.baseUrl,
|
|
97
118
|
reasoning: template.reasoning,
|
|
98
|
-
input: template.input
|
|
119
|
+
input: exact ? template.input : ["text"],
|
|
99
120
|
cost: ZERO_COST,
|
|
100
121
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
|
101
122
|
maxTokens: DEFAULT_MAX_TOKENS,
|
|
102
123
|
compat: template.compat,
|
|
103
|
-
thinkingLevelMap: template.thinkingLevelMap,
|
|
124
|
+
thinkingLevelMap: exact ? template.thinkingLevelMap : undefined,
|
|
125
|
+
catalog: { source: "provider", supplied: typeof raw.name === "string" ? ["name"] : [], pricing: "unknown" },
|
|
104
126
|
},
|
|
105
127
|
supplied: {
|
|
106
128
|
...NONE_SUPPLIED,
|
|
107
129
|
name: typeof raw.name === "string" && raw.name.trim().length > 0,
|
|
108
130
|
},
|
|
109
131
|
};
|
|
132
|
+
const context = asFiniteNumber(raw.context_window ?? raw.context_length ?? raw.max_context_length);
|
|
133
|
+
const output = asFiniteNumber(raw.max_output_tokens ?? raw.max_completion_tokens);
|
|
134
|
+
if (context && context > 0) {
|
|
135
|
+
discovery.model.contextWindow = context;
|
|
136
|
+
discovery.supplied.contextWindow = true;
|
|
137
|
+
}
|
|
138
|
+
if (output && output > 0) {
|
|
139
|
+
discovery.model.maxTokens = output;
|
|
140
|
+
discovery.supplied.maxTokens = true;
|
|
141
|
+
}
|
|
142
|
+
if (typeof raw.reasoning === "boolean") {
|
|
143
|
+
discovery.model.reasoning = raw.reasoning;
|
|
144
|
+
discovery.supplied.reasoning = true;
|
|
145
|
+
}
|
|
146
|
+
if (Array.isArray(raw.input_modalities)) {
|
|
147
|
+
const input = raw.input_modalities.filter((value) => value === "text" || value === "image");
|
|
148
|
+
if (input.length) {
|
|
149
|
+
discovery.model.input = input;
|
|
150
|
+
discovery.supplied.input = true;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
discovery.model.catalog.supplied = Object.entries(discovery.supplied)
|
|
154
|
+
.filter(([, value]) => value)
|
|
155
|
+
.map(([field]) => field);
|
|
156
|
+
return discovery;
|
|
110
157
|
}
|
|
111
158
|
/** OpenRouter field mapping (tools filter, pricing × 1e6, context) from generate-models. */
|
|
112
159
|
export function mapOpenRouterModel(raw, template) {
|
|
@@ -155,14 +202,16 @@ export function mapOpenRouterModel(raw, template) {
|
|
|
155
202
|
maxTokens: maxTokens !== undefined,
|
|
156
203
|
input: true,
|
|
157
204
|
name: typeof raw.name === "string" && raw.name.trim().length > 0,
|
|
158
|
-
cost: pricing !== undefined,
|
|
205
|
+
cost: asFiniteNumber(pricing?.prompt) !== undefined && asFiniteNumber(pricing?.completion) !== undefined,
|
|
159
206
|
reasoning: supported.includes("reasoning"),
|
|
160
207
|
},
|
|
161
208
|
};
|
|
162
209
|
}
|
|
163
210
|
export function discoverLiveModels(providerId, payload, bakedIn) {
|
|
164
|
-
|
|
165
|
-
|
|
211
|
+
if (providerId === "openai-codex")
|
|
212
|
+
return discoverCodexModels(payload, bakedIn[0]?.baseUrl ?? "https://chatgpt.com/backend-api");
|
|
213
|
+
const fallback = firstBakedInModel(bakedIn);
|
|
214
|
+
if (!fallback)
|
|
166
215
|
return [];
|
|
167
216
|
const rows = parseOpenAIModelsList(payload);
|
|
168
217
|
const discoveries = [];
|
|
@@ -170,13 +219,30 @@ export function discoverLiveModels(providerId, payload, bakedIn) {
|
|
|
170
219
|
const id = typeof raw.id === "string" ? raw.id.trim() : "";
|
|
171
220
|
if (!id)
|
|
172
221
|
continue;
|
|
222
|
+
if (raw.tool_call === false ||
|
|
223
|
+
raw.type === "embedding" ||
|
|
224
|
+
(providerId === "openai" &&
|
|
225
|
+
/^(?:text-embedding-|tts-|whisper-|dall-e-|gpt-image-|gpt-audio|gpt-realtime|sora-|.*moderation)/i.test(id)))
|
|
226
|
+
continue;
|
|
227
|
+
const template = { ...(selectLiveTemplate(providerId, id, bakedIn) ?? fallback), provider: providerId };
|
|
173
228
|
if (providerId === "openrouter") {
|
|
174
|
-
const mapped = mapOpenRouterModel(raw,
|
|
175
|
-
if (mapped)
|
|
229
|
+
const mapped = mapOpenRouterModel(raw, template);
|
|
230
|
+
if (mapped) {
|
|
231
|
+
mapped.model.catalog = {
|
|
232
|
+
source: "provider",
|
|
233
|
+
...(!mapped.supplied.cost ? { pricing: "unknown" } : {}),
|
|
234
|
+
supplied: Object.entries(mapped.supplied)
|
|
235
|
+
.filter(([, supplied]) => supplied)
|
|
236
|
+
.map(([key]) => key),
|
|
237
|
+
};
|
|
238
|
+
mapped.model = normalizeCatalogPricing(mapped.model);
|
|
239
|
+
if (mapped.model.catalog?.pricing === "unknown")
|
|
240
|
+
mapped.supplied.cost = false;
|
|
176
241
|
discoveries.push(mapped);
|
|
242
|
+
}
|
|
177
243
|
continue;
|
|
178
244
|
}
|
|
179
|
-
discoveries.push(synthesizeLiveModel(id,
|
|
245
|
+
discoveries.push(synthesizeLiveModel(id, template, raw));
|
|
180
246
|
}
|
|
181
247
|
return discoveries;
|
|
182
248
|
}
|
|
@@ -223,6 +289,10 @@ export function buildLiveOverlay(bakedIn, discoveries) {
|
|
|
223
289
|
}
|
|
224
290
|
overlay.push({
|
|
225
291
|
...baked,
|
|
292
|
+
catalog: discovery.model.catalog,
|
|
293
|
+
thinkingLevelMap: discovery.model.catalog?.supplied.includes("thinkingLevelMap")
|
|
294
|
+
? discovery.model.thinkingLevelMap
|
|
295
|
+
: baked.thinkingLevelMap,
|
|
226
296
|
name: discovery.supplied.name ? discovery.model.name : baked.name,
|
|
227
297
|
contextWindow: discovery.supplied.contextWindow ? discovery.model.contextWindow : baked.contextWindow,
|
|
228
298
|
maxTokens: discovery.supplied.maxTokens ? discovery.model.maxTokens : baked.maxTokens,
|
|
@@ -280,7 +350,7 @@ export async function fetchLiveProviderModels(options) {
|
|
|
280
350
|
incomplete: [],
|
|
281
351
|
};
|
|
282
352
|
const template = firstBakedInModel(options.bakedIn);
|
|
283
|
-
if (!template || !options.baseUrl)
|
|
353
|
+
if ((!template && options.providerId !== "openai-codex") || !options.baseUrl)
|
|
284
354
|
return empty;
|
|
285
355
|
const timeoutMs = options.timeoutMs ?? LIVE_CATALOG_TIMEOUT_MS;
|
|
286
356
|
const controller = new AbortController();
|
|
@@ -295,15 +365,28 @@ export async function fetchLiveProviderModels(options) {
|
|
|
295
365
|
controller.abort();
|
|
296
366
|
try {
|
|
297
367
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
368
|
+
const codex = options.providerId === "openai-codex";
|
|
369
|
+
const accountId = options.credential?.type === "oauth" && typeof options.credential.accountId === "string"
|
|
370
|
+
? options.credential.accountId
|
|
371
|
+
: undefined;
|
|
372
|
+
let discoveryClientVersion = options.discoveryClientVersion;
|
|
373
|
+
const payload = await Promise.race([
|
|
374
|
+
(async () => {
|
|
375
|
+
if (codex)
|
|
376
|
+
discoveryClientVersion = await resolveCodexCatalogVersion(fetchImpl, controller.signal, discoveryClientVersion);
|
|
377
|
+
const response = await fetchImpl(codex ? codexModelsUrl(options.baseUrl, discoveryClientVersion) : modelsListUrl(options.baseUrl), {
|
|
378
|
+
headers: {
|
|
379
|
+
accept: "application/json",
|
|
380
|
+
"User-Agent": getPiUserAgent(VERSION),
|
|
381
|
+
...credentialAuthHeaders(options.credential),
|
|
382
|
+
...(accountId ? { "ChatGPT-Account-ID": accountId } : {}),
|
|
383
|
+
},
|
|
384
|
+
signal: controller.signal,
|
|
385
|
+
});
|
|
386
|
+
if (!response.ok)
|
|
387
|
+
throw new Error(`HTTP ${response.status}`);
|
|
388
|
+
return response.json();
|
|
389
|
+
})(),
|
|
307
390
|
new Promise((_, reject) => {
|
|
308
391
|
const abortError = new Error("The operation was aborted");
|
|
309
392
|
abortError.name = "AbortError";
|
|
@@ -312,18 +395,16 @@ export async function fetchLiveProviderModels(options) {
|
|
|
312
395
|
reject(abortError);
|
|
313
396
|
}),
|
|
314
397
|
]);
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
const discoveries = discoverLiveModels(options.providerId, await response.json(), options.bakedIn);
|
|
398
|
+
const discoveries = codex
|
|
399
|
+
? discoverCodexModels(payload, options.baseUrl)
|
|
400
|
+
: discoverLiveModels(options.providerId, payload, options.bakedIn);
|
|
401
|
+
if (!discoveries.length)
|
|
402
|
+
throw new Error("No usable models returned; retaining cached models");
|
|
323
403
|
const bakedIds = new Set(options.bakedIn.map((model) => model.id));
|
|
324
404
|
const added = discoveries.filter((discovery) => !bakedIds.has(discovery.model.id)).length;
|
|
325
405
|
return {
|
|
326
406
|
providerId: options.providerId,
|
|
407
|
+
discoveryClientVersion,
|
|
327
408
|
status: "ok",
|
|
328
409
|
discoveries,
|
|
329
410
|
added,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-catalog.js","sourceRoot":"","sources":["../../src/core/live-catalog.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AACvC,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAC7C,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEvC,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACrC,KAAK;IACL,YAAY;IACZ,YAAY;IACZ,eAAe;IACf,MAAM;IACN,QAAQ;IACR,UAAU;CACD,CAAC;AAIX,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAS,sBAAsB,CAAC,CAAC;AAEvE,MAAM,UAAU,kBAAkB,CAAC,UAAkB,EAAoC;IACxF,OAAO,sBAAsB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AAAA,CAC9C;AAqCD,MAAM,SAAS,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;AACvE,MAAM,aAAa,GAAoB;IACtC,aAAa,EAAE,KAAK;IACpB,SAAS,EAAE,KAAK;IAChB,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,KAAK;IACX,IAAI,EAAE,KAAK;IACX,SAAS,EAAE,KAAK;CAChB,CAAC;AAEF,SAAS,QAAQ,CAAC,KAAc,EAAoC;IACnE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAAA,CAC5E;AAED,SAAS,cAAc,CAAC,KAAc,EAAsB;IAC3D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC;IAC5C,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,SAAS,CAAC,KAAa,EAAU;IACzC,OAAO,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAAA,CAChC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe,EAAU;IACtD,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC;AAAA,CAChD;AAED,MAAM,UAAU,qBAAqB,CAAC,UAAkC,EAA0B;IACjG,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAC3B,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;QACrD,OAAO,EAAE,aAAa,EAAE,UAAU,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC;IACtD,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,UAAU,CAAC,MAAM,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QAC/F,OAAO,EAAE,aAAa,EAAE,UAAU,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;IACzD,CAAC;IACD,OAAO,EAAE,CAAC;AAAA,CACV;AAED,0DAA0D;AAC1D,MAAM,UAAU,qBAAqB,CAAC,KAAc,EAA6B;IAChF,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9G,MAAM,IAAI,GAA8B,EAAE,CAAC;IAC3C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAChC,SAAS;QACV,CAAC;QACD,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1F,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,MAAM,UAAU,iBAAiB,CAAC,MAA6B,EAA0B;IACxF,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AAAA,CACjB;AAED,MAAM,UAAU,UAAU,CAAC,MAA6B,EAAS;IAChE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAO,CAAC;IAC5B,MAAM,IAAI,GAAU,EAAE,CAAC;IACvB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;YAAE,SAAS;QAClC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,MAAM,UAAU,mBAAmB,CAClC,EAAU,EACV,QAAoB,EACpB,GAAG,GAA4B,EAAE,EACZ;IACrB,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpF,OAAO;QACN,KAAK,EAAE;YACN,EAAE;YACF,IAAI;YACJ,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,SAAS,EAAE,QAAQ,CAAC,SAAS;YAC7B,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC;YACjC,IAAI,EAAE,SAAS;YACf,aAAa,EAAE,sBAAsB;YACrC,SAAS,EAAE,kBAAkB;YAC7B,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;SAC3C;QACD,QAAQ,EAAE;YACT,GAAG,aAAa;YAChB,IAAI,EAAE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;SAChE;KACD,CAAC;AAAA,CACF;AAED,6FAA4F;AAC5F,MAAM,UAAU,kBAAkB,CAAC,GAA4B,EAAE,QAAoB,EAAkC;IACtH,MAAM,EAAE,GAAG,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3D,IAAI,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAC1B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1F,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAEnD,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/E,MAAM,QAAQ,GAAG,OAAO,YAAY,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACzF,MAAM,KAAK,GAAyB,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAChF,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACrF,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC9F,MAAM,cAAc,GAAG,SAAS,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAEhG,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9E,MAAM,aAAa,GAAG,cAAc,CAAC,WAAW,EAAE,cAAc,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACxG,MAAM,SAAS,GAAG,cAAc,CAAC,WAAW,EAAE,qBAAqB,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAElH,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpF,OAAO;QACN,KAAK,EAAE;YACN,EAAE;YACF,IAAI;YACJ,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,SAAS,EAAE,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,SAAS;YAChE,KAAK;YACL,IAAI,EAAE;gBACL,KAAK,EAAE,SAAS;gBAChB,MAAM,EAAE,UAAU;gBAClB,SAAS,EAAE,aAAa;gBACxB,UAAU,EAAE,cAAc;aAC1B;YACD,aAAa,EAAE,aAAa,IAAI,sBAAsB;YACtD,SAAS,EAAE,SAAS,IAAI,kBAAkB;YAC1C,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;SAC3C;QACD,QAAQ,EAAE;YACT,aAAa,EAAE,aAAa,KAAK,SAAS;YAC1C,SAAS,EAAE,SAAS,KAAK,SAAS;YAClC,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAChE,IAAI,EAAE,OAAO,KAAK,SAAS;YAC3B,SAAS,EAAE,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC;SAC1C;KACD,CAAC;AAAA,CACF;AAED,MAAM,UAAU,kBAAkB,CACjC,UAAkB,EAClB,OAAgB,EAChB,OAA8B,EACP;IACvB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,WAAW,GAAyB,EAAE,CAAC;IAC7C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,EAAE,GAAG,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,EAAE;YAAE,SAAS;QAClB,IAAI,UAAU,KAAK,YAAY,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,EAAE,EAAE,GAAG,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;YAC9E,IAAI,MAAM;gBAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrC,SAAS;QACV,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE,EAAE,EAAE,GAAG,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,WAAW,CAAC;AAAA,CACnB;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAyB,EAAkD;IAC5G,MAAM,OAAO,GAAmD,EAAE,CAAC;IACnE,IAAI,CAAC,QAAQ,CAAC,aAAa;QAAE,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC3D,IAAI,CAAC,QAAQ,CAAC,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACnD,IAAI,CAAC,QAAQ,CAAC,KAAK;QAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,OAAO,CAAC;AAAA,CACf;AAED,MAAM,UAAU,qBAAqB,CAAC,SAA6B,EAAE,SAAsB,EAAW;IACrG,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACxF,OAAO,iBAAiB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAAA,CACxD;AAED,MAAM,UAAU,2BAA2B,CAC1C,WAA0C,EAC1C,OAA8B,EAC9B,SAAsB,EACE;IACxB,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACjC,MAAM,UAAU,GAA0B,EAAE,CAAC;IAC7C,KAAK,MAAM,SAAS,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,qBAAqB,CAAC,SAAS,EAAE,SAAS,CAAC;YAAE,SAAS;QAC3D,UAAU,CAAC,IAAI,CAAC;YACf,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,QAAQ;YAClC,EAAE,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE;YACtB,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI;YAC1B,OAAO,EAAE,iBAAiB,CAAC,SAAS,CAAC,QAAQ,CAAC;YAC9C,KAAK,EAAE,SAAS,CAAC,KAAK;YACtB,aAAa,EAAE,IAAI;SACnB,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC;AAAA,CAClB;AAED,MAAM,UAAU,gBAAgB,CAC/B,OAA8B,EAC9B,WAA0C,EAC3B;IACf,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,KAAK,MAAM,SAAS,IAAI,WAAW,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC9B,SAAS;QACV,CAAC;QACD,OAAO,CAAC,IAAI,CAAC;YACZ,GAAG,KAAK;YACR,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;YACjE,aAAa,EAAE,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa;YACrG,SAAS,EAAE,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;YACrF,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK;YACrE,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;YACjE,SAAS,EAAE,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS;SACrF,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AAAA,CACf;AAED,MAAM,UAAU,kBAAkB,CAAC,KAA0B,EAAU;IACtE,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QACnC,IAAI,KAAK,KAAK,eAAe;YAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;aACxD,IAAI,KAAK,KAAK,WAAW;YAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;;YACrD,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,WAAW,GAAG,UAAU,CAAC;IAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC;SAC3D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,WAAW,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;SACvE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,WAAW,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;IAChH,OAAO,aAAa,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,gBAAc,WAAW,GAAG,CAAC;AAAA,CAC3E;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAyB,EAAE,QAAgB,EAAU;IACrF,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE;QAAE,OAAO,QAAQ,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC9D,OAAO,MAAM,CAAC;AAAA,CACd;AAUD,MAAM,UAAU,sBAAsB,CAAC,KAAiB,EAAE,OAA+B,EAAc;IACtG,OAAO;QACN,GAAG,KAAK;QACR,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,KAAK,CAAC,aAAa;QAC3D,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS;QAC/C,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK;QACnC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS;QAC/C,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG;KAC7B,CAAC;AAAA,CACF;AAaD,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,OAAuC,EAA8B;IAClH,MAAM,KAAK,GAAsB;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,EAAE;QACf,KAAK,EAAE,CAAC;QACR,KAAK,EAAE,CAAC;QACR,UAAU,EAAE,EAAE;KACd,CAAC;IACF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAEhD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,uBAAuB,CAAC;IAC/D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;QAC9B,QAAQ,GAAG,IAAI,CAAC;QAChB,UAAU,CAAC,KAAK,EAAE,CAAC;IAAA,CACnB,EAAE,SAAS,CAAC,CAAC;IACd,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC/C,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;QAAE,UAAU,CAAC,KAAK,EAAE,CAAC;IAEhD,IAAI,CAAC;QACJ,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;QAC7C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;YACnC,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;gBACzC,OAAO,EAAE;oBACR,MAAM,EAAE,kBAAkB;oBAC1B,YAAY,EAAE,cAAc,CAAC,OAAO,CAAC;oBACrC,GAAG,qBAAqB,CAAC,OAAO,CAAC,UAAU,CAAC;iBAC5C;gBACD,MAAM,EAAE,UAAU,CAAC,MAAM;aACzB,CAAC;YACF,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;gBACjC,MAAM,UAAU,GAAG,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;gBAC1D,UAAU,CAAC,IAAI,GAAG,YAAY,CAAC;gBAC/B,UAAU,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBACtF,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;oBAAE,MAAM,CAAC,UAAU,CAAC,CAAC;YAAA,CAClD,CAAC;SACF,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,OAAO;gBACN,GAAG,KAAK;gBACR,MAAM,EAAE,OAAO;gBACf,KAAK,EAAE,QAAQ,QAAQ,CAAC,MAAM,EAAE;aAChC,CAAC;QACH,CAAC;QACD,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QACnG,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QACnE,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1F,OAAO;YACN,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,MAAM,EAAE,IAAI;YACZ,WAAW;YACX,KAAK;YACL,KAAK,EAAE,WAAW,CAAC,MAAM;YACzB,UAAU,EAAE,2BAA2B,CAAC,WAAW,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC;SACxF,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC,QAAQ;YAAE,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QACnG,IAAI,QAAQ,IAAI,CAAC,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,EAAE,CAAC;YACzE,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;QAC5D,CAAC;QACD,OAAO;YACN,GAAG,KAAK;YACR,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC7D,CAAC;IACH,CAAC;YAAS,CAAC;QACV,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,OAAO,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAC7D,CAAC;AAAA,CACD","sourcesContent":["import type { Api, Credential, Model } from \"@ashx-j/lunr-ai\";\nimport { VERSION } from \"../config.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\nimport { modelKey } from \"./official-catalog.ts\";\n\nexport const LIVE_CATALOG_TIMEOUT_MS = 4000;\nexport const INCOMPLETE_PROMPT_CAP = 8;\nexport const DEFAULT_CONTEXT_WINDOW = 128000;\nexport const DEFAULT_MAX_TOKENS = 8192;\n\nexport const LIVE_LIST_PROVIDER_IDS = [\n\t\"xai\",\n\t\"openrouter\",\n\t\"qwen-cloud\",\n\t\"qwen-cloud-cn\",\n\t\"groq\",\n\t\"openai\",\n\t\"deepseek\",\n] as const;\n\nexport type LiveListProviderId = (typeof LIVE_LIST_PROVIDER_IDS)[number];\n\nconst LIVE_LIST_PROVIDER_SET = new Set<string>(LIVE_LIST_PROVIDER_IDS);\n\nexport function isLiveListProvider(providerId: string): providerId is LiveListProviderId {\n\treturn LIVE_LIST_PROVIDER_SET.has(providerId);\n}\n\nexport interface LiveFieldSupply {\n\tcontextWindow: boolean;\n\tmaxTokens: boolean;\n\tinput: boolean;\n\tname: boolean;\n\tcost: boolean;\n\treasoning: boolean;\n}\n\nexport interface LiveModelDiscovery {\n\tmodel: Model<Api>;\n\tsupplied: LiveFieldSupply;\n}\n\nexport interface IncompleteLiveModel {\n\tprovider: string;\n\tid: string;\n\tname: string;\n\tmissing: Array<\"contextWindow\" | \"maxTokens\" | \"input\">;\n\tdraft: Model<Api>;\n\tavailableApis: Api[];\n}\n\nexport type LiveCatalogStatus = \"ok\" | \"timeout\" | \"error\" | \"skipped\";\n\nexport interface LiveCatalogResult {\n\tproviderId: string;\n\tstatus: LiveCatalogStatus;\n\tdiscoveries: LiveModelDiscovery[];\n\tadded: number;\n\ttotal: number;\n\tincomplete: IncompleteLiveModel[];\n\terror?: string;\n}\n\nconst ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\nconst NONE_SUPPLIED: LiveFieldSupply = {\n\tcontextWindow: false,\n\tmaxTokens: false,\n\tinput: false,\n\tname: false,\n\tcost: false,\n\treasoning: false,\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asFiniteNumber(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (typeof value === \"string\" && value.trim()) {\n\t\tconst parsed = Number(value);\n\t\tif (Number.isFinite(parsed)) return parsed;\n\t}\n\treturn undefined;\n}\n\nfunction roundCost(value: number): number {\n\treturn Number(value.toFixed(6));\n}\n\nexport function modelsListUrl(baseUrl: string): string {\n\treturn `${baseUrl.replace(/\\/+$/u, \"\")}/models`;\n}\n\nexport function credentialAuthHeaders(credential: Credential | undefined): Record<string, string> {\n\tif (!credential) return {};\n\tif (credential.type === \"api_key\" && credential.key) {\n\t\treturn { Authorization: `Bearer ${credential.key}` };\n\t}\n\tif (credential.type === \"oauth\" && typeof credential.access === \"string\" && credential.access) {\n\t\treturn { Authorization: `Bearer ${credential.access}` };\n\t}\n\treturn {};\n}\n\n/** OpenAI `{ data: [{ id, ... }] }` plus a bare array. */\nexport function parseOpenAIModelsList(value: unknown): Record<string, unknown>[] {\n\tconst entries = isRecord(value) && Array.isArray(value.data) ? value.data : Array.isArray(value) ? value : [];\n\tconst rows: Record<string, unknown>[] = [];\n\tfor (const entry of entries) {\n\t\tif (typeof entry === \"string\" && entry.trim()) {\n\t\t\trows.push({ id: entry.trim() });\n\t\t\tcontinue;\n\t\t}\n\t\tif (isRecord(entry) && typeof entry.id === \"string\" && entry.id.trim()) rows.push(entry);\n\t}\n\treturn rows;\n}\n\nexport function firstBakedInModel(models: readonly Model<Api>[]): Model<Api> | undefined {\n\treturn models[0];\n}\n\nexport function uniqueApis(models: readonly Model<Api>[]): Api[] {\n\tconst seen = new Set<Api>();\n\tconst apis: Api[] = [];\n\tfor (const model of models) {\n\t\tif (seen.has(model.api)) continue;\n\t\tseen.add(model.api);\n\t\tapis.push(model.api);\n\t}\n\treturn apis;\n}\n\nexport function synthesizeLiveModel(\n\tid: string,\n\ttemplate: Model<Api>,\n\traw: Record<string, unknown> = {},\n): LiveModelDiscovery {\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\treturn {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: template.reasoning,\n\t\t\tinput: template.input ?? [\"text\"],\n\t\t\tcost: ZERO_COST,\n\t\t\tcontextWindow: DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: template.thinkingLevelMap,\n\t\t},\n\t\tsupplied: {\n\t\t\t...NONE_SUPPLIED,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t},\n\t};\n}\n\n/** OpenRouter field mapping (tools filter, pricing × 1e6, context) from generate-models. */\nexport function mapOpenRouterModel(raw: Record<string, unknown>, template: Model<Api>): LiveModelDiscovery | undefined {\n\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\tif (!id) return undefined;\n\tconst supported = Array.isArray(raw.supported_parameters) ? raw.supported_parameters : [];\n\tif (!supported.includes(\"tools\")) return undefined;\n\n\tconst architecture = isRecord(raw.architecture) ? raw.architecture : undefined;\n\tconst modality = typeof architecture?.modality === \"string\" ? architecture.modality : \"\";\n\tconst input: (\"text\" | \"image\")[] = [\"text\"];\n\tif (modality.includes(\"image\")) input.push(\"image\");\n\n\tconst pricing = isRecord(raw.pricing) ? raw.pricing : undefined;\n\tconst inputCost = roundCost((asFiniteNumber(pricing?.prompt) ?? 0) * 1_000_000);\n\tconst outputCost = roundCost((asFiniteNumber(pricing?.completion) ?? 0) * 1_000_000);\n\tconst cacheReadCost = roundCost((asFiniteNumber(pricing?.input_cache_read) ?? 0) * 1_000_000);\n\tconst cacheWriteCost = roundCost((asFiniteNumber(pricing?.input_cache_write) ?? 0) * 1_000_000);\n\n\tconst topProvider = isRecord(raw.top_provider) ? raw.top_provider : undefined;\n\tconst contextWindow = asFiniteNumber(topProvider?.context_length) ?? asFiniteNumber(raw.context_length);\n\tconst maxTokens = asFiniteNumber(topProvider?.max_completion_tokens) ?? asFiniteNumber(raw.max_completion_tokens);\n\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\treturn {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: supported.includes(\"reasoning\") || template.reasoning,\n\t\t\tinput,\n\t\t\tcost: {\n\t\t\t\tinput: inputCost,\n\t\t\t\toutput: outputCost,\n\t\t\t\tcacheRead: cacheReadCost,\n\t\t\t\tcacheWrite: cacheWriteCost,\n\t\t\t},\n\t\t\tcontextWindow: contextWindow ?? DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: maxTokens ?? DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: template.thinkingLevelMap,\n\t\t},\n\t\tsupplied: {\n\t\t\tcontextWindow: contextWindow !== undefined,\n\t\t\tmaxTokens: maxTokens !== undefined,\n\t\t\tinput: true,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t\tcost: pricing !== undefined,\n\t\t\treasoning: supported.includes(\"reasoning\"),\n\t\t},\n\t};\n}\n\nexport function discoverLiveModels(\n\tproviderId: string,\n\tpayload: unknown,\n\tbakedIn: readonly Model<Api>[],\n): LiveModelDiscovery[] {\n\tconst template = firstBakedInModel(bakedIn);\n\tif (!template) return [];\n\tconst rows = parseOpenAIModelsList(payload);\n\tconst discoveries: LiveModelDiscovery[] = [];\n\tfor (const raw of rows) {\n\t\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\t\tif (!id) continue;\n\t\tif (providerId === \"openrouter\") {\n\t\t\tconst mapped = mapOpenRouterModel(raw, { ...template, provider: providerId });\n\t\t\tif (mapped) discoveries.push(mapped);\n\t\t\tcontinue;\n\t\t}\n\t\tdiscoveries.push(synthesizeLiveModel(id, { ...template, provider: providerId }, raw));\n\t}\n\treturn discoveries;\n}\n\nexport function missingLiveFields(supplied: LiveFieldSupply): Array<\"contextWindow\" | \"maxTokens\" | \"input\"> {\n\tconst missing: Array<\"contextWindow\" | \"maxTokens\" | \"input\"> = [];\n\tif (!supplied.contextWindow) missing.push(\"contextWindow\");\n\tif (!supplied.maxTokens) missing.push(\"maxTokens\");\n\tif (!supplied.input) missing.push(\"input\");\n\treturn missing;\n}\n\nexport function isLiveModelIncomplete(discovery: LiveModelDiscovery, knownKeys: Set<string>): boolean {\n\tif (knownKeys.has(modelKey(discovery.model.provider, discovery.model.id))) return false;\n\treturn missingLiveFields(discovery.supplied).length > 0;\n}\n\nexport function collectIncompleteLiveModels(\n\tdiscoveries: readonly LiveModelDiscovery[],\n\tbakedIn: readonly Model<Api>[],\n\tknownKeys: Set<string>,\n): IncompleteLiveModel[] {\n\tconst apis = uniqueApis(bakedIn);\n\tconst incomplete: IncompleteLiveModel[] = [];\n\tfor (const discovery of discoveries) {\n\t\tif (!isLiveModelIncomplete(discovery, knownKeys)) continue;\n\t\tincomplete.push({\n\t\t\tprovider: discovery.model.provider,\n\t\t\tid: discovery.model.id,\n\t\t\tname: discovery.model.name,\n\t\t\tmissing: missingLiveFields(discovery.supplied),\n\t\t\tdraft: discovery.model,\n\t\t\tavailableApis: apis,\n\t\t});\n\t}\n\treturn incomplete;\n}\n\nexport function buildLiveOverlay(\n\tbakedIn: readonly Model<Api>[],\n\tdiscoveries: readonly LiveModelDiscovery[],\n): Model<Api>[] {\n\tconst bakedById = new Map(bakedIn.map((model) => [model.id, model]));\n\tconst overlay: Model<Api>[] = [];\n\tfor (const discovery of discoveries) {\n\t\tconst baked = bakedById.get(discovery.model.id);\n\t\tif (!baked) {\n\t\t\toverlay.push(discovery.model);\n\t\t\tcontinue;\n\t\t}\n\t\toverlay.push({\n\t\t\t...baked,\n\t\t\tname: discovery.supplied.name ? discovery.model.name : baked.name,\n\t\t\tcontextWindow: discovery.supplied.contextWindow ? discovery.model.contextWindow : baked.contextWindow,\n\t\t\tmaxTokens: discovery.supplied.maxTokens ? discovery.model.maxTokens : baked.maxTokens,\n\t\t\tinput: discovery.supplied.input ? discovery.model.input : baked.input,\n\t\t\tcost: discovery.supplied.cost ? discovery.model.cost : baked.cost,\n\t\t\treasoning: discovery.supplied.reasoning ? discovery.model.reasoning : baked.reasoning,\n\t\t});\n\t}\n\treturn overlay;\n}\n\nexport function describeIncomplete(model: IncompleteLiveModel): string {\n\tconst labels: string[] = [];\n\tfor (const field of model.missing) {\n\t\tif (field === \"contextWindow\") labels.push(\"context window\");\n\t\telse if (field === \"maxTokens\") labels.push(\"max tokens\");\n\t\telse labels.push(\"input types\");\n\t}\n\tlet missingText = \"metadata\";\n\tif (labels.length === 1) missingText = labels[0] ?? missingText;\n\telse if (labels.length === 2) missingText = `${labels[0]} and ${labels[1]}`;\n\telse if (labels.length > 2) missingText = `${labels.slice(0, -1).join(\", \")}, and ${labels[labels.length - 1]}`;\n\treturn `New model ${model.provider}/${model.id} — missing ${missingText}.`;\n}\n\nexport function parsePositiveInt(value: string | undefined, fallback: number): number {\n\tif (!value?.trim()) return fallback;\n\tconst parsed = Number(value.trim());\n\tif (!Number.isInteger(parsed) || parsed <= 0) return fallback;\n\treturn parsed;\n}\n\nexport interface IncompleteModelAnswers {\n\tcontextWindow?: number;\n\tmaxTokens?: number;\n\tinput?: (\"text\" | \"image\")[];\n\treasoning?: boolean;\n\tapi?: Api;\n}\n\nexport function applyIncompleteAnswers(draft: Model<Api>, answers: IncompleteModelAnswers): Model<Api> {\n\treturn {\n\t\t...draft,\n\t\tcontextWindow: answers.contextWindow ?? draft.contextWindow,\n\t\tmaxTokens: answers.maxTokens ?? draft.maxTokens,\n\t\tinput: answers.input ?? draft.input,\n\t\treasoning: answers.reasoning ?? draft.reasoning,\n\t\tapi: answers.api ?? draft.api,\n\t};\n}\n\nexport interface FetchLiveProviderModelsOptions {\n\tproviderId: string;\n\tbaseUrl: string;\n\tbakedIn: readonly Model<Api>[];\n\tcredential?: Credential;\n\tknownKeys: Set<string>;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n\tfetchImpl?: typeof fetch;\n}\n\nexport async function fetchLiveProviderModels(options: FetchLiveProviderModelsOptions): Promise<LiveCatalogResult> {\n\tconst empty: LiveCatalogResult = {\n\t\tproviderId: options.providerId,\n\t\tstatus: \"skipped\",\n\t\tdiscoveries: [],\n\t\tadded: 0,\n\t\ttotal: 0,\n\t\tincomplete: [],\n\t};\n\tconst template = firstBakedInModel(options.bakedIn);\n\tif (!template || !options.baseUrl) return empty;\n\n\tconst timeoutMs = options.timeoutMs ?? LIVE_CATALOG_TIMEOUT_MS;\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst timer = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\tconst onParentAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onParentAbort, { once: true });\n\tif (options.signal?.aborted) controller.abort();\n\n\ttry {\n\t\tconst fetchImpl = options.fetchImpl ?? fetch;\n\t\tconst response = await Promise.race([\n\t\t\tfetchImpl(modelsListUrl(options.baseUrl), {\n\t\t\t\theaders: {\n\t\t\t\t\taccept: \"application/json\",\n\t\t\t\t\t\"User-Agent\": getPiUserAgent(VERSION),\n\t\t\t\t\t...credentialAuthHeaders(options.credential),\n\t\t\t\t},\n\t\t\t\tsignal: controller.signal,\n\t\t\t}),\n\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\tconst abortError = new Error(\"The operation was aborted\");\n\t\t\t\tabortError.name = \"AbortError\";\n\t\t\t\tcontroller.signal.addEventListener(\"abort\", () => reject(abortError), { once: true });\n\t\t\t\tif (controller.signal.aborted) reject(abortError);\n\t\t\t}),\n\t\t]);\n\t\tif (!response.ok) {\n\t\t\treturn {\n\t\t\t\t...empty,\n\t\t\t\tstatus: \"error\",\n\t\t\t\terror: `HTTP ${response.status}`,\n\t\t\t};\n\t\t}\n\t\tconst discoveries = discoverLiveModels(options.providerId, await response.json(), options.bakedIn);\n\t\tconst bakedIds = new Set(options.bakedIn.map((model) => model.id));\n\t\tconst added = discoveries.filter((discovery) => !bakedIds.has(discovery.model.id)).length;\n\t\treturn {\n\t\t\tproviderId: options.providerId,\n\t\t\tstatus: \"ok\",\n\t\t\tdiscoveries,\n\t\t\tadded,\n\t\t\ttotal: discoveries.length,\n\t\t\tincomplete: collectIncompleteLiveModels(discoveries, options.bakedIn, options.knownKeys),\n\t\t};\n\t} catch (error) {\n\t\tif (options.signal?.aborted && !timedOut) return { ...empty, status: \"skipped\", error: \"aborted\" };\n\t\tif (timedOut || (error instanceof Error && error.name === \"AbortError\")) {\n\t\t\treturn { ...empty, status: \"timeout\", error: \"timed out\" };\n\t\t}\n\t\treturn {\n\t\t\t...empty,\n\t\t\tstatus: \"error\",\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t} finally {\n\t\tclearTimeout(timer);\n\t\toptions.signal?.removeEventListener(\"abort\", onParentAbort);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"live-catalog.js","sourceRoot":"","sources":["../../src/core/live-catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Api, type Credential, isOpenAiChatModel, type Model, parseOpenAiGptVersion } from \"@ashx-j/lunr-ai\";\nimport { codexModelsUrl, resolveCodexCatalogVersion } from \"@ashx-j/lunr-ai/catalog/codex\";\nimport { normalizeCatalogPricing } from \"@ashx-j/lunr-ai/catalog/metadata\";\nimport { VERSION } from \"../config.ts\";\nimport { getPiUserAgent } from \"../utils/pi-user-agent.ts\";\nimport { discoverCodexModels } from \"./codex-catalog.ts\";\nimport { modelKey } from \"./official-catalog.ts\";\n\nexport const LIVE_CATALOG_TIMEOUT_MS = 4000;\nexport const INCOMPLETE_PROMPT_CAP = 8;\nexport const DEFAULT_CONTEXT_WINDOW = 128000;\nexport const DEFAULT_MAX_TOKENS = 8192;\n\nexport const LIVE_LIST_PROVIDER_IDS = [\n\t\"openai-codex\",\n\t\"xai\",\n\t\"openrouter\",\n\t\"qwen-cloud\",\n\t\"qwen-cloud-cn\",\n\t\"groq\",\n\t\"openai\",\n\t\"deepseek\",\n] as const;\n\nexport type LiveListProviderId = (typeof LIVE_LIST_PROVIDER_IDS)[number];\n\nconst LIVE_LIST_PROVIDER_SET = new Set<string>(LIVE_LIST_PROVIDER_IDS);\n\nexport function isLiveListProvider(providerId: string): providerId is LiveListProviderId {\n\treturn LIVE_LIST_PROVIDER_SET.has(providerId);\n}\n\nexport interface LiveFieldSupply {\n\tcontextWindow: boolean;\n\tmaxTokens: boolean;\n\tinput: boolean;\n\tname: boolean;\n\tcost: boolean;\n\treasoning: boolean;\n}\n\nexport interface LiveModelDiscovery {\n\tmodel: Model<Api>;\n\tsupplied: LiveFieldSupply;\n}\n\nexport interface IncompleteLiveModel {\n\tprovider: string;\n\tid: string;\n\tname: string;\n\tmissing: Array<\"contextWindow\" | \"maxTokens\" | \"input\">;\n\tdraft: Model<Api>;\n\tavailableApis: Api[];\n}\n\nexport type LiveCatalogStatus = \"ok\" | \"timeout\" | \"error\" | \"skipped\";\n\nexport interface LiveCatalogResult {\n\tdiscoveryClientVersion?: string;\n\tproviderId: string;\n\tstatus: LiveCatalogStatus;\n\tdiscoveries: LiveModelDiscovery[];\n\tadded: number;\n\ttotal: number;\n\tincomplete: IncompleteLiveModel[];\n\terror?: string;\n}\n\nconst ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\nconst NONE_SUPPLIED: LiveFieldSupply = {\n\tcontextWindow: false,\n\tmaxTokens: false,\n\tinput: false,\n\tname: false,\n\tcost: false,\n\treasoning: false,\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asFiniteNumber(value: unknown): number | undefined {\n\tif (typeof value === \"number\" && Number.isFinite(value)) return value;\n\tif (typeof value === \"string\" && value.trim()) {\n\t\tconst parsed = Number(value);\n\t\tif (Number.isFinite(parsed)) return parsed;\n\t}\n\treturn undefined;\n}\n\nfunction roundCost(value: number): number {\n\treturn Number(value.toFixed(6));\n}\n\nexport function modelsListUrl(baseUrl: string): string {\n\treturn `${baseUrl.replace(/\\/+$/u, \"\")}/models`;\n}\n\nexport function credentialAuthHeaders(credential: Credential | undefined): Record<string, string> {\n\tif (!credential) return {};\n\tif (credential.type === \"api_key\" && credential.key) {\n\t\treturn { Authorization: `Bearer ${credential.key}` };\n\t}\n\tif (credential.type === \"oauth\" && typeof credential.access === \"string\" && credential.access) {\n\t\treturn { Authorization: `Bearer ${credential.access}` };\n\t}\n\treturn {};\n}\n\n/** OpenAI `{ data: [{ id, ... }] }` plus a bare array. */\nexport function parseOpenAIModelsList(value: unknown): Record<string, unknown>[] {\n\tconst entries = isRecord(value) && Array.isArray(value.data) ? value.data : Array.isArray(value) ? value : [];\n\tconst rows: Record<string, unknown>[] = [];\n\tfor (const entry of entries) {\n\t\tif (typeof entry === \"string\" && entry.trim()) {\n\t\t\trows.push({ id: entry.trim() });\n\t\t\tcontinue;\n\t\t}\n\t\tif (isRecord(entry) && typeof entry.id === \"string\" && entry.id.trim()) rows.push(entry);\n\t}\n\treturn rows;\n}\n\nexport function firstBakedInModel(models: readonly Model<Api>[]): Model<Api> | undefined {\n\treturn models[0];\n}\n\nexport function selectLiveTemplate(\n\tproviderId: string,\n\tid: string,\n\tbakedIn: readonly Model<Api>[],\n): Model<Api> | undefined {\n\tconst exact = bakedIn.find((model) => model.id === id);\n\tif (exact) return exact;\n\tconst version = parseOpenAiGptVersion(id);\n\tif (providerId !== \"openai\" || !version || version.major < 5 || isOpenAiChatModel(id)) {\n\t\treturn firstBakedInModel(bakedIn);\n\t}\n\tlet reasoning: Model<Api> | undefined;\n\tfor (const model of bakedIn) {\n\t\tif (model.reasoning && parseOpenAiGptVersion(model.id)) reasoning = model;\n\t}\n\treturn reasoning ?? firstBakedInModel(bakedIn);\n}\n\nexport function uniqueApis(models: readonly Model<Api>[]): Api[] {\n\tconst seen = new Set<Api>();\n\tconst apis: Api[] = [];\n\tfor (const model of models) {\n\t\tif (seen.has(model.api)) continue;\n\t\tseen.add(model.api);\n\t\tapis.push(model.api);\n\t}\n\treturn apis;\n}\n\nexport function synthesizeLiveModel(\n\tid: string,\n\ttemplate: Model<Api>,\n\traw: Record<string, unknown> = {},\n): LiveModelDiscovery {\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\tconst exact = id === template.id;\n\tconst discovery: LiveModelDiscovery = {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: template.reasoning,\n\t\t\tinput: exact ? template.input : [\"text\"],\n\t\t\tcost: ZERO_COST,\n\t\t\tcontextWindow: DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: exact ? template.thinkingLevelMap : undefined,\n\t\t\tcatalog: { source: \"provider\", supplied: typeof raw.name === \"string\" ? [\"name\"] : [], pricing: \"unknown\" },\n\t\t},\n\t\tsupplied: {\n\t\t\t...NONE_SUPPLIED,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t},\n\t};\n\tconst context = asFiniteNumber(raw.context_window ?? raw.context_length ?? raw.max_context_length);\n\tconst output = asFiniteNumber(raw.max_output_tokens ?? raw.max_completion_tokens);\n\tif (context && context > 0) {\n\t\tdiscovery.model.contextWindow = context;\n\t\tdiscovery.supplied.contextWindow = true;\n\t}\n\tif (output && output > 0) {\n\t\tdiscovery.model.maxTokens = output;\n\t\tdiscovery.supplied.maxTokens = true;\n\t}\n\tif (typeof raw.reasoning === \"boolean\") {\n\t\tdiscovery.model.reasoning = raw.reasoning;\n\t\tdiscovery.supplied.reasoning = true;\n\t}\n\tif (Array.isArray(raw.input_modalities)) {\n\t\tconst input = raw.input_modalities.filter(\n\t\t\t(value): value is \"text\" | \"image\" => value === \"text\" || value === \"image\",\n\t\t);\n\t\tif (input.length) {\n\t\t\tdiscovery.model.input = input;\n\t\t\tdiscovery.supplied.input = true;\n\t\t}\n\t}\n\tdiscovery.model.catalog!.supplied = Object.entries(discovery.supplied)\n\t\t.filter(([, value]) => value)\n\t\t.map(([field]) => field) as NonNullable<Model<Api>[\"catalog\"]>[\"supplied\"];\n\treturn discovery;\n}\n\n/** OpenRouter field mapping (tools filter, pricing × 1e6, context) from generate-models. */\nexport function mapOpenRouterModel(raw: Record<string, unknown>, template: Model<Api>): LiveModelDiscovery | undefined {\n\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\tif (!id) return undefined;\n\tconst supported = Array.isArray(raw.supported_parameters) ? raw.supported_parameters : [];\n\tif (!supported.includes(\"tools\")) return undefined;\n\n\tconst architecture = isRecord(raw.architecture) ? raw.architecture : undefined;\n\tconst modality = typeof architecture?.modality === \"string\" ? architecture.modality : \"\";\n\tconst input: (\"text\" | \"image\")[] = [\"text\"];\n\tif (modality.includes(\"image\")) input.push(\"image\");\n\n\tconst pricing = isRecord(raw.pricing) ? raw.pricing : undefined;\n\tconst inputCost = roundCost((asFiniteNumber(pricing?.prompt) ?? 0) * 1_000_000);\n\tconst outputCost = roundCost((asFiniteNumber(pricing?.completion) ?? 0) * 1_000_000);\n\tconst cacheReadCost = roundCost((asFiniteNumber(pricing?.input_cache_read) ?? 0) * 1_000_000);\n\tconst cacheWriteCost = roundCost((asFiniteNumber(pricing?.input_cache_write) ?? 0) * 1_000_000);\n\n\tconst topProvider = isRecord(raw.top_provider) ? raw.top_provider : undefined;\n\tconst contextWindow = asFiniteNumber(topProvider?.context_length) ?? asFiniteNumber(raw.context_length);\n\tconst maxTokens = asFiniteNumber(topProvider?.max_completion_tokens) ?? asFiniteNumber(raw.max_completion_tokens);\n\n\tconst name = typeof raw.name === \"string\" && raw.name.trim() ? raw.name.trim() : id;\n\treturn {\n\t\tmodel: {\n\t\t\tid,\n\t\t\tname,\n\t\t\tapi: template.api,\n\t\t\tprovider: template.provider,\n\t\t\tbaseUrl: template.baseUrl,\n\t\t\treasoning: supported.includes(\"reasoning\") || template.reasoning,\n\t\t\tinput,\n\t\t\tcost: {\n\t\t\t\tinput: inputCost,\n\t\t\t\toutput: outputCost,\n\t\t\t\tcacheRead: cacheReadCost,\n\t\t\t\tcacheWrite: cacheWriteCost,\n\t\t\t},\n\t\t\tcontextWindow: contextWindow ?? DEFAULT_CONTEXT_WINDOW,\n\t\t\tmaxTokens: maxTokens ?? DEFAULT_MAX_TOKENS,\n\t\t\tcompat: template.compat,\n\t\t\tthinkingLevelMap: template.thinkingLevelMap,\n\t\t},\n\t\tsupplied: {\n\t\t\tcontextWindow: contextWindow !== undefined,\n\t\t\tmaxTokens: maxTokens !== undefined,\n\t\t\tinput: true,\n\t\t\tname: typeof raw.name === \"string\" && raw.name.trim().length > 0,\n\t\t\tcost: asFiniteNumber(pricing?.prompt) !== undefined && asFiniteNumber(pricing?.completion) !== undefined,\n\t\t\treasoning: supported.includes(\"reasoning\"),\n\t\t},\n\t};\n}\n\nexport function discoverLiveModels(\n\tproviderId: string,\n\tpayload: unknown,\n\tbakedIn: readonly Model<Api>[],\n): LiveModelDiscovery[] {\n\tif (providerId === \"openai-codex\")\n\t\treturn discoverCodexModels(payload, bakedIn[0]?.baseUrl ?? \"https://chatgpt.com/backend-api\");\n\tconst fallback = firstBakedInModel(bakedIn);\n\tif (!fallback) return [];\n\tconst rows = parseOpenAIModelsList(payload);\n\tconst discoveries: LiveModelDiscovery[] = [];\n\tfor (const raw of rows) {\n\t\tconst id = typeof raw.id === \"string\" ? raw.id.trim() : \"\";\n\t\tif (!id) continue;\n\t\tif (\n\t\t\traw.tool_call === false ||\n\t\t\traw.type === \"embedding\" ||\n\t\t\t(providerId === \"openai\" &&\n\t\t\t\t/^(?:text-embedding-|tts-|whisper-|dall-e-|gpt-image-|gpt-audio|gpt-realtime|sora-|.*moderation)/i.test(id))\n\t\t)\n\t\t\tcontinue;\n\t\tconst template = { ...(selectLiveTemplate(providerId, id, bakedIn) ?? fallback), provider: providerId };\n\t\tif (providerId === \"openrouter\") {\n\t\t\tconst mapped = mapOpenRouterModel(raw, template);\n\t\t\tif (mapped) {\n\t\t\t\tmapped.model.catalog = {\n\t\t\t\t\tsource: \"provider\",\n\t\t\t\t\t...(!mapped.supplied.cost ? { pricing: \"unknown\" as const } : {}),\n\t\t\t\t\tsupplied: Object.entries(mapped.supplied)\n\t\t\t\t\t\t.filter(([, supplied]) => supplied)\n\t\t\t\t\t\t.map(([key]) => key) as NonNullable<Model<Api>[\"catalog\"]>[\"supplied\"],\n\t\t\t\t};\n\t\t\t\tmapped.model = normalizeCatalogPricing(mapped.model);\n\t\t\t\tif (mapped.model.catalog?.pricing === \"unknown\") mapped.supplied.cost = false;\n\t\t\t\tdiscoveries.push(mapped);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tdiscoveries.push(synthesizeLiveModel(id, template, raw));\n\t}\n\treturn discoveries;\n}\n\nexport function missingLiveFields(supplied: LiveFieldSupply): Array<\"contextWindow\" | \"maxTokens\" | \"input\"> {\n\tconst missing: Array<\"contextWindow\" | \"maxTokens\" | \"input\"> = [];\n\tif (!supplied.contextWindow) missing.push(\"contextWindow\");\n\tif (!supplied.maxTokens) missing.push(\"maxTokens\");\n\tif (!supplied.input) missing.push(\"input\");\n\treturn missing;\n}\n\nexport function isLiveModelIncomplete(discovery: LiveModelDiscovery, knownKeys: Set<string>): boolean {\n\tif (knownKeys.has(modelKey(discovery.model.provider, discovery.model.id))) return false;\n\treturn missingLiveFields(discovery.supplied).length > 0;\n}\n\nexport function collectIncompleteLiveModels(\n\tdiscoveries: readonly LiveModelDiscovery[],\n\tbakedIn: readonly Model<Api>[],\n\tknownKeys: Set<string>,\n): IncompleteLiveModel[] {\n\tconst apis = uniqueApis(bakedIn);\n\tconst incomplete: IncompleteLiveModel[] = [];\n\tfor (const discovery of discoveries) {\n\t\tif (!isLiveModelIncomplete(discovery, knownKeys)) continue;\n\t\tincomplete.push({\n\t\t\tprovider: discovery.model.provider,\n\t\t\tid: discovery.model.id,\n\t\t\tname: discovery.model.name,\n\t\t\tmissing: missingLiveFields(discovery.supplied),\n\t\t\tdraft: discovery.model,\n\t\t\tavailableApis: apis,\n\t\t});\n\t}\n\treturn incomplete;\n}\n\nexport function buildLiveOverlay(\n\tbakedIn: readonly Model<Api>[],\n\tdiscoveries: readonly LiveModelDiscovery[],\n): Model<Api>[] {\n\tconst bakedById = new Map(bakedIn.map((model) => [model.id, model]));\n\tconst overlay: Model<Api>[] = [];\n\tfor (const discovery of discoveries) {\n\t\tconst baked = bakedById.get(discovery.model.id);\n\t\tif (!baked) {\n\t\t\toverlay.push(discovery.model);\n\t\t\tcontinue;\n\t\t}\n\t\toverlay.push({\n\t\t\t...baked,\n\t\t\tcatalog: discovery.model.catalog,\n\t\t\tthinkingLevelMap: discovery.model.catalog?.supplied.includes(\"thinkingLevelMap\")\n\t\t\t\t? discovery.model.thinkingLevelMap\n\t\t\t\t: baked.thinkingLevelMap,\n\t\t\tname: discovery.supplied.name ? discovery.model.name : baked.name,\n\t\t\tcontextWindow: discovery.supplied.contextWindow ? discovery.model.contextWindow : baked.contextWindow,\n\t\t\tmaxTokens: discovery.supplied.maxTokens ? discovery.model.maxTokens : baked.maxTokens,\n\t\t\tinput: discovery.supplied.input ? discovery.model.input : baked.input,\n\t\t\tcost: discovery.supplied.cost ? discovery.model.cost : baked.cost,\n\t\t\treasoning: discovery.supplied.reasoning ? discovery.model.reasoning : baked.reasoning,\n\t\t});\n\t}\n\treturn overlay;\n}\n\nexport function describeIncomplete(model: IncompleteLiveModel): string {\n\tconst labels: string[] = [];\n\tfor (const field of model.missing) {\n\t\tif (field === \"contextWindow\") labels.push(\"context window\");\n\t\telse if (field === \"maxTokens\") labels.push(\"max tokens\");\n\t\telse labels.push(\"input types\");\n\t}\n\tlet missingText = \"metadata\";\n\tif (labels.length === 1) missingText = labels[0] ?? missingText;\n\telse if (labels.length === 2) missingText = `${labels[0]} and ${labels[1]}`;\n\telse if (labels.length > 2) missingText = `${labels.slice(0, -1).join(\", \")}, and ${labels[labels.length - 1]}`;\n\treturn `New model ${model.provider}/${model.id} — missing ${missingText}.`;\n}\n\nexport function parsePositiveInt(value: string | undefined, fallback: number): number {\n\tif (!value?.trim()) return fallback;\n\tconst parsed = Number(value.trim());\n\tif (!Number.isInteger(parsed) || parsed <= 0) return fallback;\n\treturn parsed;\n}\n\nexport interface IncompleteModelAnswers {\n\tcontextWindow?: number;\n\tmaxTokens?: number;\n\tinput?: (\"text\" | \"image\")[];\n\treasoning?: boolean;\n\tapi?: Api;\n}\n\nexport function applyIncompleteAnswers(draft: Model<Api>, answers: IncompleteModelAnswers): Model<Api> {\n\treturn {\n\t\t...draft,\n\t\tcontextWindow: answers.contextWindow ?? draft.contextWindow,\n\t\tmaxTokens: answers.maxTokens ?? draft.maxTokens,\n\t\tinput: answers.input ?? draft.input,\n\t\treasoning: answers.reasoning ?? draft.reasoning,\n\t\tapi: answers.api ?? draft.api,\n\t};\n}\n\nexport interface FetchLiveProviderModelsOptions {\n\tdiscoveryClientVersion?: string;\n\tproviderId: string;\n\tbaseUrl: string;\n\tbakedIn: readonly Model<Api>[];\n\tcredential?: Credential;\n\tknownKeys: Set<string>;\n\ttimeoutMs?: number;\n\tsignal?: AbortSignal;\n\tfetchImpl?: typeof fetch;\n}\n\nexport async function fetchLiveProviderModels(options: FetchLiveProviderModelsOptions): Promise<LiveCatalogResult> {\n\tconst empty: LiveCatalogResult = {\n\t\tproviderId: options.providerId,\n\t\tstatus: \"skipped\",\n\t\tdiscoveries: [],\n\t\tadded: 0,\n\t\ttotal: 0,\n\t\tincomplete: [],\n\t};\n\tconst template = firstBakedInModel(options.bakedIn);\n\tif ((!template && options.providerId !== \"openai-codex\") || !options.baseUrl) return empty;\n\n\tconst timeoutMs = options.timeoutMs ?? LIVE_CATALOG_TIMEOUT_MS;\n\tconst controller = new AbortController();\n\tlet timedOut = false;\n\tconst timer = setTimeout(() => {\n\t\ttimedOut = true;\n\t\tcontroller.abort();\n\t}, timeoutMs);\n\tconst onParentAbort = () => controller.abort();\n\toptions.signal?.addEventListener(\"abort\", onParentAbort, { once: true });\n\tif (options.signal?.aborted) controller.abort();\n\n\ttry {\n\t\tconst fetchImpl = options.fetchImpl ?? fetch;\n\t\tconst codex = options.providerId === \"openai-codex\";\n\t\tconst accountId =\n\t\t\toptions.credential?.type === \"oauth\" && typeof options.credential.accountId === \"string\"\n\t\t\t\t? options.credential.accountId\n\t\t\t\t: undefined;\n\t\tlet discoveryClientVersion = options.discoveryClientVersion;\n\t\tconst payload = await Promise.race([\n\t\t\t(async () => {\n\t\t\t\tif (codex)\n\t\t\t\t\tdiscoveryClientVersion = await resolveCodexCatalogVersion(\n\t\t\t\t\t\tfetchImpl,\n\t\t\t\t\t\tcontroller.signal,\n\t\t\t\t\t\tdiscoveryClientVersion,\n\t\t\t\t\t);\n\t\t\t\tconst response = await fetchImpl(\n\t\t\t\t\tcodex ? codexModelsUrl(options.baseUrl, discoveryClientVersion) : modelsListUrl(options.baseUrl),\n\t\t\t\t\t{\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\taccept: \"application/json\",\n\t\t\t\t\t\t\t\"User-Agent\": getPiUserAgent(VERSION),\n\t\t\t\t\t\t\t...credentialAuthHeaders(options.credential),\n\t\t\t\t\t\t\t...(accountId ? { \"ChatGPT-Account-ID\": accountId } : {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tif (!response.ok) throw new Error(`HTTP ${response.status}`);\n\t\t\t\treturn response.json();\n\t\t\t})(),\n\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\tconst abortError = new Error(\"The operation was aborted\");\n\t\t\t\tabortError.name = \"AbortError\";\n\t\t\t\tcontroller.signal.addEventListener(\"abort\", () => reject(abortError), { once: true });\n\t\t\t\tif (controller.signal.aborted) reject(abortError);\n\t\t\t}),\n\t\t]);\n\t\tconst discoveries = codex\n\t\t\t? discoverCodexModels(payload, options.baseUrl)\n\t\t\t: discoverLiveModels(options.providerId, payload, options.bakedIn);\n\t\tif (!discoveries.length) throw new Error(\"No usable models returned; retaining cached models\");\n\t\tconst bakedIds = new Set(options.bakedIn.map((model) => model.id));\n\t\tconst added = discoveries.filter((discovery) => !bakedIds.has(discovery.model.id)).length;\n\t\treturn {\n\t\t\tproviderId: options.providerId,\n\t\t\tdiscoveryClientVersion,\n\t\t\tstatus: \"ok\",\n\t\t\tdiscoveries,\n\t\t\tadded,\n\t\t\ttotal: discoveries.length,\n\t\t\tincomplete: collectIncompleteLiveModels(discoveries, options.bakedIn, options.knownKeys),\n\t\t};\n\t} catch (error) {\n\t\tif (options.signal?.aborted && !timedOut) return { ...empty, status: \"skipped\", error: \"aborted\" };\n\t\tif (timedOut || (error instanceof Error && error.name === \"AbortError\")) {\n\t\t\treturn { ...empty, status: \"timeout\", error: \"timed out\" };\n\t\t}\n\t\treturn {\n\t\t\t...empty,\n\t\t\tstatus: \"error\",\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t} finally {\n\t\tclearTimeout(timer);\n\t\toptions.signal?.removeEventListener(\"abort\", onParentAbort);\n\t}\n}\n"]}
|
|
@@ -60,6 +60,8 @@ export declare class ModelRuntime implements Models {
|
|
|
60
60
|
private lastOfficial;
|
|
61
61
|
private catalogRefresh;
|
|
62
62
|
private catalogRefreshAllowsNetwork;
|
|
63
|
+
private nextAutomaticRefresh;
|
|
64
|
+
private automaticRefreshIdentity;
|
|
63
65
|
private readonly grokHome;
|
|
64
66
|
private constructor();
|
|
65
67
|
static create(options?: CreateModelRuntimeOptions): Promise<ModelRuntime>;
|
|
@@ -70,6 +72,7 @@ export declare class ModelRuntime implements Models {
|
|
|
70
72
|
private bakedInModels;
|
|
71
73
|
private rebuildProviders;
|
|
72
74
|
private updateModelSnapshot;
|
|
75
|
+
private isCatalogModelAvailable;
|
|
73
76
|
private listStoredProviderIds;
|
|
74
77
|
/** `/model` lists stored creds + models.json/extension keys, never ambient envApiKeyAuth. */
|
|
75
78
|
private configuredProviderIds;
|
|
@@ -119,6 +122,11 @@ export declare class ModelRuntime implements Models {
|
|
|
119
122
|
refresh(options?: ModelsRefreshOptions): Promise<CatalogRefreshResult>;
|
|
120
123
|
private executeCatalogRefresh;
|
|
121
124
|
getLastCatalogRefresh(): CatalogRefreshResult;
|
|
125
|
+
/** Called after first paint and by the picker; explicit /refresh always bypasses this gate. */
|
|
126
|
+
refreshIfStale(options?: {
|
|
127
|
+
signal?: AbortSignal;
|
|
128
|
+
}): Promise<CatalogRefreshResult>;
|
|
129
|
+
private scopeFor;
|
|
122
130
|
persistUserModels(rows: readonly UserModelEntry[]): void;
|
|
123
131
|
private refreshOfficialCatalog;
|
|
124
132
|
private restoreLiveCatalogs;
|