fix(codex): preserve current turn context

This commit is contained in:
Ayaan Zaidi
2026-05-10 22:28:24 +05:30
parent 7b218375f7
commit c529ab29c2
3 changed files with 50 additions and 5 deletions

View File

@@ -35,6 +35,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Agents/image: honor explicit `image` tool model overrides even when `agents.defaults.imageModel` is unset, restoring one-off vision calls for configured multimodal providers. Fixes #79341. Thanks @haumanto.
- Codex app-server: preserve prompt-local current-turn context through context-engine prompt projection, so replied-to Telegram messages stay visible to the Codex model input.
- Telegram: pass agent-scoped media roots through gateway message actions so workspace-local media from the active agent is not rejected as cross-agent access. Thanks @frankekn.
- CLI/gateway: keep `gateway status --deep` plugin-aware so configured plugin manifest warnings, including missing channel config metadata, stay visible during install and update smoke checks.
- Feishu: fall back to a top-level group send when normal group quoted replies target a withdrawn or missing message, preventing replies from disappearing silently while preserving native topic safety. Fixes #79349. Thanks @arlen8411.

View File

@@ -237,14 +237,18 @@ function expectRequestInputTextContains(
harness: ReturnType<typeof createStartedThreadHarness>,
expected: string,
): void {
expect(getRequestInputText(harness)).toContain(expected);
}
function getRequestInputText(harness: ReturnType<typeof createStartedThreadHarness>): string {
const params = requireRequestParams(harness, "turn/start");
const input = requireArray(params.input, "turn/start input");
expect(
input.some((entry) => {
return input
.map((entry) => {
const item = requireRecord(entry, "turn/start input entry");
return item.type === "text" && optionalString(item.text).includes(expected);
}),
).toBe(true);
return item.type === "text" ? optionalString(item.text) : "";
})
.join("\n");
}
describe("runCodexAppServerAttempt context-engine lifecycle", () => {
@@ -310,6 +314,37 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
expect(openSpy).not.toHaveBeenCalled();
});
it("keeps current-turn context at the front of the Codex context-engine prompt", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
SessionManager.open(sessionFile).appendMessage(
assistantMessage("older context", Date.now()) as never,
);
const contextEngine = createContextEngine();
const harness = createStartedThreadHarness();
const params = createParams(sessionFile, workspaceDir);
params.contextEngine = contextEngine;
params.currentTurnContext = {
text: [
"Conversation context (untrusted, chronological, selected for current message):",
"#6474 Sun 2026-05-10 22:22 GMT+5:30 [reply target] OpenClaw: anchor REPLYCTX this is the old message",
"#6498 Sun 2026-05-10 22:22 GMT+5:30 OpenClaw: filler REPLYCTX 23",
].join("\n"),
};
const run = runCodexAppServerAttempt(params);
await harness.waitForMethod("turn/start");
const inputText = getRequestInputText(harness);
expect(inputText).toContain("OpenClaw assembled context for this turn:");
expect(inputText).toContain("Current user request:\nhello");
expect(inputText).toContain("[reply target] OpenClaw: anchor REPLYCTX");
expect(inputText.trim().startsWith("Conversation context (untrusted")).toBe(true);
await harness.completeTurn();
await run;
});
it("calls afterTurn with the mirrored transcript and runs turn maintenance", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");

View File

@@ -640,6 +640,7 @@ export async function runCodexAppServerAttempt(
promptText = projection.promptText;
prePromptMessageCount = projection.prePromptMessageCount;
}
promptText = prependCurrentTurnContext(promptText, params.currentTurnContext);
const promptBuild = await resolveAgentHarnessBeforePromptBuildResult({
prompt: promptText,
developerInstructions,
@@ -2492,6 +2493,14 @@ function joinPresentSections(...sections: Array<string | undefined>): string {
return sections.filter((section): section is string => Boolean(section?.trim())).join("\n\n");
}
function prependCurrentTurnContext(
prompt: string,
context: EmbeddedRunAttemptParams["currentTurnContext"],
): string {
const text = context?.text.trim();
return text ? [text, prompt].filter(Boolean).join("\n\n") : prompt;
}
function handleApprovalRequest(params: {
method: string;
params: JsonValue | undefined;