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

The universe held up a mirror and we did not recognize our own arbitrary scales.

  Because the reflection was so perfect we mistook our own face for the face of God. We built the axes. We invented length, duration, mass —...