// Shared JavaScript across all pages
class AgentBuilder {
constructor() {
this.components = [];
this.connections = [];
this.selectedComponent = null;
this.dragging = false;
this.dragOffset = { x: 0, y: 0 };
this.initializeEventListeners();
}
initializeEventListeners() {
const canvas = document.getElementById('canvas');
// Drag start from toolbox
document.querySelectorAll('.toolbox-item').forEach(item => {
item.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', e.target.closest('.toolbox-item').dataset.type);
});
});
// Drop on canvas
canvas.addEventListener('dragover', (e) => {
e.preventDefault();
canvas.classList.add('border-blue-500');
});
canvas.addEventListener('dragleave', () => {
canvas.classList.remove('border-blue-500');
});
canvas.addEventListener('drop', (e) => {
e.preventDefault();
canvas.classList.remove('border-blue-500');
const type = e.dataTransfer.getData('text/plain');
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
this.addComponent(type, x, y);
});
// Canvas interactions
canvas.addEventListener('mousedown', (e) => {
const component = e.target.closest('.canvas-component');
if (component) {
this.selectComponent(component);
if (e.target.classList.contains('component-handle')) {
this.startDragging(component, e);
}
} else {
this.deselectComponent();
}
});
document.addEventListener('mousemove', (e) => {
if (this.dragging) {
this.dragComponent(e);
}
});
document.addEventListener('mouseup', () => {
this.dragging = false;
});
}
addComponent(type, x, y) {
const id = `comp-${Date.now()}`;
const component = {
id,
type,
x,
y,
properties: this.getDefaultProperties(type)
};
const element = document.createElement('div');
element.className = 'canvas-component';
element.id = id;
element.style.left = `${x}px`;
element.style.top = `${y}px`;
element.innerHTML = this.getComponentHTML(type, id);
document.getElementById('canvas').appendChild(element);
this.components.push(component);
// Add event listeners to the new component
element.addEventListener('dblclick', () => this.showProperties(component));
this.addConnectionPoints(element, id);
}
getComponentHTML(type, id) {
const templates = {
'react-agent': `
React Agent
Reasoning engine
`,
'tool': `
Tool
Function tool
`,
'prompt': `
Prompt Template
Chat setup
`,
'memory': `
Memory
State storage
`
};
return templates[type] || 'Unknown Component
';
}
addConnectionPoints(element, id) {
const inputPoint = document.createElement('div');
inputPoint.className = 'connection-point input';
inputPoint.dataset.component = id;
inputPoint.dataset.type = 'input';
const outputPoint = document.createElement('div');
outputPoint.className = 'connection-point output';
outputPoint.dataset.component = id;
outputPoint.dataset.type = 'output';
element.appendChild(inputPoint);
element.appendChild(outputPoint);
}
getDefaultProperties(type) {
const defaults = {
'react-agent': {
name: 'react_agent',
model: 'gpt-4',
temperature: 0.7
},
'tool': {
name: 'custom_tool',
description: 'A custom function tool',
function: 'def tool_function(input):\n return "processed: " + input'
},
'prompt': {
template: 'You are a helpful assistant. Answer the following question: {question}',
variables: ['question']
},
'memory': {
type: 'MemorySaver',
checkpoint_ttl: 3600
}
};
return defaults[type] || {};
}
selectComponent(componentElement) {
this.deselectComponent();
componentElement.classList.add('selected');
this.selectedComponent = this.components.find(c => c.id === componentElement.id);
this.showProperties(this.selectedComponent);
}
deselectComponent() {
document.querySelectorAll('.canvas-component.selected').forEach(el => {
el.classList.remove('selected');
});
this.selectedComponent = null;
this.hideProperties();
}
startDragging(componentElement, e) {
this.dragging = true;
const rect = componentElement.getBoundingClientRect();
const canvasRect = document.getElementById('canvas').getBoundingClientRect();
this.dragOffset = {
x: e.clientX - rect.left + canvasRect.left,
y: e.clientY - rect.top + canvasRect.top
};
}
dragComponent(e) {
if (!this.selectedComponent) return;
const canvasRect = document.getElementById('canvas').getBoundingClientRect();
const x = e.clientX - this.dragOffset.x;
const y = e.clientY - this.dragOffset.y;
const componentElement = document.getElementById(this.selectedComponent.id);
componentElement.style.left = `${x}px`;
componentElement.style.top = `${y}px`;
this.selectedComponent.x = x;
this.selectedComponent.y = y;
}
showProperties(component) {
const panel = document.getElementById('properties-panel');
const content = document.getElementById('properties-content');
panel.classList.remove('hidden');
content.innerHTML = this.generatePropertiesForm(component);
// Update properties on input change
content.querySelectorAll('input, textarea').forEach(input => {
input.addEventListener('change', (e) => {
component.properties[e.target.name] = e.target.value;
});
});
}
hideProperties() {
document.getElementById('properties-panel').classList.add('hidden');
}
generatePropertiesForm(component) {
const properties = component.properties;
let html = `${component.type.replace('-', ' ')} Properties
`;
Object.keys(properties).forEach(key => {
const value = properties[key];
const isTextarea = typeof value === 'string' && value.includes('\n');
html += `
${isTextarea ?
`` :
``
}
`;
});
return html;
}
exportToPython() {
let code = `# Generated by AgentFlow Studio\n`;
code += `from langchain_core.messages import HumanMessage, ToolMessage\n`;
code += `from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n`;
code += `from langgraph.graph import StateGraph, END\n`;
code += `from langgraph.checkpoint.memory import MemorySaver\n`;
code += `from pydantic import BaseModel, Field\n`;
code += `from langchain.agents import create_react_agent\n\n`;
// Add component definitions
this.components.forEach(comp => {
code += `# ${comp.type} component\n`;
switch(comp.type) {
case 'react-agent':
code += `agent = create_react_agent(\n`;
code += ` model="${comp.properties.model}",\n`;
code += ` temperature=${comp.properties.temperature}\n`;
code += `)\n\n`;
break;
case 'tool':
code += `class ${comp.properties.name.replace('_', ' ').title().replace(' ', '')}Tool(BaseModel):\n`;
code += ` \"\"\"${comp.properties.description}\"\"\"\n\n`;
code += ` def execute(self, input: str) -> str:\n`;
code += ` ${comp.properties.function.replace('\n', '\n ')}\n\n`;
break;
case 'prompt':
code += `prompt_template = ChatPromptTemplate.from_template(\n`;
code += ` \"\"\"${comp.properties.template}\"\"\"\n`;
code += `)\n\n`;
break;
case 'memory':
code += `memory = MemorySaver()\n\n`;
break;
}
});
// Add graph construction
code += `# Build the agent graph\n`;
code += `graph_builder = StateGraph()\n\n`;
code += `# Export the final agent\n`;
code += `def get_agent():\n`;
code += ` return graph_builder.compile()\n`;
return code;
}
}
// Global functions for UI interactions
function startNewProject() {
const builder = new AgentBuilder();
window.agentBuilder = builder;
document.getElementById('canvas').innerHTML = '';
document.getElementById('properties-panel').classList.add('hidden');
}
function loadSample() {
startNewProject();
// Add sample components
window.agentBuilder.addComponent('react-agent', 100, 100);
window.agentBuilder.addComponent('tool', 300, 100);
window.agentBuilder.addComponent('prompt', 100, 200);
window.agentBuilder.addComponent('memory', 300, 200);
}
function loadExample(exampleType) {
startNewProject();
switch(exampleType) {
case 'research':
// Research Assistant Example
const researchAgent = window.agentBuilder.addComponent('react-agent', 100, 100);
const webSearchTool = window.agentBuilder.addComponent('tool', 300, 100);
const researchPrompt = window.agentBuilder.addComponent('prompt', 100, 200);
const researchMemory = window.agentBuilder.addComponent('memory', 300, 200);
// Configure components
const researchComponents = window.agentBuilder.components;
researchComponents.find(c => c.id === researchAgent).properties = {
name: 'research_assistant',
model: 'gpt-4',
temperature: 0.3,
max_tokens: 2000
};
researchComponents.find(c => c.id === webSearchTool).properties = {
name: 'web_search',
description: 'Search the web for current information',
function: 'def web_search(query):\n # Implementation for web search\n return f"Searched for: {query}"'
};
researchComponents.find(c => c.id === researchPrompt).properties = {
template: 'You are a research assistant. Search for information about: {topic}. Provide detailed, well-sourced answers.',
variables: ['topic']
};
researchComponents.find(c => c.id === researchMemory).properties = {
type: 'MemorySaver',
checkpoint_ttl: 7200
};
break;
case 'ecommerce':
// E-commerce Assistant Example
const ecomAgent = window.agentBuilder.addComponent('react-agent', 100, 100);
const productSearch = window.agentBuilder.addComponent('tool', 300, 100);
const priceCompare = window.agentBuilder.addComponent('tool', 500, 100);
const ecomPrompt = window.agentBuilder.addComponent('prompt', 100, 200);
const ecomMemory = window.agentBuilder.addComponent('memory', 300, 200);
const ecomComponents = window.agentBuilder.components;
ecomComponents.find(c => c.id === ecomAgent).properties = {
name: 'ecommerce_assistant',
model: 'gpt-4',
temperature: 0.2,
max_tokens: 1500
};
ecomComponents.find(c => c.id === productSearch).properties = {
name: 'product_search',
description: 'Search for products in the catalog',
function: 'def product_search(category, keywords):\n # Search product database\n return f"Products in {category} matching {keywords}"'
};
ecomComponents.find(c => c.id === priceCompare).properties = {
name: 'price_comparison',
description: 'Compare prices across different vendors',
function: 'def price_comparison(product_id):\n # Get price comparisons\n return f"Price comparison for product {product_id}"'
};
ecomComponents.find(c => c.id === ecomPrompt).properties = {
template: 'You are an e-commerce assistant. Help customers find products and compare prices. Be helpful and concise.',
variables: ['user_query']
};
ecomComponents.find(c => c.id === ecomMemory).properties = {
type: 'MemorySaver',
checkpoint_ttl: 3600
};
break;
case 'code':
// Code Assistant Example
const codeAgent = window.agentBuilder.addComponent('react-agent', 100, 100);
const codeGenerator = window.agentBuilder.addComponent('tool', 300, 100);
const debuggerTool = window.agentBuilder.addComponent('tool', 500, 100);
const codePrompt = window.agentBuilder.addComponent('prompt', 100, 200);
const codeMemory = window.agentBuilder.addComponent('memory', 300, 200);
const codeComponents = window.agentBuilder.components;
codeComponents.find(c => c.id === codeAgent).properties = {
name: 'code_assistant',
model: 'gpt-4',
temperature: 0.1,
max_tokens: 3000
};
codeComponents.find(c => c.id === codeGenerator).properties = {
name: 'code_generation',
description: 'Generate code based on requirements',
function: 'def generate_code(language, requirements):\n # Generate code implementation\n return f"Generated {language} code for: {requirements}"'
};
codeComponents.find(c => c.id === debuggerTool).properties = {
name: 'debug_code',
description: 'Help debug and fix code issues',
function: 'def debug_code(code, error):\n # Debug code implementation\n return f"Debugged code with error: {error}"'
};
codeComponents.find(c => c.id === codePrompt).properties = {
template: 'You are a programming assistant. Help with code generation, debugging, and explanations. Provide clear, working code examples.',
variables: ['programming_task']
};
codeComponents.find(c => c.id === codeMemory).properties = {
type: 'MemorySaver',
checkpoint_ttl: 4800
};
break;
case 'support':
// Customer Support Example
const supportAgent = window.agentBuilder.addComponent('react-agent', 100, 100);
const faqSearch = window.agentBuilder.addComponent('tool', 300, 100);
const ticketCreator = window.agentBuilder.addComponent('tool', 500, 100);
const supportPrompt = window.agentBuilder.addComponent('prompt', 100, 200);
const supportMemory = window.agentBuilder.addComponent('memory', 300, 200);
const supportComponents = window.agentBuilder.components;
supportComponents.find(c => c.id === supportAgent).properties = {
name: 'support_agent',
model: 'gpt-4',
temperature: 0.4,
max_tokens: 1200
};
supportComponents.find(c => c.id === faqSearch).properties = {
name: 'faq_search',
description: 'Search the FAQ database for answers',
function: 'def search_faq(question):\n # Search FAQ database\n return f"FAQ results for: {question}"'
};
supportComponents.find(c => c.id === ticketCreator).properties = {
name: 'create_ticket',
description: 'Create a support ticket for escalation',
function: 'def create_ticket(issue, priority):\n # Create support ticket\n return f"Created {priority} ticket for: {issue}"'
};
supportComponents.find(c => c.id === supportPrompt).properties = {
template: 'You are a customer support agent. Be empathetic and helpful. Use FAQs when possible, escalate when needed.',
variables: ['customer_issue']
};
supportComponents.find(c => c.id === supportMemory).properties = {
type: 'MemorySaver',
checkpoint_ttl: 2400
};
break;
case 'analyst':
// Data Analyst Example
const analystAgent = window.agentBuilder.addComponent('react-agent', 100, 100);
const dataProcessor = window.agentBuilder.addComponent('tool', 300, 100);
const statsAnalyzer = window.agentBuilder.addComponent('tool', 500, 100);
const analystPrompt = window.agentBuilder.addComponent('prompt', 100, 200);
const analystMemory = window.agentBuilder.addComponent('memory', 300, 200);
const analystComponents = window.agentBuilder.components;
analystComponents.find(c => c.id === analystAgent).properties = {
name: 'data_analyst',
model: 'gpt-4',
temperature: 0.2,
max_tokens: 2500
};
analystComponents.find(c => c.id === dataProcessor).properties = {
name: 'process_data',
description: 'Process and clean datasets',
function: 'def process_data(dataset, operations):\n # Process data implementation\n return f"Processed dataset with: {operations}"'
};
analystComponents.find(c => c.id === statsAnalyzer).properties = {
name: 'analyze_statistics',
description: 'Perform statistical analysis on data',
function: 'def analyze_stats(data, metrics):\n # Statistical analysis\n return f"Analysis results for metrics: {metrics}"'
};
analystComponents.find(c => c.id === analystPrompt).properties = {
template: 'You are a data analyst. Help analyze datasets, generate insights, and create visualizations. Be precise and data-driven.',
variables: ['analysis_request']
};
analystComponents.find(c => c.id === analystMemory).properties = {
type: 'MemorySaver',
checkpoint_ttl: 6000
};
break;
case 'translator':
// Multi-language Translator Example
const translatorAgent = window.agentBuilder.addComponent('react-agent', 100, 100);
const translateTool = window.agentBuilder.addComponent('tool', 300, 100);
const contextTool = window.agentBuilder.addComponent('tool', 500, 100);
const translatorPrompt = window.agentBuilder.addComponent('prompt', 100, 200);
const translatorMemory = window.agentBuilder.addComponent('memory', 300, 200);
const translatorComponents = window.agentBuilder.components;
translatorComponents.find(c => c.id === translatorAgent).properties = {
name: 'translator',
model: 'gpt-4',
temperature: 0.3,
max_tokens: 1800
};
translatorComponents.find(c => c.id === translateTool).properties = {
name: 'translate_text',
description: 'Translate text between languages',
function: 'def translate(text, source_lang, target_lang):\n # Translation implementation\n return f"Translated from {source_lang} to {target_lang}: {text}"'
};
translatorComponents.find(c => c.id === contextTool).properties = {
name: 'preserve_context',
description: 'Maintain context and cultural nuances',
function: 'def preserve_context(translation, context):\n # Context preservation\n return f"Context-preserved translation: {translation}"'
};
translatorComponents.find(c => c.id === translatorPrompt).properties = {
template: 'You are a multilingual translator. Translate text while preserving meaning, context, and cultural nuances. Support multiple languages.',
variables: ['text_to_translate', 'target_language']
};
translatorComponents.find(c => c.id === translatorMemory).properties = {
type: 'MemorySaver',
checkpoint_ttl: 5400
};
break;
}
// Update the UI to show the loaded example
document.getElementById('properties-panel').classList.add('hidden');
// Show success message
showNotification(`Loaded ${exampleType.replace(/_/g, ' ')} example successfully!`, 'success');
}
function exportAgent() {
if (!window.agentBuilder || window.agentBuilder.components.length === 0) {
showNotification('Please add some components to the canvas first!', 'error');
return;
}
const code = window.agentBuilder.exportToPython();
showCodeModal(code);
}
function clearCanvas() {
if (confirm('Are you sure you want to clear the canvas?')) {
document.getElementById('canvas').innerHTML = '';
document.getElementById('properties-panel').classList.add('hidden');
if (window.agentBuilder) {
window.agentBuilder.components = [];
window.agentBuilder.connections = [];
}
showNotification('Canvas cleared successfully!', 'success');
}
}
function showCodeModal(code) {
const modal = document.createElement('div');
modal.className = 'modal-overlay';
modal.innerHTML = `
Generated Python Code
${code}
`;
document.body.appendChild(modal);
feather.replace();
window.copyCode = function() {
navigator.clipboard.writeText(code).then(() => {
alert('Code copied to clipboard!');
});
};
window.downloadCode = function() {
const blob = new Blob([code], { type: 'text/python' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'langchain_agent.py';
a.click();
URL.revokeObjectURL(url);
};
}
// Notification system
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg transition-all duration-300 transform translate-x-full ${
type === 'success' ? 'bg-green-600' :
type === 'error' ? 'bg-red-600' :
'bg-blue-600'
} text-white`;
notification.innerHTML = `
${message}
`;
document.body.appendChild(notification);
// Animate in
setTimeout(() => {
notification.style.transform = 'translateX(0)';
}, 100);
// Animate out and remove
setTimeout(() => {
notification.style.transform = 'translateX(full)';
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 300);
}, 3000);
feather.replace();
}
// Initialize the app when page loads
document.addEventListener('DOMContentLoaded', () => {
window.agentBuilder = new AgentBuilder();
feather.replace();
// Check for example parameter in URL
const urlParams = new URLSearchParams(window.location.search);
const example = urlParams.get('example');
if (example && ['research', 'ecommerce', 'code', 'support', 'analyst', 'translator'].includes(example)) {
// Small delay to ensure everything is loaded
setTimeout(() => {
loadExample(example);
}, 500);
}
});
console.log('AgentFlow Studio loaded');