Skip to content

Commit 2429900

Browse files
dcramergpt-5.4
andcommitted
ref(chat): align router prompt markers
Use the existing marker-block prompt structure in the turn router and replace the inline provider reasoning union with shared types/constants. This keeps the routing prompt aligned with the main user-turn formatter and trims future drift in the reasoning-level surface. Co-Authored-By: gpt-5.4 <assistant@openai.com>
1 parent 9e46edb commit 2429900

2 files changed

Lines changed: 31 additions & 18 deletions

File tree

packages/junior/src/chat/services/turn-execution-profile.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1-
import type { ThinkingLevel } from "@mariozechner/pi-agent-core";
1+
import type { ThinkingLevel as AgentThinkingLevel } from "@mariozechner/pi-agent-core";
2+
import type { ThinkingLevel as ProviderThinkingLevel } from "@mariozechner/pi-ai";
23
import { z } from "zod";
34

45
const CLASSIFIER_CONFIDENCE_THRESHOLD = 0.75;
56
const MAX_ROUTER_CONTEXT_CHARS = 1_200;
7+
const TURN_REASONING_EFFORTS = ["none", "low", "medium", "high"] as const;
68

79
const turnExecutionProfileSchema = z.object({
8-
reasoning_effort: z.enum(["none", "low", "medium", "high"]),
10+
reasoning_effort: z.enum(TURN_REASONING_EFFORTS),
911
confidence: z.number().min(0).max(1),
1012
reason: z.string().min(1),
1113
});
1214

15+
type TurnReasoningEffort = (typeof TURN_REASONING_EFFORTS)[number];
16+
1317
export interface TurnExecutionProfile {
1418
confidence?: number;
1519
modelId: string;
16-
reasoningEffort: "none" | "low" | "medium" | "high";
20+
reasoningEffort: TurnReasoningEffort;
1721
reason: string;
1822
}
1923

@@ -31,12 +35,12 @@ function trimContextForRouter(text: string | undefined): string | undefined {
3135

3236
function buildClassifierSystemPrompt(): string {
3337
return [
34-
"You route coding-assistant turns to the cheapest reasoning effort that is still likely to succeed.",
38+
"You route assistant turns to the cheapest reasoning effort that is still likely to succeed.",
3539
"Choose exactly one bucket: none, low, medium, or high.",
3640
"",
3741
"Use none for greetings, acknowledgments, and trivial single-step asks.",
3842
"Use low for straightforward explanations or simple one-step work.",
39-
"Use medium for repo investigation, multi-file analysis, ambiguous asks, or likely multi-tool work.",
43+
"Use medium for investigations, ambiguous asks, multi-step analysis, or likely multi-tool work.",
4044
"Use high for code changes, debugging/root-cause analysis, research-heavy work, non-trivial drafting, or explicit requests to be thorough.",
4145
"",
4246
"Return JSON only with reasoning_effort, confidence, and reason.",
@@ -49,20 +53,24 @@ function buildClassifierPrompt(args: {
4953
conversationContext?: string;
5054
messageText: string;
5155
}): string {
52-
const sections = [
53-
"Latest user request:",
54-
args.messageText.trim() || "[empty]",
55-
"",
56-
"Turn context:",
57-
`- active_skills: ${args.activeSkillNames.join(", ") || "none"}`,
58-
`- attachment_count: ${args.attachmentCount}`,
59-
];
56+
const sections: string[] = [];
6057

6158
const context = trimContextForRouter(args.conversationContext);
6259
if (context) {
63-
sections.push("", "Recent conversation context:", context);
60+
sections.push("<thread-background>", context, "</thread-background>", "");
6461
}
6562

63+
sections.push(
64+
"<turn-context>",
65+
`- active_skills: ${args.activeSkillNames.join(", ") || "none"}`,
66+
`- attachment_count: ${args.attachmentCount}`,
67+
"</turn-context>",
68+
"",
69+
'<current-instruction priority="highest">',
70+
args.messageText.trim() || "[empty]",
71+
"</current-instruction>",
72+
);
73+
6674
return sections.join("\n");
6775
}
6876

@@ -76,7 +84,7 @@ export async function selectTurnExecutionProfile(args: {
7684
maxTokens: number;
7785
metadata: Record<string, string>;
7886
prompt: string;
79-
reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh";
87+
reasoningEffort?: ProviderThinkingLevel;
8088
system: string;
8189
temperature: number;
8290
}) => Promise<{ object: unknown }>;
@@ -144,7 +152,7 @@ export async function selectTurnExecutionProfile(args: {
144152
/** Convert a routing effort bucket into the Pi Agent thinking level for a main turn. */
145153
export function toAgentThinkingLevel(
146154
effort: TurnExecutionProfile["reasoningEffort"],
147-
): ThinkingLevel | "off" {
155+
): AgentThinkingLevel | "off" {
148156
switch (effort) {
149157
case "none":
150158
return "off";

packages/junior/tests/unit/services/turn-execution-profile.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,15 @@ describe("selectTurnExecutionProfile", () => {
8282
expect.objectContaining({
8383
modelId: "openai/gpt-5.4-mini",
8484
prompt: expect.stringContaining(
85-
"Latest user request:\ncan you confirm this approach?",
85+
'<current-instruction priority="highest">\ncan you confirm this approach?\n</current-instruction>',
8686
),
8787
}),
8888
);
89+
expect(completeObject).toHaveBeenCalledWith(
90+
expect.objectContaining({
91+
prompt: expect.stringContaining("<turn-context>"),
92+
}),
93+
);
8994
expect(completeObject).toHaveBeenCalledWith(
9095
expect.objectContaining({
9196
prompt: expect.stringContaining("- active_skills: github"),
@@ -98,7 +103,7 @@ describe("selectTurnExecutionProfile", () => {
98103
);
99104
expect(completeObject).toHaveBeenCalledWith(
100105
expect.objectContaining({
101-
prompt: expect.stringContaining("Recent conversation context:"),
106+
prompt: expect.stringContaining("<thread-background>"),
102107
}),
103108
);
104109
});

0 commit comments

Comments
 (0)