fix(codex): sanitize context-engine assemble warnings (#70809) (thanks @jalehman)

Co-authored-by: Josh Lehman <josh@martian.engineering>
This commit is contained in:
Peter Steinberger
2026-04-24 05:13:21 +01:00
parent c7ee5d8ecf
commit 1a002b021f
3 changed files with 38 additions and 1 deletions

View File

@@ -25,6 +25,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Codex harness: route native `request_user_input` prompts back to the originating chat, preserve queued follow-up answers, and honor newer app-server command approval amendment decisions.
- Codex harness/context-engine: redact context-engine assembly failures before logging, so fallback warnings do not serialize raw error objects. (#70809) Thanks @jalehman.
- Codex harness/Windows: resolve npm-installed `codex.cmd` shims through PATHEXT before starting the native app-server, so `codex/*` models work without a manual `.exe` shim. Fixes #70913.
- Slack/groups: classify MPIM group DMs as group chat context and suppress verbose tool/plan progress on Slack non-DM surfaces, so internal "Working…" traces no longer leak into rooms. Fixes #70912.
- Agents/replay: stop OpenAI/Codex transcript replay from synthesizing missing tool results while still preserving synthetic repair on Anthropic, Gemini, and Bedrock transport-owned sessions. (#61556) Thanks @VictorJeon and @vincentkoc.

View File

@@ -4,6 +4,7 @@ import path from "node:path";
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import { SessionManager } from "@mariozechner/pi-coding-agent";
import type { EmbeddedRunAttemptParams } from "openclaw/plugin-sdk/agent-harness";
import { embeddedAgentLog } from "openclaw/plugin-sdk/agent-harness-runtime";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { ContextEngine } from "../../../../src/context-engine/types.js";
import type { CodexServerNotification } from "./protocol.js";
@@ -365,6 +366,41 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
);
});
it("logs assemble failures as a formatted message instead of the raw error object", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const rawError = new Error("Authorization: Bearer sk-abcdefghijklmnopqrstuv");
const contextEngine = createContextEngine({
assemble: vi.fn(async () => {
throw rawError;
}),
bootstrap: undefined,
});
const warn = vi.spyOn(embeddedAgentLog, "warn").mockImplementation(() => undefined);
const harness = createStartedThreadHarness();
const params = createParams(sessionFile, workspaceDir);
params.contextEngine = contextEngine;
const run = runCodexAppServerAttempt(params);
await harness.waitForMethod("turn/start");
await harness.completeTurn();
await run;
expect(warn).toHaveBeenCalledWith(
"context engine assemble failed; using Codex baseline prompt",
{
error: expect.any(String),
},
);
const warning = warn.mock.calls.find(
([message]) => message === "context engine assemble failed; using Codex baseline prompt",
);
expect(warning?.[1]).not.toEqual({ error: rawError });
expect(String((warning?.[1] as { error?: unknown } | undefined)?.error)).not.toContain(
"sk-abcdefghijklmnopqrstuv",
);
});
it("falls back to ingestBatch and skips turn maintenance on prompt failure", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");

View File

@@ -217,7 +217,7 @@ export async function runCodexAppServerAttempt(
prePromptMessageCount = projection.prePromptMessageCount;
} catch (assembleErr) {
embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", {
error: assembleErr,
error: formatErrorMessage(assembleErr),
});
}
}