fix(cli): reject codex simple-completion probes

This commit is contained in:
Peter Steinberger
2026-05-02 21:27:44 +01:00
parent b779c45a78
commit 292bbcc292
3 changed files with 48 additions and 0 deletions

View File

@@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- CLI/infer: reject local `codex/*` one-shot model probes before simple-completion dispatch and point operators at the Codex app-server runtime path instead of ending with an empty-output error.
- Agents/sessions: preserve terminal lifecycle state when final run metadata persists from a stale in-memory snapshot, preventing `main` sessions from staying stuck as running after completed or timed-out turns.
- Gateway/CLI: make `openclaw gateway start` repair stale managed service definitions that point at old OpenClaw versions, missing binaries, or temporary installer paths before starting.
- Heartbeat/scheduler: make heartbeat phase scheduling active-hours-aware so the scheduler seeks forward to the first in-window phase slot instead of arming timers for quiet-hours slots and relying solely on the runtime guard. Non-UTC `activeHours.timezone` values (e.g. `Asia/Shanghai`) now correctly influence when the next heartbeat timer fires, avoiding wasted quiet-hours ticks and long dormant gaps after gateway restarts. Fixes #75487. Thanks @amknight.

View File

@@ -547,6 +547,48 @@ describe("capability cli", () => {
expect(mocks.runtime.writeJson).not.toHaveBeenCalled();
});
it("rejects local Codex provider probes before simple-completion dispatch", async () => {
mocks.prepareSimpleCompletionModelForAgent.mockResolvedValueOnce({
selection: {
provider: "codex",
modelId: "gpt-5.4",
agentDir: "/tmp/agent",
},
model: {
provider: "codex",
id: "gpt-5.4",
api: "openai-codex-responses",
},
auth: {
apiKey: "codex-app-server",
source: "codex-app-server",
mode: "token",
},
} as never);
await expect(
runRegisteredCli({
register: registerCapabilityCli as (program: Command) => void,
argv: [
"capability",
"model",
"run",
"--model",
"codex/gpt-5.4",
"--prompt",
"hello",
"--json",
],
}),
).rejects.toThrow("exit 1");
expect(mocks.runtime.error).toHaveBeenCalledWith(
expect.stringContaining("Codex app-server agent runtime"),
);
expect(mocks.completeWithPreparedSimpleCompletionModel).not.toHaveBeenCalled();
expect(mocks.runtime.writeJson).not.toHaveBeenCalled();
});
it.each(["", " ", "\n\t"])(
"rejects empty model run prompts before local dispatch (%j)",
async (prompt) => {

View File

@@ -654,6 +654,11 @@ async function runModelRun(params: {
if ("error" in prepared) {
throw new Error(prepared.error);
}
if (prepared.selection.provider === "codex") {
throw new Error(
'The codex provider is served by the Codex app-server agent runtime, not the local simple-completion transport. Use an openai/<model> ref with agents.defaults.agentRuntime.id: "codex", run through the gateway, or use /codex commands.',
);
}
const result = await completeWithPreparedSimpleCompletionModel({
model: prepared.model,
auth: prepared.auth,