Merge remote-tracking branch 'origin/farm/e42ff742/fork-prompt-cache-affinity'

This commit is contained in:
can1357
2026-07-10 12:09:25 +02:00
10 changed files with 349 additions and 4 deletions
@@ -172,7 +172,7 @@ Interactive `/fork` creates a new session from the current one and switches the
2. Flushes pending writes.
3. Calls `SessionManager.fork()`.
4. Copies artifacts directory from old session namespace to new namespace (best-effort; non-ENOENT copy failures are logged, not fatal).
5. Updates `agent.sessionId`.
5. Updates `agent.sessionId` and inherits the previous provider prompt-cache key unless an explicit prompt-cache key is already pinned.
6. Emits `session_switch` with `reason: "fork"`.
`SessionManager.fork()` behavior:
@@ -184,6 +184,7 @@ Interactive `/fork` creates a new session from the current one and switches the
- new timestamp
- `cwd` unchanged
- `parentSession` set to previous session id
- `providerPromptCacheKey` set to the previous header's inherited key, or the previous session id when none was pinned
- Keeps all non-header entries unchanged in the new file.
### Non-persistent behavior
@@ -200,6 +201,9 @@ Startup `--fork` is resolved before normal session creation:
2. Path-like values (`/`, `\`, or `.jsonl`) call `SessionManager.forkFrom(path, cwd, sessionDir)`.
3. Other values resolve via `resolveResumableSession(...)`: local sessions first, then global search when `sessionDir` is not forced. Matching accepts lowercased session id prefixes, full JSONL filename prefixes, and timestamp-stripped filename id suffixes.
4. The forked file is created in the current cwd/session-dir scope and becomes the active session manager for startup.
5. Full-context forks automatically seed `providerPromptCacheKey` from the source header's inherited key, falling back to the source session id. Startup drops that automatic inheritance when `--model`, `--thinking`, `--system-prompt`, `--append-system-prompt`, `--tools`, or `--no-tools` changes the provider route or prompt/tool shape.
Use `--prompt-cache-key <key>` to pin the provider prompt-cache identity explicitly and independently from both the OMP session id and `--provider-session-id`. `--provider-session-id` continues to control provider session/routing headers and sticky credential selection; `--prompt-cache-key` controls the OpenAI Responses `prompt_cache_key` payload where supported.
## Resume and continue
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- Fixed full-context forks cold-missing OpenAI prompt caches by persisting an inherited provider prompt-cache key separately from the new OMP session id, adding `--prompt-cache-key` for explicit cache affinity, and dropping automatic inheritance when startup changes the model, thinking level, system prompt, or tool schema. ([#5035](https://github.com/can1357/oh-my-pi/issues/5035))
## [16.3.15] - 2026-07-09
### Changed
+1
View File
@@ -42,6 +42,7 @@ export interface Args {
noSession?: boolean;
sessionDir?: string;
providerSessionId?: string;
providerPromptCacheKey?: string;
fork?: string;
/** Collab link to join at startup (set by the `join` subcommand; no CLI flag). */
join?: string;
@@ -141,6 +141,9 @@ export const STRING_SETTERS: Record<string, StringSetter> = {
"--provider-session-id": (result, value) => {
result.providerSessionId = value;
},
"--prompt-cache-key": (result, value) => {
result.providerPromptCacheKey = value;
},
"--session-dir": (result, value) => {
result.sessionDir = value;
},
+21 -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,
@@ -820,6 +821,25 @@ async function buildSessionOptions(
if (parsed.providerSessionId) {
options.providerSessionId = parsed.providerSessionId;
}
if (parsed.providerPromptCacheKey) {
options.providerPromptCacheKey = parsed.providerPromptCacheKey;
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 ||
parsed.appendSystemPrompt !== undefined ||
parsed.tools !== undefined ||
parsed.noTools === true;
if (!forkCacheShapeChanged && header?.providerPromptCacheKey) {
options.providerPromptCacheKey = header.providerPromptCacheKey;
options.providerPromptCacheKeySource = "fork";
}
}
// Model from CLI
// - supports --provider <name> --model <pattern>
+23 -1
View File
@@ -426,6 +426,8 @@ export interface CreateAgentSessionOptions {
providerSessionId?: string;
/** Optional provider-facing prompt cache key, distinct from request lineage. */
providerPromptCacheKey?: string;
/** Whether `providerPromptCacheKey` is caller-pinned or inherited from a full fork. */
providerPromptCacheKeySource?: "explicit" | "fork";
/** Absolute wall-clock deadline in Unix epoch milliseconds. */
deadline?: number;
@@ -1221,6 +1223,25 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
SessionManager.create(cwd, SessionManager.getDefaultSessionDir(cwd, agentDir)),
);
const providerSessionId = options.providerSessionId ?? sessionManager.getSessionId();
const forkCacheShapeChanged =
options.model !== undefined ||
options.modelPattern !== undefined ||
options.thinkingLevel !== undefined ||
options.systemPrompt !== undefined ||
options.customSystemPrompt !== undefined ||
options.appendSystemPrompt !== undefined ||
options.toolNames !== undefined ||
options.customTools !== undefined;
const inheritedPromptCacheKey = forkCacheShapeChanged
? undefined
: sessionManager.getHeader()?.providerPromptCacheKey;
const providerPromptCacheKey = options.providerPromptCacheKey ?? inheritedPromptCacheKey;
const providerPromptCacheKeySource =
options.providerPromptCacheKey !== undefined
? (options.providerPromptCacheKeySource ?? "explicit")
: providerPromptCacheKey !== undefined
? "fork"
: undefined;
// Startup model *selection* only needs to know whether auth is configured for
// a candidate's provider — never the resolved key bytes. Use the synchronous,
// side-effect-free probe (`hasConfiguredAuth`): it refreshes no OAuth tokens,
@@ -2704,7 +2725,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
onPayload,
onResponse,
sessionId: providerSessionId,
promptCacheKey: options.providerPromptCacheKey,
promptCacheKey: providerPromptCacheKey,
deadline: options.deadline,
transformContext,
transformProviderContext,
@@ -2888,6 +2909,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
agentId: resolvedAgentId,
agentKind,
providerSessionId: options.providerSessionId,
providerPromptCacheKeySource,
parentEvalSessionId: options.parentEvalSessionId,
advisorTools,
titleSystemPrompt: options.titleSystemPrompt,
@@ -809,6 +809,8 @@ export interface AgentSessionConfig {
* so that credential sticky selection is consistent with the session's streaming calls.
*/
providerSessionId?: string;
/** Marks `agent.promptCacheKey` as fork-inherited so incompatible route changes can clear it. */
providerPromptCacheKeySource?: "explicit" | "fork";
/**
* Full advisor toolset, pre-built in `createAgentSession` against a distinct,
* advisor-scoped `ToolSession` (its own `-advisor` session/agent id) so the
@@ -1713,6 +1715,7 @@ export class AgentSession {
#agentKind: "main" | "sub" = "main";
#providerSessionId: string | undefined;
#freshProviderSessionId: string | undefined;
#inheritedProviderPromptCacheKey: string | undefined;
#isDisposed = false;
// Extension system
#extensionRunner: ExtensionRunner | undefined = undefined;
@@ -2228,6 +2231,8 @@ export class AgentSession {
this.#agentId = config.agentId;
this.#agentKind = config.agentKind ?? "main";
this.#providerSessionId = config.providerSessionId;
this.#inheritedProviderPromptCacheKey =
config.providerPromptCacheKeySource === "fork" ? this.agent.promptCacheKey : undefined;
this.agent.setAssistantMessageEventInterceptor((message, assistantMessageEvent) => {
const event: AgentEvent = {
type: "message_update",
@@ -5594,6 +5599,23 @@ export class AgentSession {
return this.#freshProviderSessionId ?? this.#providerSessionId ?? sessionId ?? this.sessionManager.getSessionId();
}
#adoptInheritedProviderPromptCacheKey(): void {
const key = this.sessionManager.getHeader()?.providerPromptCacheKey;
if (!key) return;
if (this.#inheritedProviderPromptCacheKey !== undefined || this.agent.promptCacheKey === undefined) {
this.agent.promptCacheKey = key;
this.#inheritedProviderPromptCacheKey = key;
}
}
#clearInheritedProviderPromptCacheKey(): void {
const key = this.#inheritedProviderPromptCacheKey;
this.#inheritedProviderPromptCacheKey = undefined;
if (key !== undefined && this.agent.promptCacheKey === key) {
this.agent.promptCacheKey = undefined;
}
}
/**
* Set agent.sessionId from the session manager and install a dynamic
* metadata resolver so every Anthropic API request carries
@@ -6399,6 +6421,9 @@ export class AgentSession {
if (this.#rebuildSystemPrompt) {
const signature = this.#computeAppliedToolSignature(validToolNames, tools);
if (signature !== this.#lastAppliedToolSignature) {
if (this.#lastAppliedToolSignature !== undefined) {
this.#clearInheritedProviderPromptCacheKey();
}
const built = await this.#rebuildSystemPrompt(validToolNames, this.#toolRegistry);
this.#baseSystemPrompt = built.systemPrompt;
this.#baseSystemPromptBeforeMemoryPromotion = undefined;
@@ -6485,9 +6510,16 @@ export class AgentSession {
if (!this.#rebuildSystemPrompt) return;
const activeToolNames = this.getActiveToolNames();
this.#setActiveToolNames?.(activeToolNames);
const previousBaseSystemPrompt = this.#baseSystemPrompt;
const built = await this.#rebuildSystemPrompt(activeToolNames, this.#toolRegistry);
this.#baseSystemPrompt = built.systemPrompt;
this.#baseSystemPromptBeforeMemoryPromotion = undefined;
if (
previousBaseSystemPrompt.length !== this.#baseSystemPrompt.length ||
previousBaseSystemPrompt.some((part, index) => part !== this.#baseSystemPrompt[index])
) {
this.#clearInheritedProviderPromptCacheKey();
}
this.agent.setSystemPrompt(this.#baseSystemPrompt);
this.#promptModelKey = this.#currentPromptModelKey();
// Refresh the cached signature so a subsequent `#applyActiveToolsByName` with
@@ -8728,6 +8760,7 @@ export class AgentSession {
this.#clearCheckpointRuntimeState();
this.setTodoPhases([]);
this.#freshProviderSessionId = undefined;
this.#clearInheritedProviderPromptCacheKey();
this.#syncAgentSessionId();
this.#rekeyHindsightMemoryForCurrentSessionId();
this.#rekeyMnemopiMemoryForCurrentSessionId();
@@ -8828,6 +8861,7 @@ export class AgentSession {
// Update agent session ID
this.#freshProviderSessionId = undefined;
this.#adoptInheritedProviderPromptCacheKey();
this.#syncAgentSessionId();
this.#rekeyHindsightMemoryForCurrentSessionId();
this.#rekeyMnemopiMemoryForCurrentSessionId();
@@ -9149,6 +9183,9 @@ export class AgentSession {
this.#autoThinking = true;
this.#autoResolvedLevel = undefined;
this.#thinkingLevel = provisional;
if (!wasAuto) {
this.#clearInheritedProviderPromptCacheKey();
}
this.#applyThinkingLevelToAgent(provisional);
if (persist) {
this.settings.set("defaultThinkingLevel", AUTO_THINKING);
@@ -9172,6 +9209,7 @@ export class AgentSession {
this.#applyThinkingLevelToAgent(effectiveLevel);
if (isChanging) {
this.#clearInheritedProviderPromptCacheKey();
this.sessionManager.appendThinkingLevelChange(effectiveLevel, effectiveLevel);
if (persist && effectiveLevel !== undefined && effectiveLevel !== ThinkingLevel.Off) {
this.settings.set("defaultThinkingLevel", effectiveLevel);
@@ -11580,6 +11618,9 @@ export class AgentSession {
const currentModel = this.model;
if (currentModel) {
this.#closeProviderSessionsForModelSwitch(currentModel, model);
if (!modelsAreEqual(currentModel, model)) {
this.#clearInheritedProviderPromptCacheKey();
}
}
this.agent.setModel(model);
@@ -14745,6 +14786,7 @@ export class AgentSession {
const previousSystemPrompt = this.agent.state.systemPrompt;
const previousBaseSystemPromptBeforeMemoryPromotion = this.#baseSystemPromptBeforeMemoryPromotion;
const previousFreshProviderSessionId = this.#freshProviderSessionId;
const previousInheritedProviderPromptCacheKey = this.#inheritedProviderPromptCacheKey;
const previousFallbackSelectedMCPToolNames = previousSessionFile
? this.#getSessionDefaultSelectedMCPToolNames(previousSessionFile)
: undefined;
@@ -14766,6 +14808,8 @@ export class AgentSession {
await this.sessionManager.setSessionFile(sessionPath);
if (switchingToDifferentSession) {
this.#freshProviderSessionId = undefined;
this.#clearInheritedProviderPromptCacheKey();
this.#adoptInheritedProviderPromptCacheKey();
}
this.#syncAgentSessionId();
this.#rekeyHindsightMemoryForCurrentSessionId();
@@ -14919,6 +14963,7 @@ export class AgentSession {
this.agent.replaceQueues(previousSteeringMessages, previousFollowUpMessages);
this.#pendingNextTurnMessages = previousPendingNextTurnMessages;
this.#scheduledHiddenNextTurnGeneration = previousScheduledHiddenNextTurnGeneration;
this.#inheritedProviderPromptCacheKey = previousInheritedProviderPromptCacheKey;
this.#checkpointState = previousCheckpointState;
this.#pendingRewindReport = previousPendingRewindReport;
this.#lastCompletedRewind = previousLastCompletedRewind;
@@ -14994,6 +15039,7 @@ export class AgentSession {
this.#rehydrateCheckpointRewindState();
this.#syncTodoPhasesFromBranch();
this.#freshProviderSessionId = undefined;
this.#clearInheritedProviderPromptCacheKey();
this.#syncAgentSessionId();
this.#rekeyHindsightMemoryForCurrentSessionId();
this.#rekeyMnemopiMemoryForCurrentSessionId();
@@ -32,10 +32,14 @@ export interface SessionHeader {
timestamp: string;
cwd: string;
parentSession?: string;
/** Provider prompt-cache identity inherited by exact-route full forks. */
providerPromptCacheKey?: string;
}
export interface NewSessionOptions {
parentSession?: string;
/** Provider prompt-cache identity to seed on the new session header. */
providerPromptCacheKey?: string;
/** Skip flushing the current session and delete it instead of saving. */
drop?: boolean;
}
@@ -783,6 +783,7 @@ export class SessionManager {
timestamp,
cwd: this.#cwd,
parentSession: options?.parentSession,
providerPromptCacheKey: options?.providerPromptCacheKey,
};
this.#titleUpdatedAt = timestamp;
@@ -1050,6 +1051,7 @@ export class SessionManager {
timestamp,
cwd: this.#cwd,
parentSession: parentSessionId,
providerPromptCacheKey: this.#header.providerPromptCacheKey ?? parentSessionId,
};
this.#sessionName = this.#header.title;
this.#titleSource = this.#header.titleSource;
@@ -1888,7 +1890,13 @@ export class SessionManager {
const sourceHeader = sourceEntries.find(entry => entry.type === "session") as SessionHeader | undefined;
const history = sourceEntries.filter(entry => entry.type !== "session") as SessionEntry[];
manager.#resetToNewSession({ parentSession: sourceHeader?.id }, options?.sessionFile);
manager.#resetToNewSession(
{
parentSession: sourceHeader?.id,
providerPromptCacheKey: sourceHeader?.providerPromptCacheKey ?? sourceHeader?.id,
},
options?.sessionFile,
);
manager.#header.title = sourceHeader?.title;
manager.#header.titleSource = sourceHeader?.titleSource;
manager.#sessionName = manager.#header.title;
@@ -0,0 +1,233 @@
import { describe, expect, it } from "bun:test";
import * as fs from "node:fs/promises";
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";
import { CURRENT_SESSION_VERSION, type SessionHeader } from "@oh-my-pi/pi-coding-agent/session/session-entries";
import { SessionManager } from "@oh-my-pi/pi-coding-agent/session/session-manager";
import { TempDir } from "@oh-my-pi/pi-utils";
const OPENAI_TEST_MODEL = getBundledModel("openai", "gpt-4o-mini");
interface ArgsWithPromptCacheKey extends Args {
providerPromptCacheKey?: string;
}
interface SourceSessionFixture {
cwd: string;
sourceFile: string;
sourceHeader: SessionHeader;
forkSessionDir: string;
}
async function createSourceSessionFixture(tempDir: TempDir, parentId: string): Promise<SourceSessionFixture> {
const cwd = tempDir.join("project");
const sourceDir = tempDir.join("source-sessions");
const forkSessionDir = tempDir.join("forked-sessions");
await fs.mkdir(cwd, { recursive: true });
await fs.mkdir(sourceDir, { recursive: true });
await fs.mkdir(forkSessionDir, { recursive: true });
const sourceFile = path.join(sourceDir, `${parentId}.jsonl`);
const sourceHeader: SessionHeader = {
type: "session",
version: CURRENT_SESSION_VERSION,
id: parentId,
timestamp: new Date().toISOString(),
cwd,
};
await Bun.write(sourceFile, `${JSON.stringify(sourceHeader)}\n`);
return { cwd, sourceFile, sourceHeader, forkSessionDir };
}
async function createMinimalSession(
tempDir: TempDir,
options: CreateAgentSessionOptions,
): Promise<{ session: AgentSession; authStorage: AuthStorage }> {
const authStorage = await AuthStorage.create(tempDir.join("sdk-auth.db"));
authStorage.setRuntimeApiKey("openai", "test-key");
const shouldSupplyModel = options.sessionManager?.getHeader()?.parentSession === undefined;
const result = await createAgentSession({
...options,
cwd: options.cwd ?? tempDir.path(),
agentDir: tempDir.path(),
authStorage,
modelRegistry: undefined,
model: shouldSupplyModel ? (options.model ?? OPENAI_TEST_MODEL) : options.model,
settings: Settings.isolated({
"async.enabled": false,
"marketplace.autoUpdate": "off",
}),
disableExtensionDiscovery: true,
preloadedExtensions: undefined,
skills: [],
contextFiles: [],
promptTemplates: [],
slashCommands: [],
workspaceTree: {
rootPath: options.cwd ?? tempDir.path(),
rendered: "",
truncated: false,
totalLines: 0,
agentsMdFiles: [],
},
enableMCP: false,
enableLsp: false,
...(options.toolNames !== undefined ? { toolNames: options.toolNames } : {}),
});
return { session: result.session, authStorage };
}
describe("provider prompt-cache key session affinity", () => {
it("parses --prompt-cache-key without folding it into provider session id or prompt text", () => {
const parsed = parseArgs([
"--provider-session-id",
"provider-lineage",
"--prompt-cache-key",
"cache-affinity",
"hello",
]);
const promptCacheArgs: ArgsWithPromptCacheKey = parsed;
expect(parsed.providerSessionId).toBe("provider-lineage");
expect(promptCacheArgs.providerPromptCacheKey).toBe("cache-affinity");
expect(parsed.messages).toEqual(["hello"]);
expect(parsed.unrecognizedFlags).toEqual([]);
});
it("creates an agent whose prompt-cache key can differ from provider request lineage", async () => {
using tempDir = TempDir.createSync("@omp-prompt-cache-sdk-");
let session: AgentSession | undefined;
let authStorage: AuthStorage | undefined;
try {
const created = await createMinimalSession(tempDir, {
providerSessionId: "provider-lineage",
providerPromptCacheKey: "cache-affinity",
sessionManager: SessionManager.inMemory(tempDir.path()),
});
session = created.session;
authStorage = created.authStorage;
expect(session.agent.sessionId).toBe("provider-lineage");
expect(session.agent.promptCacheKey).toBe("cache-affinity");
expect(session.agent.promptCacheKey).not.toBe(session.agent.sessionId);
} finally {
await session?.dispose();
authStorage?.close();
}
});
it("initializes a full fork with child request lineage and parent prompt-cache affinity", async () => {
using tempDir = TempDir.createSync("@omp-prompt-cache-fork-");
const source = await createSourceSessionFixture(tempDir, "parent-cache-session");
const forkedManager = await SessionManager.forkFrom(source.sourceFile, source.cwd, source.forkSessionDir);
let session: AgentSession | undefined;
let authStorage: AuthStorage | undefined;
try {
const created = await createMinimalSession(tempDir, {
cwd: source.cwd,
sessionManager: forkedManager,
});
session = created.session;
authStorage = created.authStorage;
const childSessionId = forkedManager.getSessionId();
expect(forkedManager.getHeader()?.parentSession).toBe(source.sourceHeader.id);
expect(childSessionId).toBeString();
expect(childSessionId).not.toBe(source.sourceHeader.id);
expect(session.agent.sessionId).toBe(childSessionId);
expect(session.agent.promptCacheKey).toBe(source.sourceHeader.id);
expect(session.agent.promptCacheKey).not.toBe(session.agent.sessionId);
} finally {
await session?.dispose();
authStorage?.close();
}
});
it("does not auto-inherit parent prompt-cache affinity when fork startup changes request-shaping inputs", async () => {
const cases: Array<{ name: string; options: CreateAgentSessionOptions }> = [
{
name: "model",
options: { model: OPENAI_TEST_MODEL },
},
{
name: "thinking",
options: { thinkingLevel: ThinkingLevel.High },
},
{
name: "system",
options: { customSystemPrompt: "Use a different provider prompt." },
},
{
name: "tools",
options: { toolNames: ["read"] },
},
];
for (const entry of cases) {
using tempDir = TempDir.createSync(`@omp-prompt-cache-fork-${entry.name}-`);
const source = await createSourceSessionFixture(tempDir, `parent-cache-session-${entry.name}`);
const forkedManager = await SessionManager.forkFrom(source.sourceFile, source.cwd, source.forkSessionDir);
let session: AgentSession | undefined;
let authStorage: AuthStorage | undefined;
try {
const created = await createMinimalSession(tempDir, {
...entry.options,
cwd: source.cwd,
sessionManager: forkedManager,
});
session = created.session;
authStorage = created.authStorage;
expect(forkedManager.getHeader()?.parentSession).toBe(source.sourceHeader.id);
expect(session.agent.promptCacheKey, entry.name).toBeUndefined();
} finally {
await session?.dispose();
authStorage?.close();
}
}
});
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();
}
});
});