@openeryc/pi-coding-agent 0.75.56 → 0.75.57
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 +9 -0
- package/dist/core/keybindings.d.ts +10 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +8 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-registry.d.ts +6 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +38 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/modes/interactive/components/model-hub.d.ts +2 -0
- package/dist/modes/interactive/components/model-hub.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-hub.js +30 -8
- package/dist/modes/interactive/components/model-hub.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +26 -24
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/models.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/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/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-registry.js","sourceRoot":"","sources":["../../src/core/model-registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model registry - manages built-in and custom models, provides API key resolution.\n */\n\nimport {\n\ttype AnthropicMessagesCompat,\n\ttype Api,\n\ttype AssistantMessageEventStream,\n\ttype Context,\n\tgetModels,\n\tgetProviders,\n\ttype KnownProvider,\n\ttype Model,\n\ttype OAuthProviderInterface,\n\ttype OpenAICompletionsCompat,\n\ttype OpenAIResponsesCompat,\n\tregisterApiProvider,\n\tresetApiProviders,\n\ttype SimpleStreamOptions,\n} from \"@openeryc/pi-ai\";\nimport { registerOAuthProvider, resetOAuthProviders } from \"@openeryc/pi-ai/oauth\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { Compile } from \"typebox/compile\";\nimport type { TLocalizedValidationError } from \"typebox/error\";\nimport { getAgentDir } from \"../config.ts\";\nimport type { AuthStatus, AuthStorage, OpenAICompatibleProviderInfo } from \"./auth-storage.ts\";\nimport { BUILT_IN_PROVIDER_DISPLAY_NAMES } from \"./provider-display-names.ts\";\nimport {\n\tclearConfigValueCache,\n\tresolveConfigValueOrThrow,\n\tresolveConfigValueUncached,\n\tresolveHeadersOrThrow,\n} from \"./resolve-config-value.ts\";\n\n// Schema for OpenRouter routing preferences\nconst PercentileCutoffsSchema = Type.Object({\n\tp50: Type.Optional(Type.Number()),\n\tp75: Type.Optional(Type.Number()),\n\tp90: Type.Optional(Type.Number()),\n\tp99: Type.Optional(Type.Number()),\n});\n\nconst OpenRouterRoutingSchema = Type.Object({\n\tallow_fallbacks: Type.Optional(Type.Boolean()),\n\trequire_parameters: Type.Optional(Type.Boolean()),\n\tdata_collection: Type.Optional(Type.Union([Type.Literal(\"deny\"), Type.Literal(\"allow\")])),\n\tzdr: Type.Optional(Type.Boolean()),\n\tenforce_distillable_text: Type.Optional(Type.Boolean()),\n\torder: Type.Optional(Type.Array(Type.String())),\n\tonly: Type.Optional(Type.Array(Type.String())),\n\tignore: Type.Optional(Type.Array(Type.String())),\n\tquantizations: Type.Optional(Type.Array(Type.String())),\n\tsort: Type.Optional(\n\t\tType.Union([\n\t\t\tType.String(),\n\t\t\tType.Object({\n\t\t\t\tby: Type.Optional(Type.String()),\n\t\t\t\tpartition: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n\t\t\t}),\n\t\t]),\n\t),\n\tmax_price: Type.Optional(\n\t\tType.Object({\n\t\t\tprompt: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\tcompletion: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\timage: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\taudio: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\trequest: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t}),\n\t),\n\tpreferred_min_throughput: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),\n\tpreferred_max_latency: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),\n});\n\n// Schema for Vercel AI Gateway routing preferences\nconst VercelGatewayRoutingSchema = Type.Object({\n\tonly: Type.Optional(Type.Array(Type.String())),\n\torder: Type.Optional(Type.Array(Type.String())),\n});\n\n// Schema for thinking level support and provider-specific values\nconst ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);\nconst ThinkingLevelMapSchema = Type.Object({\n\toff: Type.Optional(ThinkingLevelMapValueSchema),\n\tminimal: Type.Optional(ThinkingLevelMapValueSchema),\n\tlow: Type.Optional(ThinkingLevelMapValueSchema),\n\tmedium: Type.Optional(ThinkingLevelMapValueSchema),\n\thigh: Type.Optional(ThinkingLevelMapValueSchema),\n\txhigh: Type.Optional(ThinkingLevelMapValueSchema),\n});\n\nconst OpenAICompletionsCompatSchema = Type.Object({\n\tsupportsStore: Type.Optional(Type.Boolean()),\n\tsupportsDeveloperRole: Type.Optional(Type.Boolean()),\n\tsupportsReasoningEffort: Type.Optional(Type.Boolean()),\n\tsupportsUsageInStreaming: Type.Optional(Type.Boolean()),\n\tmaxTokensField: Type.Optional(Type.Union([Type.Literal(\"max_completion_tokens\"), Type.Literal(\"max_tokens\")])),\n\trequiresToolResultName: Type.Optional(Type.Boolean()),\n\trequiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),\n\trequiresThinkingAsText: Type.Optional(Type.Boolean()),\n\trequiresReasoningContentOnAssistantMessages: Type.Optional(Type.Boolean()),\n\tthinkingFormat: Type.Optional(\n\t\tType.Union([\n\t\t\tType.Literal(\"openai\"),\n\t\t\tType.Literal(\"openrouter\"),\n\t\t\tType.Literal(\"together\"),\n\t\t\tType.Literal(\"deepseek\"),\n\t\t\tType.Literal(\"zai\"),\n\t\t\tType.Literal(\"qwen\"),\n\t\t\tType.Literal(\"qwen-chat-template\"),\n\t\t]),\n\t),\n\tcacheControlFormat: Type.Optional(Type.Literal(\"anthropic\")),\n\topenRouterRouting: Type.Optional(OpenRouterRoutingSchema),\n\tvercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),\n\tsupportsStrictMode: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n});\n\nconst OpenAIResponsesCompatSchema = Type.Object({\n\tsendSessionIdHeader: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n});\n\nconst AnthropicMessagesCompatSchema = Type.Object({\n\tsupportsEagerToolInputStreaming: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n});\n\nconst ProviderCompatSchema = Type.Union([\n\tOpenAICompletionsCompatSchema,\n\tOpenAIResponsesCompatSchema,\n\tAnthropicMessagesCompatSchema,\n]);\n\n// Schema for custom model definition\n// Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)\nconst ModelDefinitionSchema = Type.Object({\n\tid: Type.String({ minLength: 1 }),\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\tapi: Type.Optional(Type.String({ minLength: 1 })),\n\tbaseUrl: Type.Optional(Type.String({ minLength: 1 })),\n\treasoning: Type.Optional(Type.Boolean()),\n\tthinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),\n\tinput: Type.Optional(Type.Array(Type.Union([Type.Literal(\"text\"), Type.Literal(\"image\")]))),\n\tcost: Type.Optional(\n\t\tType.Object({\n\t\t\tinput: Type.Number(),\n\t\t\toutput: Type.Number(),\n\t\t\tcacheRead: Type.Number(),\n\t\t\tcacheWrite: Type.Number(),\n\t\t}),\n\t),\n\tcontextWindow: Type.Optional(Type.Number()),\n\tmaxTokens: Type.Optional(Type.Number()),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n});\n\n// Schema for per-model overrides (all fields optional, merged with built-in model)\nconst ModelOverrideSchema = Type.Object({\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\treasoning: Type.Optional(Type.Boolean()),\n\tthinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),\n\tinput: Type.Optional(Type.Array(Type.Union([Type.Literal(\"text\"), Type.Literal(\"image\")]))),\n\tcost: Type.Optional(\n\t\tType.Object({\n\t\t\tinput: Type.Optional(Type.Number()),\n\t\t\toutput: Type.Optional(Type.Number()),\n\t\t\tcacheRead: Type.Optional(Type.Number()),\n\t\t\tcacheWrite: Type.Optional(Type.Number()),\n\t\t}),\n\t),\n\tcontextWindow: Type.Optional(Type.Number()),\n\tmaxTokens: Type.Optional(Type.Number()),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n});\n\ntype ModelOverride = Static<typeof ModelOverrideSchema>;\n\nconst ProviderConfigSchema = Type.Object({\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\tbaseUrl: Type.Optional(Type.String({ minLength: 1 })),\n\tapiKey: Type.Optional(Type.String({ minLength: 1 })),\n\tapi: Type.Optional(Type.String({ minLength: 1 })),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n\tauthHeader: Type.Optional(Type.Boolean()),\n\tmodels: Type.Optional(Type.Array(ModelDefinitionSchema)),\n\tmodelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema)),\n});\n\nconst ModelsConfigSchema = Type.Object({\n\tproviders: Type.Record(Type.String(), ProviderConfigSchema),\n});\n\nconst validateModelsConfig = Compile(ModelsConfigSchema);\n\ntype ModelsConfig = Static<typeof ModelsConfigSchema>;\ntype ProviderConfig = Static<typeof ProviderConfigSchema>;\n\n/** Writable provider config for models.json (subset used by TUI Manage). */\nexport type ModelsJsonProviderWrite = {\n\tbaseUrl?: string;\n\tapiKey?: string;\n\tapi?: string;\n\theaders?: Record<string, string>;\n\tauthHeader?: boolean;\n\tcompat?: Static<typeof ProviderCompatSchema>;\n\tmodels?: Array<{\n\t\tid: string;\n\t\tname?: string;\n\t\tapi?: string;\n\t\treasoning?: boolean;\n\t\tinput?: Array<\"text\" | \"image\">;\n\t\tcontextWindow?: number;\n\t\tmaxTokens?: number;\n\t\tcost?: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\t}>;\n};\n\nexport type ModelsJsonCustomProviderInfo = {\n\tname: string;\n\tbaseUrl?: string;\n\tapi?: string;\n\thasApiKey: boolean;\n\tmodelIds: string[];\n\t/** True when this provider name is a built-in (override/merge), not purely custom. */\n\tisBuiltIn: boolean;\n};\n\nfunction formatValidationPath(error: TLocalizedValidationError): string {\n\tif (error.keyword === \"required\") {\n\t\tconst requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties;\n\t\tconst requiredProperty = requiredProperties?.[0];\n\t\tif (requiredProperty) {\n\t\t\tconst basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\t\t\treturn basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n\t\t}\n\t}\n\tconst path = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\treturn path || \"root\";\n}\n\n/** Strip `//` line comments and trailing commas from JSON, leaving string literals untouched. */\nfunction stripJsonComments(input: string): string {\n\treturn input\n\t\t.replace(/\"(?:\\\\.|[^\"\\\\])*\"|\\/\\/[^\\n]*/g, (m) => (m[0] === '\"' ? m : \"\"))\n\t\t.replace(/\"(?:\\\\.|[^\"\\\\])*\"|,(\\s*[}\\]])/g, (m, tail) => tail ?? (m[0] === '\"' ? m : \"\"));\n}\n\n/** Provider override config (baseUrl, compat) without request auth/headers */\ninterface ProviderOverride {\n\tbaseUrl?: string;\n\tcompat?: Model<Api>[\"compat\"];\n}\n\ninterface ProviderRequestConfig {\n\tapiKey?: string;\n\theaders?: Record<string, string>;\n\tauthHeader?: boolean;\n}\n\nexport type ResolvedRequestAuth =\n\t| {\n\t\t\tok: true;\n\t\t\tapiKey?: string;\n\t\t\theaders?: Record<string, string>;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\terror: string;\n\t };\n\n/** Result of loading custom models from models.json */\ninterface CustomModelsResult {\n\tmodels: Model<Api>[];\n\t/** Providers with baseUrl/headers/apiKey overrides for built-in models */\n\toverrides: Map<string, ProviderOverride>;\n\t/** Per-model overrides: provider -> modelId -> override */\n\tmodelOverrides: Map<string, Map<string, ModelOverride>>;\n\terror: string | undefined;\n}\n\nfunction emptyCustomModelsResult(error?: string): CustomModelsResult {\n\treturn { models: [], overrides: new Map(), modelOverrides: new Map(), error };\n}\n\nfunction mergeCompat(\n\tbaseCompat: Model<Api>[\"compat\"],\n\toverrideCompat: ModelOverride[\"compat\"],\n): Model<Api>[\"compat\"] | undefined {\n\tif (!overrideCompat) return baseCompat;\n\n\tconst base = baseCompat as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat | undefined;\n\tconst override = overrideCompat as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat;\n\tconst merged = { ...base, ...override } as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat;\n\n\tconst baseCompletions = base as OpenAICompletionsCompat | undefined;\n\tconst overrideCompletions = override as OpenAICompletionsCompat;\n\tconst mergedCompletions = merged as OpenAICompletionsCompat;\n\n\tif (baseCompletions?.openRouterRouting || overrideCompletions.openRouterRouting) {\n\t\tmergedCompletions.openRouterRouting = {\n\t\t\t...baseCompletions?.openRouterRouting,\n\t\t\t...overrideCompletions.openRouterRouting,\n\t\t};\n\t}\n\n\tif (baseCompletions?.vercelGatewayRouting || overrideCompletions.vercelGatewayRouting) {\n\t\tmergedCompletions.vercelGatewayRouting = {\n\t\t\t...baseCompletions?.vercelGatewayRouting,\n\t\t\t...overrideCompletions.vercelGatewayRouting,\n\t\t};\n\t}\n\n\treturn merged as Model<Api>[\"compat\"];\n}\n\n/**\n * Deep merge a model override into a model.\n * Handles nested objects (cost, compat) by merging rather than replacing.\n */\nfunction applyModelOverride(model: Model<Api>, override: ModelOverride): Model<Api> {\n\tconst result = { ...model };\n\n\t// Simple field overrides\n\tif (override.name !== undefined) result.name = override.name;\n\tif (override.reasoning !== undefined) result.reasoning = override.reasoning;\n\tif (override.thinkingLevelMap !== undefined) {\n\t\tresult.thinkingLevelMap = { ...model.thinkingLevelMap, ...override.thinkingLevelMap };\n\t}\n\tif (override.input !== undefined) result.input = override.input as (\"text\" | \"image\")[];\n\tif (override.contextWindow !== undefined) result.contextWindow = override.contextWindow;\n\tif (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;\n\n\t// Merge cost (partial override)\n\tif (override.cost) {\n\t\tresult.cost = {\n\t\t\tinput: override.cost.input ?? model.cost.input,\n\t\t\toutput: override.cost.output ?? model.cost.output,\n\t\t\tcacheRead: override.cost.cacheRead ?? model.cost.cacheRead,\n\t\t\tcacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,\n\t\t};\n\t}\n\n\t// Deep merge compat\n\tresult.compat = mergeCompat(model.compat, override.compat);\n\n\treturn result;\n}\n\n/** Clear the config value command cache. Exported for testing. */\nexport const clearApiKeyCache = clearConfigValueCache;\n\n/**\n * Model registry - loads and manages models, resolves API keys via AuthStorage.\n */\nexport class ModelRegistry {\n\tprivate models: Model<Api>[] = [];\n\tprivate providerRequestConfigs: Map<string, ProviderRequestConfig> = new Map();\n\tprivate modelRequestHeaders: Map<string, Record<string, string>> = new Map();\n\tprivate registeredProviders: Map<string, ProviderConfigInput> = new Map();\n\tprivate loadError: string | undefined = undefined;\n\treadonly authStorage: AuthStorage;\n\tprivate modelsJsonPath: string | undefined;\n\n\tprivate constructor(authStorage: AuthStorage, modelsJsonPath: string | undefined) {\n\t\tthis.authStorage = authStorage;\n\t\tthis.modelsJsonPath = modelsJsonPath;\n\t\tthis.loadModels();\n\t}\n\n\tstatic create(authStorage: AuthStorage, modelsJsonPath: string = join(getAgentDir(), \"models.json\")): ModelRegistry {\n\t\treturn new ModelRegistry(authStorage, modelsJsonPath);\n\t}\n\n\tstatic inMemory(authStorage: AuthStorage): ModelRegistry {\n\t\treturn new ModelRegistry(authStorage, undefined);\n\t}\n\n\t/**\n\t * Reload models from disk (built-in + custom from models.json).\n\t */\n\trefresh(): void {\n\t\tthis.providerRequestConfigs.clear();\n\t\tthis.modelRequestHeaders.clear();\n\t\tthis.loadError = undefined;\n\n\t\t// Ensure dynamic API/OAuth registrations are rebuilt from current provider state.\n\t\tresetApiProviders();\n\t\tresetOAuthProviders();\n\n\t\tthis.loadModels();\n\n\t\tfor (const [providerName, config] of this.registeredProviders.entries()) {\n\t\t\tthis.applyProviderConfig(providerName, config);\n\t\t}\n\t}\n\n\t/**\n\t * Get any error from loading models.json (undefined if no error).\n\t */\n\tgetError(): string | undefined {\n\t\treturn this.loadError;\n\t}\n\n\t/** Path to models.json if this registry is file-backed. */\n\tgetModelsJsonPath(): string | undefined {\n\t\treturn this.modelsJsonPath;\n\t}\n\n\t/**\n\t * List providers defined in models.json (custom + overrides).\n\t * Returns empty when no models.json or on parse error.\n\t */\n\tlistModelsJsonProviders(): ModelsJsonCustomProviderInfo[] {\n\t\tconst config = this.readModelsConfigFile();\n\t\tif (!config) return [];\n\t\tconst builtIn = new Set<string>(getProviders());\n\t\treturn Object.entries(config.providers).map(([name, providerConfig]) => ({\n\t\t\tname,\n\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\tapi: providerConfig.api,\n\t\t\thasApiKey: !!providerConfig.apiKey,\n\t\t\tmodelIds: (providerConfig.models ?? []).map((m) => m.id),\n\t\t\tisBuiltIn: builtIn.has(name),\n\t\t}));\n\t}\n\n\t/**\n\t * Upsert a provider entry in models.json, then refresh the registry.\n\t * Rewrites the file as pretty JSON (comments/trailing commas are not preserved).\n\t */\n\tupsertProviderInModelsJson(providerName: string, config: ModelsJsonProviderWrite): void {\n\t\tif (!this.modelsJsonPath) {\n\t\t\tthrow new Error(\"ModelRegistry is not file-backed; cannot write models.json\");\n\t\t}\n\t\tconst trimmed = providerName.trim();\n\t\tif (!trimmed) {\n\t\t\tthrow new Error(\"Provider name cannot be empty\");\n\t\t}\n\n\t\tconst existing = this.readModelsConfigFile() ?? { providers: {} };\n\t\tconst prev = existing.providers[trimmed] ?? {};\n\t\tconst merged: ProviderConfig = {\n\t\t\t...prev,\n\t\t\t...config,\n\t\t\tmodels: config.models !== undefined ? config.models : prev.models,\n\t\t};\n\n\t\t// Drop empty optional objects so schema stays clean\n\t\tif (merged.models && merged.models.length === 0) {\n\t\t\tdelete merged.models;\n\t\t}\n\n\t\tconst nextConfig: ModelsConfig = {\n\t\t\tproviders: {\n\t\t\t\t...existing.providers,\n\t\t\t\t[trimmed]: merged,\n\t\t\t},\n\t\t};\n\n\t\tthis.validateConfig(nextConfig);\n\t\tthis.writeModelsConfigFile(nextConfig);\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Remove a provider entry from models.json, then refresh.\n\t */\n\tremoveProviderFromModelsJson(providerName: string): void {\n\t\tif (!this.modelsJsonPath) {\n\t\t\tthrow new Error(\"ModelRegistry is not file-backed; cannot write models.json\");\n\t\t}\n\t\tconst existing = this.readModelsConfigFile();\n\t\tif (!existing?.providers[providerName]) {\n\t\t\tthrow new Error(`Provider \"${providerName}\" is not defined in models.json`);\n\t\t}\n\t\tconst { [providerName]: _removed, ...rest } = existing.providers;\n\t\tconst nextConfig: ModelsConfig = { providers: rest };\n\t\tthis.writeModelsConfigFile(nextConfig);\n\t\tthis.refresh();\n\t}\n\n\tprivate readModelsConfigFile(): ModelsConfig | undefined {\n\t\tif (!this.modelsJsonPath || !existsSync(this.modelsJsonPath)) {\n\t\t\treturn undefined;\n\t\t}\n\t\ttry {\n\t\t\tconst content = readFileSync(this.modelsJsonPath, \"utf-8\");\n\t\t\tconst parsed = JSON.parse(stripJsonComments(content)) as unknown;\n\t\t\tif (!validateModelsConfig.Check(parsed)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn parsed as ModelsConfig;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate writeModelsConfigFile(config: ModelsConfig): void {\n\t\tif (!this.modelsJsonPath) {\n\t\t\tthrow new Error(\"ModelRegistry is not file-backed; cannot write models.json\");\n\t\t}\n\t\tconst dir = dirname(this.modelsJsonPath);\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t}\n\t\twriteFileSync(this.modelsJsonPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n\t}\n\n\tprivate loadModels(): void {\n\t\t// Load custom models and overrides from models.json\n\t\tconst {\n\t\t\tmodels: customModels,\n\t\t\toverrides,\n\t\t\tmodelOverrides,\n\t\t\terror,\n\t\t} = this.modelsJsonPath ? this.loadCustomModels(this.modelsJsonPath) : emptyCustomModelsResult();\n\n\t\tif (error) {\n\t\t\tthis.loadError = error;\n\t\t\t// Keep built-in models even if custom models failed to load\n\t\t}\n\n\t\tconst builtInModels = this.loadBuiltInModels(overrides, modelOverrides);\n\t\tlet combined = this.mergeCustomModels(builtInModels, customModels);\n\n\t\t// Let OAuth providers modify their models (e.g., update baseUrl)\n\t\tfor (const oauthProvider of this.authStorage.getOAuthProviders()) {\n\t\t\tconst cred = this.authStorage.get(oauthProvider.id);\n\t\t\tif (cred?.type === \"oauth\" && oauthProvider.modifyModels) {\n\t\t\t\tcombined = oauthProvider.modifyModels(combined, cred);\n\t\t\t}\n\t\t}\n\n\t\tthis.models = combined;\n\n\t\t// Register OpenAI-compatible providers stored in auth.json\n\t\tthis.loadOpenAICompatibleProviders();\n\t}\n\n\t/** Load built-in models and apply provider/model overrides */\n\tprivate loadBuiltInModels(\n\t\toverrides: Map<string, ProviderOverride>,\n\t\tmodelOverrides: Map<string, Map<string, ModelOverride>>,\n\t): Model<Api>[] {\n\t\treturn getProviders().flatMap((provider) => {\n\t\t\tconst models = getModels(provider as KnownProvider) as Model<Api>[];\n\t\t\tconst providerOverride = overrides.get(provider);\n\t\t\tconst perModelOverrides = modelOverrides.get(provider);\n\n\t\t\treturn models.map((m) => {\n\t\t\t\tlet model = m;\n\n\t\t\t\t// Apply provider-level baseUrl/headers/compat override\n\t\t\t\tif (providerOverride) {\n\t\t\t\t\tmodel = {\n\t\t\t\t\t\t...model,\n\t\t\t\t\t\tbaseUrl: providerOverride.baseUrl ?? model.baseUrl,\n\t\t\t\t\t\tcompat: mergeCompat(model.compat, providerOverride.compat),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Apply per-model override\n\t\t\t\tconst modelOverride = perModelOverrides?.get(m.id);\n\t\t\t\tif (modelOverride) {\n\t\t\t\t\tmodel = applyModelOverride(model, modelOverride);\n\t\t\t\t}\n\n\t\t\t\treturn model;\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Load OpenAI-compatible providers stored in auth.json (type \"openai_compatible\").\n\t * These are registered as dynamic providers with api=\"openai-completions\".\n\t */\n\tprivate loadOpenAICompatibleProviders(): void {\n\t\tconst providers = this.authStorage.getOpenAICompatibleProviders();\n\t\tfor (const [providerName, info] of Object.entries(providers)) {\n\t\t\tthis.storeProviderRequestConfig(providerName, { apiKey: info.key });\n\n\t\t\tfor (const modelDef of info.models) {\n\t\t\t\t// Avoid duplicates if already registered via other mechanism\n\t\t\t\tconst exists = this.models.some((m) => m.provider === providerName && m.id === modelDef.id);\n\t\t\t\tif (exists) continue;\n\n\t\t\t\tthis.models.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name,\n\t\t\t\t\tapi: \"openai-completions\" as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl: info.baseUrl,\n\t\t\t\t\treasoning: false,\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\t\t\t\tcontextWindow: 128000,\n\t\t\t\t\tmaxTokens: 16384,\n\t\t\t\t\theaders: undefined,\n\t\t\t\t\tcompat: info.compat,\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Merge custom models into built-in list by provider+id (custom wins on conflicts). */\n\tprivate mergeCustomModels(builtInModels: Model<Api>[], customModels: Model<Api>[]): Model<Api>[] {\n\t\tconst merged = [...builtInModels];\n\t\tfor (const customModel of customModels) {\n\t\t\tconst existingIndex = merged.findIndex((m) => m.provider === customModel.provider && m.id === customModel.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tmerged[existingIndex] = customModel;\n\t\t\t} else {\n\t\t\t\tmerged.push(customModel);\n\t\t\t}\n\t\t}\n\t\treturn merged;\n\t}\n\n\tprivate loadCustomModels(modelsJsonPath: string): CustomModelsResult {\n\t\tif (!existsSync(modelsJsonPath)) {\n\t\t\treturn emptyCustomModelsResult();\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(modelsJsonPath, \"utf-8\");\n\t\t\tconst parsed = JSON.parse(stripJsonComments(content)) as unknown;\n\n\t\t\tif (!validateModelsConfig.Check(parsed)) {\n\t\t\t\tconst errors =\n\t\t\t\t\tvalidateModelsConfig\n\t\t\t\t\t\t.Errors(parsed)\n\t\t\t\t\t\t.map((error) => ` - ${formatValidationPath(error)}: ${error.message}`)\n\t\t\t\t\t\t.join(\"\\n\") || \"Unknown schema error\";\n\t\t\t\treturn emptyCustomModelsResult(`Invalid models.json schema:\\n${errors}\\n\\nFile: ${modelsJsonPath}`);\n\t\t\t}\n\n\t\t\tconst config = parsed as ModelsConfig;\n\n\t\t\t// Additional validation\n\t\t\tthis.validateConfig(config);\n\n\t\t\tconst overrides = new Map<string, ProviderOverride>();\n\t\t\tconst modelOverrides = new Map<string, Map<string, ModelOverride>>();\n\n\t\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\t\tif (providerConfig.baseUrl || providerConfig.compat) {\n\t\t\t\t\toverrides.set(providerName, {\n\t\t\t\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\t\t\t\tcompat: providerConfig.compat,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tthis.storeProviderRequestConfig(providerName, providerConfig);\n\n\t\t\t\tif (providerConfig.modelOverrides) {\n\t\t\t\t\tmodelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));\n\t\t\t\t\tfor (const [modelId, modelOverride] of Object.entries(providerConfig.modelOverrides)) {\n\t\t\t\t\t\tthis.storeModelHeaders(providerName, modelId, modelOverride.headers);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { models: this.parseModels(config), overrides, modelOverrides, error: undefined };\n\t\t} catch (error) {\n\t\t\tif (error instanceof SyntaxError) {\n\t\t\t\treturn emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\\n\\nFile: ${modelsJsonPath}`);\n\t\t\t}\n\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t`Failed to load models.json: ${error instanceof Error ? error.message : error}\\n\\nFile: ${modelsJsonPath}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate validateConfig(config: ModelsConfig): void {\n\t\tconst builtInProviders = new Set<string>(getProviders());\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst isBuiltIn = builtInProviders.has(providerName);\n\t\t\tconst hasProviderApi = !!providerConfig.api;\n\t\t\tconst models = providerConfig.models ?? [];\n\t\t\tconst hasModelOverrides =\n\t\t\t\tproviderConfig.modelOverrides && Object.keys(providerConfig.modelOverrides).length > 0;\n\n\t\t\tif (models.length === 0) {\n\t\t\t\t// Override-only config: needs baseUrl, headers, compat, modelOverrides, or some combination.\n\t\t\t\tif (!providerConfig.baseUrl && !providerConfig.headers && !providerConfig.compat && !hasModelOverrides) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Provider ${providerName}: must specify \"baseUrl\", \"headers\", \"compat\", \"modelOverrides\", or \"models\".`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (!isBuiltIn) {\n\t\t\t\t// Non-built-in providers with custom models require endpoint + auth.\n\t\t\t\tif (!providerConfig.baseUrl) {\n\t\t\t\t\tthrow new Error(`Provider ${providerName}: \"baseUrl\" is required when defining custom models.`);\n\t\t\t\t}\n\t\t\t\tif (!providerConfig.apiKey) {\n\t\t\t\t\tthrow new Error(`Provider ${providerName}: \"apiKey\" is required when defining custom models.`);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Built-in providers with custom models: baseUrl/apiKey/api are optional,\n\t\t\t// inherited from built-in models. Auth comes from env vars / auth storage.\n\n\t\t\tfor (const modelDef of models) {\n\t\t\t\tconst hasModelApi = !!modelDef.api;\n\n\t\t\t\tif (!hasProviderApi && !hasModelApi && !isBuiltIn) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Provider ${providerName}, model ${modelDef.id}: no \"api\" specified. Set at provider or model level.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// For built-in providers, api is optional — inherited from built-in models.\n\n\t\t\t\tif (!modelDef.id) throw new Error(`Provider ${providerName}: model missing \"id\"`);\n\t\t\t\t// Validate contextWindow/maxTokens only if provided (they have defaults)\n\t\t\t\tif (modelDef.contextWindow !== undefined && modelDef.contextWindow <= 0)\n\t\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);\n\t\t\t\tif (modelDef.maxTokens !== undefined && modelDef.maxTokens <= 0)\n\t\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate parseModels(config: ModelsConfig): Model<Api>[] {\n\t\tconst models: Model<Api>[] = [];\n\t\tconst builtInProviders = new Set<string>(getProviders());\n\n\t\t// Cache built-in defaults (api, baseUrl) per provider, extracted from first model.\n\t\tconst builtInDefaultsCache = new Map<string, { api: string; baseUrl: string }>();\n\t\tconst getBuiltInDefaults = (providerName: string): { api: string; baseUrl: string } | undefined => {\n\t\t\tif (!builtInProviders.has(providerName)) return undefined;\n\t\t\tif (builtInDefaultsCache.has(providerName)) return builtInDefaultsCache.get(providerName);\n\t\t\tconst builtIn = getModels(providerName as KnownProvider) as Model<Api>[];\n\t\t\tif (builtIn.length === 0) return undefined;\n\t\t\tconst defaults = { api: builtIn[0].api, baseUrl: builtIn[0].baseUrl };\n\t\t\tbuiltInDefaultsCache.set(providerName, defaults);\n\t\t\treturn defaults;\n\t\t};\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst modelDefs = providerConfig.models ?? [];\n\t\t\tif (modelDefs.length === 0) continue; // Override-only, no custom models\n\n\t\t\tconst builtInDefaults = getBuiltInDefaults(providerName);\n\n\t\t\tfor (const modelDef of modelDefs) {\n\t\t\t\tconst api = modelDef.api ?? providerConfig.api ?? builtInDefaults?.api;\n\t\t\t\tif (!api) continue;\n\n\t\t\t\tconst baseUrl = modelDef.baseUrl ?? providerConfig.baseUrl ?? builtInDefaults?.baseUrl;\n\t\t\t\tif (!baseUrl) continue;\n\n\t\t\t\tconst compat = mergeCompat(providerConfig.compat, modelDef.compat);\n\t\t\t\tthis.storeModelHeaders(providerName, modelDef.id, modelDef.headers);\n\n\t\t\t\tconst defaultCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\t\t\t\tmodels.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name ?? modelDef.id,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl,\n\t\t\t\t\treasoning: modelDef.reasoning ?? false,\n\t\t\t\t\tthinkingLevelMap: modelDef.thinkingLevelMap,\n\t\t\t\t\tinput: (modelDef.input ?? [\"text\"]) as (\"text\" | \"image\")[],\n\t\t\t\t\tcost: modelDef.cost ?? defaultCost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow ?? 128000,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens ?? 16384,\n\t\t\t\t\theaders: undefined,\n\t\t\t\t\tcompat,\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\t\t}\n\n\t\treturn models;\n\t}\n\n\t/**\n\t * Get all models (built-in + custom).\n\t * If models.json had errors, returns only built-in models.\n\t */\n\tgetAll(): Model<Api>[] {\n\t\treturn this.models;\n\t}\n\n\t/**\n\t * Get only models that have auth configured.\n\t * This is a fast check that doesn't refresh OAuth tokens.\n\t */\n\tgetAvailable(): Model<Api>[] {\n\t\treturn this.models.filter((m) => this.hasConfiguredAuth(m));\n\t}\n\n\t/**\n\t * Find a model by provider and ID.\n\t */\n\tfind(provider: string, modelId: string): Model<Api> | undefined {\n\t\treturn this.models.find((m) => m.provider === provider && m.id === modelId);\n\t}\n\n\t/**\n\t * Get API key for a model.\n\t */\n\thasConfiguredAuth(model: Model<Api>): boolean {\n\t\treturn (\n\t\t\tthis.authStorage.hasAuth(model.provider) ||\n\t\t\tthis.providerRequestConfigs.get(model.provider)?.apiKey !== undefined\n\t\t);\n\t}\n\n\tprivate getModelRequestKey(provider: string, modelId: string): string {\n\t\treturn `${provider}:${modelId}`;\n\t}\n\n\tprivate storeProviderRequestConfig(\n\t\tproviderName: string,\n\t\tconfig: {\n\t\t\tapiKey?: string;\n\t\t\theaders?: Record<string, string>;\n\t\t\tauthHeader?: boolean;\n\t\t},\n\t): void {\n\t\tif (!config.apiKey && !config.headers && !config.authHeader) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.providerRequestConfigs.set(providerName, {\n\t\t\tapiKey: config.apiKey,\n\t\t\theaders: config.headers,\n\t\t\tauthHeader: config.authHeader,\n\t\t});\n\t}\n\n\tprivate storeModelHeaders(providerName: string, modelId: string, headers?: Record<string, string>): void {\n\t\tconst key = this.getModelRequestKey(providerName, modelId);\n\t\tif (!headers || Object.keys(headers).length === 0) {\n\t\t\tthis.modelRequestHeaders.delete(key);\n\t\t\treturn;\n\t\t}\n\t\tthis.modelRequestHeaders.set(key, headers);\n\t}\n\n\t/**\n\t * Get API key and request headers for a model.\n\t */\n\tasync getApiKeyAndHeaders(model: Model<Api>): Promise<ResolvedRequestAuth> {\n\t\ttry {\n\t\t\tconst providerConfig = this.providerRequestConfigs.get(model.provider);\n\t\t\tconst apiKeyFromAuthStorage = await this.authStorage.getApiKey(model.provider, { includeFallback: false });\n\t\t\tconst apiKey =\n\t\t\t\tapiKeyFromAuthStorage ??\n\t\t\t\t(providerConfig?.apiKey\n\t\t\t\t\t? resolveConfigValueOrThrow(providerConfig.apiKey, `API key for provider \"${model.provider}\"`)\n\t\t\t\t\t: undefined);\n\n\t\t\tconst providerHeaders = resolveHeadersOrThrow(providerConfig?.headers, `provider \"${model.provider}\"`);\n\t\t\tconst modelHeaders = resolveHeadersOrThrow(\n\t\t\t\tthis.modelRequestHeaders.get(this.getModelRequestKey(model.provider, model.id)),\n\t\t\t\t`model \"${model.provider}/${model.id}\"`,\n\t\t\t);\n\n\t\t\tlet headers =\n\t\t\t\tmodel.headers || providerHeaders || modelHeaders\n\t\t\t\t\t? { ...model.headers, ...providerHeaders, ...modelHeaders }\n\t\t\t\t\t: undefined;\n\n\t\t\tif (providerConfig?.authHeader) {\n\t\t\t\tif (!apiKey) {\n\t\t\t\t\treturn { ok: false, error: `No API key found for \"${model.provider}\"` };\n\t\t\t\t}\n\t\t\t\theaders = { ...headers, Authorization: `Bearer ${apiKey}` };\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tapiKey,\n\t\t\t\theaders: headers && Object.keys(headers).length > 0 ? headers : undefined,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Return auth status for a provider, including request auth configured in models.json.\n\t * This intentionally does not execute command-backed config values.\n\t */\n\tgetProviderAuthStatus(provider: string): AuthStatus {\n\t\tconst authStatus = this.authStorage.getAuthStatus(provider);\n\t\tif (authStatus.source) {\n\t\t\treturn authStatus;\n\t\t}\n\n\t\tconst providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;\n\t\tif (!providerApiKey) {\n\t\t\treturn authStatus;\n\t\t}\n\n\t\tif (providerApiKey.startsWith(\"!\")) {\n\t\t\treturn { configured: true, source: \"models_json_command\" };\n\t\t}\n\n\t\tif (process.env[providerApiKey]) {\n\t\t\treturn { configured: true, source: \"environment\", label: providerApiKey };\n\t\t}\n\n\t\treturn { configured: true, source: \"models_json_key\" };\n\t}\n\n\t/**\n\t * Get display name for a provider.\n\t */\n\tgetProviderDisplayName(provider: string): string {\n\t\tconst registeredProvider = this.registeredProviders.get(provider);\n\t\tconst oauthProvider = this.authStorage.getOAuthProviders().find((p) => p.id === provider);\n\n\t\treturn (\n\t\t\tregisteredProvider?.name ??\n\t\t\tregisteredProvider?.oauth?.name ??\n\t\t\toauthProvider?.name ??\n\t\t\tBUILT_IN_PROVIDER_DISPLAY_NAMES[provider] ??\n\t\t\tprovider\n\t\t);\n\t}\n\n\t/**\n\t * Get API key for a provider.\n\t */\n\tasync getApiKeyForProvider(provider: string): Promise<string | undefined> {\n\t\tconst apiKey = await this.authStorage.getApiKey(provider, { includeFallback: false });\n\t\tif (apiKey !== undefined) {\n\t\t\treturn apiKey;\n\t\t}\n\n\t\tconst providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;\n\t\treturn providerApiKey ? resolveConfigValueUncached(providerApiKey) : undefined;\n\t}\n\n\t/**\n\t * Register an OpenAI-compatible provider from user input.\n\t * Unlike registerProvider(), this does NOT add to registeredProviders,\n\t * so logout works correctly: refresh() reads auth.json and skips deleted entries.\n\t */\n\tconfigureOpenAICompatibleProvider(\n\t\tproviderId: string,\n\t\tconfig: {\n\t\t\tbaseUrl: string;\n\t\t\tapiKey: string;\n\t\t\tmodels: Array<{ id: string; name: string }>;\n\t\t\tcompat?: OpenAICompatibleProviderInfo[\"compat\"];\n\t\t},\n\t): void {\n\t\tthis.storeProviderRequestConfig(providerId, { apiKey: config.apiKey });\n\n\t\tfor (const modelDef of config.models) {\n\t\t\tconst exists = this.models.some((m) => m.provider === providerId && m.id === modelDef.id);\n\t\t\tif (exists) continue;\n\n\t\t\tthis.models.push({\n\t\t\t\tid: modelDef.id,\n\t\t\t\tname: modelDef.name,\n\t\t\t\tapi: \"openai-completions\" as Api,\n\t\t\t\tprovider: providerId,\n\t\t\t\tbaseUrl: config.baseUrl,\n\t\t\t\treasoning: false,\n\t\t\t\tinput: [\"text\"],\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\t\t\tcontextWindow: 128000,\n\t\t\t\tmaxTokens: 16384,\n\t\t\t\theaders: undefined,\n\t\t\t\tcompat: config.compat,\n\t\t\t} as Model<Api>);\n\t\t}\n\t}\n\n\t/**\n\t * Check if a model is using OAuth credentials (subscription).\n\t */\n\tisUsingOAuth(model: Model<Api>): boolean {\n\t\tconst cred = this.authStorage.get(model.provider);\n\t\treturn cred?.type === \"oauth\";\n\t}\n\n\t/**\n\t * Register a provider dynamically (from extensions).\n\t *\n\t * If provider has models: replaces all existing models for this provider.\n\t * If provider has only baseUrl/headers: overrides existing models' URLs.\n\t * If provider has oauth: registers OAuth provider for /login support.\n\t */\n\tregisterProvider(providerName: string, config: ProviderConfigInput): void {\n\t\tthis.validateProviderConfig(providerName, config);\n\t\tthis.applyProviderConfig(providerName, config);\n\t\tthis.upsertRegisteredProvider(providerName, config);\n\t}\n\n\t/**\n\t * Unregister a previously registered provider.\n\t *\n\t * Removes the provider from the registry and reloads models from disk so that\n\t * built-in models overridden by this provider are restored to their original state.\n\t * Also resets dynamic OAuth and API stream registrations before reapplying\n\t * remaining dynamic providers.\n\t * Has no effect if the provider was never registered.\n\t */\n\tunregisterProvider(providerName: string): void {\n\t\tif (!this.registeredProviders.has(providerName)) return;\n\t\tthis.registeredProviders.delete(providerName);\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Upsert a provider config into registeredProviders.\n\t * If the provider is already registered, defined values in the incoming config\n\t * override existing ones; undefined values are preserved from the stored config.\n\t * If the provider is not registered, the incoming config is stored as-is.\n\t */\n\tprivate upsertRegisteredProvider(providerName: string, config: ProviderConfigInput): void {\n\t\tconst existing = this.registeredProviders.get(providerName);\n\t\tif (!existing) {\n\t\t\tthis.registeredProviders.set(providerName, config);\n\t\t\treturn;\n\t\t}\n\t\tfor (const k of Object.keys(config) as (keyof ProviderConfigInput)[]) {\n\t\t\tif (config[k] !== undefined) {\n\t\t\t\t(existing as Record<string, unknown>)[k] = config[k];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate validateProviderConfig(providerName: string, config: ProviderConfigInput): void {\n\t\tif (config.streamSimple && !config.api) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"api\" is required when registering streamSimple.`);\n\t\t}\n\n\t\tif (!config.models || config.models.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!config.baseUrl) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"baseUrl\" is required when defining models.`);\n\t\t}\n\t\tif (!config.apiKey && !config.oauth) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"apiKey\" or \"oauth\" is required when defining models.`);\n\t\t}\n\n\t\tfor (const modelDef of config.models) {\n\t\t\tconst api = modelDef.api || config.api;\n\t\t\tif (!api) {\n\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: no \"api\" specified.`);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyProviderConfig(providerName: string, config: ProviderConfigInput): void {\n\t\t// Register OAuth provider if provided\n\t\tif (config.oauth) {\n\t\t\t// Ensure the OAuth provider ID matches the provider name\n\t\t\tconst oauthProvider: OAuthProviderInterface = {\n\t\t\t\t...config.oauth,\n\t\t\t\tid: providerName,\n\t\t\t};\n\t\t\tregisterOAuthProvider(oauthProvider);\n\t\t}\n\n\t\tif (config.streamSimple) {\n\t\t\tconst streamSimple = config.streamSimple;\n\t\t\tregisterApiProvider(\n\t\t\t\t{\n\t\t\t\t\tapi: config.api!,\n\t\t\t\t\tstream: (model, context, options) => streamSimple(model, context, options as SimpleStreamOptions),\n\t\t\t\t\tstreamSimple,\n\t\t\t\t},\n\t\t\t\t`provider:${providerName}`,\n\t\t\t);\n\t\t}\n\n\t\tthis.storeProviderRequestConfig(providerName, config);\n\n\t\tif (config.models && config.models.length > 0) {\n\t\t\t// Full replacement: remove existing models for this provider\n\t\t\tthis.models = this.models.filter((m) => m.provider !== providerName);\n\n\t\t\t// Parse and add new models\n\t\t\tfor (const modelDef of config.models) {\n\t\t\t\tconst api = modelDef.api || config.api;\n\t\t\t\tthis.storeModelHeaders(providerName, modelDef.id, modelDef.headers);\n\n\t\t\t\tthis.models.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl: modelDef.baseUrl ?? config.baseUrl!,\n\t\t\t\t\treasoning: modelDef.reasoning,\n\t\t\t\t\tthinkingLevelMap: modelDef.thinkingLevelMap,\n\t\t\t\t\tinput: modelDef.input as (\"text\" | \"image\")[],\n\t\t\t\t\tcost: modelDef.cost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens,\n\t\t\t\t\theaders: undefined,\n\t\t\t\t\tcompat: modelDef.compat,\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\n\t\t\t// Apply OAuth modifyModels if credentials exist (e.g., to update baseUrl)\n\t\t\tif (config.oauth?.modifyModels) {\n\t\t\t\tconst cred = this.authStorage.get(providerName);\n\t\t\t\tif (cred?.type === \"oauth\") {\n\t\t\t\t\tthis.models = config.oauth.modifyModels(this.models, cred);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (config.baseUrl || config.headers) {\n\t\t\t// Override-only: update baseUrl for existing models. Request headers are resolved per request.\n\t\t\tthis.models = this.models.map((m) => {\n\t\t\t\tif (m.provider !== providerName) return m;\n\t\t\t\treturn {\n\t\t\t\t\t...m,\n\t\t\t\t\tbaseUrl: config.baseUrl ?? m.baseUrl,\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Input type for registerProvider API.\n */\nexport interface ProviderConfigInput {\n\tname?: string;\n\tbaseUrl?: string;\n\tapiKey?: string;\n\tapi?: Api;\n\tstreamSimple?: (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;\n\theaders?: Record<string, string>;\n\tauthHeader?: boolean;\n\t/** OAuth provider for /login support */\n\toauth?: Omit<OAuthProviderInterface, \"id\">;\n\tmodels?: Array<{\n\t\tid: string;\n\t\tname: string;\n\t\tapi?: Api;\n\t\tbaseUrl?: string;\n\t\treasoning: boolean;\n\t\tthinkingLevelMap?: Model<Api>[\"thinkingLevelMap\"];\n\t\tinput: (\"text\" | \"image\")[];\n\t\tcost: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\t\tcontextWindow: number;\n\t\tmaxTokens: number;\n\t\theaders?: Record<string, string>;\n\t\tcompat?: Model<Api>[\"compat\"];\n\t}>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model-registry.js","sourceRoot":"","sources":["../../src/core/model-registry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model registry - manages built-in and custom models, provides API key resolution.\n */\n\nimport {\n\ttype AnthropicMessagesCompat,\n\ttype Api,\n\ttype AssistantMessageEventStream,\n\ttype Context,\n\tgetModels,\n\tgetProviders,\n\ttype KnownProvider,\n\ttype Model,\n\ttype OAuthProviderInterface,\n\ttype OpenAICompletionsCompat,\n\ttype OpenAIResponsesCompat,\n\tregisterApiProvider,\n\tresetApiProviders,\n\ttype SimpleStreamOptions,\n} from \"@openeryc/pi-ai\";\nimport { registerOAuthProvider, resetOAuthProviders } from \"@openeryc/pi-ai/oauth\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { Compile } from \"typebox/compile\";\nimport type { TLocalizedValidationError } from \"typebox/error\";\nimport { getAgentDir } from \"../config.ts\";\nimport type { AuthStatus, AuthStorage, OpenAICompatibleProviderInfo } from \"./auth-storage.ts\";\nimport { BUILT_IN_PROVIDER_DISPLAY_NAMES } from \"./provider-display-names.ts\";\nimport {\n\tclearConfigValueCache,\n\tresolveConfigValueOrThrow,\n\tresolveConfigValueUncached,\n\tresolveHeadersOrThrow,\n} from \"./resolve-config-value.ts\";\n\n// Schema for OpenRouter routing preferences\nconst PercentileCutoffsSchema = Type.Object({\n\tp50: Type.Optional(Type.Number()),\n\tp75: Type.Optional(Type.Number()),\n\tp90: Type.Optional(Type.Number()),\n\tp99: Type.Optional(Type.Number()),\n});\n\nconst OpenRouterRoutingSchema = Type.Object({\n\tallow_fallbacks: Type.Optional(Type.Boolean()),\n\trequire_parameters: Type.Optional(Type.Boolean()),\n\tdata_collection: Type.Optional(Type.Union([Type.Literal(\"deny\"), Type.Literal(\"allow\")])),\n\tzdr: Type.Optional(Type.Boolean()),\n\tenforce_distillable_text: Type.Optional(Type.Boolean()),\n\torder: Type.Optional(Type.Array(Type.String())),\n\tonly: Type.Optional(Type.Array(Type.String())),\n\tignore: Type.Optional(Type.Array(Type.String())),\n\tquantizations: Type.Optional(Type.Array(Type.String())),\n\tsort: Type.Optional(\n\t\tType.Union([\n\t\t\tType.String(),\n\t\t\tType.Object({\n\t\t\t\tby: Type.Optional(Type.String()),\n\t\t\t\tpartition: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n\t\t\t}),\n\t\t]),\n\t),\n\tmax_price: Type.Optional(\n\t\tType.Object({\n\t\t\tprompt: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\tcompletion: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\timage: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\taudio: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t\trequest: Type.Optional(Type.Union([Type.Number(), Type.String()])),\n\t\t}),\n\t),\n\tpreferred_min_throughput: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),\n\tpreferred_max_latency: Type.Optional(Type.Union([Type.Number(), PercentileCutoffsSchema])),\n});\n\n// Schema for Vercel AI Gateway routing preferences\nconst VercelGatewayRoutingSchema = Type.Object({\n\tonly: Type.Optional(Type.Array(Type.String())),\n\torder: Type.Optional(Type.Array(Type.String())),\n});\n\n// Schema for thinking level support and provider-specific values\nconst ThinkingLevelMapValueSchema = Type.Union([Type.String(), Type.Null()]);\nconst ThinkingLevelMapSchema = Type.Object({\n\toff: Type.Optional(ThinkingLevelMapValueSchema),\n\tminimal: Type.Optional(ThinkingLevelMapValueSchema),\n\tlow: Type.Optional(ThinkingLevelMapValueSchema),\n\tmedium: Type.Optional(ThinkingLevelMapValueSchema),\n\thigh: Type.Optional(ThinkingLevelMapValueSchema),\n\txhigh: Type.Optional(ThinkingLevelMapValueSchema),\n});\n\nconst OpenAICompletionsCompatSchema = Type.Object({\n\tsupportsStore: Type.Optional(Type.Boolean()),\n\tsupportsDeveloperRole: Type.Optional(Type.Boolean()),\n\tsupportsReasoningEffort: Type.Optional(Type.Boolean()),\n\tsupportsUsageInStreaming: Type.Optional(Type.Boolean()),\n\tmaxTokensField: Type.Optional(Type.Union([Type.Literal(\"max_completion_tokens\"), Type.Literal(\"max_tokens\")])),\n\trequiresToolResultName: Type.Optional(Type.Boolean()),\n\trequiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),\n\trequiresThinkingAsText: Type.Optional(Type.Boolean()),\n\trequiresReasoningContentOnAssistantMessages: Type.Optional(Type.Boolean()),\n\tthinkingFormat: Type.Optional(\n\t\tType.Union([\n\t\t\tType.Literal(\"openai\"),\n\t\t\tType.Literal(\"openrouter\"),\n\t\t\tType.Literal(\"together\"),\n\t\t\tType.Literal(\"deepseek\"),\n\t\t\tType.Literal(\"zai\"),\n\t\t\tType.Literal(\"qwen\"),\n\t\t\tType.Literal(\"qwen-chat-template\"),\n\t\t]),\n\t),\n\tcacheControlFormat: Type.Optional(Type.Literal(\"anthropic\")),\n\topenRouterRouting: Type.Optional(OpenRouterRoutingSchema),\n\tvercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),\n\tsupportsStrictMode: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n});\n\nconst OpenAIResponsesCompatSchema = Type.Object({\n\tsendSessionIdHeader: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n});\n\nconst AnthropicMessagesCompatSchema = Type.Object({\n\tsupportsEagerToolInputStreaming: Type.Optional(Type.Boolean()),\n\tsupportsLongCacheRetention: Type.Optional(Type.Boolean()),\n});\n\nconst ProviderCompatSchema = Type.Union([\n\tOpenAICompletionsCompatSchema,\n\tOpenAIResponsesCompatSchema,\n\tAnthropicMessagesCompatSchema,\n]);\n\n// Schema for custom model definition\n// Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)\nconst ModelDefinitionSchema = Type.Object({\n\tid: Type.String({ minLength: 1 }),\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\tapi: Type.Optional(Type.String({ minLength: 1 })),\n\tbaseUrl: Type.Optional(Type.String({ minLength: 1 })),\n\treasoning: Type.Optional(Type.Boolean()),\n\tthinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),\n\tinput: Type.Optional(Type.Array(Type.Union([Type.Literal(\"text\"), Type.Literal(\"image\")]))),\n\tcost: Type.Optional(\n\t\tType.Object({\n\t\t\tinput: Type.Number(),\n\t\t\toutput: Type.Number(),\n\t\t\tcacheRead: Type.Number(),\n\t\t\tcacheWrite: Type.Number(),\n\t\t}),\n\t),\n\tcontextWindow: Type.Optional(Type.Number()),\n\tmaxTokens: Type.Optional(Type.Number()),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n});\n\n// Schema for per-model overrides (all fields optional, merged with built-in model)\nconst ModelOverrideSchema = Type.Object({\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\treasoning: Type.Optional(Type.Boolean()),\n\tthinkingLevelMap: Type.Optional(ThinkingLevelMapSchema),\n\tinput: Type.Optional(Type.Array(Type.Union([Type.Literal(\"text\"), Type.Literal(\"image\")]))),\n\tcost: Type.Optional(\n\t\tType.Object({\n\t\t\tinput: Type.Optional(Type.Number()),\n\t\t\toutput: Type.Optional(Type.Number()),\n\t\t\tcacheRead: Type.Optional(Type.Number()),\n\t\t\tcacheWrite: Type.Optional(Type.Number()),\n\t\t}),\n\t),\n\tcontextWindow: Type.Optional(Type.Number()),\n\tmaxTokens: Type.Optional(Type.Number()),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n});\n\ntype ModelOverride = Static<typeof ModelOverrideSchema>;\n\nconst ProviderConfigSchema = Type.Object({\n\tname: Type.Optional(Type.String({ minLength: 1 })),\n\tbaseUrl: Type.Optional(Type.String({ minLength: 1 })),\n\tapiKey: Type.Optional(Type.String({ minLength: 1 })),\n\tapi: Type.Optional(Type.String({ minLength: 1 })),\n\theaders: Type.Optional(Type.Record(Type.String(), Type.String())),\n\tcompat: Type.Optional(ProviderCompatSchema),\n\tauthHeader: Type.Optional(Type.Boolean()),\n\tmodels: Type.Optional(Type.Array(ModelDefinitionSchema)),\n\tmodelOverrides: Type.Optional(Type.Record(Type.String(), ModelOverrideSchema)),\n});\n\nconst ModelsConfigSchema = Type.Object({\n\tproviders: Type.Record(Type.String(), ProviderConfigSchema),\n});\n\nconst validateModelsConfig = Compile(ModelsConfigSchema);\n\ntype ModelsConfig = Static<typeof ModelsConfigSchema>;\ntype ProviderConfig = Static<typeof ProviderConfigSchema>;\n\n/** Writable provider config for models.json (subset used by TUI Manage). */\nexport type ModelsJsonProviderWrite = {\n\tbaseUrl?: string;\n\tapiKey?: string;\n\tapi?: string;\n\theaders?: Record<string, string>;\n\tauthHeader?: boolean;\n\tcompat?: Static<typeof ProviderCompatSchema>;\n\tmodels?: Array<{\n\t\tid: string;\n\t\tname?: string;\n\t\tapi?: string;\n\t\treasoning?: boolean;\n\t\tinput?: Array<\"text\" | \"image\">;\n\t\tcontextWindow?: number;\n\t\tmaxTokens?: number;\n\t\tcost?: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\t}>;\n};\n\nexport type ModelsJsonCustomProviderInfo = {\n\tname: string;\n\tbaseUrl?: string;\n\tapi?: string;\n\tapiKey?: string;\n\thasApiKey: boolean;\n\tmodelIds: string[];\n\t/** True when this provider name is a built-in (override/merge), not purely custom. */\n\tisBuiltIn: boolean;\n};\n\nfunction formatValidationPath(error: TLocalizedValidationError): string {\n\tif (error.keyword === \"required\") {\n\t\tconst requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties;\n\t\tconst requiredProperty = requiredProperties?.[0];\n\t\tif (requiredProperty) {\n\t\t\tconst basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\t\t\treturn basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n\t\t}\n\t}\n\tconst path = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\treturn path || \"root\";\n}\n\n/** Strip `//` line comments and trailing commas from JSON, leaving string literals untouched. */\nfunction stripJsonComments(input: string): string {\n\treturn input\n\t\t.replace(/\"(?:\\\\.|[^\"\\\\])*\"|\\/\\/[^\\n]*/g, (m) => (m[0] === '\"' ? m : \"\"))\n\t\t.replace(/\"(?:\\\\.|[^\"\\\\])*\"|,(\\s*[}\\]])/g, (m, tail) => tail ?? (m[0] === '\"' ? m : \"\"));\n}\n\n/** Provider override config (baseUrl, compat) without request auth/headers */\ninterface ProviderOverride {\n\tbaseUrl?: string;\n\tcompat?: Model<Api>[\"compat\"];\n}\n\ninterface ProviderRequestConfig {\n\tapiKey?: string;\n\theaders?: Record<string, string>;\n\tauthHeader?: boolean;\n}\n\nexport type ResolvedRequestAuth =\n\t| {\n\t\t\tok: true;\n\t\t\tapiKey?: string;\n\t\t\theaders?: Record<string, string>;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\terror: string;\n\t };\n\n/** Result of loading custom models from models.json */\ninterface CustomModelsResult {\n\tmodels: Model<Api>[];\n\t/** Providers with baseUrl/headers/apiKey overrides for built-in models */\n\toverrides: Map<string, ProviderOverride>;\n\t/** Per-model overrides: provider -> modelId -> override */\n\tmodelOverrides: Map<string, Map<string, ModelOverride>>;\n\terror: string | undefined;\n}\n\nfunction emptyCustomModelsResult(error?: string): CustomModelsResult {\n\treturn { models: [], overrides: new Map(), modelOverrides: new Map(), error };\n}\n\nfunction mergeCompat(\n\tbaseCompat: Model<Api>[\"compat\"],\n\toverrideCompat: ModelOverride[\"compat\"],\n): Model<Api>[\"compat\"] | undefined {\n\tif (!overrideCompat) return baseCompat;\n\n\tconst base = baseCompat as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat | undefined;\n\tconst override = overrideCompat as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat;\n\tconst merged = { ...base, ...override } as OpenAICompletionsCompat | OpenAIResponsesCompat | AnthropicMessagesCompat;\n\n\tconst baseCompletions = base as OpenAICompletionsCompat | undefined;\n\tconst overrideCompletions = override as OpenAICompletionsCompat;\n\tconst mergedCompletions = merged as OpenAICompletionsCompat;\n\n\tif (baseCompletions?.openRouterRouting || overrideCompletions.openRouterRouting) {\n\t\tmergedCompletions.openRouterRouting = {\n\t\t\t...baseCompletions?.openRouterRouting,\n\t\t\t...overrideCompletions.openRouterRouting,\n\t\t};\n\t}\n\n\tif (baseCompletions?.vercelGatewayRouting || overrideCompletions.vercelGatewayRouting) {\n\t\tmergedCompletions.vercelGatewayRouting = {\n\t\t\t...baseCompletions?.vercelGatewayRouting,\n\t\t\t...overrideCompletions.vercelGatewayRouting,\n\t\t};\n\t}\n\n\treturn merged as Model<Api>[\"compat\"];\n}\n\n/**\n * Deep merge a model override into a model.\n * Handles nested objects (cost, compat) by merging rather than replacing.\n */\nfunction applyModelOverride(model: Model<Api>, override: ModelOverride): Model<Api> {\n\tconst result = { ...model };\n\n\t// Simple field overrides\n\tif (override.name !== undefined) result.name = override.name;\n\tif (override.reasoning !== undefined) result.reasoning = override.reasoning;\n\tif (override.thinkingLevelMap !== undefined) {\n\t\tresult.thinkingLevelMap = { ...model.thinkingLevelMap, ...override.thinkingLevelMap };\n\t}\n\tif (override.input !== undefined) result.input = override.input as (\"text\" | \"image\")[];\n\tif (override.contextWindow !== undefined) result.contextWindow = override.contextWindow;\n\tif (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;\n\n\t// Merge cost (partial override)\n\tif (override.cost) {\n\t\tresult.cost = {\n\t\t\tinput: override.cost.input ?? model.cost.input,\n\t\t\toutput: override.cost.output ?? model.cost.output,\n\t\t\tcacheRead: override.cost.cacheRead ?? model.cost.cacheRead,\n\t\t\tcacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,\n\t\t};\n\t}\n\n\t// Deep merge compat\n\tresult.compat = mergeCompat(model.compat, override.compat);\n\n\treturn result;\n}\n\n/** Clear the config value command cache. Exported for testing. */\nexport const clearApiKeyCache = clearConfigValueCache;\n\n/**\n * Model registry - loads and manages models, resolves API keys via AuthStorage.\n */\nexport class ModelRegistry {\n\tprivate models: Model<Api>[] = [];\n\tprivate providerRequestConfigs: Map<string, ProviderRequestConfig> = new Map();\n\tprivate modelRequestHeaders: Map<string, Record<string, string>> = new Map();\n\tprivate registeredProviders: Map<string, ProviderConfigInput> = new Map();\n\tprivate loadError: string | undefined = undefined;\n\treadonly authStorage: AuthStorage;\n\tprivate modelsJsonPath: string | undefined;\n\n\tprivate constructor(authStorage: AuthStorage, modelsJsonPath: string | undefined) {\n\t\tthis.authStorage = authStorage;\n\t\tthis.modelsJsonPath = modelsJsonPath;\n\t\tthis.loadModels();\n\t}\n\n\tstatic create(authStorage: AuthStorage, modelsJsonPath: string = join(getAgentDir(), \"models.json\")): ModelRegistry {\n\t\treturn new ModelRegistry(authStorage, modelsJsonPath);\n\t}\n\n\tstatic inMemory(authStorage: AuthStorage): ModelRegistry {\n\t\treturn new ModelRegistry(authStorage, undefined);\n\t}\n\n\t/**\n\t * Reload models from disk (built-in + custom from models.json).\n\t */\n\trefresh(): void {\n\t\tthis.providerRequestConfigs.clear();\n\t\tthis.modelRequestHeaders.clear();\n\t\tthis.loadError = undefined;\n\n\t\t// Ensure dynamic API/OAuth registrations are rebuilt from current provider state.\n\t\tresetApiProviders();\n\t\tresetOAuthProviders();\n\n\t\tthis.loadModels();\n\n\t\tfor (const [providerName, config] of this.registeredProviders.entries()) {\n\t\t\tthis.applyProviderConfig(providerName, config);\n\t\t}\n\t}\n\n\t/**\n\t * Get any error from loading models.json (undefined if no error).\n\t */\n\tgetError(): string | undefined {\n\t\treturn this.loadError;\n\t}\n\n\t/** Path to models.json if this registry is file-backed. */\n\tgetModelsJsonPath(): string | undefined {\n\t\treturn this.modelsJsonPath;\n\t}\n\n\t/**\n\t * List providers defined in models.json (custom + overrides).\n\t * Returns empty when no models.json or on parse error.\n\t */\n\tlistModelsJsonProviders(): ModelsJsonCustomProviderInfo[] {\n\t\tconst config = this.readModelsConfigFile();\n\t\tif (!config) return [];\n\t\tconst builtIn = new Set<string>(getProviders());\n\t\treturn Object.entries(config.providers).map(([name, providerConfig]) => ({\n\t\t\tname,\n\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\tapi: providerConfig.api,\n\t\t\tapiKey: providerConfig.apiKey,\n\t\t\thasApiKey: !!providerConfig.apiKey,\n\t\t\tmodelIds: (providerConfig.models ?? []).map((m) => m.id),\n\t\t\tisBuiltIn: builtIn.has(name),\n\t\t}));\n\t}\n\n\t/**\n\t * Rename a provider key in models.json (optionally merging new fields), then refresh.\n\t * Used by Manage edit when the user changes the provider name/id.\n\t */\n\trenameProviderInModelsJson(oldName: string, newName: string, config?: ModelsJsonProviderWrite): void {\n\t\tif (!this.modelsJsonPath) {\n\t\t\tthrow new Error(\"ModelRegistry is not file-backed; cannot write models.json\");\n\t\t}\n\t\tconst from = oldName.trim();\n\t\tconst to = newName.trim();\n\t\tif (!from || !to) {\n\t\t\tthrow new Error(\"Provider name cannot be empty\");\n\t\t}\n\t\tconst existing = this.readModelsConfigFile();\n\t\tif (!existing?.providers[from]) {\n\t\t\tthrow new Error(`Provider \"${from}\" is not defined in models.json`);\n\t\t}\n\t\tif (from !== to && existing.providers[to]) {\n\t\t\tthrow new Error(`Provider \"${to}\" already exists in models.json`);\n\t\t}\n\n\t\tconst prev = existing.providers[from] ?? {};\n\t\tconst merged: ProviderConfig = {\n\t\t\t...prev,\n\t\t\t...(config ?? {}),\n\t\t\tmodels: config?.models !== undefined ? config.models : prev.models,\n\t\t};\n\t\tif (merged.models && merged.models.length === 0) {\n\t\t\tdelete merged.models;\n\t\t}\n\n\t\tconst rest = { ...existing.providers };\n\t\tdelete rest[from];\n\t\trest[to] = merged;\n\t\tconst nextConfig: ModelsConfig = { providers: rest };\n\t\tthis.validateConfig(nextConfig);\n\t\tthis.writeModelsConfigFile(nextConfig);\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Upsert a provider entry in models.json, then refresh the registry.\n\t * Rewrites the file as pretty JSON (comments/trailing commas are not preserved).\n\t */\n\tupsertProviderInModelsJson(providerName: string, config: ModelsJsonProviderWrite): void {\n\t\tif (!this.modelsJsonPath) {\n\t\t\tthrow new Error(\"ModelRegistry is not file-backed; cannot write models.json\");\n\t\t}\n\t\tconst trimmed = providerName.trim();\n\t\tif (!trimmed) {\n\t\t\tthrow new Error(\"Provider name cannot be empty\");\n\t\t}\n\n\t\tconst existing = this.readModelsConfigFile() ?? { providers: {} };\n\t\tconst prev = existing.providers[trimmed] ?? {};\n\t\tconst merged: ProviderConfig = {\n\t\t\t...prev,\n\t\t\t...config,\n\t\t\tmodels: config.models !== undefined ? config.models : prev.models,\n\t\t};\n\n\t\t// Drop empty optional objects so schema stays clean\n\t\tif (merged.models && merged.models.length === 0) {\n\t\t\tdelete merged.models;\n\t\t}\n\n\t\tconst nextConfig: ModelsConfig = {\n\t\t\tproviders: {\n\t\t\t\t...existing.providers,\n\t\t\t\t[trimmed]: merged,\n\t\t\t},\n\t\t};\n\n\t\tthis.validateConfig(nextConfig);\n\t\tthis.writeModelsConfigFile(nextConfig);\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Remove a provider entry from models.json, then refresh.\n\t */\n\tremoveProviderFromModelsJson(providerName: string): void {\n\t\tif (!this.modelsJsonPath) {\n\t\t\tthrow new Error(\"ModelRegistry is not file-backed; cannot write models.json\");\n\t\t}\n\t\tconst existing = this.readModelsConfigFile();\n\t\tif (!existing?.providers[providerName]) {\n\t\t\tthrow new Error(`Provider \"${providerName}\" is not defined in models.json`);\n\t\t}\n\t\tconst { [providerName]: _removed, ...rest } = existing.providers;\n\t\tconst nextConfig: ModelsConfig = { providers: rest };\n\t\tthis.writeModelsConfigFile(nextConfig);\n\t\tthis.refresh();\n\t}\n\n\tprivate readModelsConfigFile(): ModelsConfig | undefined {\n\t\tif (!this.modelsJsonPath || !existsSync(this.modelsJsonPath)) {\n\t\t\treturn undefined;\n\t\t}\n\t\ttry {\n\t\t\tconst content = readFileSync(this.modelsJsonPath, \"utf-8\");\n\t\t\tconst parsed = JSON.parse(stripJsonComments(content)) as unknown;\n\t\t\tif (!validateModelsConfig.Check(parsed)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn parsed as ModelsConfig;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate writeModelsConfigFile(config: ModelsConfig): void {\n\t\tif (!this.modelsJsonPath) {\n\t\t\tthrow new Error(\"ModelRegistry is not file-backed; cannot write models.json\");\n\t\t}\n\t\tconst dir = dirname(this.modelsJsonPath);\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t}\n\t\twriteFileSync(this.modelsJsonPath, `${JSON.stringify(config, null, 2)}\\n`, \"utf-8\");\n\t}\n\n\tprivate loadModels(): void {\n\t\t// Load custom models and overrides from models.json\n\t\tconst {\n\t\t\tmodels: customModels,\n\t\t\toverrides,\n\t\t\tmodelOverrides,\n\t\t\terror,\n\t\t} = this.modelsJsonPath ? this.loadCustomModels(this.modelsJsonPath) : emptyCustomModelsResult();\n\n\t\tif (error) {\n\t\t\tthis.loadError = error;\n\t\t\t// Keep built-in models even if custom models failed to load\n\t\t}\n\n\t\tconst builtInModels = this.loadBuiltInModels(overrides, modelOverrides);\n\t\tlet combined = this.mergeCustomModels(builtInModels, customModels);\n\n\t\t// Let OAuth providers modify their models (e.g., update baseUrl)\n\t\tfor (const oauthProvider of this.authStorage.getOAuthProviders()) {\n\t\t\tconst cred = this.authStorage.get(oauthProvider.id);\n\t\t\tif (cred?.type === \"oauth\" && oauthProvider.modifyModels) {\n\t\t\t\tcombined = oauthProvider.modifyModels(combined, cred);\n\t\t\t}\n\t\t}\n\n\t\tthis.models = combined;\n\n\t\t// Register OpenAI-compatible providers stored in auth.json\n\t\tthis.loadOpenAICompatibleProviders();\n\t}\n\n\t/** Load built-in models and apply provider/model overrides */\n\tprivate loadBuiltInModels(\n\t\toverrides: Map<string, ProviderOverride>,\n\t\tmodelOverrides: Map<string, Map<string, ModelOverride>>,\n\t): Model<Api>[] {\n\t\treturn getProviders().flatMap((provider) => {\n\t\t\tconst models = getModels(provider as KnownProvider) as Model<Api>[];\n\t\t\tconst providerOverride = overrides.get(provider);\n\t\t\tconst perModelOverrides = modelOverrides.get(provider);\n\n\t\t\treturn models.map((m) => {\n\t\t\t\tlet model = m;\n\n\t\t\t\t// Apply provider-level baseUrl/headers/compat override\n\t\t\t\tif (providerOverride) {\n\t\t\t\t\tmodel = {\n\t\t\t\t\t\t...model,\n\t\t\t\t\t\tbaseUrl: providerOverride.baseUrl ?? model.baseUrl,\n\t\t\t\t\t\tcompat: mergeCompat(model.compat, providerOverride.compat),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Apply per-model override\n\t\t\t\tconst modelOverride = perModelOverrides?.get(m.id);\n\t\t\t\tif (modelOverride) {\n\t\t\t\t\tmodel = applyModelOverride(model, modelOverride);\n\t\t\t\t}\n\n\t\t\t\treturn model;\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Load OpenAI-compatible providers stored in auth.json (type \"openai_compatible\").\n\t * These are registered as dynamic providers with api=\"openai-completions\".\n\t */\n\tprivate loadOpenAICompatibleProviders(): void {\n\t\tconst providers = this.authStorage.getOpenAICompatibleProviders();\n\t\tfor (const [providerName, info] of Object.entries(providers)) {\n\t\t\tthis.storeProviderRequestConfig(providerName, { apiKey: info.key });\n\n\t\t\tfor (const modelDef of info.models) {\n\t\t\t\t// Avoid duplicates if already registered via other mechanism\n\t\t\t\tconst exists = this.models.some((m) => m.provider === providerName && m.id === modelDef.id);\n\t\t\t\tif (exists) continue;\n\n\t\t\t\tthis.models.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name,\n\t\t\t\t\tapi: \"openai-completions\" as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl: info.baseUrl,\n\t\t\t\t\treasoning: false,\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\t\t\t\tcontextWindow: 128000,\n\t\t\t\t\tmaxTokens: 16384,\n\t\t\t\t\theaders: undefined,\n\t\t\t\t\tcompat: info.compat,\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Merge custom models into built-in list by provider+id (custom wins on conflicts). */\n\tprivate mergeCustomModels(builtInModels: Model<Api>[], customModels: Model<Api>[]): Model<Api>[] {\n\t\tconst merged = [...builtInModels];\n\t\tfor (const customModel of customModels) {\n\t\t\tconst existingIndex = merged.findIndex((m) => m.provider === customModel.provider && m.id === customModel.id);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tmerged[existingIndex] = customModel;\n\t\t\t} else {\n\t\t\t\tmerged.push(customModel);\n\t\t\t}\n\t\t}\n\t\treturn merged;\n\t}\n\n\tprivate loadCustomModels(modelsJsonPath: string): CustomModelsResult {\n\t\tif (!existsSync(modelsJsonPath)) {\n\t\t\treturn emptyCustomModelsResult();\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(modelsJsonPath, \"utf-8\");\n\t\t\tconst parsed = JSON.parse(stripJsonComments(content)) as unknown;\n\n\t\t\tif (!validateModelsConfig.Check(parsed)) {\n\t\t\t\tconst errors =\n\t\t\t\t\tvalidateModelsConfig\n\t\t\t\t\t\t.Errors(parsed)\n\t\t\t\t\t\t.map((error) => ` - ${formatValidationPath(error)}: ${error.message}`)\n\t\t\t\t\t\t.join(\"\\n\") || \"Unknown schema error\";\n\t\t\t\treturn emptyCustomModelsResult(`Invalid models.json schema:\\n${errors}\\n\\nFile: ${modelsJsonPath}`);\n\t\t\t}\n\n\t\t\tconst config = parsed as ModelsConfig;\n\n\t\t\t// Additional validation\n\t\t\tthis.validateConfig(config);\n\n\t\t\tconst overrides = new Map<string, ProviderOverride>();\n\t\t\tconst modelOverrides = new Map<string, Map<string, ModelOverride>>();\n\n\t\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\t\tif (providerConfig.baseUrl || providerConfig.compat) {\n\t\t\t\t\toverrides.set(providerName, {\n\t\t\t\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\t\t\t\tcompat: providerConfig.compat,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tthis.storeProviderRequestConfig(providerName, providerConfig);\n\n\t\t\t\tif (providerConfig.modelOverrides) {\n\t\t\t\t\tmodelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));\n\t\t\t\t\tfor (const [modelId, modelOverride] of Object.entries(providerConfig.modelOverrides)) {\n\t\t\t\t\t\tthis.storeModelHeaders(providerName, modelId, modelOverride.headers);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { models: this.parseModels(config), overrides, modelOverrides, error: undefined };\n\t\t} catch (error) {\n\t\t\tif (error instanceof SyntaxError) {\n\t\t\t\treturn emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\\n\\nFile: ${modelsJsonPath}`);\n\t\t\t}\n\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t`Failed to load models.json: ${error instanceof Error ? error.message : error}\\n\\nFile: ${modelsJsonPath}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate validateConfig(config: ModelsConfig): void {\n\t\tconst builtInProviders = new Set<string>(getProviders());\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst isBuiltIn = builtInProviders.has(providerName);\n\t\t\tconst hasProviderApi = !!providerConfig.api;\n\t\t\tconst models = providerConfig.models ?? [];\n\t\t\tconst hasModelOverrides =\n\t\t\t\tproviderConfig.modelOverrides && Object.keys(providerConfig.modelOverrides).length > 0;\n\n\t\t\tif (models.length === 0) {\n\t\t\t\t// Override-only config: needs baseUrl, headers, compat, modelOverrides, or some combination.\n\t\t\t\tif (!providerConfig.baseUrl && !providerConfig.headers && !providerConfig.compat && !hasModelOverrides) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Provider ${providerName}: must specify \"baseUrl\", \"headers\", \"compat\", \"modelOverrides\", or \"models\".`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else if (!isBuiltIn) {\n\t\t\t\t// Non-built-in providers with custom models require endpoint + auth.\n\t\t\t\tif (!providerConfig.baseUrl) {\n\t\t\t\t\tthrow new Error(`Provider ${providerName}: \"baseUrl\" is required when defining custom models.`);\n\t\t\t\t}\n\t\t\t\tif (!providerConfig.apiKey) {\n\t\t\t\t\tthrow new Error(`Provider ${providerName}: \"apiKey\" is required when defining custom models.`);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Built-in providers with custom models: baseUrl/apiKey/api are optional,\n\t\t\t// inherited from built-in models. Auth comes from env vars / auth storage.\n\n\t\t\tfor (const modelDef of models) {\n\t\t\t\tconst hasModelApi = !!modelDef.api;\n\n\t\t\t\tif (!hasProviderApi && !hasModelApi && !isBuiltIn) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Provider ${providerName}, model ${modelDef.id}: no \"api\" specified. Set at provider or model level.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// For built-in providers, api is optional — inherited from built-in models.\n\n\t\t\t\tif (!modelDef.id) throw new Error(`Provider ${providerName}: model missing \"id\"`);\n\t\t\t\t// Validate contextWindow/maxTokens only if provided (they have defaults)\n\t\t\t\tif (modelDef.contextWindow !== undefined && modelDef.contextWindow <= 0)\n\t\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);\n\t\t\t\tif (modelDef.maxTokens !== undefined && modelDef.maxTokens <= 0)\n\t\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate parseModels(config: ModelsConfig): Model<Api>[] {\n\t\tconst models: Model<Api>[] = [];\n\t\tconst builtInProviders = new Set<string>(getProviders());\n\n\t\t// Cache built-in defaults (api, baseUrl) per provider, extracted from first model.\n\t\tconst builtInDefaultsCache = new Map<string, { api: string; baseUrl: string }>();\n\t\tconst getBuiltInDefaults = (providerName: string): { api: string; baseUrl: string } | undefined => {\n\t\t\tif (!builtInProviders.has(providerName)) return undefined;\n\t\t\tif (builtInDefaultsCache.has(providerName)) return builtInDefaultsCache.get(providerName);\n\t\t\tconst builtIn = getModels(providerName as KnownProvider) as Model<Api>[];\n\t\t\tif (builtIn.length === 0) return undefined;\n\t\t\tconst defaults = { api: builtIn[0].api, baseUrl: builtIn[0].baseUrl };\n\t\t\tbuiltInDefaultsCache.set(providerName, defaults);\n\t\t\treturn defaults;\n\t\t};\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst modelDefs = providerConfig.models ?? [];\n\t\t\tif (modelDefs.length === 0) continue; // Override-only, no custom models\n\n\t\t\tconst builtInDefaults = getBuiltInDefaults(providerName);\n\n\t\t\tfor (const modelDef of modelDefs) {\n\t\t\t\tconst api = modelDef.api ?? providerConfig.api ?? builtInDefaults?.api;\n\t\t\t\tif (!api) continue;\n\n\t\t\t\tconst baseUrl = modelDef.baseUrl ?? providerConfig.baseUrl ?? builtInDefaults?.baseUrl;\n\t\t\t\tif (!baseUrl) continue;\n\n\t\t\t\tconst compat = mergeCompat(providerConfig.compat, modelDef.compat);\n\t\t\t\tthis.storeModelHeaders(providerName, modelDef.id, modelDef.headers);\n\n\t\t\t\tconst defaultCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\t\t\t\tmodels.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name ?? modelDef.id,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl,\n\t\t\t\t\treasoning: modelDef.reasoning ?? false,\n\t\t\t\t\tthinkingLevelMap: modelDef.thinkingLevelMap,\n\t\t\t\t\tinput: (modelDef.input ?? [\"text\"]) as (\"text\" | \"image\")[],\n\t\t\t\t\tcost: modelDef.cost ?? defaultCost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow ?? 128000,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens ?? 16384,\n\t\t\t\t\theaders: undefined,\n\t\t\t\t\tcompat,\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\t\t}\n\n\t\treturn models;\n\t}\n\n\t/**\n\t * Get all models (built-in + custom).\n\t * If models.json had errors, returns only built-in models.\n\t */\n\tgetAll(): Model<Api>[] {\n\t\treturn this.models;\n\t}\n\n\t/**\n\t * Get only models that have auth configured.\n\t * This is a fast check that doesn't refresh OAuth tokens.\n\t */\n\tgetAvailable(): Model<Api>[] {\n\t\treturn this.models.filter((m) => this.hasConfiguredAuth(m));\n\t}\n\n\t/**\n\t * Find a model by provider and ID.\n\t */\n\tfind(provider: string, modelId: string): Model<Api> | undefined {\n\t\treturn this.models.find((m) => m.provider === provider && m.id === modelId);\n\t}\n\n\t/**\n\t * Get API key for a model.\n\t */\n\thasConfiguredAuth(model: Model<Api>): boolean {\n\t\treturn (\n\t\t\tthis.authStorage.hasAuth(model.provider) ||\n\t\t\tthis.providerRequestConfigs.get(model.provider)?.apiKey !== undefined\n\t\t);\n\t}\n\n\tprivate getModelRequestKey(provider: string, modelId: string): string {\n\t\treturn `${provider}:${modelId}`;\n\t}\n\n\tprivate storeProviderRequestConfig(\n\t\tproviderName: string,\n\t\tconfig: {\n\t\t\tapiKey?: string;\n\t\t\theaders?: Record<string, string>;\n\t\t\tauthHeader?: boolean;\n\t\t},\n\t): void {\n\t\tif (!config.apiKey && !config.headers && !config.authHeader) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.providerRequestConfigs.set(providerName, {\n\t\t\tapiKey: config.apiKey,\n\t\t\theaders: config.headers,\n\t\t\tauthHeader: config.authHeader,\n\t\t});\n\t}\n\n\tprivate storeModelHeaders(providerName: string, modelId: string, headers?: Record<string, string>): void {\n\t\tconst key = this.getModelRequestKey(providerName, modelId);\n\t\tif (!headers || Object.keys(headers).length === 0) {\n\t\t\tthis.modelRequestHeaders.delete(key);\n\t\t\treturn;\n\t\t}\n\t\tthis.modelRequestHeaders.set(key, headers);\n\t}\n\n\t/**\n\t * Get API key and request headers for a model.\n\t */\n\tasync getApiKeyAndHeaders(model: Model<Api>): Promise<ResolvedRequestAuth> {\n\t\ttry {\n\t\t\tconst providerConfig = this.providerRequestConfigs.get(model.provider);\n\t\t\tconst apiKeyFromAuthStorage = await this.authStorage.getApiKey(model.provider, { includeFallback: false });\n\t\t\tconst apiKey =\n\t\t\t\tapiKeyFromAuthStorage ??\n\t\t\t\t(providerConfig?.apiKey\n\t\t\t\t\t? resolveConfigValueOrThrow(providerConfig.apiKey, `API key for provider \"${model.provider}\"`)\n\t\t\t\t\t: undefined);\n\n\t\t\tconst providerHeaders = resolveHeadersOrThrow(providerConfig?.headers, `provider \"${model.provider}\"`);\n\t\t\tconst modelHeaders = resolveHeadersOrThrow(\n\t\t\t\tthis.modelRequestHeaders.get(this.getModelRequestKey(model.provider, model.id)),\n\t\t\t\t`model \"${model.provider}/${model.id}\"`,\n\t\t\t);\n\n\t\t\tlet headers =\n\t\t\t\tmodel.headers || providerHeaders || modelHeaders\n\t\t\t\t\t? { ...model.headers, ...providerHeaders, ...modelHeaders }\n\t\t\t\t\t: undefined;\n\n\t\t\tif (providerConfig?.authHeader) {\n\t\t\t\tif (!apiKey) {\n\t\t\t\t\treturn { ok: false, error: `No API key found for \"${model.provider}\"` };\n\t\t\t\t}\n\t\t\t\theaders = { ...headers, Authorization: `Bearer ${apiKey}` };\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tok: true,\n\t\t\t\tapiKey,\n\t\t\t\theaders: headers && Object.keys(headers).length > 0 ? headers : undefined,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Return auth status for a provider, including request auth configured in models.json.\n\t * This intentionally does not execute command-backed config values.\n\t */\n\tgetProviderAuthStatus(provider: string): AuthStatus {\n\t\tconst authStatus = this.authStorage.getAuthStatus(provider);\n\t\tif (authStatus.source) {\n\t\t\treturn authStatus;\n\t\t}\n\n\t\tconst providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;\n\t\tif (!providerApiKey) {\n\t\t\treturn authStatus;\n\t\t}\n\n\t\tif (providerApiKey.startsWith(\"!\")) {\n\t\t\treturn { configured: true, source: \"models_json_command\" };\n\t\t}\n\n\t\tif (process.env[providerApiKey]) {\n\t\t\treturn { configured: true, source: \"environment\", label: providerApiKey };\n\t\t}\n\n\t\treturn { configured: true, source: \"models_json_key\" };\n\t}\n\n\t/**\n\t * Get display name for a provider.\n\t */\n\tgetProviderDisplayName(provider: string): string {\n\t\tconst registeredProvider = this.registeredProviders.get(provider);\n\t\tconst oauthProvider = this.authStorage.getOAuthProviders().find((p) => p.id === provider);\n\n\t\treturn (\n\t\t\tregisteredProvider?.name ??\n\t\t\tregisteredProvider?.oauth?.name ??\n\t\t\toauthProvider?.name ??\n\t\t\tBUILT_IN_PROVIDER_DISPLAY_NAMES[provider] ??\n\t\t\tprovider\n\t\t);\n\t}\n\n\t/**\n\t * Get API key for a provider.\n\t */\n\tasync getApiKeyForProvider(provider: string): Promise<string | undefined> {\n\t\tconst apiKey = await this.authStorage.getApiKey(provider, { includeFallback: false });\n\t\tif (apiKey !== undefined) {\n\t\t\treturn apiKey;\n\t\t}\n\n\t\tconst providerApiKey = this.providerRequestConfigs.get(provider)?.apiKey;\n\t\treturn providerApiKey ? resolveConfigValueUncached(providerApiKey) : undefined;\n\t}\n\n\t/**\n\t * Register an OpenAI-compatible provider from user input.\n\t * Unlike registerProvider(), this does NOT add to registeredProviders,\n\t * so logout works correctly: refresh() reads auth.json and skips deleted entries.\n\t */\n\tconfigureOpenAICompatibleProvider(\n\t\tproviderId: string,\n\t\tconfig: {\n\t\t\tbaseUrl: string;\n\t\t\tapiKey: string;\n\t\t\tmodels: Array<{ id: string; name: string }>;\n\t\t\tcompat?: OpenAICompatibleProviderInfo[\"compat\"];\n\t\t},\n\t): void {\n\t\tthis.storeProviderRequestConfig(providerId, { apiKey: config.apiKey });\n\n\t\tfor (const modelDef of config.models) {\n\t\t\tconst exists = this.models.some((m) => m.provider === providerId && m.id === modelDef.id);\n\t\t\tif (exists) continue;\n\n\t\t\tthis.models.push({\n\t\t\t\tid: modelDef.id,\n\t\t\t\tname: modelDef.name,\n\t\t\t\tapi: \"openai-completions\" as Api,\n\t\t\t\tprovider: providerId,\n\t\t\t\tbaseUrl: config.baseUrl,\n\t\t\t\treasoning: false,\n\t\t\t\tinput: [\"text\"],\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\t\t\tcontextWindow: 128000,\n\t\t\t\tmaxTokens: 16384,\n\t\t\t\theaders: undefined,\n\t\t\t\tcompat: config.compat,\n\t\t\t} as Model<Api>);\n\t\t}\n\t}\n\n\t/**\n\t * Check if a model is using OAuth credentials (subscription).\n\t */\n\tisUsingOAuth(model: Model<Api>): boolean {\n\t\tconst cred = this.authStorage.get(model.provider);\n\t\treturn cred?.type === \"oauth\";\n\t}\n\n\t/**\n\t * Register a provider dynamically (from extensions).\n\t *\n\t * If provider has models: replaces all existing models for this provider.\n\t * If provider has only baseUrl/headers: overrides existing models' URLs.\n\t * If provider has oauth: registers OAuth provider for /login support.\n\t */\n\tregisterProvider(providerName: string, config: ProviderConfigInput): void {\n\t\tthis.validateProviderConfig(providerName, config);\n\t\tthis.applyProviderConfig(providerName, config);\n\t\tthis.upsertRegisteredProvider(providerName, config);\n\t}\n\n\t/**\n\t * Unregister a previously registered provider.\n\t *\n\t * Removes the provider from the registry and reloads models from disk so that\n\t * built-in models overridden by this provider are restored to their original state.\n\t * Also resets dynamic OAuth and API stream registrations before reapplying\n\t * remaining dynamic providers.\n\t * Has no effect if the provider was never registered.\n\t */\n\tunregisterProvider(providerName: string): void {\n\t\tif (!this.registeredProviders.has(providerName)) return;\n\t\tthis.registeredProviders.delete(providerName);\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Upsert a provider config into registeredProviders.\n\t * If the provider is already registered, defined values in the incoming config\n\t * override existing ones; undefined values are preserved from the stored config.\n\t * If the provider is not registered, the incoming config is stored as-is.\n\t */\n\tprivate upsertRegisteredProvider(providerName: string, config: ProviderConfigInput): void {\n\t\tconst existing = this.registeredProviders.get(providerName);\n\t\tif (!existing) {\n\t\t\tthis.registeredProviders.set(providerName, config);\n\t\t\treturn;\n\t\t}\n\t\tfor (const k of Object.keys(config) as (keyof ProviderConfigInput)[]) {\n\t\t\tif (config[k] !== undefined) {\n\t\t\t\t(existing as Record<string, unknown>)[k] = config[k];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate validateProviderConfig(providerName: string, config: ProviderConfigInput): void {\n\t\tif (config.streamSimple && !config.api) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"api\" is required when registering streamSimple.`);\n\t\t}\n\n\t\tif (!config.models || config.models.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!config.baseUrl) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"baseUrl\" is required when defining models.`);\n\t\t}\n\t\tif (!config.apiKey && !config.oauth) {\n\t\t\tthrow new Error(`Provider ${providerName}: \"apiKey\" or \"oauth\" is required when defining models.`);\n\t\t}\n\n\t\tfor (const modelDef of config.models) {\n\t\t\tconst api = modelDef.api || config.api;\n\t\t\tif (!api) {\n\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: no \"api\" specified.`);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyProviderConfig(providerName: string, config: ProviderConfigInput): void {\n\t\t// Register OAuth provider if provided\n\t\tif (config.oauth) {\n\t\t\t// Ensure the OAuth provider ID matches the provider name\n\t\t\tconst oauthProvider: OAuthProviderInterface = {\n\t\t\t\t...config.oauth,\n\t\t\t\tid: providerName,\n\t\t\t};\n\t\t\tregisterOAuthProvider(oauthProvider);\n\t\t}\n\n\t\tif (config.streamSimple) {\n\t\t\tconst streamSimple = config.streamSimple;\n\t\t\tregisterApiProvider(\n\t\t\t\t{\n\t\t\t\t\tapi: config.api!,\n\t\t\t\t\tstream: (model, context, options) => streamSimple(model, context, options as SimpleStreamOptions),\n\t\t\t\t\tstreamSimple,\n\t\t\t\t},\n\t\t\t\t`provider:${providerName}`,\n\t\t\t);\n\t\t}\n\n\t\tthis.storeProviderRequestConfig(providerName, config);\n\n\t\tif (config.models && config.models.length > 0) {\n\t\t\t// Full replacement: remove existing models for this provider\n\t\t\tthis.models = this.models.filter((m) => m.provider !== providerName);\n\n\t\t\t// Parse and add new models\n\t\t\tfor (const modelDef of config.models) {\n\t\t\t\tconst api = modelDef.api || config.api;\n\t\t\t\tthis.storeModelHeaders(providerName, modelDef.id, modelDef.headers);\n\n\t\t\t\tthis.models.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl: modelDef.baseUrl ?? config.baseUrl!,\n\t\t\t\t\treasoning: modelDef.reasoning,\n\t\t\t\t\tthinkingLevelMap: modelDef.thinkingLevelMap,\n\t\t\t\t\tinput: modelDef.input as (\"text\" | \"image\")[],\n\t\t\t\t\tcost: modelDef.cost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens,\n\t\t\t\t\theaders: undefined,\n\t\t\t\t\tcompat: modelDef.compat,\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\n\t\t\t// Apply OAuth modifyModels if credentials exist (e.g., to update baseUrl)\n\t\t\tif (config.oauth?.modifyModels) {\n\t\t\t\tconst cred = this.authStorage.get(providerName);\n\t\t\t\tif (cred?.type === \"oauth\") {\n\t\t\t\t\tthis.models = config.oauth.modifyModels(this.models, cred);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (config.baseUrl || config.headers) {\n\t\t\t// Override-only: update baseUrl for existing models. Request headers are resolved per request.\n\t\t\tthis.models = this.models.map((m) => {\n\t\t\t\tif (m.provider !== providerName) return m;\n\t\t\t\treturn {\n\t\t\t\t\t...m,\n\t\t\t\t\tbaseUrl: config.baseUrl ?? m.baseUrl,\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Input type for registerProvider API.\n */\nexport interface ProviderConfigInput {\n\tname?: string;\n\tbaseUrl?: string;\n\tapiKey?: string;\n\tapi?: Api;\n\tstreamSimple?: (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;\n\theaders?: Record<string, string>;\n\tauthHeader?: boolean;\n\t/** OAuth provider for /login support */\n\toauth?: Omit<OAuthProviderInterface, \"id\">;\n\tmodels?: Array<{\n\t\tid: string;\n\t\tname: string;\n\t\tapi?: Api;\n\t\tbaseUrl?: string;\n\t\treasoning: boolean;\n\t\tthinkingLevelMap?: Model<Api>[\"thinkingLevelMap\"];\n\t\tinput: (\"text\" | \"image\")[];\n\t\tcost: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\t\tcontextWindow: number;\n\t\tmaxTokens: number;\n\t\theaders?: Record<string, string>;\n\t\tcompat?: Model<Api>[\"compat\"];\n\t}>;\n}\n"]}
|
|
@@ -96,6 +96,8 @@ export declare class ModelHubComponent extends Container implements Focusable {
|
|
|
96
96
|
private getFooterText;
|
|
97
97
|
private setTab;
|
|
98
98
|
private cycleTab;
|
|
99
|
+
/** Left/right switch tabs only when the search box is empty, so typing is unaffected. */
|
|
100
|
+
private trySwitchTabWithArrows;
|
|
99
101
|
private applySearch;
|
|
100
102
|
private ensureSelectableIndex;
|
|
101
103
|
private updateList;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-hub.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/model-hub.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,KAAK,EAAkB,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EACN,SAAS,EACT,KAAK,SAAS,EAGd,KAAK,EAKL,KAAK,GAAG,EACR,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AASzE,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAExD,UAAU,SAAS;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;CAClB;AAED,UAAU,eAAe;IACxB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAID,KAAK,SAAS,GACX;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAYtD,MAAM,WAAW,iBAAiB;IACjC,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,2CAA2C;IAC3C,aAAa,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,qCAAqC;IACrC,cAAc,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,2EAA2E;IAC3E,WAAW,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,kEAAkE;IAClE,YAAY,EAAE,CAAC,MAAM,EAAE,aAAa,GAAG,mBAAmB,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxG,kCAAkC;IAClC,cAAc,EAAE,CAAC,MAAM,EAAE,aAAa,GAAG,mBAAmB,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1G;AAMD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUtD;AAwDD,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACxC,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,SAAS,EAAE,CA4Ed;AAMD,qBAAa,iBAAkB,SAAQ,SAAU,YAAW,SAAS;IACpE,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,UAAU,CAAO;IACzB,OAAO,CAAC,UAAU,CAAO;IACzB,OAAO,CAAC,QAAQ,CAAO;IAEvB,OAAO,CAAC,QAAQ,CAAS;IACzB,IAAI,OAAO,IAAI,OAAO,CAErB;IACD,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,YAAY,CAAC,CAAa;IAClC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,SAAS,CAAoB;IAErC,OAAO,CAAC,GAAG,CAAc;IACzB,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,YAAY,CAAiC;IAGrD,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,iBAAiB,CAAqB;IAG9C,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,eAAe,CAAiC;IACxD,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,UAAU,CAAsE;IACxF,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,UAAU,CAAS;IAG3B,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,WAAW,CAAK;IAExB,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,cAAc,CAAK;IAE3B,YACC,GAAG,EAAE,GAAG,EACR,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,EACpC,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,aAAa,CAAC,eAAe,CAAC,EAC5C,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,EAChC,SAAS,EAAE,iBAAiB,EAC5B,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,WAAW,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;KAAE,EA2CnE;IAID,MAAM,IAAI,WAAW,CAEpB;IAED,cAAc,IAAI,KAAK,CAEtB;IAED,2CAA2C;IACrC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAEjC;YAIa,MAAM;IA2CpB,OAAO,CAAC,iBAAiB;IAmCzB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,aAAa;IAyBrB,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,WAAW;IA2CnB,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,gBAAgB;IAmDxB,OAAO,CAAC,eAAe;IAoCvB,OAAO,CAAC,gBAAgB;IA8BxB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CA8BjC;IAED,OAAO,CAAC,iBAAiB;IAiCzB,OAAO,CAAC,gBAAgB;IA0FxB,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,aAAa;IA0CrB,gEAAgE;IAC1D,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAGxC;CACD;AAED,qDAAqD;AACrD,OAAO,EAAE,iBAAiB,IAAI,sBAAsB,EAAE,CAAC","sourcesContent":["/**\n * Unified model hub: Select current model, manage cycle whitelist, manage custom providers.\n */\n\nimport { type Model, modelsAreEqual } from \"@openeryc/pi-ai\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@openeryc/pi-tui\";\nimport type { ModelRegistry } from \"../../../core/model-registry.ts\";\nimport type { SettingsManager } from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, keyText } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type ModelHubTab = \"select\" | \"cycle\" | \"manage\";\n\ninterface ModelItem {\n\tprovider: string;\n\tid: string;\n\tmodel: Model<any>;\n}\n\ninterface ScopedModelItem {\n\tmodel: Model<any>;\n\tthinkingLevel?: string;\n}\n\ntype EnabledIds = string[] | null;\n\ntype SelectRow =\n\t| { kind: \"header\"; label: string }\n\t| { kind: \"collapsed\"; provider: string; count: number }\n\t| { kind: \"model\"; item: ModelItem; badges: string };\n\ntype ManageRow =\n\t| {\n\t\t\tkind: \"provider\";\n\t\t\tsource: \"models_json\" | \"openai_compatible\";\n\t\t\tid: string;\n\t\t\tlabel: string;\n\t\t\tdetail: string;\n\t }\n\t| { kind: \"action\"; action: \"add\"; label: string };\n\nexport interface ModelHubCallbacks {\n\tonSelectModel: (model: Model<any>) => void | Promise<void>;\n\tonCancel: () => void;\n\t/** Cycle tab: session-only scope change */\n\tonCycleChange: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Cycle tab: persist to settings */\n\tonCyclePersist: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Manage tab: open add-provider wizard (writes models.json by default) */\n\tonManageAdd: () => void | Promise<void>;\n\t/** Manage tab: edit existing custom/openai_compatible provider */\n\tonManageEdit: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n\t/** Manage tab: remove provider */\n\tonManageRemove: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers (exported for tests)\n// ---------------------------------------------------------------------------\n\nexport function formatTokenCount(count: number): string {\n\tif (count >= 1_000_000) {\n\t\tconst millions = count / 1_000_000;\n\t\treturn millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;\n\t}\n\tif (count >= 1_000) {\n\t\tconst thousands = count / 1_000;\n\t\treturn thousands % 1 === 0 ? `${thousands}K` : `${thousands.toFixed(1)}K`;\n\t}\n\treturn count.toString();\n}\n\nfunction modelBadges(model: Model<any>): string {\n\tconst parts: string[] = [];\n\tif (model.reasoning) parts.push(\"R\");\n\tparts.push(formatTokenCount(model.contextWindow));\n\treturn parts.join(\" \");\n}\n\nfunction isEnabled(enabledIds: EnabledIds, id: string): boolean {\n\treturn enabledIds === null || enabledIds.includes(id);\n}\n\nfunction toggle(enabledIds: EnabledIds, id: string): EnabledIds {\n\tif (enabledIds === null) return [id];\n\tconst index = enabledIds.indexOf(id);\n\tif (index >= 0) return [...enabledIds.slice(0, index), ...enabledIds.slice(index + 1)];\n\treturn [...enabledIds, id];\n}\n\nfunction enableAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst targets = targetIds ?? allIds;\n\tconst result = [...enabledIds];\n\tfor (const id of targets) {\n\t\tif (!result.includes(id)) result.push(id);\n\t}\n\treturn result.length === allIds.length ? null : result;\n}\n\nfunction clearAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) {\n\t\treturn targetIds ? allIds.filter((id) => !targetIds.includes(id)) : [];\n\t}\n\tconst targets = new Set(targetIds ?? enabledIds);\n\treturn enabledIds.filter((id) => !targets.has(id));\n}\n\nfunction move(enabledIds: EnabledIds, id: string, delta: number): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst list = [...enabledIds];\n\tconst index = list.indexOf(id);\n\tif (index < 0) return list;\n\tconst newIndex = index + delta;\n\tif (newIndex < 0 || newIndex >= list.length) return list;\n\tconst result = [...list];\n\t[result[index], result[newIndex]] = [result[newIndex], result[index]];\n\treturn result;\n}\n\nfunction getSortedIds(enabledIds: EnabledIds, allIds: string[]): string[] {\n\tif (enabledIds === null) return allIds;\n\tconst enabledSet = new Set(enabledIds);\n\treturn [...enabledIds, ...allIds.filter((id) => !enabledSet.has(id))];\n}\n\nexport function buildSelectRows(options: {\n\tmodels: ModelItem[];\n\tcurrentModel?: Model<any>;\n\trecentKeys: string[];\n\tquery: string;\n\texpandedProviders: Set<string>;\n\tcollapsedLimit?: number;\n}): SelectRow[] {\n\tconst { models, currentModel, recentKeys, query, expandedProviders, collapsedLimit = 12 } = options;\n\tconst rows: SelectRow[] = [];\n\n\tif (query) {\n\t\tconst filtered = fuzzyFilter(\n\t\t\tmodels,\n\t\t\tquery,\n\t\t\t({ id, provider, model }) => `${id} ${provider} ${provider}/${id} ${model.name ?? \"\"} ${provider} ${id}`,\n\t\t);\n\t\tfor (const item of filtered) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t\treturn rows;\n\t}\n\n\tconst byKey = new Map(models.map((m) => [`${m.provider}/${m.id}`, m]));\n\tconst seen = new Set<string>();\n\n\t// Current first (if available)\n\tif (currentModel) {\n\t\tconst key = `${currentModel.provider}/${currentModel.id}`;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trows.push({ kind: \"header\", label: \"Current\" });\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\n\t// Recent\n\tconst recentItems: ModelItem[] = [];\n\tfor (const key of recentKeys) {\n\t\tif (seen.has(key)) continue;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trecentItems.push(item);\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\tif (recentItems.length > 0) {\n\t\trows.push({ kind: \"header\", label: \"Recent\" });\n\t\tfor (const item of recentItems.slice(0, 8)) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\t// Group remaining by provider\n\tconst byProvider = new Map<string, ModelItem[]>();\n\tfor (const item of models) {\n\t\tconst key = `${item.provider}/${item.id}`;\n\t\tif (seen.has(key)) continue;\n\t\tconst list = byProvider.get(item.provider) ?? [];\n\t\tlist.push(item);\n\t\tbyProvider.set(item.provider, list);\n\t}\n\n\tconst providers = [...byProvider.keys()].sort((a, b) => a.localeCompare(b));\n\tconst currentProvider = currentModel?.provider;\n\n\tfor (const provider of providers) {\n\t\tconst list = byProvider.get(provider) ?? [];\n\t\tlist.sort((a, b) => a.id.localeCompare(b.id));\n\t\tconst expand = expandedProviders.has(provider) || provider === currentProvider || list.length <= collapsedLimit;\n\n\t\trows.push({ kind: \"header\", label: provider });\n\t\tif (!expand) {\n\t\t\trows.push({ kind: \"collapsed\", provider, count: list.length });\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const item of list) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\treturn rows;\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport class ModelHubComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate listContainer: Container;\n\tprivate headerText: Text;\n\tprivate footerText: Text;\n\tprivate hintText: Text;\n\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tprivate tui: TUI;\n\tprivate currentModel?: Model<any>;\n\tprivate settingsManager: SettingsManager;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate callbacks: ModelHubCallbacks;\n\n\tprivate tab: ModelHubTab;\n\tprivate allModels: ModelItem[] = [];\n\tprivate scopedModels: ReadonlyArray<ScopedModelItem>;\n\n\t// Select state\n\tprivate selectRows: SelectRow[] = [];\n\tprivate selectIndex = 0;\n\tprivate expandedProviders = new Set<string>();\n\n\t// Cycle state\n\tprivate cycleAllIds: string[] = [];\n\tprivate cycleModelsById = new Map<string, Model<any>>();\n\tprivate enabledIds: EnabledIds = null;\n\tprivate cycleItems: Array<{ fullId: string; model: Model<any>; enabled: boolean }> = [];\n\tprivate cycleIndex = 0;\n\tprivate cycleDirty = false;\n\n\t// Manage state\n\tprivate manageRows: ManageRow[] = [];\n\tprivate manageIndex = 0;\n\n\tprivate errorMessage?: string;\n\tprivate maxVisible = 10;\n\tprivate loadGeneration = 0;\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tcurrentModel: Model<any> | undefined,\n\t\tsettingsManager: SettingsManager,\n\t\tmodelRegistry: ModelRegistry,\n\t\tscopedModels: ReadonlyArray<ScopedModelItem>,\n\t\tenabledModelIds: string[] | null,\n\t\tcallbacks: ModelHubCallbacks,\n\t\toptions?: { initialTab?: ModelHubTab; initialSearchInput?: string },\n\t) {\n\t\tsuper();\n\t\tthis.tui = tui;\n\t\tthis.currentModel = currentModel;\n\t\tthis.settingsManager = settingsManager;\n\t\tthis.modelRegistry = modelRegistry;\n\t\tthis.scopedModels = scopedModels;\n\t\tthis.callbacks = callbacks;\n\t\tthis.tab = options?.initialTab ?? \"select\";\n\t\tthis.enabledIds = enabledModelIds === null ? null : [...enabledModelIds];\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.headerText = new Text(this.getHeaderText(), 0, 0);\n\t\tthis.addChild(this.headerText);\n\t\tthis.hintText = new Text(this.getHintText(), 0, 0);\n\t\tthis.addChild(this.hintText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new Input();\n\t\tif (options?.initialSearchInput) {\n\t\t\tthis.searchInput.setValue(options.initialSearchInput);\n\t\t}\n\t\tthis.searchInput.onSubmit = () => this.handleConfirm();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tvoid this.reload().then(() => {\n\t\t\tif (options?.initialSearchInput) {\n\t\t\t\tthis.applySearch();\n\t\t\t}\n\t\t\tthis.tui.requestRender();\n\t\t});\n\t}\n\n\t// ---- public helpers for tests ----\n\n\tgetTab(): ModelHubTab {\n\t\treturn this.tab;\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n\n\t/** Test helper: force reload completion */\n\tasync waitForLoad(): Promise<void> {\n\t\tawait this.reload();\n\t}\n\n\t// ---- load ----\n\n\tprivate async reload(): Promise<void> {\n\t\tconst gen = ++this.loadGeneration;\n\t\tthis.modelRegistry.refresh();\n\t\tconst loadError = this.modelRegistry.getError();\n\t\tif (loadError) {\n\t\t\tthis.errorMessage = loadError;\n\t\t} else {\n\t\t\tthis.errorMessage = undefined;\n\t\t}\n\n\t\ttry {\n\t\t\tconst available = this.modelRegistry.getAvailable();\n\t\t\tif (gen !== this.loadGeneration) return;\n\n\t\t\tthis.allModels = available.map((model) => ({\n\t\t\t\tprovider: model.provider,\n\t\t\t\tid: model.id,\n\t\t\t\tmodel,\n\t\t\t}));\n\n\t\t\t// Refresh scoped models against registry\n\t\t\tthis.scopedModels = this.scopedModels.map((scoped) => {\n\t\t\t\tconst refreshed = this.modelRegistry.find(scoped.model.provider, scoped.model.id);\n\t\t\t\treturn refreshed ? { ...scoped, model: refreshed } : scoped;\n\t\t\t});\n\n\t\t\tthis.cycleModelsById.clear();\n\t\t\tthis.cycleAllIds = [];\n\t\t\tfor (const item of this.allModels) {\n\t\t\t\tconst fullId = `${item.provider}/${item.id}`;\n\t\t\t\tthis.cycleModelsById.set(fullId, item.model);\n\t\t\t\tthis.cycleAllIds.push(fullId);\n\t\t\t}\n\n\t\t\tthis.rebuildManageRows();\n\t\t\tthis.applySearch();\n\t\t} catch (error) {\n\t\t\tthis.allModels = [];\n\t\t\tthis.errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tthis.applySearch();\n\t\t}\n\t}\n\n\tprivate rebuildManageRows(): void {\n\t\tconst rows: ManageRow[] = [];\n\t\trows.push({ kind: \"action\", action: \"add\", label: \"+ Add custom provider (models.json)\" });\n\n\t\tfor (const p of this.modelRegistry.listModelsJsonProviders()) {\n\t\t\tconst modelLabel =\n\t\t\t\tp.modelIds.length === 0\n\t\t\t\t\t? \"override only\"\n\t\t\t\t\t: `${p.modelIds.length} model${p.modelIds.length === 1 ? \"\" : \"s\"}`;\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"models_json\",\n\t\t\t\tid: p.name,\n\t\t\t\tlabel: p.name,\n\t\t\t\tdetail: `${p.isBuiltIn ? \"built-in override\" : \"custom\"} · ${modelLabel}${p.baseUrl ? ` · ${p.baseUrl}` : \"\"}`,\n\t\t\t});\n\t\t}\n\n\t\tconst openaiCompat = this.modelRegistry.authStorage.getOpenAICompatibleProviders();\n\t\tfor (const [id, info] of Object.entries(openaiCompat)) {\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"openai_compatible\",\n\t\t\t\tid,\n\t\t\t\tlabel: id,\n\t\t\t\tdetail: `openai-compatible · ${info.models.length} model${info.models.length === 1 ? \"\" : \"s\"} · ${info.baseUrl}`,\n\t\t\t});\n\t\t}\n\n\t\tthis.manageRows = rows;\n\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, rows.length - 1));\n\t}\n\n\t// ---- header / footer ----\n\n\tprivate getHeaderText(): string {\n\t\tconst tabs: Array<{ id: ModelHubTab; label: string }> = [\n\t\t\t{ id: \"select\", label: \"Select\" },\n\t\t\t{ id: \"cycle\", label: \"Cycle\" },\n\t\t\t{ id: \"manage\", label: \"Manage\" },\n\t\t];\n\t\tconst parts = tabs.map((t) => (t.id === this.tab ? theme.fg(\"accent\", t.label) : theme.fg(\"muted\", t.label)));\n\t\treturn `${theme.fg(\"muted\", \"Models: \")}${parts.join(theme.fg(\"muted\", \" | \"))}`;\n\t}\n\n\tprivate getHintText(): string {\n\t\tif (this.tab === \"select\") {\n\t\t\treturn (\n\t\t\t\tkeyHint(\"tui.input.tab\", \"tabs\") +\n\t\t\t\ttheme.fg(\"muted\", \" · type to search · Enter select · collapsed providers: Enter expand\")\n\t\t\t);\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\treturn (\n\t\t\t\tkeyHint(\"tui.input.tab\", \"tabs\") + theme.fg(\"muted\", ` · session-only until ${keyText(\"app.models.save\")}`)\n\t\t\t);\n\t\t}\n\t\treturn keyHint(\"tui.input.tab\", \"tabs\") + theme.fg(\"muted\", \" · Enter edit/add · Backspace/Delete remove\");\n\t}\n\n\tprivate getFooterText(): string {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst modelCount = this.selectRows.filter((r) => r.kind === \"model\").length;\n\t\t\treturn theme.fg(\"dim\", ` ${modelCount} model${modelCount === 1 ? \"\" : \"s\"} · Esc cancel`);\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst enabledCount = this.enabledIds?.length ?? this.cycleAllIds.length;\n\t\t\tconst allEnabled = this.enabledIds === null;\n\t\t\tconst countText = allEnabled ? \"all enabled\" : `${enabledCount}/${this.cycleAllIds.length} enabled`;\n\t\t\tconst parts = [\n\t\t\t\t`${keyText(\"tui.select.confirm\")} toggle`,\n\t\t\t\t`${keyText(\"app.models.enableAll\")} all`,\n\t\t\t\t`${keyText(\"app.models.clearAll\")} clear`,\n\t\t\t\t`${keyText(\"app.models.toggleProvider\")} provider`,\n\t\t\t\t`${keyText(\"app.models.reorderUp\")}/${keyText(\"app.models.reorderDown\")} reorder`,\n\t\t\t\t`${keyText(\"app.models.save\")} save`,\n\t\t\t\tcountText,\n\t\t\t];\n\t\t\treturn this.cycleDirty\n\t\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t\t}\n\t\treturn theme.fg(\"dim\", \" Enter open · Backspace delete · writing models.json drops comments/trailing commas\");\n\t}\n\n\tprivate setTab(tab: ModelHubTab): void {\n\t\tif (this.tab === tab) return;\n\t\tthis.tab = tab;\n\t\tthis.headerText.setText(this.getHeaderText());\n\t\tthis.hintText.setText(this.getHintText());\n\t\tthis.applySearch();\n\t}\n\n\tprivate cycleTab(): void {\n\t\tconst order: ModelHubTab[] = [\"select\", \"cycle\", \"manage\"];\n\t\tconst idx = order.indexOf(this.tab);\n\t\tthis.setTab(order[(idx + 1) % order.length]!);\n\t}\n\n\t// ---- list building ----\n\n\tprivate applySearch(): void {\n\t\tconst query = this.searchInput.getValue();\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.selectRows = buildSelectRows({\n\t\t\t\tmodels: this.allModels,\n\t\t\t\tcurrentModel: this.currentModel,\n\t\t\t\trecentKeys: this.settingsManager.getRecentModels(),\n\t\t\t\tquery,\n\t\t\t\texpandedProviders: this.expandedProviders,\n\t\t\t});\n\t\t\t// Prefer current model selection\n\t\t\tconst currentIdx = this.selectRows.findIndex(\n\t\t\t\t(r) => r.kind === \"model\" && modelsAreEqual(this.currentModel, r.item.model),\n\t\t\t);\n\t\t\tthis.selectIndex =\n\t\t\t\tcurrentIdx >= 0 ? currentIdx : Math.min(this.selectIndex, Math.max(0, this.selectRows.length - 1));\n\t\t\t// Snap to first selectable if landing on header\n\t\t\tthis.ensureSelectableIndex(\"select\");\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tconst items = getSortedIds(this.enabledIds, this.cycleAllIds)\n\t\t\t\t.filter((id) => this.cycleModelsById.has(id))\n\t\t\t\t.map((id) => ({\n\t\t\t\t\tfullId: id,\n\t\t\t\t\tmodel: this.cycleModelsById.get(id)!,\n\t\t\t\t\tenabled: isEnabled(this.enabledIds, id),\n\t\t\t\t}));\n\t\t\tthis.cycleItems = query ? fuzzyFilter(items, query, (i) => `${i.model.id} ${i.model.provider}`) : items;\n\t\t\tthis.cycleIndex = Math.min(this.cycleIndex, Math.max(0, this.cycleItems.length - 1));\n\t\t} else {\n\t\t\tthis.rebuildManageRows();\n\t\t\tif (query) {\n\t\t\t\tthis.manageRows = fuzzyFilter(this.manageRows, query, (r) =>\n\t\t\t\t\tr.kind === \"action\" ? r.label : `${r.label} ${r.detail} ${r.id}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, this.manageRows.length - 1));\n\t\t}\n\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate ensureSelectableIndex(which: \"select\"): void {\n\t\tif (which !== \"select\" || this.selectRows.length === 0) return;\n\t\tif (this.selectRows[this.selectIndex]?.kind === \"header\") {\n\t\t\tconst next = this.selectRows.findIndex((r, i) => i >= this.selectIndex && r.kind !== \"header\");\n\t\t\tif (next >= 0) {\n\t\t\t\tthis.selectIndex = next;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst prev = [...this.selectRows]\n\t\t\t\t.map((r, i) => ({ r, i }))\n\t\t\t\t.reverse()\n\t\t\t\t.find(({ r }) => r.kind !== \"header\");\n\t\t\tif (prev) this.selectIndex = prev.i;\n\t\t}\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tif (this.errorMessage && this.tab !== \"manage\") {\n\t\t\tfor (const line of this.errorMessage.split(\"\\n\")) {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"error\", line), 0, 0));\n\t\t\t}\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.renderSelectList();\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.renderCycleList();\n\t\t} else {\n\t\t\tthis.renderManageList();\n\t\t}\n\t}\n\n\tprivate renderSelectList(): void {\n\t\tif (this.selectRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectIndex - Math.floor(this.maxVisible / 2), this.selectRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.selectRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.selectRows[i]!;\n\t\t\tconst isSelected = i === this.selectIndex;\n\n\t\t\tif (row.kind === \"header\") {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ── ${row.label} ──`), 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\t\tconst text = isSelected\n\t\t\t\t\t? theme.fg(\"accent\", `▸ ${row.provider} (${row.count})`)\n\t\t\t\t\t: theme.fg(\"muted\", `▸ ${row.provider} (${row.count})`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst isCurrent = modelsAreEqual(this.currentModel, row.item.model);\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", row.item.id) : row.item.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${row.item.provider}]`);\n\t\t\tconst badges = theme.fg(\"dim\", ` ${row.badges}`);\n\t\t\tconst check = isCurrent ? theme.fg(\"success\", \" ✓\") : \"\";\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${badges}${check}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.selectRows.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectIndex + 1}/${this.selectRows.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tconst selected = this.selectRows[this.selectIndex];\n\t\tif (selected?.kind === \"model\") {\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected.item.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderCycleList(): void {\n\t\tif (this.cycleItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.cycleIndex - Math.floor(this.maxVisible / 2), this.cycleItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.cycleItems.length);\n\t\tconst allEnabled = this.enabledIds === null;\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.cycleItems[i]!;\n\t\t\tconst isSelected = i === this.cycleIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", item.model.id) : item.model.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${item.model.provider}]`);\n\t\t\tconst status = allEnabled ? \"\" : item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.cycleItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.cycleIndex + 1}/${this.cycleItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tif (this.cycleItems.length > 0) {\n\t\t\tconst selected = this.cycleItems[this.cycleIndex];\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected?.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderManageList(): void {\n\t\tif (this.manageRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No custom providers\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.manageIndex - Math.floor(this.maxVisible / 2), this.manageRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.manageRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.manageRows[i]!;\n\t\t\tconst isSelected = i === this.manageIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tif (row.kind === \"action\") {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : theme.fg(\"success\", row.label);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t} else {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : row.label;\n\t\t\t\tconst detail = theme.fg(\"muted\", ` ${row.detail}`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tthis.listContainer.addChild(new Text(`${detail}`, 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t// ---- input ----\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(keyData, \"tui.input.tab\")) {\n\t\t\tthis.cycleTab();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.cancel\") || matchesKey(keyData, Key.escape)) {\n\t\t\tthis.callbacks.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\tif (matchesKey(keyData, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.applySearch();\n\t\t\t} else {\n\t\t\t\tthis.callbacks.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.handleSelectInput(keyData, kb);\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.handleCycleInput(keyData, kb);\n\t\t} else {\n\t\t\tthis.handleManageInput(keyData, kb);\n\t\t}\n\t}\n\n\tprivate handleSelectInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === 0 ? this.selectRows.length - 1 : this.selectIndex - 1;\n\t\t\t// Skip headers when moving\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === 0 ? this.selectRows.length - 1 : next - 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === this.selectRows.length - 1 ? 0 : this.selectIndex + 1;\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === this.selectRows.length - 1 ? 0 : next + 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleCycleInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === 0 ? this.cycleItems.length - 1 : this.cycleIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === this.cycleItems.length - 1 ? 0 : this.cycleIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\tconst reorderUp = kb.matches(keyData, \"app.models.reorderUp\");\n\t\tconst reorderDown = kb.matches(keyData, \"app.models.reorderDown\");\n\t\tif (reorderUp || reorderDown) {\n\t\t\tif (this.enabledIds === null) return;\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item && isEnabled(this.enabledIds, item.fullId)) {\n\t\t\t\tconst delta = reorderUp ? -1 : 1;\n\t\t\t\tconst currentIndex = this.enabledIds.indexOf(item.fullId);\n\t\t\t\tconst newIndex = currentIndex + delta;\n\t\t\t\tif (newIndex >= 0 && newIndex < this.enabledIds.length) {\n\t\t\t\t\tthis.enabledIds = move(this.enabledIds, item.fullId, delta);\n\t\t\t\t\tthis.cycleDirty = true;\n\t\t\t\t\tthis.cycleIndex += delta;\n\t\t\t\t\tthis.applySearch();\n\t\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.enableAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = enableAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.clearAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = clearAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.toggleProvider\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tconst provider = item.model.provider;\n\t\t\t\tconst providerIds = this.cycleAllIds.filter((id) => this.cycleModelsById.get(id)!.provider === provider);\n\t\t\t\tconst allOn = providerIds.every((id) => isEnabled(this.enabledIds, id));\n\t\t\t\tthis.enabledIds = allOn\n\t\t\t\t\t? clearAll(this.enabledIds, this.cycleAllIds, providerIds)\n\t\t\t\t\t: enableAll(this.enabledIds, this.cycleAllIds, providerIds);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.save\")) {\n\t\t\tvoid this.callbacks.onCyclePersist(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\tthis.cycleDirty = false;\n\t\t\tthis.footerText.setText(this.getFooterText());\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleManageInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === 0 ? this.manageRows.length - 1 : this.manageIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === this.manageRows.length - 1 ? 0 : this.manageIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\t\t// Backspace / Delete remove selected provider\n\t\tif (matchesKey(keyData, Key.backspace) || matchesKey(keyData, Key.delete)) {\n\t\t\tconst row = this.manageRows[this.manageIndex];\n\t\t\tif (row?.kind === \"provider\") {\n\t\t\t\tvoid this.callbacks.onManageRemove(row.source, row.id);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleConfirm(): void {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst row = this.selectRows[this.selectIndex];\n\t\t\tif (!row) return;\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tthis.expandedProviders.add(row.provider);\n\t\t\t\tthis.applySearch();\n\t\t\t\t// Move selection to first model under that provider\n\t\t\t\tconst idx = this.selectRows.findIndex((r) => r.kind === \"model\" && r.item.provider === row.provider);\n\t\t\t\tif (idx >= 0) this.selectIndex = idx;\n\t\t\t\tthis.updateList();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (row.kind === \"model\") {\n\t\t\t\tthis.settingsManager.setDefaultModelAndProvider(row.item.model.provider, row.item.model.id);\n\t\t\t\tvoid this.callbacks.onSelectModel(row.item.model);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst row = this.manageRows[this.manageIndex];\n\t\tif (!row) return;\n\t\tif (row.kind === \"action\" && row.action === \"add\") {\n\t\t\tvoid this.callbacks.onManageAdd();\n\t\t\treturn;\n\t\t}\n\t\tif (row.kind === \"provider\") {\n\t\t\tvoid this.callbacks.onManageEdit(row.source, row.id);\n\t\t}\n\t}\n\n\t/** Called by parent after manage mutation so list refreshes. */\n\tasync refreshAfterManage(): Promise<void> {\n\t\tawait this.reload();\n\t\tthis.tui.requestRender();\n\t}\n}\n\n/** Back-compat alias used by older tests/imports. */\nexport { ModelHubComponent as ModelSelectorComponent };\n"]}
|
|
1
|
+
{"version":3,"file":"model-hub.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/model-hub.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified model hub: Select current model, manage cycle whitelist, manage custom providers.\n */\n\nimport { type Model, modelsAreEqual } from \"@openeryc/pi-ai\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@openeryc/pi-tui\";\nimport type { ModelRegistry } from \"../../../core/model-registry.ts\";\nimport type { SettingsManager } from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, keyText } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type ModelHubTab = \"select\" | \"cycle\" | \"manage\";\n\ninterface ModelItem {\n\tprovider: string;\n\tid: string;\n\tmodel: Model<any>;\n}\n\ninterface ScopedModelItem {\n\tmodel: Model<any>;\n\tthinkingLevel?: string;\n}\n\ntype EnabledIds = string[] | null;\n\ntype SelectRow =\n\t| { kind: \"header\"; label: string }\n\t| { kind: \"collapsed\"; provider: string; count: number }\n\t| { kind: \"model\"; item: ModelItem; badges: string };\n\ntype ManageRow =\n\t| {\n\t\t\tkind: \"provider\";\n\t\t\tsource: \"models_json\" | \"openai_compatible\";\n\t\t\tid: string;\n\t\t\tlabel: string;\n\t\t\tdetail: string;\n\t }\n\t| { kind: \"action\"; action: \"add\"; label: string };\n\nexport interface ModelHubCallbacks {\n\tonSelectModel: (model: Model<any>) => void | Promise<void>;\n\tonCancel: () => void;\n\t/** Cycle tab: session-only scope change */\n\tonCycleChange: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Cycle tab: persist to settings */\n\tonCyclePersist: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Manage tab: open add-provider wizard (writes models.json by default) */\n\tonManageAdd: () => void | Promise<void>;\n\t/** Manage tab: edit existing custom/openai_compatible provider */\n\tonManageEdit: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n\t/** Manage tab: remove provider */\n\tonManageRemove: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers (exported for tests)\n// ---------------------------------------------------------------------------\n\nexport function formatTokenCount(count: number): string {\n\tif (count >= 1_000_000) {\n\t\tconst millions = count / 1_000_000;\n\t\treturn millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;\n\t}\n\tif (count >= 1_000) {\n\t\tconst thousands = count / 1_000;\n\t\treturn thousands % 1 === 0 ? `${thousands}K` : `${thousands.toFixed(1)}K`;\n\t}\n\treturn count.toString();\n}\n\nfunction modelBadges(model: Model<any>): string {\n\tconst parts: string[] = [];\n\tif (model.reasoning) parts.push(\"R\");\n\tparts.push(formatTokenCount(model.contextWindow));\n\treturn parts.join(\" \");\n}\n\nfunction isEnabled(enabledIds: EnabledIds, id: string): boolean {\n\treturn enabledIds === null || enabledIds.includes(id);\n}\n\nfunction toggle(enabledIds: EnabledIds, id: string): EnabledIds {\n\tif (enabledIds === null) return [id];\n\tconst index = enabledIds.indexOf(id);\n\tif (index >= 0) return [...enabledIds.slice(0, index), ...enabledIds.slice(index + 1)];\n\treturn [...enabledIds, id];\n}\n\nfunction enableAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst targets = targetIds ?? allIds;\n\tconst result = [...enabledIds];\n\tfor (const id of targets) {\n\t\tif (!result.includes(id)) result.push(id);\n\t}\n\treturn result.length === allIds.length ? null : result;\n}\n\nfunction clearAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) {\n\t\treturn targetIds ? allIds.filter((id) => !targetIds.includes(id)) : [];\n\t}\n\tconst targets = new Set(targetIds ?? enabledIds);\n\treturn enabledIds.filter((id) => !targets.has(id));\n}\n\nfunction move(enabledIds: EnabledIds, id: string, delta: number): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst list = [...enabledIds];\n\tconst index = list.indexOf(id);\n\tif (index < 0) return list;\n\tconst newIndex = index + delta;\n\tif (newIndex < 0 || newIndex >= list.length) return list;\n\tconst result = [...list];\n\t[result[index], result[newIndex]] = [result[newIndex], result[index]];\n\treturn result;\n}\n\nfunction getSortedIds(enabledIds: EnabledIds, allIds: string[]): string[] {\n\tif (enabledIds === null) return allIds;\n\tconst enabledSet = new Set(enabledIds);\n\treturn [...enabledIds, ...allIds.filter((id) => !enabledSet.has(id))];\n}\n\nexport function buildSelectRows(options: {\n\tmodels: ModelItem[];\n\tcurrentModel?: Model<any>;\n\trecentKeys: string[];\n\tquery: string;\n\texpandedProviders: Set<string>;\n\tcollapsedLimit?: number;\n}): SelectRow[] {\n\tconst { models, currentModel, recentKeys, query, expandedProviders, collapsedLimit = 12 } = options;\n\tconst rows: SelectRow[] = [];\n\n\tif (query) {\n\t\tconst filtered = fuzzyFilter(\n\t\t\tmodels,\n\t\t\tquery,\n\t\t\t({ id, provider, model }) => `${id} ${provider} ${provider}/${id} ${model.name ?? \"\"} ${provider} ${id}`,\n\t\t);\n\t\tfor (const item of filtered) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t\treturn rows;\n\t}\n\n\tconst byKey = new Map(models.map((m) => [`${m.provider}/${m.id}`, m]));\n\tconst seen = new Set<string>();\n\n\t// Current first (if available)\n\tif (currentModel) {\n\t\tconst key = `${currentModel.provider}/${currentModel.id}`;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trows.push({ kind: \"header\", label: \"Current\" });\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\n\t// Recent\n\tconst recentItems: ModelItem[] = [];\n\tfor (const key of recentKeys) {\n\t\tif (seen.has(key)) continue;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trecentItems.push(item);\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\tif (recentItems.length > 0) {\n\t\trows.push({ kind: \"header\", label: \"Recent\" });\n\t\tfor (const item of recentItems.slice(0, 8)) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\t// Group remaining by provider\n\tconst byProvider = new Map<string, ModelItem[]>();\n\tfor (const item of models) {\n\t\tconst key = `${item.provider}/${item.id}`;\n\t\tif (seen.has(key)) continue;\n\t\tconst list = byProvider.get(item.provider) ?? [];\n\t\tlist.push(item);\n\t\tbyProvider.set(item.provider, list);\n\t}\n\n\tconst providers = [...byProvider.keys()].sort((a, b) => a.localeCompare(b));\n\tconst currentProvider = currentModel?.provider;\n\n\tfor (const provider of providers) {\n\t\tconst list = byProvider.get(provider) ?? [];\n\t\tlist.sort((a, b) => a.id.localeCompare(b.id));\n\t\tconst expand = expandedProviders.has(provider) || provider === currentProvider || list.length <= collapsedLimit;\n\n\t\trows.push({ kind: \"header\", label: provider });\n\t\tif (!expand) {\n\t\t\trows.push({ kind: \"collapsed\", provider, count: list.length });\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const item of list) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\treturn rows;\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport class ModelHubComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate listContainer: Container;\n\tprivate headerText: Text;\n\tprivate footerText: Text;\n\tprivate hintText: Text;\n\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tprivate tui: TUI;\n\tprivate currentModel?: Model<any>;\n\tprivate settingsManager: SettingsManager;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate callbacks: ModelHubCallbacks;\n\n\tprivate tab: ModelHubTab;\n\tprivate allModels: ModelItem[] = [];\n\tprivate scopedModels: ReadonlyArray<ScopedModelItem>;\n\n\t// Select state\n\tprivate selectRows: SelectRow[] = [];\n\tprivate selectIndex = 0;\n\tprivate expandedProviders = new Set<string>();\n\n\t// Cycle state\n\tprivate cycleAllIds: string[] = [];\n\tprivate cycleModelsById = new Map<string, Model<any>>();\n\tprivate enabledIds: EnabledIds = null;\n\tprivate cycleItems: Array<{ fullId: string; model: Model<any>; enabled: boolean }> = [];\n\tprivate cycleIndex = 0;\n\tprivate cycleDirty = false;\n\n\t// Manage state\n\tprivate manageRows: ManageRow[] = [];\n\tprivate manageIndex = 0;\n\n\tprivate errorMessage?: string;\n\tprivate maxVisible = 10;\n\tprivate loadGeneration = 0;\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tcurrentModel: Model<any> | undefined,\n\t\tsettingsManager: SettingsManager,\n\t\tmodelRegistry: ModelRegistry,\n\t\tscopedModels: ReadonlyArray<ScopedModelItem>,\n\t\tenabledModelIds: string[] | null,\n\t\tcallbacks: ModelHubCallbacks,\n\t\toptions?: { initialTab?: ModelHubTab; initialSearchInput?: string },\n\t) {\n\t\tsuper();\n\t\tthis.tui = tui;\n\t\tthis.currentModel = currentModel;\n\t\tthis.settingsManager = settingsManager;\n\t\tthis.modelRegistry = modelRegistry;\n\t\tthis.scopedModels = scopedModels;\n\t\tthis.callbacks = callbacks;\n\t\tthis.tab = options?.initialTab ?? \"select\";\n\t\tthis.enabledIds = enabledModelIds === null ? null : [...enabledModelIds];\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.headerText = new Text(this.getHeaderText(), 0, 0);\n\t\tthis.addChild(this.headerText);\n\t\tthis.hintText = new Text(this.getHintText(), 0, 0);\n\t\tthis.addChild(this.hintText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new Input();\n\t\tif (options?.initialSearchInput) {\n\t\t\tthis.searchInput.setValue(options.initialSearchInput);\n\t\t}\n\t\tthis.searchInput.onSubmit = () => this.handleConfirm();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tvoid this.reload().then(() => {\n\t\t\tif (options?.initialSearchInput) {\n\t\t\t\tthis.applySearch();\n\t\t\t}\n\t\t\tthis.tui.requestRender();\n\t\t});\n\t}\n\n\t// ---- public helpers for tests ----\n\n\tgetTab(): ModelHubTab {\n\t\treturn this.tab;\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n\n\t/** Test helper: force reload completion */\n\tasync waitForLoad(): Promise<void> {\n\t\tawait this.reload();\n\t}\n\n\t// ---- load ----\n\n\tprivate async reload(): Promise<void> {\n\t\tconst gen = ++this.loadGeneration;\n\t\tthis.modelRegistry.refresh();\n\t\tconst loadError = this.modelRegistry.getError();\n\t\tif (loadError) {\n\t\t\tthis.errorMessage = loadError;\n\t\t} else {\n\t\t\tthis.errorMessage = undefined;\n\t\t}\n\n\t\ttry {\n\t\t\tconst available = this.modelRegistry.getAvailable();\n\t\t\tif (gen !== this.loadGeneration) return;\n\n\t\t\tthis.allModels = available.map((model) => ({\n\t\t\t\tprovider: model.provider,\n\t\t\t\tid: model.id,\n\t\t\t\tmodel,\n\t\t\t}));\n\n\t\t\t// Refresh scoped models against registry\n\t\t\tthis.scopedModels = this.scopedModels.map((scoped) => {\n\t\t\t\tconst refreshed = this.modelRegistry.find(scoped.model.provider, scoped.model.id);\n\t\t\t\treturn refreshed ? { ...scoped, model: refreshed } : scoped;\n\t\t\t});\n\n\t\t\tthis.cycleModelsById.clear();\n\t\t\tthis.cycleAllIds = [];\n\t\t\tfor (const item of this.allModels) {\n\t\t\t\tconst fullId = `${item.provider}/${item.id}`;\n\t\t\t\tthis.cycleModelsById.set(fullId, item.model);\n\t\t\t\tthis.cycleAllIds.push(fullId);\n\t\t\t}\n\n\t\t\tthis.rebuildManageRows();\n\t\t\tthis.applySearch();\n\t\t} catch (error) {\n\t\t\tthis.allModels = [];\n\t\t\tthis.errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tthis.applySearch();\n\t\t}\n\t}\n\n\tprivate rebuildManageRows(): void {\n\t\tconst rows: ManageRow[] = [];\n\t\trows.push({ kind: \"action\", action: \"add\", label: \"+ Add custom provider (models.json)\" });\n\n\t\tfor (const p of this.modelRegistry.listModelsJsonProviders()) {\n\t\t\tconst modelLabel =\n\t\t\t\tp.modelIds.length === 0\n\t\t\t\t\t? \"override only\"\n\t\t\t\t\t: `${p.modelIds.length} model${p.modelIds.length === 1 ? \"\" : \"s\"}`;\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"models_json\",\n\t\t\t\tid: p.name,\n\t\t\t\tlabel: p.name,\n\t\t\t\tdetail: `${p.isBuiltIn ? \"built-in override\" : \"custom\"} · ${modelLabel}${p.baseUrl ? ` · ${p.baseUrl}` : \"\"}`,\n\t\t\t});\n\t\t}\n\n\t\tconst openaiCompat = this.modelRegistry.authStorage.getOpenAICompatibleProviders();\n\t\tfor (const [id, info] of Object.entries(openaiCompat)) {\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"openai_compatible\",\n\t\t\t\tid,\n\t\t\t\tlabel: id,\n\t\t\t\tdetail: `openai-compatible · ${info.models.length} model${info.models.length === 1 ? \"\" : \"s\"} · ${info.baseUrl}`,\n\t\t\t});\n\t\t}\n\n\t\tthis.manageRows = rows;\n\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, rows.length - 1));\n\t}\n\n\t// ---- header / footer ----\n\n\tprivate getHeaderText(): string {\n\t\tconst tabs: Array<{ id: ModelHubTab; label: string }> = [\n\t\t\t{ id: \"select\", label: \"Select\" },\n\t\t\t{ id: \"cycle\", label: \"Cycle\" },\n\t\t\t{ id: \"manage\", label: \"Manage\" },\n\t\t];\n\t\tconst parts = tabs.map((t) => (t.id === this.tab ? theme.fg(\"accent\", t.label) : theme.fg(\"muted\", t.label)));\n\t\treturn `${theme.fg(\"muted\", \"Models: \")}${parts.join(theme.fg(\"muted\", \" | \"))}`;\n\t}\n\n\tprivate getHintText(): string {\n\t\tconst tabHint =\n\t\t\tkeyHint(\"tui.input.tab\", \"tabs\") +\n\t\t\ttheme.fg(\"muted\", \"/\") +\n\t\t\tkeyHint(\"app.model.hubTabPrev\", \"←\") +\n\t\t\ttheme.fg(\"muted\", \"/\") +\n\t\t\tkeyHint(\"app.model.hubTabNext\", \"→\");\n\t\tif (this.tab === \"select\") {\n\t\t\treturn tabHint + theme.fg(\"muted\", \" · type to search · Enter select · collapsed providers: Enter expand\");\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\treturn tabHint + theme.fg(\"muted\", ` · session-only until ${keyText(\"app.models.save\")}`);\n\t\t}\n\t\treturn tabHint + theme.fg(\"muted\", \" · Enter edit name/url/key/models · Backspace/Delete remove\");\n\t}\n\n\tprivate getFooterText(): string {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst modelCount = this.selectRows.filter((r) => r.kind === \"model\").length;\n\t\t\treturn theme.fg(\"dim\", ` ${modelCount} model${modelCount === 1 ? \"\" : \"s\"} · Esc cancel`);\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst enabledCount = this.enabledIds?.length ?? this.cycleAllIds.length;\n\t\t\tconst allEnabled = this.enabledIds === null;\n\t\t\tconst countText = allEnabled ? \"all enabled\" : `${enabledCount}/${this.cycleAllIds.length} enabled`;\n\t\t\tconst parts = [\n\t\t\t\t`${keyText(\"tui.select.confirm\")} toggle`,\n\t\t\t\t`${keyText(\"app.models.enableAll\")} all`,\n\t\t\t\t`${keyText(\"app.models.clearAll\")} clear`,\n\t\t\t\t`${keyText(\"app.models.toggleProvider\")} provider`,\n\t\t\t\t`${keyText(\"app.models.reorderUp\")}/${keyText(\"app.models.reorderDown\")} reorder`,\n\t\t\t\t`${keyText(\"app.models.save\")} save`,\n\t\t\t\tcountText,\n\t\t\t];\n\t\t\treturn this.cycleDirty\n\t\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t\t}\n\t\treturn theme.fg(\n\t\t\t\"dim\",\n\t\t\t\" Enter edit name/url/key/models · Backspace delete · writing models.json drops comments/trailing commas\",\n\t\t);\n\t}\n\n\tprivate setTab(tab: ModelHubTab): void {\n\t\tif (this.tab === tab) return;\n\t\tthis.tab = tab;\n\t\tthis.headerText.setText(this.getHeaderText());\n\t\tthis.hintText.setText(this.getHintText());\n\t\tthis.applySearch();\n\t}\n\n\tprivate cycleTab(delta: number = 1): void {\n\t\tconst order: ModelHubTab[] = [\"select\", \"cycle\", \"manage\"];\n\t\tconst idx = order.indexOf(this.tab);\n\t\tconst next = (idx + delta + order.length * 10) % order.length;\n\t\tthis.setTab(order[next]!);\n\t}\n\n\t/** Left/right switch tabs only when the search box is empty, so typing is unaffected. */\n\tprivate trySwitchTabWithArrows(keyData: string, kb: ReturnType<typeof getKeybindings>): boolean {\n\t\tif (this.searchInput.getValue()) return false;\n\t\tif (kb.matches(keyData, \"app.model.hubTabNext\") || matchesKey(keyData, Key.right)) {\n\t\t\tthis.cycleTab(1);\n\t\t\treturn true;\n\t\t}\n\t\tif (kb.matches(keyData, \"app.model.hubTabPrev\") || matchesKey(keyData, Key.left)) {\n\t\t\tthis.cycleTab(-1);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t// ---- list building ----\n\n\tprivate applySearch(): void {\n\t\tconst query = this.searchInput.getValue();\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.selectRows = buildSelectRows({\n\t\t\t\tmodels: this.allModels,\n\t\t\t\tcurrentModel: this.currentModel,\n\t\t\t\trecentKeys: this.settingsManager.getRecentModels(),\n\t\t\t\tquery,\n\t\t\t\texpandedProviders: this.expandedProviders,\n\t\t\t});\n\t\t\t// Prefer current model selection\n\t\t\tconst currentIdx = this.selectRows.findIndex(\n\t\t\t\t(r) => r.kind === \"model\" && modelsAreEqual(this.currentModel, r.item.model),\n\t\t\t);\n\t\t\tthis.selectIndex =\n\t\t\t\tcurrentIdx >= 0 ? currentIdx : Math.min(this.selectIndex, Math.max(0, this.selectRows.length - 1));\n\t\t\t// Snap to first selectable if landing on header\n\t\t\tthis.ensureSelectableIndex(\"select\");\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tconst items = getSortedIds(this.enabledIds, this.cycleAllIds)\n\t\t\t\t.filter((id) => this.cycleModelsById.has(id))\n\t\t\t\t.map((id) => ({\n\t\t\t\t\tfullId: id,\n\t\t\t\t\tmodel: this.cycleModelsById.get(id)!,\n\t\t\t\t\tenabled: isEnabled(this.enabledIds, id),\n\t\t\t\t}));\n\t\t\tthis.cycleItems = query ? fuzzyFilter(items, query, (i) => `${i.model.id} ${i.model.provider}`) : items;\n\t\t\tthis.cycleIndex = Math.min(this.cycleIndex, Math.max(0, this.cycleItems.length - 1));\n\t\t} else {\n\t\t\tthis.rebuildManageRows();\n\t\t\tif (query) {\n\t\t\t\tthis.manageRows = fuzzyFilter(this.manageRows, query, (r) =>\n\t\t\t\t\tr.kind === \"action\" ? r.label : `${r.label} ${r.detail} ${r.id}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, this.manageRows.length - 1));\n\t\t}\n\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate ensureSelectableIndex(which: \"select\"): void {\n\t\tif (which !== \"select\" || this.selectRows.length === 0) return;\n\t\tif (this.selectRows[this.selectIndex]?.kind === \"header\") {\n\t\t\tconst next = this.selectRows.findIndex((r, i) => i >= this.selectIndex && r.kind !== \"header\");\n\t\t\tif (next >= 0) {\n\t\t\t\tthis.selectIndex = next;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst prev = [...this.selectRows]\n\t\t\t\t.map((r, i) => ({ r, i }))\n\t\t\t\t.reverse()\n\t\t\t\t.find(({ r }) => r.kind !== \"header\");\n\t\t\tif (prev) this.selectIndex = prev.i;\n\t\t}\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tif (this.errorMessage && this.tab !== \"manage\") {\n\t\t\tfor (const line of this.errorMessage.split(\"\\n\")) {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"error\", line), 0, 0));\n\t\t\t}\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.renderSelectList();\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.renderCycleList();\n\t\t} else {\n\t\t\tthis.renderManageList();\n\t\t}\n\t}\n\n\tprivate renderSelectList(): void {\n\t\tif (this.selectRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectIndex - Math.floor(this.maxVisible / 2), this.selectRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.selectRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.selectRows[i]!;\n\t\t\tconst isSelected = i === this.selectIndex;\n\n\t\t\tif (row.kind === \"header\") {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ── ${row.label} ──`), 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\t\tconst text = isSelected\n\t\t\t\t\t? theme.fg(\"accent\", `▸ ${row.provider} (${row.count})`)\n\t\t\t\t\t: theme.fg(\"muted\", `▸ ${row.provider} (${row.count})`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst isCurrent = modelsAreEqual(this.currentModel, row.item.model);\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", row.item.id) : row.item.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${row.item.provider}]`);\n\t\t\tconst badges = theme.fg(\"dim\", ` ${row.badges}`);\n\t\t\tconst check = isCurrent ? theme.fg(\"success\", \" ✓\") : \"\";\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${badges}${check}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.selectRows.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectIndex + 1}/${this.selectRows.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tconst selected = this.selectRows[this.selectIndex];\n\t\tif (selected?.kind === \"model\") {\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected.item.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderCycleList(): void {\n\t\tif (this.cycleItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.cycleIndex - Math.floor(this.maxVisible / 2), this.cycleItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.cycleItems.length);\n\t\tconst allEnabled = this.enabledIds === null;\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.cycleItems[i]!;\n\t\t\tconst isSelected = i === this.cycleIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", item.model.id) : item.model.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${item.model.provider}]`);\n\t\t\tconst status = allEnabled ? \"\" : item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.cycleItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.cycleIndex + 1}/${this.cycleItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tif (this.cycleItems.length > 0) {\n\t\t\tconst selected = this.cycleItems[this.cycleIndex];\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected?.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderManageList(): void {\n\t\tif (this.manageRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No custom providers\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.manageIndex - Math.floor(this.maxVisible / 2), this.manageRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.manageRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.manageRows[i]!;\n\t\t\tconst isSelected = i === this.manageIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tif (row.kind === \"action\") {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : theme.fg(\"success\", row.label);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t} else {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : row.label;\n\t\t\t\tconst detail = theme.fg(\"muted\", ` ${row.detail}`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tthis.listContainer.addChild(new Text(`${detail}`, 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t// ---- input ----\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(keyData, \"tui.input.tab\")) {\n\t\t\tthis.cycleTab(1);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.trySwitchTabWithArrows(keyData, kb)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.cancel\") || matchesKey(keyData, Key.escape)) {\n\t\t\tthis.callbacks.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\tif (matchesKey(keyData, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.applySearch();\n\t\t\t} else {\n\t\t\t\tthis.callbacks.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.handleSelectInput(keyData, kb);\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.handleCycleInput(keyData, kb);\n\t\t} else {\n\t\t\tthis.handleManageInput(keyData, kb);\n\t\t}\n\t}\n\n\tprivate handleSelectInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === 0 ? this.selectRows.length - 1 : this.selectIndex - 1;\n\t\t\t// Skip headers when moving\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === 0 ? this.selectRows.length - 1 : next - 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === this.selectRows.length - 1 ? 0 : this.selectIndex + 1;\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === this.selectRows.length - 1 ? 0 : next + 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleCycleInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === 0 ? this.cycleItems.length - 1 : this.cycleIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === this.cycleItems.length - 1 ? 0 : this.cycleIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\tconst reorderUp = kb.matches(keyData, \"app.models.reorderUp\");\n\t\tconst reorderDown = kb.matches(keyData, \"app.models.reorderDown\");\n\t\tif (reorderUp || reorderDown) {\n\t\t\tif (this.enabledIds === null) return;\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item && isEnabled(this.enabledIds, item.fullId)) {\n\t\t\t\tconst delta = reorderUp ? -1 : 1;\n\t\t\t\tconst currentIndex = this.enabledIds.indexOf(item.fullId);\n\t\t\t\tconst newIndex = currentIndex + delta;\n\t\t\t\tif (newIndex >= 0 && newIndex < this.enabledIds.length) {\n\t\t\t\t\tthis.enabledIds = move(this.enabledIds, item.fullId, delta);\n\t\t\t\t\tthis.cycleDirty = true;\n\t\t\t\t\tthis.cycleIndex += delta;\n\t\t\t\t\tthis.applySearch();\n\t\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.enableAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = enableAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.clearAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = clearAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.toggleProvider\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tconst provider = item.model.provider;\n\t\t\t\tconst providerIds = this.cycleAllIds.filter((id) => this.cycleModelsById.get(id)!.provider === provider);\n\t\t\t\tconst allOn = providerIds.every((id) => isEnabled(this.enabledIds, id));\n\t\t\t\tthis.enabledIds = allOn\n\t\t\t\t\t? clearAll(this.enabledIds, this.cycleAllIds, providerIds)\n\t\t\t\t\t: enableAll(this.enabledIds, this.cycleAllIds, providerIds);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.save\")) {\n\t\t\tvoid this.callbacks.onCyclePersist(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\tthis.cycleDirty = false;\n\t\t\tthis.footerText.setText(this.getFooterText());\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleManageInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === 0 ? this.manageRows.length - 1 : this.manageIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === this.manageRows.length - 1 ? 0 : this.manageIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\t\t// Backspace / Delete remove selected provider\n\t\tif (matchesKey(keyData, Key.backspace) || matchesKey(keyData, Key.delete)) {\n\t\t\tconst row = this.manageRows[this.manageIndex];\n\t\t\tif (row?.kind === \"provider\") {\n\t\t\t\tvoid this.callbacks.onManageRemove(row.source, row.id);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleConfirm(): void {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst row = this.selectRows[this.selectIndex];\n\t\t\tif (!row) return;\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tthis.expandedProviders.add(row.provider);\n\t\t\t\tthis.applySearch();\n\t\t\t\t// Move selection to first model under that provider\n\t\t\t\tconst idx = this.selectRows.findIndex((r) => r.kind === \"model\" && r.item.provider === row.provider);\n\t\t\t\tif (idx >= 0) this.selectIndex = idx;\n\t\t\t\tthis.updateList();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (row.kind === \"model\") {\n\t\t\t\tthis.settingsManager.setDefaultModelAndProvider(row.item.model.provider, row.item.model.id);\n\t\t\t\tvoid this.callbacks.onSelectModel(row.item.model);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst row = this.manageRows[this.manageIndex];\n\t\tif (!row) return;\n\t\tif (row.kind === \"action\" && row.action === \"add\") {\n\t\t\tvoid this.callbacks.onManageAdd();\n\t\t\treturn;\n\t\t}\n\t\tif (row.kind === \"provider\") {\n\t\t\tvoid this.callbacks.onManageEdit(row.source, row.id);\n\t\t}\n\t}\n\n\t/** Called by parent after manage mutation so list refreshes. */\n\tasync refreshAfterManage(): Promise<void> {\n\t\tawait this.reload();\n\t\tthis.tui.requestRender();\n\t}\n}\n\n/** Back-compat alias used by older tests/imports. */\nexport { ModelHubComponent as ModelSelectorComponent };\n"]}
|