mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-17 08:40:46 +00:00
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:
@@ -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",
|
||||
}),
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user