| 1 | import * as NodeAssert from "node:assert/strict"; |
| 2 | |
| 3 | import { describe, it } from "vite-plus/test"; |
| 4 | |
| 5 | import { |
| 6 | buildCodexAdditionalContext, |
| 7 | buildCodexDeveloperInstructions, |
| 8 | } from "./CodexDeveloperInstructions.ts"; |
| 9 | |
| 10 | describe("buildCodexDeveloperInstructions", () => { |
| 11 | it("appends runtime info after the mode instructions", () => { |
| 12 | const instructions = runtimeInstructions({ |
| 13 | model: "gpt-5.3-codex", |
| 14 | reasoningEffort: "high", |
| 15 | }); |
| 16 | |
| 17 | NodeAssert.match( |
| 18 | buildCodexDeveloperInstructions("default"), |
| 19 | /^<collaboration_mode># Collaboration Mode: Default/, |
| 20 | ); |
| 21 | NodeAssert.match(instructions, /T3 Code/); |
| 22 | NodeAssert.match(instructions, /Codex harness/); |
| 23 | NodeAssert.match(instructions, /as gpt-5\.3-codex with high reasoning effort/); |
| 24 | }); |
| 25 | |
| 26 | it("describes Markdown media support in the runtime context in both modes", () => { |
| 27 | { |
| 28 | const instructions = runtimeInstructions({ |
| 29 | model: "gpt-5.3-codex", |
| 30 | reasoningEffort: "high", |
| 31 | }); |
| 32 | NodeAssert.match( |
| 33 | instructions, |
| 34 | /<runtime_info>.*embed images and videos.*Markdown.*<\/runtime_info>/, |
| 35 | ); |
| 36 | } |
| 37 | }); |
| 38 | |
| 39 | it("includes runtime info alongside plan mode instructions", () => { |
| 40 | const instructions = runtimeInstructions({ |
| 41 | model: "gpt-5.3-codex", |
| 42 | reasoningEffort: "medium", |
| 43 | }); |
| 44 | |
| 45 | NodeAssert.match(buildCodexDeveloperInstructions("plan"), /^<collaboration_mode># Plan Mode/); |
| 46 | NodeAssert.match(instructions, /as gpt-5\.3-codex with medium reasoning effort/); |
| 47 | }); |
| 48 | |
| 49 | it("varies with the model and effort of each turn", () => { |
| 50 | const first = runtimeInstructions({ |
| 51 | model: "gpt-5.3-codex", |
| 52 | reasoningEffort: "medium", |
| 53 | }); |
| 54 | const second = runtimeInstructions({ |
| 55 | model: "gpt-5.4", |
| 56 | reasoningEffort: "high", |
| 57 | }); |
| 58 | |
| 59 | NodeAssert.notEqual(first, second); |
| 60 | }); |
| 61 | |
| 62 | it("flattens multiline metadata into single-line runtime info", () => { |
| 63 | const instructions = runtimeInstructions({ |
| 64 | model: "gpt\n5.3\ncodex", |
| 65 | reasoningEffort: " high\neffort ", |
| 66 | }); |
| 67 | |
| 68 | NodeAssert.match(instructions, /as gpt 5\.3 codex with high effort reasoning effort/); |
| 69 | NodeAssert.doesNotMatch(instructions, /<runtime_info>[^<]*\n/); |
| 70 | }); |
| 71 | }); |
| 72 | |
| 73 | describe("T3 browser developer instructions", () => { |
| 74 | const runtime = { model: "gpt-5.3-codex", reasoningEffort: "high" }; |
| 75 | |
| 76 | it("prefers the product-native preview tools in both collaboration modes", () => { |
| 77 | { |
| 78 | const instructions = toolInstructions(runtime, true); |
| 79 | NodeAssert.match(instructions, /t3-code/); |
| 80 | NodeAssert.match(instructions, /preview_status/); |
| 81 | NodeAssert.match(instructions, /preview_open/); |
| 82 | NodeAssert.match(instructions, /Do not switch to global browser skills/); |
| 83 | } |
| 84 | }); |
| 85 | |
| 86 | it("omits the browser block entirely when the preview tools are not attached", () => { |
| 87 | for (const mode of ["default", "plan"] as const) { |
| 88 | const instructions = toolInstructions(runtime, false); |
| 89 | NodeAssert.doesNotMatch(instructions, /preview_status/); |
| 90 | NodeAssert.doesNotMatch(instructions, /preview_open/); |
| 91 | NodeAssert.doesNotMatch(instructions, /T3 Code collaborative browser/); |
| 92 | // Steering away from other browser automation must go with the tools; |
| 93 | // keeping it would leave the model talked out of its only option. |
| 94 | NodeAssert.doesNotMatch(instructions, /Do not switch to global browser skills/); |
| 95 | // The rest of the collaboration mode is untouched. |
| 96 | NodeAssert.match(buildCodexDeveloperInstructions(mode), /<collaboration_mode>/); |
| 97 | NodeAssert.match(buildCodexDeveloperInstructions(mode), /<\/collaboration_mode>/); |
| 98 | } |
| 99 | }); |
| 100 | |
| 101 | it("tracks the turn's MCP configuration rather than defaulting to on", () => { |
| 102 | NodeAssert.match(toolInstructions(runtime, true), /preview_open/); |
| 103 | NodeAssert.doesNotMatch(toolInstructions(runtime, false), /preview_open/); |
| 104 | }); |
| 105 | }); |
| 106 | |
| 107 | function runtimeInstructions(runtime: Parameters<typeof buildCodexAdditionalContext>[0]) { |
| 108 | return buildCodexAdditionalContext(runtime).t3_code_runtime!.value; |
| 109 | } |
| 110 | function toolInstructions( |
| 111 | runtime: Parameters<typeof buildCodexAdditionalContext>[0], |
| 112 | available: boolean, |
| 113 | ) { |
| 114 | return buildCodexAdditionalContext(runtime, available).t3_code_tools?.value ?? ""; |
| 115 | } |