Class: SwarmCLI::InteractiveREPL
- Inherits:
-
Object
- Object
- SwarmCLI::InteractiveREPL
- Defined in:
- lib/swarm_cli/interactive_repl.rb
Overview
InteractiveREPL provides a professional, interactive terminal interface for conversing with SwarmSDK agents.
Features:
- Multiline input with intuitive submission (Enter on empty line or Ctrl+D)
- Beautiful Markdown rendering for agent responses
- Progress indicators during processing
- Command system (/help, /exit, /clear, etc.)
- Conversation history with context preservation
- Professional styling with Pastel and TTY tools
Constant Summary collapse
- COMMANDS =
{ "/help" => "Show available commands", "/clear" => "Clear the lead agent's conversation context", "/tools" => "List the lead agent's available tools", "/history" => "Show conversation history", "/defrag" => "Run memory defragmentation workflow (find and link related entries)", "/exit" => "Exit the REPL (or press Ctrl+D)", }.freeze
- HISTORY_SIZE =
History configuration
1000
Class Method Summary collapse
-
.history_file ⇒ Object
Get history file path (can be overridden with SWARM_HISTORY env var).
Instance Method Summary collapse
-
#execute_with_cancellation(input, &log_callback) ⇒ SwarmSDK::Result?
Execute a message with Ctrl+C cancellation support Public for testing.
-
#handle_command(input) ⇒ Object
Handle slash commands Public for testing.
-
#initialize(swarm:, options:, initial_message: nil) ⇒ InteractiveREPL
constructor
A new instance of InteractiveREPL.
- #run ⇒ Object
-
#save_persistent_history ⇒ void
Save persistent history to file Public for testing.
Constructor Details
#initialize(swarm:, options:, initial_message: nil) ⇒ InteractiveREPL
Returns a new instance of InteractiveREPL.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/swarm_cli/interactive_repl.rb', line 42 def initialize(swarm:, options:, initial_message: nil) @swarm = swarm @options = @initial_message = @conversation_history = [] @session_results = [] # Accumulate all results for session summary @validation_warnings_shown = false setup_ui_components setup_persistent_history # Create formatter for swarm execution output (interactive mode) @formatter = Formatters::HumanFormatter.new( output: $stdout, quiet: .quiet?, truncate: .truncate?, verbose: .verbose?, mode: :interactive, ) end |
Class Method Details
.history_file ⇒ Object
Get history file path (can be overridden with SWARM_HISTORY env var)
37 38 39 |
# File 'lib/swarm_cli/interactive_repl.rb', line 37 def history_file ENV["SWARM_HISTORY"] || File.("~/.swarm/history") end |
Instance Method Details
#execute_with_cancellation(input, &log_callback) ⇒ SwarmSDK::Result?
Execute a message with Ctrl+C cancellation support Public for testing
Uses swarm.stop for thread-safe cancellation via IO.pipe signaling. The INT trap handler calls swarm.stop which writes to the pipe, waking the Async scheduler's stop listener to cancel all tasks.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/swarm_cli/interactive_repl.rb', line 99 def execute_with_cancellation(input, &log_callback) # Install trap ONLY during execution # swarm.stop is safe to call from trap context (IO.pipe write) old_trap = trap("INT") do @swarm.stop end result = @swarm.execute(input, &log_callback) result&.interrupted? ? nil : result ensure # CRITICAL: Restore old trap when done # This ensures Ctrl+C at the prompt still exits the REPL trap("INT", old_trap) end |
#handle_command(input) ⇒ Object
Handle slash commands Public for testing
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/swarm_cli/interactive_repl.rb', line 119 def handle_command(input) command = input.split.first.downcase case command when "/help" display_help when "/clear" clear_context when "/tools" list_tools when "/history" display_history when "/defrag" defrag_memory when "/exit" # Break from main loop to trigger session summary throw(:exit_repl) else puts render_error("Unknown command: #{command}") puts @colors[:system].call("Type /help for available commands") end end |
#run ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/swarm_cli/interactive_repl.rb', line 63 def run display_welcome # Emit validation warnings before first prompt emit_validation_warnings_before_prompt # Send initial message if provided if @initial_message && !@initial_message.empty? (@initial_message) end main_loop display_goodbye display_session_summary rescue Interrupt puts "\n" display_goodbye display_session_summary exit(130) ensure # Defensive: ensure all spinners are stopped on exit @formatter&.spinner_manager&.stop_all # Save history on exit save_persistent_history end |
#save_persistent_history ⇒ void
This method returns an undefined value.
Save persistent history to file Public for testing
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/swarm_cli/interactive_repl.rb', line 146 def save_persistent_history history_file = self.class.history_file return unless history_file history = Reline::HISTORY.to_a # Limit to configured size if HISTORY_SIZE.positive? && history.size > HISTORY_SIZE history = history.last(HISTORY_SIZE) end # Write with secure permissions (owner read/write only) File.open(history_file, "w", 0o600, encoding: Encoding::UTF_8) do |f| # Handle multi-line entries by escaping newlines with backslash history.each do |entry| escaped = entry.scrub.split("\n").join("\\\n") f.puts(escaped) end end rescue Errno::EACCES, Errno::ENOENT # Can't write history - continue anyway nil end |