diff options
| author | blackhao <13851610112@163.com> | 2025-12-06 01:30:57 -0600 |
|---|---|---|
| committer | blackhao <13851610112@163.com> | 2025-12-06 01:30:57 -0600 |
| commit | 93dbe11014cf967690727c25e89d9d1075008c24 (patch) | |
| tree | e168becbfff0e699f49021c1b3de6918e7f0a124 /frontend/src/store | |
| parent | bcb44d5a7c4b17afd7ba64be5b497d74afc69fb6 (diff) | |
Diffstat (limited to 'frontend/src/store')
| -rw-r--r-- | frontend/src/store/flowStore.ts | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/frontend/src/store/flowStore.ts b/frontend/src/store/flowStore.ts index d2114aa..0c90357 100644 --- a/frontend/src/store/flowStore.ts +++ b/frontend/src/store/flowStore.ts @@ -38,6 +38,9 @@ export interface NodeData { systemPrompt: string; userPrompt: string; mergeStrategy: 'raw' | 'smart'; + enableGoogleSearch?: boolean; + reasoningEffort: 'low' | 'medium' | 'high'; // For OpenAI reasoning models + disabled?: boolean; // Greyed out, no interaction // Traces logic traces: Trace[]; // INCOMING Traces @@ -53,10 +56,21 @@ export interface NodeData { export type LLMNode = Node<NodeData>; +// Archived node template (for reuse) +export interface ArchivedNode { + id: string; + label: string; + model: string; + systemPrompt: string; + temperature: number; + reasoningEffort: 'low' | 'medium' | 'high'; +} + interface FlowState { nodes: LLMNode[]; edges: Edge[]; selectedNodeId: string | null; + archivedNodes: ArchivedNode[]; // Stored node templates onNodesChange: OnNodesChange; onEdgesChange: OnEdgesChange; @@ -72,6 +86,16 @@ interface FlowState { deleteEdge: (edgeId: string) => void; deleteNode: (nodeId: string) => void; deleteBranch: (startNodeId?: string, startEdgeId?: string) => void; + + // Archive actions + toggleNodeDisabled: (nodeId: string) => void; + archiveNode: (nodeId: string) => void; + removeFromArchive: (archiveId: string) => void; + createNodeFromArchive: (archiveId: string, position: { x: number; y: number }) => void; + + // Trace disable + toggleTraceDisabled: (edgeId: string) => void; + updateEdgeStyles: () => void; propagateTraces: () => void; } @@ -90,6 +114,7 @@ const useFlowStore = create<FlowState>((set, get) => ({ nodes: [], edges: [], selectedNodeId: null, + archivedNodes: [], onNodesChange: (changes: NodeChange[]) => { set({ @@ -274,6 +299,172 @@ const useFlowStore = create<FlowState>((set, get) => ({ get().propagateTraces(); }, + toggleNodeDisabled: (nodeId: string) => { + const node = get().nodes.find(n => n.id === nodeId); + if (node) { + const newDisabled = !node.data.disabled; + // Update node data AND draggable property + set(state => ({ + nodes: state.nodes.map(n => { + if (n.id === nodeId) { + return { + ...n, + draggable: !newDisabled, // Disable dragging when node is disabled + selectable: !newDisabled, // Disable selection when node is disabled + data: { ...n.data, disabled: newDisabled } + }; + } + return n; + }) + })); + // Update edge styles to reflect disabled state + setTimeout(() => get().updateEdgeStyles(), 0); + } + }, + + archiveNode: (nodeId: string) => { + const node = get().nodes.find(n => n.id === nodeId); + if (!node) return; + + const archived: ArchivedNode = { + id: `archive_${Date.now()}`, + label: node.data.label, + model: node.data.model, + systemPrompt: node.data.systemPrompt, + temperature: node.data.temperature, + reasoningEffort: node.data.reasoningEffort || 'medium' + }; + + set(state => ({ + archivedNodes: [...state.archivedNodes, archived] + })); + }, + + removeFromArchive: (archiveId: string) => { + set(state => ({ + archivedNodes: state.archivedNodes.filter(a => a.id !== archiveId) + })); + }, + + createNodeFromArchive: (archiveId: string, position: { x: number; y: number }) => { + const archived = get().archivedNodes.find(a => a.id === archiveId); + if (!archived) return; + + const newNode: LLMNode = { + id: `node_${Date.now()}`, + type: 'llmNode', + position, + data: { + label: archived.label, + model: archived.model, + temperature: archived.temperature, + systemPrompt: archived.systemPrompt, + userPrompt: '', + mergeStrategy: 'smart', + reasoningEffort: archived.reasoningEffort, + traces: [], + outgoingTraces: [], + forkedTraces: [], + activeTraceIds: [], + response: '', + status: 'idle', + inputs: 1 + } + }; + + get().addNode(newNode); + }, + + toggleTraceDisabled: (edgeId: string) => { + const { edges, nodes } = get(); + const edge = edges.find(e => e.id === edgeId); + if (!edge) return; + + // Find all nodes connected through this trace (BIDIRECTIONAL) + const nodesInTrace = new Set<string>(); + const visitedEdges = new Set<string>(); + + // Traverse downstream (source -> target direction) + const traverseDownstream = (currentNodeId: string) => { + nodesInTrace.add(currentNodeId); + + const outgoing = edges.filter(e => e.source === currentNodeId); + outgoing.forEach(nextEdge => { + if (visitedEdges.has(nextEdge.id)) return; + visitedEdges.add(nextEdge.id); + traverseDownstream(nextEdge.target); + }); + }; + + // Traverse upstream (target -> source direction) + const traverseUpstream = (currentNodeId: string) => { + nodesInTrace.add(currentNodeId); + + const incoming = edges.filter(e => e.target === currentNodeId); + incoming.forEach(prevEdge => { + if (visitedEdges.has(prevEdge.id)) return; + visitedEdges.add(prevEdge.id); + traverseUpstream(prevEdge.source); + }); + }; + + // Start bidirectional traversal from clicked edge + visitedEdges.add(edge.id); + + // Go upstream from source (including source itself) + traverseUpstream(edge.source); + + // Go downstream from target (including target itself) + traverseDownstream(edge.target); + + // Check if any node in this trace is disabled + const anyDisabled = Array.from(nodesInTrace).some( + nodeId => nodes.find(n => n.id === nodeId)?.data.disabled + ); + + // Toggle: if any disabled -> enable all, else disable all + const newDisabledState = !anyDisabled; + + set(state => ({ + nodes: state.nodes.map(node => { + if (nodesInTrace.has(node.id)) { + return { + ...node, + draggable: !newDisabledState, + selectable: !newDisabledState, + data: { ...node.data, disabled: newDisabledState } + }; + } + return node; + }) + })); + + // Update edge styles + get().updateEdgeStyles(); + }, + + updateEdgeStyles: () => { + const { nodes, edges } = get(); + + const updatedEdges = edges.map(edge => { + const sourceNode = nodes.find(n => n.id === edge.source); + const targetNode = nodes.find(n => n.id === edge.target); + + const isDisabled = sourceNode?.data.disabled || targetNode?.data.disabled; + + return { + ...edge, + style: { + ...edge.style, + opacity: isDisabled ? 0.3 : 1, + strokeDasharray: isDisabled ? '5,5' : undefined + } + }; + }); + + set({ edges: updatedEdges }); + }, + propagateTraces: () => { const { nodes, edges } = get(); |
