Skip to content

Commit ea9f69c

Browse files
Merge pull request #1132 from corbitsdev/cl-8296-0330-merge-grok-ceremony-lines-into-the-one-residual
feat(agent): merge grok ceremony lines into the one residual
2 parents 4931d74 + d9be39a commit ea9f69c

3 files changed

Lines changed: 105 additions & 7 deletions

File tree

‎src/agent/grok-residual.test.ts‎

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { describe, expect, it } from "bun:test";
2+
import { GROK_PROMPT_RESIDUAL } from "./model-family-policy.js";
3+
import {
4+
buildGrokLeafAntiThrashNote,
5+
buildSubAgentSystemPrompt,
6+
} from "./prompts.js";
7+
import { shouldApplyGrokAntiThrash } from "../subagent/provider-family.js";
8+
9+
// The three Grok ceremony lines (CL-7768 Design, merged by CL-8296): no git,
10+
// no pre-plan, verify once.
11+
const CEREMONY_LINES = [
12+
"- Never run git add, git commit, git stash, or any other state-changing git command unless the user asks.",
13+
"- Do not narrate a plan before acting on a small task; act, then report.",
14+
"- Verify with the test command once at the end, not after every edit.",
15+
] as const;
16+
17+
function countOccurrences(haystack: string, needle: string): number {
18+
return haystack.split(needle).length - 1;
19+
}
20+
21+
describe("grok ceremony merge (CL-8296)", () => {
22+
it("exposes a single grok residual with each ceremony line exactly once", () => {
23+
expect(GROK_PROMPT_RESIDUAL).toContain("Finish bias (xAI / Grok worker):");
24+
for (const line of CEREMONY_LINES) {
25+
expect(countOccurrences(GROK_PROMPT_RESIDUAL, line)).toBe(1);
26+
}
27+
});
28+
29+
it("keeps the don't re-read line exactly once — no duplicate", () => {
30+
expect(
31+
countOccurrences(GROK_PROMPT_RESIDUAL, "re-open paths you already read"),
32+
).toBe(1);
33+
});
34+
35+
it("is grok-only: the finish-bias gate fires for grok leaves alone", () => {
36+
expect(
37+
shouldApplyGrokAntiThrash({
38+
providerName: "xai/default",
39+
model: "grok-4.6",
40+
orchestrator: false,
41+
}),
42+
).toBe(true);
43+
for (const input of [
44+
{ providerName: "anthropic", model: "claude-sonnet-4" },
45+
{ providerName: "moonshot", model: "kimi-k2" },
46+
{ providerName: "opencode-go", model: "muse-spark-1.3-contributor" },
47+
{ providerName: "openai", model: "gpt-4.1" },
48+
] as const) {
49+
expect(shouldApplyGrokAntiThrash({ ...input, orchestrator: false })).toBe(
50+
false,
51+
);
52+
}
53+
expect(
54+
shouldApplyGrokAntiThrash({
55+
providerName: "xai/default",
56+
model: "grok-4.6",
57+
orchestrator: true,
58+
}),
59+
).toBe(false);
60+
});
61+
62+
it("buildGrokLeafAntiThrashNote is the same single residual (one source of truth)", () => {
63+
expect(buildGrokLeafAntiThrashNote()).toBe(GROK_PROMPT_RESIDUAL);
64+
});
65+
66+
it("the assembled grok worker prompt carries the merged residual exactly once", () => {
67+
const prompt = buildSubAgentSystemPrompt(undefined, undefined, undefined, {
68+
orchestrator: false,
69+
grokAntiThrash: true,
70+
});
71+
expect(countOccurrences(prompt, "Finish bias (xAI / Grok worker):")).toBe(
72+
1,
73+
);
74+
for (const line of CEREMONY_LINES) {
75+
expect(countOccurrences(prompt, line)).toBe(1);
76+
}
77+
});
78+
});

‎src/agent/model-family-policy.ts‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,27 @@ const MUSE_POLICY: Omit<ModelFamilyPolicy, "family"> = {
129129
toolDisciplineRules: MUSE_TOOL_DISCIPLINE_RULES,
130130
};
131131

132+
// Single grok finish-bias + ceremony residual (CL-8296): the finish-bias
133+
// bullets plus the three ceremony lines from the CL-7768 design (no git, no
134+
// pre-plan, verify once), merged into one block with no line twice. The don't
135+
// re-read idea appears exactly once (the "re-open paths" bullet) — it is not
136+
// repeated. Grok-only: detectModelFamily has no glm family, so per the <30min
137+
// rule no GLM row ships here. The text lives here once; exported for
138+
// buildGrokLeafAntiThrashNote (prompts.ts), which returns it verbatim, so the
139+
// prompt carries exactly one copy. This is a different block from the CL-8297
140+
// tool-budget hook (GROK_TOOL_BUDGET_RESIDUAL, surfaced via the
141+
// ModelFamilyPolicy.promptResidual field): grok leaves carry both, each once.
142+
export const GROK_PROMPT_RESIDUAL = [
143+
"Finish bias (xAI / Grok worker):",
144+
"- Once you can answer the dispatch brief, prefer the structured report over another speculative tool call.",
145+
"- If the next call would only re-open paths you already read, write the report instead.",
146+
"- When the dispatch brief's done-definition is met, write the report envelope instead of making one more search or micro-edit.",
147+
"- Route file and web work through the dedicated tools, never run_shell — mining showed grok reaching for shell first when a typed tool already covered the job.",
148+
"- Never run git add, git commit, git stash, or any other state-changing git command unless the user asks.",
149+
"- Do not narrate a plan before acting on a small task; act, then report.",
150+
"- Verify with the test command once at the end, not after every edit.",
151+
].join("\n");
152+
132153
export function resolveModelFamilyPolicy(input: {
133154
providerName: string;
134155
model?: string;

‎src/agent/prompts.ts‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
buildWorkerContract,
1212
buildWorkerToolNames,
1313
} from "./worker-contract.js";
14+
import { GROK_PROMPT_RESIDUAL } from "./model-family-policy.js";
1415

1516
// Advertise every gated core tool when the caller has no session-start facts
1617
// (tests, ad-hoc prompt previews) — except wait_agents, which is mount-gated:
@@ -511,14 +512,12 @@ export function buildSubAgentReportContract(
511512
// Tiny residual for Grok/xAI workers: mining showed higher tools-only thrash
512513
// than Codex on the same harness. Shared thrash harness + spawn contracts do
513514
// the structural work; this is only a finish-bias nudge, not a full rewrite.
515+
// Single source of truth is the GROK_PROMPT_RESIDUAL block in
516+
// model-family-policy.ts (CL-8296 merged the three ceremony lines into it);
517+
// this returns that block verbatim so the prompt carries one grok residual
518+
// with no line twice.
514519
export function buildGrokLeafAntiThrashNote(): string {
515-
return [
516-
"Finish bias (xAI / Grok worker):",
517-
"- Once you can answer the dispatch brief, prefer the structured report over another speculative tool call.",
518-
"- If the next call would only re-open paths you already read, write the report instead.",
519-
"- When the dispatch brief's done-definition is met, write the report envelope instead of making one more search or micro-edit.",
520-
"- Route file and web work through the dedicated tools, never run_shell — mining showed grok reaching for shell first when a typed tool already covered the job.",
521-
].join("\n");
520+
return GROK_PROMPT_RESIDUAL;
522521
}
523522

524523
export function buildSubAgentSystemPrompt(

0 commit comments

Comments
 (0)