Commit 0e2456f

mo khan <mo@mokhan.ca>
2025-08-13 15:37:49
feat: add colour and progress indicators
1 parent 4a8da39
Changed files (4)
lib/elelem/agent.rb
@@ -36,6 +36,18 @@ module Elelem
       configuration.tools.execute(tool_call)
     end
 
+    def show_progress(message, prefix = "[.]", colour: :gray)
+      configuration.tui.show_progress(message, prefix, colour: colour)
+    end
+
+    def clear_line
+      configuration.tui.clear_line
+    end
+
+    def complete_progress(message = "Completed")
+      configuration.tui.complete_progress(message)
+    end
+
     def quit
       logger.debug("Exiting...")
       exit
lib/elelem/state.rb
@@ -44,12 +44,22 @@ module Elelem
     end
 
     class Thinking < State
+      def initialize(agent)
+        super(agent)
+        @progress_shown = false
+      end
+
       def process(message)
         if message["thinking"] && !message["thinking"]&.empty?
+          unless @progress_shown
+            agent.show_progress("Thinking...", "[*]", colour: :yellow)
+            agent.say("\n", newline: false)
+            @progress_shown = true
+          end
           agent.say(message["thinking"], colour: :gray, newline: false)
           self
         else
-          agent.say("", newline: true)
+          agent.say("\n\n", newline: false)
           Waiting.new(agent).process(message)
         end
       end
@@ -59,7 +69,16 @@ module Elelem
       def process(message)
         if message["tool_calls"]&.any?
           message["tool_calls"].each do |tool_call|
-            agent.conversation.add(role: :tool, content: agent.execute(tool_call))
+            tool_name = tool_call.dig("function", "name") || "unknown"
+            agent.show_progress(tool_name, "[>]", colour: :magenta)
+            agent.say("\n\n", newline: false)
+            
+            result = agent.execute(tool_call)
+            agent.conversation.add(role: :tool, content: result)
+            
+            agent.say("\n", newline: false)
+            agent.complete_progress("Tool completed")
+            agent.say("\n", newline: false)
           end
         end
 
@@ -68,13 +87,23 @@ module Elelem
     end
 
     class Talking < State
+      def initialize(agent)
+        super(agent)
+        @progress_shown = false
+      end
+
       def process(message)
         if message["content"] && !message["content"]&.empty?
+          unless @progress_shown
+            agent.show_progress("Responding...", "[~]", colour: :white)
+            agent.say("\n", newline: false)
+            @progress_shown = true
+          end
           agent.conversation.add(role: message["role"], content: message["content"])
           agent.say(message["content"], colour: :default, newline: false)
           self
         else
-          agent.say("", newline: true)
+          agent.say("\n", newline: true)
           Waiting.new(agent).process(message)
         end
       end
@@ -82,6 +111,9 @@ module Elelem
 
     def run(agent)
       agent.logger.debug("Working...")
+      agent.show_progress("Processing...", "[.]", colour: :cyan)
+      agent.say("\n\n", newline: false)
+      
       state = Waiting.new(agent)
       done = false
 
lib/elelem/tools.rb
@@ -44,7 +44,6 @@ module Elelem
       tool = @tools.find do |tool|
         tool.dig(:function, :name) == name
       end
-      configuration.tui.say(args, newline: true)
       tool&.fetch(:handler)&.call(args).tap do |result|
         configuration.tui.say(result)
       end
lib/elelem/tui.rb
@@ -24,12 +24,46 @@ module Elelem
       stdout.flush
     end
 
+    def show_progress(message, prefix = "[.]", colour: :gray)
+      timestamp = current_time_string
+      formatted_message = colourize("#{prefix} #{timestamp} #{message}", colour: colour)
+      stdout.print(formatted_message)
+      stdout.flush
+    end
+
+    def clear_line
+      stdout.print("\r" + " " * 80 + "\r")
+      stdout.flush
+    end
+
+    def complete_progress(message = "Completed")
+      clear_line
+      timestamp = current_time_string
+      formatted_message = colourize("[✓] #{timestamp} #{message}", colour: :green)
+      stdout.puts(formatted_message)
+      stdout.flush
+    end
+
     private
 
+    def current_time_string
+      Time.now.strftime("%H:%M:%S")
+    end
+
     def colourize(text, colour: :default)
       case colour
       when :gray
         "\e[90m#{text}\e[0m"
+      when :cyan
+        "\e[36m#{text}\e[0m"
+      when :yellow
+        "\e[33m#{text}\e[0m"
+      when :magenta
+        "\e[35m#{text}\e[0m"
+      when :green
+        "\e[32m#{text}\e[0m"
+      when :white
+        "\e[37m#{text}\e[0m"
       else
         text
       end