fix(coding-agent): guarded fork cache on scoped models

- Treated startup scoped model selection as a prompt-cache shape override before inheriting fork cache keys.

- Covered the --models fork path so a scoped startup model cannot reuse the parent prompt_cache_key.

Fixes #5035
This commit is contained in:
roboomp
2026-07-10 07:41:59 +00:00
parent 7fa2c3f42d
commit b2b1708d88
2 changed files with 43 additions and 1 deletions
+4 -1
View File
@@ -789,7 +789,8 @@ export function applyResolvedSystemPromptInputs(
}
}
async function buildSessionOptions(
/** Builds startup session options from parsed CLI flags, scoped models, and resolved session lineage. */
export async function buildSessionOptions(
parsed: Args,
scopedModels: ScopedModel[],
sessionManager: SessionManager | undefined,
@@ -825,7 +826,9 @@ async function buildSessionOptions(
options.providerPromptCacheKeySource = "explicit";
} else {
const header = sessionManager?.getHeader();
const scopedModelOverride = scopedModels.length > 0 && !parsed.continue && !parsed.resume;
const forkCacheShapeChanged =
scopedModelOverride ||
parsed.model !== undefined ||
parsed.thinking !== undefined ||
parsed.systemPrompt !== undefined ||
@@ -4,7 +4,10 @@ import * as path from "node:path";
import { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
import { getBundledModel } from "@oh-my-pi/pi-catalog/models";
import { type Args, parseArgs } from "@oh-my-pi/pi-coding-agent/cli/args";
import { ModelRegistry } from "@oh-my-pi/pi-coding-agent/config/model-registry";
import type { ScopedModel } from "@oh-my-pi/pi-coding-agent/config/model-resolver";
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
import { buildSessionOptions } from "@oh-my-pi/pi-coding-agent/main";
import { type CreateAgentSessionOptions, createAgentSession } from "@oh-my-pi/pi-coding-agent/sdk";
import type { AgentSession } from "@oh-my-pi/pi-coding-agent/session/agent-session";
import { AuthStorage } from "@oh-my-pi/pi-coding-agent/session/auth-storage";
@@ -191,4 +194,40 @@ describe("provider prompt-cache key session affinity", () => {
}
}
});
it("does not pre-pin parent prompt-cache affinity when a scoped model selects the startup route", async () => {
using tempDir = TempDir.createSync("@omp-prompt-cache-scoped-model-");
const source = await createSourceSessionFixture(tempDir, "parent-cache-session-scoped");
const forkedManager = await SessionManager.forkFrom(source.sourceFile, source.cwd, source.forkSessionDir);
const authStorage = await AuthStorage.create(tempDir.join("scoped-auth.db"));
authStorage.setRuntimeApiKey(OPENAI_TEST_MODEL.provider, "test-key");
try {
const modelRegistry = new ModelRegistry(authStorage, tempDir.join("models.yml"));
const parsed = parseArgs([
"--cwd",
source.cwd,
"--models",
`${OPENAI_TEST_MODEL.provider}/${OPENAI_TEST_MODEL.id}`,
]);
const scopedModels: ScopedModel[] = [
{
model: OPENAI_TEST_MODEL,
explicitThinkingLevel: false,
},
];
const options = await buildSessionOptions(
parsed,
scopedModels,
forkedManager,
modelRegistry,
Settings.isolated({ "marketplace.autoUpdate": "off" }),
);
expect(options.model).toBe(OPENAI_TEST_MODEL);
expect(options.providerPromptCacheKey).toBeUndefined();
} finally {
authStorage.close();
}
});
});