Mastodon Politics, Power, and Science: Implementation Plan: Agent Test & Run Facility to agent workflow GUI

Monday, August 4, 2025

Implementation Plan: Agent Test & Run Facility to agent workflow GUI

This plan outlines the necessary steps to integrate a "Run/Test" feature directly into the GUI, transforming it into a complete IDE for your agents.

The core principle is to treat dynamic_workflows_agents.py as a library and the GUI as a client application, with zero modifications to the core engine.


Implementation Plan: Agent Test & Run Facility

Phase 1: GUI - The "Run" Button and Modal Launcher

This phase involves adding the user-facing entry point and preparing the main application to launch the test environment.

  1. Modify editor_app.py - Add UI Trigger:

    • In the create_settings_tab method of the ProcEditorFrame, TemplateEditorFrame, and WorkflowEditorFrame classes, add a new button.

    • Code:

      Generated python
      # Add this within the create_settings_tab method of each editor frame
      ctk.CTkButton(tab, text="Run/Test Agent...", command=self.open_run_modal).pack(anchor="w", padx=10, pady=10)
          
  2. Add a Launcher Method to Each Editor Frame:

    • In ProcEditorFrame, TemplateEditorFrame, and WorkflowEditorFrame, create a new method that gathers the current, potentially unsaved data from the form and calls the main app's launcher. This ensures the test run uses the very latest edits.

    • Code:

      Generated python
      # Add this method to each of the three main editor frames
      def open_run_modal(self):
          # Get the current data from the editor, including unsaved changes
          current_agent_data = self.get_data()
          # The name is part of the data, so we extract it
          agent_name = current_agent_data.pop('name', self.agent_name)
          self.app_ref.launch_run_modal(agent_name, current_agent_data)
          
  3. Add a Global Launcher Method to the App Class:

    • This method in the main App class will be responsible for creating and displaying the modal window.

    • Code:

      Generated python
      # Add this new method to the App class in editor_app.py
      def launch_run_modal(self, agent_name, agent_data):
          """Launches the modal window for running/testing an agent."""
          modal = RunAgentModal(self, agent_name, agent_data, self.config)
          # The .wait_window() call is not strictly necessary but good practice
          # if you want to ensure it blocks until closed.
          

Phase 2: The Core Feature - RunAgentModal

This is a new, self-contained class that manages the entire test-run process. It will be added to editor_app.py.

  1. Create the TextboxLogHandler Class:

    • This custom logging handler is crucial for redirecting log output to a GUI widget.

    • Code:

      Generated python
      import logging
      import customtkinter as ctk
      
      class TextboxLogHandler(logging.Handler):
          """A logging handler that redirects records to a CTkTextbox widget."""
          def __init__(self, textbox_widget):
              super().__init__()
              self.textbox = textbox_widget
              self.textbox.configure(state="disabled")
      
          def emit(self, record):
              msg = self.format(record)
              self.textbox.configure(state="normal")
              self.textbox.insert(ctk.END, msg + "\n")
              self.textbox.see(ctk.END) # Auto-scroll
              self.textbox.configure(state="disabled")
          
  2. Create the RunAgentModal Class Skeleton:

    • Import necessary modules at the top of editor_app.py: import time, import dynamic_workflows_agents, import json.

    • Define the new class. Its __init__ will store the context it needs.

    • Code:

      Generated python

            class RunAgentModal(ctk.CTkToplevel):
          def __init__(self, parent, agent_name, agent_data, config_manager):
              super().__init__(parent)
              self.title(f"Test Run: {agent_name}")
              self.geometry("1200x700")
      
              self.parent = parent
              self.agent_name = agent_name
              self.agent_data = agent_data
              self.config_manager = config_manager
              self.input_entries = {}
      
              self.grid_columnconfigure(1, weight=3)
              self.grid_columnconfigure(0, weight=2)
              self.grid_rowconfigure(0, weight=1)
      
              self.create_widgets()
              self.transient(parent)
              self.grab_set()
          
  3. Implement create_widgets for RunAgentModal:

    • This method builds the UI for inputs and outputs.

    • Conceptual Code:

      Generated python

            def create_widgets(self):
          # --- Input Pane (Left) ---
          input_frame = ctk.CTkFrame(self)
          input_frame.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
          # Add labels, entries for required inputs from self.agent_data['inputs']
          # Populate self.input_entries dictionary mapping input_name -> CTkEntry widget
          # Add a way to add optional inputs from self.agent_data['optional_inputs']
          # Add the "Run Workflow" button, with command=self.execute_run
      
          # --- Output Pane (Right) ---
          output_tabs = ctk.CTkTabview(self)
          output_tabs.grid(row=0, column=1, padx=10, pady=10, sticky="nsew")
          # Create "Result", "Log", "Status & Stats" tabs
          # Add a CTkTextbox to each tab, storing them in self.result_box, self.log_box, etc.
          
  4. Implement execute_run for RunAgentModal:

    • This is the core logic that orchestrates the test run.

    • Conceptual Code:

      Generated python

           def execute_run(self):
          # 1. Clear previous outputs
          # self.result_box.delete(...), self.log_box.delete(...)
      
          # 2. Gather inputs from self.input_entries into a cli_args dictionary
      
          # 3. Prepare the agent (reuse existing logic)
          if self.agent_data.get('type') != 'workflow':
              agent_to_run = dynamic_workflows_agents.create_temp_workflow(
                  self.agent_name, self.agent_data, self.config_manager.config, cli_args
              )
          else:
              agent_to_run = self.agent_data
      
          # 4. Setup logging redirection
          log_handler = TextboxLogHandler(self.log_box)
          # Set a formatter for clean output
          log_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
          logging.getLogger().addHandler(log_handler)
          
          # 5. Execute in a try...finally block to ensure cleanup
          try:
              start_time = time.perf_counter()
              
              final_result, status = dynamic_workflows_agents.exec_workflow(
                  workflow=agent_to_run,
                  config=self.config_manager.config,
                  cli_args=cli_args,
                  results={} # Always start with a fresh results tape
              )
              
              duration = time.perf_counter() - start_time
              
              # 6. Display results
              # Format final_result as pretty JSON and insert into self.result_box
              # Format status and duration and insert into self.stats_box
      
          except Exception as e:
              # Log any crashes to the log box itself
              logging.error(f"FATAL EXECUTION ERROR: {e}", exc_info=True)
          finally:
              # 7. CRITICAL: Clean up the logger
              logging.getLogger().removeHandler(log_handler)
          

Plan Summary

This plan provides a complete, isolated, and robust solution. It perfectly demonstrates the power of your decoupled architecture by having the GUI act as a sophisticated client to the core engine library. It introduces a major new feature without requiring a single change to the engine itself, proving the soundness of the overall design.

No comments:

Post a Comment

Progress on the campaign manager

You can see that you can build tactical maps automatically from the world map data.  You can place roads, streams, buildings. The framework ...