/** * `resolveLLMForSystem` — the single DRY chokepoint for all LLM resolution (E9). * * ## Purpose * * CLEO previously had a 4-resolver / 3-picker sprawl: `resolveLLMForRole`, * `resolveAnthropicForRole`, `resolveCredentials`, and several inline `pickX` * helpers each duplicated the implicit fallback model literal or called different * tiers of the resolution chain independently. * * `resolveLLMForSystem` is the ONE chokepoint that: * * 1. Accepts a semantic "system of use" label (e.g. `'sentient'`, `'memory'`) * instead of raw role names — insulating call-sites from config vocabulary. * 2. Maps the system label to the canonical {@link RoleName} via * {@link SYSTEM_ROLE_MAP} (overridable by `opts.roleOverride`). * 3. Delegates to `resolveLLMForRole` for the full 5-tier config + * CredentialPool resolution chain — no duplication. * 4. When resolution lands on `implicit-fallback`, replaces the hardcoded * haiku literal with the SSoT default model from the provider registry * (`getProviderProfile(provider).defaultModel`) — satisfying the * "not hardcoded" acceptance criterion. * * ## What this is NOT * * - A replacement for `resolveLLMForRole`. Existing callers of * `resolveLLMForRole` continue to work unchanged; T11757 will migrate them * to this chokepoint incrementally. * - A new credential store or provider registry. All credential I/O goes * through the existing CredentialPool (E3 pool) inside `resolveLLMForRole`. * * @module llm/system-resolver * @task T11749 * @epic T11745 */ import type { ResolveLLMForSystemOptions, RoleName, SystemResolverInput } from '@cleocode/contracts'; import { type ResolvedLLM } from './role-resolver.js'; /** * Result of {@link resolveLLMForSystem}. * * Extends {@link ResolvedLLM} with the resolved `system` label so callers * can log/audit which system triggered the resolution without passing it * separately. * * @task T11749 */ export interface ResolvedLLMForSystem extends ResolvedLLM { /** * The {@link SystemResolverInput} that initiated this resolution — either the * flat {@link SystemOfUseLabel} or the structured {@link RoleSystem} * descriptor (`{ kind: 'role', id }`) the caller passed. * * Preserved verbatim from the call argument — not normalised or remapped. */ system: SystemResolverInput; /** * The {@link RoleName} that was actually used for config lookup. * * `null` when `system === 'default'` and no role override was supplied * (the global LLM default path was used instead of a per-role entry). */ resolvedRole: RoleName | null; } /** * Resolve the LLM client + credential for a semantic system-of-use label OR a * structured {@link RoleSystem} descriptor. * * This is the single DRY chokepoint for all LLM resolution in CLEO (E9 · * T11745). It wraps `resolveLLMForRole` with: * * - System label → role mapping (via {@link SYSTEM_ROLE_MAP}); OR direct * `{ kind: 'role', id }` descriptor resolution (T11750 · AC1). * - SSoT default model from the provider registry when `implicit-fallback` * is reached (the hardcoded haiku literal is NOT used as the final model). * - Full CredentialPool (E3) binding via `resolveLLMForRole` delegation. * * ## Role equivalence (T11750 · AC1) * * `resolveLLMForSystem({ kind: 'role', id })` is the chokepoint expression of a * direct role resolution — identical to `resolveLLMForRole(id)` for every * resolution-relevant field (`provider` / `model` / `source` / `credential` / * `sealedCredential` / `apiMode` / …), differing ONLY by the additive `system` * + `resolvedRole` envelope fields. There is exactly ONE resolution * implementation (`resolveLLMForRole`); both input forms funnel through it with * ZERO duplicated logic. The descriptor form does NOT thread a `systemKey` * (there is no flat label to key the `llm.systems[key]` override tier on), so it * walks the same tier chain a bare `resolveLLMForRole(id)` call walks. * * Like `resolveLLMForRole`, this function **never throws**: when no credential * is reachable the caller receives `{ credential: null, client: null, … }` and * is responsible for its own graceful-degradation path. * * @example * ```ts * // Flat label (background subsystem): * const a = await resolveLLMForSystem('sentient', { projectRoot }); * // Structured role descriptor (T11750 · AC1) — equivalent to * // resolveLLMForRole('consolidation'): * const b = await resolveLLMForSystem({ kind: 'role', id: 'consolidation' }, { projectRoot }); * if (!a.sealedCredential || !a.client) { * return null; // graceful no-op — no credential available * } * // Use resolved.model, resolved.client, resolved.credential (metadata only); * // materialize the secret at the wire via resolved.sealedCredential.fetch(). * ``` * * @param system - Flat {@link SystemOfUseLabel} or {@link RoleSystem} descriptor. * @param opts - Optional overrides (project root, role override, skipCatalogDefault). * @returns A {@link ResolvedLLMForSystem} envelope; never throws. * * @task T11749 * @task T11750 * @epic T11745 */ export declare function resolveLLMForSystem(system: SystemResolverInput, opts?: ResolveLLMForSystemOptions): Promise; //# sourceMappingURL=system-resolver.d.ts.map