fix: respect agent model selection in heartbeat and manual runs
Heartbeat read non-existent split modelProvider/modelId fields while the dashboard saves runtimeConfig.model as combined "provider/modelId", so sessions fell through to pi's default model and failed with "No API key for provider: openai-codex". Add extractRuntimeModel helper that prefers the combined string and use it from heartbeat. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1344,7 +1344,7 @@ export class HeartbeatMonitor {
|
||||
},
|
||||
};
|
||||
|
||||
const { createResolvedAgentSession, extractRuntimeHint } = await import("./agent-session-helpers.js");
|
||||
const { createResolvedAgentSession, extractRuntimeHint, extractRuntimeModel } = await import("./agent-session-helpers.js");
|
||||
const { buildSessionSkillContextSync } = await import("./session-skill-context.js");
|
||||
|
||||
// Build tools with task creation tracking and run context for mutation correlation
|
||||
@@ -1449,8 +1449,10 @@ export class HeartbeatMonitor {
|
||||
systemPrompt,
|
||||
tools: "readonly",
|
||||
customTools: heartbeatTools,
|
||||
defaultProvider: agent.runtimeConfig?.modelProvider as string | undefined,
|
||||
defaultModelId: agent.runtimeConfig?.modelId as string | undefined,
|
||||
...(() => {
|
||||
const { provider, modelId } = extractRuntimeModel(agent.runtimeConfig);
|
||||
return { defaultProvider: provider, defaultModelId: modelId };
|
||||
})(),
|
||||
onText: (delta) => {
|
||||
outputLength += delta.length;
|
||||
appendStdoutExcerpt(delta);
|
||||
|
||||
@@ -70,6 +70,37 @@ export function extractRuntimeHint(
|
||||
return normalizedHint.length > 0 ? normalizedHint : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the model provider and id from an agent's runtimeConfig.
|
||||
*
|
||||
* The dashboard's NewAgentDialog stores the agent's selected model as a
|
||||
* single combined string `runtimeConfig.model = "provider/modelId"` (see
|
||||
* register-chat-routes.ts which parses the same shape). Older code paths
|
||||
* also looked at separate `modelProvider` / `modelId` fields. This helper
|
||||
* accepts either shape, preferring the combined `model` string.
|
||||
*/
|
||||
export function extractRuntimeModel(
|
||||
runtimeConfig: Record<string, unknown> | undefined,
|
||||
): { provider: string | undefined; modelId: string | undefined } {
|
||||
const combined = typeof runtimeConfig?.model === "string" ? runtimeConfig.model.trim() : "";
|
||||
if (combined) {
|
||||
const slashIdx = combined.indexOf("/");
|
||||
if (slashIdx > 0 && slashIdx < combined.length - 1) {
|
||||
return {
|
||||
provider: combined.slice(0, slashIdx).trim() || undefined,
|
||||
modelId: combined.slice(slashIdx + 1).trim() || undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const provider = typeof runtimeConfig?.modelProvider === "string" ? runtimeConfig.modelProvider.trim() : "";
|
||||
const modelId = typeof runtimeConfig?.modelId === "string" ? runtimeConfig.modelId.trim() : "";
|
||||
return {
|
||||
provider: provider || undefined,
|
||||
modelId: modelId || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an agent session using runtime resolution.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user