mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 22:00:44 +00:00
Improve Codex happy path prompt snapshots (#76229)
* test: add Codex model prompt layers to snapshots * test: keep rendered prompt snapshots raw * test: check prompt snapshot drift in ci * test: prefer codex model cache for prompt fixtures * fix: exclude publishable plugin dist from core package
This commit is contained in:
@@ -6,7 +6,16 @@ import {
|
||||
createFormattedPromptSnapshotFiles,
|
||||
deleteStalePromptSnapshotFiles,
|
||||
} from "../../scripts/generate-prompt-snapshots.js";
|
||||
import { HAPPY_PATH_PROMPT_SNAPSHOT_DIR } from "../helpers/agents/happy-path-prompt-snapshots.js";
|
||||
import {
|
||||
defaultCatalogPathCandidates,
|
||||
findDefaultCatalogPath,
|
||||
renderCodexModelInstructions,
|
||||
runCodexModelPromptFixtureSync,
|
||||
} from "../../scripts/sync-codex-model-prompt-fixture.js";
|
||||
import {
|
||||
CODEX_MODEL_PROMPT_FIXTURE_DIR,
|
||||
HAPPY_PATH_PROMPT_SNAPSHOT_DIR,
|
||||
} from "../helpers/agents/happy-path-prompt-snapshots.js";
|
||||
|
||||
describe("happy path prompt snapshots", () => {
|
||||
it("matches the committed Codex prompt snapshot artifacts", async () => {
|
||||
@@ -40,4 +49,102 @@ describe("happy path prompt snapshots", () => {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("renders the Codex model-bound prompt layers", async () => {
|
||||
const generated = await createFormattedPromptSnapshotFiles();
|
||||
const telegram = generated.find((file) =>
|
||||
file.path.endsWith("telegram-direct-codex-message-tool.md"),
|
||||
);
|
||||
|
||||
expect(telegram?.content).toContain("## Reconstructed Model-Bound Prompt Layers");
|
||||
expect(telegram?.content).toContain(
|
||||
"### System: Codex Model Instructions (gpt-5.5, pragmatic)",
|
||||
);
|
||||
expect(telegram?.content).toContain("You are Codex, a coding agent based on GPT-5.");
|
||||
expect(telegram?.content).toContain("### Developer: Codex Permission Instructions");
|
||||
expect(telegram?.content).toContain(
|
||||
"Approval policy is currently never. Do not provide the `sandbox_permissions`",
|
||||
);
|
||||
expect(telegram?.content).toContain("### Tools: Dynamic Tool Catalog");
|
||||
});
|
||||
|
||||
it("keeps the Codex model prompt fixture next to its source metadata", () => {
|
||||
expect(
|
||||
fs.existsSync(path.join(CODEX_MODEL_PROMPT_FIXTURE_DIR, "gpt-5.5.pragmatic.instructions.md")),
|
||||
).toBe(true);
|
||||
expect(
|
||||
fs.existsSync(path.join(CODEX_MODEL_PROMPT_FIXTURE_DIR, "gpt-5.5.pragmatic.source.json")),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("renders Codex model catalog instructions with the selected personality", () => {
|
||||
const rendered = renderCodexModelInstructions({
|
||||
model: {
|
||||
slug: "gpt-5.5",
|
||||
base_instructions: "fallback",
|
||||
model_messages: {
|
||||
instructions_template: "Intro\n{{ personality }}\nEnd",
|
||||
instructions_variables: {
|
||||
personality_pragmatic: "Pragmatic voice",
|
||||
},
|
||||
},
|
||||
},
|
||||
personality: "pragmatic",
|
||||
});
|
||||
|
||||
expect(rendered).toEqual({
|
||||
instructions: "Intro\nPragmatic voice\nEnd",
|
||||
field:
|
||||
"model_messages.instructions_template + model_messages.instructions_variables.personality_pragmatic",
|
||||
});
|
||||
});
|
||||
|
||||
it("prefers the Codex runtime model cache before local checkout fallbacks", () => {
|
||||
const candidates = defaultCatalogPathCandidates({
|
||||
env: { CODEX_HOME: "/tmp/codex-home" },
|
||||
homeDir: "/tmp/home",
|
||||
});
|
||||
|
||||
expect(candidates).toEqual([
|
||||
path.join("/tmp/codex-home", "models_cache.json"),
|
||||
path.join("/tmp/home", ".codex", "models_cache.json"),
|
||||
path.join("/tmp/home", "code", "codex", "codex-rs", "models-manager", "models.json"),
|
||||
]);
|
||||
});
|
||||
|
||||
it("finds the first available default Codex model catalog source", async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-codex-catalog-"));
|
||||
try {
|
||||
const cachePath = path.join(root, ".codex", "models_cache.json");
|
||||
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
|
||||
fs.writeFileSync(cachePath, JSON.stringify({ models: [] }));
|
||||
|
||||
await expect(findDefaultCatalogPath({ env: {}, homeDir: root })).resolves.toMatchObject({
|
||||
catalogPath: cachePath,
|
||||
});
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("skips Codex model prompt fixture sync when no default catalog exists", async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-codex-catalog-missing-"));
|
||||
const chunks: string[] = [];
|
||||
try {
|
||||
const result = await runCodexModelPromptFixtureSync([], {
|
||||
env: {},
|
||||
homeDir: root,
|
||||
stdout: {
|
||||
write(chunk) {
|
||||
chunks.push(chunk);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.status).toBe("skipped");
|
||||
expect(chunks.join("")).toContain("No Codex model catalog/cache found");
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
BOUNDARY_CHECKS,
|
||||
formatCommand,
|
||||
resolveConcurrency,
|
||||
runChecks,
|
||||
@@ -19,6 +20,14 @@ function createOutputBuffer() {
|
||||
}
|
||||
|
||||
describe("run-additional-boundary-checks", () => {
|
||||
it("runs prompt snapshot drift checks in CI", () => {
|
||||
expect(BOUNDARY_CHECKS).toContainEqual({
|
||||
label: "prompt:snapshots:check",
|
||||
command: "pnpm",
|
||||
args: ["prompt:snapshots:check"],
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes concurrency input", () => {
|
||||
expect(resolveConcurrency("6")).toBe(6);
|
||||
expect(resolveConcurrency("0")).toBe(4);
|
||||
|
||||
Reference in New Issue
Block a user