Skip to content

Commit d001f48

Browse files
committed
feat(prompts): promptResidual with grok tool budget, appended once
1 parent 91bf1a3 commit d001f48

4 files changed

Lines changed: 36 additions & 1 deletion

File tree

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ export interface ModelFamilyPolicy {
3838
* at the tail so it cannot disturb the cached prompt prefix.
3939
*/
4040
toolDisciplineRules?: string;
41+
/**
42+
* Provider-family residual appended once to the assembled leaf system
43+
* prompt (CL-8297). Generic tool-budget text today (grok only); the
44+
* ceremony / Claude / GPT seams stay unfilled in sibling lanes. Withheld
45+
* from orchestrators and appended at the tail so it cannot disturb the
46+
* cached prompt prefix. Undefined for families that need none.
47+
*/
48+
promptResidual?: string | undefined;
4149
}
4250

4351
const DEFAULT_WRAP_UP_NUDGE_TEXT =
@@ -66,6 +74,16 @@ const DEFAULT_POLICY: Omit<ModelFamilyPolicy, "family"> = {
6674
advertisedToolDeny: [],
6775
};
6876

77+
// Generic 4-line tool-budget residual (CL-8297). Grok leaves get this via
78+
// promptResidual today; other families leave the seam unfilled until their
79+
// own lanes land. Deliberately free of ceremony lines and family-specific
80+
// routing — pure tool-loop budget.
81+
export const GROK_TOOL_BUDGET_RESIDUAL =
82+
"Tool budget:\n" +
83+
"- Batch independent tool calls into a single turn.\n" +
84+
"- Never re-issue a tool call whose result you already have.\n" +
85+
"- When the next call would only repeat prior work, write the report instead.";
86+
6987
// A directly observed 14-turn pure-tool-call session for this family
7088
// previously motivated a tightened nudge/pause pair here (6/10). That pair
7189
// was miscalibrated: it fired on a session that was making real progress
@@ -83,6 +101,8 @@ const GROK_POLICY: Omit<ModelFamilyPolicy, "family"> = {
83101
applyGrokFinishBias: true,
84102
// Leaf value; the resolver clears it for orchestrators below.
85103
advertisedToolDeny: ["skill_search"],
104+
// Leaf value; the resolver clears it for orchestrators below.
105+
promptResidual: GROK_TOOL_BUDGET_RESIDUAL,
86106
};
87107

88108
// Kimi (Moonshot) detection ships now so callers can branch on family, but
@@ -126,6 +146,7 @@ export function resolveModelFamilyPolicy(input: {
126146
...policy,
127147
applyGrokFinishBias: policy.applyGrokFinishBias && !orchestrator,
128148
advertisedToolDeny: orchestrator ? [] : policy.advertisedToolDeny,
149+
promptResidual: orchestrator ? undefined : policy.promptResidual,
129150
};
130151
}
131152
case "kimi":

‎src/agent/prompt-sizes.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
MAX_AGENTS_MD_BYTES,
1818
} from "./context-extensions.js";
1919
import { shouldApplyGrokAntiThrash } from "../subagent/provider-family.js";
20+
import { resolveModelFamilyPolicy } from "./model-family-policy.js";
2021
import { isCodexProviderName } from "../config/codex-providers.js";
2122
import { shellCollectDefinition } from "./background-shell-tool.js";
2223
import {
@@ -35,7 +36,9 @@ import { webSearchDefinition } from "../tools/web-search.js";
3536
* Assembles each director prompt exactly as src/subagent/run.ts does:
3637
* extensions=[director systemPromptRole] + environment + tools +
3738
* appendix, with the Grok finish-bias note gated by
38-
* shouldApplyGrokAntiThrash (leaves on Grok-family providers only).
39+
* shouldApplyGrokAntiThrash (leaves on Grok-family providers only) and the
40+
* family promptResidual (CL-8297 tool budget, grok leaves only) resolved
41+
* from the model family policy.
3942
*
4043
* The env and provider inputs are pinned here so sizes never drift with the
4144
* machine, date, or checkout — only real prompt changes move the numbers.
@@ -156,6 +159,7 @@ export function assembleDirectorPrompt(
156159
const pkg = DIRECTOR_REGISTRY[directorId];
157160
const orchestrator = pkg.spawn.maySpawn;
158161
const provider = family === "grok" ? GROK_PROVIDER : DEFAULT_PROVIDER;
162+
const policy = resolveModelFamilyPolicy({ ...provider, orchestrator });
159163
return buildSubAgentSystemPrompt(
160164
[formatDirectorSystemPrompt(pkg)],
161165
CANONICAL_PROMPT_ENV,
@@ -164,6 +168,7 @@ export function assembleDirectorPrompt(
164168
orchestrator,
165169
toolNames: canonicalToolNamesForDirector(pkg, family),
166170
grokAntiThrash: shouldApplyGrokAntiThrash({ ...provider, orchestrator }),
171+
promptResidual: policy.promptResidual,
167172
},
168173
);
169174
}

‎src/agent/prompts.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,11 @@ export function buildSubAgentSystemPrompt(
530530
toolNames?: readonly string[];
531531
/** When true, append the tiny Grok/xAI finish-bias note (provider residual). */
532532
grokAntiThrash?: boolean;
533+
/**
534+
* Family policy residual (CL-8297) appended once at the tail so it
535+
* cannot disturb the cached prompt prefix. Unset for families with none.
536+
*/
537+
promptResidual?: string | undefined;
533538
} = {},
534539
): string {
535540
const toolListForPrompt =
@@ -556,5 +561,8 @@ export function buildSubAgentSystemPrompt(
556561
if (opts.grokAntiThrash === true) {
557562
sections.push(buildGrokLeafAntiThrashNote());
558563
}
564+
if (opts.promptResidual !== undefined && opts.promptResidual.length > 0) {
565+
sections.push(opts.promptResidual);
566+
}
559567
return joinSections(sections);
560568
}

‎src/subagent/run.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,7 @@ async function runSubAgentInner(
10551055
model: params.provider.model,
10561056
orchestrator: params.orchestrator === true,
10571057
}),
1058+
promptResidual: modelFamilyPolicy.promptResidual,
10581059
},
10591060
);
10601061

0 commit comments

Comments
 (0)