Keep OpenAI Codex migrations on automatic runtime routing (#79238)

* fix: keep migrated openai codex routes automatic

* scope runtime policy to providers and models

* fix runtime policy surfaces

* fix ci runtime policy checks

* fix doctor stale session runtime pins
This commit is contained in:
pashpashpash
2026-05-08 00:05:35 -07:00
committed by GitHub
parent b7aca7dc6e
commit 02fe0d8978
92 changed files with 1421 additions and 1264 deletions

View File

@@ -653,7 +653,9 @@ describe("CLI attempt execution", () => {
cfg: {
agents: {
defaults: {
agentRuntime: { id: "claude-cli" },
models: {
"anthropic/claude-opus-4-7": { agentRuntime: { id: "claude-cli" } },
},
},
},
} as OpenClawConfig,
@@ -708,7 +710,9 @@ describe("CLI attempt execution", () => {
cfg: {
agents: {
defaults: {
agentRuntime: { id: "codex-cli" },
models: {
"openai/gpt-5.4": { agentRuntime: { id: "codex-cli" } },
},
},
},
} as OpenClawConfig,
@@ -890,7 +894,7 @@ describe("embedded attempt harness pinning", () => {
await fs.rm(tmpDir, { recursive: true, force: true });
});
it("treats legacy OpenAI sessions with history as Codex-pinned", async () => {
it("does not store a session harness pin for default OpenAI Codex routing", async () => {
const sessionEntry: SessionEntry = {
sessionId: "legacy-session",
updatedAt: Date.now(),
@@ -929,12 +933,57 @@ describe("embedded attempt harness pinning", () => {
expect(runEmbeddedPiAgent).toHaveBeenCalledWith(
expect.objectContaining({
agentHarnessId: "codex",
agentHarnessId: undefined,
}),
);
});
it("pins sessions with history to the configured Codex harness instead of PI", async () => {
it("ignores stale session Codex harness pins on non-OpenAI model switches", async () => {
const sessionEntry: SessionEntry = {
sessionId: "mixed-provider-session",
updatedAt: Date.now(),
agentHarnessId: "codex",
};
runEmbeddedPiAgentMock.mockResolvedValueOnce({
meta: { durationMs: 1 },
} satisfies EmbeddedPiRunResult);
await runAgentAttempt({
providerOverride: "minimax",
originalProvider: "minimax",
modelOverride: "minimax-m2.7",
cfg: {} as OpenClawConfig,
sessionEntry,
sessionId: sessionEntry.sessionId,
sessionKey: "agent:main:main",
sessionAgentId: "main",
sessionFile: path.join(tmpDir, "session.jsonl"),
workspaceDir: tmpDir,
body: "switch to minimax",
isFallbackRetry: false,
resolvedThinkLevel: "medium",
timeoutMs: 1_000,
runId: "run-mixed-provider-auto-runtime",
opts: { senderIsOwner: false } as Parameters<typeof runAgentAttempt>[0]["opts"],
runContext: {} as Parameters<typeof runAgentAttempt>[0]["runContext"],
spawnedBy: undefined,
messageChannel: undefined,
skillsSnapshot: undefined,
resolvedVerboseLevel: undefined,
agentDir: tmpDir,
onAgentEvent: vi.fn(),
authProfileProvider: "minimax",
sessionHasHistory: true,
});
expect(runEmbeddedPiAgent).toHaveBeenCalledWith(
expect.objectContaining({
agentHarnessId: undefined,
}),
);
});
it("lets provider/model runtime policy choose Codex without storing a session harness pin", async () => {
const sessionEntry: SessionEntry = {
sessionId: "codex-history-session",
updatedAt: Date.now(),
@@ -948,9 +997,13 @@ describe("embedded attempt harness pinning", () => {
originalProvider: "codex",
modelOverride: "gpt-5.4",
cfg: {
agents: {
defaults: {
agentRuntime: { id: "codex" },
models: {
providers: {
codex: {
baseUrl: "https://api.openai.com/v1",
agentRuntime: { id: "codex" },
models: [],
},
},
},
} as OpenClawConfig,
@@ -979,7 +1032,7 @@ describe("embedded attempt harness pinning", () => {
expect(runEmbeddedPiAgent).toHaveBeenCalledWith(
expect.objectContaining({
agentHarnessId: "codex",
agentHarnessId: undefined,
}),
);
});
@@ -1038,7 +1091,7 @@ describe("embedded attempt harness pinning", () => {
expect(runEmbeddedPiAgent).toHaveBeenCalledWith(
expect.objectContaining({
agentHarnessId: "codex",
agentHarnessId: undefined,
authProfileId: "openai-codex:work",
authProfileIdSource: "auto",
}),
@@ -1084,12 +1137,12 @@ describe("embedded attempt harness pinning", () => {
expect(runEmbeddedPiAgent).toHaveBeenCalledWith(
expect.objectContaining({
agentHarnessId: "codex",
agentHarnessId: undefined,
}),
);
});
it("repairs stale OpenAI sessions pinned to PI back to the default Codex harness", async () => {
it("ignores stale OpenAI sessions pinned to PI and relies on default Codex routing", async () => {
const sessionEntry: SessionEntry = {
sessionId: "stale-pi-session",
updatedAt: Date.now(),
@@ -1130,7 +1183,7 @@ describe("embedded attempt harness pinning", () => {
expect(runEmbeddedPiAgentMock).toHaveBeenCalledWith(
expect.objectContaining({
provider: "openai",
agentHarnessId: "codex",
agentHarnessId: undefined,
}),
);
});
@@ -1151,9 +1204,13 @@ describe("embedded attempt harness pinning", () => {
originalProvider: "openai",
modelOverride: "gpt-5.4",
cfg: {
agents: {
defaults: {
agentRuntime: { id: "pi" },
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
agentRuntime: { id: "pi" },
models: [],
},
},
},
} as OpenClawConfig,
@@ -1184,7 +1241,7 @@ describe("embedded attempt harness pinning", () => {
expect.objectContaining({
provider: "openai-codex",
model: "gpt-5.4",
agentHarnessId: "pi",
agentHarnessId: undefined,
authProfileId: "openai-codex:work",
authProfileIdSource: "user",
}),

View File

@@ -21,10 +21,9 @@ import { runCliAgent } from "../cli-runner.js";
import { getCliSessionBinding, setCliSessionBinding } from "../cli-session.js";
import { FailoverError } from "../failover-error.js";
import { resolveAgentHarnessPolicy } from "../harness/selection.js";
import { isCliRuntimeAlias, resolveCliRuntimeExecutionProvider } from "../model-runtime-aliases.js";
import { resolveCliRuntimeExecutionProvider } from "../model-runtime-aliases.js";
import { isCliProvider } from "../model-selection.js";
import { isOpenAIProvider, resolveOpenAIRuntimeProviderForPi } from "../openai-codex-routing.js";
import { normalizeEmbeddedAgentRuntime } from "../pi-embedded-runner/runtime.js";
import { resolveOpenAIRuntimeProviderForPi } from "../openai-codex-routing.js";
import { runEmbeddedPiAgent, type EmbeddedPiRunResult } from "../pi-embedded.js";
import { buildAgentRuntimeAuthPlan } from "../runtime-plan/auth.js";
import {
@@ -409,28 +408,14 @@ export function runAgentAttempt(params: {
);
const bootstrapPromptWarningSignature =
bootstrapPromptWarningSignaturesSeen[bootstrapPromptWarningSignaturesSeen.length - 1];
const sessionPinnedAgentHarnessId = isRawModelRun
? "pi"
: resolveSessionPinnedAgentHarnessId({
cfg: params.cfg,
sessionAgentId: params.sessionAgentId,
sessionEntry: params.sessionEntry,
sessionHasHistory: params.sessionHasHistory,
sessionId: params.sessionId,
sessionKey: params.sessionKey ?? params.sessionId,
provider: params.providerOverride,
modelId: params.modelOverride,
});
const agentRuntimeOverride = isRawModelRun
? undefined
: params.sessionEntry?.agentRuntimeOverride?.trim();
const requestedAgentHarnessId = isRawModelRun ? "pi" : undefined;
const cliExecutionProvider = isRawModelRun
? params.providerOverride
: (resolveCliRuntimeExecutionProvider({
provider: params.providerOverride,
cfg: params.cfg,
agentId: params.sessionAgentId,
runtimeOverride: agentRuntimeOverride,
modelId: params.modelOverride,
}) ?? params.providerOverride);
const agentHarnessPolicy = isRawModelRun
? ({ runtime: "pi" } as const)
@@ -449,7 +434,7 @@ export function runAgentAttempt(params: {
authProfileProvider: params.authProfileProvider,
sessionAuthProfileId: params.sessionEntry?.authProfileOverride,
sessionAuthProfileSource: params.sessionEntry?.authProfileOverrideSource,
harnessId: sessionPinnedAgentHarnessId,
harnessId: requestedAgentHarnessId,
harnessRuntime: agentHarnessPolicy.runtime,
allowHarnessAuthProfileForwarding: !isCliProvider(cliExecutionProvider, params.cfg),
});
@@ -459,7 +444,7 @@ export function runAgentAttempt(params: {
sessionAuthProfileId: harnessAuthSelection.authProfileId,
config: params.cfg,
workspaceDir: params.workspaceDir,
harnessId: sessionPinnedAgentHarnessId,
harnessId: requestedAgentHarnessId,
harnessRuntime: agentHarnessPolicy.runtime,
allowHarnessAuthProfileForwarding: !isCliProvider(cliExecutionProvider, params.cfg),
});
@@ -467,7 +452,7 @@ export function runAgentAttempt(params: {
const embeddedPiProvider = resolveOpenAIRuntimeProviderForPi({
provider: params.providerOverride,
harnessRuntime: agentHarnessPolicy.runtime,
agentHarnessId: sessionPinnedAgentHarnessId,
agentHarnessId: requestedAgentHarnessId,
authProfileProvider: runtimeAuthPlan.authProfileProviderForAuth,
authProfileId,
config: params.cfg,
@@ -618,7 +603,7 @@ export function runAgentAttempt(params: {
sessionFile: params.sessionFile,
workspaceDir: params.workspaceDir,
config: params.cfg,
agentHarnessId: sessionPinnedAgentHarnessId,
agentHarnessId: requestedAgentHarnessId,
skillsSnapshot: params.skillsSnapshot,
prompt: effectivePrompt,
images: params.isFallbackRetry ? undefined : params.opts.images,
@@ -656,72 +641,6 @@ export function runAgentAttempt(params: {
});
}
function resolveSessionPinnedAgentHarnessId(params: {
cfg: OpenClawConfig;
sessionAgentId: string;
sessionEntry?: SessionEntry;
sessionHasHistory?: boolean;
sessionId: string;
sessionKey: string;
provider: string;
modelId?: string;
}): string | undefined {
if (params.sessionEntry?.sessionId !== params.sessionId) {
return resolveConfiguredAgentHarnessId(params);
}
if (params.sessionEntry.agentHarnessId) {
if (isOpenAIProvider(params.provider)) {
const configuredPolicy = resolveAgentHarnessPolicy({
config: params.cfg,
agentId: params.sessionAgentId,
sessionKey: params.sessionKey,
provider: params.provider,
modelId: params.modelId,
});
const configuredAgentHarnessId =
configuredPolicy.runtime === "auto" || isCliRuntimeAlias(configuredPolicy.runtime)
? undefined
: configuredPolicy.runtime;
const storedRuntime = normalizeEmbeddedAgentRuntime(params.sessionEntry.agentHarnessId);
if (configuredAgentHarnessId && configuredPolicy.runtimeSource !== "implicit") {
return configuredAgentHarnessId;
}
if (storedRuntime === "pi" && configuredAgentHarnessId) {
return configuredAgentHarnessId;
}
}
return params.sessionEntry.agentHarnessId;
}
const configuredAgentHarnessId = resolveConfiguredAgentHarnessId(params);
if (configuredAgentHarnessId) {
return configuredAgentHarnessId;
}
if (!params.sessionHasHistory) {
return undefined;
}
return "pi";
}
function resolveConfiguredAgentHarnessId(params: {
cfg: OpenClawConfig;
sessionAgentId: string;
sessionKey: string;
provider: string;
modelId?: string;
}): string | undefined {
const policy = resolveAgentHarnessPolicy({
config: params.cfg,
agentId: params.sessionAgentId,
sessionKey: params.sessionKey,
provider: params.provider,
modelId: params.modelId,
});
if (policy.runtime === "auto" || isCliRuntimeAlias(policy.runtime)) {
return undefined;
}
return policy.runtime;
}
export function buildAcpResult(params: {
payloadText: string;
startedAt: number;