diff --git a/CHANGELOG.md b/CHANGELOG.md index 1af27bdd6dd..36316d6c9b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/src/cli/capability-cli.test.ts b/src/cli/capability-cli.test.ts index ae6b6ad459d..6de317155fb 100644 --- a/src/cli/capability-cli.test.ts +++ b/src/cli/capability-cli.test.ts @@ -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) => { diff --git a/src/cli/capability-cli.ts b/src/cli/capability-cli.ts index bf7b12b6eaa..06bafa9742e 100644 --- a/src/cli/capability-cli.ts +++ b/src/cli/capability-cli.ts @@ -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/ 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,