Module: AIA::ContentExtractor

Instance Method Summary collapse

Instance Method Details

#extract_content(result) ⇒ String

Extract text content from a response object.

Parameters:

  • result

    the response (RobotResult, SimpleFlow::Result, String, etc.)

Returns:

  • (String)

    the extracted text



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/aia/content_extractor.rb', line 15

def extract_content(result)
  if defined?(SimpleFlow::Result) && result.is_a?(SimpleFlow::Result)
    return extract_network_content(result)
  end

  if result.respond_to?(:reply)
    result.reply
  elsif result.respond_to?(:last_text_content)
    result.last_text_content
  elsif result.respond_to?(:content)
    result.content
  else
    result.to_s
  end
end

#extract_network_content(flow_result) ⇒ String

Extract content from a Network's SimpleFlow::Result. Each robot's result is stored in context under its task name. Includes per-robot timing when available.

Parameters:

  • flow_result (SimpleFlow::Result)

Returns:

  • (String)


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
# File 'lib/aia/content_extractor.rb', line 37

def extract_network_content(flow_result)
  parts = []
  flow_result.context.each do |task_name, robot_result|
    next if task_name == :run_params

    content = if robot_result.respond_to?(:reply)
                robot_result.reply
              elsif robot_result.respond_to?(:content)
                robot_result.content
              else
                robot_result.to_s
              end
    next unless content && !content.empty?

    duration = robot_result.respond_to?(:duration) ? robot_result.duration : nil
    robot_name = robot_result.respond_to?(:robot_name) ? robot_result.robot_name : nil
    label = robot_name && robot_name != task_name.to_s ? "#{robot_name} [#{task_name}]" : task_name.to_s
    header = if duration
               "**#{label}** (#{format_duration(duration)}):"
             else
               "**#{label}:**"
             end
    parts << "#{header}\n#{content}"
  end
  parts.join("\n\n")
end

#format_duration(seconds) ⇒ String

Format a duration in seconds to a human-readable string.

Parameters:

  • seconds (Float, nil)

Returns:

  • (String)


141
142
143
144
145
146
147
148
149
150
151
# File 'lib/aia/content_extractor.rb', line 141

def format_duration(seconds)
  return "0.0s" unless seconds

  if seconds < 60
    "%.1fs" % seconds
  else
    minutes = (seconds / 60).to_i
    secs = seconds % 60
    "#{minutes}m %04.1fs" % secs
  end
end

#output_to_file(content) ⇒ Object

Write AI response content to the configured output file.

Parameters:

  • content (String)

    the AI response text



130
131
132
133
134
135
# File 'lib/aia/content_extractor.rb', line 130

def output_to_file(content)
  out_file = AIA.config.output.file
  return unless out_file

  File.open(out_file, 'a') { |f| f.puts "\nAI: #{content}" }
end

#present_result(result, ui_presenter:, streamed_content: nil, prompt: nil, elapsed: nil, tracker: nil, decisions: nil) ⇒ String

Present an AI result: extract content, record the turn, display, write to output file, show metrics, speak, and print separator. Callers pass only the keyword args they need; everything optional defaults to nil / false so this works for both full ChatLoop turns and simpler SpecialModeHandler dispatches.

Parameters:

  • result

    the response object

  • streamed_content (String, nil) (defaults to: nil)

    pre-streamed content (skips display_ai_response)

  • prompt (String, nil) (defaults to: nil)

    user prompt for tracker

  • elapsed (Float, nil) (defaults to: nil)

    elapsed seconds

  • ui_presenter (UIPresenter)

    for display calls

  • tracker (SessionTracker, nil) (defaults to: nil)

    to record the turn

  • decisions (Hash, nil) (defaults to: nil)

    routing decisions for tracker

Returns:

  • (String)

    the extracted content



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/aia/content_extractor.rb', line 100

def present_result(result, ui_presenter:, streamed_content: nil, prompt: nil, elapsed: nil, tracker: nil, decisions: nil)
  content = streamed_content || extract_content(result)

  if tracker && prompt
    tracker.record_turn(
      model: AIA.config.models.first.name,
      input: prompt,
      result: result,
      decisions: decisions,
      elapsed: elapsed
    )
  end

  if streamed_content
    puts
  else
    ui_presenter.display_ai_response(content)
  end

  output_to_file(content)
  display_metrics(result, elapsed: elapsed) if respond_to?(:display_metrics, true)
  speak(content) if respond_to?(:speak, true)
  ui_presenter.display_separator

  content
end

#store_results_in_memory(flow_result, network) ⇒ Object

Store structured robot results into a network's shared memory. Each robot's output is written as a hash under result_<task_name>.

Parameters:

  • flow_result (SimpleFlow::Result)
  • network (RobotLab::Network)


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/aia/content_extractor.rb', line 69

def store_results_in_memory(flow_result, network)
  return unless network.respond_to?(:memory)

  memory = network.memory
  flow_result.context.each do |task_name, robot_result|
    next if task_name == :run_params
    next unless robot_result.respond_to?(:reply)

    memory.current_writer = task_name.to_s
    memory.set(:"result_#{task_name}", {
      content:  robot_result.reply,
      model:    robot_result.respond_to?(:robot_name) ? robot_result.robot_name : nil,
      duration: robot_result.respond_to?(:duration) ? robot_result.duration : nil
    })
  end
end