import type { LanguageModel } from "ai"; import { type DevCredential } from "./resolve.js"; /** * `vendoModel(name?)` — the vendo model family entry (models spec 2026-07-22): * a lazily-resolving ai-SDK LanguageModel bound to the app's credential * ladder. It IS an ai-SDK LanguageModel (BYO seam unchanged, 03-agent §1), * resolving the credential lazily on first use: * * - env-key rungs delegate to the host-installed @ai-sdk provider (either live * spec, v3 or v4) with full native tool calling — works in production too. * Since the * selection law they are reachable only through the internal * VENDO_DEV_CREDENTIAL pin: a host's own provider key belongs in `models`, * where it is a CHOICE (`models: { default: anthropic(key) }`), not in an env * var Vendo sniffs. * - VENDO_API_KEY delegates to the Vendo Cloud model gateway: the * host-installed @ai-sdk/anthropic pointed at `/api/v1`, whose * Anthropic-compatible /messages endpoint serves the metered allowance * under the vendo model family names (`vendo` by default). * - nothing available → every call fails with the exact instructions. * * Name strings pass through VERBATIM to whatever the resolved credential * talks to — Cloud key → the gateway (vendo-* names are real model ids * there), provider key → that provider, untouched. There is NO client-side * name translation of any kind; an unknown name surfaces the provider's own * error. The only "magic" is per-rung/per-slot DEFAULTS when no name is * given, and per-slot env pins (precedence: explicit model object → env pin * → configured string → per-rung default). */ /** The model slots the runtime composes — one per real job, matching the seats * in `@vendoai/core` (`agent` is what the `default` seat rides). `extract` * never runs in-process; it exists so the CLI extraction ladder shares the * same pin names. */ export type VendoModelSlot = "agent" | "apps" | "review" | "judge" | "extract"; export interface VendoModelOptions { /** Host app root; providers resolve from here. Default cwd. */ root?: string; env?: Record; /** Test seam for host-module resolution (providers). */ importModule?: (root: string, specifier: string) => Promise>; /** Which slot's env pin + per-rung default applies. Normally inferred from * the family name (`vendo-apps` → apps, `vendo-review` → review, * `vendo-judge` → judge, `vendo-extract` → extract, anything else → agent); * createVendo passes it explicitly when composing internal slots. */ slot?: VendoModelSlot; /** The `fetch` the resolved provider dials with. Unset leaves the provider * on its own default; createVendo passes the keep-alive pool, so a turn's * inference does not re-handshake the gateway after every idle gap. */ fetch?: typeof fetch; } interface LanguageModelV3Like { specificationVersion: "v3"; provider: string; modelId: string; supportedUrls: PromiseLike> | Record; doGenerate(options: unknown): PromiseLike; doStream(options: unknown): PromiseLike; } type Resolution = /** The credential rides along so a rejected key can name its own fix * (rejectedKey below); an explicit host-passed model object has none. */ { mode: "delegate"; model: LanguageModelV3Like; credential?: DevCredential; } | { mode: "unavailable"; message: string; }; /** Env pins, one per slot (spec DX surface 5). Highest non-explicit * precedence: explicit model object → env pin → models string → default. */ export declare const SLOT_PIN_ENV: Record; /** The keyless boot error. Both ways out, in order: explicit config first, then * VENDO_API_KEY. Byte-for-byte coupled to `MODEL_UNAVAILABLE_SIGNAL` in * `@vendoai/apps` (server/doors/build-messages.ts), which anchors on this * sentence's opening so the actionable line survives the build door's fold — * change one and the other stops matching. The seam is tested in * tests/dev-creds/model.test.ts, through the real regex. */ export declare const NO_CREDENTIAL_MESSAGE: string; /** The slots whose model `createVendo`'s `models` block can configure by name * or object. Every other slot resolves through the seat record * (resolveModels), so they are not bound per-instance here. */ declare const CONFIGURABLE_SLOTS: readonly ["judge"]; type ConfigurableSlot = (typeof CONFIGURABLE_SLOTS)[number]; export type ConfigurableSlotModels = Partial>; /** Bind createVendo's `models` slot config onto ONE vendoModel-built instance * (spec: models.judge is consumed only by a judge the host wired from * vendoModel("vendo-judge") — the model rides Judge.model so composition can * reach it). Per instance, replacing the former process-level registry whose * last createVendo won. A BYO model object (or anything else that is not a * vendoModel instance) is a deliberate no-op: explicit models never change * behavior. @internal — called by createVendo; not public API. */ export declare function bindVendoModelSlots(model: unknown, models: ConfigurableSlotModels | undefined): void; /** Host-root resolution first, vendo's own copy as the provider fallback. * * Precedence: the HOST's install always wins when present — their version, * their module instance, so the `ai` SDK never sees two copies of one * provider in a repo that has it (the dual-package hazard). Only when the * host root resolves nothing do we resolve from vendo's own module context * (createRequire off import.meta.url): @ai-sdk/anthropic ships as a real * dependency of @vendoai/vendo, so a VENDO_API_KEY — via the * Anthropic-compatible Cloud gateway — lights up live chat under * `npx vendo try` with nothing installed in the repo. Scoped to @ai-sdk/* * provider modules; arbitrary specifiers keep strict host-root resolution. * (Exported for the resolution tests; the injectable seam is `importModule`.) */ export declare function importHostModule(root: string, specifier: string): Promise>; export declare class DevModelController { private readonly root; private readonly env; private readonly importModule; private readonly slot; private readonly name; private readonly fetch; private resolution; private announced; /** Per-instance slot config bound by createVendo (bindVendoModelSlots). */ private slotModels; constructor(options?: VendoModelOptions & { name?: string; }); /** Bind createVendo's `models` slot config to THIS instance (see * bindVendoModelSlots). Composition runs before the first model call, so * the lazy resolution below always sees the bound config. */ configureSlots(models: ConfigurableSlotModels | undefined): void; /** What `models.` says for THIS instance's slot, if anything. */ private get configured(); /** Resolve the credential once per process; state it on the server log once. * An unavailable resolution logs its full instructions HERE — the wire * deliberately shows clients only a generic error, so the operator's * terminal is where the honest message must land. */ resolve(): Promise; private announce; /** The string-tier model id for the resolved rung. Precedence (spec §DX * surfaces): env pin → configured slot string (models.judge) → the verbatim * name → the per-rung slot default. */ private modelId; /** The shared delegate rung: load the provider module (an install failure * resolves unavailable with the exact install command), pick the model id * (per-slot precedence above), and hand the factory-built model back. */ private delegate; private resolveOnce; /** This controller's own lazy model — the credential-aware call path. A * caller that probes `resolve()` first (vendo try's capability flags) must * hand THIS to the runtime, never the raw provider model the resolution * carries: only this path keeps the rejected key's rung (rejectedKey). */ model(): LanguageModel; doGenerate(callOptions: unknown): Promise; doStream(callOptions: unknown): Promise; private call; } /** The vendo model family entry (see module doc). No argument means the * agent slot: `vendo` on the Cloud rung, the provider's flagship default on * a BYO rung. A name is passed VERBATIM to the resolved rung. */ export declare function vendoModel(name?: string, options?: VendoModelOptions): LanguageModel; export {}; //# sourceMappingURL=model.d.ts.map