parent
146402e149
commit
982601614e
@ -0,0 +1,359 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
import litellm
|
||||
|
||||
from swarms import Agent
|
||||
|
||||
litellm.drop_params = True
|
||||
|
||||
|
||||
def extract_code_blocks(text: str) -> str:
|
||||
"""
|
||||
Extracts code blocks enclosed in triple backticks from the given text.
|
||||
|
||||
Args:
|
||||
text (str): The input text containing code blocks.
|
||||
|
||||
Returns:
|
||||
str: The extracted code blocks joined together as a single string.
|
||||
"""
|
||||
# Regular expression to match code blocks enclosed in triple backticks
|
||||
code_block_pattern = re.compile(
|
||||
r"```(?:[a-zA-Z]*)\n(.*?)```", re.DOTALL
|
||||
)
|
||||
|
||||
# Find all matches and join them into a single string
|
||||
matches = code_block_pattern.findall(text)
|
||||
return "\n".join(matches)
|
||||
|
||||
|
||||
# Prompt #1: Translate PyTorch code into CUDA (extensive instructions)
|
||||
translate_pytorch_to_cuda_prompt = """
|
||||
You are an AI agent specialized in converting PyTorch code into efficient,
|
||||
well-structured, and properly functioning CUDA code. Your role is to transform
|
||||
the given PyTorch code (which may include Python-based tensor operations,
|
||||
layers, and training loops) into a CUDA codebase capable of running directly on
|
||||
NVIDIA GPUs without relying on the high-level abstractions of PyTorch.
|
||||
|
||||
Detailed Instructions:
|
||||
1. Read and thoroughly understand every line of the provided PyTorch code,
|
||||
including model definitions, forward passes, loss functions, backward passes,
|
||||
and optimization steps.
|
||||
|
||||
2. Rewrite the code in pure CUDA C/C++:
|
||||
- Convert high-level tensor operations to raw GPU kernel operations and
|
||||
memory management.
|
||||
- Allocate and deallocate memory on the GPU using CUDA APIs like cudaMalloc
|
||||
and cudaFree.
|
||||
- Handle data transfers between the host (CPU) and the device (GPU)
|
||||
appropriately (e.g., cudaMemcpy).
|
||||
- Convert PyTorch's autograd-based gradient calculations into manual CUDA
|
||||
kernel operations or unify them within your own backward pass
|
||||
implementation if needed.
|
||||
- Replace Pythonic loops and array operations with explicit CUDA kernels.
|
||||
- Implement or port any custom CUDA kernels for special functionality.
|
||||
|
||||
3. Optimize the CUDA code for parallel execution:
|
||||
- Use grid and block dimensions that take advantage of the target GPU's
|
||||
compute capabilities and memory bandwidth.
|
||||
- Leverage shared memory, constant memory, or registers when beneficial.
|
||||
- Unroll loops and reduce warp divergence where possible.
|
||||
- Use efficient memory access patterns (e.g., coalesced memory access).
|
||||
|
||||
4. Preserve the overall logic and functionality:
|
||||
- The final CUDA code must produce equivalent numerical results as the
|
||||
original PyTorch code for the same inputs and initialization.
|
||||
- Keep the data types, precision, and numerical stability in mind while
|
||||
performing computations in CUDA.
|
||||
|
||||
5. Ensure readability and maintainability:
|
||||
- Add comments where necessary to explain tricky parts of the CUDA kernels
|
||||
and memory management.
|
||||
- Use clear function or file organization to separate different components
|
||||
(e.g., forward pass, backward pass, kernel definitions, helper utilities).
|
||||
|
||||
6. Remember that the goal is to create an extensive and fully functional .cu
|
||||
file or files that can be compiled with NVCC or integrated into a larger
|
||||
project.
|
||||
|
||||
7. Ensure PyTorch Integration:
|
||||
- Implement proper PyTorch C++ extension interfaces using torch::extension
|
||||
- Include necessary PyTorch headers and macros for tensor operations
|
||||
- Create Python bindings using pybind11 to expose CUDA functions to PyTorch
|
||||
- Handle PyTorch tensor types and conversions appropriately
|
||||
- Ensure compatibility with PyTorch's autograd system
|
||||
- Follow PyTorch's extension conventions for error handling and memory management
|
||||
- Make the code loadable as a PyTorch extension module
|
||||
|
||||
Output Requirements:
|
||||
- Provide only the final CUDA code.
|
||||
- Do not include any explanatory text outside of comments in the code itself.
|
||||
- The CUDA code should stand on its own as a complete solution that can be
|
||||
compiled or integrated without additional references.
|
||||
- The code must be fully compatible with PyTorch's extension system and
|
||||
able to be imported and used seamlessly within PyTorch models.
|
||||
- Ensure the code is fully compatible with PyTorch's extension system.
|
||||
- And, the code should be very long and extensive
|
||||
"""
|
||||
|
||||
# Prompt #2: Make the CUDA code super reliable and fast (extensive instructions)
|
||||
make_cuda_super_reliable_and_fast_prompt = """
|
||||
You are an advanced AI agent whose goal is to take a fully functional CUDA codebase
|
||||
and optimize it to be extraordinarily robust, reliable, and efficient. You must
|
||||
focus on performance improvements at both the kernel level and architectural
|
||||
level, ensuring that the code is streamlined and built to handle potential edge
|
||||
cases gracefully.
|
||||
|
||||
Detailed Instructions:
|
||||
1. Dive deeply into the CUDA kernels and identify performance bottlenecks:
|
||||
- Look for any uncoalesced memory accesses, unnecessary global memory reads,
|
||||
or writes that could be optimized.
|
||||
- Identify any opportunities to reduce shared memory usage, if that memory
|
||||
usage does not yield significant benefit, or to increase it if it can help
|
||||
reduce global memory accesses.
|
||||
|
||||
2. Implement advanced optimization techniques:
|
||||
- Use loop unrolling where beneficial to reduce overhead.
|
||||
- Employ occupancy analysis to find the ideal block size and grid size for
|
||||
maximum parallelism.
|
||||
- Consider the use of constant memory for frequently accessed read-only data.
|
||||
- Evaluate the benefits of pinned (page-locked) memory for host-device
|
||||
transfers.
|
||||
|
||||
3. Improve reliability and error handling:
|
||||
- Insert meaningful checks for CUDA API function calls (e.g., cudaMalloc,
|
||||
cudaMemcpy, cudaFree, kernel launches). Ensure proper cleanup if any call
|
||||
fails or returns an error code.
|
||||
- Handle edge cases where input sizes might be too large or too small,
|
||||
preventing invalid memory accesses or out-of-bounds kernel launches.
|
||||
- Ensure that any macros, compilation flags, or library calls align with
|
||||
best practices for portability across different GPU architectures.
|
||||
|
||||
4. Document any advanced tricks or strategies used:
|
||||
- In-line commentary is crucial. Briefly explain why a specific optimization
|
||||
was chosen and how it impacts performance.
|
||||
|
||||
5. Maintain numerical equivalence:
|
||||
- All transformations must preserve the original numerical outcomes within
|
||||
reasonable floating-point precision limits. Do not alter the algorithmic
|
||||
results unexpectedly.
|
||||
|
||||
6. Provide a clean final output:
|
||||
- The output must be only the improved and optimized CUDA source code.
|
||||
- All extraneous explanation beyond code comments should be avoided.
|
||||
- The code must be very long and extensive, containing all necessary functionality.
|
||||
- Output only the complete code file with no additional text.
|
||||
|
||||
Goal:
|
||||
- Deliver a high-performance CUDA code that is not only efficient in running
|
||||
time but is also resilient, capable of handling unexpected conditions, and
|
||||
thoroughly commented to allow easy maintenance and future modifications.
|
||||
- Ensure the output is a complete, extensive codebase with all functionality included.
|
||||
"""
|
||||
|
||||
# Prompt #3: Cleanup errors and add extensive documentation (extensive instructions)
|
||||
cleanup_and_document_cuda_code_prompt = """
|
||||
You are a specialized AI agent focused on thoroughly debugging, cleaning up, and
|
||||
documenting a CUDA codebase. Your mission is to ensure the code compiles cleanly,
|
||||
handles errors gracefully, follows best coding practices, and includes detailed
|
||||
documentation for maintainability and educational purposes.
|
||||
|
||||
Detailed Instructions:
|
||||
1. Debug and error cleanup:
|
||||
- Identify any compilation or runtime errors and fix them.
|
||||
- Check for mismatched types, undeclared variables, improper memory usage, or
|
||||
incorrect kernel configurations.
|
||||
- Make sure that each kernel launch has correct grid and block dimensions and
|
||||
that indexing inside kernels is handled properly (avoid out-of-bounds
|
||||
threads).
|
||||
|
||||
2. Strengthen error handling:
|
||||
- Wrap all CUDA library calls (cudaMalloc, cudaMemcpy, kernel launches, etc.)
|
||||
with macros or functions that check for and report errors in a consistent
|
||||
manner (e.g., using cudaGetErrorString).
|
||||
- Ensure resources are deallocated in case of failure and that the program
|
||||
can exit safely without memory leaks or GPU lockups.
|
||||
|
||||
3. Add thorough documentation:
|
||||
- Provide high-level explanations near the top of the file describing the
|
||||
overall code structure and flow.
|
||||
- Within each function, write docstrings or block comments to explain the
|
||||
function's purpose, inputs, outputs, and major steps.
|
||||
- For each kernel, add comments describing how threads are mapped to data,
|
||||
how memory is accessed, and what the main loop or computational logic
|
||||
accomplishes.
|
||||
|
||||
4. Check performance remains robust:
|
||||
- Ensure that none of the debugging or cleanup processes introduce unnecessary
|
||||
slowdowns. Where possible, maintain or improve previous optimizations.
|
||||
|
||||
5. Provide final cleaned, well-documented CUDA source code:
|
||||
- The output must contain only the updated source code, with no additional
|
||||
explanation outside of code comments and docstrings.
|
||||
- The code must be ready to compile, fully functional, and in a polished
|
||||
state that one can confidently integrate into a production environment.
|
||||
- The code must be very long and extensive, containing all necessary functionality.
|
||||
- Output only the complete code file with no additional text.
|
||||
|
||||
Goal:
|
||||
- Deliver a thoroughly cleaned, expertly documented CUDA code file. The
|
||||
readability, reliability, and educational clarity of the code should be
|
||||
enhanced without sacrificing computational performance.
|
||||
- Ensure the output is a complete, extensive codebase with all functionality included.
|
||||
"""
|
||||
|
||||
# Prompt #4: Produce a final, extensive CUDA file (extensive instructions)
|
||||
produce_extensive_cuda_file_prompt = """
|
||||
You are an AI agent tasked with producing a final, extensive .cu or .cuh file
|
||||
containing all functionality needed to run the code originally derived from
|
||||
PyTorch. This final file should encapsulate:
|
||||
- The core CUDA kernels.
|
||||
- The initialization and teardown logic for GPU resources.
|
||||
- Optimized computations and any specialized routines (e.g., custom backward
|
||||
passes, advanced math operations).
|
||||
- Comprehensive yet concise in-code documentation.
|
||||
|
||||
Detailed Instructions:
|
||||
1. Merge all relevant kernels, utility functions, and structures into a cohesive
|
||||
single file or a well-structured set of files.
|
||||
2. Ensure you apply all previous optimizations and cleanup efforts, reflecting
|
||||
them in this combined final output.
|
||||
3. Use robust function prototypes for any utility routines, paying attention to
|
||||
scope and avoiding unnecessary global variables.
|
||||
4. Keep the code easily navigable with clear sections:
|
||||
- Data structures and utility definitions.
|
||||
- Kernel definitions.
|
||||
- Host functions for kernel launches.
|
||||
- Initialization and cleanup logic.
|
||||
- Document each section thoroughly for ease of reference.
|
||||
5. Ensure it compiles error-free under standard NVCC compilation.
|
||||
6. Provide only the CUDA code, including all documentation within comments:
|
||||
- No additional external explanation should be outside these comments.
|
||||
- The code must be very long and extensive, containing all necessary functionality.
|
||||
- Output only the complete code file with no additional text.
|
||||
|
||||
Goal:
|
||||
- A single or modular set of .cu/.cuh files that stand as the definitive version
|
||||
of the CUDA codebase, balancing performance, reliability, and maintainability.
|
||||
- Ensure the output is a complete, extensive codebase with all functionality included.
|
||||
"""
|
||||
|
||||
|
||||
# Now create one agent for each prompt, similar to the example with the Financial-Analysis-Agent.
|
||||
translate_agent = Agent(
|
||||
agent_name="Translate-PyTorch-To-CUDA-Agent",
|
||||
system_prompt=translate_pytorch_to_cuda_prompt,
|
||||
model_name="openai/o1",
|
||||
max_loops=1,
|
||||
max_tokens=10000,
|
||||
output_type="str",
|
||||
temperature=0,
|
||||
)
|
||||
|
||||
super_fast_agent = Agent(
|
||||
agent_name="Make-CUDA-Code-Super-Fast-Agent",
|
||||
system_prompt=make_cuda_super_reliable_and_fast_prompt,
|
||||
model_name="openai/o1",
|
||||
max_loops=1,
|
||||
max_tokens=10000,
|
||||
output_type="str",
|
||||
temperature=0,
|
||||
)
|
||||
|
||||
cleanup_agent = Agent(
|
||||
agent_name="Cleanup-and-Document-CUDA-Agent",
|
||||
system_prompt=cleanup_and_document_cuda_code_prompt,
|
||||
model_name="openai/o1",
|
||||
max_loops=1,
|
||||
max_tokens=10000,
|
||||
output_type="str",
|
||||
temperature=0,
|
||||
)
|
||||
|
||||
final_cuda_agent = Agent(
|
||||
agent_name="Produce-Final-Extensive-CUDA-File-Agent",
|
||||
system_prompt=produce_extensive_cuda_file_prompt,
|
||||
model_name="openai/o1",
|
||||
max_loops=1,
|
||||
max_tokens=10000,
|
||||
output_type="str",
|
||||
temperature=0,
|
||||
)
|
||||
|
||||
|
||||
class CudaSwarm:
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "CudaSwarm",
|
||||
description: str = "A swarm of agents that convert PyTorch code into CUDA code",
|
||||
agents: list[Agent] = [
|
||||
translate_agent,
|
||||
super_fast_agent,
|
||||
cleanup_agent,
|
||||
final_cuda_agent,
|
||||
],
|
||||
max_loops: int = 1,
|
||||
file_path: str = "cuda_code.cu",
|
||||
):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.agents = agents
|
||||
self.max_loops = max_loops
|
||||
self.file_path = file_path
|
||||
|
||||
def write_file(self, content: str = "") -> None:
|
||||
"""
|
||||
Creates a new CUDA file or overwrites an existing one with the specified content.
|
||||
|
||||
Args:
|
||||
content (str): The content to write into the file. Defaults to an empty string.
|
||||
"""
|
||||
# Ensure the file has a .cu extension
|
||||
if not self.file_path.endswith(".cu"):
|
||||
self.file_path += ".cu"
|
||||
|
||||
# Create the directory if it doesn't exist
|
||||
directory = os.path.dirname(self.file_path)
|
||||
if directory and not os.path.exists(directory):
|
||||
os.makedirs(directory)
|
||||
|
||||
# Use write mode to overwrite the file
|
||||
mode = "w"
|
||||
|
||||
try:
|
||||
# Write content to the file
|
||||
with open(self.file_path, mode) as file:
|
||||
file.write(content)
|
||||
print(f"Content successfully written to {self.file_path}")
|
||||
except IOError as e:
|
||||
print(f"An error occurred while writing to the file: {e}")
|
||||
|
||||
def run(self, task: str):
|
||||
"""
|
||||
Runs the swarm of agents to complete the task.
|
||||
"""
|
||||
first_iteration = self.agents[0].run(task)
|
||||
first_iteration = extract_code_blocks(first_iteration)
|
||||
self.write_file(first_iteration)
|
||||
|
||||
# second_iteration = self.agents[1].run(task)
|
||||
# second_iteration = extract_code_blocks(second_iteration)
|
||||
# self.write_file(second_iteration)
|
||||
|
||||
# third_iteration = self.agents[2].run(task)
|
||||
# third_iteration = extract_code_blocks(third_iteration)
|
||||
# self.write_file(third_iteration)
|
||||
|
||||
# final_iteration = self.agents[3].run(task)
|
||||
# final_iteration = extract_code_blocks(final_iteration)
|
||||
# self.write_file(final_iteration)
|
||||
|
||||
return first_iteration
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
swarm = CudaSwarm(file_path="cuda_code.cu")
|
||||
swarm.run(
|
||||
"Create the cuda code for a highly optimized liquid continous learner ssm model"
|
||||
)
|
@ -0,0 +1,49 @@
|
||||
from swarms import Agent
|
||||
from swarms.prompts.finance_agent_sys_prompt import (
|
||||
FINANCIAL_AGENT_SYS_PROMPT,
|
||||
)
|
||||
|
||||
# Initialize the equity analyst agents
|
||||
equity_analyst_1 = Agent(
|
||||
agent_name="Equity-Analyst-1",
|
||||
agent_description="Equity research analyst focused on fundamental analysis",
|
||||
system_prompt=FINANCIAL_AGENT_SYS_PROMPT,
|
||||
max_loops=1,
|
||||
model_name="gpt-4o",
|
||||
dynamic_temperature_enabled=True,
|
||||
user_name="swarms_corp",
|
||||
retry_attempts=3,
|
||||
context_length=8192,
|
||||
return_step_meta=False,
|
||||
output_type="str",
|
||||
auto_generate_prompt=False,
|
||||
max_tokens=4000,
|
||||
saved_state_path="equity_analyst_1.json",
|
||||
interactive=False,
|
||||
roles="analyst"
|
||||
)
|
||||
|
||||
equity_analyst_2 = Agent(
|
||||
agent_name="Equity-Analyst-2",
|
||||
agent_description="Equity research analyst focused on technical analysis",
|
||||
system_prompt=FINANCIAL_AGENT_SYS_PROMPT,
|
||||
max_loops=1,
|
||||
model_name="gpt-4o",
|
||||
dynamic_temperature_enabled=True,
|
||||
user_name="swarms_corp",
|
||||
retry_attempts=3,
|
||||
context_length=8192,
|
||||
return_step_meta=False,
|
||||
output_type="str",
|
||||
auto_generate_prompt=False,
|
||||
max_tokens=4000,
|
||||
saved_state_path="equity_analyst_2.json",
|
||||
interactive=False,
|
||||
roles="analyst"
|
||||
)
|
||||
|
||||
# Run analysis with both analysts
|
||||
equity_analyst_1.talk_to(
|
||||
equity_analyst_2,
|
||||
"Analyze high growth tech stocks focusing on fundamentals like revenue growth, margins, and market position. Create a detailed analysis table in markdown."
|
||||
)
|
@ -0,0 +1,506 @@
|
||||
from typing import Callable, Any
|
||||
import psutil
|
||||
import asyncio
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
from rich.panel import Panel
|
||||
from rich.layout import Layout
|
||||
from rich.tree import Tree
|
||||
from rich.progress import (
|
||||
Progress,
|
||||
TimeElapsedColumn,
|
||||
TextColumn,
|
||||
SpinnerColumn,
|
||||
)
|
||||
from rich.live import Live
|
||||
from rich.text import Text
|
||||
from typing import Dict, Optional, List
|
||||
from dataclasses import dataclass
|
||||
from queue import Queue
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
import pynvml
|
||||
|
||||
pynvml.nvmlInit()
|
||||
GPU_ENABLED = True
|
||||
except ImportError:
|
||||
GPU_ENABLED = False
|
||||
|
||||
|
||||
@dataclass
|
||||
class SwarmMetadata:
|
||||
name: str
|
||||
description: str
|
||||
version: str
|
||||
type: str # hierarchical, parallel, sequential
|
||||
created_at: datetime
|
||||
author: str
|
||||
tags: List[str]
|
||||
primary_objective: str
|
||||
secondary_objectives: List[str]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Agent:
|
||||
name: str
|
||||
role: str
|
||||
description: str
|
||||
agent_type: str # e.g., "LLM", "Neural", "Rule-based"
|
||||
capabilities: List[str]
|
||||
parameters: Dict[str, any]
|
||||
metadata: Dict[str, str]
|
||||
children: List["Agent"] = None
|
||||
parent: Optional["Agent"] = None
|
||||
output_stream: Queue = None
|
||||
|
||||
def __post_init__(self):
|
||||
self.children = self.children or []
|
||||
self.output_stream = Queue()
|
||||
|
||||
@property
|
||||
def hierarchy_level(self) -> int:
|
||||
level = 0
|
||||
current = self
|
||||
while current.parent:
|
||||
level += 1
|
||||
current = current.parent
|
||||
return level
|
||||
|
||||
|
||||
class SwarmVisualizationRich:
|
||||
def __init__(
|
||||
self,
|
||||
swarm_metadata: SwarmMetadata,
|
||||
root_agent: Agent,
|
||||
update_resources: bool = True,
|
||||
refresh_rate: float = 0.1,
|
||||
):
|
||||
self.swarm_metadata = swarm_metadata
|
||||
self.root_agent = root_agent
|
||||
self.update_resources = update_resources
|
||||
self.refresh_rate = refresh_rate
|
||||
self.console = Console()
|
||||
self.live = None
|
||||
self.output_history = {}
|
||||
|
||||
# System monitoring
|
||||
self.cores_available = 0
|
||||
self.memory_usage = "N/A"
|
||||
self.gpu_power = "N/A"
|
||||
self.start_time = datetime.now()
|
||||
|
||||
if self.update_resources:
|
||||
self._update_resource_stats()
|
||||
|
||||
def _format_uptime(self) -> str:
|
||||
"""Formats the swarm's uptime."""
|
||||
delta = datetime.now() - self.start_time
|
||||
hours, remainder = divmod(delta.seconds, 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
||||
|
||||
def _build_agent_tree(
|
||||
self, agent: Agent, tree: Optional[Tree] = None
|
||||
) -> Tree:
|
||||
"""Builds a detailed tree visualization of the agent hierarchy."""
|
||||
agent_info = [
|
||||
f"[bold cyan]{agent.name}[/bold cyan]",
|
||||
f"[yellow]Role:[/yellow] {agent.role}",
|
||||
f"[green]Type:[/green] {agent.agent_type}",
|
||||
f"[blue]Level:[/blue] {agent.hierarchy_level}",
|
||||
f"[magenta]Capabilities:[/magenta] {', '.join(agent.capabilities)}",
|
||||
]
|
||||
|
||||
# Add any custom metadata
|
||||
for key, value in agent.metadata.items():
|
||||
agent_info.append(f"[white]{key}:[/white] {value}")
|
||||
|
||||
# Parameters summary
|
||||
param_summary = ", ".join(
|
||||
f"{k}: {v}" for k, v in agent.parameters.items()
|
||||
)
|
||||
agent_info.append(
|
||||
f"[white]Parameters:[/white] {param_summary}"
|
||||
)
|
||||
|
||||
node_text = "\n".join(agent_info)
|
||||
|
||||
if tree is None:
|
||||
tree = Tree(node_text)
|
||||
else:
|
||||
branch = tree.add(node_text)
|
||||
tree = branch
|
||||
|
||||
for child in agent.children:
|
||||
self._build_agent_tree(child, tree)
|
||||
|
||||
return tree
|
||||
|
||||
def _count_agents(self, agent: Agent) -> int:
|
||||
"""Recursively counts total number of agents in the swarm."""
|
||||
count = 1 # Count current agent
|
||||
for child in agent.children or []:
|
||||
count += self._count_agents(child)
|
||||
return count
|
||||
|
||||
def _create_unified_info_panel(self) -> Panel:
|
||||
"""Creates a unified panel showing both swarm metadata and architecture."""
|
||||
# Create the main container
|
||||
info_layout = Layout()
|
||||
info_layout.split_column(
|
||||
Layout(name="metadata", size=13),
|
||||
Layout(name="architecture"),
|
||||
)
|
||||
|
||||
# Calculate total agents
|
||||
total_agents = self._count_agents(self.root_agent)
|
||||
|
||||
# Metadata section
|
||||
metadata_table = Table.grid(padding=1, expand=True)
|
||||
metadata_table.add_column("Label", style="bold cyan")
|
||||
metadata_table.add_column("Value", style="white")
|
||||
|
||||
# System resources
|
||||
if self.update_resources:
|
||||
self._update_resource_stats()
|
||||
|
||||
# Add description with proper wrapping
|
||||
description_text = Text(
|
||||
self.swarm_metadata.description, style="italic"
|
||||
)
|
||||
description_text.wrap(self.console, width=60, overflow="fold")
|
||||
|
||||
metadata_table.add_row("Swarm Name", self.swarm_metadata.name)
|
||||
metadata_table.add_row("Description", description_text)
|
||||
metadata_table.add_row("Version", self.swarm_metadata.version)
|
||||
metadata_table.add_row("Total Agents", str(total_agents))
|
||||
metadata_table.add_row("Author", self.swarm_metadata.author)
|
||||
metadata_table.add_row(
|
||||
"System",
|
||||
f"CPU: {self.cores_available} cores | Memory: {self.memory_usage}",
|
||||
)
|
||||
metadata_table.add_row(
|
||||
"Primary Objective", self.swarm_metadata.primary_objective
|
||||
)
|
||||
|
||||
info_layout["metadata"].update(metadata_table)
|
||||
|
||||
info_layout["metadata"].update(metadata_table)
|
||||
|
||||
# Architecture section with tree visualization
|
||||
architecture_tree = self._build_agent_tree(self.root_agent)
|
||||
info_layout["architecture"].update(architecture_tree)
|
||||
|
||||
return Panel(
|
||||
info_layout,
|
||||
title="[bold]Swarm Information & Architecture[/bold]",
|
||||
)
|
||||
|
||||
def _create_outputs_panel(self) -> Panel:
|
||||
"""Creates a panel that displays stacked message history for all agents."""
|
||||
# Create a container for all messages across all agents
|
||||
all_messages = []
|
||||
|
||||
def collect_agent_messages(agent: Agent):
|
||||
"""Recursively collect messages from all agents."""
|
||||
messages = self.output_history.get(agent.name, [])
|
||||
for msg in messages:
|
||||
all_messages.append(
|
||||
{
|
||||
"agent": agent.name,
|
||||
"time": msg["time"],
|
||||
"content": msg["content"],
|
||||
"style": msg["style"],
|
||||
}
|
||||
)
|
||||
for child in agent.children:
|
||||
collect_agent_messages(child)
|
||||
|
||||
# Collect all messages
|
||||
collect_agent_messages(self.root_agent)
|
||||
|
||||
# Sort messages by timestamp
|
||||
all_messages.sort(key=lambda x: x["time"])
|
||||
|
||||
# Create the stacked message display
|
||||
Layout()
|
||||
messages_container = []
|
||||
|
||||
for msg in all_messages:
|
||||
# Create a panel for each message
|
||||
message_text = Text()
|
||||
message_text.append(f"[{msg['time']}] ", style="dim")
|
||||
message_text.append(
|
||||
f"{msg['agent']}: ", style="bold cyan"
|
||||
)
|
||||
message_text.append(msg["content"], style=msg["style"])
|
||||
|
||||
messages_container.append(message_text)
|
||||
|
||||
# Join all messages with line breaks
|
||||
if messages_container:
|
||||
final_text = Text("\n").join(messages_container)
|
||||
else:
|
||||
final_text = Text("No messages yet...", style="dim")
|
||||
|
||||
# Create scrollable panel for all messages
|
||||
return Panel(
|
||||
final_text,
|
||||
title="[bold]Agent Communication Log[/bold]",
|
||||
border_style="green",
|
||||
padding=(1, 2),
|
||||
)
|
||||
|
||||
def _update_resource_stats(self):
|
||||
"""Updates system resource statistics."""
|
||||
self.cores_available = psutil.cpu_count(logical=True)
|
||||
mem_info = psutil.virtual_memory()
|
||||
total_gb = mem_info.total / (1024**3)
|
||||
used_gb = mem_info.used / (1024**3)
|
||||
self.memory_usage = f"{used_gb:.1f}GB / {total_gb:.1f}GB ({mem_info.percent}%)"
|
||||
|
||||
if GPU_ENABLED:
|
||||
try:
|
||||
device_count = pynvml.nvmlDeviceGetCount()
|
||||
gpu_info = []
|
||||
for i in range(device_count):
|
||||
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
|
||||
name = pynvml.nvmlDeviceGetName(handle).decode()
|
||||
mem = pynvml.nvmlDeviceGetMemoryInfo(handle)
|
||||
usage = (mem.used / mem.total) * 100
|
||||
gpu_info.append(f"{name}: {usage:.1f}%")
|
||||
self.gpu_power = " | ".join(gpu_info)
|
||||
except Exception as e:
|
||||
self.gpu_power = f"GPU Error: {str(e)}"
|
||||
else:
|
||||
self.gpu_power = "No GPU detected"
|
||||
|
||||
async def stream_output(
|
||||
self,
|
||||
agent: Agent,
|
||||
text: str,
|
||||
title: Optional[str] = None,
|
||||
style: str = "bold cyan",
|
||||
delay: float = 0.05,
|
||||
by_word: bool = False,
|
||||
):
|
||||
"""
|
||||
Streams output for a specific agent with sophisticated token-by-token animation.
|
||||
|
||||
Args:
|
||||
agent (Agent): The agent whose output is being streamed
|
||||
text (str): The text to stream
|
||||
title (Optional[str]): Custom title for the output panel
|
||||
style (str): Style for the output text
|
||||
delay (float): Delay between tokens
|
||||
by_word (bool): If True, streams word by word instead of character by character
|
||||
"""
|
||||
display_text = Text(style=style)
|
||||
current_output = ""
|
||||
|
||||
# Split into words or characters
|
||||
tokens = text.split() if by_word else text
|
||||
|
||||
# Create a panel for this agent's output
|
||||
title = title or f"{agent.name} Output"
|
||||
|
||||
for token in tokens:
|
||||
# Add appropriate spacing
|
||||
token_with_space = token + (" " if by_word else "")
|
||||
current_output += token_with_space
|
||||
display_text.append(token_with_space)
|
||||
|
||||
# Initialize history list if it doesn't exist
|
||||
if agent.name not in self.output_history:
|
||||
self.output_history[agent.name] = []
|
||||
|
||||
# Store the complete message when finished
|
||||
if token == tokens[-1]:
|
||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||
self.output_history[agent.name].append(
|
||||
{
|
||||
"time": timestamp,
|
||||
"content": current_output,
|
||||
"style": style,
|
||||
}
|
||||
)
|
||||
|
||||
# Update live display if active
|
||||
if self.live:
|
||||
self.live.update(self._create_layout())
|
||||
await asyncio.sleep(delay)
|
||||
|
||||
async def print_progress(
|
||||
self,
|
||||
description: str,
|
||||
task_fn: Callable,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""
|
||||
Displays a progress spinner while executing a task.
|
||||
|
||||
Args:
|
||||
description (str): Task description
|
||||
task_fn (Callable): Function to execute
|
||||
*args (Any): Arguments for task_fn
|
||||
**kwargs (Any): Keyword arguments for task_fn
|
||||
|
||||
Returns:
|
||||
Any: Result of task_fn
|
||||
"""
|
||||
progress = Progress(
|
||||
SpinnerColumn(),
|
||||
TextColumn("[progress.description]{task.description}"),
|
||||
TimeElapsedColumn(),
|
||||
)
|
||||
|
||||
try:
|
||||
with progress:
|
||||
task = progress.add_task(description, total=None)
|
||||
result = await task_fn(*args, **kwargs)
|
||||
progress.update(task, completed=True)
|
||||
return result
|
||||
except Exception as e:
|
||||
progress.stop()
|
||||
raise e
|
||||
|
||||
def _create_layout(self) -> Layout:
|
||||
"""Creates the main visualization layout."""
|
||||
layout = Layout()
|
||||
layout.split_row(
|
||||
Layout(name="info", ratio=2),
|
||||
Layout(name="outputs", ratio=3),
|
||||
)
|
||||
|
||||
layout["info"].update(self._create_unified_info_panel())
|
||||
layout["outputs"].update(self._create_outputs_panel())
|
||||
|
||||
return layout
|
||||
|
||||
async def start(self):
|
||||
"""Starts the visualization with live updates."""
|
||||
with Live(
|
||||
self._create_layout(),
|
||||
refresh_per_second=int(1 / self.refresh_rate),
|
||||
) as self.live:
|
||||
while True:
|
||||
|
||||
def process_agent_streams(agent: Agent):
|
||||
while not agent.output_stream.empty():
|
||||
new_output = agent.output_stream.get()
|
||||
asyncio.create_task(
|
||||
self.stream_output(agent, new_output)
|
||||
)
|
||||
for child in agent.children:
|
||||
process_agent_streams(child)
|
||||
|
||||
process_agent_streams(self.root_agent)
|
||||
await asyncio.sleep(self.refresh_rate)
|
||||
|
||||
|
||||
# Example usage
|
||||
if __name__ == "__main__":
|
||||
# Create swarm metadata
|
||||
swarm_metadata = SwarmMetadata(
|
||||
name="Financial Advisory Swarm",
|
||||
description="Intelligent swarm for financial analysis and advisory",
|
||||
version="1.0.0",
|
||||
type="hierarchical",
|
||||
created_at=datetime.now(),
|
||||
author="AI Research Team",
|
||||
# tags=["finance", "analysis", "advisory"],
|
||||
primary_objective="Provide comprehensive financial analysis and recommendations",
|
||||
secondary_objectives=[
|
||||
"Monitor market trends",
|
||||
"Analyze competitor behavior",
|
||||
"Generate investment strategies",
|
||||
],
|
||||
)
|
||||
|
||||
# Create agent hierarchy with detailed parameters
|
||||
analyst = Agent(
|
||||
name="Financial Analyst",
|
||||
role="Analysis",
|
||||
description="Analyzes financial data and market trends",
|
||||
agent_type="LLM",
|
||||
capabilities=[
|
||||
"data analysis",
|
||||
"trend detection",
|
||||
"risk assessment",
|
||||
],
|
||||
parameters={"model": "gpt-4", "temperature": 0.7},
|
||||
metadata={
|
||||
"specialty": "Market Analysis",
|
||||
"confidence_threshold": "0.85",
|
||||
},
|
||||
)
|
||||
|
||||
researcher = Agent(
|
||||
name="Market Researcher",
|
||||
role="Research",
|
||||
description="Conducts market research and competitor analysis",
|
||||
agent_type="Neural",
|
||||
capabilities=[
|
||||
"competitor analysis",
|
||||
"market sentiment",
|
||||
"trend forecasting",
|
||||
],
|
||||
parameters={"batch_size": 32, "learning_rate": 0.001},
|
||||
metadata={
|
||||
"data_sources": "Bloomberg, Reuters",
|
||||
"update_frequency": "1h",
|
||||
},
|
||||
)
|
||||
|
||||
advisor = Agent(
|
||||
name="Investment Advisor",
|
||||
role="Advisory",
|
||||
description="Provides investment recommendations",
|
||||
agent_type="Hybrid",
|
||||
capabilities=[
|
||||
"portfolio optimization",
|
||||
"risk management",
|
||||
"strategy generation",
|
||||
],
|
||||
parameters={
|
||||
"risk_tolerance": "moderate",
|
||||
"time_horizon": "long",
|
||||
},
|
||||
metadata={
|
||||
"certification": "CFA Level 3",
|
||||
"specialization": "Equity",
|
||||
},
|
||||
children=[analyst, researcher],
|
||||
)
|
||||
|
||||
# Create visualization
|
||||
viz = SwarmVisualizationRich(
|
||||
swarm_metadata=swarm_metadata,
|
||||
root_agent=advisor,
|
||||
refresh_rate=0.1,
|
||||
)
|
||||
|
||||
# Example of streaming output simulation
|
||||
async def simulate_outputs():
|
||||
await viz.stream_output(
|
||||
advisor,
|
||||
"Analyzing market conditions...\nGenerating investment advice...",
|
||||
)
|
||||
await viz.stream_output(
|
||||
analyst,
|
||||
"Processing financial data...\nIdentifying trends...",
|
||||
)
|
||||
await viz.stream_output(
|
||||
researcher,
|
||||
"Researching competitor movements...\nAnalyzing market share...",
|
||||
)
|
||||
|
||||
# Run the visualization
|
||||
async def main():
|
||||
viz_task = asyncio.create_task(viz.start())
|
||||
await simulate_outputs()
|
||||
await viz_task
|
||||
|
||||
asyncio.run(main())
|
Loading…
Reference in new issue