mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 03:01:56 +00:00
Fix model selector not showing models with settings.json API keys
Fixes #295
This commit is contained in:
parent
a96b9201f9
commit
ac5f4a77cc
8 changed files with 357 additions and 249 deletions
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import type { Api, Model } from "@mariozechner/pi-ai";
|
||||
import { getAvailableModels } from "../core/model-config.js";
|
||||
import type { SettingsManager } from "../core/settings-manager.js";
|
||||
import { fuzzyFilter } from "../utils/fuzzy.js";
|
||||
|
||||
/**
|
||||
|
|
@ -24,8 +25,11 @@ function formatTokenCount(count: number): string {
|
|||
/**
|
||||
* List available models, optionally filtered by search pattern
|
||||
*/
|
||||
export async function listModels(searchPattern?: string): Promise<void> {
|
||||
const { models, error } = await getAvailableModels();
|
||||
export async function listModels(searchPattern?: string, settingsManager?: SettingsManager): Promise<void> {
|
||||
const { models, error } = await getAvailableModels(
|
||||
undefined,
|
||||
settingsManager ? (provider) => settingsManager.getApiKey(provider) : undefined,
|
||||
);
|
||||
|
||||
if (error) {
|
||||
console.error(error);
|
||||
|
|
|
|||
|
|
@ -616,7 +616,9 @@ export class AgentSession {
|
|||
}
|
||||
|
||||
private async _cycleAvailableModel(): Promise<ModelCycleResult | null> {
|
||||
const { models: availableModels, error } = await getAvailableModels();
|
||||
const { models: availableModels, error } = await getAvailableModels(undefined, (provider) =>
|
||||
this.settingsManager.getApiKey(provider),
|
||||
);
|
||||
if (error) throw new Error(`Failed to load models: ${error}`);
|
||||
if (availableModels.length <= 1) return null;
|
||||
|
||||
|
|
@ -648,7 +650,9 @@ export class AgentSession {
|
|||
* Get all available models with valid API keys.
|
||||
*/
|
||||
async getAvailableModels(): Promise<Model<any>[]> {
|
||||
const { models, error } = await getAvailableModels();
|
||||
const { models, error } = await getAvailableModels(undefined, (provider) =>
|
||||
this.settingsManager.getApiKey(provider),
|
||||
);
|
||||
if (error) throw new Error(error);
|
||||
return models;
|
||||
}
|
||||
|
|
@ -1330,7 +1334,9 @@ export class AgentSession {
|
|||
|
||||
// Restore model if saved
|
||||
if (sessionContext.model) {
|
||||
const availableModels = (await getAvailableModels()).models;
|
||||
const availableModels = (
|
||||
await getAvailableModels(undefined, (provider) => this.settingsManager.getApiKey(provider))
|
||||
).models;
|
||||
const match = availableModels.find(
|
||||
(m) => m.provider === sessionContext.model!.provider && m.id === sessionContext.model!.modelId,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -358,9 +358,14 @@ export async function getApiKeyForModel(model: Model<Api>): Promise<string | und
|
|||
/**
|
||||
* Get only models that have valid API keys available
|
||||
* Returns { models, error } - either models array or error message
|
||||
*
|
||||
* @param agentDir - Agent config directory
|
||||
* @param fallbackKeyResolver - Optional function to check for API keys not found by getApiKeyForModel
|
||||
* (e.g., keys from settings.json)
|
||||
*/
|
||||
export async function getAvailableModels(
|
||||
agentDir: string = getAgentDir(),
|
||||
fallbackKeyResolver?: (provider: string) => string | undefined,
|
||||
): Promise<{ models: Model<Api>[]; error: string | null }> {
|
||||
const { models: allModels, error } = loadAndMergeModels(agentDir);
|
||||
|
||||
|
|
@ -370,7 +375,11 @@ export async function getAvailableModels(
|
|||
|
||||
const availableModels: Model<Api>[] = [];
|
||||
for (const model of allModels) {
|
||||
const apiKey = await getApiKeyForModel(model);
|
||||
let apiKey = await getApiKeyForModel(model);
|
||||
// Check fallback resolver if primary lookup failed
|
||||
if (!apiKey && fallbackKeyResolver) {
|
||||
apiKey = fallbackKeyResolver(model.provider);
|
||||
}
|
||||
if (apiKey) {
|
||||
availableModels.push(model);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,9 +167,15 @@ export function parseModelPattern(pattern: string, availableModels: Model<Api>[]
|
|||
* Supports models with colons in their IDs (e.g., OpenRouter's model:exacto).
|
||||
* The algorithm tries to match the full pattern first, then progressively
|
||||
* strips colon-suffixes to find a match.
|
||||
*
|
||||
* @param patterns - Model patterns to resolve
|
||||
* @param settingsManager - Optional settings manager for API key fallback from settings.json
|
||||
*/
|
||||
export async function resolveModelScope(patterns: string[]): Promise<ScopedModel[]> {
|
||||
const { models: availableModels, error } = await getAvailableModels();
|
||||
export async function resolveModelScope(patterns: string[], settingsManager?: SettingsManager): Promise<ScopedModel[]> {
|
||||
const { models: availableModels, error } = await getAvailableModels(
|
||||
undefined,
|
||||
settingsManager ? (provider) => settingsManager.getApiKey(provider) : undefined,
|
||||
);
|
||||
|
||||
if (error) {
|
||||
console.warn(chalk.yellow(`Warning: Error loading models: ${error}`));
|
||||
|
|
@ -269,7 +275,9 @@ export async function findInitialModel(options: {
|
|||
}
|
||||
|
||||
// 4. Try first available model with valid API key
|
||||
const { models: availableModels, error } = await getAvailableModels();
|
||||
const { models: availableModels, error } = await getAvailableModels(undefined, (provider) =>
|
||||
settingsManager.getApiKey(provider),
|
||||
);
|
||||
|
||||
if (error) {
|
||||
console.error(chalk.red(error));
|
||||
|
|
@ -302,6 +310,7 @@ export async function restoreModelFromSession(
|
|||
savedModelId: string,
|
||||
currentModel: Model<Api> | null,
|
||||
shouldPrintMessages: boolean,
|
||||
settingsManager?: SettingsManager,
|
||||
): Promise<{ model: Model<Api> | null; fallbackMessage: string | null }> {
|
||||
const { model: restoredModel, error } = findModel(savedProvider, savedModelId);
|
||||
|
||||
|
|
@ -339,7 +348,10 @@ export async function restoreModelFromSession(
|
|||
}
|
||||
|
||||
// Try to find any available model
|
||||
const { models: availableModels, error: availableError } = await getAvailableModels();
|
||||
const { models: availableModels, error: availableError } = await getAvailableModels(
|
||||
undefined,
|
||||
settingsManager ? (provider) => settingsManager.getApiKey(provider) : undefined,
|
||||
);
|
||||
if (availableError) {
|
||||
console.error(chalk.red(availableError));
|
||||
process.exit(1);
|
||||
|
|
|
|||
|
|
@ -270,7 +270,8 @@ export async function main(args: string[]) {
|
|||
|
||||
if (parsed.listModels !== undefined) {
|
||||
const searchPattern = typeof parsed.listModels === "string" ? parsed.listModels : undefined;
|
||||
await listModels(searchPattern);
|
||||
const settingsManager = SettingsManager.create(process.cwd());
|
||||
await listModels(searchPattern, settingsManager);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -305,7 +306,7 @@ export async function main(args: string[]) {
|
|||
|
||||
let scopedModels: ScopedModel[] = [];
|
||||
if (parsed.models && parsed.models.length > 0) {
|
||||
scopedModels = await resolveModelScope(parsed.models);
|
||||
scopedModels = await resolveModelScope(parsed.models, settingsManager);
|
||||
time("resolveModelScope");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,10 @@ export class ModelSelectorComponent extends Container {
|
|||
}));
|
||||
} else {
|
||||
// Load available models fresh (includes custom models from models.json)
|
||||
const { models: availableModels, error } = await getAvailableModels();
|
||||
// Pass settings manager's key resolver as fallback for settings.json apiKeys
|
||||
const { models: availableModels, error } = await getAvailableModels(undefined, (provider) =>
|
||||
this.settingsManager.getApiKey(provider),
|
||||
);
|
||||
|
||||
// If there's an error loading models.json, we'll show it via the "no models" path
|
||||
// The error will be displayed to the user
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue