Skip to content

Commit 3a5b3b6

Browse files
Fix plan follow-up mode switching and submission text
- Extract follow-up submission resolution into `resolvePlanFollowUpSubmission` - Send implementation prompt in default mode when follow-up text is empty - Keep composer mode toggle synced when starting same-thread implementation turns - Add tests for follow-up submission behavior
1 parent f62310b commit 3a5b3b6

File tree

3 files changed

+60
-7
lines changed

3 files changed

+60
-7
lines changed

apps/web/src/components/ChatView.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ import {
9292
buildPlanImplementationPrompt,
9393
buildProposedPlanMarkdownFilename,
9494
proposedPlanTitle,
95+
resolvePlanFollowUpSubmission,
9596
} from "../proposedPlan";
9697
import { truncateTitle } from "../truncateTitle";
9798
import {
@@ -2318,19 +2319,18 @@ export default function ChatView({ threadId }: ChatViewProps) {
23182319
}
23192320
const trimmed = prompt.trim();
23202321
if (showPlanFollowUpPrompt && activeProposedPlan) {
2321-
const followUpText =
2322-
trimmed.length > 0
2323-
? trimmed
2324-
: buildPlanImplementationPrompt(activeProposedPlan.planMarkdown);
2325-
const nextInteractionMode = trimmed.length > 0 ? "plan" : "default";
2322+
const followUp = resolvePlanFollowUpSubmission({
2323+
draftText: trimmed,
2324+
planMarkdown: activeProposedPlan.planMarkdown,
2325+
});
23262326
promptRef.current = "";
23272327
clearComposerDraftContent(activeThread.id);
23282328
setComposerHighlightedItemId(null);
23292329
setComposerCursor(0);
23302330
setComposerTrigger(null);
23312331
await onSubmitPlanFollowUp({
2332-
text: followUpText,
2333-
interactionMode: nextInteractionMode,
2332+
text: followUp.text,
2333+
interactionMode: followUp.interactionMode,
23342334
});
23352335
return;
23362336
}
@@ -2795,6 +2795,10 @@ export default function ChatView({ threadId }: ChatViewProps) {
27952795
interactionMode: nextInteractionMode,
27962796
});
27972797

2798+
// Keep the mode toggle and plan-follow-up banner in sync immediately
2799+
// while the same-thread implementation turn is starting.
2800+
setComposerDraftInteractionMode(threadIdForSend, nextInteractionMode);
2801+
27982802
await api.orchestration.dispatchCommand({
27992803
type: "thread.turn.start",
28002804
commandId: newCommandId(),
@@ -2840,6 +2844,7 @@ export default function ChatView({ threadId }: ChatViewProps) {
28402844
selectedModel,
28412845
selectedModelOptionsForDispatch,
28422846
selectedProvider,
2847+
setComposerDraftInteractionMode,
28432848
setThreadError,
28442849
settings.enableAssistantStreaming,
28452850
],

apps/web/src/proposedPlan.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
buildPlanImplementationPrompt,
66
buildProposedPlanMarkdownFilename,
77
proposedPlanTitle,
8+
resolvePlanFollowUpSubmission,
89
} from "./proposedPlan";
910

1011
describe("proposedPlanTitle", () => {
@@ -25,6 +26,32 @@ describe("buildPlanImplementationPrompt", () => {
2526
});
2627
});
2728

29+
describe("resolvePlanFollowUpSubmission", () => {
30+
it("switches to default mode when implementing the ready plan without extra text", () => {
31+
expect(
32+
resolvePlanFollowUpSubmission({
33+
draftText: " ",
34+
planMarkdown: "## Ship it\n\n- step 1\n",
35+
}),
36+
).toEqual({
37+
text: "PLEASE IMPLEMENT THIS PLAN:\n## Ship it\n\n- step 1",
38+
interactionMode: "default",
39+
});
40+
});
41+
42+
it("stays in plan mode when the user adds a follow-up prompt", () => {
43+
expect(
44+
resolvePlanFollowUpSubmission({
45+
draftText: "Refine step 2 first",
46+
planMarkdown: "## Ship it\n\n- step 1\n",
47+
}),
48+
).toEqual({
49+
text: "Refine step 2 first",
50+
interactionMode: "plan",
51+
});
52+
});
53+
});
54+
2855
describe("buildPlanImplementationThreadTitle", () => {
2956
it("uses the plan heading when building the implementation thread title", () => {
3057
expect(buildPlanImplementationThreadTitle("# Integrate RPC\n\nBody")).toBe(

apps/web/src/proposedPlan.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,27 @@ export function buildPlanImplementationPrompt(planMarkdown: string): string {
1616
return `PLEASE IMPLEMENT THIS PLAN:\n${planMarkdown.trim()}`;
1717
}
1818

19+
export function resolvePlanFollowUpSubmission(input: {
20+
draftText: string;
21+
planMarkdown: string;
22+
}): {
23+
text: string;
24+
interactionMode: "default" | "plan";
25+
} {
26+
const trimmedDraftText = input.draftText.trim();
27+
if (trimmedDraftText.length > 0) {
28+
return {
29+
text: trimmedDraftText,
30+
interactionMode: "plan",
31+
};
32+
}
33+
34+
return {
35+
text: buildPlanImplementationPrompt(input.planMarkdown),
36+
interactionMode: "default",
37+
};
38+
}
39+
1940
export function buildPlanImplementationThreadTitle(planMarkdown: string): string {
2041
const title = proposedPlanTitle(planMarkdown);
2142
if (!title) {

0 commit comments

Comments
 (0)