diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -1,70 +1,2558 @@ +from dataclasses import asdict, dataclass, field +import os +import pickle +from typing import Dict, List, Optional, Any import gradio as gr -from huggingface_hub import InferenceClient - - -def respond( - message, - history: list[dict[str, str]], - system_message, - max_tokens, - temperature, - top_p, - hf_token: gr.OAuthToken, -): - """ - For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference - """ - client = InferenceClient(token=hf_token.token, model="openai/gpt-oss-20b") - - messages = [{"role": "system", "content": system_message}] - - messages.extend(history) - - messages.append({"role": "user", "content": message}) - - response = "" - - for message in client.chat_completion( - messages, - max_tokens=max_tokens, - stream=True, - temperature=temperature, - top_p=top_p, - ): - choices = message.choices - token = "" - if len(choices) and choices[0].delta.content: - token = choices[0].delta.content - - response += token - yield response - - -""" -For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface -""" -chatbot = gr.ChatInterface( - respond, - type="messages", - additional_inputs=[ - gr.Textbox(value="You are a friendly Chatbot.", label="System message"), - gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"), - gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"), - gr.Slider( - minimum=0.1, - maximum=1.0, - value=0.95, - step=0.05, - label="Top-p (nucleus sampling)", - ), - ], -) - -with gr.Blocks() as demo: - with gr.Sidebar(): - gr.LoginButton() - chatbot.render() +import json +import tempfile +import asyncio +import uuid +from dataclasses import dataclass, asdict +from typing import List, Dict, Optional, Any +from openai import AsyncOpenAI +#================================================================================ +# Unified Hierarchical Component definitions for UML and Object-Oriented Design +# as well as agentic design +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"] + }, + } +} +# Complete Component Information with Configuration +COMPONENT_INFO = { + # =================================== + # CLASS: Class diagram elements + # =================================== + "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": ["<>", "<>", ""], "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"}, + } + }, + + # =================================== + # USECASE: Use case diagram elements + # =================================== + "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": "<>", "default": "<>"}, + } + }, + + "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": "<>", "default": "<>"}, + "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"}, + } + }, + + # =================================== + # SEQUENCE: Sequence diagram elements + # =================================== + "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"}, + } + }, + + # =================================== + # ACTIVITY: Activity diagram elements + # =================================== + "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: State machine elements + # =================================== + "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": ""}, + } + }, + + # =================================== + # OBJECT: Object diagram elements + # =================================== + "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: Component diagram elements + # =================================== + "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": "<>"}, + } + }, + + # =================================== + # DEPLOYMENT: Deployment diagram elements + # =================================== + "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: Package diagram elements + # =================================== + "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": "<>"}, + } + }, + # SYSTEM + "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 + "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 + "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 - FIXED: All tools now have proper config_fields + "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 + "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 + "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 + "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 + "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 + "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"}, + } + }, +} + +# Enhanced Example workflows +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"} + ] + } +} +#================================================================================ + +# Combine all components +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 + +# CRITICAL FIX: Ensure ALL components have config_fields +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 ''' + + + + + + + + + 🚀 Start Building Your Workflow + Add components from the library + + ''' + + width = 1200 + height = max(600, max([n.y for n in self.nodes.values()], default=0) + 200) + + svg_parts = [ + f'', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '' + ] + + # Draw connections + 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'' + ) + + # Draw nodes + 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" + + # Node background + if comp_data.shape == "ellipse": + svg_parts.append( + f'' + ) + elif comp_data.shape == "cylinder": + svg_parts.append( + f'' + ) + svg_parts.append( + f'' + ) + svg_parts.append( + f'' + ) + svg_parts.append( + f'' + ) + svg_parts.append( + f'' + ) + 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'' + ) + 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'' + ) + else: # rect, document, folder + svg_parts.append( + f'' + ) + + # Icon + svg_parts.append( + f'{comp_data.icon}' + ) + + # Label + label_display = node.label[:15] + "..." if len(node.label) > 15 else node.label + svg_parts.append( + f'{label_display}' + ) + + svg_parts.append('') + 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() +#================================================================================ +#================================================================================ +# Original Fully working model ! +#================================================================================ +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**") + + # State variables + selected_node_state = gr.State(None) + pending_component_type = gr.State(None) + + with gr.Row(equal_height=False): + # Left Sidebar - Component Library + with gr.Column(scale=1, min_width=300): + gr.Markdown("## 📚 Component Library") + + with gr.Tabs() as library_tabs: + # High-level categories tab + 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']}*") + + # Main category button + btn = gr.Button( + f"{info['icon']} Add {category}", + size="sm", + variant="primary" + ) + component_buttons.append((btn, category)) + + # Sub-components + 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)) + + # All components tab + 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") + + # Center - Canvas and Configuration + 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", + + ) + + # Dynamic configuration form + 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") + + # Right Sidebar - Information and Export + 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") + + # Core state management functions + 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 node info + 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, # canvas + gr.Dropdown(choices=node_choices), # from_node + gr.Dropdown(choices=node_choices), # to_node + selected_info, # selected_node_info + config_data, # config_display + wf_json, # workflow_json + comp_info_text, # component_info + gr.update(visible=False), # config_form + ) + + 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: # prev + 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) # Show config form + + # Show relevant config inputs + 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 = {} + + # Build config from visible inputs + 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) # Hide config form + return tuple(updates) + + # Connect component buttons + 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 + ] + ) + + # Connect navigation and interaction + 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 + 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 + ] + ) + + # Other interactions + 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 + ] + ) + + # Configuration 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()) + ) + + # Double-click to edit config + def handle_canvas_double_click(): + return show_config_form() + + # Download functions + 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]) + + # JavaScript for node selection + js_code = ''' + + ''' + + 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) # For JS code + ] + ) + + return demo +#================================================================================ + +#================================================================================ +# FULL VERSION +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**") + + # State variables + pending_component_type = gr.State("") + editing_node_id = gr.State("") + +#================================================================================ + # Left Sidebar + 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") + + # Center + + +#================================================================================ + with gr.Column(): + # Config Modal - + with gr.Column(visible=False, elem_classes=["modal-overlay"]) as config_modal: + with gr.Row(): + gr.Markdown("") # Left spacer + + # Modal content + 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): # Reasonable number of fields + 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("") # Right spacer + +#================================================================================ + + # Canvas - + 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") + + +#================================================================================ + + + + + + + # Right Sidebar + 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") +#================================================================================ + # Add custom CSS for modal styling + 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; + } + """ +#================================================================================ + # Helper functions + 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)] + + # Get component info + 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), # modal + title, + comp_type, + existing_config.get('id', '') if existing_config else "", + ] + + # Get config fields + field_configs = comp_info.get('config_fields', {}) + field_names = list(field_configs.keys()) + + # Update inputs (max 8) + 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)) + + # Button visibility + 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] + + # Ensure name + 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), "", ""] +#================================================================================ + # Connect component buttons + 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] + ) + + # Edit button + 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 buttons + 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]) + + # Close modal actions + 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]) +#================================================================================ + # Navigation and other interactions remain the same... + 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]) + + # Movement + 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]) +#================================================================================ + # Other actions + 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]) +#================================================================================ + # Export + 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]) +#================================================================================ + # Initialize + 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.launch() + demo = create_main_workflow_ui() + demo.launch(share=True) \ No newline at end of file