Class: SkillBench::Agent::ReactAgent::Step

Inherits:
Object
  • Object
show all
Defined in:
lib/skill_bench/agent/react_agent/step.rb

Overview

Service object responsible for executing a single step of the ReAct loop.

Class Method Summary collapse

Class Method Details

.build_iteration(thought:, tools_used:, observation_summary:) ⇒ Hash

Builds an iteration metadata hash.

Parameters:

  • thought (String)

    The agent’s reasoning for this step.

  • tools_used (Array<String>)

    Names of tools invoked.

  • observation_summary (String)

    Summary of tool results.

Returns:

  • (Hash)

    Iteration metadata.



82
83
84
85
86
87
88
# File 'lib/skill_bench/agent/react_agent/step.rb', line 82

def self.build_iteration(thought:, tools_used:, observation_summary:)
  {
    thought: thought,
    tools_used: tools_used,
    observation_summary: observation_summary
  }
end

.call(messages, config) ⇒ Hash

Executes one iteration of reasoning and potential tool usage.

Parameters:

  • messages (Array<Hash>)

    The conversation history.

  • config (Hash)

    Configuration for this step (client params, system prompt, working dir).

Returns:

  • (Hash)

    Step outcome containing :continue (boolean), :result (hash, if finished), and :messages.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
74
# File 'lib/skill_bench/agent/react_agent/step.rb', line 16

def self.call(messages, config)
  messages = messages.dup
  client_result = Client.call(
    system_prompt: config[:system_prompt],
    messages: messages,
    tools: Tools.definitions,
    **config[:client_params]
  )

  unless client_result[:success]
    error_msg = client_result.dig(:response, :error, :message) || 'Unknown error'
    return {
      continue: false,
      result: client_result,
      iteration: build_iteration(thought: '', tools_used: [], observation_summary: error_msg)
    }
  end

  response_msg = client_result.dig(:response, :message)
  unless response_msg
    return {
      continue: false,
      result: { success: false, response: { error: { message: 'Empty response from LLM' } } },
      iteration: build_iteration(thought: '', tools_used: [], observation_summary: 'Empty response from LLM')
    }
  end

  messages << response_msg

  tool_calls = response_msg['tool_calls']
  content = response_msg['content']
  tool_calls_array = Array(tool_calls)
  thought = content.to_s

  if tool_calls_array.empty?
    return {
      continue: false,
      result: { success: true, response: { content: content } },
      iteration: build_iteration(thought: thought, tools_used: [], observation_summary: '')
    }
  end

  if thought.strip.length.positive?
    warn "\n=== Agent Thought ==="
    warn content
  end

  tool_results = ToolExecutor.call(tool_calls, config[:working_dir], config[:container_id])
  messages.concat(tool_results)

  tools_used = tool_calls_array.map { |tc| tc.dig('function', 'name') }.compact
  observation_summary = Array(tool_results).map { |tr| tr[:content] || tr['content'] }.compact.join(', ')

  {
    continue: true,
    messages: messages,
    iteration: build_iteration(thought: thought, tools_used: tools_used, observation_summary: observation_summary)
  }
end