Class: RubyPi::Agent::State

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_pi/agent/state.rb

Overview

Mutable state object threaded through the agent loop. Encapsulates the full conversation history, configuration, and hook callables so that the loop, compaction, and transforms all operate on a single shared object.

Examples:

Creating and using state

state = RubyPi::Agent::State.new(
  system_prompt: "You are helpful.",
  model: RubyPi::LLM.model(:gemini, "gemini-2.0-flash"),
  tools: registry,
  max_iterations: 10
)
state.add_message(role: :user, content: "Hi!")
state.messages  # => [{ role: :user, content: "Hi!" }]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(system_prompt:, model:, tools: nil, messages: [], max_iterations: 10, transform_context: nil, before_tool_call: nil, after_tool_call: nil, user_data: {}) ⇒ State

Creates a new State instance with the given configuration.

Parameters:

  • system_prompt (String)

    the system-level instruction prompt

  • model (RubyPi::LLM::BaseProvider)

    the LLM provider to use

  • tools (RubyPi::Tools::Registry, nil) (defaults to: nil)

    tool registry (nil for no tools)

  • messages (Array<Hash>) (defaults to: [])

    initial conversation history

  • max_iterations (Integer) (defaults to: 10)

    max think-act-observe cycles (default: 10)

  • transform_context (Proc, nil) (defaults to: nil)

    context transform hook

  • before_tool_call (Proc, nil) (defaults to: nil)

    pre-tool-execution hook

  • after_tool_call (Proc, nil) (defaults to: nil)

    post-tool-execution hook

  • user_data (Hash) (defaults to: {})

    arbitrary data bag for extensions/transforms



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/ruby_pi/agent/state.rb', line 69

def initialize(
  system_prompt:,
  model:,
  tools: nil,
  messages: [],
  max_iterations: 10,
  transform_context: nil,
  before_tool_call: nil,
  after_tool_call: nil,
  user_data: {}
)
  @system_prompt = system_prompt
  @model = model
  @tools = tools
  @messages = Array(messages).dup
  @max_iterations = max_iterations
  @transform_context = transform_context
  @before_tool_call = before_tool_call
  @after_tool_call = after_tool_call
  @user_data = user_data
  @iteration = 0
end

Instance Attribute Details

#after_tool_callProc?

Returns callable invoked after each tool call; receives the ToolCall and the RubyPi::Tools::Result.

Returns:

  • (Proc, nil)

    callable invoked after each tool call; receives the ToolCall and the RubyPi::Tools::Result



52
53
54
# File 'lib/ruby_pi/agent/state.rb', line 52

def after_tool_call
  @after_tool_call
end

#before_tool_callProc?

Returns callable invoked before each tool call; receives the RubyPi::LLM::ToolCall.

Returns:

  • (Proc, nil)

    callable invoked before each tool call; receives the RubyPi::LLM::ToolCall



48
49
50
# File 'lib/ruby_pi/agent/state.rb', line 48

def before_tool_call
  @before_tool_call
end

#max_iterationsInteger (readonly)

Returns maximum think-act-observe iterations before halting.

Returns:

  • (Integer)

    maximum think-act-observe iterations before halting



40
41
42
# File 'lib/ruby_pi/agent/state.rb', line 40

def max_iterations
  @max_iterations
end

#modelRubyPi::LLM::BaseProvider (readonly)

Returns the LLM provider instance.

Returns:



34
35
36
# File 'lib/ruby_pi/agent/state.rb', line 34

def model
  @model
end

#system_promptString

Returns the system prompt prepended to every LLM call.

Returns:

  • (String)

    the system prompt prepended to every LLM call



31
32
33
# File 'lib/ruby_pi/agent/state.rb', line 31

def system_prompt
  @system_prompt
end

#toolsRubyPi::Tools::Registry (readonly)

Returns the registry of available tools.

Returns:



37
38
39
# File 'lib/ruby_pi/agent/state.rb', line 37

def tools
  @tools
end

#transform_contextProc?

Returns callable invoked with state before each LLM call to transform context (system prompt, messages).

Returns:

  • (Proc, nil)

    callable invoked with state before each LLM call to transform context (system prompt, messages)



44
45
46
# File 'lib/ruby_pi/agent/state.rb', line 44

def transform_context
  @transform_context
end

#user_dataHash

Returns arbitrary user-provided data accessible by transforms and extensions.

Returns:

  • (Hash)

    arbitrary user-provided data accessible by transforms and extensions



56
57
58
# File 'lib/ruby_pi/agent/state.rb', line 56

def user_data
  @user_data
end

Instance Method Details

#add_message(role:, content: nil, **options) ⇒ Array<Hash>

Appends a message to the conversation history.

Parameters:

  • role (Symbol, String)

    the message role (:user, :assistant, :system, :tool)

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

    the text content of the message

  • options (Hash)

    additional fields (e.g., :tool_call_id, :tool_calls)

Returns:

  • (Array<Hash>)

    the updated messages array



98
99
100
101
102
# File 'lib/ruby_pi/agent/state.rb', line 98

def add_message(role:, content: nil, **options)
  message = { role: role.to_sym, content: content }.merge(options)
  @messages << message
  @messages
end

#increment_iteration!Integer

Increments the iteration counter by one. Called by the agent loop at the end of each think-act-observe cycle.

Returns:

  • (Integer)

    the new iteration count



133
134
135
# File 'lib/ruby_pi/agent/state.rb', line 133

def increment_iteration!
  @iteration += 1
end

#inspectString

Provides a human-readable summary of the current state for debugging.

Returns:

  • (String)


147
148
149
150
151
152
# File 'lib/ruby_pi/agent/state.rb', line 147

def inspect
  "#<RubyPi::Agent::State " \
    "iteration=#{@iteration}/#{@max_iterations} " \
    "messages=#{@messages.size} " \
    "tools=#{@tools&.size || 0}>"
end

#iterationInteger

Returns the current iteration count (number of completed think-act-observe cycles).

Returns:

  • (Integer)

    the iteration count



125
126
127
# File 'lib/ruby_pi/agent/state.rb', line 125

def iteration
  @iteration
end

#max_iterations_reached?Boolean

Returns true if the iteration count has reached or exceeded max_iterations.

Returns:

  • (Boolean)


140
141
142
# File 'lib/ruby_pi/agent/state.rb', line 140

def max_iterations_reached?
  @iteration >= @max_iterations
end

#messagesArray<Hash>

Returns a frozen copy of the conversation history. Callers cannot accidentally mutate the internal array through this reference.

Returns:

  • (Array<Hash>)

    the full conversation history



108
109
110
# File 'lib/ruby_pi/agent/state.rb', line 108

def messages
  @messages.dup.freeze
end

#messages=(new_messages) ⇒ Array<Hash>

Replaces the entire conversation history. Used by compaction to swap in a shortened message array.

Parameters:

  • new_messages (Array<Hash>)

    the replacement message array

Returns:

  • (Array<Hash>)

    the new messages array



117
118
119
# File 'lib/ruby_pi/agent/state.rb', line 117

def messages=(new_messages)
  @messages = Array(new_messages).dup
end