UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

142 lines (141 loc) 6.94 kB
import { type GatewayCredentialResolution } from "#internal/resolve-model-endpoint-status.js"; import type { AgentModelSettingsPatch } from "#source-change/apply-agent-model-settings.js"; import { type SelectModelDeps } from "../boxes/select-model.js"; import { type GatewayModelCapabilities, type ReasoningLevel } from "../boxes/model-capabilities.js"; import { type VercelProjectOperationOptions } from "../project-resolution.js"; import type { AgentReasoningDefinition, ModelRouting } from "#shared/agent-definition.js"; import { type GatewayServiceTierState } from "#shared/gateway-service-tier.js"; import type { Prompter, SelectOption } from "../prompter.js"; import { type ApplyModelSettingsOutcome } from "./model-source-change.js"; import { runProviderFlow, type ModelProviderStatus } from "./provider.js"; /** The current model id, its routing, and whether `/model` can rewrite it. */ export interface CurrentAgentModel { id: string | null; routing: ModelRouting | null; reasoning: AgentReasoningDefinition | null; serviceTier: GatewayServiceTierState; /** * The authored `model` is a string the source editor can rewrite. False for a * source-backed SDK model call (`gateway(...)`, `anthropic(...)`), which is * not a string literal — independent of how the model routes. */ editable: boolean; /** Whether the top-level agent config object can carry reasoning/tier edits. */ settingsEditable: boolean; } export type { GatewayServiceTierState }; /** * Everything the composite Change-model screen edits, resolved before it * opens. The model section is a searchable catalog pick, or a fixed line when * the authored model is a source-backed SDK call `/model` cannot rewrite. */ export interface ModelSettingsRequest { model: { kind: "pick"; options: readonly SelectOption<string>[]; current: string | null; } | { kind: "fixed"; current: string | null; reason: string; }; /** Authored reasoning effort; null means the provider default. */ reasoning: ReasoningLevel | null; /** Authored Gateway service tier. */ serviceTier: GatewayServiceTierState; /** Whether the agent config object can carry reasoning/tier edits. */ settingsEditable: boolean; /** True for a direct external provider, where Gateway tiers do not apply. */ externalRouting: boolean; /** Capability lookup over the already-fetched catalog; called on every pick. */ capabilitiesFor(modelId: string | null): GatewayModelCapabilities | undefined; } /** * The screen's draft on Done. Each field is present only when it differs from * the authored value; `"default"` and `"standard"` mean "remove the setting". */ export interface ModelSettingsResult { model?: string; reasoning?: "default" | ReasoningLevel; serviceTier?: "standard" | "priority"; } /** Renderer-owned composite model screen; only the dev TUI implements this. */ export type ModelSettingsPicker = (request: ModelSettingsRequest) => Promise<ModelSettingsResult | undefined>; /** Injected for tests; defaults to the real reads, fetches, and source edit. */ export interface ModelFlowDeps { /** * Reads the model the runtime currently serves and how it routes; both null * before the first compile. */ readCurrentModel: (appRoot: string) => Promise<CurrentAgentModel>; /** Applies one completed `/model` draft to authored source. */ applySettings: (input: { appRoot: string; patch: AgentModelSettingsPatch; }) => Promise<ApplyModelSettingsOutcome>; /** Catalog fetch behind the shared model picker. */ selectModel?: SelectModelDeps; /** The composite Change-model screen; the dev TUI renderer implements it. */ pickModelSettings?: ModelSettingsPicker; /** Reads how the model is backed right now, for the menu's provider row. */ detectProviderStatus: typeof detectModelProviderStatus; /** The provider sub-flow behind the menu's provider row. */ runProviderFlow: typeof runProviderFlow; } export type { ModelProviderStatus }; /** * A provider sub-flow run that actually moved the provider: the credential * the link flow verified landed in an env file (when one did), paired with * the re-detected {@link ModelProviderStatus} — the same read the menu's * provider row shows, so every surface reports one truth. The sub-flow's * external-provider branch only shows instructions — nothing changes on * disk — so it never surfaces as an outcome. */ export interface ModelProviderOutcome { /** The credential resolution the runtime will honor; see {@link LinkFlowResult}. */ resolution?: GatewayCredentialResolution; status: ModelProviderStatus; } export type ModelFlowResult = { kind: "cancelled"; /** True when Esc dropped drafted setting changes that Done would commit. */ discardedDraft?: boolean; } | { kind: "done"; /** The last apply line, when the model was changed this session. */ modelMessage?: string; /** The last provider sub-flow outcome, when one ran to completion. */ providerOutcome?: ModelProviderOutcome; }; export declare const MODEL_MENU_MESSAGE = ""; /** * Reads the provider status the menu shows. Detection order matters: a linked * project subsumes any pulled credential (the link is what the user manages), * and `AI_GATEWAY_API_KEY` outranks `VERCEL_OIDC_TOKEN` because it is the one * the provider sub-flow's own-key branch writes. */ export declare function detectModelProviderStatus(appRoot: string, options?: VercelProjectOperationOptions, env?: Record<string, string | undefined>): Promise<ModelProviderStatus>; /** * THE MODEL FLOW for the dev TUI's `/model`: a root menu whose Change model * row opens the composite model screen (catalog pick, reasoning-effort slider, * service-tier toggle) and whose provider row runs {@link runProviderFlow}. * Authored setting changes stay in memory until Done, then land through one * source transform and atomic rename. A completed provider change commits the * current draft and returns to the prompt; cancelled flows and * external-provider instructions return to the menu. */ export declare function runModelFlow(input: { appRoot: string; prompter: Prompter; /** Opens provider setup before the root menu when runtime evidence requires it. */ initialStep?: "provider"; signal?: AbortSignal; deps?: Partial<ModelFlowDeps>; }): Promise<ModelFlowResult>; /** * Refusal message when `/model` can't rewrite the model — it is a source-backed * SDK model call (`gateway(...)`, `anthropic(...)`), not a string literal — or * null when the model is an editable string. Editability is independent of * routing: a `gateway(...)` call is gateway-routed yet still uneditable here. */ export declare function modelChangeRefusalForUneditableModel(appRoot: string): Promise<string | null>;