- Removed commented-out header styles from styles.base.tcss and styles.tcss. - Added new styles for danger buttons and agent selection views in styles.base.tcss and styles.tcss. - Implemented AgentHomeView to manage agent actions and display metadata. - Created AgentSelectView for selecting agents with a new layout and functionality. - Added CreateAgentView for creating new agents with input validation. - Removed obsolete eval.py and replaced it with evaluation.py. - Developed GameSelectView for selecting games with a dynamic loading interface. - Introduced ModelSelectView for selecting models associated with agents. - Created SelectRunView for managing runs associated with agents. - Added SubmissionView and TrainingView for handling model training and submission processes. - Updated requirements.txt to include pyfiglet for ASCII art rendering.
167 lines
6.7 KiB
Python
167 lines
6.7 KiB
Python
from textual.screen import Screen
|
||
from textual.containers import Vertical, Horizontal, VerticalScroll
|
||
from textual.widgets import Static, Button
|
||
from agentm.logic.db_functions import get_agents_for_game, delete_agent_by_id
|
||
from agentm.theme.palette import get_theme
|
||
from agentm.utils.logger import log_with_caller
|
||
from agentm.components.footer import AgentMFooter
|
||
from .create_agent import CreateAgentView
|
||
from .select_run import SelectRunView
|
||
from pathlib import Path
|
||
|
||
palette = get_theme()
|
||
|
||
class AgentCard(Static):
|
||
def __init__(self, agent_data: dict, parent_view):
|
||
super().__init__(classes="agent_card")
|
||
self.agent_data = agent_data
|
||
self.parent_view = parent_view
|
||
|
||
def render(self) -> str:
|
||
return f"""
|
||
[bold {palette.ACCENT}]{self.agent_data['name']}[/]
|
||
[dim]ID:[/] {self.agent_data['id']}
|
||
[dim]Created:[/] {self.agent_data.get('created_at', '—')}
|
||
[dim]Game ID:[/] {self.agent_data['game_id']}
|
||
""".strip()
|
||
|
||
async def on_click(self):
|
||
await self.parent_view.display_agent_info(self.agent_data)
|
||
|
||
|
||
class AgentSelectView(Screen):
|
||
BINDINGS = [
|
||
("escape", "app.pop_screen", "Back"),
|
||
("n", "create_agent", "New Agent"),
|
||
("r", "refresh_agents", "Refresh"),
|
||
("up", "scroll_up", "Scroll Up"),
|
||
("down", "scroll_down", "Scroll Down"),
|
||
]
|
||
|
||
def __init__(self, game_metadata: dict):
|
||
super().__init__()
|
||
self.game_metadata = game_metadata
|
||
self.selected_agent = None
|
||
self.delete_mode = False
|
||
|
||
def compose(self):
|
||
ascii_path = Path(__file__).parent.parent / "assets" / "headers" / "agent_select.txt"
|
||
try:
|
||
header_text = ascii_path.read_text()
|
||
except FileNotFoundError:
|
||
header_text = "=== SELECT AGENT ==="
|
||
|
||
self.header = Static(f"[{palette.ACCENT}]{header_text}[/{palette.ACCENT}]", classes="header")
|
||
self.subheader = Static(f"[b]{self.game_metadata['title']}[/b]", classes="subheader")
|
||
|
||
self.agent_list = VerticalScroll(id="agent_scroll")
|
||
self.agent_info = Horizontal(id="agent_info_panel")
|
||
|
||
self.confirm_button = Button("✅ Select Agent", id="confirm_agent_btn", classes="confirm_button", disabled=True)
|
||
self.delete_button = Button("🗑️ Delete Agent", id="delete_agent_btn", classes="danger_button", disabled=True)
|
||
self.create_button = Button("➕ Create Agent", id="create_agent_btn", classes="confirm_button")
|
||
|
||
yield Vertical(
|
||
self.header,
|
||
self.subheader,
|
||
self.agent_list,
|
||
self.agent_info,
|
||
self.create_button,
|
||
AgentMFooter(compact=True),
|
||
id="agent_select_layout"
|
||
)
|
||
|
||
async def on_mount(self):
|
||
log_with_caller("debug", f"Mounted AgentSelectView for game_id: {self.game_metadata['game_id']}")
|
||
await self.refresh_agent_list()
|
||
|
||
async def on_resume(self):
|
||
await self.refresh_agent_list()
|
||
|
||
async def refresh_agent_list(self):
|
||
try:
|
||
for child in list(self.agent_list.children):
|
||
await child.remove()
|
||
|
||
agents = get_agents_for_game(self.game_metadata["game_id"])
|
||
log_with_caller("info", f"Refreshed: {len(agents)} agents found for {self.game_metadata['game_id']}")
|
||
|
||
if agents:
|
||
for agent in agents:
|
||
await self.agent_list.mount(AgentCard(agent, self))
|
||
else:
|
||
await self.agent_list.mount(Static("[dim]No agents found for this game.[/dim]"))
|
||
|
||
self.selected_agent = None
|
||
self.delete_mode = False
|
||
await self.display_agent_info(None)
|
||
except Exception as e:
|
||
log_with_caller("error", f"Error rendering agent list: {e}")
|
||
|
||
async def display_agent_info(self, agent: dict | None):
|
||
self.selected_agent = agent
|
||
self.delete_mode = False
|
||
await self.agent_info.remove_children()
|
||
|
||
if not agent:
|
||
await self.agent_info.mount(Static("[dim]Select an agent to view details[/dim]"))
|
||
self.confirm_button.disabled = True
|
||
self.delete_button.disabled = True
|
||
return
|
||
|
||
from rich.panel import Panel
|
||
from rich.table import Table
|
||
|
||
table = Table.grid(padding=(0, 1))
|
||
table.add_column("Key", style="bold underline")
|
||
table.add_column("Value", style=palette.ACCENT, overflow="fold")
|
||
|
||
table.add_row("Name", agent["name"])
|
||
table.add_row("Agent ID", str(agent["id"]))
|
||
table.add_row("Game ID", agent["game_id"])
|
||
table.add_row("Created", agent.get("created_at", "—"))
|
||
table.add_row("Type", agent.get("agent_type", "—"))
|
||
table.add_row("Framework", agent.get("framework", "—"))
|
||
table.add_row("Imitation", str(agent.get("is_imitation", False)))
|
||
|
||
info_panel = Static(Panel(table, title="Agent Info", border_style=palette.BORDER), classes="agent_info_box")
|
||
button_column = Vertical(self.confirm_button, self.delete_button, classes="agent_action_box")
|
||
|
||
await self.agent_info.mount(info_panel, button_column)
|
||
self.confirm_button.disabled = False
|
||
self.delete_button.disabled = False
|
||
self.delete_button.label = "🗑️ Delete Agent"
|
||
|
||
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
||
if event.button.id == "create_agent_btn":
|
||
log_with_caller("info", "Create Agent button pressed.")
|
||
await self.app.push_screen(CreateAgentView(self.game_metadata))
|
||
|
||
elif event.button.id == "confirm_agent_btn" and self.selected_agent:
|
||
log_with_caller("info", f"Agent confirmed: {self.selected_agent['name']}")
|
||
await self.app.push_screen(SelectRunView(self.selected_agent))
|
||
|
||
elif event.button.id == "delete_agent_btn" and self.selected_agent:
|
||
if not self.delete_mode:
|
||
self.delete_mode = True
|
||
self.delete_button.label = "❌ Confirm Delete"
|
||
log_with_caller("warning", f"Pending deletion for agent: {self.selected_agent['name']}")
|
||
else:
|
||
log_with_caller("info", f"Deleting agent: {self.selected_agent['name']} ({self.selected_agent['id']})")
|
||
delete_agent_by_id(self.selected_agent["id"])
|
||
await self.refresh_agent_list()
|
||
|
||
async def action_create_agent(self):
|
||
await self.app.push_screen(CreateAgentView(self.game_metadata))
|
||
|
||
async def action_refresh_agents(self):
|
||
await self.refresh_agent_list()
|
||
|
||
async def action_scroll_up(self):
|
||
scroll = self.query_one("#agent_scroll", VerticalScroll)
|
||
scroll.scroll_up()
|
||
|
||
async def action_scroll_down(self):
|
||
scroll = self.query_one("#agent_scroll", VerticalScroll)
|
||
scroll.scroll_down()
|