|
|
from dataclasses import asdict, dataclass, field |
|
|
import os |
|
|
import pickle |
|
|
from typing import Dict, List, Optional, Any |
|
|
import gradio as gr |
|
|
import json |
|
|
import tempfile |
|
|
import asyncio |
|
|
import uuid |
|
|
from dataclasses import dataclass, asdict |
|
|
from typing import List, Dict, Optional, Any |
|
|
from openai import AsyncOpenAI |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
COMPONENT_HIERARCHY = { |
|
|
"HIGH_LEVEL": { |
|
|
"CLASS": { |
|
|
"description": "Class diagrams and object-oriented design elements", |
|
|
"color": "#4CAF50", |
|
|
"icon": "📋", |
|
|
"shape": "rect", |
|
|
"sub_components": ["ATTRIBUTE", "METHOD", "RELATIONSHIP", "INHERITANCE", "COMPOSITION", "AGGREGATION"] |
|
|
}, |
|
|
"USECASE": { |
|
|
"description": "Use case diagrams and system interactions", |
|
|
"color": "#2196F3", |
|
|
"icon": "🎯", |
|
|
"shape": "ellipse", |
|
|
"sub_components": ["ACTOR", "USECASE", "INCLUDE", "EXTEND", "SYSTEM_BOUNDARY"] |
|
|
}, |
|
|
"SEQUENCE": { |
|
|
"description": "Sequence diagrams and message flows", |
|
|
"color": "#FF9800", |
|
|
"icon": "⚡", |
|
|
"shape": "rect", |
|
|
"sub_components": ["LIFELINE", "MESSAGE", "ACTIVATION", "ALT_FRAME", "LOOP_FRAME"] |
|
|
}, |
|
|
"ACTIVITY": { |
|
|
"description": "Activity diagrams and workflow processes", |
|
|
"color": "#00BCD4", |
|
|
"icon": "🔄", |
|
|
"shape": "diamond", |
|
|
"sub_components": ["ACTION", "DECISION", "MERGE", "FORK", "JOIN", "START_NODE", "END_NODE"] |
|
|
}, |
|
|
"STATE": { |
|
|
"description": "State machine diagrams and object states", |
|
|
"color": "#9C27B0", |
|
|
"icon": "🔄", |
|
|
"shape": "ellipse", |
|
|
"sub_components": ["STATE", "TRANSITION", "ENTRY_ACTION", "EXIT_ACTION", "INTERNAL_ACTION"] |
|
|
}, |
|
|
"OBJECT": { |
|
|
"description": "Object diagrams and runtime instances", |
|
|
"color": "#795548", |
|
|
"icon": "📦", |
|
|
"shape": "rect", |
|
|
"sub_components": ["INSTANCE", "LINK", "OBJECT_ATTRIBUTE", "OBJECT_VALUE"] |
|
|
}, |
|
|
"COMPONENT": { |
|
|
"description": "Component diagrams and system architecture", |
|
|
"color": "#009688", |
|
|
"icon": "🧩", |
|
|
"shape": "rect", |
|
|
"sub_components": ["COMPONENT", "INTERFACE", "PORT", "ARTIFACT", "DEPENDENCY"] |
|
|
}, |
|
|
"DEPLOYMENT": { |
|
|
"description": "Deployment diagrams and physical architecture", |
|
|
"color": "#FF5722", |
|
|
"icon": "🌐", |
|
|
"shape": "rect", |
|
|
"sub_components": ["NODE", "ARTIFACT", "DEVICE", "EXECUTION_ENVIRONMENT", "COMMUNICATION_PATH"] |
|
|
}, |
|
|
"PACKAGE": { |
|
|
"description": "Package diagrams and module organization", |
|
|
"color": "#E91E63", |
|
|
"icon": "📦", |
|
|
"shape": "folder", |
|
|
"sub_components": ["PACKAGE", "SUBPACKAGE", "PACKAGE_DEPENDENCY", "IMPORT", "ACCESS"] |
|
|
}, |
|
|
"SYSTEM": { |
|
|
"description": "Top-level system architecture containing all components", |
|
|
"color": "#333333", |
|
|
"icon": "🌐", |
|
|
"shape": "folder", |
|
|
"sub_components": ["AGENT", "USER", "TOOL", "DATA", "PROCESSOR", "ROUTER", "INFRASTRUCTURE", "CONFIG"] |
|
|
}, |
|
|
"AGENT": { |
|
|
"description": "Autonomous reasoning and decision-making units", |
|
|
"color": "#4CAF50", |
|
|
"icon": "🤖", |
|
|
"shape": "rect", |
|
|
"sub_components": ["REASONING_AGENT", "ACTION_AGENT", "PLANNER_AGENT", "REACT_AGENT", "MULTI_AGENT"] |
|
|
}, |
|
|
"USER": { |
|
|
"description": "User interaction points and interfaces", |
|
|
"color": "#9C27B0", |
|
|
"icon": "👤", |
|
|
"shape": "ellipse", |
|
|
"sub_components": ["USER_INPUT", "USER_OUTPUT", "MULTIMODAL_INTERFACE"] |
|
|
}, |
|
|
"TOOL": { |
|
|
"description": "External functions and capabilities", |
|
|
"color": "#795548", |
|
|
"icon": "🔧", |
|
|
"shape": "hexagon", |
|
|
"sub_components": ["MCP_TOOL", "API_TOOL", "LOCAL_TOOL", "AGENT_TOOL", "FUNCTION_TOOL"] |
|
|
}, |
|
|
"DATA": { |
|
|
"description": "Data sources and storage systems", |
|
|
"color": "#009688", |
|
|
"icon": "💾", |
|
|
"shape": "cylinder", |
|
|
"sub_components": ["KNOWLEDGE_BASE", "VECTOR_DB", "DOCUMENT_STORE", "CACHE", "MEMORY"] |
|
|
}, |
|
|
"PROCESSOR": { |
|
|
"description": "Data processing and transformation units", |
|
|
"color": "#2196F3", |
|
|
"icon": "⚙️", |
|
|
"shape": "rect", |
|
|
"sub_components": ["QUERY_PROCESSOR", "CONTENT_RETRIEVAL", "PROMPT_TEMPLATE", "RESPONSE_FORMATTER"] |
|
|
}, |
|
|
"ROUTER": { |
|
|
"description": "Decision points and workflow routing", |
|
|
"color": "#FF9800", |
|
|
"icon": "🎯", |
|
|
"shape": "diamond", |
|
|
"sub_components": ["INTENT_DISCOVERY", "MODEL_SELECTOR", "WORKFLOW_ROUTER", "VALIDATOR"] |
|
|
}, |
|
|
"INFRASTRUCTURE": { |
|
|
"description": "System infrastructure and services", |
|
|
"color": "#FF5722", |
|
|
"icon": "🌐", |
|
|
"shape": "rect", |
|
|
"sub_components": ["PROVIDER", "MONITOR", "FALLBACK", "ORCHESTRATOR"] |
|
|
}, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
COMPONENT_INFO = { |
|
|
|
|
|
|
|
|
|
|
|
"CLASS": { |
|
|
"description": "Class with attributes and methods", |
|
|
"color": "#4CAF50", |
|
|
"icon": "📋", |
|
|
"shape": "rect", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Class Name", "default": "MyClass"}, |
|
|
"visibility": {"type": "dropdown", "label": "Visibility", "choices": ["public", "private", "protected"], "default": "public"}, |
|
|
"stereotype": {"type": "text", "label": "Stereotype (optional)", "default": ""}, |
|
|
"abstract": {"type": "boolean", "label": "Abstract Class", "default": False}, |
|
|
"documentation": {"type": "textarea", "label": "Documentation", "default": "Class description"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"ATTRIBUTE": { |
|
|
"shape": "rect", |
|
|
"color": "#4CAF50", |
|
|
"icon": "🏷️", |
|
|
"description": "Class attribute with visibility and type", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Attribute Name", "default": "myAttribute"}, |
|
|
"type": {"type": "text", "label": "Type", "default": "String"}, |
|
|
"visibility": {"type": "dropdown", "label": "Visibility", "choices": ["+", "-", "#"], "default": "+"}, |
|
|
"static": {"type": "boolean", "label": "Static", "default": False}, |
|
|
"final": {"type": "boolean", "label": "Final/Constant", "default": False}, |
|
|
"default_value": {"type": "text", "label": "Default Value", "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"METHOD": { |
|
|
"shape": "rect", |
|
|
"color": "#4CAF50", |
|
|
"icon": "⚙️", |
|
|
"description": "Class method with parameters and return type", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Method Name", "default": "myMethod"}, |
|
|
"return_type": {"type": "text", "label": "Return Type", "default": "void"}, |
|
|
"visibility": {"type": "dropdown", "label": "Visibility", "choices": ["+", "-", "#"], "default": "+"}, |
|
|
"static": {"type": "boolean", "label": "Static", "default": False}, |
|
|
"abstract": {"type": "boolean", "label": "Abstract", "default": False}, |
|
|
"parameters": {"type": "text", "label": "Parameters (comma-separated)", "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"INHERITANCE": { |
|
|
"shape": "line", |
|
|
"color": "#4CAF50", |
|
|
"icon": "🡅", |
|
|
"description": "Inheritance relationship (generalization)", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Relationship Name", "default": "Inheritance"}, |
|
|
"stereotype": {"type": "dropdown", "label": "Stereotype", "choices": ["<<extend>>", "<<implement>>", ""], "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"COMPOSITION": { |
|
|
"shape": "line", |
|
|
"color": "#4CAF50", |
|
|
"icon": "🔗", |
|
|
"description": "Composition relationship (strong ownership)", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Relationship Name", "default": "Composition"}, |
|
|
"multiplicity_source": {"type": "text", "label": "Source Multiplicity", "default": "1"}, |
|
|
"multiplicity_target": {"type": "text", "label": "Target Multiplicity", "default": "1..*"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"AGGREGATION": { |
|
|
"shape": "line", |
|
|
"color": "#4CAF50", |
|
|
"icon": "🔗", |
|
|
"description": "Aggregation relationship (weak ownership)", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Relationship Name", "default": "Aggregation"}, |
|
|
"multiplicity_source": {"type": "text", "label": "Source Multiplicity", "default": "0..1"}, |
|
|
"multiplicity_target": {"type": "text", "label": "Target Multiplicity", "default": "0..*"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"ASSOCIATION": { |
|
|
"shape": "line", |
|
|
"color": "#4CAF50", |
|
|
"icon": "🔗", |
|
|
"description": "Association relationship between classes", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Relationship Name", "default": "Association"}, |
|
|
"direction": {"type": "dropdown", "label": "Direction", "choices": ["bidirectional", "source_to_target", "target_to_source"], "default": "bidirectional"}, |
|
|
"multiplicity_source": {"type": "text", "label": "Source Multiplicity", "default": "1"}, |
|
|
"multiplicity_target": {"type": "text", "label": "Target Multiplicity", "default": "1"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"ACTOR": { |
|
|
"shape": "ellipse", |
|
|
"color": "#2196F3", |
|
|
"icon": "👤", |
|
|
"description": "External entity that interacts with the system", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Actor Name", "default": "User"}, |
|
|
"stereotype": {"type": "text", "label": "Stereotype (optional)", "default": ""}, |
|
|
"description": {"type": "textarea", "label": "Description", "default": "Actor description"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"USECASE": { |
|
|
"shape": "ellipse", |
|
|
"color": "#2196F3", |
|
|
"icon": "🎯", |
|
|
"description": "Specific functionality provided by the system", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Use Case Name", "default": "Login"}, |
|
|
"description": {"type": "textarea", "label": "Description", "default": "Use case description"}, |
|
|
"preconditions": {"type": "textarea", "label": "Preconditions", "default": ""}, |
|
|
"postconditions": {"type": "textarea", "label": "Postconditions", "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"INCLUDE": { |
|
|
"shape": "line", |
|
|
"color": "#2196F3", |
|
|
"icon": "➡️", |
|
|
"description": "Include relationship between use cases", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Relationship Name", "default": "Include"}, |
|
|
"stereotype": {"type": "text", "label": "<<include>>", "default": "<<include>>"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"EXTEND": { |
|
|
"shape": "line", |
|
|
"color": "#2196F3", |
|
|
"icon": "➡️", |
|
|
"description": "Extend relationship between use cases", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Relationship Name", "default": "Extend"}, |
|
|
"stereotype": {"type": "text", "label": "<<extend>>", "default": "<<extend>>"}, |
|
|
"extension_point": {"type": "text", "label": "Extension Point", "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"SYSTEM_BOUNDARY": { |
|
|
"shape": "rect", |
|
|
"color": "#2196F3", |
|
|
"icon": "🏗️", |
|
|
"description": "Boundary of the system being modeled", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "System Name", "default": "MySystem"}, |
|
|
"description": {"type": "textarea", "label": "System Description", "default": "System boundary"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"LIFELINE": { |
|
|
"shape": "rect", |
|
|
"color": "#FF9800", |
|
|
"icon": "⁞", |
|
|
"description": "Lifeline representing an object instance", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Object Name", "default": "object1"}, |
|
|
"class_name": {"type": "text", "label": "Class Name", "default": "MyClass"}, |
|
|
"stereotype": {"type": "text", "label": "Stereotype (optional)", "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"MESSAGE": { |
|
|
"shape": "line", |
|
|
"color": "#FF9800", |
|
|
"icon": "➡️", |
|
|
"description": "Message sent between lifelines", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Message Name", "default": "request()"}, |
|
|
"message_type": {"type": "dropdown", "label": "Type", "choices": ["synchronous", "asynchronous", "return"], "default": "synchronous"}, |
|
|
"stereotype": {"type": "text", "label": "Stereotype (optional)", "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"ACTIVATION": { |
|
|
"shape": "rect", |
|
|
"color": "#FF9800", |
|
|
"icon": "║", |
|
|
"description": "Activation box showing object is active", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Activation Name", "default": "Active"}, |
|
|
"duration": {"type": "number", "label": "Duration (time units)", "default": 10}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"ALT_FRAME": { |
|
|
"shape": "rect", |
|
|
"color": "#FF9800", |
|
|
"icon": "⎇", |
|
|
"description": "Alternative frame for conditional flows", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Frame Name", "default": "alt"}, |
|
|
"condition": {"type": "text", "label": "Condition", "default": "[condition]"}, |
|
|
"description": {"type": "textarea", "label": "Description", "default": "Alternative flow"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"LOOP_FRAME": { |
|
|
"shape": "rect", |
|
|
"color": "#FF9800", |
|
|
"icon": "↻", |
|
|
"description": "Loop frame for repetitive flows", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Frame Name", "default": "loop"}, |
|
|
"condition": {"type": "text", "label": "Condition", "default": "[loop condition]"}, |
|
|
"description": {"type": "textarea", "label": "Description", "default": "Loop flow"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"ACTION": { |
|
|
"shape": "rect", |
|
|
"color": "#00BCD4", |
|
|
"icon": "⚡", |
|
|
"description": "Action or activity node", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Action Name", "default": "Do Something"}, |
|
|
"description": {"type": "textarea", "label": "Description", "default": "Action description"}, |
|
|
"cost": {"type": "number", "label": "Cost/Time", "default": 0}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"DECISION": { |
|
|
"shape": "diamond", |
|
|
"color": "#00BCD4", |
|
|
"icon": "❓", |
|
|
"description": "Decision point with multiple outgoing flows", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Decision Name", "default": "Decision"}, |
|
|
"description": {"type": "textarea", "label": "Description", "default": "Decision point"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"MERGE": { |
|
|
"shape": "diamond", |
|
|
"color": "#00BCD4", |
|
|
"icon": "🡇", |
|
|
"description": "Merge point combining multiple flows", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Merge Name", "default": "Merge"}, |
|
|
"description": {"type": "textarea", "label": "Description", "default": "Merge point"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"FORK": { |
|
|
"shape": "rect", |
|
|
"color": "#00BCD4", |
|
|
"icon": "🡇", |
|
|
"description": "Fork point for parallel flows", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Fork Name", "default": "Fork"}, |
|
|
"description": {"type": "textarea", "label": "Description", "default": "Parallel fork"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"JOIN": { |
|
|
"shape": "rect", |
|
|
"color": "#00BCD4", |
|
|
"icon": "🡅", |
|
|
"description": "Join point for parallel flows", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Join Name", "default": "Join"}, |
|
|
"description": {"type": "textarea", "label": "Description", "default": "Parallel join"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"START_NODE": { |
|
|
"shape": "circle", |
|
|
"color": "#00BCD4", |
|
|
"icon": "🟢", |
|
|
"description": "Start node of activity diagram", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Start", "default": "Start"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"END_NODE": { |
|
|
"shape": "circle", |
|
|
"color": "#00BCD4", |
|
|
"icon": "🔴", |
|
|
"description": "End node of activity diagram", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "End", "default": "End"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"STATE": { |
|
|
"shape": "rect", |
|
|
"color": "#9C27B0", |
|
|
"icon": "🔄", |
|
|
"description": "State in a state machine", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "State Name", "default": "InitialState"}, |
|
|
"entry_action": {"type": "textarea", "label": "Entry Action", "default": ""}, |
|
|
"exit_action": {"type": "textarea", "label": "Exit Action", "default": ""}, |
|
|
"internal_action": {"type": "textarea", "label": "Internal Action", "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"TRANSITION": { |
|
|
"shape": "line", |
|
|
"color": "#9C27B0", |
|
|
"icon": "➡️", |
|
|
"description": "Transition between states", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Transition Name", "default": "Transition"}, |
|
|
"trigger": {"type": "text", "label": "Trigger", "default": "event"}, |
|
|
"guard_condition": {"type": "text", "label": "Guard Condition", "default": "[condition]"}, |
|
|
"action": {"type": "text", "label": "Action", "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"INSTANCE": { |
|
|
"shape": "rect", |
|
|
"color": "#795548", |
|
|
"icon": "📦", |
|
|
"description": "Object instance in runtime", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Instance Name", "default": "object1"}, |
|
|
"class_name": {"type": "text", "label": "Class Name", "default": "MyClass"}, |
|
|
"values": {"type": "textarea", "label": "Attribute Values", "default": "attr1=value1"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"LINK": { |
|
|
"shape": "line", |
|
|
"color": "#795548", |
|
|
"icon": "🔗", |
|
|
"description": "Link between object instances", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Link Name", "default": "Link"}, |
|
|
"association": {"type": "text", "label": "Association Name", "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"COMPONENT": { |
|
|
"shape": "rect", |
|
|
"color": "#009688", |
|
|
"icon": "🧩", |
|
|
"description": "Software component with interfaces", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Component Name", "default": "MyComponent"}, |
|
|
"type": {"type": "text", "label": "Component Type", "default": "Library"}, |
|
|
"version": {"type": "text", "label": "Version", "default": "1.0"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"INTERFACE": { |
|
|
"shape": "ellipse", |
|
|
"color": "#009688", |
|
|
"icon": "🔌", |
|
|
"description": "Component interface", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Interface Name", "default": "MyInterface"}, |
|
|
"type": {"type": "dropdown", "label": "Type", "choices": ["provided", "required"], "default": "provided"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"DEPENDENCY": { |
|
|
"shape": "line", |
|
|
"color": "#009688", |
|
|
"icon": "➡️", |
|
|
"description": "Dependency relationship between components", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Dependency Name", "default": "Dependency"}, |
|
|
"stereotype": {"type": "text", "label": "Stereotype", "default": "<<use>>"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"NODE": { |
|
|
"shape": "rect", |
|
|
"color": "#FF5722", |
|
|
"icon": "🖥️", |
|
|
"description": "Physical node or device", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Node Name", "default": "Server"}, |
|
|
"node_type": {"type": "text", "label": "Node Type", "default": "Device"}, |
|
|
"hardware": {"type": "text", "label": "Hardware", "default": "x86_64"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"ARTIFACT": { |
|
|
"shape": "rect", |
|
|
"color": "#FF5722", |
|
|
"icon": "📦", |
|
|
"description": "Deployable software artifact", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Artifact Name", "default": "Application.jar"}, |
|
|
"artifact_type": {"type": "text", "label": "Type", "default": "File"}, |
|
|
"version": {"type": "text", "label": "Version", "default": "1.0"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"COMMUNICATION_PATH": { |
|
|
"shape": "line", |
|
|
"color": "#FF5722", |
|
|
"icon": "📡", |
|
|
"description": "Communication path between nodes", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Path Name", "default": "Network"}, |
|
|
"protocol": {"type": "text", "label": "Protocol", "default": "TCP/IP"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"PACKAGE": { |
|
|
"shape": "folder", |
|
|
"color": "#E91E63", |
|
|
"icon": "📦", |
|
|
"description": "Package containing other elements", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Package Name", "default": "MyPackage"}, |
|
|
"namespace": {"type": "text", "label": "Namespace", "default": "com.example"}, |
|
|
"description": {"type": "textarea", "label": "Description", "default": "Package description"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"PACKAGE_DEPENDENCY": { |
|
|
"shape": "line", |
|
|
"color": "#E91E63", |
|
|
"icon": "➡️", |
|
|
"description": "Dependency between packages", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Dependency Name", "default": "Dependency"}, |
|
|
"stereotype": {"type": "text", "label": "Stereotype", "default": "<<import>>"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"SYSTEM": { |
|
|
"description": "Top-level system architecture containing all components", |
|
|
"color": "#333333", |
|
|
"icon": "🌐", |
|
|
"shape": "folder", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "System Name", "default": "AgenticSystem"}, |
|
|
"description": {"type": "textarea", "label": "System Description", "default": "Multi-agent AI system"}, |
|
|
"version": {"type": "text", "label": "System Version", "default": "1.0.0"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
"AGENT": { |
|
|
"description": "Autonomous reasoning and decision-making units", |
|
|
"color": "#4CAF50", |
|
|
"icon": "🤖", |
|
|
"shape": "rect", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Agent Name", "default": "MyAgent"}, |
|
|
"role": {"type": "textarea", "label": "Role Description", "default": "Assistant"}, |
|
|
"system_prompt": {"type": "textarea", "label": "System Prompt", "default": "You are a helpful assistant"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"REASONING_AGENT": { |
|
|
"shape": "rect", |
|
|
"color": "#4CAF50", |
|
|
"icon": "🧠", |
|
|
"description": "Performs complex reasoning tasks using chain-of-thought approaches", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Agent Name", "default": "ReasoningAgent"}, |
|
|
"reasoning_type": {"type": "dropdown", "label": "Reasoning Type", "choices": ["chain_of_thought", "tree_of_thought"], "default": "chain_of_thought"}, |
|
|
"max_steps": {"type": "number", "label": "Max Reasoning Steps", "default": 5}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"ACTION_AGENT": { |
|
|
"shape": "rect", |
|
|
"color": "#4CAF50", |
|
|
"icon": "⚡", |
|
|
"description": "Executes actions using available tools", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Agent Name", "default": "ActionAgent"}, |
|
|
"retry_attempts": {"type": "number", "label": "Retry Attempts", "default": 3}, |
|
|
"timeout_seconds": {"type": "number", "label": "Timeout Seconds", "default": 30}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"PLANNER_AGENT": { |
|
|
"shape": "rect", |
|
|
"color": "#4CAF50", |
|
|
"icon": "📋", |
|
|
"description": "Creates multi-step plans to achieve goals", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Agent Name", "default": "PlannerAgent"}, |
|
|
"max_steps": {"type": "number", "label": "Max Plan Steps", "default": 20}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"REACT_AGENT": { |
|
|
"shape": "rect", |
|
|
"color": "#4CAF50", |
|
|
"icon": "🔄", |
|
|
"description": "Implements ReAct (Reason + Act) framework", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Agent Name", "default": "ReActAgent"}, |
|
|
"max_iterations": {"type": "number", "label": "Max Iterations", "default": 10}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"MULTI_AGENT": { |
|
|
"shape": "rect", |
|
|
"color": "#4CAF50", |
|
|
"icon": "👥", |
|
|
"description": "Coordinates multiple specialized agents", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "System Name", "default": "MultiAgentSystem"}, |
|
|
"max_concurrent_agents": {"type": "number", "label": "Max Concurrent Agents", "default": 10}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
"USER": { |
|
|
"description": "User interaction points and interfaces", |
|
|
"color": "#9C27B0", |
|
|
"icon": "👤", |
|
|
"shape": "ellipse", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "User Interface", "default": "UserInterface"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"USER_INPUT": { |
|
|
"shape": "ellipse", |
|
|
"color": "#9C27B0", |
|
|
"icon": "⌨️", |
|
|
"description": "Accepts and validates user input", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Input Name", "default": "UserInput"}, |
|
|
"input_types": {"type": "dropdown", "label": "Input Types", "choices": ["text", "voice", "gesture"], "default": "text"}, |
|
|
"max_length": {"type": "number", "label": "Max Input Length", "default": 1000}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"USER_OUTPUT": { |
|
|
"shape": "ellipse", |
|
|
"color": "#9C27B0", |
|
|
"icon": "🔊", |
|
|
"description": "Formats responses for user consumption", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Output Name", "default": "UserOutput"}, |
|
|
"output_format": {"type": "dropdown", "label": "Output Format", "choices": ["text", "audio", "visual"], "default": "text"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"MULTIMODAL_INTERFACE": { |
|
|
"shape": "ellipse", |
|
|
"color": "#9C27B0", |
|
|
"icon": "🖼️", |
|
|
"description": "Handles multiple input/output modalities", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Interface Name", "default": "MultimodalInterface"}, |
|
|
"supported_modalities": {"type": "dropdown", "label": "Modalities", "choices": ["text", "image", "audio", "video"], "default": "text"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
"TOOL": { |
|
|
"description": "External functions and capabilities", |
|
|
"color": "#795548", |
|
|
"icon": "🔧", |
|
|
"shape": "hexagon", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Tool Name", "default": "MyTool"}, |
|
|
"description": {"type": "textarea", "label": "Tool Description", "default": "Tool description"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"MCP_TOOL": { |
|
|
"shape": "hexagon", |
|
|
"color": "#795548", |
|
|
"icon": "🔌", |
|
|
"description": "Model Context Protocol server interface", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Tool Name", "default": "MCPTool"}, |
|
|
"server_command": {"type": "text", "label": "Server Command", "default": "npx"}, |
|
|
"server_args": {"type": "text", "label": "Server Arguments", "default": ""}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"API_TOOL": { |
|
|
"shape": "hexagon", |
|
|
"color": "#795548", |
|
|
"icon": "🔗", |
|
|
"description": "Wraps external REST/gRPC APIs", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "API Tool Name", "default": "APITool"}, |
|
|
"base_url": {"type": "text", "label": "Base URL", "default": "https://api.example.com"}, |
|
|
"timeout": {"type": "number", "label": "Timeout (seconds)", "default": 30}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"LOCAL_TOOL": { |
|
|
"shape": "hexagon", |
|
|
"color": "#795548", |
|
|
"icon": "💻", |
|
|
"description": "Locally executed utility functions", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Local Tool Name", "default": "LocalTool"}, |
|
|
"allowed_operations": {"type": "dropdown", "label": "Operations", "choices": ["file", "math", "system"], "default": "file"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"AGENT_TOOL": { |
|
|
"shape": "hexagon", |
|
|
"color": "#795548", |
|
|
"icon": "🛠️", |
|
|
"description": "Allows one agent to act as a tool", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Agent Tool Name", "default": "AgentTool"}, |
|
|
"max_concurrent_calls": {"type": "number", "label": "Max Concurrent Calls", "default": 5}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"FUNCTION_TOOL": { |
|
|
"shape": "hexagon", |
|
|
"color": "#795548", |
|
|
"icon": "🧮", |
|
|
"description": "Generic callable function", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Function Tool Name", "default": "FunctionTool"}, |
|
|
"max_params": {"type": "number", "label": "Max Parameters", "default": 10}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
"DATA": { |
|
|
"description": "Data sources and storage systems", |
|
|
"color": "#009688", |
|
|
"icon": "💾", |
|
|
"shape": "cylinder", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Data Store", "default": "DataStore"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"KNOWLEDGE_BASE": { |
|
|
"shape": "cylinder", |
|
|
"color": "#009688", |
|
|
"icon": "📘", |
|
|
"description": "Curated domain-specific knowledge", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Knowledge Base Name", "default": "MyKnowledgeBase"}, |
|
|
"max_facts": {"type": "number", "label": "Max Facts", "default": 10000}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"VECTOR_DB": { |
|
|
"shape": "cylinder", |
|
|
"color": "#009688", |
|
|
"icon": "🔍", |
|
|
"description": "Embedding-based semantic search database", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Vector DB Name", "default": "MyVectorDB"}, |
|
|
"embedding_model": {"type": "text", "label": "Embedding Model", "default": "all-MiniLM-L6-v2"}, |
|
|
"max_documents": {"type": "number", "label": "Max Documents", "default": 10000}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"DOCUMENT_STORE": { |
|
|
"shape": "cylinder", |
|
|
"color": "#009688", |
|
|
"icon": "🗂️", |
|
|
"description": "Raw document repository", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Document Store Name", "default": "DocumentStore"}, |
|
|
"supported_formats": {"type": "dropdown", "label": "Supported Formats", "choices": [".pdf", ".txt", ".docx"], "default": ".pdf"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"CACHE": { |
|
|
"shape": "cylinder", |
|
|
"color": "#009688", |
|
|
"icon": "⏱️", |
|
|
"description": "Temporary fast-access storage", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Cache Name", "default": "ResponseCache"}, |
|
|
"max_size": {"type": "number", "label": "Max Cache Size", "default": 1000}, |
|
|
"ttl_seconds": {"type": "number", "label": "TTL (seconds)", "default": 3600}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"MEMORY": { |
|
|
"shape": "cylinder", |
|
|
"color": "#009588", |
|
|
"icon": "🧠", |
|
|
"description": "Short-term context memory", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Memory Name", "default": "SessionMemory"}, |
|
|
"max_context_length": {"type": "number", "label": "Max Context Length", "default": 2000}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
"PROCESSOR": { |
|
|
"description": "Data processing and transformation units", |
|
|
"color": "#2196F3", |
|
|
"icon": "⚙️", |
|
|
"shape": "rect", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Processor", "default": "DataProcessor"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"QUERY_PROCESSOR": { |
|
|
"shape": "rect", |
|
|
"color": "#2196F3", |
|
|
"icon": "🔎", |
|
|
"description": "Parses and enriches queries", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Processor Name", "default": "QueryProcessor"}, |
|
|
"max_query_length": {"type": "number", "label": "Max Query Length", "default": 1000}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"CONTENT_RETRIEVAL": { |
|
|
"shape": "rect", |
|
|
"color": "#2196F3", |
|
|
"icon": "📤", |
|
|
"description": "Fetches relevant content from data stores", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Retrieval Name", "default": "ContentRetrieval"}, |
|
|
"top_k": {"type": "number", "label": "Top K Results", "default": 5}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"PROMPT_TEMPLATE": { |
|
|
"shape": "rect", |
|
|
"color": "#2196F3", |
|
|
"icon": "📝", |
|
|
"description": "Template-based prompt construction", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Template Name", "default": "MyPromptTemplate"}, |
|
|
"template_content": {"type": "textarea", "label": "Template Content", "default": "You are a helpful assistant. User: {query}"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"RESPONSE_FORMATTER": { |
|
|
"shape": "rect", |
|
|
"color": "#2196F3", |
|
|
"icon": "📄", |
|
|
"description": "Structures final output", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Formatter Name", "default": "ResponseFormatter"}, |
|
|
"default_format": {"type": "dropdown", "label": "Default Format", "choices": ["json", "xml", "markdown", "text"], "default": "json"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
"ROUTER": { |
|
|
"description": "Decision points and workflow routing", |
|
|
"color": "#FF9800", |
|
|
"icon": "🎯", |
|
|
"shape": "diamond", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Router", "default": "WorkflowRouter"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"INTENT_DISCOVERY": { |
|
|
"shape": "diamond", |
|
|
"color": "#FF9800", |
|
|
"icon": "🎯", |
|
|
"description": "Identifies user intent", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Intent Discovery Name", "default": "IntentDiscovery"}, |
|
|
"fallback_intent": {"type": "text", "label": "Fallback Intent", "default": "unknown"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"MODEL_SELECTOR": { |
|
|
"shape": "diamond", |
|
|
"color": "#FF9800", |
|
|
"icon": "🧠", |
|
|
"description": "Selects appropriate model", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Model Selector Name", "default": "ModelSelector"}, |
|
|
"selection_strategy": {"type": "dropdown", "label": "Selection Strategy", "choices": ["performance", "cost", "latency"], "default": "performance"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"WORKFLOW_ROUTER": { |
|
|
"shape": "diamond", |
|
|
"color": "#FF9800", |
|
|
"icon": "🔄", |
|
|
"description": "Routes requests through workflows", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Workflow Router Name", "default": "WorkflowRouter"}, |
|
|
"max_concurrent_workflows": {"type": "number", "label": "Max Concurrent", "default": 100}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"VALIDATOR": { |
|
|
"shape": "diamond", |
|
|
"color": "#FF9800", |
|
|
"icon": "✅", |
|
|
"description": "Validates inputs and outputs", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Validator Name", "default": "DataValidator"}, |
|
|
"error_handling": {"type": "dropdown", "label": "Error Handling", "choices": ["strict", "lenient", "adaptive"], "default": "adaptive"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
"INFRASTRUCTURE": { |
|
|
"description": "System infrastructure and services", |
|
|
"color": "#FF5722", |
|
|
"icon": "🌐", |
|
|
"shape": "rect", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Infrastructure", "default": "SystemInfrastructure"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"PROVIDER": { |
|
|
"shape": "rect", |
|
|
"color": "#FF5722", |
|
|
"icon": "🌐", |
|
|
"description": "API connection to LLM service", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Provider Name", "default": "LocalLM"}, |
|
|
"provider_type": {"type": "dropdown", "label": "Provider Type", "choices": ["openai", "anthropic", "local"], "default": "local"}, |
|
|
"base_url": {"type": "text", "label": "Base URL", "default": "http://localhost:1234/v1"}, |
|
|
"model": {"type": "text", "label": "Model", "default": "qwen3-0.6b"}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"MONITOR": { |
|
|
"shape": "rect", |
|
|
"color": "#FF5722", |
|
|
"icon": "📊", |
|
|
"description": "Tracks system performance", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Monitor Name", "default": "SystemMonitor"}, |
|
|
"metrics_retention_hours": {"type": "number", "label": "Metrics Retention (hours)", "default": 24}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"FALLBACK": { |
|
|
"shape": "rect", |
|
|
"color": "#FF5722", |
|
|
"icon": "🔄", |
|
|
"description": "Provides alternative execution paths", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Fallback Name", "default": "FallbackHandler"}, |
|
|
"max_fallback_attempts": {"type": "number", "label": "Max Attempts", "default": 3}, |
|
|
} |
|
|
}, |
|
|
|
|
|
"ORCHESTRATOR": { |
|
|
"shape": "rect", |
|
|
"color": "#FF5722", |
|
|
"icon": "🎬", |
|
|
"description": "Coordinates complex multi-step processes", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Orchestrator Name", "default": "WorkflowOrchestrator"}, |
|
|
"max_workflow_steps": {"type": "number", "label": "Max Steps", "default": 100}, |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
"CONFIG": { |
|
|
"shape": "document", |
|
|
"color": "#607D8B", |
|
|
"icon": "⚙️", |
|
|
"description": "System configuration management", |
|
|
"config_fields": { |
|
|
"name": {"type": "text", "label": "Config Name", "default": "SystemConfig"}, |
|
|
"environment": {"type": "dropdown", "label": "Environment", "choices": ["development", "staging", "production"], "default": "development"}, |
|
|
} |
|
|
}, |
|
|
} |
|
|
|
|
|
|
|
|
EXAMPLE_WORKFLOWS = { |
|
|
"E-Commerce Class Diagram": { |
|
|
"description": "Object-oriented design for e-commerce system", |
|
|
"nodes": [ |
|
|
{"id": "user", "type": "CLASS", "x": 100, "y": 100}, |
|
|
{"id": "product", "type": "CLASS", "x": 300, "y": 100}, |
|
|
{"id": "order", "type": "CLASS", "x": 500, "y": 100}, |
|
|
{"id": "payment", "type": "CLASS", "x": 700, "y": 100}, |
|
|
{"id": "cart", "type": "CLASS", "x": 300, "y": 300}, |
|
|
{"id": "inventory", "type": "CLASS", "x": 500, "y": 300} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "user", "to": "order", "type": "AGGREGATION"}, |
|
|
{"from": "order", "to": "product", "type": "COMPOSITION"}, |
|
|
{"from": "order", "to": "payment", "type": "AGGREGATION"}, |
|
|
{"from": "user", "to": "cart", "type": "AGGREGATION"}, |
|
|
{"from": "cart", "to": "product", "type": "AGGREGATION"}, |
|
|
{"from": "product", "to": "inventory", "type": "AGGREGATION"} |
|
|
] |
|
|
}, |
|
|
|
|
|
"User Authentication Use Case": { |
|
|
"description": "Use case diagram for user authentication system", |
|
|
"nodes": [ |
|
|
{"id": "user", "type": "ACTOR", "x": 50, "y": 200}, |
|
|
{"id": "admin", "type": "ACTOR", "x": 50, "y": 300}, |
|
|
{"id": "login", "type": "USECASE", "x": 250, "y": 150}, |
|
|
{"id": "register", "type": "USECASE", "x": 250, "y": 250}, |
|
|
{"id": "reset_password", "type": "USECASE", "x": 250, "y": 350}, |
|
|
{"id": "admin_panel", "type": "USECASE", "x": 450, "y": 300}, |
|
|
{"id": "system_boundary", "type": "SYSTEM_BOUNDARY", "x": 150, "y": 100} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "user", "to": "login"}, |
|
|
{"from": "user", "to": "register"}, |
|
|
{"from": "user", "to": "reset_password"}, |
|
|
{"from": "admin", "to": "admin_panel"}, |
|
|
{"from": "admin", "to": "login"}, |
|
|
{"from": "login", "to": "reset_password", "type": "EXTEND"} |
|
|
] |
|
|
}, |
|
|
|
|
|
"Order Processing Sequence": { |
|
|
"description": "Sequence diagram for order processing workflow", |
|
|
"nodes": [ |
|
|
{"id": "customer", "type": "LIFELINE", "x": 100, "y": 50}, |
|
|
{"id": "ui", "type": "LIFELINE", "x": 250, "y": 50}, |
|
|
{"id": "order_service", "type": "LIFELINE", "x": 400, "y": 50}, |
|
|
{"id": "payment_service", "type": "LIFELINE", "x": 550, "y": 50}, |
|
|
{"id": "inventory_service", "type": "LIFELINE", "x": 700, "y": 50} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "customer", "to": "ui", "type": "MESSAGE", "label": "placeOrder()"}, |
|
|
{"from": "ui", "to": "order_service", "type": "MESSAGE", "label": "createOrder()"}, |
|
|
{"from": "order_service", "to": "inventory_service", "type": "MESSAGE", "label": "checkAvailability()"}, |
|
|
{"from": "inventory_service", "to": "order_service", "type": "MESSAGE", "label": "availabilityConfirmed()"}, |
|
|
{"from": "order_service", "to": "payment_service", "type": "MESSAGE", "label": "processPayment()"}, |
|
|
{"from": "payment_service", "to": "order_service", "type": "MESSAGE", "label": "paymentConfirmed()"}, |
|
|
{"from": "order_service", "to": "ui", "type": "MESSAGE", "label": "orderConfirmed()"}, |
|
|
{"from": "ui", "to": "customer", "type": "MESSAGE", "label": "showConfirmation()"} |
|
|
] |
|
|
}, |
|
|
|
|
|
"User State Machine": { |
|
|
"description": "State machine for user account states", |
|
|
"nodes": [ |
|
|
{"id": "pending", "type": "STATE", "x": 100, "y": 100}, |
|
|
{"id": "active", "type": "STATE", "x": 300, "y": 100}, |
|
|
{"id": "suspended", "type": "STATE", "x": 500, "y": 100}, |
|
|
{"id": "deleted", "type": "STATE", "x": 300, "y": 300}, |
|
|
{"id": "start", "type": "START_NODE", "x": 50, "y": 100}, |
|
|
{"id": "end", "type": "END_NODE", "x": 300, "y": 400} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "start", "to": "pending"}, |
|
|
{"from": "pending", "to": "active", "type": "TRANSITION", "label": "approveAccount()"}, |
|
|
{"from": "active", "to": "suspended", "type": "TRANSITION", "label": "suspendAccount()"}, |
|
|
{"from": "suspended", "to": "active", "type": "TRANSITION", "label": "activateAccount()"}, |
|
|
{"from": "active", "to": "deleted", "type": "TRANSITION", "label": "deleteAccount()"}, |
|
|
{"from": "suspended", "to": "deleted", "type": "TRANSITION", "label": "deleteAccount()"}, |
|
|
{"from": "deleted", "to": "end"} |
|
|
] |
|
|
}, |
|
|
|
|
|
"Document Management Activity": { |
|
|
"description": "Activity diagram for document management process", |
|
|
"nodes": [ |
|
|
{"id": "start", "type": "START_NODE", "x": 200, "y": 50}, |
|
|
{"id": "upload", "type": "ACTION", "x": 200, "y": 150}, |
|
|
{"id": "validate", "type": "DECISION", "x": 200, "y": 250}, |
|
|
{"id": "process", "type": "ACTION", "x": 200, "y": 350}, |
|
|
{"id": "store", "type": "ACTION", "x": 200, "y": 450}, |
|
|
{"id": "notify", "type": "ACTION", "x": 200, "y": 550}, |
|
|
{"id": "end", "type": "END_NODE", "x": 200, "y": 650}, |
|
|
{"id": "error", "type": "ACTION", "x": 400, "y": 350} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "start", "to": "upload"}, |
|
|
{"from": "upload", "to": "validate"}, |
|
|
{"from": "validate", "to": "process", "label": "[valid]"}, |
|
|
{"from": "validate", "to": "error", "label": "[invalid]"}, |
|
|
{"from": "error", "to": "end"}, |
|
|
{"from": "process", "to": "store"}, |
|
|
{"from": "store", "to": "notify"}, |
|
|
{"from": "notify", "to": "end"} |
|
|
] |
|
|
}, |
|
|
"Simple Chat Agent": { |
|
|
"description": "Basic conversational agent with single LLM call", |
|
|
"nodes": [ |
|
|
{"id": "user_1", "type": "USER_INPUT", "x": 150, "y": 200}, |
|
|
{"id": "agent_1", "type": "REASONING_AGENT", "x": 400, "y": 200}, |
|
|
{"id": "provider_1", "type": "PROVIDER", "x": 650, "y": 200}, |
|
|
{"id": "output_1", "type": "USER_OUTPUT", "x": 900, "y": 200} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "user_1", "to": "agent_1"}, |
|
|
{"from": "agent_1", "to": "provider_1"}, |
|
|
{"from": "provider_1", "to": "output_1"} |
|
|
] |
|
|
}, |
|
|
"Intent-Driven Routing": { |
|
|
"description": "Routes to specialized agents based on user intent", |
|
|
"nodes": [ |
|
|
{"id": "user_1", "type": "USER_INPUT", "x": 150, "y": 300}, |
|
|
{"id": "intent_1", "type": "INTENT_DISCOVERY", "x": 400, "y": 300}, |
|
|
{"id": "agent_1", "type": "REASONING_AGENT", "x": 650, "y": 150}, |
|
|
{"id": "agent_2", "type": "ACTION_AGENT", "x": 650, "y": 450}, |
|
|
{"id": "output_1", "type": "USER_OUTPUT", "x": 900, "y": 300} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "user_1", "to": "intent_1"}, |
|
|
{"from": "intent_1", "to": "agent_1"}, |
|
|
{"from": "intent_1", "to": "agent_2"}, |
|
|
{"from": "agent_1", "to": "output_1"}, |
|
|
{"from": "agent_2", "to": "output_1"} |
|
|
] |
|
|
}, |
|
|
"RAG Pipeline": { |
|
|
"description": "Retrieval-Augmented Generation with context", |
|
|
"nodes": [ |
|
|
{"id": "user_1", "type": "USER_INPUT", "x": 100, "y": 250}, |
|
|
{"id": "query_1", "type": "QUERY_PROCESSOR", "x": 250, "y": 250}, |
|
|
{"id": "content_1", "type": "CONTENT_RETRIEVAL", "x": 400, "y": 250}, |
|
|
{"id": "prompt_1", "type": "PROMPT_TEMPLATE", "x": 550, "y": 250}, |
|
|
{"id": "agent_1", "type": "REASONING_AGENT", "x": 700, "y": 250}, |
|
|
{"id": "output_1", "type": "USER_OUTPUT", "x": 900, "y": 250} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "user_1", "to": "query_1"}, |
|
|
{"from": "query_1", "to": "content_1"}, |
|
|
{"from": "content_1", "to": "prompt_1"}, |
|
|
{"from": "prompt_1", "to": "agent_1"}, |
|
|
{"from": "agent_1", "to": "output_1"} |
|
|
] |
|
|
}, |
|
|
"Multi-Agent with Tools": { |
|
|
"description": "Coordinated agents with tool access and validation", |
|
|
"nodes": [ |
|
|
{"id": "user_1", "type": "USER_INPUT", "x": 100, "y": 300}, |
|
|
{"id": "intent_1", "type": "INTENT_DISCOVERY", "x": 280, "y": 300}, |
|
|
{"id": "agent_1", "type": "REASONING_AGENT", "x": 460, "y": 150}, |
|
|
{"id": "agent_2", "type": "ACTION_AGENT", "x": 460, "y": 450}, |
|
|
{"id": "tool_1", "type": "MCP_TOOL", "x": 640, "y": 150}, |
|
|
{"id": "tool_2", "type": "API_TOOL", "x": 640, "y": 450}, |
|
|
{"id": "validator_1", "type": "VALIDATOR", "x": 820, "y": 300}, |
|
|
{"id": "output_1", "type": "USER_OUTPUT", "x": 980, "y": 300} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "user_1", "to": "intent_1"}, |
|
|
{"from": "intent_1", "to": "agent_1"}, |
|
|
{"from": "intent_1", "to": "agent_2"}, |
|
|
{"from": "agent_1", "to": "tool_1"}, |
|
|
{"from": "agent_2", "to": "tool_2"}, |
|
|
{"from": "tool_1", "to": "validator_1"}, |
|
|
{"from": "tool_2", "to": "validator_1"}, |
|
|
{"from": "validator_1", "to": "output_1"} |
|
|
] |
|
|
}, |
|
|
"Advanced RAG with Cache": { |
|
|
"description": "Enhanced RAG with caching and monitoring", |
|
|
"nodes": [ |
|
|
{"id": "user_1", "type": "USER_INPUT", "x": 100, "y": 200}, |
|
|
{"id": "query_1", "type": "QUERY_PROCESSOR", "x": 250, "y": 200}, |
|
|
{"id": "cache_1", "type": "CACHE", "x": 400, "y": 100}, |
|
|
{"id": "knowledge_1", "type": "KNOWLEDGE_BASE", "x": 400, "y": 300}, |
|
|
{"id": "prompt_1", "type": "PROMPT_TEMPLATE", "x": 550, "y": 200}, |
|
|
{"id": "agent_1", "type": "REASONING_AGENT", "x": 700, "y": 200}, |
|
|
{"id": "monitor_1", "type": "MONITOR", "x": 850, "y": 100}, |
|
|
{"id": "output_1", "type": "USER_OUTPUT", "x": 850, "y": 300} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "user_1", "to": "query_1"}, |
|
|
{"from": "query_1", "to": "cache_1"}, |
|
|
{"from": "query_1", "to": "knowledge_1"}, |
|
|
{"from": "cache_1", "to": "prompt_1"}, |
|
|
{"from": "knowledge_1", "to": "prompt_1"}, |
|
|
{"from": "prompt_1", "to": "agent_1"}, |
|
|
{"from": "agent_1", "to": "monitor_1"}, |
|
|
{"from": "agent_1", "to": "output_1"} |
|
|
] |
|
|
}, |
|
|
"MCP Tool Agent": { |
|
|
"description": "Agent using MCP tools for extended capabilities", |
|
|
"nodes": [ |
|
|
{"id": "user_1", "type": "USER_INPUT", "x": 100, "y": 250}, |
|
|
{"id": "agent_1", "type": "REACT_AGENT", "x": 300, "y": 250}, |
|
|
{"id": "mcp_tool_1", "type": "MCP_TOOL", "x": 500, "y": 150}, |
|
|
{"id": "mcp_tool_2", "type": "MCP_TOOL", "x": 500, "y": 350}, |
|
|
{"id": "memory_1", "type": "MEMORY", "x": 700, "y": 250}, |
|
|
{"id": "output_1", "type": "USER_OUTPUT", "x": 900, "y": 250} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "user_1", "to": "agent_1"}, |
|
|
{"from": "agent_1", "to": "mcp_tool_1"}, |
|
|
{"from": "agent_1", "to": "mcp_tool_2"}, |
|
|
{"from": "mcp_tool_1", "to": "agent_1"}, |
|
|
{"from": "mcp_tool_2", "to": "agent_1"}, |
|
|
{"from": "agent_1", "to": "memory_1"}, |
|
|
{"from": "agent_1", "to": "output_1"} |
|
|
] |
|
|
}, |
|
|
"Multi-Agent Planning System": { |
|
|
"description": "Complex planning with multiple specialized agents", |
|
|
"nodes": [ |
|
|
{"id": "user_1", "type": "USER_INPUT", "x": 100, "y": 300}, |
|
|
{"id": "planner_1", "type": "PLANNER_AGENT", "x": 300, "y": 300}, |
|
|
{"id": "reasoning_1", "type": "REASONING_AGENT", "x": 500, "y": 150}, |
|
|
{"id": "action_1", "type": "ACTION_AGENT", "x": 500, "y": 300}, |
|
|
{"id": "multi_1", "type": "MULTI_AGENT", "x": 500, "y": 450}, |
|
|
{"id": "orchestrator_1", "type": "ORCHESTRATOR", "x": 700, "y": 300}, |
|
|
{"id": "output_1", "type": "USER_OUTPUT", "x": 900, "y": 300} |
|
|
], |
|
|
"connections": [ |
|
|
{"from": "user_1", "to": "planner_1"}, |
|
|
{"from": "planner_1", "to": "orchestrator_1"}, |
|
|
{"from": "orchestrator_1", "to": "reasoning_1"}, |
|
|
{"from": "orchestrator_1", "to": "action_1"}, |
|
|
{"from": "orchestrator_1", "to": "multi_1"}, |
|
|
{"from": "reasoning_1", "to": "orchestrator_1"}, |
|
|
{"from": "action_1", "to": "orchestrator_1"}, |
|
|
{"from": "multi_1", "to": "orchestrator_1"}, |
|
|
{"from": "orchestrator_1", "to": "output_1"} |
|
|
] |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ALL_COMPONENTS = {} |
|
|
for category, components in COMPONENT_HIERARCHY["HIGH_LEVEL"].items(): |
|
|
ALL_COMPONENTS[category] = components |
|
|
for sub_comp in components.get('sub_components', []): |
|
|
if sub_comp in COMPONENT_INFO: |
|
|
ALL_COMPONENTS[sub_comp] = COMPONENT_INFO[sub_comp] |
|
|
|
|
|
for comp_name, comp_info in COMPONENT_INFO.items(): |
|
|
if comp_name not in ALL_COMPONENTS: |
|
|
ALL_COMPONENTS[comp_name] = comp_info |
|
|
|
|
|
|
|
|
for comp_name, comp_info in ALL_COMPONENTS.items(): |
|
|
if 'config_fields' not in comp_info: |
|
|
comp_info['config_fields'] = { |
|
|
"name": {"type": "text", "label": "Component Name", "default": comp_name} |
|
|
} |
|
|
|
|
|
|
|
|
@dataclass |
|
|
class ComponentData: |
|
|
type: str |
|
|
shape: str |
|
|
color: str |
|
|
icon: str |
|
|
description: str |
|
|
config: Dict[str, Any] = field(default_factory=dict) |
|
|
|
|
|
@dataclass |
|
|
class AgentNode: |
|
|
id: str |
|
|
type: str |
|
|
x: int |
|
|
y: int |
|
|
label: str = "" |
|
|
config: Dict[str, Any] = field(default_factory=dict) |
|
|
component_data: ComponentData = field(default_factory=lambda: ComponentData("", "", "", "", "")) |
|
|
|
|
|
class Connection: |
|
|
def __init__(self, from_node: str, to_node: str): |
|
|
self.from_node = from_node |
|
|
self.to_node = to_node |
|
|
|
|
|
class WorkflowDesigner: |
|
|
def __init__(self): |
|
|
self.nodes: Dict[str, AgentNode] = {} |
|
|
self.connections: List[Connection] = [] |
|
|
self.node_counter = 0 |
|
|
self.selected_node: Optional[str] = None |
|
|
|
|
|
def select_node(self, node_id: str) -> None: |
|
|
self.selected_node = node_id if node_id in self.nodes else None |
|
|
|
|
|
def move_selected_node(self, dx: int, dy: int) -> None: |
|
|
if self.selected_node and self.selected_node in self.nodes: |
|
|
node = self.nodes[self.selected_node] |
|
|
node.x = max(0, node.x + dx) |
|
|
node.y = max(0, node.y + dy) |
|
|
|
|
|
def add_node(self, node_type: str, config: Dict[str, Any] = None) -> AgentNode: |
|
|
self.node_counter += 1 |
|
|
node_id = f"{node_type}_{self.node_counter}" |
|
|
|
|
|
comp_info = ALL_COMPONENTS.get(node_type, { |
|
|
"shape": "rect", |
|
|
"color": "#666666", |
|
|
"icon": "❓", |
|
|
"description": "Unknown component type", |
|
|
"config_fields": {"name": {"type": "text", "label": "Name", "default": node_id}} |
|
|
}) |
|
|
|
|
|
label = config.get("name", node_id) if config else node_id |
|
|
|
|
|
col = len(self.nodes) % 4 |
|
|
row = len(self.nodes) // 4 |
|
|
x_pos = 150 + (col * 300) |
|
|
y_pos = 150 + (row * 200) |
|
|
|
|
|
component_data = ComponentData( |
|
|
type=node_type, |
|
|
shape=comp_info["shape"], |
|
|
color=comp_info["color"], |
|
|
icon=comp_info["icon"], |
|
|
description=comp_info["description"], |
|
|
config=config or {} |
|
|
) |
|
|
|
|
|
node = AgentNode( |
|
|
id=node_id, |
|
|
type=node_type, |
|
|
x=x_pos, |
|
|
y=y_pos, |
|
|
label=label, |
|
|
config=config or {}, |
|
|
component_data=component_data |
|
|
) |
|
|
|
|
|
self.nodes[node_id] = node |
|
|
self.selected_node = node_id |
|
|
return node |
|
|
|
|
|
def delete_node(self, node_id: str): |
|
|
if node_id in self.nodes: |
|
|
self.connections = [ |
|
|
conn for conn in self.connections |
|
|
if conn.from_node != node_id and conn.to_node != node_id |
|
|
] |
|
|
del self.nodes[node_id] |
|
|
if self.selected_node == node_id: |
|
|
self.selected_node = None |
|
|
|
|
|
def add_connection(self, from_node: str, to_node: str): |
|
|
if from_node in self.nodes and to_node in self.nodes and from_node != to_node: |
|
|
existing = any( |
|
|
conn.from_node == from_node and conn.to_node == to_node |
|
|
for conn in self.connections |
|
|
) |
|
|
if not existing: |
|
|
self.connections.append(Connection(from_node, to_node)) |
|
|
|
|
|
def load_example(self, example_name: str): |
|
|
if example_name not in EXAMPLE_WORKFLOWS: |
|
|
return |
|
|
|
|
|
example = EXAMPLE_WORKFLOWS[example_name] |
|
|
self.nodes.clear() |
|
|
self.connections.clear() |
|
|
|
|
|
for node_data in example["nodes"]: |
|
|
node_type = node_data["type"] |
|
|
|
|
|
comp_info = ALL_COMPONENTS.get(node_type, { |
|
|
"shape": "rect", |
|
|
"color": "#666666", |
|
|
"icon": "❓", |
|
|
"description": "Unknown component type" |
|
|
}) |
|
|
|
|
|
component_data = ComponentData( |
|
|
type=node_type, |
|
|
shape=comp_info["shape"], |
|
|
color=comp_info["color"], |
|
|
icon=comp_info["icon"], |
|
|
description=comp_info["description"] |
|
|
) |
|
|
|
|
|
node = AgentNode( |
|
|
id=node_data["id"], |
|
|
type=node_type, |
|
|
x=node_data["x"], |
|
|
y=node_data["y"], |
|
|
label=node_data["id"], |
|
|
component_data=component_data |
|
|
) |
|
|
self.nodes[node.id] = node |
|
|
|
|
|
for conn_data in example["connections"]: |
|
|
conn = Connection( |
|
|
from_node=conn_data["from"], |
|
|
to_node=conn_data["to"] |
|
|
) |
|
|
self.connections.append(conn) |
|
|
|
|
|
if self.nodes: |
|
|
self.selected_node = list(self.nodes.keys())[0] |
|
|
|
|
|
def get_workflow_json(self) -> Dict[str, Any]: |
|
|
return { |
|
|
"metadata": { |
|
|
"total_nodes": len(self.nodes), |
|
|
"total_connections": len(self.connections), |
|
|
"selected_node": self.selected_node, |
|
|
}, |
|
|
"nodes": [ |
|
|
{ |
|
|
"id": node.id, |
|
|
"type": node.type, |
|
|
"label": node.label, |
|
|
"position": {"x": node.x, "y": node.y}, |
|
|
"config": node.config, |
|
|
"component_data": { |
|
|
"type": node.component_data.type, |
|
|
"shape": node.component_data.shape, |
|
|
"color": node.component_data.color, |
|
|
"icon": node.component_data.icon, |
|
|
"description": node.component_data.description |
|
|
} |
|
|
} |
|
|
for node in self.nodes.values() |
|
|
], |
|
|
"connections": [ |
|
|
{"from": conn.from_node, "to": conn.to_node} |
|
|
for conn in self.connections |
|
|
] |
|
|
} |
|
|
|
|
|
def update_node_config(self, node_id: str, config: Dict[str, Any]): |
|
|
if node_id in self.nodes: |
|
|
self.nodes[node_id].config = config |
|
|
self.nodes[node_id].label = config.get("name", node_id) |
|
|
|
|
|
def render_svg(self) -> str: |
|
|
if not self.nodes: |
|
|
return ''' |
|
|
<svg width="1200" height="600" style="border-radius: 12px;"> |
|
|
<defs> |
|
|
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%"> |
|
|
<stop offset="0%" style="stop-color:#667eea;stop-opacity:1" /> |
|
|
<stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" /> |
|
|
</linearGradient> |
|
|
</defs> |
|
|
<rect width="1200" height="600" fill="url(#bg)"/> |
|
|
<text x="600" y="280" text-anchor="middle" fill="white" font-size="32" font-weight="bold">🚀 Start Building Your Workflow</text> |
|
|
<text x="600" y="320" text-anchor="middle" fill="white" font-size="18" opacity="0.9">Add components from the library</text> |
|
|
</svg> |
|
|
''' |
|
|
|
|
|
width = 1200 |
|
|
height = max(600, max([n.y for n in self.nodes.values()], default=0) + 200) |
|
|
|
|
|
svg_parts = [ |
|
|
f'<svg width="{width}" height="{height}" style="border-radius: 12px;">', |
|
|
'<defs>', |
|
|
'<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">', |
|
|
'<stop offset="0%" style="stop-color:#667eea;stop-opacity:1" />', |
|
|
'<stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" />', |
|
|
'</linearGradient>', |
|
|
'<marker id="arrowhead" markerWidth="12" markerHeight="12" refX="11" refY="3" orient="auto">', |
|
|
'<polygon points="0 0, 12 3, 0 6" fill="white" opacity="0.9"/>', |
|
|
'</marker>', |
|
|
'<filter id="shadow">', |
|
|
'<feDropShadow dx="0" dy="4" stdDeviation="4" flood-opacity="0.3"/>', |
|
|
'</filter>', |
|
|
'<filter id="selected-glow">', |
|
|
'<feGaussianBlur stdDeviation="5" result="coloredBlur"/>', |
|
|
'<feMerge><feMergeNode in="coloredBlur"/><feMergeNode in="SourceGraphic"/></feMerge>', |
|
|
'</filter>', |
|
|
'</defs>', |
|
|
'<rect width="100%" height="100%" fill="url(#bg)"/>' |
|
|
] |
|
|
|
|
|
|
|
|
for conn in self.connections: |
|
|
if conn.from_node in self.nodes and conn.to_node in self.nodes: |
|
|
from_node = self.nodes[conn.from_node] |
|
|
to_node = self.nodes[conn.to_node] |
|
|
|
|
|
from_x = from_node.x + 85 |
|
|
from_y = from_node.y + 60 |
|
|
to_x = to_node.x + 15 |
|
|
to_y = to_node.y + 60 |
|
|
|
|
|
mid_x = (from_x + to_x) / 2 |
|
|
|
|
|
svg_parts.append( |
|
|
f'<path d="M {from_x} {from_y} C {mid_x} {from_y}, {mid_x} {to_y}, {to_x} {to_y}" ' |
|
|
f'stroke="white" stroke-width="3" fill="none" opacity="0.8" marker-end="url(#arrowhead)"/>' |
|
|
) |
|
|
|
|
|
|
|
|
for node in self.nodes.values(): |
|
|
comp_data = node.component_data |
|
|
cx = node.x + 85 |
|
|
cy = node.y + 60 |
|
|
|
|
|
is_selected = (node.id == self.selected_node) |
|
|
selection_glow = 'filter="url(#selected-glow)"' if is_selected else 'filter="url(#shadow)"' |
|
|
selection_stroke = "6" if is_selected else "4" |
|
|
|
|
|
|
|
|
if comp_data.shape == "ellipse": |
|
|
svg_parts.append( |
|
|
f'<ellipse cx="{cx}" cy="{cy}" rx="80" ry="50" ' |
|
|
f'fill="white" stroke="{comp_data.color}" stroke-width="{selection_stroke}" {selection_glow} ' |
|
|
f'class="node" id="node_{node.id}" style="cursor: move;"/>' |
|
|
) |
|
|
elif comp_data.shape == "cylinder": |
|
|
svg_parts.append( |
|
|
f'<ellipse cx="{cx}" cy="{cy-35}" rx="70" ry="18" ' |
|
|
f'fill="white" stroke="{comp_data.color}" stroke-width="3"/>' |
|
|
) |
|
|
svg_parts.append( |
|
|
f'<rect x="{cx-70}" y="{cy-35}" width="140" height="70" ' |
|
|
f'fill="white" stroke="none"/>' |
|
|
) |
|
|
svg_parts.append( |
|
|
f'<line x1="{cx-70}" y1="{cy-35}" x2="{cx-70}" y2="{cy+35}" ' |
|
|
f'stroke="{comp_data.color}" stroke-width="3"/>' |
|
|
) |
|
|
svg_parts.append( |
|
|
f'<line x1="{cx+70}" y1="{cy-35}" x2="{cx+70}" y2="{cy+35}" ' |
|
|
f'stroke="{comp_data.color}" stroke-width="3"/>' |
|
|
) |
|
|
svg_parts.append( |
|
|
f'<ellipse cx="{cx}" cy="{cy+35}" rx="70" ry="18" ' |
|
|
f'fill="white" stroke="{comp_data.color}" stroke-width="3" {selection_glow} ' |
|
|
f'class="node" id="node_{node.id}" style="cursor: move;"/>' |
|
|
) |
|
|
elif comp_data.shape == "diamond": |
|
|
size = 60 |
|
|
points = f"{cx},{cy-size} {cx+size},{cy} {cx},{cy+size} {cx-size},{cy}" |
|
|
svg_parts.append( |
|
|
f'<polygon points="{points}" ' |
|
|
f'fill="white" stroke="{comp_data.color}" stroke-width="{selection_stroke}" {selection_glow} ' |
|
|
f'class="node" id="node_{node.id}" style="cursor: move;"/>' |
|
|
) |
|
|
elif comp_data.shape == "hexagon": |
|
|
size = 50 |
|
|
points = f"{cx-size},{cy-30} {cx-size},{cy+30} {cx},{cy+size} {cx+size},{cy+30} {cx+size},{cy-30} {cx},{cy-size}" |
|
|
svg_parts.append( |
|
|
f'<polygon points="{points}" ' |
|
|
f'fill="white" stroke="{comp_data.color}" stroke-width="{selection_stroke}" {selection_glow} ' |
|
|
f'class="node" id="node_{node.id}" style="cursor: move;"/>' |
|
|
) |
|
|
else: |
|
|
svg_parts.append( |
|
|
f'<rect x="{cx-80}" y="{cy-45}" width="160" height="90" rx="12" ' |
|
|
f'fill="white" stroke="{comp_data.color}" stroke-width="{selection_stroke}" {selection_glow} ' |
|
|
f'class="node" id="node_{node.id}" style="cursor: move;"/>' |
|
|
) |
|
|
|
|
|
|
|
|
svg_parts.append( |
|
|
f'<text x="{cx}" y="{cy-10}" text-anchor="middle" font-size="36">{comp_data.icon}</text>' |
|
|
) |
|
|
|
|
|
|
|
|
label_display = node.label[:15] + "..." if len(node.label) > 15 else node.label |
|
|
svg_parts.append( |
|
|
f'<text x="{cx}" y="{cy+25}" text-anchor="middle" ' |
|
|
f'fill="#333" font-size="13" font-weight="600">{label_display}</text>' |
|
|
) |
|
|
|
|
|
svg_parts.append('</svg>') |
|
|
return '\n'.join(svg_parts) |
|
|
|
|
|
class WorkflowReporter: |
|
|
def __init__(self): |
|
|
try: |
|
|
self.client = AsyncOpenAI(base_url="http://localhost:1234/v1", api_key="lm-studio") |
|
|
except Exception as e: |
|
|
print("LM Studio client init failed:", e) |
|
|
|
|
|
async def generate_report(self, workflow_json: str) -> str: |
|
|
prompt = f""" |
|
|
|
|
|
Generate a comprehensive system design report based on the following workflow: |
|
|
{workflow_json} |
|
|
|
|
|
The report should include a detailed repost and system breif with full examples and implimentations where possible and explanaion of requirement in cases where the workflow is complexed and need further deconstruction, as well as example usages : |
|
|
1. A high-level system overview |
|
|
2. User stories for each component or connection expetation |
|
|
3. Use case briefs for each component interaction and component relationship |
|
|
4. Pseudocode for the implementation for each component and for the overall workflow |
|
|
5. Component responsibilities and interfaces |
|
|
6. Data flow description and example use-cases |
|
|
|
|
|
""" |
|
|
|
|
|
try: |
|
|
response = await self.client.chat.completions.create( |
|
|
model="leroydyer/qwen/qwen3-0.6b-q4_k_m.gguf", |
|
|
messages=[{"role": "user", "content": prompt}], |
|
|
temperature=0.7, |
|
|
max_tokens=2048 |
|
|
) |
|
|
return response.choices[0].message.content |
|
|
except Exception as e: |
|
|
return f"Error generating report: {str(e)}" |
|
|
|
|
|
|
|
|
workflow = WorkflowDesigner() |
|
|
reporter = WorkflowReporter() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_workflow_ui(): |
|
|
"""Create a unified interface that works properly""" |
|
|
with gr.Blocks(title="Agent Workflow Designer", theme=gr.themes.Soft(), css=""" |
|
|
.component-library { max-height: 70vh; overflow-y: auto; } |
|
|
.canvas-container { border: 2px solid #e0e0e0; border-radius: 12px; padding: 10px; } |
|
|
.config-panel { background: #f8f9fa; padding: 15px; border-radius: 8px; margin: 10px 0; } |
|
|
""") as demo: |
|
|
gr.Markdown("# 🎓 Agentic System Workflow Designer") |
|
|
gr.Markdown("**Educational tool for planning and understanding agent architectures**") |
|
|
|
|
|
|
|
|
selected_node_state = gr.State(None) |
|
|
pending_component_type = gr.State(None) |
|
|
|
|
|
with gr.Row(equal_height=False): |
|
|
|
|
|
with gr.Column(scale=1, min_width=300): |
|
|
gr.Markdown("## 📚 Component Library") |
|
|
|
|
|
with gr.Tabs() as library_tabs: |
|
|
|
|
|
with gr.TabItem("Categories"): |
|
|
component_buttons = [] |
|
|
for category, info in COMPONENT_HIERARCHY["HIGH_LEVEL"].items(): |
|
|
with gr.Accordion(f"{info['icon']} {category}", open=False): |
|
|
gr.Markdown(f"*{info['description']}*") |
|
|
|
|
|
|
|
|
btn = gr.Button( |
|
|
f"{info['icon']} Add {category}", |
|
|
size="sm", |
|
|
variant="primary" |
|
|
) |
|
|
component_buttons.append((btn, category)) |
|
|
|
|
|
|
|
|
if info.get('sub_components'): |
|
|
gr.Markdown("**Specialized types:**") |
|
|
for sub_comp in info['sub_components']: |
|
|
if sub_comp in COMPONENT_INFO: |
|
|
sub_info = COMPONENT_INFO[sub_comp] |
|
|
sub_btn = gr.Button( |
|
|
f"{sub_info['icon']} {sub_comp.replace('_', ' ').title()}", |
|
|
size="sm" |
|
|
) |
|
|
component_buttons.append((sub_btn, sub_comp)) |
|
|
|
|
|
|
|
|
with gr.TabItem("All Components"): |
|
|
for comp_type, comp_info in COMPONENT_INFO.items(): |
|
|
btn = gr.Button( |
|
|
f"{comp_info['icon']} {comp_type.replace('_', ' ').title()}", |
|
|
size="sm", |
|
|
variant="secondary" |
|
|
) |
|
|
component_buttons.append((btn, comp_type)) |
|
|
|
|
|
|
|
|
gr.Markdown("---") |
|
|
gr.Markdown("## 📋 Examples") |
|
|
example_dropdown = gr.Dropdown( |
|
|
choices=list(EXAMPLE_WORKFLOWS.keys()), |
|
|
label="Load Example Workflow", |
|
|
interactive=True |
|
|
) |
|
|
load_example_btn = gr.Button("📥 Load Example", variant="secondary") |
|
|
|
|
|
gr.Markdown("---") |
|
|
with gr.Row(): |
|
|
clear_btn = gr.Button("🗑️ Clear All", variant="stop") |
|
|
download_btn = gr.Button("💾 Export", variant="primary") |
|
|
|
|
|
|
|
|
with gr.Column(scale=3): |
|
|
gr.Markdown("## 🎨 Workflow Canvas") |
|
|
canvas = gr.HTML(label="Workflow Visualization") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
gr.Markdown("### 🎯 Selected Node") |
|
|
selected_node_info = gr.Markdown("No node selected") |
|
|
|
|
|
with gr.Row(): |
|
|
select_prev_btn = gr.Button("⬅️ Prev", size="sm") |
|
|
select_next_btn = gr.Button("➡️ Next", size="sm") |
|
|
deselect_btn = gr.Button("❌ Deselect", size="sm") |
|
|
|
|
|
gr.Markdown("**Move Selected:**") |
|
|
with gr.Row(): |
|
|
move_left_btn = gr.Button("⬅️", size="sm") |
|
|
move_up_btn = gr.Button("⬆️", size="sm") |
|
|
move_down_btn = gr.Button("⬇️", size="sm") |
|
|
move_right_btn = gr.Button("➡️", size="sm") |
|
|
|
|
|
delete_btn = gr.Button("🗑️ Delete Selected", variant="stop", size="sm") |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
gr.Markdown("### ⚙️ Node Configuration") |
|
|
config_display = gr.JSON( |
|
|
label="Current Configuration", |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
config_form = gr.Column(visible=False) |
|
|
config_inputs = {} |
|
|
|
|
|
with config_form: |
|
|
gr.Markdown("#### Edit Configuration") |
|
|
for comp_type, comp_info in COMPONENT_INFO.items(): |
|
|
if 'config_fields' in comp_info: |
|
|
for field_name, field_config in comp_info['config_fields'].items(): |
|
|
input_key = f"{comp_type}_{field_name}" |
|
|
if field_config['type'] == 'text': |
|
|
config_inputs[input_key] = gr.Textbox( |
|
|
label=field_config['label'], |
|
|
value=field_config.get('default', ''), |
|
|
visible=False |
|
|
) |
|
|
elif field_config['type'] == 'textarea': |
|
|
config_inputs[input_key] = gr.Textbox( |
|
|
label=field_config['label'], |
|
|
value=field_config.get('default', ''), |
|
|
lines=3, |
|
|
visible=False |
|
|
) |
|
|
elif field_config['type'] == 'number': |
|
|
config_inputs[input_key] = gr.Number( |
|
|
label=field_config['label'], |
|
|
value=field_config.get('default', 0), |
|
|
visible=False |
|
|
) |
|
|
elif field_config['type'] == 'slider': |
|
|
config_inputs[input_key] = gr.Slider( |
|
|
label=field_config['label'], |
|
|
minimum=field_config.get('min', 0), |
|
|
maximum=field_config.get('max', 1), |
|
|
step=field_config.get('step', 0.1), |
|
|
value=field_config.get('default', 0), |
|
|
visible=False |
|
|
) |
|
|
elif field_config['type'] == 'dropdown': |
|
|
config_inputs[input_key] = gr.Dropdown( |
|
|
label=field_config['label'], |
|
|
choices=field_config['choices'], |
|
|
value=field_config.get('default'), |
|
|
visible=False |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
save_config_btn = gr.Button("💾 Save Config", variant="primary") |
|
|
cancel_config_btn = gr.Button("❌ Cancel", variant="secondary") |
|
|
with gr.Row(): |
|
|
gr.Markdown("---") |
|
|
gr.Markdown("## 🔗 Connections") |
|
|
with gr.Row(): |
|
|
from_node = gr.Dropdown(label="From", choices=[], interactive=True, scale=2) |
|
|
to_node = gr.Dropdown(label="To", choices=[], interactive=True, scale=2) |
|
|
connect_btn = gr.Button("➡️ Connect Nodes", variant="secondary") |
|
|
|
|
|
|
|
|
with gr.Column(scale=1, min_width=300): |
|
|
gr.Markdown("## 📊 Workflow Information") |
|
|
|
|
|
with gr.Accordion("📋 Workflow JSON", open=False): |
|
|
workflow_json = gr.JSON(label="Complete Workflow Data") |
|
|
|
|
|
with gr.Accordion("📝 Component Info", open=True): |
|
|
component_info = gr.Markdown("Select a component to see details") |
|
|
|
|
|
gr.Markdown("---") |
|
|
gr.Markdown("## 📄 System Report") |
|
|
report_btn = gr.Button("📊 Generate Report", variant="primary") |
|
|
report_output = gr.Textbox( |
|
|
label="Design Report", |
|
|
lines=10, |
|
|
max_lines=15, |
|
|
interactive=False |
|
|
) |
|
|
download_report_btn = gr.Button("📥 Download Report", variant="secondary") |
|
|
|
|
|
gr.Markdown("---") |
|
|
download_files = gr.Files(label="📥 Download Files") |
|
|
|
|
|
|
|
|
def get_full_state(): |
|
|
"""Get complete application state""" |
|
|
svg = workflow.render_svg() |
|
|
node_choices = list(workflow.nodes.keys()) |
|
|
wf_json = workflow.get_workflow_json() |
|
|
|
|
|
|
|
|
selected_info = "**No node selected**" |
|
|
comp_info_text = "Select a component to see its description and configuration options" |
|
|
config_data = {} |
|
|
|
|
|
if workflow.selected_node and workflow.selected_node in workflow.nodes: |
|
|
node = workflow.nodes[workflow.selected_node] |
|
|
comp_info = ALL_COMPONENTS.get(node.type, {}) |
|
|
selected_info = f"**Selected:** `{node.label}`\n\n**Type:** {node.type}\n**Position:** ({node.x}, {node.y})" |
|
|
comp_info_text = f"### {comp_info.get('icon', '❓')} {node.type}\n\n{comp_info.get('description', 'No description available')}" |
|
|
config_data = node.config |
|
|
|
|
|
return ( |
|
|
svg, |
|
|
gr.Dropdown(choices=node_choices), |
|
|
gr.Dropdown(choices=node_choices), |
|
|
selected_info, |
|
|
config_data, |
|
|
wf_json, |
|
|
comp_info_text, |
|
|
gr.update(visible=False), |
|
|
) |
|
|
|
|
|
def add_node_simple(node_type): |
|
|
"""Add node with default configuration""" |
|
|
default_config = {} |
|
|
if node_type in COMPONENT_INFO and 'config_fields' in COMPONENT_INFO[node_type]: |
|
|
for field_name, field_config in COMPONENT_INFO[node_type]['config_fields'].items(): |
|
|
default_config[field_name] = field_config.get('default', '') |
|
|
default_config['name'] = f"{node_type}_{workflow.node_counter + 1}" |
|
|
|
|
|
workflow.add_node(node_type, default_config) |
|
|
return get_full_state() |
|
|
|
|
|
def select_node_handler(node_id): |
|
|
"""Handle node selection""" |
|
|
if node_id: |
|
|
workflow.select_node(node_id) |
|
|
return get_full_state() |
|
|
|
|
|
def navigate_nodes(direction): |
|
|
"""Navigate between nodes""" |
|
|
if workflow.nodes: |
|
|
node_ids = list(workflow.nodes.keys()) |
|
|
if not workflow.selected_node: |
|
|
workflow.selected_node = node_ids[0] |
|
|
else: |
|
|
current_idx = node_ids.index(workflow.selected_node) |
|
|
if direction == 'next': |
|
|
new_idx = (current_idx + 1) % len(node_ids) |
|
|
else: |
|
|
new_idx = (current_idx - 1) % len(node_ids) |
|
|
workflow.selected_node = node_ids[new_idx] |
|
|
return get_full_state() |
|
|
|
|
|
def move_node_handler(dx, dy): |
|
|
"""Move selected node""" |
|
|
if workflow.selected_node: |
|
|
workflow.move_selected_node(dx, dy) |
|
|
return get_full_state() |
|
|
|
|
|
def connect_nodes_handler(from_node, to_node): |
|
|
"""Connect two nodes""" |
|
|
if from_node and to_node and from_node != to_node: |
|
|
workflow.add_connection(from_node, to_node) |
|
|
return get_full_state() |
|
|
|
|
|
def delete_selected_handler(): |
|
|
"""Delete selected node""" |
|
|
if workflow.selected_node: |
|
|
workflow.delete_node(workflow.selected_node) |
|
|
return get_full_state() |
|
|
|
|
|
def load_example_handler(example_name): |
|
|
"""Load example workflow""" |
|
|
if example_name: |
|
|
workflow.load_example(example_name) |
|
|
return get_full_state() |
|
|
|
|
|
def clear_workflow_handler(): |
|
|
"""Clear entire workflow""" |
|
|
workflow.nodes.clear() |
|
|
workflow.connections.clear() |
|
|
workflow.node_counter = 0 |
|
|
workflow.selected_node = None |
|
|
return get_full_state() |
|
|
|
|
|
def show_config_form(): |
|
|
"""Show configuration form for selected node""" |
|
|
if not workflow.selected_node: |
|
|
return get_full_state() |
|
|
|
|
|
node = workflow.nodes[workflow.selected_node] |
|
|
updates = list(get_full_state()) |
|
|
updates[-1] = gr.update(visible=True) |
|
|
|
|
|
|
|
|
for input_key in config_inputs: |
|
|
comp_type, field_name = input_key.split('_', 1) |
|
|
if comp_type == node.type: |
|
|
updates.append(gr.update(visible=True, value=node.config.get(field_name, ''))) |
|
|
else: |
|
|
updates.append(gr.update(visible=False)) |
|
|
|
|
|
return tuple(updates) |
|
|
|
|
|
def save_config_handler(*config_values): |
|
|
"""Save configuration for selected node""" |
|
|
if not workflow.selected_node: |
|
|
return get_full_state() |
|
|
|
|
|
node = workflow.nodes[workflow.selected_node] |
|
|
new_config = {} |
|
|
|
|
|
|
|
|
for idx, (input_key, input_comp) in enumerate(config_inputs.items()): |
|
|
comp_type, field_name = input_key.split('_', 1) |
|
|
if comp_type == node.type: |
|
|
new_config[field_name] = config_values[idx] |
|
|
|
|
|
workflow.update_node_config(workflow.selected_node, new_config) |
|
|
|
|
|
updates = list(get_full_state()) |
|
|
updates[-1] = gr.update(visible=False) |
|
|
return tuple(updates) |
|
|
|
|
|
|
|
|
for btn, comp_type in component_buttons: |
|
|
btn.click( |
|
|
lambda ct=comp_type: add_node_simple(ct), |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form |
|
|
] |
|
|
) |
|
|
|
|
|
|
|
|
select_prev_btn.click( |
|
|
lambda: navigate_nodes('prev'), |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form |
|
|
] |
|
|
) |
|
|
|
|
|
select_next_btn.click( |
|
|
lambda: navigate_nodes('next'), |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form |
|
|
] |
|
|
) |
|
|
|
|
|
|
|
|
movement_buttons = [move_left_btn, move_right_btn, move_up_btn, move_down_btn] |
|
|
movements = [(-20, 0), (20, 0), (0, -20), (0, 20)] |
|
|
|
|
|
for btn, (dx, dy) in zip(movement_buttons, movements): |
|
|
btn.click( |
|
|
lambda dx=dx, dy=dy: move_node_handler(dx, dy), |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form |
|
|
] |
|
|
) |
|
|
|
|
|
|
|
|
connect_btn.click( |
|
|
connect_nodes_handler, |
|
|
inputs=[from_node, to_node], |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form |
|
|
] |
|
|
) |
|
|
|
|
|
delete_btn.click( |
|
|
delete_selected_handler, |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form |
|
|
] |
|
|
) |
|
|
|
|
|
load_example_btn.click( |
|
|
load_example_handler, |
|
|
inputs=[example_dropdown], |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form |
|
|
] |
|
|
) |
|
|
|
|
|
clear_btn.click( |
|
|
clear_workflow_handler, |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form |
|
|
] |
|
|
) |
|
|
|
|
|
|
|
|
save_config_btn.click( |
|
|
save_config_handler, |
|
|
inputs=list(config_inputs.values()), |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form |
|
|
] + list(config_inputs.values()) |
|
|
) |
|
|
|
|
|
cancel_config_btn.click( |
|
|
lambda: get_full_state() + tuple([gr.update(visible=False)] * len(config_inputs)), |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form |
|
|
] + list(config_inputs.values()) |
|
|
) |
|
|
|
|
|
|
|
|
def handle_canvas_double_click(): |
|
|
return show_config_form() |
|
|
|
|
|
|
|
|
def download_workflow(): |
|
|
wf_json = workflow.get_workflow_json() |
|
|
json_path = tempfile.mktemp(suffix="_workflow.json") |
|
|
with open(json_path, "w", encoding="utf-8") as f: |
|
|
json.dump(wf_json, f, indent=2) |
|
|
|
|
|
svg_path = tempfile.mktemp(suffix="_workflow.svg") |
|
|
with open(svg_path, "w", encoding="utf-8") as f: |
|
|
f.write(workflow.render_svg()) |
|
|
|
|
|
return [json_path, svg_path] |
|
|
|
|
|
def generate_report(): |
|
|
wf_data = workflow.get_workflow_json() |
|
|
json_str = json.dumps(wf_data, indent=2) |
|
|
try: |
|
|
report = asyncio.run(reporter.generate_report(json_str)) |
|
|
except Exception as e: |
|
|
report = f"Report generation failed: {str(e)}\n\nPlease ensure LM Studio is running with a model loaded." |
|
|
return report |
|
|
|
|
|
def download_report_func(): |
|
|
report_text = generate_report() |
|
|
report_path = tempfile.mktemp(suffix="_report.txt") |
|
|
with open(report_path, "w", encoding="utf-8") as f: |
|
|
f.write(f"Agentic Workflow Design Report\n") |
|
|
f.write(f"Generated: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n") |
|
|
f.write(report_text) |
|
|
return [report_path] |
|
|
|
|
|
download_btn.click(download_workflow, outputs=[download_files]) |
|
|
report_btn.click(generate_report, outputs=[report_output]) |
|
|
download_report_btn.click(download_report_func, outputs=[download_files]) |
|
|
|
|
|
|
|
|
js_code = ''' |
|
|
<script> |
|
|
window.gradio_api = function(type, data) { |
|
|
if (type === 'select_node') { |
|
|
const event = new CustomEvent('gradio_node_select', { detail: data }); |
|
|
document.dispatchEvent(event); |
|
|
} |
|
|
}; |
|
|
|
|
|
document.addEventListener('gradio_node_select', (e) => { |
|
|
// This will be handled by Gradio's event system |
|
|
console.log('Node selected:', e.detail); |
|
|
}); |
|
|
</script> |
|
|
''' |
|
|
|
|
|
def init_app(): |
|
|
state = get_full_state() |
|
|
return state + (js_code,) |
|
|
|
|
|
demo.load( |
|
|
init_app, |
|
|
outputs=[ |
|
|
canvas, from_node, to_node, selected_node_info, |
|
|
config_display, workflow_json, component_info, config_form, |
|
|
gr.HTML(visible=False) |
|
|
] |
|
|
) |
|
|
|
|
|
return demo |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_main_workflow_ui(): |
|
|
"""Create unified interface with proper modal popup""" |
|
|
with gr.Blocks(title="Agent Workflow Designer", theme=gr.themes.Soft()) as demo: |
|
|
gr.Markdown("# 🎓 Agentic System Workflow Designer") |
|
|
gr.Markdown("**Educational tool for planning agent architectures**") |
|
|
|
|
|
|
|
|
pending_component_type = gr.State("") |
|
|
editing_node_id = gr.State("") |
|
|
|
|
|
|
|
|
|
|
|
with gr.Sidebar(open=True,label = "Components",width=600, position = "right"): |
|
|
gr.Markdown("## 📚 Component Library") |
|
|
|
|
|
with gr.Tabs(): |
|
|
with gr.TabItem("Categories"): |
|
|
component_buttons = [] |
|
|
for category, info in COMPONENT_HIERARCHY["HIGH_LEVEL"].items(): |
|
|
with gr.TabItem(f"{info['icon']} {category}"): |
|
|
gr.Markdown(f"*{info['description']}*") |
|
|
|
|
|
btn = gr.Button( |
|
|
f"{info['icon']} Add {category}", |
|
|
size="sm", |
|
|
variant="primary" |
|
|
) |
|
|
component_buttons.append((btn, category)) |
|
|
|
|
|
if info.get('sub_components'): |
|
|
gr.Markdown("**Specialized:**") |
|
|
for sub_comp in info['sub_components']: |
|
|
if sub_comp in COMPONENT_INFO: |
|
|
sub_info = COMPONENT_INFO[sub_comp] |
|
|
sub_btn = gr.Button( |
|
|
f"{sub_info['icon']} {sub_comp.replace('_', ' ').title()}", |
|
|
size="sm" |
|
|
) |
|
|
component_buttons.append((sub_btn, sub_comp)) |
|
|
|
|
|
with gr.TabItem("All"): |
|
|
for comp_type, comp_info in COMPONENT_INFO.items(): |
|
|
btn = gr.Button( |
|
|
f"{comp_info['icon']} {comp_type.replace('_', ' ').title()}", |
|
|
size="sm", |
|
|
variant="secondary" |
|
|
) |
|
|
component_buttons.append((btn, comp_type)) |
|
|
|
|
|
|
|
|
gr.Markdown("---") |
|
|
example_dropdown = gr.Dropdown( |
|
|
choices=list(EXAMPLE_WORKFLOWS.keys()), |
|
|
label="Load Example", |
|
|
interactive=True |
|
|
) |
|
|
load_example_btn = gr.Button("📥 Load", variant="secondary") |
|
|
|
|
|
gr.Markdown("---") |
|
|
with gr.Row(): |
|
|
clear_btn = gr.Button("🗑️ Clear", variant="stop") |
|
|
download_btn = gr.Button("💾 Export", variant="primary") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Column(): |
|
|
|
|
|
with gr.Column(visible=False, elem_classes=["modal-overlay"]) as config_modal: |
|
|
with gr.Row(): |
|
|
gr.Markdown("") |
|
|
|
|
|
|
|
|
with gr.Column(scale=2, min_width=400, elem_classes=["modal-content"]): |
|
|
with gr.Row(): |
|
|
config_modal_title = gr.Markdown("### ⚙️ Configure Component") |
|
|
close_btn = gr.Button("❌", size="sm", elem_classes=["close-btn"]) |
|
|
|
|
|
config_inputs = [] |
|
|
for i in range(8): |
|
|
config_input = gr.Textbox( |
|
|
label=f"Field {i}", |
|
|
visible=False, |
|
|
interactive=True |
|
|
) |
|
|
config_inputs.append(config_input) |
|
|
|
|
|
with gr.Row(): |
|
|
save_new_btn = gr.Button("✅ Add Component", variant="primary") |
|
|
save_edit_btn = gr.Button("✅ Save Changes", variant="primary", visible=False) |
|
|
cancel_btn = gr.Button("❌ Cancel", variant="secondary") |
|
|
|
|
|
gr.Markdown("") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Column(scale=3,min_width=600): |
|
|
gr.Markdown("## 🎨 Canvas") |
|
|
canvas = gr.HTML(min_height=600,label="Workflow") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=2): |
|
|
gr.Markdown("### 🎯 Selected") |
|
|
selected_node_info = gr.Markdown("No node selected") |
|
|
with gr.Row(): |
|
|
from_node = gr.Dropdown(label="From", choices=[], interactive=True) |
|
|
to_node = gr.Dropdown(label="To", choices=[], interactive=True) |
|
|
connect_btn = gr.Button("➡️ Connect", variant="secondary") |
|
|
|
|
|
|
|
|
with gr.Row(): |
|
|
select_prev_btn = gr.Button("⬅️", size="sm") |
|
|
select_next_btn = gr.Button("➡️", size="sm") |
|
|
|
|
|
gr.Markdown("**Move:**") |
|
|
with gr.Row(): |
|
|
move_left_btn = gr.Button("⬅️", size="sm") |
|
|
move_up_btn = gr.Button("⬆️", size="sm") |
|
|
move_down_btn = gr.Button("⬇️", size="sm") |
|
|
move_right_btn = gr.Button("➡️", size="sm") |
|
|
|
|
|
|
|
|
delete_btn = gr.Button("🗑️ Delete", variant="stop", size="sm") |
|
|
edit_config_btn = gr.Button("⚙️ Config", variant="primary", size="sm") |
|
|
|
|
|
with gr.Column(scale=1): |
|
|
gr.Markdown("### ⚙️ Configuration") |
|
|
config_display = gr.JSON(label="Current Config") |
|
|
gr.Markdown("---") |
|
|
with gr.Row(): |
|
|
gr.Markdown("---") |
|
|
gr.Markdown("## 🔗 Connections") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Sidebar(width=600,position = "left",open = False): |
|
|
gr.Markdown("## 📊 Info") |
|
|
|
|
|
with gr.Accordion("📋 JSON", open=True): |
|
|
workflow_json = gr.JSON(label="Workflow Data") |
|
|
|
|
|
with gr.Accordion("📝 Component", open=True): |
|
|
component_info = gr.Markdown("Select a component") |
|
|
|
|
|
gr.Markdown("---") |
|
|
gr.Markdown("## 📄 Report") |
|
|
report_btn = gr.Button("📊 Generate", variant="primary") |
|
|
report_output = gr.Textbox(label="Report", lines=10, interactive=False) |
|
|
|
|
|
gr.Markdown("---") |
|
|
download_files = gr.Files(label="📥 Downloads") |
|
|
|
|
|
|
|
|
demo.css = """ |
|
|
.modal-overlay { |
|
|
position: fixed !important; |
|
|
top: 0 !important; |
|
|
left: 0 !important; |
|
|
width: 100vw !important; |
|
|
height: 100vh !important; |
|
|
background-color: rgba(0,0,0,0.5) !important; |
|
|
z-index: 1000 !important; |
|
|
display: flex !important; |
|
|
align-items: center !important; |
|
|
justify-content: center !important; |
|
|
} |
|
|
.modal-content { |
|
|
background: white !important; |
|
|
padding: 20px !important; |
|
|
border-radius: 10px !important; |
|
|
box-shadow: 0 4px 20px rgba(0,0,0,0.3) !important; |
|
|
max-height: 80vh !important; |
|
|
overflow-y: auto !important; |
|
|
border: 1px solid #ccc !important; |
|
|
} |
|
|
.close-btn { |
|
|
margin-left: auto !important; |
|
|
margin-bottom: 10px !important; |
|
|
} |
|
|
""" |
|
|
|
|
|
|
|
|
def get_full_state(): |
|
|
svg = workflow.render_svg() |
|
|
node_choices = list(workflow.nodes.keys()) |
|
|
wf_json = workflow.get_workflow_json() |
|
|
|
|
|
selected_info = "**No node selected**" |
|
|
comp_info_text = "Select a component" |
|
|
config_data = {} |
|
|
|
|
|
if workflow.selected_node and workflow.selected_node in workflow.nodes: |
|
|
node = workflow.nodes[workflow.selected_node] |
|
|
comp_info = ALL_COMPONENTS.get(node.type, {}) |
|
|
selected_info = f"**Selected:** `{node.label}`\n**Type:** {node.type}" |
|
|
comp_info_text = f"### {comp_info.get('icon', '❓')} {node.type}\n\n{comp_info.get('description', 'No description')}" |
|
|
config_data = node.config |
|
|
|
|
|
return ( |
|
|
svg, |
|
|
gr.Dropdown(choices=node_choices), |
|
|
gr.Dropdown(choices=node_choices), |
|
|
selected_info, |
|
|
config_data, |
|
|
wf_json, |
|
|
comp_info_text, |
|
|
) |
|
|
|
|
|
def show_config_modal(comp_type, is_editing=False, existing_config=None): |
|
|
"""FIXED: Proper modal display with correct field setup""" |
|
|
if not comp_type: |
|
|
return [gr.update(visible=False), "", comp_type, ""] + [gr.update(visible=False)] * 8 + [gr.update(visible=False), gr.update(visible=False)] |
|
|
|
|
|
|
|
|
comp_info = COMPONENT_INFO.get(comp_type, { |
|
|
"icon": "❓", |
|
|
"config_fields": {"name": {"type": "text", "label": "Name", "default": comp_type}} |
|
|
}) |
|
|
|
|
|
action = "Edit" if is_editing else "Add" |
|
|
title = f"### {comp_info.get('icon', '❓')} {action} {comp_type.replace('_', ' ').title()}" |
|
|
|
|
|
updates = [ |
|
|
gr.update(visible=True), |
|
|
title, |
|
|
comp_type, |
|
|
existing_config.get('id', '') if existing_config else "", |
|
|
] |
|
|
|
|
|
|
|
|
field_configs = comp_info.get('config_fields', {}) |
|
|
field_names = list(field_configs.keys()) |
|
|
|
|
|
|
|
|
for i in range(8): |
|
|
if i < len(field_names): |
|
|
field_name = field_names[i] |
|
|
field_config = field_configs[field_name] |
|
|
|
|
|
existing_value = existing_config.get(field_name, field_config.get('default', '')) if existing_config else field_config.get('default', '') |
|
|
|
|
|
updates.append(gr.update( |
|
|
label=field_config['label'], |
|
|
value=str(existing_value), |
|
|
placeholder=field_config.get('placeholder', ''), |
|
|
visible=True, |
|
|
interactive=True |
|
|
)) |
|
|
else: |
|
|
updates.append(gr.update(visible=False)) |
|
|
|
|
|
|
|
|
updates.append(gr.update(visible=not is_editing)) |
|
|
updates.append(gr.update(visible=is_editing)) |
|
|
|
|
|
return updates |
|
|
|
|
|
def save_and_add(comp_type, *field_values): |
|
|
"""Save new component configuration""" |
|
|
if not comp_type: |
|
|
return get_full_state() + (gr.update(visible=False),) |
|
|
|
|
|
comp_info = COMPONENT_INFO.get(comp_type, {}) |
|
|
config = {} |
|
|
|
|
|
if 'config_fields' in comp_info: |
|
|
field_names = list(comp_info['config_fields'].keys()) |
|
|
for i, field_name in enumerate(field_names): |
|
|
if i < len(field_values) and field_values[i] is not None and field_values[i] != "": |
|
|
config[field_name] = field_values[i] |
|
|
|
|
|
|
|
|
if 'name' not in config or not config['name']: |
|
|
config['name'] = f"{comp_type}_{workflow.node_counter + 1}" |
|
|
|
|
|
workflow.add_node(comp_type, config) |
|
|
return get_full_state() + (gr.update(visible=False),) |
|
|
|
|
|
def save_edit(node_id, comp_type, *field_values): |
|
|
"""Save edited component configuration""" |
|
|
if not node_id or node_id not in workflow.nodes: |
|
|
return get_full_state() + (gr.update(visible=False),) |
|
|
|
|
|
comp_info = COMPONENT_INFO.get(comp_type, {}) |
|
|
config = {} |
|
|
|
|
|
if 'config_fields' in comp_info: |
|
|
field_names = list(comp_info['config_fields'].keys()) |
|
|
for i, field_name in enumerate(field_names): |
|
|
if i < len(field_values) and field_values[i] is not None and field_values[i] != "": |
|
|
config[field_name] = field_values[i] |
|
|
|
|
|
workflow.update_node_config(node_id, config) |
|
|
return get_full_state() + (gr.update(visible=False),) |
|
|
|
|
|
def close_modal(): |
|
|
"""Close modal and reset state""" |
|
|
return [gr.update(visible=False), "", ""] |
|
|
|
|
|
|
|
|
for btn, comp_type in component_buttons: |
|
|
btn.click( |
|
|
lambda ct=comp_type: show_config_modal(ct, is_editing=False), |
|
|
outputs=[config_modal, config_modal_title, pending_component_type, editing_node_id] + |
|
|
config_inputs + [save_new_btn, save_edit_btn] |
|
|
) |
|
|
|
|
|
|
|
|
def show_edit(): |
|
|
if not workflow.selected_node or workflow.selected_node not in workflow.nodes: |
|
|
return [gr.update(visible=False)] + [gr.update()] * (3 + 8 + 2) |
|
|
|
|
|
node = workflow.nodes[workflow.selected_node] |
|
|
existing_config = node.config.copy() |
|
|
existing_config['id'] = node.id |
|
|
|
|
|
return show_config_modal(node.type, is_editing=True, existing_config=existing_config) |
|
|
|
|
|
edit_config_btn.click(show_edit, outputs=[config_modal, config_modal_title, pending_component_type, editing_node_id] + config_inputs + [save_new_btn, save_edit_btn]) |
|
|
|
|
|
|
|
|
save_new_btn.click(save_and_add, inputs=[pending_component_type] + config_inputs, |
|
|
outputs=[canvas, from_node, to_node, selected_node_info, config_display, workflow_json, component_info, config_modal]) |
|
|
|
|
|
save_edit_btn.click(save_edit, inputs=[editing_node_id, pending_component_type] + config_inputs, |
|
|
outputs=[canvas, from_node, to_node, selected_node_info, config_display, workflow_json, component_info, config_modal]) |
|
|
|
|
|
|
|
|
cancel_btn.click(close_modal, outputs=[config_modal, pending_component_type, editing_node_id]) |
|
|
close_btn.click(close_modal, outputs=[config_modal, pending_component_type, editing_node_id]) |
|
|
|
|
|
|
|
|
def navigate(direction): |
|
|
if workflow.nodes: |
|
|
node_ids = list(workflow.nodes.keys()) |
|
|
if not workflow.selected_node: |
|
|
workflow.selected_node = node_ids[0] |
|
|
else: |
|
|
idx = node_ids.index(workflow.selected_node) |
|
|
idx = (idx + (1 if direction == 'next' else -1)) % len(node_ids) |
|
|
workflow.selected_node = node_ids[idx] |
|
|
return get_full_state() |
|
|
|
|
|
select_prev_btn.click(lambda: navigate('prev'), outputs=[canvas, from_node, to_node, selected_node_info, config_display, workflow_json, component_info]) |
|
|
select_next_btn.click(lambda: navigate('next'), outputs=[canvas, from_node, to_node, selected_node_info, config_display, workflow_json, component_info]) |
|
|
|
|
|
|
|
|
for btn, dx, dy in [(move_left_btn, -20, 0), (move_right_btn, 20, 0), (move_up_btn, 0, -20), (move_down_btn, 0, 20)]: |
|
|
btn.click(lambda dx=dx, dy=dy: (workflow.move_selected_node(dx, dy) or get_full_state()), |
|
|
outputs=[canvas, from_node, to_node, selected_node_info, config_display, workflow_json, component_info]) |
|
|
|
|
|
|
|
|
connect_btn.click(lambda f, t: (workflow.add_connection(f, t) or get_full_state()) if f and t else get_full_state(), |
|
|
inputs=[from_node, to_node], outputs=[canvas, from_node, to_node, selected_node_info, config_display, workflow_json, component_info]) |
|
|
|
|
|
delete_btn.click(lambda: (workflow.delete_node(workflow.selected_node) or get_full_state()) if workflow.selected_node else get_full_state(), |
|
|
outputs=[canvas, from_node, to_node, selected_node_info, config_display, workflow_json, component_info]) |
|
|
|
|
|
load_example_btn.click(lambda e: (workflow.load_example(e) or get_full_state()) if e else get_full_state(), |
|
|
inputs=[example_dropdown], outputs=[canvas, from_node, to_node, selected_node_info, config_display, workflow_json, component_info]) |
|
|
|
|
|
clear_btn.click(lambda: (workflow.nodes.clear(), workflow.connections.clear(), setattr(workflow, 'node_counter', 0), setattr(workflow, 'selected_node', None), get_full_state())[-1], |
|
|
outputs=[canvas, from_node, to_node, selected_node_info, config_display, workflow_json, component_info]) |
|
|
|
|
|
|
|
|
def export(): |
|
|
wf = workflow.get_workflow_json() |
|
|
json_path = tempfile.mktemp(suffix="_workflow.json") |
|
|
with open(json_path, "w") as f: |
|
|
json.dump(wf, f, indent=2) |
|
|
|
|
|
svg_path = tempfile.mktemp(suffix="_workflow.svg") |
|
|
with open(svg_path, "w") as f: |
|
|
try: |
|
|
f.write(workflow.render_svg()) |
|
|
except: |
|
|
pass |
|
|
return [json_path, svg_path] |
|
|
|
|
|
download_btn.click(export, outputs=[download_files]) |
|
|
|
|
|
def gen_report(): |
|
|
try: |
|
|
wf = json.dumps(workflow.get_workflow_json(), indent=2) |
|
|
return asyncio.run(reporter.generate_report(wf)) |
|
|
except Exception as e: |
|
|
return f"Error: {str(e)}\n\nEnsure LM Studio is running." |
|
|
|
|
|
report_btn.click(gen_report, outputs=[report_output]) |
|
|
|
|
|
|
|
|
demo.load(get_full_state, outputs=[canvas, from_node, to_node, selected_node_info, config_display, workflow_json, component_info]) |
|
|
|
|
|
return demo |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo = create_main_workflow_ui() |
|
|
demo.launch(share=True) |