@mzwing/pi-model-info 0.1.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["isRecord"],"sources":["../src/config.ts","../src/cache.ts","../src/compact.ts","../src/types.ts","../src/catalog-sources.ts","../src/catalog-index.ts","../src/fetcher.ts","../src/catalog.ts","../src/command.ts","../src/models-json.ts","../src/merge.ts","../src/resolver.ts","../src/provider-apply.ts","../src/extension.ts","../src/index.ts"],"sourcesContent":["import type {\n AffixRule,\n ModelCompat,\n ModelGate,\n ModelInfoConfig,\n ProviderOptIn,\n ResolvedConfig,\n ResolvedProvider,\n SourceId,\n} from './types.js'\nimport { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport process from 'node:process'\nimport { z } from 'zod'\n\nexport const EXTENSION_ID = 'pi-model-info'\nexport const COMMAND_NAME = 'model-info'\nconst CONFIG_SCHEMA_URL =\n 'https://raw.githubusercontent.com/mzwing/pi-packages/main/packages/pi-model-info/schemas/config.schema.json'\n\nexport const DEFAULT_SOURCES: SourceId[] = ['pi.dev', 'models.dev']\nconst DEFAULT_CACHE_TTL_MS: number = 24 * 60 * 60 * 1000\nconst DEFAULT_TIMEOUT_MS = 15_000\nconst DEFAULT_MAX_BYTES: number = 16 * 1024 * 1024\n\nconst FREE_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }\n\n/** Suffix variants every relay uses. Disable individually with `enabled: false`. */\nconst BUILTIN_RULES: AffixRule[] = [\n { id: 'free-dash', kind: 'suffix', value: '-free', override: { cost: FREE_COST } },\n { id: 'free-colon', kind: 'suffix', value: ':free', override: { cost: FREE_COST } },\n]\n\n// ── Schema (module-private: `isolatedDeclarations` makes exporting it unworkable) ──\n\n// Spelled out rather than derived from THINKING_LEVELS so the inferred type is the exact\n// `ThinkingLevelMap` shape instead of a string index signature.\nconst thinkingValue = z.union([z.string(), z.null()]).optional()\nconst thinkingLevelMapSchema = z.strictObject({\n off: thinkingValue,\n minimal: thinkingValue,\n low: thinkingValue,\n medium: thinkingValue,\n high: thinkingValue,\n xhigh: thinkingValue,\n max: thinkingValue,\n})\n\nconst costTierSchema = z.strictObject({\n input: z.number().min(0),\n output: z.number().min(0),\n cacheRead: z.number().min(0),\n cacheWrite: z.number().min(0),\n inputTokensAbove: z.number().int().positive(),\n})\n\nconst metadataOverrideSchema = z.strictObject({\n name: z.string().trim().min(1).optional(),\n reasoning: z.boolean().optional(),\n input: z\n .array(z.enum(['text', 'image']))\n .min(1)\n .optional(),\n cost: z\n .strictObject({\n input: z.number().min(0).optional(),\n output: z.number().min(0).optional(),\n cacheRead: z.number().min(0).optional(),\n cacheWrite: z.number().min(0).optional(),\n tiers: z.array(costTierSchema).optional(),\n })\n .optional(),\n contextWindow: z.number().int().positive().optional(),\n maxTokens: z.number().int().positive().optional(),\n thinkingLevelMap: thinkingLevelMapSchema.optional(),\n // Pi's `compat` is a three-way union keyed on `api`; reproducing it here would duplicate hundreds\n // of lines Pi already validates on registration, so the check stays structural.\n compat: z\n .custom<ModelCompat>(value => typeof value === 'object' && value !== null && !Array.isArray(value), {\n message: 'compat must be an object',\n })\n .optional(),\n})\n\nconst affixRuleSchema = z.strictObject({\n id: z.string().trim().min(1),\n kind: z.enum(['prefix', 'suffix']),\n value: z.string().min(1),\n enabled: z.boolean().optional(),\n override: metadataOverrideSchema.optional(),\n})\n\nconst modelGateSchema = z.strictObject({\n prefixes: z.array(z.string().trim().min(1)).optional(),\n suffixes: z.array(z.string().trim().min(1)).optional(),\n alias: z.string().trim().min(1).optional(),\n override: metadataOverrideSchema.optional(),\n skip: z.boolean().optional(),\n})\n\nconst providerOptInSchema = z.strictObject({\n catalogProvider: z.string().trim().min(1).optional(),\n costMultiplier: z.number().min(0).optional(),\n costPolicy: z.enum(['catalog', 'zero', 'keep']).optional(),\n contextWindowPolicy: z.enum(['catalog', 'min', 'keep']).optional(),\n capabilityPolicy: z.enum(['catalog', 'widen', 'keep']).optional(),\n useCatalogName: z.boolean().optional(),\n mapThinkingLevels: z.boolean().optional(),\n allowDynamic: z.boolean().optional(),\n models: z.record(z.string().trim().min(1), modelGateSchema).optional(),\n})\n\nconst configFileShape = {\n $schema: z.string().min(1).optional(),\n providers: z.record(z.string().trim().min(1), providerOptInSchema).optional(),\n aliases: z.record(z.string().trim().min(1), z.string().trim().min(1)).optional(),\n models: z.record(z.string().trim().min(1), modelGateSchema).optional(),\n rules: z.array(affixRuleSchema).optional(),\n builtinRules: z.boolean().optional(),\n sources: z\n .array(z.enum(['pi.dev', 'models.dev']))\n .min(1)\n .optional(),\n network: z\n .strictObject({\n enabled: z.boolean().optional(),\n timeoutMs: z.number().int().positive().max(120_000).optional(),\n maxBytes: z.number().int().positive().optional(),\n })\n .optional(),\n cache: z\n .strictObject({\n ttlMs: z.number().int().min(0).optional(),\n dir: z.string().trim().min(1).optional(),\n })\n .optional(),\n applyOnIdleOnly: z.boolean().optional(),\n}\n\nconst configFileSchema = z.strictObject(configFileShape)\n\nconst modelInfoConfigSchema = z\n .strictObject({\n ...configFileShape,\n providers: z.record(z.string().trim().min(1), providerOptInSchema).default({}),\n })\n .superRefine((config, context) => {\n const seen = new Set<string>()\n for (const [index, rule] of (config.rules ?? []).entries()) {\n if (seen.has(rule.id)) {\n context.addIssue({ code: 'custom', message: `duplicate rule id '${rule.id}'`, path: ['rules', index, 'id'] })\n }\n seen.add(rule.id)\n }\n if (config.sources && new Set(config.sources).size !== config.sources.length) {\n context.addIssue({ code: 'custom', message: 'sources must not repeat a value', path: ['sources'] })\n }\n })\n\n/**\n * One scope on disk, where `providers` only becomes required once the two scopes are merged.\n * Hand-written because `isolatedDeclarations` cannot emit a `z.infer` of a module-private schema;\n * `test/config.test.ts` asserts the two stay in step.\n */\ninterface ModelInfoConfigFile extends Omit<ModelInfoConfig, 'providers'> {\n providers?: Record<string, ProviderOptIn> | undefined\n}\n\n// ── Paths and loading ─────────────────────────────────────────────────────────\n\nexport interface ConfigIssue {\n sourcePath: string\n message: string\n}\n\nexport interface ModelInfoConfigPaths {\n globalPath: string\n projectPath: string\n}\n\nexport interface LoadConfigResult {\n config: ModelInfoConfig | undefined\n issues: ConfigIssue[]\n globalPath: string\n projectPath: string\n}\n\nexport interface LoadConfigOptions {\n cwd: string\n agentDir?: string\n readFile?: (path: string) => string | undefined\n}\n\nexport function defaultModelInfoAgentDir(): string {\n return process.env['PI_CODING_AGENT_DIR'] ?? join(homedir(), '.pi', 'agent')\n}\n\nexport function getModelInfoConfigPaths(\n cwd: string,\n agentDir: string = defaultModelInfoAgentDir(),\n): ModelInfoConfigPaths {\n return {\n globalPath: join(agentDir, 'extensions', EXTENSION_ID, 'config.json'),\n projectPath: join(cwd, '.pi', 'extensions', EXTENSION_ID, 'config.json'),\n }\n}\n\n/** Reads a config file, reporting a missing one as `undefined` rather than an error. */\nfunction readConfigFile(path: string): string | undefined {\n try {\n return readFileSync(path, 'utf8')\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {\n return undefined\n }\n throw error\n }\n}\n\nfunction formatZodIssue(error: z.ZodError): string {\n return error.issues\n .map(issue => `${issue.path.length > 0 ? issue.path.join('.') : '(root)'}: ${issue.message}`)\n .join('; ')\n}\n\n/** Returns `undefined` on failure, having recorded why; an absent file reads as an empty scope. */\nfunction readScope(\n path: string,\n readFile: (path: string) => string | undefined,\n issues: ConfigIssue[],\n): ModelInfoConfigFile | undefined {\n let source: string | undefined\n try {\n source = readFile(path)\n } catch (error) {\n issues.push({ sourcePath: path, message: error instanceof Error ? error.message : String(error) })\n\n return undefined\n }\n if (source === undefined) {\n return {}\n }\n\n let value: unknown\n try {\n value = JSON.parse(source)\n } catch (error) {\n issues.push({\n sourcePath: path,\n message: `invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n })\n\n return undefined\n }\n\n const parsed = configFileSchema.safeParse(value)\n if (!parsed.success) {\n issues.push({ sourcePath: path, message: formatZodIssue(parsed.error) })\n\n return undefined\n }\n\n return parsed.data\n}\n\nexport function loadModelInfoConfig(options: LoadConfigOptions): LoadConfigResult {\n const { globalPath, projectPath } = getModelInfoConfigPaths(options.cwd, options.agentDir)\n const readFile = options.readFile ?? readConfigFile\n const issues: ConfigIssue[] = []\n const globalConfig = readScope(globalPath, readFile, issues)\n const projectConfig = readScope(projectPath, readFile, issues)\n\n if (globalConfig === undefined || projectConfig === undefined) {\n return { config: undefined, issues, globalPath, projectPath }\n }\n\n const merged = modelInfoConfigSchema.safeParse({ ...globalConfig, ...projectConfig })\n if (!merged.success) {\n issues.push({ sourcePath: projectPath, message: formatZodIssue(merged.error) })\n\n return { config: undefined, issues, globalPath, projectPath }\n }\n\n return { config: merged.data, issues, globalPath, projectPath }\n}\n\n// ── Desugaring ────────────────────────────────────────────────────────────────\n\nexport interface ResolveConfigResult {\n config: ResolvedConfig\n issues: ConfigIssue[]\n}\n\n/**\n * Model ids routinely contain `/`, so a flat `\"provider/model\"` key is only unambiguous because\n * provider ids are known: split at the FIRST separator and require the head to be an opted-in one.\n */\nfunction splitFlatKey(key: string, providers: Map<string, ResolvedProvider>): [ResolvedProvider, string] | undefined {\n const separator = key.indexOf('/')\n if (separator <= 0 || separator === key.length - 1) {\n return undefined\n }\n const provider = providers.get(key.slice(0, separator))\n\n return provider === undefined ? undefined : [provider, key.slice(separator + 1)]\n}\n\nfunction orderRules(rules: AffixRule[]): AffixRule[] {\n return rules\n .map((rule, ordinal) => ({ rule, ordinal }))\n .sort((a, b) => b.rule.value.length - a.rule.value.length || a.ordinal - b.ordinal)\n .map(entry => entry.rule)\n}\n\n/** The flat `models` and `aliases` sugar, as `[section, key, gate]` in the order they are folded in. */\nfunction flatGates(config: ModelInfoConfig): [string, string, ModelGate][] {\n return [\n ...Object.entries(config.models ?? {}).map(([key, gate]): [string, string, ModelGate] => ['models', key, gate]),\n ...Object.entries(config.aliases ?? {}).map(([key, alias]): [string, string, ModelGate] => [\n 'aliases',\n key,\n { alias },\n ]),\n ]\n}\n\n/**\n * Materialises defaults, folds the flat sugar into per-provider gates, and orders the affix rules.\n * Problems here are reported, not fatal: an unusable entry is dropped and the rest still applies.\n */\nexport function resolveModelInfoConfig(config: ModelInfoConfig, sourcePath: string): ResolveConfigResult {\n const issues: ConfigIssue[] = []\n const providers = new Map<string, ResolvedProvider>()\n\n for (const [id, optIn] of Object.entries(config.providers)) {\n providers.set(id, {\n id,\n catalogProvider: optIn.catalogProvider,\n costMultiplier: optIn.costMultiplier ?? 1,\n costPolicy: optIn.costPolicy ?? 'catalog',\n contextWindowPolicy: optIn.contextWindowPolicy ?? 'catalog',\n capabilityPolicy: optIn.capabilityPolicy ?? 'catalog',\n useCatalogName: optIn.useCatalogName ?? false,\n mapThinkingLevels: optIn.mapThinkingLevels ?? false,\n allowDynamic: optIn.allowDynamic ?? false,\n models: new Map(Object.entries(optIn.models ?? {})),\n })\n }\n\n for (const [section, key, gate] of flatGates(config)) {\n const split = splitFlatKey(key, providers)\n if (split === undefined) {\n issues.push({ sourcePath, message: `${section}['${key}'] does not start with an opted-in provider id` })\n continue\n }\n const [provider, modelId] = split\n provider.models.set(modelId, { ...provider.models.get(modelId), ...gate })\n }\n\n const declared = [...(config.rules ?? []), ...(config.builtinRules === false ? [] : BUILTIN_RULES)]\n const enabled = declared.filter(rule => rule.enabled !== false)\n const ruleIds = new Set(declared.map(rule => rule.id))\n\n for (const provider of providers.values()) {\n for (const [modelId, gate] of provider.models) {\n const known = (id: string): boolean => {\n if (ruleIds.has(id)) {\n return true\n }\n issues.push({\n sourcePath,\n message: `providers['${provider.id}'].models['${modelId}'] references unknown rule '${id}'`,\n })\n\n return false\n }\n const prefixes = gate.prefixes?.filter(known)\n const suffixes = gate.suffixes?.filter(known)\n provider.models.set(modelId, {\n ...gate,\n ...(prefixes === undefined ? {} : { prefixes }),\n ...(suffixes === undefined ? {} : { suffixes }),\n })\n }\n }\n\n return {\n config: {\n providers,\n prefixRules: orderRules(enabled.filter(rule => rule.kind === 'prefix')),\n suffixRules: orderRules(enabled.filter(rule => rule.kind === 'suffix')),\n sources: config.sources ?? DEFAULT_SOURCES,\n network: {\n enabled: config.network?.enabled ?? true,\n timeoutMs: config.network?.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxBytes: config.network?.maxBytes ?? DEFAULT_MAX_BYTES,\n },\n cache: { ttlMs: config.cache?.ttlMs ?? DEFAULT_CACHE_TTL_MS, dir: config.cache?.dir },\n applyOnIdleOnly: config.applyOnIdleOnly ?? true,\n },\n issues,\n }\n}\n\nexport function buildModelInfoJsonSchema(): Record<string, unknown> {\n const { $schema, ...schema } = z.toJSONSchema(modelInfoConfigSchema, {\n target: 'draft-2020-12',\n io: 'input',\n // `compat` is the one custom node here. Pi owns its large, version-specific union and validates\n // it on registration, so the published schema leaves it unconstrained rather than going stale.\n unrepresentable: 'any',\n })\n\n return { $schema, $id: CONFIG_SCHEMA_URL, ...schema }\n}\n","import type { CatalogEntry, NormalizedSource, SourceId } from './types.js'\nimport { mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { defaultModelInfoAgentDir, EXTENSION_ID } from './config.js'\n\nexport const CACHE_VERSION = 1\n\nexport interface CachedEnvelope {\n version: number\n source: SourceId\n etag: string | undefined\n lastModified: string | undefined\n fetchedAt: number\n entryCount: number\n entries: CatalogEntry[]\n /** `Map` does not survive JSON, so the vendor oracle is persisted as pairs. */\n vendors: [string, string][]\n}\n\nexport interface CatalogCacheFileSystem {\n readFile: (path: string) => string | undefined\n writeFile: (path: string, data: string) => void\n rename: (from: string, to: string) => void\n mkdir: (path: string) => void\n unlink: (path: string) => void\n}\n\nexport interface CatalogCacheOptions {\n dir?: string | undefined\n agentDir?: string | undefined\n fileSystem?: CatalogCacheFileSystem | undefined\n}\n\nconst FILE_NAMES: Record<SourceId, string> = {\n 'pi.dev': 'pi-dev.json',\n 'models.dev': 'models-dev.json',\n}\n\nconst defaultFileSystem: CatalogCacheFileSystem = {\n readFile(path) {\n try {\n return readFileSync(path, 'utf8')\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {\n return undefined\n }\n throw error\n }\n },\n writeFile(path, data) {\n writeFileSync(path, data, 'utf8')\n },\n rename(from, to) {\n renameSync(from, to)\n },\n mkdir(path) {\n mkdirSync(path, { recursive: true })\n },\n unlink(path) {\n unlinkSync(path)\n },\n}\n\nexport function toNormalizedSource(envelope: CachedEnvelope): NormalizedSource {\n return {\n source: envelope.source,\n entries: envelope.entries,\n vendors: new Map(envelope.vendors),\n }\n}\n\nexport class CatalogCache {\n private readonly dir: string\n private readonly fileSystem: CatalogCacheFileSystem\n\n constructor(options: CatalogCacheOptions = {}) {\n const agentDir = options.agentDir ?? defaultModelInfoAgentDir()\n this.dir = options.dir ?? join(agentDir, 'extensions', EXTENSION_ID, 'cache')\n this.fileSystem = options.fileSystem ?? defaultFileSystem\n }\n\n /**\n * A corrupt or half-written envelope reads as absent and is left on disk: the next successful\n * fetch replaces it, and until then a copy another machine can still read is not worth destroying.\n */\n read(source: SourceId): CachedEnvelope | undefined {\n let raw: string | undefined\n try {\n raw = this.fileSystem.readFile(this.path(source))\n } catch {\n return undefined\n }\n if (raw === undefined) {\n return undefined\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n return undefined\n }\n if (typeof parsed !== 'object' || parsed === null) {\n return undefined\n }\n\n const envelope = parsed as Partial<CachedEnvelope>\n const usable =\n envelope.version === CACHE_VERSION &&\n envelope.source === source &&\n Array.isArray(envelope.entries) &&\n Array.isArray(envelope.vendors) &&\n typeof envelope.fetchedAt === 'number' &&\n envelope.entries.length === envelope.entryCount\n\n return usable ? (envelope as CachedEnvelope) : undefined\n }\n\n write(envelope: CachedEnvelope): void {\n const path = this.path(envelope.source)\n const temporary = `${path}.tmp`\n try {\n this.fileSystem.mkdir(dirname(path))\n this.fileSystem.writeFile(temporary, `${JSON.stringify(envelope)}\\n`)\n this.fileSystem.rename(temporary, path)\n } catch (error) {\n try {\n this.fileSystem.unlink(temporary)\n } catch {\n // The write error is the actionable one; a failed cleanup is not.\n }\n throw error\n }\n }\n\n private path(source: SourceId): string {\n return join(this.dir, FILE_NAMES[source])\n }\n}\n","/** Drops undefined values, so `exactOptionalPropertyTypes` sees omission rather than an undefined slot. */\nexport function compact<T extends object>(value: { [K in keyof T]: T[K] | undefined }): T {\n return Object.fromEntries(Object.entries(value).filter(([, field]) => field !== undefined)) as T\n}\n","import type { Api } from '@earendil-works/pi-ai'\nimport type { ProviderModelConfig } from '@earendil-works/pi-coding-agent'\n\nexport type ModelCost = ProviderModelConfig['cost']\nexport type ModelCostTier = NonNullable<ModelCost['tiers']>[number]\nexport type ModelInput = ProviderModelConfig['input']\nexport type ModelCompat = ProviderModelConfig['compat']\nexport type ThinkingLevelMap = NonNullable<ProviderModelConfig['thinkingLevelMap']>\n\nexport const THINKING_LEVELS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'] as const\ntype ThinkingLevel = (typeof THINKING_LEVELS)[number]\n\n/** JSON can carry a present-but-undefined slot, which Pi's own map forbids; those are dropped on the way out. */\nexport type ThinkingLevelMapInput = { [K in ThinkingLevel]?: string | null | undefined }\n\n/** The subset of `Model<Api>` this extension reads. Registry models are assignable to it. */\nexport interface SnapshotModel {\n id: string\n name: string\n api: Api\n baseUrl: string\n reasoning: boolean\n thinkingLevelMap?: ThinkingLevelMap | undefined\n input: ModelInput\n cost: ModelCost\n contextWindow: number\n maxTokens: number\n samplingParams?: Record<string, unknown> | undefined\n headers?: Record<string, string> | undefined\n compat?: ModelCompat | undefined\n}\n\n/** Spelled out because `Partial<ModelCost>` drops the `| undefined` a parsed config needs. */\ninterface PartialModelCost {\n input?: number | undefined\n output?: number | undefined\n cacheRead?: number | undefined\n cacheWrite?: number | undefined\n tiers?: ModelCostTier[] | undefined\n}\n\n/** Every field a rule, gate, or catalog entry may contribute. Never includes identity fields. */\nexport interface MetadataOverride {\n name?: string | undefined\n reasoning?: boolean | undefined\n input?: ModelInput | undefined\n cost?: PartialModelCost | undefined\n contextWindow?: number | undefined\n maxTokens?: number | undefined\n thinkingLevelMap?: ThinkingLevelMapInput | undefined\n compat?: ModelCompat | undefined\n}\n\n// ── Config ────────────────────────────────────────────────────────────────────\n\ntype AffixKind = 'prefix' | 'suffix'\ntype CostPolicy = 'catalog' | 'zero' | 'keep'\ntype ContextWindowPolicy = 'catalog' | 'min' | 'keep'\ntype CapabilityPolicy = 'catalog' | 'widen' | 'keep'\nexport type SourceId = 'pi.dev' | 'models.dev'\n\nexport interface AffixRule {\n /** Stable key referenced by per-model gating. */\n id: string\n kind: AffixKind\n /** Literal affix, separator included: `-free`, `:free`. */\n value: string\n /** Default true. Set false to disable a built-in without removing it. */\n enabled?: boolean | undefined\n /** Applied ONLY when this rule was actually used for the match. */\n override?: MetadataOverride | undefined\n}\n\nexport interface ModelGate {\n /** unset = all rules · `[]` = none · `['id']` = only those. */\n prefixes?: string[] | undefined\n suffixes?: string[] | undefined\n /** Highest-priority resolution. `provider/model` or a bare id. */\n alias?: string | undefined\n /** Highest-priority merge layer. */\n override?: MetadataOverride | undefined\n /** Leave this model's metadata untouched. */\n skip?: boolean | undefined\n}\n\nexport interface ProviderOptIn {\n /** Catalog provider to scope lookups to, e.g. `openrouter`. Tie-break tier 1. */\n catalogProvider?: string | undefined\n /** Relay markup applied to catalog cost only, before rule overrides. */\n costMultiplier?: number | undefined\n costPolicy?: CostPolicy | undefined\n contextWindowPolicy?: ContextWindowPolicy | undefined\n capabilityPolicy?: CapabilityPolicy | undefined\n useCatalogName?: boolean | undefined\n mapThinkingLevels?: boolean | undefined\n /** Accept the model-list freeze on a provider whose base refreshes dynamically. */\n allowDynamic?: boolean | undefined\n models?: Record<string, ModelGate> | undefined\n}\n\nexport interface ModelInfoConfig {\n $schema?: string | undefined\n /** Opt-in only. An empty map means the extension does nothing. */\n providers: Record<string, ProviderOptIn>\n /** Flat sugar for `providers[p].models[m].alias`. Key splits at the FIRST `/`. */\n aliases?: Record<string, string> | undefined\n /** Flat sugar for `providers[p].models[m]`. Key splits at the FIRST `/`. */\n models?: Record<string, ModelGate> | undefined\n rules?: AffixRule[] | undefined\n builtinRules?: boolean | undefined\n /** Order is priority. */\n sources?: SourceId[] | undefined\n network?: { enabled?: boolean | undefined; timeoutMs?: number | undefined; maxBytes?: number | undefined } | undefined\n cache?: { ttlMs?: number | undefined; dir?: string | undefined } | undefined\n applyOnIdleOnly?: boolean | undefined\n}\n\n/** Config with sugar desugared, defaults materialised, and rules ordered. */\nexport interface ResolvedProvider {\n id: string\n catalogProvider: string | undefined\n costMultiplier: number\n costPolicy: CostPolicy\n contextWindowPolicy: ContextWindowPolicy\n capabilityPolicy: CapabilityPolicy\n useCatalogName: boolean\n mapThinkingLevels: boolean\n allowDynamic: boolean\n models: Map<string, ModelGate>\n}\n\nexport interface ResolvedConfig {\n providers: Map<string, ResolvedProvider>\n /** Both sorted longest-`value`-first, then config order, built-ins last. */\n prefixRules: AffixRule[]\n suffixRules: AffixRule[]\n sources: SourceId[]\n network: { enabled: boolean; timeoutMs: number; maxBytes: number }\n cache: { ttlMs: number; dir: string | undefined }\n applyOnIdleOnly: boolean\n}\n\n// ── Catalog ───────────────────────────────────────────────────────────────────\n\nexport interface CatalogEntry {\n source: SourceId\n /** Provider id within the source catalog, when the source is provider-scoped. */\n sourceProvider: string | undefined\n /** The id verbatim as it appears in the source. */\n sourceId: string\n /** `vendor/model` identity when the source exposes one. */\n canonicalId: string\n api?: Api | undefined\n metadata: MetadataOverride\n}\n\nexport interface NormalizedSource {\n source: SourceId\n entries: CatalogEntry[]\n /** Bare id → vendor, from `vendor/model` keys. Only models.dev populates this. */\n vendors: Map<string, string>\n}\n\nexport interface CatalogIndex {\n /** Provider + NUL + lowercased id, to entries in source-priority order. */\n scoped: Map<string, CatalogEntry[]>\n /** Lowercased verbatim id → entries. */\n exact: Map<string, CatalogEntry[]>\n /** Lowercased vendor-stripped id → entries. */\n bare: Map<string, CatalogEntry[]>\n /** Lowercased bare id → vendor, for tie-break tier 4. */\n vendors: Map<string, string>\n}\n\nexport type MatchKind = 'alias' | 'exact' | 'vendor-qualified' | 'stripped'\ntype UnresolvedReason = 'no-match' | 'alias-miss' | 'rules-disabled' | 'skipped'\n\nexport interface ResolvedMatch {\n kind: 'resolved'\n entry: CatalogEntry\n /** Same-provider entry from a higher-ranked source, for structural backfill only. */\n donor: CatalogEntry | undefined\n matchKind: MatchKind\n prefixRule: AffixRule | undefined\n suffixRule: AffixRule | undefined\n}\n\nexport type Resolution =\n | ResolvedMatch\n | { kind: 'ambiguous'; candidates: CatalogEntry[] }\n | { kind: 'unresolved'; reason: UnresolvedReason }\n","import type {\n CatalogEntry,\n MetadataOverride,\n ModelCost,\n ModelCostTier,\n ModelInput,\n NormalizedSource,\n ThinkingLevelMapInput,\n} from './types.js'\nimport { compact } from './compact.js'\nimport { THINKING_LEVELS } from './types.js'\n\nexport const PI_DEV_URL = 'https://pi.dev/api/models'\nexport const MODELS_DEV_URL = 'https://models.dev/models.json'\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** Remote JSON delivers `__proto__` and friends as ordinary own keys; dropping them keeps them out of index keys. */\nconst FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype'])\n\nfunction entriesOf(value: unknown): [string, unknown][] {\n if (!isRecord(value)) {\n return []\n }\n\n return Object.entries(value).filter(([key]) => !FORBIDDEN_KEYS.has(key))\n}\n\nfunction positiveInt(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined\n}\n\nfunction nonNegative(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined\n}\n\nfunction flag(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined\n}\n\nexport function bareId(id: string): string {\n const separator = id.indexOf('/')\n\n return separator > 0 && separator < id.length - 1 ? id.slice(separator + 1) : id\n}\n\nexport function vendorOf(id: string): string | undefined {\n const separator = id.indexOf('/')\n\n return separator > 0 && separator < id.length - 1 ? id.slice(0, separator) : undefined\n}\n\n/** Pi accepts only `text` and `image`; absent modalities mean \"unknown\", not \"text only\". */\nfunction toModelInput(modalities: unknown): ModelInput | undefined {\n if (!isRecord(modalities) || !Array.isArray(modalities['input'])) {\n return undefined\n }\n const declared = new Set(modalities['input'].filter((value): value is string => typeof value === 'string'))\n const input: ModelInput = ['text']\n if (declared.has('image')) {\n input.push('image')\n }\n\n return input\n}\n\nfunction toCost(raw: unknown): ModelCost | undefined {\n if (!isRecord(raw)) {\n return undefined\n }\n const input = nonNegative(raw['input'])\n const output = nonNegative(raw['output'])\n if (input === undefined || output === undefined) {\n return undefined\n }\n\n return compact<ModelCost>({\n input,\n output,\n cacheRead: nonNegative(raw['cacheRead'] ?? raw['cache_read']) ?? 0,\n cacheWrite: nonNegative(raw['cacheWrite'] ?? raw['cache_write']) ?? 0,\n tiers: toTiers(raw),\n })\n}\n\nfunction toTier(raw: unknown, fallbackThreshold?: number): ModelCostTier | undefined {\n if (!isRecord(raw)) {\n return undefined\n }\n const input = nonNegative(raw['input'])\n const output = nonNegative(raw['output'])\n const above =\n positiveInt(raw['inputTokensAbove']) ??\n (isRecord(raw['tier']) ? positiveInt(raw['tier']['size']) : undefined) ??\n fallbackThreshold\n if (input === undefined || output === undefined || above === undefined) {\n return undefined\n }\n\n return {\n input,\n output,\n cacheRead: nonNegative(raw['cacheRead'] ?? raw['cache_read']) ?? 0,\n cacheWrite: nonNegative(raw['cacheWrite'] ?? raw['cache_write']) ?? 0,\n inputTokensAbove: above,\n }\n}\n\nfunction toTiers(raw: Record<string, unknown>): ModelCostTier[] | undefined {\n if (Array.isArray(raw['tiers'])) {\n const tiers: ModelCostTier[] = []\n for (const entry of raw['tiers'] as unknown[]) {\n const tier = toTier(entry)\n if (tier !== undefined) {\n tiers.push(tier)\n }\n }\n\n return tiers.length > 0 ? tiers : undefined\n }\n\n // `context_over_200k` is models.dev's deprecated single-tier spelling, duplicating `tiers[0]` when both are present.\n const legacy = toTier(raw['context_over_200k'], 200_000)\n\n return legacy === undefined ? undefined : [legacy]\n}\n\nfunction toThinkingLevelMap(raw: unknown): ThinkingLevelMapInput | undefined {\n if (!isRecord(raw)) {\n return undefined\n }\n const map: ThinkingLevelMapInput = {}\n let mapped = false\n for (const level of THINKING_LEVELS) {\n const value = raw[level]\n if (typeof value === 'string' || value === null) {\n map[level] = value\n mapped = true\n }\n }\n\n return mapped ? map : undefined\n}\n\n/**\n * models.dev describes reasoning as options rather than a level map. Only the `effort` form maps to\n * the strings Pi sends; `toggle` and `budget_tokens` carry no level names, and inventing one is a\n * 400 on every turn.\n */\nfunction reasoningOptionsToThinkingLevelMap(raw: unknown): ThinkingLevelMapInput | undefined {\n if (!Array.isArray(raw)) {\n return undefined\n }\n const effort = raw.find(\n (option): option is Record<string, unknown> =>\n isRecord(option) && option['type'] === 'effort' && Array.isArray(option['values']),\n )\n if (effort === undefined) {\n return undefined\n }\n const values = new Set((effort['values'] as unknown[]).filter((value): value is string => typeof value === 'string'))\n const map: ThinkingLevelMapInput = {}\n let mapped = false\n for (const level of THINKING_LEVELS) {\n // models.dev spells Pi's `off` as `none`; the rest are identical.\n const name = level === 'off' ? 'none' : level\n if (values.has(name)) {\n map[level] = name\n mapped = true\n }\n }\n\n return mapped ? map : undefined\n}\n\n/** `{ providerId: { modelId: Model } }`, already in Pi's own shape. */\nexport function normalizePiDev(payload: unknown): NormalizedSource {\n const entries: CatalogEntry[] = []\n\n for (const [providerId, models] of entriesOf(payload)) {\n for (const [modelId, raw] of entriesOf(models)) {\n if (!isRecord(raw)) {\n continue\n }\n const id = text(raw['id']) ?? modelId\n const input = Array.isArray(raw['input'])\n ? raw['input'].filter((value): value is 'text' | 'image' => value === 'text' || value === 'image')\n : undefined\n\n entries.push(\n compact<CatalogEntry>({\n source: 'pi.dev',\n sourceProvider: providerId,\n sourceId: id,\n canonicalId: `${providerId}/${id}`,\n api: text(raw['api']),\n metadata: compact<MetadataOverride>({\n name: text(raw['name']),\n reasoning: flag(raw['reasoning']),\n input: input === undefined || input.length === 0 ? undefined : input,\n cost: toCost(raw['cost']),\n contextWindow: positiveInt(raw['contextWindow']),\n maxTokens: positiveInt(raw['maxTokens']),\n thinkingLevelMap: toThinkingLevelMap(raw['thinkingLevelMap']),\n compat: isRecord(raw['compat']) ? raw['compat'] : undefined,\n }),\n }),\n )\n }\n }\n\n return { source: 'pi.dev', entries, vendors: new Map() }\n}\n\n/** `{ \"vendor/model\": metadata }` — provider-agnostic, and carries no pricing. */\nexport function normalizeModelsDev(payload: unknown): NormalizedSource {\n const entries: CatalogEntry[] = []\n const vendors = new Map<string, string>()\n\n for (const [key, raw] of entriesOf(payload)) {\n if (!isRecord(raw)) {\n continue\n }\n const canonicalId = text(raw['id']) ?? key\n const vendor = vendorOf(canonicalId)\n const bare = bareId(canonicalId)\n if (vendor !== undefined) {\n vendors.set(bare.toLowerCase(), vendor)\n }\n const limit = isRecord(raw['limit']) ? raw['limit'] : undefined\n\n entries.push({\n source: 'models.dev',\n sourceProvider: vendor,\n sourceId: bare,\n canonicalId,\n metadata: compact<MetadataOverride>({\n name: text(raw['name']),\n reasoning: flag(raw['reasoning']),\n input: toModelInput(raw['modalities']),\n contextWindow: limit === undefined ? undefined : positiveInt(limit['context']),\n maxTokens: limit === undefined ? undefined : positiveInt(limit['output']),\n thinkingLevelMap: reasoningOptionsToThinkingLevelMap(raw['reasoning_options']),\n }),\n })\n }\n\n return { source: 'models.dev', entries, vendors }\n}\n","import type { CatalogEntry, CatalogIndex, NormalizedSource, SourceId } from './types.js'\nimport { bareId } from './catalog-sources.js'\n\n/** NUL cannot appear in a provider or model id, so the composite key is unambiguous. */\nconst SCOPE_SEPARATOR = String.fromCharCode(0)\n\nexport function scopedKey(provider: string, id: string): string {\n return `${provider.toLowerCase()}${SCOPE_SEPARATOR}${id.toLowerCase()}`\n}\n\nfunction push(map: Map<string, CatalogEntry[]>, key: string, entry: CatalogEntry): void {\n const bucket = map.get(key)\n if (bucket === undefined) {\n map.set(key, [entry])\n } else {\n bucket.push(entry)\n }\n}\n\n/** Inserts in source-priority order, so every bucket is ranked and the resolver never sorts by source. */\nexport function buildCatalogIndex(sources: NormalizedSource[], order: SourceId[]): CatalogIndex {\n const rank = new Map<SourceId, number>(order.map((source, position) => [source, position]))\n const ordered = sources\n .filter(source => rank.has(source.source))\n .sort((a, b) => (rank.get(a.source) ?? 0) - (rank.get(b.source) ?? 0))\n\n const scoped = new Map<string, CatalogEntry[]>()\n const exact = new Map<string, CatalogEntry[]>()\n const bare = new Map<string, CatalogEntry[]>()\n const vendors = new Map<string, string>()\n\n for (const source of ordered) {\n for (const [key, vendor] of source.vendors) {\n if (!vendors.has(key)) {\n vendors.set(key, vendor)\n }\n }\n for (const entry of source.entries) {\n const short = bareId(entry.sourceId)\n if (entry.sourceProvider !== undefined) {\n push(scoped, scopedKey(entry.sourceProvider, entry.sourceId), entry)\n if (short !== entry.sourceId) {\n push(scoped, scopedKey(entry.sourceProvider, short), entry)\n }\n }\n push(exact, entry.sourceId.toLowerCase(), entry)\n if (entry.canonicalId !== entry.sourceId) {\n push(exact, entry.canonicalId.toLowerCase(), entry)\n }\n push(bare, short.toLowerCase(), entry)\n }\n }\n\n return { scoped, exact, bare, vendors }\n}\n","export interface CatalogRequest {\n url: string\n etag: string | undefined\n lastModified: string | undefined\n timeoutMs: number\n maxBytes: number\n}\n\nexport type FetchOutcome =\n | { status: 'ok'; body: unknown; etag: string | undefined; lastModified: string | undefined }\n | { status: 'not-modified' }\n | { status: 'error'; message: string }\n\nexport interface CatalogFetcher {\n get: (request: CatalogRequest, signal: AbortSignal) => Promise<FetchOutcome>\n}\n\nfunction describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\n/** Reads through the stream so an oversized payload is abandoned rather than buffered whole. */\nasync function readCapped(response: Response, maxBytes: number): Promise<string> {\n const body = response.body\n if (body === null) {\n return ''\n }\n // Node's `undici` types reach us as `any`, so the chunk shape is pinned explicitly.\n const reader: ReadableStreamDefaultReader<Uint8Array> = body.getReader()\n const decoder = new TextDecoder()\n const chunks: string[] = []\n let size = 0\n try {\n for (;;) {\n const chunk = await reader.read()\n if (chunk.done) {\n break\n }\n size += chunk.value.byteLength\n if (size > maxBytes) {\n throw new Error(`response exceeded ${maxBytes} bytes`)\n }\n chunks.push(decoder.decode(chunk.value, { stream: true }))\n }\n } finally {\n reader.releaseLock()\n }\n chunks.push(decoder.decode())\n\n return chunks.join('')\n}\n\nexport const catalogFetcher: CatalogFetcher = {\n async get(request, signal) {\n let url: URL\n try {\n url = new URL(request.url)\n } catch (error) {\n return { status: 'error', message: `invalid url: ${describe(error)}` }\n }\n if (url.protocol !== 'https:') {\n return { status: 'error', message: `refusing non-https catalog url '${request.url}'` }\n }\n\n const headers = new Headers({ accept: 'application/json' })\n if (request.etag !== undefined) {\n headers.set('if-none-match', request.etag)\n }\n if (request.lastModified !== undefined) {\n headers.set('if-modified-since', request.lastModified)\n }\n\n try {\n const response = await fetch(url, {\n headers,\n signal: AbortSignal.any([signal, AbortSignal.timeout(request.timeoutMs)]),\n })\n\n if (response.status === 304) {\n await response.body?.cancel()\n\n return { status: 'not-modified' }\n }\n if (!response.ok) {\n await response.body?.cancel()\n\n return { status: 'error', message: `HTTP ${response.status}` }\n }\n\n const text = await readCapped(response, request.maxBytes)\n if (text.length === 0) {\n return { status: 'error', message: 'empty response' }\n }\n\n return {\n status: 'ok',\n body: JSON.parse(text),\n etag: response.headers.get('etag') ?? undefined,\n lastModified: response.headers.get('last-modified') ?? undefined,\n }\n } catch (error) {\n return { status: 'error', message: describe(error) }\n }\n },\n}\n","import type { CachedEnvelope } from './cache.js'\nimport type { CatalogFetcher } from './fetcher.js'\nimport type { CatalogIndex, NormalizedSource, ResolvedConfig, SourceId } from './types.js'\nimport { CACHE_VERSION, CatalogCache, toNormalizedSource } from './cache.js'\nimport { buildCatalogIndex } from './catalog-index.js'\nimport { MODELS_DEV_URL, normalizeModelsDev, normalizePiDev, PI_DEV_URL } from './catalog-sources.js'\nimport { catalogFetcher } from './fetcher.js'\n\ninterface SourceDescriptor {\n url: string\n normalize: (payload: unknown) => NormalizedSource\n}\n\nconst SOURCES: Record<SourceId, SourceDescriptor> = {\n 'pi.dev': { url: PI_DEV_URL, normalize: normalizePiDev },\n 'models.dev': { url: MODELS_DEV_URL, normalize: normalizeModelsDev },\n}\n\ninterface SourceStatus {\n source: SourceId\n fetchedAt: number | undefined\n entryCount: number\n lastError: string | undefined\n}\n\nexport interface CatalogSnapshot {\n index: CatalogIndex\n /** `unavailable` means nothing was loaded, so nothing may be registered. */\n status: 'ready' | 'unavailable'\n sources: SourceStatus[]\n}\n\nexport interface CatalogStoreDeps {\n cache?: CatalogCache | undefined\n fetcher?: CatalogFetcher | undefined\n now?: (() => number) | undefined\n random?: (() => number) | undefined\n}\n\nexport class CatalogStore {\n private readonly cache: CatalogCache\n private readonly fetcher: CatalogFetcher\n private readonly now: () => number\n private readonly random: () => number\n private readonly errors = new Map<SourceId, string>()\n\n constructor(deps: CatalogStoreDeps = {}) {\n this.cache = deps.cache ?? new CatalogCache()\n this.fetcher = deps.fetcher ?? catalogFetcher\n this.now = deps.now ?? (() => Date.now())\n this.random = deps.random ?? Math.random\n }\n\n /** Cache only. Safe to call before any network work has happened. */\n load(config: ResolvedConfig): CatalogSnapshot {\n const loaded = new Map<SourceId, CachedEnvelope>()\n for (const source of config.sources) {\n const cached = this.cache.read(source)\n if (cached !== undefined) {\n loaded.set(source, cached)\n }\n }\n\n return this.snapshot(config, loaded)\n }\n\n async refresh(config: ResolvedConfig, signal: AbortSignal, force = false): Promise<CatalogSnapshot> {\n const loaded = new Map<SourceId, CachedEnvelope>()\n\n for (const source of config.sources) {\n const envelope = await this.refreshOne(config, source, signal, force)\n if (envelope !== undefined) {\n loaded.set(source, envelope)\n }\n if (signal.aborted) {\n break\n }\n }\n\n return this.snapshot(config, loaded)\n }\n\n private async refreshOne(\n config: ResolvedConfig,\n source: SourceId,\n signal: AbortSignal,\n force: boolean,\n ): Promise<CachedEnvelope | undefined> {\n const descriptor = SOURCES[source]\n const cached = this.cache.read(source)\n\n // Jitter keeps several Pi processes on one machine from expiring together.\n const ttl = config.cache.ttlMs * (0.9 + this.random() * 0.2)\n if (!force && cached !== undefined && this.now() - cached.fetchedAt < ttl) {\n this.errors.delete(source)\n\n return cached\n }\n if (!config.network.enabled || signal.aborted) {\n return cached\n }\n\n const outcome = await this.fetcher.get(\n {\n url: descriptor.url,\n etag: cached?.etag,\n lastModified: cached?.lastModified,\n timeoutMs: config.network.timeoutMs,\n maxBytes: config.network.maxBytes,\n },\n signal,\n )\n\n if (outcome.status === 'not-modified') {\n if (cached === undefined) {\n this.errors.set(source, '304 with no cached copy')\n\n return undefined\n }\n const renewed: CachedEnvelope = { ...cached, fetchedAt: this.now() }\n this.persist(source, renewed)\n this.errors.delete(source)\n\n return renewed\n }\n\n if (outcome.status === 'error') {\n // Stale-on-failure: an old catalog beats no catalog, and the file is untouched.\n this.errors.set(source, outcome.message)\n\n return cached\n }\n\n const normalized = descriptor.normalize(outcome.body)\n if (normalized.entries.length === 0) {\n this.errors.set(source, 'catalog contained no usable models')\n\n return cached\n }\n\n const envelope: CachedEnvelope = {\n version: CACHE_VERSION,\n source,\n etag: outcome.etag,\n lastModified: outcome.lastModified,\n fetchedAt: this.now(),\n entryCount: normalized.entries.length,\n entries: normalized.entries,\n vendors: [...normalized.vendors],\n }\n this.persist(source, envelope)\n this.errors.delete(source)\n\n return envelope\n }\n\n private persist(source: SourceId, envelope: CachedEnvelope): void {\n try {\n this.cache.write(envelope)\n } catch (error) {\n // A cache we cannot write is a slower extension, not a broken one.\n this.errors.set(source, `cache write failed: ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n\n private snapshot(config: ResolvedConfig, loaded: Map<SourceId, CachedEnvelope>): CatalogSnapshot {\n const sources = config.sources.map((source): SourceStatus => {\n const envelope = loaded.get(source)\n\n return {\n source,\n fetchedAt: envelope?.fetchedAt,\n entryCount: envelope?.entries.length ?? 0,\n lastError: this.errors.get(source),\n }\n })\n\n const normalized = config.sources\n .map(source => loaded.get(source))\n .filter((envelope): envelope is CachedEnvelope => envelope !== undefined)\n .map(toNormalizedSource)\n\n return {\n index: buildCatalogIndex(normalized, config.sources),\n status: normalized.some(source => source.entries.length > 0) ? 'ready' : 'unavailable',\n sources,\n }\n }\n}\n","import type { CatalogSnapshot } from './catalog.js'\nimport type { ConfigIssue } from './config.js'\nimport type { ModelReport, ProviderReport } from './provider-apply.js'\nimport type { Resolution, SnapshotModel } from './types.js'\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent'\nimport { COMMAND_NAME } from './config.js'\n\nexport interface ModelInfoCommandController {\n getReports: () => ProviderReport[]\n getCatalog: () => CatalogSnapshot | undefined\n getIssues: () => ConfigIssue[]\n /** The model as Pi finally sees it, after models.json `modelOverrides`. */\n getEffectiveModel: (providerId: string, modelId: string) => SnapshotModel | undefined\n refresh: () => Promise<void>\n}\n\nconst COMPLETION_LIMIT = 50\n\ninterface ModelReference {\n providerId: string | undefined\n modelId: string\n}\n\nfunction splitReference(reference: string): ModelReference {\n const separator = reference.indexOf('/')\n\n return separator > 0\n ? { providerId: reference.slice(0, separator), modelId: reference.slice(separator + 1) }\n : { providerId: undefined, modelId: reference }\n}\n\nfunction age(now: number, fetchedAt: number | undefined): string {\n if (fetchedAt === undefined) {\n return 'never fetched'\n }\n const minutes = Math.max(0, Math.round((now - fetchedAt) / 60_000))\n\n return minutes < 60 ? `${minutes}m ago` : `${Math.round(minutes / 60)}h ago`\n}\n\nfunction countByKind(models: ModelReport[]): Record<Resolution['kind'], number> {\n const counts = { resolved: 0, ambiguous: 0, unresolved: 0 }\n for (const model of models) {\n counts[model.resolution.kind] += 1\n }\n\n return counts\n}\n\nexport function formatSummary(\n reports: ProviderReport[],\n catalog: CatalogSnapshot | undefined,\n issues: ConfigIssue[],\n now: number,\n): string {\n const lines: string[] = []\n\n if (reports.length === 0) {\n lines.push('No providers opted in. Add one under \"providers\" in the config to complete its models.')\n }\n\n for (const report of reports) {\n if (report.status === 'skipped' || report.status === 'failed') {\n lines.push(`${report.provider}: ${report.status} — ${report.reason ?? 'no reason given'}`)\n continue\n }\n const counts = countByKind(report.models)\n lines.push(\n `${report.provider}: ${counts.resolved} completed, ${counts.ambiguous} ambiguous, ` +\n `${counts.unresolved} unresolved (${report.models.length} models)`,\n )\n }\n\n if (catalog === undefined) {\n lines.push('', 'catalogs: not loaded yet')\n } else {\n lines.push('', catalog.status === 'ready' ? 'catalogs:' : 'catalogs: unavailable — nothing was applied')\n for (const source of catalog.sources) {\n const error = source.lastError === undefined ? '' : ` — ${source.lastError}`\n lines.push(` ${source.source}: ${source.entryCount} entries, ${age(now, source.fetchedAt)}${error}`)\n }\n }\n\n if (issues.length > 0) {\n lines.push('', 'config issues:')\n for (const issue of issues) {\n lines.push(` ${issue.sourcePath}: ${issue.message}`)\n }\n }\n\n return lines.join('\\n')\n}\n\nexport function formatDetail(\n reports: ProviderReport[],\n reference: string,\n effective: SnapshotModel | undefined,\n): string {\n const { providerId, modelId } = splitReference(reference)\n const matches = reports.flatMap(report =>\n report.models\n .filter(model => model.id === modelId && (providerId === undefined || report.provider === providerId))\n .map(model => ({ report, model })),\n )\n\n const first = matches[0]\n if (first === undefined) {\n return `No completed model matches '${reference}'. Run /${COMMAND_NAME} to see what is covered.`\n }\n\n const { report, model } = first\n const lines = [`requested: ${report.provider}/${model.id}`]\n\n if (model.resolution.kind === 'resolved') {\n const { entry, matchKind, prefixRule, suffixRule } = model.resolution\n lines.push(`canonical: ${entry.canonicalId} (${entry.source})`)\n lines.push(`match: ${matchKind}`)\n const rules = [prefixRule?.id, suffixRule?.id].filter((id): id is string => id !== undefined)\n if (rules.length > 0) {\n lines.push(`rule: ${rules.join(', ')}`)\n }\n } else if (model.resolution.kind === 'ambiguous') {\n lines.push('match: ambiguous — nothing was applied')\n lines.push('candidates:')\n for (const candidate of model.resolution.candidates) {\n lines.push(` ${candidate.canonicalId} (${candidate.source})`)\n }\n lines.push('Add an alias for this model to choose one.')\n } else {\n lines.push(`match: unresolved (${model.resolution.reason})`)\n }\n\n const source = (field: string): string => {\n const origin = model.provenance.get(field)\n\n return origin === undefined || origin === 'existing' ? '' : ` from ${origin}`\n }\n\n lines.push('')\n lines.push(`context: ${model.model.contextWindow}${source('contextWindow')}`)\n lines.push(`maxTokens: ${model.model.maxTokens}${source('maxTokens')}`)\n lines.push(`reasoning: ${model.model.reasoning}${source('reasoning')}`)\n lines.push(`input: ${model.model.input.join(', ')}${source('input')}`)\n lines.push(`cost: $${model.model.cost.input}/$${model.model.cost.output} per Mtok${source('cost')}`)\n\n // models.json `modelOverrides` are layered above this extension, so what we computed is not\n // always what Pi ends up using.\n if (effective !== undefined && diverges(effective, model)) {\n lines.push('')\n lines.push('Pi is using different values (models.json modelOverrides win over this extension):')\n lines.push(` context: ${effective.contextWindow} maxTokens: ${effective.maxTokens}`)\n lines.push(` reasoning: ${effective.reasoning} cost: $${effective.cost.input}/$${effective.cost.output}`)\n }\n\n if (model.issues.length > 0) {\n lines.push('')\n for (const issue of model.issues) {\n lines.push(`note: ${issue}`)\n }\n }\n\n if (matches.length > 1) {\n lines.push('')\n lines.push(\n `'${modelId}' also exists on: ${matches\n .slice(1)\n .map(match => match.report.provider)\n .join(', ')}`,\n )\n }\n\n return lines.join('\\n')\n}\n\nfunction diverges(effective: SnapshotModel, report: ModelReport): boolean {\n return (\n effective.contextWindow !== report.model.contextWindow ||\n effective.maxTokens !== report.model.maxTokens ||\n effective.reasoning !== report.model.reasoning ||\n effective.cost.input !== report.model.cost.input ||\n effective.cost.output !== report.model.cost.output\n )\n}\n\nexport interface CompletionItem {\n value: string\n label: string\n description: string\n}\n\n/** Runs on every keystroke, so it stays a prefix filter over an already-built list. */\nexport function buildCompletions(reports: ProviderReport[], prefix: string): CompletionItem[] | null {\n const needle = prefix.trim().toLowerCase()\n const items: CompletionItem[] = []\n\n if ('refresh'.startsWith(needle)) {\n items.push({ value: 'refresh', label: 'refresh', description: 'Re-check the catalogs now' })\n }\n\n for (const report of reports) {\n for (const model of report.models) {\n const value = `${report.provider}/${model.id}`\n if (needle.length === 0 || value.toLowerCase().includes(needle)) {\n items.push({ value, label: value, description: model.resolution.kind })\n }\n if (items.length >= COMPLETION_LIMIT) {\n return items\n }\n }\n }\n\n return items.length > 0 ? items : null\n}\n\nexport function registerModelInfoCommand(pi: ExtensionAPI, controller: ModelInfoCommandController): void {\n try {\n pi.registerCommand(COMMAND_NAME, {\n description: 'Inspect the model metadata pi-model-info resolved for your third-party providers',\n getArgumentCompletions(prefix) {\n return buildCompletions(controller.getReports(), prefix)\n },\n async handler(args, ctx) {\n const argument = args.trim()\n\n if (argument === 'refresh') {\n await controller.refresh()\n }\n if (argument === 'refresh' || argument.length === 0) {\n const summary = formatSummary(\n controller.getReports(),\n controller.getCatalog(),\n controller.getIssues(),\n Date.now(),\n )\n ctx.ui.notify(summary, 'info')\n\n return\n }\n\n const { providerId, modelId } = splitReference(argument)\n const effective = providerId === undefined ? undefined : controller.getEffectiveModel(providerId, modelId)\n ctx.ui.notify(formatDetail(controller.getReports(), argument, effective), 'info')\n },\n })\n } catch (error) {\n // `model-info` is a generic name; a clash must not take the extension down.\n console.warn(\n `[pi-model-info] could not register /${COMMAND_NAME}: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n}\n","import { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\n/** provider id → model id → field names the user hand-wrote. */\nexport type UserAuthoredMap = Map<string, Map<string, Set<string>>>\n\n/** Only fields this extension would otherwise overwrite are worth tracking. */\nconst TRACKED_FIELDS = new Set(['name', 'reasoning', 'input', 'cost', 'contextWindow', 'maxTokens', 'thinkingLevelMap'])\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction defaultRead(path: string): string | undefined {\n try {\n return readFileSync(path, 'utf8')\n } catch {\n return undefined\n }\n}\n\n/**\n * Answers what the registry cannot: whether a value was hand-written or is Pi's placeholder.\n * Without it, a user who wrote `contextWindow: 200000` would silently get the catalog's number.\n */\nexport function readUserAuthoredFields(\n agentDir: string,\n readFile: (path: string) => string | undefined = defaultRead,\n): UserAuthoredMap {\n const authored: UserAuthoredMap = new Map()\n\n let raw: string | undefined\n try {\n raw = readFile(join(agentDir, 'models.json'))\n } catch {\n return authored\n }\n if (raw === undefined) {\n return authored\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n return authored\n }\n if (!isRecord(parsed) || !isRecord(parsed['providers'])) {\n return authored\n }\n\n for (const [providerId, provider] of Object.entries(parsed['providers'])) {\n if (!isRecord(provider) || !Array.isArray(provider['models'])) {\n continue\n }\n const models = new Map<string, Set<string>>()\n for (const definition of provider['models']) {\n if (!isRecord(definition) || typeof definition['id'] !== 'string') {\n continue\n }\n const fields = new Set(Object.keys(definition).filter(key => TRACKED_FIELDS.has(key)))\n if (fields.size > 0) {\n models.set(definition['id'], fields)\n }\n }\n if (models.size > 0) {\n authored.set(providerId, models)\n }\n }\n\n return authored\n}\n","import type {\n MetadataOverride,\n ModelCost,\n ModelGate,\n ModelInput,\n Resolution,\n ResolvedMatch,\n ResolvedProvider,\n SnapshotModel,\n ThinkingLevelMap,\n ThinkingLevelMapInput,\n} from './types.js'\nimport type { ProviderModelConfig } from '@earendil-works/pi-coding-agent'\nimport { compact } from './compact.js'\nimport { THINKING_LEVELS } from './types.js'\n\n/**\n * `ProviderModelConfig` omits `samplingParams`, but the runtime shape has it and `applyExtension`\n * spreads the definition verbatim — carrying it here is what keeps a user's sampling defaults alive.\n */\nexport interface EnrichedModel extends ProviderModelConfig {\n samplingParams?: Record<string, unknown> | undefined\n}\n\nexport interface MergeInput {\n snapshot: SnapshotModel\n provider: ResolvedProvider\n resolution: Resolution\n gate: ModelGate | undefined\n /** Field names the user hand-wrote in models.json `models[]`; catalogs never overwrite them. */\n userAuthored?: ReadonlySet<string> | undefined\n}\n\nexport interface MergeOutput {\n model: EnrichedModel\n issues: string[]\n /** Field name to the layer that produced its final value, for `/model-info`. */\n provenance: Map<string, string>\n}\n\nconst OVERRIDE_FIELDS = [\n 'name',\n 'reasoning',\n 'input',\n 'cost',\n 'contextWindow',\n 'maxTokens',\n 'thinkingLevelMap',\n 'compat',\n] as const\n\ntype OverrideField = (typeof OVERRIDE_FIELDS)[number]\n\nfunction isOverrideField(field: string): field is OverrideField {\n return (OVERRIDE_FIELDS as readonly string[]).includes(field)\n}\n\nfunction mergeCost(base: ModelCost, incoming: NonNullable<MetadataOverride['cost']>): ModelCost {\n return compact<ModelCost>({\n input: incoming.input ?? base.input,\n output: incoming.output ?? base.output,\n cacheRead: incoming.cacheRead ?? base.cacheRead,\n cacheWrite: incoming.cacheWrite ?? base.cacheWrite,\n tiers: incoming.tiers ?? base.tiers,\n })\n}\n\nfunction unionInput(a: ModelInput, b: ModelInput): ModelInput {\n const combined = new Set<string>([...a, ...b])\n const input: ModelInput = ['text']\n if (combined.has('image')) {\n input.push('image')\n }\n\n return input\n}\n\n/** A relay's markup applies to catalog pricing only, never to a rule's explicit `0`. */\nfunction scaleCost(\n cost: NonNullable<MetadataOverride['cost']>,\n multiplier: number,\n): NonNullable<MetadataOverride['cost']> {\n if (multiplier === 1) {\n return cost\n }\n const scale = (value: number | undefined): number | undefined =>\n value === undefined ? undefined : value * multiplier\n\n return compact<NonNullable<MetadataOverride['cost']>>({\n input: scale(cost.input),\n output: scale(cost.output),\n cacheRead: scale(cost.cacheRead),\n cacheWrite: scale(cost.cacheWrite),\n tiers: cost.tiers?.map(tier => ({\n input: tier.input * multiplier,\n output: tier.output * multiplier,\n cacheRead: tier.cacheRead * multiplier,\n cacheWrite: tier.cacheWrite * multiplier,\n inputTokensAbove: tier.inputTokensAbove,\n })),\n })\n}\n\n/**\n * Cost, limits and capabilities all come from the single winning entry. Only fields the winner's\n * source schema cannot express are backfilled, and only from a same-provider pi.dev donor.\n */\nfunction catalogLayer(match: ResolvedMatch, provider: ResolvedProvider, snapshot: SnapshotModel): MetadataOverride {\n const { entry, donor } = match\n const metadata = entry.metadata\n\n // pi.dev ships a real level map; the one derived from models.dev's `reasoning_options` guesses at\n // provider-specific strings, so it stays opt-in.\n const ownMap = entry.source === 'pi.dev' || provider.mapThinkingLevels ? metadata.thinkingLevelMap : undefined\n\n const layer: MetadataOverride = {}\n\n if (provider.useCatalogName && metadata.name !== undefined) {\n layer.name = metadata.name\n }\n\n if (provider.capabilityPolicy !== 'keep') {\n if (metadata.reasoning !== undefined) {\n layer.reasoning =\n provider.capabilityPolicy === 'widen' ? snapshot.reasoning || metadata.reasoning : metadata.reasoning\n }\n if (metadata.input !== undefined) {\n layer.input = provider.capabilityPolicy === 'widen' ? unionInput(snapshot.input, metadata.input) : metadata.input\n }\n }\n\n if (provider.contextWindowPolicy !== 'keep') {\n if (metadata.contextWindow !== undefined) {\n layer.contextWindow =\n provider.contextWindowPolicy === 'min'\n ? Math.min(metadata.contextWindow, snapshot.contextWindow)\n : metadata.contextWindow\n }\n if (metadata.maxTokens !== undefined) {\n layer.maxTokens =\n provider.contextWindowPolicy === 'min' ? Math.min(metadata.maxTokens, snapshot.maxTokens) : metadata.maxTokens\n }\n }\n\n if (provider.costPolicy === 'zero') {\n layer.cost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }\n } else if (provider.costPolicy === 'catalog' && metadata.cost !== undefined) {\n layer.cost = scaleCost(metadata.cost, provider.costMultiplier)\n }\n\n const thinkingLevelMap = ownMap ?? donor?.metadata.thinkingLevelMap\n if (thinkingLevelMap !== undefined) {\n layer.thinkingLevelMap = thinkingLevelMap\n }\n\n // `compat` is a conditional type keyed on `api`; copying it across APIs is structurally wrong even\n // when the model is the same.\n const compat =\n (entry.api === snapshot.api ? metadata.compat : undefined) ??\n (donor?.api === snapshot.api ? donor.metadata.compat : undefined)\n if (compat !== undefined) {\n layer.compat = compat\n }\n\n return layer\n}\n\ninterface Draft {\n name: string\n reasoning: boolean\n input: ModelInput\n cost: ModelCost\n contextWindow: number\n maxTokens: number\n thinkingLevelMap: ThinkingLevelMapInput | undefined\n compat: SnapshotModel['compat']\n}\n\n/** Drops slots that are present but undefined; omission already means \"provider default\". */\nfunction compactThinkingLevelMap(map: ThinkingLevelMapInput | undefined): ThinkingLevelMap | undefined {\n if (map === undefined) {\n return undefined\n }\n const compacted: ThinkingLevelMap = {}\n let kept = false\n for (const level of THINKING_LEVELS) {\n const value = map[level]\n if (value !== undefined) {\n compacted[level] = value\n kept = true\n }\n }\n\n return kept ? compacted : undefined\n}\n\nfunction applyLayer(draft: Draft, label: string, override: MetadataOverride, provenance: Map<string, string>): void {\n for (const field of OVERRIDE_FIELDS) {\n if (override[field] !== undefined) {\n provenance.set(field, label)\n }\n }\n if (override.name !== undefined) {\n draft.name = override.name\n }\n if (override.reasoning !== undefined) {\n draft.reasoning = override.reasoning\n }\n if (override.input !== undefined) {\n draft.input = override.input\n }\n if (override.cost !== undefined) {\n draft.cost = mergeCost(draft.cost, override.cost)\n }\n if (override.contextWindow !== undefined) {\n draft.contextWindow = override.contextWindow\n }\n if (override.maxTokens !== undefined) {\n draft.maxTokens = override.maxTokens\n }\n if (override.thinkingLevelMap !== undefined) {\n draft.thinkingLevelMap = { ...draft.thinkingLevelMap, ...override.thinkingLevelMap }\n }\n if (override.compat !== undefined) {\n draft.compat = override.compat\n }\n}\n\n/**\n * Automatic values never overwrite what the user hand-wrote in models.json; an explicit override\n * layered later is a different matter, being equally deliberate.\n */\nfunction dropAuthored(layer: MetadataOverride, authored: ReadonlySet<string>, provenance: Map<string, string>): void {\n for (const field of authored) {\n if (isOverrideField(field)) {\n delete layer[field]\n provenance.set(field, 'models.json')\n }\n }\n}\n\nfunction isPositiveInt(value: number): boolean {\n return Number.isInteger(value) && value > 0\n}\n\nfunction costIsValid(cost: ModelCost): boolean {\n const values = [\n cost.input,\n cost.output,\n cost.cacheRead,\n cost.cacheWrite,\n ...(cost.tiers ?? []).flatMap(tier => [tier.input, tier.output, tier.cacheRead, tier.cacheWrite]),\n ]\n\n return values.every(value => Number.isFinite(value) && value >= 0)\n}\n\nexport function mergeMetadata(input: MergeInput): MergeOutput {\n const { snapshot, provider, resolution, gate } = input\n const issues: string[] = []\n const provenance = new Map<string, string>(OVERRIDE_FIELDS.map(field => [field, 'existing']))\n\n const draft: Draft = {\n name: snapshot.name,\n reasoning: snapshot.reasoning,\n input: [...snapshot.input],\n cost: snapshot.cost,\n contextWindow: snapshot.contextWindow,\n maxTokens: snapshot.maxTokens,\n thinkingLevelMap: snapshot.thinkingLevelMap,\n compat: snapshot.compat,\n }\n\n if (resolution.kind === 'resolved') {\n const layer = catalogLayer(resolution, provider, snapshot)\n if (input.userAuthored !== undefined) {\n dropAuthored(layer, input.userAuthored, provenance)\n }\n applyLayer(draft, resolution.entry.source, layer, provenance)\n\n for (const rule of [resolution.prefixRule, resolution.suffixRule]) {\n if (rule?.override !== undefined) {\n applyLayer(draft, `rule '${rule.id}'`, rule.override, provenance)\n }\n }\n }\n\n if (gate?.override !== undefined) {\n applyLayer(draft, 'model override', gate.override, provenance)\n }\n\n if (!isPositiveInt(draft.contextWindow)) {\n issues.push(`invalid contextWindow ${draft.contextWindow}; kept ${snapshot.contextWindow}`)\n draft.contextWindow = snapshot.contextWindow\n provenance.set('contextWindow', 'existing')\n }\n if (!isPositiveInt(draft.maxTokens)) {\n issues.push(`invalid maxTokens ${draft.maxTokens}; kept ${snapshot.maxTokens}`)\n draft.maxTokens = snapshot.maxTokens\n provenance.set('maxTokens', 'existing')\n }\n if (draft.maxTokens > draft.contextWindow) {\n draft.maxTokens = draft.contextWindow\n }\n if (!costIsValid(draft.cost)) {\n issues.push('invalid cost; kept the existing rates')\n draft.cost = snapshot.cost\n provenance.set('cost', 'existing')\n }\n if (draft.input.length === 0) {\n draft.input = [...snapshot.input]\n provenance.set('input', 'existing')\n }\n\n const model = compact<EnrichedModel>({\n id: snapshot.id,\n name: draft.name,\n // Pinned rather than inherited: `applyExtension` falls back to `models[0]` and throws when it\n // cannot resolve these, which a later recompose turns into a deleted provider.\n api: snapshot.api,\n baseUrl: snapshot.baseUrl,\n reasoning: draft.reasoning,\n input: draft.input,\n cost: draft.cost,\n contextWindow: draft.contextWindow,\n maxTokens: draft.maxTokens,\n thinkingLevelMap: compactThinkingLevelMap(draft.thinkingLevelMap),\n compat: draft.compat,\n headers: snapshot.headers,\n samplingParams: snapshot.samplingParams,\n })\n\n return { model, issues, provenance }\n}\n","import type {\n AffixRule,\n CatalogEntry,\n CatalogIndex,\n MatchKind,\n Resolution,\n ResolvedMatch,\n ResolvedProvider,\n} from './types.js'\nimport { scopedKey } from './catalog-index.js'\nimport { bareId, vendorOf } from './catalog-sources.js'\n\nexport interface ResolveInput {\n index: CatalogIndex\n provider: ResolvedProvider\n prefixRules: AffixRule[]\n suffixRules: AffixRule[]\n modelId: string\n}\n\ninterface Hit {\n entry: CatalogEntry\n /** Same-provider entry from another source, for structural backfill only. */\n donor: CatalogEntry | undefined\n viaVendorSplit: boolean\n}\n\ntype Outcome = { hit: Hit } | { ambiguous: CatalogEntry[] } | undefined\n\ninterface KeyForm {\n scope: string | undefined\n id: string\n /** This form is scoped by the vendor parsed out of the requested id. */\n vendorScoped: boolean\n /** The vendor the request named, if any. */\n vendor: string | undefined\n}\n\n/**\n * Vendor qualification is a key form rather than an affix rule: relays overwhelmingly use\n * `vendor/model` ids, and spending the one-prefix budget on that would leave nothing for a real\n * prefix. The vendor-scoped form deliberately precedes the unscoped one, whose bare-id fallback can\n * return several providers — an explicit `anthropic/…` should settle that outright.\n */\nfunction keyForms(provider: ResolvedProvider, id: string): KeyForm[] {\n const forms: KeyForm[] = []\n const vendor = vendorOf(id)\n const rest = bareId(id)\n\n if (provider.catalogProvider !== undefined) {\n forms.push({ scope: provider.catalogProvider, id, vendorScoped: false, vendor })\n if (vendor !== undefined) {\n forms.push({ scope: provider.catalogProvider, id: rest, vendorScoped: false, vendor })\n }\n }\n forms.push({ scope: provider.id, id, vendorScoped: false, vendor })\n if (vendor !== undefined) {\n forms.push({ scope: vendor, id: rest, vendorScoped: true, vendor })\n }\n forms.push({ scope: undefined, id, vendorScoped: false, vendor })\n\n return forms\n}\n\ninterface Candidates {\n entries: CatalogEntry[]\n /** True when the verbatim id missed and the vendor-stripped id was used instead. */\n viaBare: boolean\n}\n\nfunction candidatesFor(index: CatalogIndex, form: KeyForm): Candidates {\n if (form.scope !== undefined) {\n return { entries: index.scoped.get(scopedKey(form.scope, form.id)) ?? [], viaBare: false }\n }\n const exact = index.exact.get(form.id.toLowerCase())\n if (exact !== undefined && exact.length > 0) {\n return { entries: exact, viaBare: false }\n }\n\n return { entries: index.bare.get(bareId(form.id).toLowerCase()) ?? [], viaBare: true }\n}\n\n/**\n * The tie-break selects a PROVIDER; insertion order (already source-ranked) then selects the entry.\n * Splicing fields from two providers would be incoherent — the same bare id genuinely differs in\n * price and limits between them.\n */\nfunction select(found: Candidates, index: CatalogIndex, provider: ResolvedProvider, form: KeyForm): Outcome {\n const candidates = found.entries\n if (candidates.length === 0) {\n return undefined\n }\n\n const groups = new Map<string, CatalogEntry[]>()\n for (const candidate of candidates) {\n const key = (candidate.sourceProvider ?? '').toLowerCase()\n const bucket = groups.get(key)\n if (bucket === undefined) {\n groups.set(key, [candidate])\n } else {\n bucket.push(candidate)\n }\n }\n\n let group = groups.size === 1 ? [...groups.values()][0] : undefined\n if (group === undefined) {\n // A vendor named in the request never reaches this point: `keyForms` already scopes to it.\n const tiers = [provider.catalogProvider, provider.id, index.vendors.get(bareId(form.id).toLowerCase())]\n for (const tier of tiers) {\n const match = tier === undefined ? undefined : groups.get(tier.toLowerCase())\n if (match !== undefined) {\n group = match\n break\n }\n }\n }\n\n if (group === undefined) {\n return { ambiguous: candidates }\n }\n\n const winner = group[0]\n if (winner === undefined) {\n return undefined\n }\n\n return {\n hit: {\n entry: winner,\n // pi.dev is the only source carrying `thinkingLevelMap` and `compat`, so it is the only useful donor.\n donor: group.find(entry => entry !== winner && entry.source === 'pi.dev'),\n // The vendor prefix did work: it either scoped the lookup, or only the stripped id matched.\n viaVendorSplit: form.vendorScoped || (found.viaBare && form.vendor !== undefined),\n },\n }\n}\n\nfunction lookup(index: CatalogIndex, provider: ResolvedProvider, id: string): Outcome {\n for (const form of keyForms(provider, id)) {\n const outcome = select(candidatesFor(index, form), index, provider, form)\n if (outcome !== undefined) {\n return outcome\n }\n }\n\n return undefined\n}\n\nfunction matched(hit: Hit, matchKind: MatchKind, prefixRule?: AffixRule, suffixRule?: AffixRule): ResolvedMatch {\n return { kind: 'resolved', entry: hit.entry, donor: hit.donor, matchKind, prefixRule, suffixRule }\n}\n\n/** Removes at most one prefix and one suffix; a no-op or empty residual is not a match. */\nfunction strip(id: string, prefix: AffixRule | undefined, suffix: AffixRule | undefined): string | undefined {\n let out = id\n if (prefix !== undefined) {\n if (!out.startsWith(prefix.value)) {\n return undefined\n }\n out = out.slice(prefix.value.length)\n }\n if (suffix !== undefined) {\n if (!out.endsWith(suffix.value)) {\n return undefined\n }\n out = out.slice(0, out.length - suffix.value.length)\n }\n\n return out.length === 0 || out === id ? undefined : out\n}\n\n/** unset = every rule · `[]` = none · `['id']` = only those. */\nfunction gateRules(allowed: string[] | undefined, rules: AffixRule[]): AffixRule[] {\n if (allowed === undefined) {\n return rules\n }\n const ids = new Set(allowed)\n\n return rules.filter(rule => ids.has(rule.id))\n}\n\n/**\n * Single strips before double strips, so `x-preview-free` does not lose `-preview` when only `-free`\n * was needed. Rules arrive longest-value-first, so a broad `-free` cannot shadow `-preview-free`.\n */\nfunction combinations(prefixes: AffixRule[], suffixes: AffixRule[]): [AffixRule | undefined, AffixRule | undefined][] {\n const combos: [AffixRule | undefined, AffixRule | undefined][] = []\n for (const suffix of suffixes) {\n combos.push([undefined, suffix])\n }\n for (const prefix of prefixes) {\n combos.push([prefix, undefined])\n }\n for (const prefix of prefixes) {\n for (const suffix of suffixes) {\n combos.push([prefix, suffix])\n }\n }\n\n return combos\n}\n\nexport function resolveModel(input: ResolveInput): Resolution {\n const { index, provider, modelId } = input\n const gate = provider.models.get(modelId)\n\n if (gate?.skip === true) {\n return { kind: 'unresolved', reason: 'skipped' }\n }\n\n // An alias miss is reported rather than falling through, which would hide a config typo forever.\n if (gate?.alias !== undefined) {\n const outcome = lookup(index, provider, gate.alias)\n if (outcome === undefined) {\n return { kind: 'unresolved', reason: 'alias-miss' }\n }\n\n return 'ambiguous' in outcome ? { kind: 'ambiguous', candidates: outcome.ambiguous } : matched(outcome.hit, 'alias')\n }\n\n // The unstripped id always comes first: catalogs really do carry `:free` and `-free` as distinct\n // entries with their own pricing.\n const direct = lookup(index, provider, modelId)\n if (direct !== undefined) {\n if ('ambiguous' in direct) {\n return { kind: 'ambiguous', candidates: direct.ambiguous }\n }\n\n return matched(direct.hit, direct.hit.viaVendorSplit ? 'vendor-qualified' : 'exact')\n }\n\n const combos = combinations(\n gateRules(gate?.prefixes, input.prefixRules),\n gateRules(gate?.suffixes, input.suffixRules),\n )\n for (const [prefix, suffix] of combos) {\n const stripped = strip(modelId, prefix, suffix)\n if (stripped === undefined) {\n continue\n }\n const outcome = lookup(index, provider, stripped)\n if (outcome === undefined) {\n continue\n }\n\n return 'ambiguous' in outcome\n ? { kind: 'ambiguous', candidates: outcome.ambiguous }\n : matched(outcome.hit, 'stripped', prefix, suffix)\n }\n\n const hadRules = input.prefixRules.length > 0 || input.suffixRules.length > 0\n\n return { kind: 'unresolved', reason: hadRules && combos.length === 0 ? 'rules-disabled' : 'no-match' }\n}\n","import type { CatalogSnapshot } from './catalog.js'\nimport type { EnrichedModel } from './merge.js'\nimport type { UserAuthoredMap } from './models-json.js'\nimport type { Resolution, ResolvedConfig, ResolvedProvider, SnapshotModel } from './types.js'\nimport type { ExtensionAPI, ModelRegistry } from '@earendil-works/pi-coding-agent'\nimport { mergeMetadata } from './merge.js'\nimport { resolveModel } from './resolver.js'\n\nexport interface ModelReport {\n id: string\n resolution: Resolution\n provenance: Map<string, string>\n issues: string[]\n model: EnrichedModel\n}\n\nexport interface ProviderReport {\n provider: string\n status: 'applied' | 'skipped' | 'failed' | 'pending'\n reason: string | undefined\n models: ModelReport[]\n}\n\nexport interface ProviderApplierDeps {\n warn?: ((message: string) => void) | undefined\n}\n\nexport class ProviderApplier {\n private readonly snapshots = new Map<string, SnapshotModel[]>()\n private readonly skipped = new Map<string, string>()\n private readonly reports = new Map<string, ProviderReport>()\n private readonly lastRegistered = new Map<string, EnrichedModel[]>()\n private readonly warn: (message: string) => void\n\n constructor(deps: ProviderApplierDeps = {}) {\n this.warn = deps.warn ?? (() => {})\n }\n\n /**\n * Must run before the first registration of the session: afterwards `getProvider(id).getModels()`\n * returns our own list, and re-deriving from it would fold every previous pass into the next one.\n */\n capture(registry: ModelRegistry, config: ResolvedConfig): void {\n this.snapshots.clear()\n this.skipped.clear()\n this.reports.clear()\n\n for (const provider of config.providers.values()) {\n const live = registry.getProvider(provider.id)\n if (live === undefined) {\n this.skip(provider.id, 'not present in Pi; check the provider id')\n continue\n }\n if (registry.getRegisteredNativeProvider(provider.id) !== undefined) {\n // registerProvider drops the native registration, so we would delete it.\n this.skip(provider.id, 'another extension registered a native provider for this id')\n continue\n }\n\n const snapshot = [...live.getModels()]\n if (snapshot.length === 0) {\n this.skip(provider.id, 'no models to complete')\n continue\n }\n if (live.refreshModels !== undefined && !provider.allowDynamic) {\n this.warn(\n `provider '${provider.id}' refreshes its model list dynamically; completing it freezes ` +\n 'newly discovered models until the next session',\n )\n }\n\n this.snapshots.set(provider.id, snapshot)\n this.reports.set(provider.id, { provider: provider.id, status: 'pending', reason: undefined, models: [] })\n }\n }\n\n apply(pi: ExtensionAPI, config: ResolvedConfig, catalog: CatalogSnapshot, userAuthored: UserAuthoredMap): void {\n if (catalog.status === 'unavailable') {\n return\n }\n\n for (const [providerId, snapshot] of this.snapshots) {\n const provider = config.providers.get(providerId)\n if (provider !== undefined) {\n this.applyProvider(pi, provider, snapshot, config, catalog, userAuthored)\n }\n }\n }\n\n private applyProvider(\n pi: ExtensionAPI,\n provider: ResolvedProvider,\n snapshots: SnapshotModel[],\n config: ResolvedConfig,\n catalog: CatalogSnapshot,\n userAuthored: UserAuthoredMap,\n ): void {\n const authored = userAuthored.get(provider.id)\n const models: EnrichedModel[] = []\n const reports: ModelReport[] = []\n\n // Every model from the snapshot, always: `applyExtension` replaces the list wholesale, so\n // anything omitted here disappears from Pi.\n for (const snapshot of snapshots) {\n const resolution = resolveModel({\n index: catalog.index,\n provider,\n prefixRules: config.prefixRules,\n suffixRules: config.suffixRules,\n modelId: snapshot.id,\n })\n const merged = mergeMetadata({\n snapshot,\n provider,\n resolution,\n gate: provider.models.get(snapshot.id),\n userAuthored: authored?.get(snapshot.id),\n })\n models.push(merged.model)\n reports.push({\n id: snapshot.id,\n resolution,\n provenance: merged.provenance,\n issues: merged.issues,\n model: merged.model,\n })\n }\n\n try {\n // Exactly `{ models }`: registerProvider merges defined keys and never expires them, so any\n // other key would permanently shadow a sibling extension's — and a relay's apiKey usually\n // lives in that sibling's registration.\n pi.registerProvider(provider.id, { models })\n this.lastRegistered.set(provider.id, models)\n this.reports.set(provider.id, { provider: provider.id, status: 'applied', reason: undefined, models: reports })\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n this.warn(`failed to complete provider '${provider.id}': ${message}`)\n this.reports.set(provider.id, { provider: provider.id, status: 'failed', reason: message, models: reports })\n }\n }\n\n /**\n * Cheap id-set comparison against the live list. Ordering already guarantees a discovery extension\n * registers before our first pass, so this only catches a third party changing the list mid-session.\n */\n reconcile(registry: ModelRegistry): boolean {\n let drifted = false\n for (const providerId of this.snapshots.keys()) {\n const live = registry.getProvider(providerId)\n if (live === undefined) {\n continue\n }\n const liveModels = [...live.getModels()]\n const registered = this.lastRegistered.get(providerId)\n if (liveModels.length === 0 || (registered !== undefined && sameIds(liveModels, registered))) {\n continue\n }\n this.snapshots.set(providerId, liveModels)\n drifted = true\n }\n\n return drifted\n }\n\n /**\n * `extensionProviders` outlives a `/reload` while our in-memory state does not, so a registration\n * for a provider that is no longer opted in would linger and could make a later recompose delete\n * the provider outright.\n */\n releaseStale(pi: ExtensionAPI, registry: ModelRegistry, config: ResolvedConfig): void {\n for (const [providerId, models] of this.lastRegistered) {\n if (config.providers.has(providerId)) {\n continue\n }\n // unregisterProvider drops the whole entry, including another extension's baseUrl and apiKey.\n // Leaving ours in place is the lesser harm.\n if (!isSolelyOurRegistration(registry.getRegisteredProviderConfig(providerId), models)) {\n continue\n }\n try {\n pi.unregisterProvider(providerId)\n this.lastRegistered.delete(providerId)\n } catch (error) {\n this.warn(\n `failed to release provider '${providerId}': ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n }\n\n getReports(): ProviderReport[] {\n const reports = [...this.reports.values()]\n for (const [provider, reason] of this.skipped) {\n reports.push({ provider, status: 'skipped', reason, models: [] })\n }\n\n return reports.sort((a, b) => a.provider.localeCompare(b.provider))\n }\n\n private skip(providerId: string, reason: string): void {\n this.skipped.set(providerId, reason)\n this.warn(`skipping provider '${providerId}': ${reason}`)\n }\n}\n\nfunction sameIds(live: readonly SnapshotModel[], registered: readonly EnrichedModel[]): boolean {\n if (live.length !== registered.length) {\n return false\n }\n const ids = new Set(registered.map(model => model.id))\n\n return live.every(model => ids.has(model.id))\n}\n\nfunction isSolelyOurRegistration(stored: object | undefined, models: EnrichedModel[]): boolean {\n if (stored === undefined) {\n return false\n }\n const keys = Object.keys(stored)\n\n return keys.length === 1 && keys[0] === 'models' && (stored as { models?: unknown }).models === models\n}\n","import type { CatalogSnapshot } from './catalog.js'\nimport type { ConfigIssue, LoadConfigResult } from './config.js'\nimport type { UserAuthoredMap } from './models-json.js'\nimport type { ResolvedConfig, SnapshotModel } from './types.js'\nimport type { ExtensionAPI, ModelRegistry } from '@earendil-works/pi-coding-agent'\nimport { CatalogStore } from './catalog.js'\nimport { registerModelInfoCommand } from './command.js'\nimport { defaultModelInfoAgentDir, EXTENSION_ID, loadModelInfoConfig, resolveModelInfoConfig } from './config.js'\nimport { readUserAuthoredFields } from './models-json.js'\nimport { ProviderApplier } from './provider-apply.js'\n\nexport interface ModelInfoExtensionDependencies {\n catalogStore?: CatalogStore | undefined\n applier?: ProviderApplier | undefined\n loadConfig?: ((cwd: string, agentDir: string) => LoadConfigResult) | undefined\n readUserAuthored?: ((agentDir: string) => UserAuthoredMap) | undefined\n agentDir?: string | undefined\n /** Defers all I/O off the extension factory and off `session_start`. */\n schedule?: ((task: () => void) => void) | undefined\n warn?: ((message: string) => void) | undefined\n}\n\nfunction defaultWarn(message: string): void {\n console.warn(`[${EXTENSION_ID}] ${message}`)\n}\n\nexport function createModelInfoExtension(pi: ExtensionAPI, dependencies: ModelInfoExtensionDependencies = {}): void {\n const warn = dependencies.warn ?? defaultWarn\n const agentDir = dependencies.agentDir ?? defaultModelInfoAgentDir()\n const loadConfig = dependencies.loadConfig ?? ((cwd, dir) => loadModelInfoConfig({ cwd, agentDir: dir }))\n const readUserAuthored = dependencies.readUserAuthored ?? (dir => readUserAuthoredFields(dir))\n const schedule =\n dependencies.schedule ??\n (task => {\n setTimeout(task, 0)\n })\n const store = dependencies.catalogStore ?? new CatalogStore()\n const applier = dependencies.applier ?? new ProviderApplier({ warn })\n\n let config: ResolvedConfig | undefined\n let issues: ConfigIssue[] = []\n let registry: ModelRegistry | undefined\n let userAuthored: UserAuthoredMap = new Map()\n let catalog: CatalogSnapshot | undefined\n let pending: CatalogSnapshot | undefined\n let session: AbortController | undefined\n let isIdle: () => boolean = () => true\n\n function applyCatalog(snapshot: CatalogSnapshot): void {\n catalog = snapshot\n if (config === undefined) {\n return\n }\n // A contextWindow that changes mid-turn can flip a compaction decision, so by default the swap\n // waits for the turn to finish.\n if (config.applyOnIdleOnly && !isIdle()) {\n pending = snapshot\n\n return\n }\n pending = undefined\n applier.apply(pi, config, snapshot, userAuthored)\n }\n\n async function run(signal: AbortSignal): Promise<void> {\n if (config === undefined) {\n return\n }\n applyCatalog(store.load(config))\n if (signal.aborted) {\n return\n }\n const refreshed = await store.refresh(config, signal)\n if (!signal.aborted) {\n applyCatalog(refreshed)\n }\n }\n\n function start(): void {\n const controller = new AbortController()\n session = controller\n schedule(() => {\n void run(controller.signal).catch(error => {\n warn(`catalog refresh failed: ${error instanceof Error ? error.message : String(error)}`)\n })\n })\n }\n\n // Synchronous by contract: `initializeExtension` awaits the factory, and a discovery extension's\n // registration is flushed before any session event — so staying out of the factory is also what\n // guarantees we complete its models rather than racing them.\n pi.on('session_start', (_event, context) => {\n session?.abort()\n session = undefined\n pending = undefined\n catalog = undefined\n registry = context.modelRegistry\n isIdle = () => context.isIdle()\n\n const loaded = loadConfig(context.cwd, agentDir)\n const resolved = loaded.config === undefined ? undefined : resolveModelInfoConfig(loaded.config, loaded.globalPath)\n issues = [...loaded.issues, ...(resolved?.issues ?? [])]\n for (const issue of issues) {\n warn(`config issue at ${issue.sourcePath}: ${issue.message}`)\n }\n\n config = resolved?.config\n if (config === undefined) {\n return\n }\n\n applier.releaseStale(pi, context.modelRegistry, config)\n if (config.providers.size === 0) {\n return\n }\n\n applier.capture(context.modelRegistry, config)\n userAuthored = readUserAuthored(agentDir)\n start()\n })\n\n pi.on('before_agent_start', (_event, context) => {\n if (config === undefined || catalog === undefined || registry === undefined) {\n return\n }\n isIdle = () => context.isIdle()\n if (applier.reconcile(registry)) {\n applier.apply(pi, config, catalog, userAuthored)\n }\n })\n\n pi.on('turn_end', () => {\n if (pending !== undefined && config !== undefined) {\n applier.apply(pi, config, pending, userAuthored)\n }\n pending = undefined\n })\n\n pi.on('session_shutdown', () => {\n session?.abort()\n session = undefined\n pending = undefined\n })\n\n registerModelInfoCommand(pi, {\n getReports: () => applier.getReports(),\n getCatalog: () => catalog,\n getIssues: () => issues,\n getEffectiveModel: (providerId, modelId): SnapshotModel | undefined => registry?.find(providerId, modelId),\n refresh: async () => {\n if (config === undefined) {\n return\n }\n applyCatalog(await store.refresh(config, new AbortController().signal, true))\n },\n })\n}\n","import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'\nimport { createModelInfoExtension } from './extension.js'\n\nexport default function modelInfoExtension(pi: ExtensionAPI): void {\n createModelInfoExtension(pi)\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@mzwing/pi-model-info",
3
+ "version": "0.1.0",
4
+ "description": "Completes third-party model metadata in Pi from the pi.dev and models.dev catalogs",
5
+ "keywords": [
6
+ "context-window",
7
+ "model-metadata",
8
+ "models.dev",
9
+ "pi",
10
+ "pi-coding-agent",
11
+ "pi-extension",
12
+ "pi-package",
13
+ "pricing"
14
+ ],
15
+ "homepage": "https://github.com/mzwing/pi-packages/tree/main/packages/pi-model-info#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/mzwing/pi-packages/issues"
18
+ },
19
+ "license": "MIT",
20
+ "author": {
21
+ "name": "mzwing",
22
+ "email": "mzwing@mzwing.eu.org"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/mzwing/pi-packages.git",
27
+ "directory": "packages/pi-model-info"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "schemas",
32
+ "config/config.example.json",
33
+ "README.md",
34
+ "LICENSE"
35
+ ],
36
+ "type": "module",
37
+ "sideEffects": false,
38
+ "main": "./dist/index.js",
39
+ "types": "./dist/index.d.ts",
40
+ "exports": {
41
+ ".": {
42
+ "types": "./dist/index.d.ts",
43
+ "import": "./dist/index.js"
44
+ }
45
+ },
46
+ "publishConfig": {
47
+ "access": "public",
48
+ "registry": "https://registry.npmjs.org/"
49
+ },
50
+ "dependencies": {
51
+ "zod": "4.5.2"
52
+ },
53
+ "devDependencies": {
54
+ "@earendil-works/pi-ai": "0.84.4",
55
+ "@earendil-works/pi-coding-agent": "0.84.4",
56
+ "@types/node": "26.4.0",
57
+ "tsdown": "0.22.14",
58
+ "typescript": "7.0.2",
59
+ "vitest": "4.1.11"
60
+ },
61
+ "peerDependencies": {
62
+ "@earendil-works/pi-ai": "^0.84.2 || ^0.85.0",
63
+ "@earendil-works/pi-coding-agent": "^0.84.2 || ^0.85.0"
64
+ },
65
+ "engines": {
66
+ "node": ">=24"
67
+ },
68
+ "pi": {
69
+ "extensions": [
70
+ "./dist/index.js"
71
+ ]
72
+ },
73
+ "scripts": {
74
+ "build": "tsdown",
75
+ "typecheck": "tsc --noEmit",
76
+ "test": "vitest run",
77
+ "test:watch": "vitest",
78
+ "gen:schema": "node --experimental-strip-types scripts/generate-schema.ts"
79
+ }
80
+ }