File size: 5,665 Bytes
3b9084c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 4: utils.py
with open(f"{base_dir}/utils.py", "w") as f:
    f.write('''"""Shared utilities for Swarm CLI"""
import json
import os
import hashlib
import datetime
from typing import Any, Dict, List, Optional
from rich.console import Console
from rich.panel import Panel
from rich.syntax import Syntax
from rich.table import Table
from rich.tree import Tree

console = Console()

class Logger:
    """Activity logger"""
    
    @staticmethod
    def log(action: str, details: Dict[str, Any], agent: str = "system"):
        """Log an action"""
        entry = {
            "timestamp": datetime.datetime.now().isoformat(),
            "agent": agent,
            "action": action,
            "details": details
        }
        
        # Print to console
        console.print(f"[dim][{entry['timestamp']}] {agent}: {action}[/dim]")
        
        # Append to log file
        try:
            with open("swarm.log", "a", encoding="utf-8") as f:
                f.write(json.dumps(entry) + "\n")
        except:
            pass
        
        return entry

class Memory:
    """Simple JSON-based memory store"""
    
    def __init__(self, filepath: str = "memory.json"):
        self.filepath = filepath
        self.data = self._load()
    
    def _load(self) -> Dict:
        if os.path.exists(self.filepath):
            try:
                with open(self.filepath, "r", encoding="utf-8") as f:
                    return json.load(f)
            except:
                return {"facts": [], "conversations": [], "tools_used": []}
        return {"facts": [], "conversations": [], "tools_used": []}
    
    def save(self):
        with open(self.filepath, "w", encoding="utf-8") as f:
            json.dump(self.data, f, indent=2, ensure_ascii=False)
    
    def add_fact(self, key: str, value: Any):
        self.data["facts"].append({
            "key": key,
            "value": value,
            "timestamp": datetime.datetime.now().isoformat()
        })
        self.save()
    
    def get_facts(self, query: str = "") -> List[Dict]:
        if not query:
            return self.data["facts"][-20:]
        return [f for f in self.data["facts"] if query.lower() in f["key"].lower()]
    
    def add_conversation(self, role: str, content: str):
        self.data["conversations"].append({
            "role": role,
            "content": content,
            "timestamp": datetime.datetime.now().isoformat()
        })
        self.data["conversations"] = self.data["conversations"][-100:]
        self.save()
    
    def get_conversation_history(self, limit: int = 10) -> List[Dict]:
        return self.data["conversations"][-limit:]
    
    def record_tool_use(self, tool_name: str, success: bool, details: str = ""):
        self.data["tools_used"].append({
            "tool": tool_name,
            "success": success,
            "details": details,
            "timestamp": datetime.datetime.now().isoformat()
        })
        self.save()

class UI:
    """Rich UI helpers"""
    
    @staticmethod
    def header(text: str):
        console.print(Panel(text, style="bold cyan", border_style="cyan"))
    
    @staticmethod
    def agent_message(agent: str, message: str):
        colors = {
            "orchestrator": "green",
            "planner": "blue",
            "executor": "yellow",
            "reviewer": "magenta",
            "researcher": "cyan",
            "coder": "bright_green",
            "system": "white"
        }
        color = colors.get(agent.lower(), "white")
        console.print(f"[bold {color}]{agent.upper()}:[/bold {color}] {message}")
    
    @staticmethod
    def code_block(code: str, language: str = "python"):
        syntax = Syntax(code, language, theme="monokai", line_numbers=True)
        console.print(Panel(syntax, border_style="dim"))
    
    @staticmethod
    def table(headers: List[str], rows: List[List[str]], title: str = ""):
        table = Table(title=title, show_header=True, header_style="bold magenta")
        for h in headers:
            table.add_column(h)
        for row in rows:
            table.add_row(*row)
        console.print(table)
    
    @staticmethod
    def tree(label: str, items: List[str]):
        tree = Tree(f"[bold]{label}[/bold]")
        for item in items:
            tree.add(item)
        console.print(tree)
    
    @staticmethod
    def confirm(prompt: str) -> bool:
        """Ask for user confirmation"""
        response = console.input(f"[bold yellow]{prompt} (y/n): [/bold yellow]").lower().strip()
        return response in ("y", "yes", "yeah", "sure")
    
    @staticmethod
    def success(message: str):
        console.print(f"[bold green]✓ {message}[/bold green]")
    
    @staticmethod
    def error(message: str):
        console.print(f"[bold red]✗ {message}[/bold red]")
    
    @staticmethod
    def warning(message: str):
        console.print(f"[bold yellow]⚠ {message}[/bold yellow]")
    
    @staticmethod
    def info(message: str):
        console.print(f"[dim]{message}[/dim]")

def hash_string(text: str) -> str:
    """Generate MD5 hash of string"""
    return hashlib.md5(text.encode()).hexdigest()[:8]

def truncate(text: str, max_length: int = 500) -> str:
    """Truncate text with ellipsis"""
    if len(text) <= max_length:
        return text
    return text[:max_length] + "... [truncated]"

def format_size(size_bytes: int) -> str:
    """Format bytes to human readable"""
    for unit in ["B", "KB", "MB", "GB"]:
        if size_bytes < 1024:
            return f"{size_bytes:.1f} {unit}"
        size_bytes /= 1024
    return f"{size_bytes:.1f} TB"
''')

print("utils.py done")