/** * Same-id reasoning-capability inheritance for hand-declared pi-ai routes: * the model catalog inherits capabilities by route key, not by model id, so a * relay route listing `gpt-5.5` reads nothing from the installed `openai` * catalog entry and materializes as `reasoning: false` until its settings * entry declares `reasoningEfforts`. This adapter closes that gap without * touching upstream: whenever a pi-ai profile's model entry carries no * declaration and its live row advertises no efforts, but the same model id * is declared (in a sibling settings entry) or advertised (on another route) * elsewhere, the declaration is materialized into settings — verbatim from a * sibling declaration when one exists, otherwise as an identity level map * (`off` maps to null, every other level to its own name), which is the * correct wire spelling for OpenAI-compatible relays. Writes ride the same * `settings.mutate` path as the provider panel, so the upstream * `assertServiceable` gate still rejects anything invalid atomically. * * @module @deepseek-ai/dsh-tui/model-capabilities */ import type { Context } from '@deepseek-ai/cordis'; import { type ModelRow } from './models.ts'; /** A notice sink structurally compatible with the app bridge's `notify`. */ export type CapabilityNotice = (text: string, tone?: 'info' | 'warning' | 'error') => void; /** One pi-ai provider profile as stored in settings, addressed for mutation. */ export interface CapabilityProfileSource { /** Settings namespace owning the profile (`llm-pi-ai`). */ readonly settingsNs: string; /** Path from the section root to this provider's profile. */ readonly settingsPath: readonly string[]; /** Revision of the owning section at read time. */ readonly revision: number; /** Raw model entries, exactly as stored (declaration fields included). */ readonly models: readonly Record[]; } /** One planned per-provider models rewrite. */ export interface CapabilitySyncPlan { /** Provider route the plan targets. */ readonly provider: string; /** Settings namespace owning the profile. */ readonly settingsNs: string; /** Path from the section root to the provider profile. */ readonly settingsPath: readonly string[]; /** Raw model entries, exactly as stored (declaration fields included). */ readonly models: readonly Record[]; /** Fingerprint of the source models array this plan was derived from. */ readonly sourceFingerprint: string; /** Document revision of the owning section when the plan was derived. */ readonly sourceRevision: number; /** Model ids that gained a declaration, notice-facing. */ readonly inherited: readonly string[]; /** `provider/model` labels the declarations came from, notice-facing. */ readonly sources: readonly string[]; } /** * Plan the reasoning declarations to materialize. A model entry inherits * when it declares nothing (`reasoningEfforts` absent — a dict or `false` is * an explicit choice and is never touched) and its live row advertises no * efforts; the donor is the first sibling settings declaration for the same * id, copied verbatim so dialect wire spellings survive, otherwise the first * other-route row advertising efforts for that id, mapped by identity. * Entries never lose fields and keep their key order; a provider appears in * the result only when at least one entry changes. * @param input - the live model rows and the raw pi-ai profiles from settings. * @returns one plan per provider with at least one inheritance. */ export declare function planCapabilitySync(input: { readonly rows: readonly ModelRow[]; readonly profiles: ReadonlyMap; }): readonly CapabilitySyncPlan[]; /** * Materialize same-id reasoning declarations once per provider. Reads the * configurable directory, the redacted settings document, and the live model * rows; plans; then writes each provider's merged models array through * `settings.mutate` under a fresh revision (writes bump the section * revision, so per-plan revisions are re-read). Every failure converges to a * single-line notice — the caller's promise never rejects and the session * keeps running on the previous configuration. * @param ctx - context carrying the `llm` and `settings` services (optional). * @param notify - the app bridge's notice sink, when one is live. */ export declare function syncModelCapabilities(ctx: Context, notify?: CapabilityNotice): Promise; /** Test seam: forget the applied-write fingerprints. */ export declare function resetCapabilitySyncState(): void;