Ensure disableResponseStorage flag is respected

This commit is contained in:
Kevin Alwell
2025-04-29 11:25:07 -04:00
parent 3818df7ba4
commit 6686f28338
4 changed files with 124 additions and 2 deletions

View File

@@ -168,6 +168,7 @@ const cli = meow(
disableResponseStorage: {
type: "boolean",
default: undefined,
description:
"Disable server-side response storage (sends full conversation context with every request)",
},
@@ -297,7 +298,7 @@ config = {
disableResponseStorage:
cli.flags.disableResponseStorage !== undefined
? Boolean(cli.flags.disableResponseStorage)
: config.disableResponseStorage,
: (config.disableResponseStorage ?? false),
};
// Check for updates after loading config. This is important because we write state file in

View File

@@ -365,7 +365,7 @@ export const loadConfig = (
instructions: combinedInstructions,
notify: storedConfig.notify === true,
approvalMode: storedConfig.approvalMode,
disableResponseStorage: storedConfig.disableResponseStorage ?? false,
disableResponseStorage: storedConfig.disableResponseStorage === true,
};
// -----------------------------------------------------------------------

View File

@@ -0,0 +1,79 @@
/**
* codex-cli/tests/disableResponseStorage.agentLoop.test.ts
*
* Verifies AgentLoop's request-building logic for both values of
* disableResponseStorage.
*/
import { describe, it, expect, vi } from "vitest";
import { AgentLoop } from "../src/utils/agent/agent-loop";
import type { AppConfig } from "../src/utils/config";
/* ─────────── 1. Spy + module mock ──────────────────────────────── */
const createSpy = vi.fn().mockResolvedValue({
data: { id: "resp_123", status: "completed", output: [] },
});
vi.mock("openai", () => ({
default: class {
public responses = { create: createSpy };
},
APIConnectionTimeoutError: class extends Error {},
}));
/* ─────────── 2. Parametrised tests ─────────────────────────────── */
describe.each([
{ flag: true, title: "omits previous_response_id & sets store:false" },
{ flag: false, title: "sends previous_response_id & allows store:true" },
])("AgentLoop with disableResponseStorage=%s", ({ flag, title }) => {
/* build a fresh config for each case */
const cfg: AppConfig = {
model: "o4-mini",
provider: "openai",
instructions: "",
disableResponseStorage: flag,
notify: false,
};
it(title, async () => {
/* reset spy per iteration */
createSpy.mockClear();
const loop = new AgentLoop({
model: cfg.model,
provider: cfg.provider,
config: cfg,
instructions: "",
approvalPolicy: "suggest",
disableResponseStorage: flag,
additionalWritableRoots: [],
onItem() {},
onLoading() {},
getCommandConfirmation: async () => ({ review: "approve" }),
onLastResponseId() {},
});
await loop.run([{ type: "text", content: "hello" }]);
expect(createSpy).toHaveBeenCalledTimes(1);
const payload = createSpy.mock.calls[0][0];
if (flag) {
/* behaviour when ZDR is *on* */
expect(payload).not.toHaveProperty("previous_response_id");
payload.input.forEach((m: any) =>
expect(m.store === undefined ? false : m.store).toBe(false),
);
} else {
/* behaviour when ZDR is *off* */
expect(payload).toHaveProperty("previous_response_id");
// first user message is usually non-stored; assistant messages will be stored
// so here we just assert the property is not forcibly set to false
payload.input.forEach((m: any) => {
if ("store" in m) {
expect(m.store).not.toBe(false);
}
});
}
});
});

View File

@@ -0,0 +1,42 @@
/**
* codex/codex-cli/tests/disableResponseStorage.test.ts
*/
import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { loadConfig, saveConfig } from "../src/utils/config";
const sandboxHome = mkdtempSync(join(tmpdir(), "codex-home-"));
const codexDir = join(sandboxHome, ".codex");
const yamlPath = join(codexDir, "config.yaml");
describe("disableResponseStorage persistence", () => {
beforeAll(() => {
// mkdir -p ~/.codex inside the sandbox
rmSync(codexDir, { recursive: true, force: true });
require("fs").mkdirSync(codexDir, { recursive: true });
// seed YAML with ZDR enabled
writeFileSync(yamlPath, "model: o4-mini\ndisableResponseStorage: true\n");
});
afterAll(() => {
rmSync(sandboxHome, { recursive: true, force: true });
});
it("keeps disableResponseStorage=true across load/save cycle", async () => {
// 1⃣ explicitly load the sandbox file
const cfg1 = loadConfig(yamlPath);
expect(cfg1.disableResponseStorage).toBe(true);
// 2⃣ save right back to the same file
await saveConfig(cfg1, yamlPath);
// 3⃣ reload and re-assert
const cfg2 = loadConfig(yamlPath);
expect(cfg2.disableResponseStorage).toBe(true);
});
});