fix: address Codex guard review findings

This commit is contained in:
Peter Steinberger
2026-05-17 11:01:50 +01:00
parent a6908fac16
commit 403fbd7296
4 changed files with 95 additions and 2 deletions

View File

@@ -266,6 +266,55 @@ describe("createCodexDynamicToolBridge", () => {
expect(text).toContain("rerun with narrower args");
});
it("honors normalized per-agent dynamic tool result caps", async () => {
const bridge = createCodexDynamicToolBridge({
tools: [
createTool({
name: "large_lookup",
execute: vi.fn(async () => textToolResult("x".repeat(400))),
}),
],
signal: new AbortController().signal,
hookContext: {
agentId: "research-bot",
config: {
agents: {
defaults: {
contextLimits: {
toolResultMaxChars: 1_000,
},
},
list: [
{
id: "Research Bot",
contextLimits: {
toolResultMaxChars: 180,
},
},
],
},
} as never,
},
});
const result = await bridge.handleToolCall({
threadId: "thread-1",
turnId: "turn-1",
callId: "call-1",
namespace: null,
tool: "large_lookup",
arguments: {},
});
expect(result.success).toBe(true);
const firstItem = result.contentItems[0];
if (firstItem?.type !== "inputText" || typeof firstItem.text !== "string") {
throw new Error("expected inputText tool result");
}
expect(firstItem.text.length).toBeLessThanOrEqual(180);
expect(firstItem.text).toContain("OpenClaw truncated dynamic tool result");
});
it("keeps truncation notices within tiny configured caps", async () => {
const bridge = createCodexDynamicToolBridge({
tools: [

View File

@@ -18,6 +18,7 @@ import {
type MessagingToolSourceReplyPayload,
wrapToolWithBeforeToolCallHook,
} from "openclaw/plugin-sdk/agent-harness-runtime";
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
import type { CodexDynamicToolsLoading } from "./config.js";
import { invalidInlineImageText, sanitizeInlineImageDataUrl } from "./image-payload-sanitizer.js";
import {
@@ -253,7 +254,11 @@ function resolveAgentContextLimitValue(params: {
if (!Array.isArray(list)) {
return defaultValue;
}
const agent = list.find((entry) => readRecord(entry)?.id === params.agentId);
const normalizedAgentId = normalizeAgentId(params.agentId);
const agent = list.find((entry) => {
const entryId = readRecord(entry)?.id;
return typeof entryId === "string" && normalizeAgentId(entryId) === normalizedAgentId;
});
const agentValue = readPositiveInteger(
readRecord(readRecord(agent)?.contextLimits)?.[params.key],
);

View File

@@ -6452,6 +6452,45 @@ describe("runCodexAppServerAttempt", () => {
expect(savedBinding).toBeUndefined();
});
it("clears native rollouts at the configured byte limit", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");
const agentDir = path.join(tempDir, "agent");
await writeExistingBinding(sessionFile, workspaceDir, { dynamicToolsFingerprint: "[]" });
await fs.writeFile(
path.join(path.dirname(sessionFile), "sessions.json"),
JSON.stringify({
"agent:main:session-1": {
sessionFile,
totalTokens: 12_000,
},
}),
);
const rolloutDir = path.join(agentDir, "codex-home", "sessions");
await fs.mkdir(rolloutDir, { recursive: true });
await fs.writeFile(path.join(rolloutDir, "rollout-thread-existing.jsonl"), "x".repeat(1_000));
const binding = await __testing.rotateOversizedCodexAppServerStartupBinding({
binding: await readCodexAppServerBinding(sessionFile),
sessionFile,
agentDir,
config: {
agents: {
defaults: {
compaction: {
truncateAfterCompaction: true,
maxActiveTranscriptBytes: 1_000,
},
},
},
} as never,
});
expect(binding).toBeUndefined();
const savedBinding = await readCodexAppServerBinding(sessionFile);
expect(savedBinding).toBeUndefined();
});
it("resumes a bound Codex thread when only dynamic tool descriptions change", async () => {
const sessionFile = path.join(tempDir, "session.jsonl");
const workspaceDir = path.join(tempDir, "workspace");

View File

@@ -679,7 +679,7 @@ async function rotateOversizedCodexAppServerStartupBinding(params: {
params.codexHome,
);
if (maxBytes !== undefined) {
const oversizedFiles = rolloutFiles.filter((file) => file.bytes > maxBytes);
const oversizedFiles = rolloutFiles.filter((file) => file.bytes >= maxBytes);
if (oversizedFiles.length > 0) {
embeddedAgentLog.warn(
"codex app-server native transcript exceeded active byte limit; starting a fresh thread",