Class: Octo::Server::HistoryCollector

Inherits:
Object
  • Object
show all
Defined in:
lib/octo/server/http_server.rb

Overview

Lightweight UI collector used by api_session_messages to capture events emitted by Agent#replay_history without broadcasting over WebSocket. Implements the same show_* interface as WebUIController.

Instance Method Summary collapse

Constructor Details

#initialize(session_id, events) ⇒ HistoryCollector

Returns a new instance of HistoryCollector.



30
31
32
33
# File 'lib/octo/server/http_server.rb', line 30

def initialize(session_id, events)
  @session_id = session_id
  @events     = events
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, **kwargs) ⇒ Object

Ignore all other UI methods (progress, errors, etc.) during history replay



113
# File 'lib/octo/server/http_server.rb', line 113

def method_missing(name, *args, **kwargs); end

Instance Method Details

#respond_to_missing?(name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


114
# File 'lib/octo/server/http_server.rb', line 114

def respond_to_missing?(name, include_private = false); true; end

#show_assistant_message(content, files:) ⇒ Object



75
76
77
78
79
80
81
# File 'lib/octo/server/http_server.rb', line 75

def show_assistant_message(content, files:)
  return if content.nil? || content.to_s.strip.empty?

  # Rewrite local image paths to /api/local-image proxy URLs for browser rendering
  rewritten = Utils::FileProcessor.rewrite_local_image_urls(content.to_s)
  @events << { type: "assistant_message", session_id: @session_id, content: rewritten }
end

#show_token_usage(token_data) ⇒ Object



106
107
108
109
110
# File 'lib/octo/server/http_server.rb', line 106

def show_token_usage(token_data)
  return unless token_data.is_a?(Hash)

  @events << { type: "token_usage", session_id: @session_id }.merge(token_data)
end

#show_tool_call(name, args) ⇒ Object



83
84
85
86
87
# File 'lib/octo/server/http_server.rb', line 83

def show_tool_call(name, args)
  args_data = args.is_a?(String) ? (JSON.parse(args) rescue args) : args
  summary   = tool_call_summary(name, args_data)
  @events << { type: "tool_call", session_id: @session_id, name: name, args: args_data, summary: summary }
end

#show_tool_result(result, ui_payload: nil) ⇒ Object



100
101
102
103
104
# File 'lib/octo/server/http_server.rb', line 100

def show_tool_result(result, ui_payload: nil)
  ev = { type: "tool_result", session_id: @session_id, result: result }
  ev[:ui_payload] = ui_payload if ui_payload
  @events << ev
end

#show_user_message(content, created_at: nil, files: []) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/octo/server/http_server.rb', line 35

def show_user_message(content, created_at: nil, files: [])
  images = []
  if content.is_a?(Array)
    text_parts = []
    content.each do |block|
      next unless block.is_a?(Hash)
      case block[:type]
      when "text"
        text_parts << block[:text]
      when "image_url"
        url = block.dig(:image_url, :url)
        images << url if url
      end
    end
    content = text_parts.join("\n")
  end

  ev = { type: "history_user_message", session_id: @session_id, content: content }
  ev[:created_at] = created_at if created_at
  rendered = Array(files).filter_map do |f|
    url  = f[:data_url] || f["data_url"]
    name = f[:name]     || f["name"]
    path = f[:path]     || f["path"]

    if url
      url
    elsif path && File.exist?(path.to_s)
      # Reconstruct data_url from the tmp file (still present on disk)
      Utils::FileProcessor.image_path_to_data_url(path) rescue "expired:#{name}"
    elsif name
      # File badge for non-image disk files, or image whose tmp file is gone
      type = f[:type] || f["type"] || ""
      type.to_s == "image" ? "expired:#{name}" : "pdf:#{name}"
    end
  end
  images.concat(rendered)
  ev[:images] = images unless images.empty?
  @events << ev
end