{"version":3,"file":"model-selection.d.ts","sourceRoot":"","sources":["../../../src/watchdog/model-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAKN,KAAK,aAAa,EAElB,MAAM,yBAAyB,CAAC;AAEjC,eAAO,MAAM,wBAAwB,EAAE,aAAsB,CAAC;AAe9D,KAAK,aAAa,GAAG,UAAU,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAE3E,MAAM,WAAW,0BAA0B;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,aAAa,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,2BAA2B;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;CAC1C;AAuBD,wBAAgB,0BAA0B,CACzC,KAAK,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,EACjC,MAAM,SAAmB,GACvB,aAAa,GAAG,KAAK,GAAG,SAAS,CAKnC;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,GAAG,0BAA0B,CA0B7G;AAkED,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,gBAAgB,GAAG,2BAA2B,CAS/F","sourcesContent":["import type { ExtensionContext } from \"@lpb-work/pi-coding-agent\";\nimport { normalizeModelSegment, resolveModelCandidate } from \"../runs/shared/model-fallback.ts\";\nimport {\n\tgetSupportedThinkingLevels,\n\ttype ModelInfo,\n\tsplitKnownThinkingSuffix,\n\tTHINKING_LEVELS,\n\ttype ThinkingLevel,\n\ttoModelInfo,\n} from \"../shared/model-info.ts\";\n\nexport const STRONG_WATCHDOG_THINKING: ThinkingLevel = \"high\";\n\nconst STRONG_WATCHDOG_MODELS = {\n\topus48: {\n\t\tlabel: \"Opus 4.8\",\n\t\tqueries: [\"anthropic/claude-opus-4-8\", \"anthropic/claude-opus-4.8\", \"anthropic/opus-4-8\", \"anthropic/opus-4.8\"],\n\t},\n\tgpt55: {\n\t\tlabel: \"GPT 5.5\",\n\t\tqueries: [\"openai-codex/gpt-5.5\", \"openai-codex/gpt-5-5\", \"openai/gpt-5.5\", \"openai/gpt-5-5\"],\n\t},\n} as const;\n\ntype StrongWatchdogFamily = keyof typeof STRONG_WATCHDOG_MODELS;\n\ntype RegistryModel = ReturnType<ExtensionContext[\"modelRegistry\"][\"find\"]>;\n\nexport interface ResolvedWatchdogModelInput {\n\tmodel: string;\n\tthinking?: ThinkingLevel;\n\tregistryModel: NonNullable<RegistryModel>;\n}\n\nexport interface WatchdogModelRecommendation {\n\tmodel: string;\n\tthinking: ThinkingLevel;\n\tlabel: string;\n\treason: string;\n\tregistryModel: NonNullable<RegistryModel>;\n}\n\nfunction fullModelId(model: Pick<ModelInfo, \"provider\" | \"id\">): string {\n\treturn `${model.provider}/${model.id}`;\n}\n\nfunction modelRegistryEntries(ctx: ExtensionContext): ModelInfo[] {\n\treturn ctx.modelRegistry.getAvailable().map(toModelInfo);\n}\n\nfunction splitProviderModel(value: string): { provider: string; id: string } | undefined {\n\tconst slashIndex = value.indexOf(\"/\");\n\tif (slashIndex <= 0 || slashIndex === value.length - 1) return undefined;\n\treturn { provider: value.slice(0, slashIndex), id: value.slice(slashIndex + 1) };\n}\n\nfunction assertSupportedThinking(value: string, source: string): ThinkingLevel {\n\tif ((THINKING_LEVELS as readonly string[]).includes(value)) return value as ThinkingLevel;\n\tthrow new Error(\n\t\t`Unsupported watchdog thinking '${value}' from ${source}; expected ${THINKING_LEVELS.join(\", \")}, false, or inherit.`,\n\t);\n}\n\nexport function parseWatchdogThinkingInput(\n\tvalue: string | false | undefined,\n\tsource = \"watchdog input\",\n): ThinkingLevel | false | undefined {\n\tif (value === undefined || value === \"\") return undefined;\n\tif (value === false) return false;\n\tif (value === \"false\") return false;\n\treturn assertSupportedThinking(value, source);\n}\n\nexport function resolveWatchdogModelInput(ctx: ExtensionContext, rawModel: string): ResolvedWatchdogModelInput {\n\tconst trimmed = rawModel.trim();\n\tif (!trimmed) throw new Error(\"Watchdog model must be a non-empty provider/model value.\");\n\tconst availableModels = modelRegistryEntries(ctx);\n\tconst preferredProvider = typeof ctx.model?.provider === \"string\" ? ctx.model.provider : undefined;\n\tconst resolved = resolveModelCandidate(trimmed, availableModels, preferredProvider) ?? trimmed;\n\tconst { baseModel, thinkingSuffix } = splitKnownThinkingSuffix(resolved);\n\tconst named = splitProviderModel(baseModel);\n\tif (!named)\n\t\tthrow new Error(\n\t\t\t`Watchdog model '${rawModel}' did not resolve to provider/model. Use a provider-qualified model such as openai-codex/gpt-5.5:high or anthropic/claude-opus-4-8:high.`,\n\t\t);\n\tconst registryModel = ctx.modelRegistry.find(named.provider, named.id);\n\tif (!registryModel) throw new Error(`Watchdog model '${rawModel}' was not found as '${baseModel}'.`);\n\tif (!ctx.modelRegistry.hasConfiguredAuth(registryModel)) {\n\t\tthrow new Error(\n\t\t\t`Watchdog model '${baseModel}' is not authenticated. Configure credentials for provider '${named.provider}' or choose an authenticated model.`,\n\t\t);\n\t}\n\treturn {\n\t\tmodel: `${named.provider}/${named.id}`,\n\t\t...(thinkingSuffix\n\t\t\t? { thinking: assertSupportedThinking(thinkingSuffix.slice(1), \"watchdog model suffix\") }\n\t\t\t: {}),\n\t\tregistryModel,\n\t};\n}\n\nfunction familyForModel(model: Pick<ModelInfo, \"provider\" | \"id\"> | undefined): StrongWatchdogFamily | undefined {\n\tif (!model) return undefined;\n\tconst provider = normalizeModelSegment(model.provider);\n\tconst id = normalizeModelSegment(model.id);\n\tif (provider.includes(\"openai\") && /^gpt-5-5(-\\d{8}|-\\d{4}-\\d{2}-\\d{2})?$/.test(id)) return \"gpt55\";\n\tif (provider.includes(\"anthropic\") && /^(claude-opus-4-8|opus-4-8)(-\\d{8}|-\\d{4}-\\d{2}-\\d{2})?$/.test(id))\n\t\treturn \"opus48\";\n\treturn undefined;\n}\n\nfunction currentProviderFamily(ctx: ExtensionContext): \"openai\" | \"anthropic\" | undefined {\n\tconst provider = typeof ctx.model?.provider === \"string\" ? normalizeModelSegment(ctx.model.provider) : \"\";\n\tif (provider.includes(\"openai\")) return \"openai\";\n\tif (provider.includes(\"anthropic\")) return \"anthropic\";\n\treturn undefined;\n}\n\nfunction strongFamilyOrder(ctx: ExtensionContext): StrongWatchdogFamily[] {\n\tconst current = ctx.model ? familyForModel(toModelInfo(ctx.model)) : undefined;\n\tif (current === \"gpt55\") return [\"opus48\"];\n\tif (current === \"opus48\") return [\"gpt55\"];\n\tconst providerFamily = currentProviderFamily(ctx);\n\tif (providerFamily === \"openai\") return [\"opus48\", \"gpt55\"];\n\tif (providerFamily === \"anthropic\") return [\"gpt55\", \"opus48\"];\n\treturn [\"gpt55\", \"opus48\"];\n}\n\nfunction findFamilyMatch(family: StrongWatchdogFamily, availableModels: ModelInfo[]): string | undefined {\n\tconst matches = availableModels.filter((entry) => familyForModel(entry) === family);\n\tif (matches.length === 1) return matches[0]!.fullId;\n\treturn undefined;\n}\n\nfunction resolveStrongCandidate(\n\tctx: ExtensionContext,\n\tfamily: StrongWatchdogFamily,\n): WatchdogModelRecommendation | undefined {\n\tconst availableModels = modelRegistryEntries(ctx);\n\tconst preference = STRONG_WATCHDOG_MODELS[family];\n\tconst queries: string[] = [...preference.queries];\n\tconst familyMatch = findFamilyMatch(family, availableModels);\n\tif (familyMatch) queries.push(familyMatch);\n\tfor (const query of queries) {\n\t\tlet resolved: ResolvedWatchdogModelInput;\n\t\ttry {\n\t\t\tresolved = resolveWatchdogModelInput(ctx, query as Parameters<typeof resolveWatchdogModelInput>[1]);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tconst modelInfo = toModelInfo(resolved.registryModel);\n\t\tif (familyForModel(modelInfo) !== family) continue;\n\t\tif (!getSupportedThinkingLevels(modelInfo).includes(STRONG_WATCHDOG_THINKING)) continue;\n\t\tconst current = ctx.model ? fullModelId(toModelInfo(ctx.model)) : \"no current session model\";\n\t\treturn {\n\t\t\tmodel: resolved.model,\n\t\t\tthinking: STRONG_WATCHDOG_THINKING,\n\t\t\tlabel: preference.label,\n\t\t\treason: `Use ${preference.label} with thinking high as a strong independent watchdog for ${current}.`,\n\t\t\tregistryModel: resolved.registryModel,\n\t\t};\n\t}\n\treturn undefined;\n}\n\nexport function recommendStrongWatchdogModel(ctx: ExtensionContext): WatchdogModelRecommendation {\n\tfor (const family of strongFamilyOrder(ctx)) {\n\t\tconst recommendation = resolveStrongCandidate(ctx, family);\n\t\tif (recommendation) return recommendation;\n\t}\n\tconst current = ctx.model ? fullModelId(toModelInfo(ctx.model)) : \"the current session\";\n\tthrow new Error(\n\t\t`No authenticated strong complementary watchdog model was found for ${current}. Configure access to Opus 4.8 or GPT 5.5, then run the recommendation again.`,\n\t);\n}\n"]}