Class: Pikuri::Agent::Control::StepLimit

Inherits:
Object
  • Object
show all
Defined in:
lib/pikuri/agent/control/step_limit.rb

Overview

Caps the number of tool calls per Pikuri::Agent#run_loop. ruby_llm has no step budget; the Agent pokes #tick! on every before_tool_call and #reset! at turn start. Once the count exceeds the cap, #tick! raises Exceeded and the Agent applies #on_exhausted: re-raise to the host (default), or run the synthesizer to salvage a partial answer.

Why the policy lives here, not on Agent

Synthesis can only fire off a tripped step limit, so an Agent.new(synthesize: ...) kwarg would be meaningless when step_limit: is nil — an invalid combination. Attaching the policy to the budget makes "what happens when it runs out" travel with the budget, and that nonsense state unrepresentable. Hosts pick per wiring: a Q&A REPL wants :synthesize (salvage from evidence so far); a coding agent wants :raise (a tools-free pass can't finish code — stop, let the user say "continue"; #reset! refreshes the budget next turn).

Defined Under Namespace

Classes: Exceeded

Constant Summary collapse

ON_EXHAUSTED =

Valid #on_exhausted policies.

%i[raise synthesize].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max:, on_exhausted: :raise) ⇒ StepLimit

Returns a new instance of StepLimit.

Parameters:

  • max (Integer)

    hard cap on tool-call rounds; must be positive

  • on_exhausted (Symbol) (defaults to: :raise)

    :raise (default) or :synthesize — see #on_exhausted

Raises:

  • (ArgumentError)

    if max is zero or negative, or on_exhausted is not one of ON_EXHAUSTED



53
54
55
56
57
58
59
60
61
# File 'lib/pikuri/agent/control/step_limit.rb', line 53

def initialize(max:, on_exhausted: :raise)
  raise ArgumentError, "max must be positive, got #{max}" if max <= 0
  raise ArgumentError, "on_exhausted must be one of #{ON_EXHAUSTED.inspect}, got #{on_exhausted.inspect}" \
    unless ON_EXHAUSTED.include?(on_exhausted)

  @max = max
  @on_exhausted = on_exhausted
  @step = 0
end

Instance Attribute Details

#maxInteger (readonly)

Returns the configured cap.

Returns:

  • (Integer)

    the configured cap



39
40
41
# File 'lib/pikuri/agent/control/step_limit.rb', line 39

def max
  @max
end

#on_exhaustedSymbol (readonly)

Returns what Pikuri::Agent#run_loop does when this budget trips: :raise lets Exceeded propagate to the host; :synthesize runs the tools-free synthesizer rescue. See the class header for how to pick.

Returns:

  • (Symbol)

    what Pikuri::Agent#run_loop does when this budget trips: :raise lets Exceeded propagate to the host; :synthesize runs the tools-free synthesizer rescue. See the class header for how to pick.



45
46
47
# File 'lib/pikuri/agent/control/step_limit.rb', line 45

def on_exhausted
  @on_exhausted
end

#stepInteger (readonly)

Returns current step count.

Returns:

  • (Integer)

    current step count.



84
85
86
# File 'lib/pikuri/agent/control/step_limit.rb', line 84

def step
  @step
end

Instance Method Details

#reset!void

This method returns an undefined value.

Reset the counter to zero. Called by Pikuri::Agent at each turn start so one instance governs many turns. Mid-loop Interloper injections deliberately do not reset — they're context for the same turn, and a chatty user could otherwise refresh the budget forever by injecting.



79
80
81
# File 'lib/pikuri/agent/control/step_limit.rb', line 79

def reset!
  @step = 0
end

#tick!void

This method returns an undefined value.

Increment the counter; raise Exceeded once it crosses #max. Called from Pikuri::Agent's before_tool_call wiring.

Raises:



68
69
70
71
# File 'lib/pikuri/agent/control/step_limit.rb', line 68

def tick!
  @step += 1
  raise Exceeded, @max if @step > @max
end

#to_sString

Returns short config dump for Pikuri::Agent#to_s; the policy renders only when the non-default :synthesize.

Returns:

  • (String)

    short config dump for Pikuri::Agent#to_s; the policy renders only when the non-default :synthesize.



88
89
90
91
# File 'lib/pikuri/agent/control/step_limit.rb', line 88

def to_s
  policy = @on_exhausted == :raise ? '' : ", on_exhausted=#{@on_exhausted}"
  "StepLimit(max=#{@max}#{policy})"
end