WIP - using deep agent to create dog using workflow

This commit is contained in:
Francisco Gaona
2026-01-17 22:51:53 +01:00
parent ded413b99b
commit de65aa4025
26 changed files with 2288 additions and 193 deletions

View File

@@ -1,43 +1,153 @@
import { Background, Controls, MiniMap, ReactFlow, useEdgesState, useNodesState } from '@xyflow/react'
import { useCallback, useEffect } from 'react'
import {
Background,
Controls,
MiniMap,
ReactFlow,
useEdgesState,
useNodesState,
addEdge,
Connection,
Edge,
Node,
Panel,
} from '@xyflow/react'
import '@xyflow/react/dist/style.css'
import './styles.css'
const initialNodes = [
{ id: 'start', data: { label: 'Start' }, position: { x: 0, y: 0 } },
{ id: 'llm', data: { label: 'LLM Decision' }, position: { x: 220, y: 0 } },
{ id: 'tool', data: { label: 'Tool Node' }, position: { x: 440, y: 0 } },
{ id: 'end', data: { label: 'End' }, position: { x: 660, y: 0 } },
const nodeTypes = {
Start: { style: { background: '#22c55e', color: 'white', padding: 10, borderRadius: 5 } },
LLMDecisionNode: { style: { background: '#3b82f6', color: 'white', padding: 10, borderRadius: 5 } },
ToolNode: { style: { background: '#f59e0b', color: 'white', padding: 10, borderRadius: 5 } },
HumanInputNode: { style: { background: '#8b5cf6', color: 'white', padding: 10, borderRadius: 5 } },
End: { style: { background: '#ef4444', color: 'white', padding: 10, borderRadius: 5 } },
}
const initialNodes: Node[] = [
{
id: 'start-1',
type: 'default',
data: { label: '🟢 Start', type: 'Start' },
position: { x: 250, y: 50 },
style: nodeTypes.Start.style,
},
{
id: 'end-1',
type: 'default',
data: { label: '🔴 End', type: 'End' },
position: { x: 250, y: 400 },
style: nodeTypes.End.style,
},
]
const initialEdges = [
{ id: 'e1-2', source: 'start', target: 'llm' },
{ id: 'e2-3', source: 'llm', target: 'tool' },
{ id: 'e3-4', source: 'tool', target: 'end' },
]
const initialEdges: Edge[] = []
export const App = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes)
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges)
const onConnect = useCallback(
(params: Connection) => setEdges((eds) => addEdge(params, eds)),
[setEdges]
)
// Send graph updates to parent window
const notifyParent = useCallback(() => {
const graphData = {
id: 'process-graph',
name: 'Process',
nodes: nodes.map((node) => ({
id: node.id,
type: node.data.type || 'Start',
position: node.position,
data: node.data,
})),
edges: edges.map((edge) => ({
id: edge.id,
source: edge.source,
target: edge.target,
condition: edge.data?.condition,
})),
}
window.parent.postMessage(
{
type: 'GRAPH_UPDATED',
payload: graphData,
},
'*'
)
}, [nodes, edges])
// Listen for graph load from parent
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
if (event.data.type === 'LOAD_GRAPH') {
const graph = event.data.payload
if (graph && graph.nodes && graph.edges) {
setNodes(
graph.nodes.map((node: any) => ({
id: node.id,
type: 'default',
data: { label: node.data.label || node.type, ...node.data },
position: node.position,
style: nodeTypes[node.type as keyof typeof nodeTypes]?.style || {},
}))
)
setEdges(
graph.edges.map((edge: any) => ({
id: edge.id,
source: edge.source,
target: edge.target,
data: edge.condition ? { condition: edge.condition } : undefined,
}))
)
}
}
}
window.addEventListener('message', handleMessage)
return () => window.removeEventListener('message', handleMessage)
}, [setNodes, setEdges])
// Notify parent on changes
useEffect(() => {
notifyParent()
}, [nodes, edges, notifyParent])
const addNode = (type: string) => {
const newNode: Node = {
id: `${type.toLowerCase()}-${Date.now()}`,
type: 'default',
data: { label: `${type}`, type },
position: { x: Math.random() * 400 + 50, y: Math.random() * 300 + 100 },
style: nodeTypes[type as keyof typeof nodeTypes]?.style || {},
}
setNodes((nds) => nds.concat(newNode))
}
return (
<div className="editor-shell">
<header className="editor-header">
<h1>AI Process Builder</h1>
<p>Design tenant workflows with deterministic execution.</p>
</header>
<div className="editor-canvas">
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
fitView
>
<MiniMap />
<Controls />
<Background />
</ReactFlow>
</div>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
>
<Panel position="top-left" className="node-palette">
<h3>Node Palette</h3>
<button onClick={() => addNode('LLMDecisionNode')}>🔵 LLM Decision</button>
<button onClick={() => addNode('ToolNode')}>🟠 Tool</button>
<button onClick={() => addNode('HumanInputNode')}>🟣 Human Input</button>
<button onClick={() => addNode('End')}>🔴 End</button>
</Panel>
<MiniMap />
<Controls />
<Background />
</ReactFlow>
</div>
)
}

View File

@@ -4,30 +4,68 @@ body {
color: #0f172a;
}
#root {
width: 100%;
height: 100vh;
}
.editor-shell {
display: flex;
flex-direction: column;
height: 100vh;
width: 100%;
}
.editor-header {
padding: 16px 20px;
border-bottom: 1px solid #e2e8f0;
background: #fff;
.node-palette {
background: white;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
min-width: 150px;
}
.editor-header h1 {
margin: 0 0 4px;
font-size: 18px;
.node-palette h3 {
margin: 0 0 12px 0;
font-size: 14px;
font-weight: 600;
color: #1e293b;
}
.editor-header p {
margin: 0;
.node-palette button {
display: block;
width: 100%;
padding: 8px 12px;
margin-bottom: 6px;
background: white;
border: 1px solid #e2e8f0;
border-radius: 6px;
font-size: 13px;
cursor: pointer;
text-align: left;
transition: all 0.2s;
}
.node-palette button:hover {
background: #f1f5f9;
border-color: #cbd5e1;
}
.node-palette button:active {
background: #e2e8f0;
}
.react-flow__node {
font-size: 12px;
color: #64748b;
font-weight: 500;
}
.editor-canvas {
flex: 1;
background: #f8fafc;
.react-flow__edge-path {
stroke: #64748b;
stroke-width: 2;
}
.react-flow__edge.selected .react-flow__edge-path {
stroke: #3b82f6;
}