@@ -14,7 +14,7 @@ import type {
1414 Workflow ,
1515} from '@shared/types/messages' ;
1616import type React from 'react' ;
17- import { useCallback , useEffect , useMemo , useState } from 'react' ;
17+ import { useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
1818import { ProcessingOverlay } from './components/common/ProcessingOverlay' ;
1919import { SimpleOverlay } from './components/common/SimpleOverlay' ;
2020import { ConfirmDialog } from './components/dialogs/ConfirmDialog' ;
@@ -35,7 +35,7 @@ import { useCollapsiblePanel } from './hooks/useCollapsiblePanel';
3535import { useIsCompactMode } from './hooks/useWindowWidth' ;
3636import { useTranslation } from './i18n/i18n-context' ;
3737import { vscode } from './main' ;
38- import { deserializeWorkflow } from './services/workflow-service' ;
38+ import { deserializeWorkflow , serializeWorkflow } from './services/workflow-service' ;
3939import { useRefinementStore } from './stores/refinement-store' ;
4040import { useWorkflowStore } from './stores/workflow-store' ;
4141import type { RefinementChatState } from './types/refinement-chat-state' ;
@@ -47,10 +47,16 @@ const App: React.FC = () => {
4747 confirmDeleteNodes,
4848 cancelDeleteNodes,
4949 activeWorkflow,
50+ nodes,
51+ edges,
52+ workflowName,
53+ workflowDescription,
54+ subAgentFlows,
5055 setNodes,
5156 setEdges,
5257 setWorkflowName,
5358 setActiveWorkflow,
59+ updateActiveWorkflowMetadata,
5460 isPropertyOverlayOpen,
5561 selectedNodeId,
5662 activeSubAgentFlowId,
@@ -90,6 +96,65 @@ const App: React.FC = () => {
9096 refinementStore . closeChat ( ) ;
9197 } , [ refinementStore ] ) ;
9298
99+ // Issue #384: Sync conversation history from refinement-store to workflow-store
100+ // This ensures that conversation history is preserved when the refinement panel
101+ // is collapsed/expanded, and is included when the workflow is saved.
102+ const prevHistoryRef = useRef ( refinementStore . conversationHistory ) ;
103+ useEffect ( ( ) => {
104+ const conversationHistory = refinementStore . conversationHistory ;
105+
106+ // Skip if history hasn't changed (same reference)
107+ if ( conversationHistory === prevHistoryRef . current ) {
108+ return ;
109+ }
110+ prevHistoryRef . current = conversationHistory ;
111+
112+ // Only sync if we have both an activeWorkflow and conversation history
113+ if ( activeWorkflow && conversationHistory ) {
114+ updateActiveWorkflowMetadata ( { conversationHistory } ) ;
115+ }
116+ } , [ refinementStore . conversationHistory , activeWorkflow , updateActiveWorkflowMetadata ] ) ;
117+
118+ // Issue #388: Sync activeWorkflow when canvas (nodes/edges) changes
119+ // This ensures that AI refinement always sees the current canvas state,
120+ // not a stale snapshot from when the panel was opened.
121+ // Note: Use updateActiveWorkflowMetadata (not setActiveWorkflow) to avoid
122+ // updating nodes/edges which would cause an infinite loop.
123+ const prevNodesRef = useRef ( nodes ) ;
124+ const prevEdgesRef = useRef ( edges ) ;
125+ useEffect ( ( ) => {
126+ // Skip if nodes/edges haven't changed (same reference)
127+ if ( nodes === prevNodesRef . current && edges === prevEdgesRef . current ) {
128+ return ;
129+ }
130+ prevNodesRef . current = nodes ;
131+ prevEdgesRef . current = edges ;
132+
133+ // Only sync if we have an activeWorkflow and nodes (non-empty canvas)
134+ if ( activeWorkflow && nodes . length > 0 ) {
135+ const workflow = serializeWorkflow (
136+ nodes ,
137+ edges ,
138+ workflowName || 'Untitled' ,
139+ workflowDescription || undefined ,
140+ activeWorkflow . conversationHistory ,
141+ subAgentFlows
142+ ) ;
143+ // Preserve original ID
144+ workflow . id = activeWorkflow . id ;
145+ // Update only activeWorkflow without touching nodes/edges
146+ updateActiveWorkflowMetadata ( workflow ) ;
147+ }
148+ } , [
149+ nodes ,
150+ edges ,
151+ workflowName ,
152+ workflowDescription ,
153+ subAgentFlows ,
154+ activeWorkflow ,
155+ updateActiveWorkflowMetadata ,
156+ ] ) ;
157+
93158 // App mode: null = loading, 'edit' = full editor, 'preview' = read-only preview
94159 // Start with null to prevent flashing the wrong UI
95160 const [ mode , setMode ] = useState < 'edit' | 'preview' | null > ( null ) ;
0 commit comments