diff --git a/.changeset/fn-210-planning-session-prompt.md b/.changeset/fn-210-planning-session-prompt.md new file mode 100644 index 0000000000..687c64d351 --- /dev/null +++ b/.changeset/fn-210-planning-session-prompt.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": minor +--- + +summary: Planning Mode history now shows the original prompt that started the session, read-only. +category: feature +dev: Adds PlanningSessionPrompt to History, error, and plan-review Q&A surfaces. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index e2e626e9e0..2d889f9cff 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -683,6 +683,9 @@ When an active Planning AI generation appears stuck, Planning Mode automatically Use **New session** to restart planning with a different idea. + +The **History** panel, the error panel, and plan review's **Show user Q&A** section show the original request that started the session in a read-only box above the questions and answers. Reading, scrolling, selecting, or copying this text does not edit it or change the session. When an older or incomplete session has no saved starting text, Planning Mode omits the box entirely. + Planning Mode uses a dedicated collaborative system prompt. It investigates relevant repository and board context, explores assumptions and tradeoffs, considers decomposition choices without automatically creating child tasks, and sharpens concrete deliverables with observable acceptance criteria. This is separate from task triage and the executor-ready **PROMPT.md** generated after task creation. An explicitly configured nonblank `planning-system` prompt override replaces the complete dedicated system prompt; blank or absent values retain the default interview. diff --git a/packages/dashboard/app/components/PlanningModeModal.css b/packages/dashboard/app/components/PlanningModeModal.css index 4e0edab906..2eba685cb7 100644 --- a/packages/dashboard/app/components/PlanningModeModal.css +++ b/packages/dashboard/app/components/PlanningModeModal.css @@ -248,6 +248,10 @@ The embedded planning header must be a visual SIBLING of MissionManager's inline overscroll-behavior: contain; } +.planning-history-scroll .planning-session-prompt { + margin-bottom: var(--space-lg); +} + .planning-history-scroll .conversation-history { max-height: none; margin: 0; @@ -2338,6 +2342,11 @@ mobile and desktop offer the same View task / Return to sessions choices. padding: var(--space-lg); } + .planning-history-scroll .planning-session-prompt { + width: 100%; + max-width: 100%; + } + /* FNXC:PlanningMode 2026-07-21-18:34: Mobile question and plan-review panes were double-inset: workspace gutter + scroll padding + nested card chrome on top of the pane frame. Drop the outer gutter and pane chrome so content sits flush edge-to-edge like desktop, keep a light tab strip inset, and leave readable content padding on the question panel / plan document only. Clear the desktop column divider so a solo question/plan card is not edged by a right border. diff --git a/packages/dashboard/app/components/PlanningModeModal.tsx b/packages/dashboard/app/components/PlanningModeModal.tsx index ee8a26036e..7fe435d149 100644 --- a/packages/dashboard/app/components/PlanningModeModal.tsx +++ b/packages/dashboard/app/components/PlanningModeModal.tsx @@ -56,6 +56,7 @@ import { getRelativeTimeBucket } from "../utils/relativeTimeAgo"; import { Lightbulb, X, Loader2, CheckCircle, ArrowLeft, ArrowRight, Sparkles, Trash2, RefreshCw, ChevronLeft, MessageSquarePlus, AlertCircle, Clock, HelpCircle, StopCircle, Archive, ArchiveRestore, Pencil, History } from "lucide-react"; import { CustomModelDropdown } from "./CustomModelDropdown"; import { ConversationHistory } from "./ConversationHistory"; +import { PlanningSessionPrompt } from "./PlanningSessionPrompt"; import { ThinkingTrace } from "./ThinkingTrace"; import { MailboxMessageContent } from "./MailboxMessageContent"; import { OnboardingDisclosure } from "./OnboardingDisclosure"; @@ -445,8 +446,11 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat /* FNXC:Planning 2026-07-15-00:00: FN-8003 keeps the started prompt separate from the editable composer so users can recover the original idea when an interview errors or drifts off track. The composer may be reset or reused, but this value belongs only to the active session. + + FNXC:PlanningHistory 2026-08-28-03:34: + FN-210 renders the active session's initiating prompt read-only wherever Planning Mode presents its question-and-answer history. */ - const [_activePlanPrompt, setActivePlanPrompt] = useState(""); + const [activePlanPrompt, setActivePlanPrompt] = useState(""); const [view, setView] = useState({ type: "initial" }); const [error, setError] = useState(null); // FNXC:PlanningMultiTask 2026-08-03-18:32: Latest task created from this plan. Passing its id with the next explicit Proceed action @@ -2003,12 +2007,20 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat typed or selected local answer before its enabled Next action can submit it. A different session still takes the neutral loader so its prior turn never remains visible. */ - const preservesActiveWorkspace = currentSessionIdRef.current === sessionId + const isDifferentSession = currentSessionIdRef.current !== sessionId; + const preservesActiveWorkspace = !isDifferentSession && (viewRef.current.type === "question" || viewRef.current.type === "plan_review"); streamConnectionRef.current?.close(); streamConnectionRef.current = null; currentSessionIdRef.current = sessionId; + /* + FNXC:PlanningHistory 2026-08-28-03:47: + The History overlay remains mounted while an externally selected session loads. Clear the + initiating prompt at a different-session load boundary so the prior session's prompt cannot + appear under the new selection, while same-session refreshes retain their visible prompt. + */ + if (isDifferentSession) setActivePlanPrompt(""); setError(null); /* FNXC:PlanningMultiTask 2026-07-24-01:40: @@ -2988,10 +3000,10 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat }); } else { draftSessionIdRef.current = sessionId; - setInitialPlan(_activePlanPrompt); + setInitialPlan(activePlanPrompt); setView({ type: "initial" }); } - }, [_activePlanPrompt, projectId, workspaceQuestion]); + }, [activePlanPrompt, projectId, workspaceQuestion]); const handleRetryFromError = useCallback(async () => { if (view.type !== "error") { @@ -3685,6 +3697,7 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
+ {historyPanelEntries.length > 0 ? ( // FNXC:PlanningHistory 2026-07-20-23:24: FN-8449 keeps history thinking collapsed so operators can scan Q&A first; the existing toggle remains available to expand it, matching the FN-7974 chat default. @@ -3979,6 +3992,7 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat {view.type === "error" && (
+ {conversationHistory.length > 0 && ( <> @@ -4225,6 +4239,7 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat projectId={projectId} summary={editedSummary} historyEntries={conversationHistory} + initialPrompt={activePlanPrompt} onSummaryChange={setEditedSummary} tasks={tasks} branchMode={branchMode} @@ -4664,6 +4679,7 @@ interface SummaryViewProps { projectId?: string; summary: PlanningSummary; historyEntries: ConversationHistoryEntry[]; + initialPrompt?: string; onSummaryChange: (summary: PlanningSummary) => void; tasks: Task[]; branchMode: "project-default" | "auto-new" | "existing" | "custom-new"; @@ -4684,6 +4700,7 @@ export function SummaryView({ projectId, summary: rawSummary, historyEntries, + initialPrompt, onSummaryChange, tasks, branchMode, @@ -4743,6 +4760,7 @@ export function SummaryView({
{historyEntries.length > 0 && ( +
diff --git a/packages/dashboard/app/components/PlanningSessionPrompt.css b/packages/dashboard/app/components/PlanningSessionPrompt.css new file mode 100644 index 0000000000..e7e4bffcf6 --- /dev/null +++ b/packages/dashboard/app/components/PlanningSessionPrompt.css @@ -0,0 +1,29 @@ +.planning-session-prompt { + display: flex; + flex-direction: column; + gap: var(--space-sm); + min-width: 0; +} + +.planning-session-prompt-label { + color: var(--text-muted); + font-size: var(--font-size-sm); + font-weight: 600; +} + +.planning-session-prompt-text { + box-sizing: border-box; + width: 100%; + min-width: 0; + padding: var(--space-md); + border: solid var(--btn-border-width) color-mix(in srgb, var(--border) 82%, transparent); + border-radius: var(--radius-lg); + background: var(--card); + color: var(--text); + font: inherit; + line-height: 1.5; + white-space: pre-wrap; + overflow-y: auto; + resize: none; + cursor: default; +} diff --git a/packages/dashboard/app/components/PlanningSessionPrompt.tsx b/packages/dashboard/app/components/PlanningSessionPrompt.tsx new file mode 100644 index 0000000000..fe3a6931d0 --- /dev/null +++ b/packages/dashboard/app/components/PlanningSessionPrompt.tsx @@ -0,0 +1,37 @@ +import "./PlanningSessionPrompt.css"; +import { useTranslation } from "react-i18next"; +import { useAutosizeTextarea } from "../hooks/useAutosizeTextarea"; + +interface PlanningSessionPromptProps { + prompt?: string; + testId: string; +} + +/** + * FNXC:PlanningHistory 2026-08-28-03:34: + * Planning Mode session history shows the operator's initiating prompt read-only next to the Q&A. Sessions without a saved prompt render nothing instead of leaving an empty history shell. + */ +export function PlanningSessionPrompt({ prompt, testId }: PlanningSessionPromptProps) { + const { t } = useTranslation("app"); + const { ref } = useAutosizeTextarea({ value: prompt ?? "", minHeight: 64, maxHeight: 240 }); + + if (!prompt?.trim()) { + return null; + } + + const label = t("planning.initialPromptLabel", "Prompt that started this session"); + + return ( +
+ {label} +