From 4805182d0cfdd416f1685ca6064c14a3d306d850 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Wed, 1 Jul 2026 09:24:50 -0700 Subject: [PATCH] FN-7369: add custom answers to Planning Mode confirms Planning Mode confirm prompts can now preserve a user-authored Other answer instead of forcing Yes or No. - Add an Other option with a textarea to confirm-style Planning Mode questions. - Submit confirm Other answers with the shared `_other` payload and render them in agent/history formatting. - Cover confirm Other behavior in modal flow and formatter tests. - Add a patch changeset for the published CLI package. Files changed: .changeset/fn-7369-confirm-other.md | 7 ++ .../dashboard/app/components/PlanningModeModal.css | 10 ++ .../dashboard/app/components/PlanningModeModal.tsx | 74 +++++++++--- .../PlanningModeModal.planning-flow.test.tsx | 125 +++++++++++++++++++++ .../planning-interview-formatters.test.ts | 27 +++++ packages/dashboard/src/planning.ts | 10 +- 6 files changed, 234 insertions(+), 19 deletions(-) Fusion-Task-Id: FN-7369 Fusion-Task-Lineage: 67b4d943-8ff3-4502-bca1-7e74eb95ac06 Co-authored-by: Fusion (runfusion.ai) --- .changeset/fn-7369-confirm-other.md | 7 + .../app/components/PlanningModeModal.css | 10 ++ .../app/components/PlanningModeModal.tsx | 74 ++++++++--- .../PlanningModeModal.planning-flow.test.tsx | 125 ++++++++++++++++++ .../planning-interview-formatters.test.ts | 27 ++++ packages/dashboard/src/planning.ts | 10 +- 6 files changed, 234 insertions(+), 19 deletions(-) create mode 100644 .changeset/fn-7369-confirm-other.md diff --git a/.changeset/fn-7369-confirm-other.md b/.changeset/fn-7369-confirm-other.md new file mode 100644 index 0000000000..d7cf313df3 --- /dev/null +++ b/.changeset/fn-7369-confirm-other.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Let Planning Mode Yes/No questions accept a custom Other answer. +category: fix +dev: Extends confirm-question handling to preserve user-authored alternatives via `_other`. diff --git a/packages/dashboard/app/components/PlanningModeModal.css b/packages/dashboard/app/components/PlanningModeModal.css index 7f86b2161a..d09d11d632 100644 --- a/packages/dashboard/app/components/PlanningModeModal.css +++ b/packages/dashboard/app/components/PlanningModeModal.css @@ -1033,6 +1033,12 @@ An empty footer must NOT reserve vertical space or paint its divider band. When gap: var(--space-sm); } +.planning-confirm-answer { + display: flex; + flex-direction: column; + gap: var(--space-sm); +} + .planning-confirm-group { display: flex; gap: var(--space-md); @@ -1732,6 +1738,10 @@ Tablet embedded Planning keeps the desktop two-pane shell, so the summary footer } /* Confirm buttons: mobile-friendly sizing */ + .planning-confirm-group { + flex-direction: column; + } + .planning-confirm-btn { min-height: 36px; padding: var(--space-sm) var(--space-md); diff --git a/packages/dashboard/app/components/PlanningModeModal.tsx b/packages/dashboard/app/components/PlanningModeModal.tsx index 8012151ab7..37c3572e63 100644 --- a/packages/dashboard/app/components/PlanningModeModal.tsx +++ b/packages/dashboard/app/components/PlanningModeModal.tsx @@ -2465,7 +2465,14 @@ function QuestionForm({ question: rawQuestion, progress, historyEntries, onSubmi if (question.type === "text") { nextResponse = { [question.id]: textValue }; } else if (question.type === "confirm") { - nextResponse = { [question.id]: response[question.id] === true }; + const trimmedOther = otherValue.trim(); + /* + FNXC:PlanningInterview 2026-07-01-00:00: + GitHub #1832 requires Yes/No Planning Mode questions to offer an Other path so users can replace a forced boolean with their own answer. Reuse the reserved `_other` payload shape used by structured selection questions instead of inventing a confirm-only custom-answer contract. + */ + nextResponse = isOtherSelected && trimmedOther.length > 0 + ? { [PLANNING_OTHER_RESPONSE_KEY]: trimmedOther } + : { [question.id]: response[question.id] === true }; } else if (question.type === "single_select") { const trimmedOther = otherValue.trim(); /* @@ -2522,7 +2529,7 @@ function QuestionForm({ question: rawQuestion, progress, historyEntries, onSubmi */ return (Array.isArray(response[question.id] as unknown) && (response[question.id] as unknown[]).length > 0) || (isOtherSelected && otherValue.trim().length > 0); case "confirm": - return response[question.id] !== undefined; + return response[question.id] !== undefined || (isOtherSelected && otherValue.trim().length > 0); default: return true; } @@ -2687,21 +2694,54 @@ function QuestionForm({ question: rawQuestion, progress, historyEntries, onSubmi )} {question.type === "confirm" && ( -
- - +
+
+ + + +
+ {isOtherSelected && ( +
+