feat(coding-agent): replace model registry with model runtime

Move provider auth and OAuth flows onto pi-ai Models, compose models.json and extension overlays through ModelRuntime, and retain ModelRegistry as an extension compatibility facade.
This commit is contained in:
Mario Zechner
2026-07-14 17:48:45 +02:00
parent 6731a0ba9e
commit 9993c96907
133 changed files with 5103 additions and 4340 deletions
+12 -14
View File
@@ -23,12 +23,11 @@ import {
createAgentSessionServices,
} from "./core/agent-session-services.ts";
import { formatNoModelsAvailableMessage } from "./core/auth-guidance.ts";
import { AuthStorage } from "./core/auth-storage.ts";
import { exportFromFile } from "./core/export-html/index.ts";
import type { InlineExtension } from "./core/extensions/types.ts";
import { applyHttpProxySettings, configureHttpDispatcher } from "./core/http-dispatcher.ts";
import type { ModelRegistry } from "./core/model-registry.ts";
import { resolveCliModel, resolveModelScope, type ScopedModel } from "./core/model-resolver.ts";
import type { ModelRuntime } from "./core/model-runtime.ts";
import { restoreStdout, takeOverStdout } from "./core/output-guard.ts";
import { type AppMode, resolveProjectTrusted } from "./core/project-trust.ts";
import type { CreateAgentSessionOptions } from "./core/sdk.ts";
@@ -358,7 +357,7 @@ function buildSessionOptions(
parsed: Args,
scopedModels: ScopedModel[],
hasExistingSession: boolean,
modelRegistry: ModelRegistry,
modelRuntime: ModelRuntime,
settingsManager: SettingsManager,
): {
options: CreateAgentSessionOptions;
@@ -377,7 +376,7 @@ function buildSessionOptions(
cliProvider: parsed.provider,
cliModel: parsed.model,
cliThinking: parsed.thinking,
modelRegistry,
modelRuntime,
});
if (resolved.warning) {
diagnostics.push({ type: "warning", message: resolved.warning });
@@ -400,7 +399,7 @@ function buildSessionOptions(
// Check if saved default is in scoped models - use it if so, otherwise first scoped model
const savedProvider = settingsManager.getDefaultProvider();
const savedModelId = settingsManager.getDefaultModel();
const savedModel = savedProvider && savedModelId ? modelRegistry.find(savedProvider, savedModelId) : undefined;
const savedModel = savedProvider && savedModelId ? modelRuntime.getModel(savedProvider, savedModelId) : undefined;
const savedInScope = savedModel ? scopedModels.find((sm) => modelsAreEqual(sm.model, savedModel)) : undefined;
if (savedInScope) {
@@ -433,7 +432,7 @@ function buildSessionOptions(
}));
}
// API key from CLI - set in authStorage
// API key from CLI - set as a non-persistent runtime override
// (handled by caller before createAgentSession)
// Tools
@@ -611,7 +610,6 @@ export async function main(args: string[], options?: MainOptions) {
const resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);
const resolvedPromptTemplatePaths = resolveCliPaths(cwd, parsed.promptTemplates);
const resolvedThemePaths = resolveCliPaths(cwd, parsed.themes);
const authStorage = AuthStorage.create();
const createRuntime: CreateAgentSessionRuntimeFactory = async ({
cwd,
agentDir,
@@ -634,7 +632,6 @@ export async function main(args: string[], options?: MainOptions) {
const services = await createAgentSessionServices({
cwd,
agentDir,
authStorage,
settingsManager: runtimeSettingsManager,
extensionFlagValues: parsed.unknownFlags,
resourceLoaderReloadOptions: shouldResolveProjectTrust
@@ -676,7 +673,7 @@ export async function main(args: string[], options?: MainOptions) {
extensionFactories: options?.extensionFactories,
},
});
const { settingsManager, modelRegistry, resourceLoader } = services;
const { settingsManager, modelRuntime, resourceLoader } = services;
const diagnostics: AgentSessionRuntimeDiagnostic[] = [
...projectTrustDiagnostics,
...services.diagnostics,
@@ -689,7 +686,7 @@ export async function main(args: string[], options?: MainOptions) {
const modelPatterns = parsed.models ?? settingsManager.getEnabledModels();
const scopedModels =
modelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRegistry) : [];
modelPatterns && modelPatterns.length > 0 ? await resolveModelScope(modelPatterns, modelRuntime) : [];
const {
options: sessionOptions,
cliThinkingFromModel,
@@ -698,7 +695,7 @@ export async function main(args: string[], options?: MainOptions) {
parsed,
scopedModels,
sessionManager.buildSessionContext().messages.length > 0,
modelRegistry,
modelRuntime,
settingsManager,
);
diagnostics.push(...sessionOptionDiagnostics);
@@ -710,7 +707,8 @@ export async function main(args: string[], options?: MainOptions) {
message: "--api-key requires a model to be specified via --model, --provider/--model, or --models",
});
} else {
authStorage.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);
modelRuntime.setRuntimeApiKey(sessionOptions.model.provider, parsed.apiKey);
await services.modelRuntime.getAvailable();
}
}
@@ -745,7 +743,7 @@ export async function main(args: string[], options?: MainOptions) {
});
time("createAgentSessionRuntime");
const { services, session, modelFallbackMessage } = runtime;
const { settingsManager, modelRegistry, resourceLoader } = services;
const { settingsManager, modelRuntime, resourceLoader } = services;
applyHttpProxySettings(settingsManager.getGlobalSettings().httpProxy);
configureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs());
@@ -759,7 +757,7 @@ export async function main(args: string[], options?: MainOptions) {
if (parsed.listModels !== undefined) {
const searchPattern = typeof parsed.listModels === "string" ? parsed.listModels : undefined;
await listModels(modelRegistry, searchPattern);
await listModels(modelRuntime, searchPattern);
process.exit(0);
}