fix: flush extension provider registrations before model resolution (#1923)
Extension-based providers like pi-claude-cli register their models during extension loading, but registrations were queued and not flushed until after model resolution ran. This caused findInitialModel() and the startup model validation to see extension models as nonexistent, permanently overwriting the user's saved model selection on every launch. - Flush pendingProviderRegistrations in createAgentSession() before findInitialModel() so extension models are visible in the registry - Move model validation to after createAgentSession() in both print and interactive code paths - Load extensions before --list-models so extension models appear
This commit is contained in:
parent
416be1e169
commit
110c01b8c6
2 changed files with 78 additions and 1 deletions
|
|
@ -219,6 +219,16 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||||
time("resourceLoader.reload");
|
time("resourceLoader.reload");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flush provider registrations queued during extension loading so that
|
||||||
|
// extension models (e.g. pi-claude-cli) are visible in the registry before
|
||||||
|
// findInitialModel() runs. bindCore() repeats this flush as a safety net
|
||||||
|
// for any late-arriving registrations.
|
||||||
|
const { runtime: extensionRuntime } = resourceLoader.getExtensions();
|
||||||
|
for (const { name, config } of extensionRuntime.pendingProviderRegistrations) {
|
||||||
|
modelRegistry.registerProvider(name, config);
|
||||||
|
}
|
||||||
|
extensionRuntime.pendingProviderRegistrations = [];
|
||||||
|
|
||||||
// Check if session has existing data to restore
|
// Check if session has existing data to restore
|
||||||
const existingSession = sessionManager.buildSessionContext();
|
const existingSession = sessionManager.buildSessionContext();
|
||||||
const hasExistingSession = existingSession.messages.length > 0;
|
const hasExistingSession = existingSession.messages.length > 0;
|
||||||
|
|
|
||||||
69
src/cli.ts
69
src/cli.ts
|
|
@ -131,6 +131,48 @@ function parseCliArgs(argv: string[]): CliFlags {
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the configured default model against the registry and reset it if
|
||||||
|
* it no longer exists. Must run AFTER extensions have registered their
|
||||||
|
* providers so that extension models (e.g. pi-claude-cli) are visible.
|
||||||
|
*/
|
||||||
|
function validateConfiguredModel(
|
||||||
|
modelRegistry: ModelRegistry,
|
||||||
|
settingsManager: SettingsManager,
|
||||||
|
): void {
|
||||||
|
const configuredProvider = settingsManager.getDefaultProvider()
|
||||||
|
const configuredModel = settingsManager.getDefaultModel()
|
||||||
|
const allModels = modelRegistry.getAll()
|
||||||
|
const availableModels = modelRegistry.getAvailable()
|
||||||
|
const configuredExists = configuredProvider && configuredModel &&
|
||||||
|
allModels.some((m) => m.provider === configuredProvider && m.id === configuredModel)
|
||||||
|
const configuredAvailable = configuredProvider && configuredModel &&
|
||||||
|
availableModels.some((m) => m.provider === configuredProvider && m.id === configuredModel)
|
||||||
|
|
||||||
|
if (!configuredModel || !configuredExists) {
|
||||||
|
// Model not configured at all, or removed from registry — pick a fallback.
|
||||||
|
// Only fires when the model is genuinely unknown (not just temporarily unavailable).
|
||||||
|
const piDefault = getPiDefaultModelAndProvider()
|
||||||
|
const preferred =
|
||||||
|
(piDefault
|
||||||
|
? availableModels.find((m) => m.provider === piDefault.provider && m.id === piDefault.model)
|
||||||
|
: undefined) ||
|
||||||
|
availableModels.find((m) => m.provider === 'openai' && m.id === 'gpt-5.4') ||
|
||||||
|
availableModels.find((m) => m.provider === 'openai') ||
|
||||||
|
availableModels.find((m) => m.provider === 'anthropic' && m.id === 'claude-opus-4-6') ||
|
||||||
|
availableModels.find((m) => m.provider === 'anthropic' && m.id.includes('opus')) ||
|
||||||
|
availableModels.find((m) => m.provider === 'anthropic') ||
|
||||||
|
availableModels[0]
|
||||||
|
if (preferred) {
|
||||||
|
settingsManager.setDefaultModelAndProvider(preferred.provider, preferred.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settingsManager.getDefaultThinkingLevel() !== 'off' && !configuredExists) {
|
||||||
|
settingsManager.setDefaultThinkingLevel('off')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const cliFlags = parseCliArgs(process.argv)
|
const cliFlags = parseCliArgs(process.argv)
|
||||||
const isPrintMode = cliFlags.print || cliFlags.mode !== undefined
|
const isPrintMode = cliFlags.print || cliFlags.mode !== undefined
|
||||||
|
|
||||||
|
|
@ -382,8 +424,23 @@ if (!isPrintMode && process.stdout.columns && process.stdout.columns < 40) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --list-models: print available models and exit (no TTY needed)
|
// --list-models: load extensions so that extension-registered providers (e.g.
|
||||||
|
// pi-claude-cli) appear in the listing, then flush their pending registrations
|
||||||
|
// into the model registry before printing.
|
||||||
if (cliFlags.listModels !== undefined) {
|
if (cliFlags.listModels !== undefined) {
|
||||||
|
exitIfManagedResourcesAreNewer(agentDir)
|
||||||
|
initResources(agentDir)
|
||||||
|
const listModelsLoader = new DefaultResourceLoader({
|
||||||
|
agentDir,
|
||||||
|
additionalExtensionPaths: cliFlags.extensions.length > 0 ? cliFlags.extensions : undefined,
|
||||||
|
})
|
||||||
|
await listModelsLoader.reload()
|
||||||
|
const listModelsExtensions = listModelsLoader.getExtensions()
|
||||||
|
for (const { name, config } of listModelsExtensions.runtime.pendingProviderRegistrations) {
|
||||||
|
modelRegistry.registerProvider(name, config)
|
||||||
|
}
|
||||||
|
listModelsExtensions.runtime.pendingProviderRegistrations = []
|
||||||
|
|
||||||
const models = modelRegistry.getAvailable()
|
const models = modelRegistry.getAvailable()
|
||||||
if (models.length === 0) {
|
if (models.length === 0) {
|
||||||
console.log('No models available. Set API keys in environment variables.')
|
console.log('No models available. Set API keys in environment variables.')
|
||||||
|
|
@ -532,6 +589,11 @@ if (isPrintMode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate configured model now that extension providers are registered.
|
||||||
|
// Must run after createAgentSession() which flushes pendingProviderRegistrations
|
||||||
|
// so extension models (e.g. pi-claude-cli) are visible in the registry.
|
||||||
|
validateConfiguredModel(modelRegistry, settingsManager)
|
||||||
|
|
||||||
// Apply --model override if specified
|
// Apply --model override if specified
|
||||||
if (cliFlags.model) {
|
if (cliFlags.model) {
|
||||||
const available = modelRegistry.getAvailable()
|
const available = modelRegistry.getAvailable()
|
||||||
|
|
@ -738,6 +800,11 @@ if (extensionsResult.errors.length > 0) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate configured model now that extension providers are registered.
|
||||||
|
// Must run after createAgentSession() which flushes pendingProviderRegistrations
|
||||||
|
// so extension models (e.g. pi-claude-cli) are visible in the registry.
|
||||||
|
validateConfiguredModel(modelRegistry, settingsManager)
|
||||||
|
|
||||||
// Restore scoped models from settings on startup.
|
// Restore scoped models from settings on startup.
|
||||||
// The upstream InteractiveMode reads enabledModels from settings when /scoped-models is opened,
|
// The upstream InteractiveMode reads enabledModels from settings when /scoped-models is opened,
|
||||||
// but doesn't apply them to the session at startup — so Ctrl+P cycles all models instead of
|
// but doesn't apply them to the session at startup — so Ctrl+P cycles all models instead of
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue