extract resolveModel() to run before agent selection

model resolution was duplicated inside each agent (opentoad, claude) and
PULLFROG_MODEL override was not considered when choosing the agent. now
resolveModel() runs first in main.ts, its result feeds into resolveAgent()
for agent selection, and the resolved model is passed to the agent via
ctx.resolvedModel. agents only handle their own fallback (opentoad: auto-select
via opencode models, claude: strip provider prefix).

also removes the hardcoded anthropic/claude-sonnet test runner default since
ANTHROPIC_API_KEY is no longer in CI.

Made-with: Cursor
This commit is contained in:
Colin McDonnell
2026-04-01 06:51:18 +00:00
committed by pullfrog[bot]
parent 1f1e3995f9
commit b1f9878877
8 changed files with 83 additions and 127 deletions
+29 -45
View File
@@ -149422,24 +149422,9 @@ function writeMcpConfig(ctx) {
);
return configPath;
}
function resolveClaudeModel(modelSlug) {
const envModel = process.env.PULLFROG_MODEL?.trim();
if (envModel) {
const slashIndex = envModel.indexOf("/");
const cliModel = slashIndex > 0 ? envModel.slice(slashIndex + 1) : envModel;
log.info(`\xBB model: ${cliModel} (override via PULLFROG_MODEL)`);
return cliModel;
}
if (!modelSlug) return void 0;
const resolved = resolveModelSlug(modelSlug);
if (resolved) {
const slashIndex = resolved.indexOf("/");
const cliModel = slashIndex > 0 ? resolved.slice(slashIndex + 1) : resolved;
log.info(`\xBB model: ${cliModel} (resolved from ${modelSlug})`);
return cliModel;
}
log.warning(`\xBB unknown model slug "${modelSlug}" \u2014 letting Claude Code auto-select`);
return void 0;
function stripProviderPrefix(specifier) {
const slashIndex = specifier.indexOf("/");
return slashIndex > 0 ? specifier.slice(slashIndex + 1) : specifier;
}
async function runClaude(params) {
const startTime = performance6.now();
@@ -149687,7 +149672,8 @@ var claude = agent({
install: installClaudeCli,
run: async (ctx) => {
const cliPath = await installClaudeCli();
const model = ctx.payload.proxyModel ?? resolveClaudeModel(ctx.payload.model);
const specifier = ctx.payload.proxyModel ?? ctx.resolvedModel;
const model = specifier ? stripProviderPrefix(specifier) : void 0;
const homeEnv = {
HOME: ctx.tmpdir,
XDG_CONFIG_HOME: join10(ctx.tmpdir, ".config")
@@ -149788,25 +149774,8 @@ function getOpenCodeModels(cliPath) {
}
}
var AUTO_SELECT_WARNING = "select a model explicitly in the Pullfrog console (https://pullfrog.com/console) to avoid this.";
function resolveOpenCodeModel(ctx) {
const envModel = process.env.PULLFROG_MODEL?.trim();
if (envModel) {
log.info(`\xBB model: ${envModel} (override via PULLFROG_MODEL)`);
return envModel;
}
if (ctx.modelSlug) {
const resolved = resolveCliModel(ctx.modelSlug);
if (resolved) {
if (resolved !== ctx.modelSlug) {
log.info(`\xBB model: ${ctx.modelSlug} (resolved to ${resolved})`);
} else {
log.info(`\xBB model: ${resolved}`);
}
return resolved;
}
log.warning(`\xBB unknown model slug "${ctx.modelSlug}" \u2014 falling through to auto-select`);
}
const availableModels = getOpenCodeModels(ctx.cliPath);
function autoSelectModel(cliPath) {
const availableModels = getOpenCodeModels(cliPath);
const availableSet = new Set(availableModels);
if (availableSet.size > 0) {
log.debug(`\xBB opencode models (${availableSet.size}): ${availableModels.join(", ")}`);
@@ -150122,10 +150091,7 @@ var opentoad = agent({
install: installOpencodeCli,
run: async (ctx) => {
const cliPath = await installOpencodeCli();
const model = ctx.payload.proxyModel ?? resolveOpenCodeModel({
cliPath,
modelSlug: ctx.payload.model
});
const model = ctx.payload.proxyModel ?? ctx.resolvedModel ?? autoSelectModel(cliPath);
const homeEnv = {
HOME: ctx.tmpdir,
XDG_CONFIG_HOME: join11(ctx.tmpdir, ".config")
@@ -150170,6 +150136,22 @@ function hasEnvVar(name) {
function hasClaudeCodeAuth() {
return hasEnvVar("CLAUDE_CODE_OAUTH_TOKEN") || hasEnvVar("ANTHROPIC_API_KEY");
}
function resolveModel(ctx) {
const envModel = process.env.PULLFROG_MODEL?.trim();
if (envModel) {
log.info(`\xBB model: ${envModel} (override via PULLFROG_MODEL)`);
return envModel;
}
if (ctx.slug) {
const resolved = resolveCliModel(ctx.slug);
if (resolved) {
log.info(`\xBB model: ${resolved} (resolved from ${ctx.slug})`);
return resolved;
}
log.warning(`\xBB unknown model slug "${ctx.slug}" \u2014 agent will auto-select`);
}
return void 0;
}
function resolveAgent(ctx) {
const envAgent = process.env.PULLFROG_AGENT?.trim();
if (envAgent) {
@@ -150179,7 +150161,7 @@ function resolveAgent(ctx) {
}
log.warning(`\xBB unknown PULLFROG_AGENT="${envAgent}" \u2014 falling through to auto-select`);
}
if (ctx?.model) {
if (ctx.model) {
try {
const provider2 = getModelProvider(ctx.model);
if (provider2 === "anthropic" && hasClaudeCodeAuth()) {
@@ -151497,10 +151479,11 @@ async function main() {
const tmpdir2 = createTempDirectory();
const gitAuthServer = __using(_stack, await startGitAuthServer(tmpdir2), true);
setGitAuthServer(gitAuthServer);
const agent2 = resolveAgent({ model: payload.proxyModel ? void 0 : payload.model });
const resolvedModel = payload.proxyModel ? void 0 : resolveModel({ slug: payload.model });
const agent2 = resolveAgent({ model: resolvedModel });
validateAgentApiKey({
agent: agent2,
model: payload.proxyModel ?? payload.model,
model: payload.proxyModel ?? resolvedModel ?? payload.model,
owner: runContext.repo.owner,
name: runContext.repo.name
});
@@ -151577,6 +151560,7 @@ ${instructions.user}` : null,
toolState.todoTracker = todoTracker;
const agentPromise = agent2.run({
payload,
resolvedModel,
mcpServerUrl: mcpHttpServer.url,
tmpdir: tmpdir2,
instructions,