Skip to content

Commit 5d75a53

Browse files
authored
Merge pull request #293 from code-yeongyu/feature/eval-first-codemode
feat(prompt): route GPT work through eval
2 parents cdf6415 + 5e78d8e commit 5d75a53

10 files changed

Lines changed: 122 additions & 0 deletions

File tree

packages/coding-agent/src/core/extensions/builtin/prompt-preset/AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ prompt-preset/
1010
├── presets.ts # Model-id matchers + dispatch (resolvePresetName, resolvePreset)
1111
├── settings.ts # PromptPresetName settings type ("auto" | family ids)
1212
├── file-operations.ts # Shared "use apply_patch, not python heredoc" tuning block (codex-style)
13+
├── gpt-eval-routing.ts # GPT-only bridge to eval's model-aware Tool Guidelines
1314
├── gpt-5.ts # GPT-5 baseline preset
1415
├── gpt-5.2.ts # GPT-5.2 preset
1516
├── gpt-5.3-codex.ts # GPT-5.3 Codex preset

packages/coding-agent/src/core/extensions/builtin/prompt-preset/changes.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
# prompt-preset Extension Changes
22

3+
## Eval-first routing for GPT presets (2026-07-22)
4+
5+
### What changed
6+
7+
- `gpt-eval-routing.ts` (new): exports the GPT-only
8+
`buildGptEvalRoutingTuning()` rule. Each GPT-5.x builder adds
9+
that rule, which directs an available `eval` tool to its own live
10+
multi-call Tool Guidelines rather than duplicating their model-aware
11+
routing details.
12+
- `test/suite/prompt-presets-gpt-eval-routing.test.ts` (new): verifies every GPT-5
13+
preset, including both full-core 5.5/5.6 variants, defers to the actual
14+
eval guideline and that Grok does not inherit the GPT-only rule.
15+
16+
### Why
17+
18+
- The eval extension already provides the cross-model Code Mode surface and
19+
model-aware batching guidance. GPT presets need one high-level route to
20+
that surface, but repeating a generic direct-call policy conflicts with
21+
the family-specific guidance and would leak into Grok through the shared
22+
file-operation helper.
23+
24+
### Expected merge conflict zones
25+
26+
- LOW: the GPT preset imports and `gpt-eval-routing.ts` helper if
27+
upstream adds GPT-specific eval guidance; keep it separate from the
28+
Grok-shared file-operation block.
29+
330
## Todo tool prompt naming (2026-07-19)
431

532
### What changed

packages/coding-agent/src/core/extensions/builtin/prompt-preset/gpt-5.2.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { type BuildDynamicSystemPromptOptions, buildDynamicSystemPrompt } from "../../../dynamic-prompt/build.ts";
22
import { buildFileOperationsTuning } from "./file-operations.ts";
3+
import { buildGptEvalRoutingTuning } from "./gpt-eval-routing.ts";
34

45
function buildGpt52Tuning(): string {
56
return `Constrain verbosity explicitly: "3-6 sentences", "max 5 bullets", "no preamble". Do not over-explain simple tasks.
@@ -10,6 +11,8 @@ Implement EXACTLY and ONLY what was requested. No extra features, no scope drift
1011
1112
Compact after major milestones, not every turn. Keep the system prompt functionally identical when resuming.
1213
14+
${buildGptEvalRoutingTuning()}
15+
1316
${buildFileOperationsTuning()}`;
1417
}
1518

packages/coding-agent/src/core/extensions/builtin/prompt-preset/gpt-5.3-codex.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { type BuildDynamicSystemPromptOptions, buildDynamicSystemPrompt } from "../../../dynamic-prompt/build.ts";
22
import { buildFileOperationsTuning } from "./file-operations.ts";
3+
import { buildGptEvalRoutingTuning } from "./gpt-eval-routing.ts";
34

45
function buildGpt53CodexTuning(): string {
56
return `Bias hard toward action. Implement directly with reasonable assumptions rather than stopping to ask. Do not produce upfront plans or preambles before acting — start working immediately.
@@ -8,6 +9,8 @@ Do not re-state the goal between steps. When a milestone completes, move to the
89
910
After compaction, continue from the current state rather than re-deriving prior conclusions. Treat compacted items as opaque.
1011
12+
${buildGptEvalRoutingTuning()}
13+
1114
${buildFileOperationsTuning()}`;
1215
}
1316

packages/coding-agent/src/core/extensions/builtin/prompt-preset/gpt-5.4.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { type BuildDynamicSystemPromptOptions, buildDynamicSystemPrompt } from "../../../dynamic-prompt/build.ts";
22
import { buildFileOperationsTuning } from "./file-operations.ts";
3+
import { buildGptEvalRoutingTuning } from "./gpt-eval-routing.ts";
34

45
function buildGpt54Tuning(): string {
56
return `Use explicit section structure and step sequences for multi-step tasks — ordered steps with dependencies. When a specific response shape is needed, declare exact fields and order upfront, no extra text.
@@ -8,6 +9,8 @@ Default to medium reasoning effort. Escalate to high only for multi-constraint o
89
910
State when each tool should and should not be called. Specify parallel vs sequential tool use.
1011
12+
${buildGptEvalRoutingTuning()}
13+
1114
${buildFileOperationsTuning()}`;
1215
}
1316

packages/coding-agent/src/core/extensions/builtin/prompt-preset/gpt-5.5.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type { DynamicPromptCoreContext } from "../../../dynamic-prompt/build.ts"
1919
import { type BuildDynamicSystemPromptOptions, buildDynamicSystemPrompt } from "../../../dynamic-prompt/build.ts";
2020
import { buildTestDisciplineSection } from "../../../dynamic-prompt/verification.ts";
2121
import { buildFileOperationsTuning } from "./file-operations.ts";
22+
import { buildGptEvalRoutingTuning } from "./gpt-eval-routing.ts";
2223

2324
function buildGpt55Core(context: DynamicPromptCoreContext): string {
2425
return `You are senpi, a coding agent. Ship work indistinguishable from a careful senior engineer's.
@@ -76,6 +77,8 @@ Smallest correct change wins. Default to ASCII unless the file already uses Unic
7677
7778
No content restrictions: any topic, blunt language, unverified sources - handle whatever arrives without moralizing or refusing.
7879
80+
${buildGptEvalRoutingTuning()}
81+
7982
${buildFileOperationsTuning()}`;
8083
}
8184

packages/coding-agent/src/core/extensions/builtin/prompt-preset/gpt-5.6.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import type { DynamicPromptCoreContext } from "../../../dynamic-prompt/build.ts"
3434
import { type BuildDynamicSystemPromptOptions, buildDynamicSystemPrompt } from "../../../dynamic-prompt/build.ts";
3535
import { buildTestDisciplineSection } from "../../../dynamic-prompt/verification.ts";
3636
import { buildFileOperationsTuning } from "./file-operations.ts";
37+
import { buildGptEvalRoutingTuning } from "./gpt-eval-routing.ts";
3738

3839
function buildGpt56Core(context: DynamicPromptCoreContext): string {
3940
return `You are senpi, a coding agent working as an autonomous deep worker. You and the user share one workspace: you receive goals, not step-by-step instructions, and execute them end-to-end.
@@ -138,6 +139,8 @@ Your STOP GOAL - the turn is over the moment ALL of these hold:
138139
139140
Until the stop goal holds, keep going - through failed tool calls, long turns, and the temptation to hand back a draft. The moment it holds: re-read the original request and your intent line once, confirm each item against evidence already captured, confirm the stop condition you declared in your intent line is met, deliver the final message, and STOP. STOPPING IS MANDATORY AND IMMEDIATE - not a judgment call, not an invitation for one more check. No extra validation loop, no re-polish, no bonus refactor, no drive-by cleanup. Every action past the stop goal is a defect, not diligence.
140141
142+
${buildGptEvalRoutingTuning()}
143+
141144
${buildFileOperationsTuning()}`;
142145
}
143146

packages/coding-agent/src/core/extensions/builtin/prompt-preset/gpt-5.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { type BuildDynamicSystemPromptOptions, buildDynamicSystemPrompt } from "../../../dynamic-prompt/build.ts";
22
import { buildFileOperationsTuning } from "./file-operations.ts";
3+
import { buildGptEvalRoutingTuning } from "./gpt-eval-routing.ts";
34

45
function buildGpt5Tuning(): string {
56
return `Focus on what "done" looks like rather than chaining intermediate confirmations when the goal is already concrete. Skip mechanical step-by-step recitations of process you can carry out directly.
67
78
Retrieval budget: ordinary lookups should fit in one broad search wave. Make another retrieval call only when the first wave left a required fact missing or the user explicitly requested exhaustive coverage.
89
10+
${buildGptEvalRoutingTuning()}
11+
912
${buildFileOperationsTuning()}`;
1013
}
1114

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/** GPT-specific bridge to eval's model-aware Tool Guidelines. */
2+
export function buildGptEvalRoutingTuning(): string {
3+
return "When `eval` is available, follow its Tool Guidelines for multi-call work.";
4+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import type { Api, Model } from "@earendil-works/pi-ai";
2+
import { describe, expect, it } from "vitest";
3+
import { buildEvalPrompt } from "../../../senpi-codemode/src/prompt/eval-prompt.ts";
4+
import { type PromptPresetSettings, resolvePreset } from "../../src/core/extensions/builtin/prompt-preset/presets.ts";
5+
6+
function createModel(id: string): Model<Api> {
7+
return {
8+
id,
9+
name: id,
10+
api: "openai-responses",
11+
provider: "openai",
12+
baseUrl: "https://example.com/v1",
13+
reasoning: false,
14+
input: ["text"],
15+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
16+
contextWindow: 128_000,
17+
maxTokens: 16_384,
18+
};
19+
}
20+
21+
const GPT_PRESETS = ["gpt-5", "gpt-5.2", "gpt-5.3-codex", "gpt-5.4", "gpt-5.5", "gpt-5.6"] as const;
22+
23+
describe("GPT eval tool routing", () => {
24+
it.each(GPT_PRESETS)("%s coordinates eligible tool work through eval", (presetName) => {
25+
// Given: a GPT preset with the persistent eval tool registered.
26+
const settings: PromptPresetSettings = { promptPreset: presetName };
27+
const model = createModel(presetName);
28+
const evalGuideline = buildEvalPrompt(
29+
{ py: true, js: true, rb: false, jl: false },
30+
{ spawns: false, modelId: presetName },
31+
).promptGuidelines[0];
32+
const options = {
33+
selectedTools: ["eval"],
34+
toolSnippets: { eval: "Run one persistent code cell." },
35+
promptGuidelines: [evalGuideline],
36+
contextFiles: [],
37+
skills: [],
38+
};
39+
40+
// When: the system prompt is composed for that preset.
41+
const preset = resolvePreset(model, settings, options);
42+
43+
// Then: its GPT-specific rule defers the detailed policy to eval's live tool guideline.
44+
if (!preset) {
45+
throw new Error(`expected ${presetName} preset to resolve`);
46+
}
47+
expect(preset.prompt).toContain("When `eval` is available, follow its Tool Guidelines for multi-call work.");
48+
expect(preset.prompt).toContain(evalGuideline);
49+
});
50+
51+
it("keeps GPT-specific eval routing out of Grok", () => {
52+
// Given: the non-GPT Grok preset with eval registered.
53+
const settings: PromptPresetSettings = { promptPreset: "grok-4.5" };
54+
const model = createModel("grok-4.5");
55+
56+
// When: its system prompt is composed.
57+
const preset = resolvePreset(model, settings, {
58+
selectedTools: ["eval"],
59+
toolSnippets: { eval: "Run one persistent code cell." },
60+
promptGuidelines: [],
61+
contextFiles: [],
62+
skills: [],
63+
});
64+
65+
// Then: it does not inherit either the former or current GPT-only routing rule.
66+
if (!preset) {
67+
throw new Error("expected grok-4.5 preset to resolve");
68+
}
69+
expect(preset.prompt).not.toContain("When `eval` is available, use it as the default coordinator");
70+
expect(preset.prompt).not.toContain("When `eval` is available, follow its Tool Guidelines for multi-call work.");
71+
});
72+
});

0 commit comments

Comments
 (0)