When resolving models from custom provider configurations, ensure the provider name is attached to each inline model entry. This fixes model resolution for custom providers where the model definition exists in the config but lacks an explicit provider field. Without this fix, inline models from custom providers (like amazon-bedrock) would fail to resolve because the provider context was lost during the flatMap operation.
77 lines
2.9 KiB
TypeScript
77 lines
2.9 KiB
TypeScript
import type { Api, Model } from "@mariozechner/pi-ai";
|
|
import { discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-agent";
|
|
|
|
import type { ClawdbotConfig } from "../../config/config.js";
|
|
import { resolveClawdbotAgentDir } from "../agent-paths.js";
|
|
import { DEFAULT_CONTEXT_TOKENS } from "../defaults.js";
|
|
import { normalizeModelCompat } from "../model-compat.js";
|
|
|
|
export function buildModelAliasLines(cfg?: ClawdbotConfig) {
|
|
const models = cfg?.agents?.defaults?.models ?? {};
|
|
const entries: Array<{ alias: string; model: string }> = [];
|
|
for (const [keyRaw, entryRaw] of Object.entries(models)) {
|
|
const model = String(keyRaw ?? "").trim();
|
|
if (!model) continue;
|
|
const alias = String((entryRaw as { alias?: string } | undefined)?.alias ?? "").trim();
|
|
if (!alias) continue;
|
|
entries.push({ alias, model });
|
|
}
|
|
return entries
|
|
.sort((a, b) => a.alias.localeCompare(b.alias))
|
|
.map((entry) => `- ${entry.alias}: ${entry.model}`);
|
|
}
|
|
|
|
export function resolveModel(
|
|
provider: string,
|
|
modelId: string,
|
|
agentDir?: string,
|
|
cfg?: ClawdbotConfig,
|
|
): {
|
|
model?: Model<Api>;
|
|
error?: string;
|
|
authStorage: ReturnType<typeof discoverAuthStorage>;
|
|
modelRegistry: ReturnType<typeof discoverModels>;
|
|
} {
|
|
const resolvedAgentDir = agentDir ?? resolveClawdbotAgentDir();
|
|
const authStorage = discoverAuthStorage(resolvedAgentDir);
|
|
const modelRegistry = discoverModels(authStorage, resolvedAgentDir);
|
|
const model = modelRegistry.find(provider, modelId) as Model<Api> | null;
|
|
if (!model) {
|
|
const providers = cfg?.models?.providers ?? {};
|
|
const inlineModels =
|
|
providers[provider]?.models?.map((entry) => ({ ...entry, provider })) ??
|
|
Object.values(providers)
|
|
.flatMap((entry) => entry?.models ?? [])
|
|
.map((entry) => ({ ...entry, provider }));
|
|
const inlineMatch = inlineModels.find((entry) => entry.id === modelId);
|
|
if (inlineMatch) {
|
|
const normalized = normalizeModelCompat(inlineMatch as Model<Api>);
|
|
return {
|
|
model: normalized,
|
|
authStorage,
|
|
modelRegistry,
|
|
};
|
|
}
|
|
const providerCfg = providers[provider];
|
|
if (providerCfg || modelId.startsWith("mock-")) {
|
|
const fallbackModel: Model<Api> = normalizeModelCompat({
|
|
id: modelId,
|
|
name: modelId,
|
|
api: providerCfg?.api ?? "openai-responses",
|
|
provider,
|
|
reasoning: false,
|
|
input: ["text"],
|
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
contextWindow: providerCfg?.models?.[0]?.contextWindow ?? DEFAULT_CONTEXT_TOKENS,
|
|
maxTokens: providerCfg?.models?.[0]?.maxTokens ?? DEFAULT_CONTEXT_TOKENS,
|
|
} as Model<Api>);
|
|
return { model: fallbackModel, authStorage, modelRegistry };
|
|
}
|
|
return {
|
|
error: `Unknown model: ${provider}/${modelId}`,
|
|
authStorage,
|
|
modelRegistry,
|
|
};
|
|
}
|
|
return { model: normalizeModelCompat(model), authStorage, modelRegistry };
|
|
}
|