- 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.
107 lines
4.3 KiB
Python
107 lines
4.3 KiB
Python
from textual.screen import Screen
|
|
from textual.widgets import Static, Input, Button
|
|
from textual.containers import Vertical, Horizontal
|
|
from agentm.theme.palette import get_theme
|
|
from agentm.utils.logger import log_with_caller
|
|
from agentm.logic.db_functions import insert_model, update_run_pending
|
|
from datetime import datetime
|
|
|
|
palette = get_theme()
|
|
|
|
class TrainingView(Screen):
|
|
BINDINGS = [
|
|
("escape", "app.pop_screen", "Back")
|
|
]
|
|
|
|
def __init__(self, agent: dict, model: dict | None, run: dict):
|
|
super().__init__()
|
|
self.agent_metadata = agent
|
|
self.model_metadata = model
|
|
self.run_metadata = run
|
|
self.is_pending_run = run.get("pending", True)
|
|
|
|
def compose(self):
|
|
log_with_caller("info", f"Opening TrainingView for agent='{self.agent_metadata['name']}', run='{self.run_metadata['name']}', pending={self.is_pending_run}")
|
|
|
|
yield Static(f"[{palette.ACCENT} bold]Training: {self.agent_metadata['name']}[/]", classes="header")
|
|
|
|
if self.is_pending_run:
|
|
yield self.render_pending_setup()
|
|
else:
|
|
yield self.render_resume_options()
|
|
|
|
def render_pending_setup(self):
|
|
yield Static("[b]Initial Model Setup[/b]", classes="subheader")
|
|
|
|
self.name_input = Input(placeholder="Model Name", id="model_name")
|
|
self.steps_input = Input(placeholder="Total Training Steps", id="total_steps")
|
|
self.lr_input = Input(placeholder="Initial Learning Rate", id="learning_rate")
|
|
self.clip_input = Input(placeholder="Initial Clip Range", id="clip_range")
|
|
self.notes_input = Input(placeholder="Notes", id="notes")
|
|
|
|
self.confirm_button = Button("✅ Create & Start Training", id="confirm_model_btn", classes="confirm_button")
|
|
|
|
return Vertical(
|
|
self.name_input,
|
|
self.steps_input,
|
|
self.lr_input,
|
|
self.clip_input,
|
|
self.notes_input,
|
|
self.confirm_button,
|
|
classes="centered_layout"
|
|
)
|
|
|
|
def render_resume_options(self):
|
|
model = self.model_metadata
|
|
from rich.table import Table
|
|
from rich.panel import Panel
|
|
|
|
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", model["name"])
|
|
table.add_row("Steps", f"{model['total_steps_completed']} / {model['total_steps_planned']}")
|
|
table.add_row("Reward", str(model.get("average_reward", "—")))
|
|
table.add_row("Learning Rate", str(model.get("current_learning_rate", "—")))
|
|
table.add_row("Clip Range", str(model.get("current_clip_range", "—")))
|
|
table.add_row("Created", model.get("created_at", "—"))
|
|
|
|
return Vertical(
|
|
Static(Panel(table, title="Model Info", border_style=palette.BORDER), classes="agent_info_box"),
|
|
Button("⏯️ Resume Training", id="resume_training_btn", classes="confirm_button"),
|
|
classes="centered_layout"
|
|
)
|
|
|
|
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
|
if event.button.id == "confirm_model_btn":
|
|
try:
|
|
name = self.name_input.value.strip()
|
|
total_steps = int(self.steps_input.value)
|
|
learning_rate = float(self.lr_input.value)
|
|
clip_range = float(self.clip_input.value)
|
|
notes = self.notes_input.value.strip()
|
|
|
|
log_with_caller("info", f"Creating new model: {name} for agent_id={self.agent_metadata['id']}")
|
|
|
|
insert_model(
|
|
agent_id=self.agent_metadata["id"],
|
|
name=name,
|
|
total_steps_planned=total_steps,
|
|
current_learning_rate=learning_rate,
|
|
current_clip_range=clip_range,
|
|
notes=notes
|
|
)
|
|
|
|
update_run_pending(self.run_metadata["id"], False)
|
|
log_with_caller("info", f"Model '{name}' created and run marked as not pending")
|
|
|
|
await self.app.pop_screen()
|
|
|
|
except Exception as e:
|
|
log_with_caller("error", f"Failed to create model: {e}")
|
|
|
|
elif event.button.id == "resume_training_btn":
|
|
log_with_caller("info", f"Resuming training for model: {self.model_metadata['name']}")
|
|
await self.app.pop_screen()
|