374 lines
13 KiB
Python
374 lines
13 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Agent Mode for DarkHal 2.0
|
||
|
|
Integrates Hal's unrestricted capabilities into the chat interface
|
||
|
|
"""
|
||
|
|
|
||
|
|
import os
|
||
|
|
import sys
|
||
|
|
import json
|
||
|
|
import asyncio
|
||
|
|
import threading
|
||
|
|
from typing import Optional, Callable, Dict, Any, List
|
||
|
|
from dataclasses import dataclass
|
||
|
|
import tkinter as tk
|
||
|
|
from tkinter import messagebox
|
||
|
|
|
||
|
|
# Add agent_dhal to path
|
||
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'agent_dhal'))
|
||
|
|
|
||
|
|
# Import Hal components
|
||
|
|
try:
|
||
|
|
from agent_dhal.hal import create_dhal, DhalConfig, HalModelClient
|
||
|
|
except ImportError:
|
||
|
|
# Fallback for testing
|
||
|
|
create_dhal = None
|
||
|
|
DhalConfig = None
|
||
|
|
HalModelClient = None
|
||
|
|
print("[Agent Mode] Warning: Could not import Hal components")
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class AgentModeConfig:
|
||
|
|
"""Configuration for agent mode"""
|
||
|
|
enabled: bool = False
|
||
|
|
allow_file_operations: bool = True
|
||
|
|
allow_shell_commands: bool = True
|
||
|
|
allow_system_control: bool = True # mouse, keyboard
|
||
|
|
allow_elevated_commands: bool = False # sudo, admin powershell
|
||
|
|
require_confirmation: bool = True # Ask before dangerous operations
|
||
|
|
model_name: str = "gpt-4"
|
||
|
|
|
||
|
|
|
||
|
|
class AgentModeHandler:
|
||
|
|
"""Handles agent mode functionality for the chat interface"""
|
||
|
|
|
||
|
|
def __init__(self, output_callback: Callable[[str], None] = None):
|
||
|
|
"""
|
||
|
|
Initialize agent mode handler
|
||
|
|
|
||
|
|
Args:
|
||
|
|
output_callback: Function to call with output text
|
||
|
|
"""
|
||
|
|
self.config = AgentModeConfig()
|
||
|
|
self.output_callback = output_callback or print
|
||
|
|
self.agent = None
|
||
|
|
self.is_initialized = False
|
||
|
|
self._init_lock = threading.Lock()
|
||
|
|
|
||
|
|
def initialize_agent(self, model_path: str = None) -> bool:
|
||
|
|
"""
|
||
|
|
Initialize the Hal agent
|
||
|
|
|
||
|
|
Args:
|
||
|
|
model_path: Path to model file or model name
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
True if initialized successfully
|
||
|
|
"""
|
||
|
|
with self._init_lock:
|
||
|
|
if self.is_initialized:
|
||
|
|
return True
|
||
|
|
|
||
|
|
try:
|
||
|
|
if not create_dhal:
|
||
|
|
self.output_callback("[Agent Mode] Hal components not available\n")
|
||
|
|
return False
|
||
|
|
|
||
|
|
# Configure agent based on settings
|
||
|
|
config = DhalConfig(
|
||
|
|
name="Hal",
|
||
|
|
system_message=self._get_system_prompt(),
|
||
|
|
model=model_path or "gpt-4",
|
||
|
|
temperature=0.7,
|
||
|
|
max_tokens=2000
|
||
|
|
)
|
||
|
|
|
||
|
|
# Create model client
|
||
|
|
model_client = HalModelClient(model_name=model_path or "gpt-4")
|
||
|
|
|
||
|
|
# Create agent
|
||
|
|
self.agent = create_dhal(
|
||
|
|
name="Hal",
|
||
|
|
system_message=self._get_system_prompt(),
|
||
|
|
model=model_path or "gpt-4",
|
||
|
|
model_client=model_client
|
||
|
|
)
|
||
|
|
|
||
|
|
self.is_initialized = True
|
||
|
|
self.output_callback("[Agent Mode] Hal agent initialized successfully\n")
|
||
|
|
return True
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
self.output_callback(f"[Agent Mode] Failed to initialize: {e}\n")
|
||
|
|
return False
|
||
|
|
|
||
|
|
def _get_system_prompt(self) -> str:
|
||
|
|
"""Generate system prompt based on current permissions"""
|
||
|
|
prompt = """You are Hal, an advanced AI assistant with direct system access.
|
||
|
|
You can execute commands and control the system based on user requests.
|
||
|
|
|
||
|
|
Available capabilities:"""
|
||
|
|
|
||
|
|
if self.config.allow_file_operations:
|
||
|
|
prompt += "\n- Read, write, and list files"
|
||
|
|
if self.config.allow_shell_commands:
|
||
|
|
prompt += "\n- Execute shell commands (bash, PowerShell)"
|
||
|
|
prompt += "\n- Run Python code"
|
||
|
|
if self.config.allow_system_control:
|
||
|
|
prompt += "\n- Control mouse and keyboard"
|
||
|
|
prompt += "\n- Send keystrokes and type text"
|
||
|
|
if self.config.allow_elevated_commands:
|
||
|
|
prompt += "\n- Execute elevated/admin commands"
|
||
|
|
|
||
|
|
prompt += "\n\nAlways explain what you're doing before executing commands."
|
||
|
|
|
||
|
|
if self.config.require_confirmation:
|
||
|
|
prompt += "\nWait for user confirmation before destructive operations."
|
||
|
|
|
||
|
|
return prompt
|
||
|
|
|
||
|
|
async def process_message_async(self, message: str) -> str:
|
||
|
|
"""
|
||
|
|
Process a message through the agent asynchronously
|
||
|
|
|
||
|
|
Args:
|
||
|
|
message: User message to process
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Agent response
|
||
|
|
"""
|
||
|
|
if not self.is_initialized:
|
||
|
|
return "[Agent Mode] Not initialized. Please enable agent mode first."
|
||
|
|
|
||
|
|
try:
|
||
|
|
# Get response from agent
|
||
|
|
from agent_dhal.hal import MessageContext
|
||
|
|
|
||
|
|
# Create a mock context for standalone usage
|
||
|
|
class MockContext:
|
||
|
|
def __init__(self):
|
||
|
|
self.agent_id = "user"
|
||
|
|
|
||
|
|
ctx = MockContext()
|
||
|
|
|
||
|
|
# Process message through agent
|
||
|
|
response = await self.agent.handle_user_message(message, ctx)
|
||
|
|
|
||
|
|
return response
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
return f"[Agent Mode] Error processing message: {e}"
|
||
|
|
|
||
|
|
def process_message(self, message: str) -> str:
|
||
|
|
"""
|
||
|
|
Process a message through the agent (synchronous wrapper)
|
||
|
|
|
||
|
|
Args:
|
||
|
|
message: User message to process
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Agent response
|
||
|
|
"""
|
||
|
|
# Run async function in new event loop
|
||
|
|
loop = asyncio.new_event_loop()
|
||
|
|
asyncio.set_event_loop(loop)
|
||
|
|
try:
|
||
|
|
return loop.run_until_complete(self.process_message_async(message))
|
||
|
|
finally:
|
||
|
|
loop.close()
|
||
|
|
|
||
|
|
def enable(self, model_path: str = None) -> bool:
|
||
|
|
"""
|
||
|
|
Enable agent mode
|
||
|
|
|
||
|
|
Args:
|
||
|
|
model_path: Path to model or model name
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
True if enabled successfully
|
||
|
|
"""
|
||
|
|
if not self.is_initialized:
|
||
|
|
if not self.initialize_agent(model_path):
|
||
|
|
return False
|
||
|
|
|
||
|
|
self.config.enabled = True
|
||
|
|
self.output_callback("[Agent Mode] ENABLED - Hal has full system access\n")
|
||
|
|
self._show_capabilities()
|
||
|
|
return True
|
||
|
|
|
||
|
|
def disable(self):
|
||
|
|
"""Disable agent mode"""
|
||
|
|
self.config.enabled = False
|
||
|
|
self.output_callback("[Agent Mode] DISABLED - Normal chat mode\n")
|
||
|
|
|
||
|
|
def _show_capabilities(self):
|
||
|
|
"""Show current capabilities to user"""
|
||
|
|
caps = []
|
||
|
|
if self.config.allow_file_operations:
|
||
|
|
caps.append("• File operations (read/write/list)")
|
||
|
|
if self.config.allow_shell_commands:
|
||
|
|
caps.append("• Shell commands (bash/PowerShell/Python)")
|
||
|
|
if self.config.allow_system_control:
|
||
|
|
caps.append("• Mouse & keyboard control")
|
||
|
|
if self.config.allow_elevated_commands:
|
||
|
|
caps.append("• Elevated/admin commands")
|
||
|
|
|
||
|
|
if caps:
|
||
|
|
self.output_callback("Enabled capabilities:\n" + "\n".join(caps) + "\n")
|
||
|
|
|
||
|
|
def update_config(self, **kwargs):
|
||
|
|
"""Update configuration settings"""
|
||
|
|
for key, value in kwargs.items():
|
||
|
|
if hasattr(self.config, key):
|
||
|
|
setattr(self.config, key, value)
|
||
|
|
|
||
|
|
# Reinitialize agent if needed
|
||
|
|
if self.is_initialized:
|
||
|
|
self.agent.update_config(system_message=self._get_system_prompt())
|
||
|
|
|
||
|
|
|
||
|
|
class AgentModeUI:
|
||
|
|
"""UI components for agent mode"""
|
||
|
|
|
||
|
|
def __init__(self, parent_frame: tk.Frame, handler: AgentModeHandler):
|
||
|
|
"""
|
||
|
|
Create agent mode UI controls
|
||
|
|
|
||
|
|
Args:
|
||
|
|
parent_frame: Parent tkinter frame
|
||
|
|
handler: AgentModeHandler instance
|
||
|
|
"""
|
||
|
|
self.handler = handler
|
||
|
|
self.parent = parent_frame
|
||
|
|
|
||
|
|
# Create control frame
|
||
|
|
self.control_frame = tk.LabelFrame(parent_frame, text="🤖 Agent Mode", relief=tk.RIDGE, borderwidth=2)
|
||
|
|
self.control_frame.pack(fill=tk.X, padx=5, pady=5)
|
||
|
|
|
||
|
|
# Main toggle
|
||
|
|
self.enabled_var = tk.BooleanVar(value=False)
|
||
|
|
self.enable_check = tk.Checkbutton(
|
||
|
|
self.control_frame,
|
||
|
|
text="Enable Agent Mode (FULL SYSTEM ACCESS)",
|
||
|
|
variable=self.enabled_var,
|
||
|
|
command=self._toggle_agent_mode,
|
||
|
|
font=('Arial', 10, 'bold'),
|
||
|
|
fg='red'
|
||
|
|
)
|
||
|
|
self.enable_check.grid(row=0, column=0, columnspan=3, sticky=tk.W, padx=5, pady=5)
|
||
|
|
|
||
|
|
# Permission toggles
|
||
|
|
self.file_ops_var = tk.BooleanVar(value=True)
|
||
|
|
tk.Checkbutton(
|
||
|
|
self.control_frame,
|
||
|
|
text="File Operations",
|
||
|
|
variable=self.file_ops_var,
|
||
|
|
command=self._update_permissions
|
||
|
|
).grid(row=1, column=0, sticky=tk.W, padx=20, pady=2)
|
||
|
|
|
||
|
|
self.shell_var = tk.BooleanVar(value=True)
|
||
|
|
tk.Checkbutton(
|
||
|
|
self.control_frame,
|
||
|
|
text="Shell Commands",
|
||
|
|
variable=self.shell_var,
|
||
|
|
command=self._update_permissions
|
||
|
|
).grid(row=1, column=1, sticky=tk.W, padx=20, pady=2)
|
||
|
|
|
||
|
|
self.system_var = tk.BooleanVar(value=True)
|
||
|
|
tk.Checkbutton(
|
||
|
|
self.control_frame,
|
||
|
|
text="Mouse/Keyboard",
|
||
|
|
variable=self.system_var,
|
||
|
|
command=self._update_permissions
|
||
|
|
).grid(row=1, column=2, sticky=tk.W, padx=20, pady=2)
|
||
|
|
|
||
|
|
self.elevated_var = tk.BooleanVar(value=False)
|
||
|
|
tk.Checkbutton(
|
||
|
|
self.control_frame,
|
||
|
|
text="Elevated Commands (DANGEROUS)",
|
||
|
|
variable=self.elevated_var,
|
||
|
|
command=self._update_permissions,
|
||
|
|
fg='orange'
|
||
|
|
).grid(row=2, column=0, columnspan=2, sticky=tk.W, padx=20, pady=2)
|
||
|
|
|
||
|
|
self.confirm_var = tk.BooleanVar(value=True)
|
||
|
|
tk.Checkbutton(
|
||
|
|
self.control_frame,
|
||
|
|
text="Require Confirmation",
|
||
|
|
variable=self.confirm_var,
|
||
|
|
command=self._update_permissions
|
||
|
|
).grid(row=2, column=2, sticky=tk.W, padx=20, pady=2)
|
||
|
|
|
||
|
|
# Status label
|
||
|
|
self.status_label = tk.Label(
|
||
|
|
self.control_frame,
|
||
|
|
text="Status: DISABLED",
|
||
|
|
font=('Arial', 9),
|
||
|
|
fg='gray'
|
||
|
|
)
|
||
|
|
self.status_label.grid(row=3, column=0, columnspan=3, pady=5)
|
||
|
|
|
||
|
|
def _toggle_agent_mode(self):
|
||
|
|
"""Toggle agent mode on/off"""
|
||
|
|
if self.enabled_var.get():
|
||
|
|
# Show warning
|
||
|
|
result = messagebox.askyesno(
|
||
|
|
"⚠️ Enable Agent Mode",
|
||
|
|
"WARNING: Agent mode gives the AI unrestricted access to:\n\n"
|
||
|
|
"• Your file system\n"
|
||
|
|
"• Shell commands\n"
|
||
|
|
"• Mouse and keyboard control\n"
|
||
|
|
"• System settings\n\n"
|
||
|
|
"Only enable if you understand the risks.\n\n"
|
||
|
|
"Continue?",
|
||
|
|
icon='warning'
|
||
|
|
)
|
||
|
|
|
||
|
|
if result:
|
||
|
|
# Get model path from parent if available
|
||
|
|
model_path = None
|
||
|
|
if hasattr(self.parent.master, 'model_var'):
|
||
|
|
model_path = self.parent.master.model_var.get()
|
||
|
|
|
||
|
|
if self.handler.enable(model_path):
|
||
|
|
self.status_label.config(text="Status: ACTIVE", fg='red')
|
||
|
|
self._update_permissions()
|
||
|
|
else:
|
||
|
|
self.enabled_var.set(False)
|
||
|
|
messagebox.showerror("Error", "Failed to initialize agent mode")
|
||
|
|
else:
|
||
|
|
self.enabled_var.set(False)
|
||
|
|
else:
|
||
|
|
self.handler.disable()
|
||
|
|
self.status_label.config(text="Status: DISABLED", fg='gray')
|
||
|
|
|
||
|
|
def _update_permissions(self):
|
||
|
|
"""Update handler permissions based on UI settings"""
|
||
|
|
self.handler.update_config(
|
||
|
|
allow_file_operations=self.file_ops_var.get(),
|
||
|
|
allow_shell_commands=self.shell_var.get(),
|
||
|
|
allow_system_control=self.system_var.get(),
|
||
|
|
allow_elevated_commands=self.elevated_var.get(),
|
||
|
|
require_confirmation=self.confirm_var.get()
|
||
|
|
)
|
||
|
|
|
||
|
|
def is_enabled(self) -> bool:
|
||
|
|
"""Check if agent mode is enabled"""
|
||
|
|
return self.enabled_var.get() and self.handler.config.enabled
|
||
|
|
|
||
|
|
|
||
|
|
# Example usage
|
||
|
|
if __name__ == "__main__":
|
||
|
|
# Test agent mode
|
||
|
|
handler = AgentModeHandler()
|
||
|
|
|
||
|
|
print("Testing agent mode...")
|
||
|
|
if handler.enable():
|
||
|
|
response = handler.process_message("List files in the current directory")
|
||
|
|
print(f"Response: {response}")
|
||
|
|
|
||
|
|
response = handler.process_message("What's 2+2? Calculate with Python")
|
||
|
|
print(f"Response: {response}")
|
||
|
|
|
||
|
|
handler.disable()
|