Module: RubyLLM::Agents::Instrumentation Deprecated Private

Extended by:
ActiveSupport::Concern
Defined in:
lib/ruby_llm/agents/core/instrumentation.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Deprecated.

This module is deprecated and will be removed in a future version. All agents now use Pipeline::Middleware::Instrumentation automatically via the middleware pipeline. This module is no longer included in any production class. It remains only for backward compatibility with code that explicitly includes it.

Instance Method Summary collapse

Instance Method Details

#capture_response(response) ⇒ RubyLLM::Message

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Stores the LLM response for metrics extraction

Called by the agent after receiving a response from the LLM. The response is used to extract token counts and model information.

Parameters:

  • response (RubyLLM::Message)

    The response from the LLM

Returns:

  • (RubyLLM::Message)

    The same response (for method chaining)



215
216
217
218
# File 'lib/ruby_llm/agents/core/instrumentation.rb', line 215

def capture_response(response)
  @last_response = response
  response
end

#instrument_execution { ... } ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Wraps agent execution with comprehensive metrics tracking

Execution lifecycle:

  1. Creates execution record immediately with ‘running’ status

  2. Yields to the block for actual agent execution

  3. Updates record with final status and metrics

  4. Uses ensure block to guarantee status update even on failures

Yields:

  • The block containing the actual agent execution

Returns:

  • (Object)

    The result from the yielded block

Raises:

  • (Timeout::Error)

    Re-raised after logging timeout status

  • (StandardError)

    Re-raised after logging error status



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/ruby_llm/agents/core/instrumentation.rb', line 137

def instrument_execution(&block)
  started_at = Time.current
  @last_response = nil
  @status_update_completed = false
  raised_exception = nil
  completion_error = nil

  # Create execution record immediately with running status
  execution = create_running_execution(started_at)
  self.execution_id = execution&.id

  begin
    result = yield

    # Update to success
    # NOTE: If this fails, we capture the error but DON'T re-raise
    # The ensure block will handle it via mark_execution_failed!
    begin
      complete_execution(
        execution,
        completed_at: Time.current,
        status: "success",
        response: @last_response
      )
      @status_update_completed = true
    rescue => e
      completion_error = e
      # Don't re-raise - let ensure block handle via mark_execution_failed!
    end

    result
  rescue Timeout::Error => e
    raised_exception = e
    begin
      complete_execution(
        execution,
        completed_at: Time.current,
        status: "timeout",
        error: e
      )
      @status_update_completed = true
    rescue => completion_err
      completion_error = completion_err
    end
    raise
  rescue => e
    raised_exception = e
    begin
      complete_execution(
        execution,
        completed_at: Time.current,
        status: "error",
        error: e
      )
      @status_update_completed = true
    rescue => completion_err
      completion_error = completion_err
    end
    raise
  ensure
    # Emergency fallback: mark as error if complete_execution itself failed
    # This ensures executions never remain stuck in 'running' status
    unless @status_update_completed
      # Prefer completion_error (from update! failure) over raised_exception (from execution)
      # Use $! as final fallback - it holds the current exception being propagated
      actual_error = completion_error || raised_exception || $!
      mark_execution_failed!(execution, error: actual_error)
    end
  end
end

#instrument_execution_with_attempts(models_to_try:) {|AttemptTracker| ... } ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Wraps agent execution with comprehensive metrics tracking (for reliability-enabled agents)

Creates a single execution record and tracks multiple attempts within it. Used by execute_with_reliability for retry/fallback scenarios.

Uses catch/throw pattern because the yielded block uses ‘throw :execution_success` to exit early on success. Regular `return` from within a block would bypass our completion code, so we use throw/catch to properly intercept success cases.

Parameters:

  • models_to_try (Array<String>)

    List of models in the fallback chain

Yields:

  • (AttemptTracker)

    Block receives attempt tracker for recording attempts

Returns:

  • (Object)

    The result from the yielded block

Raises:

  • (Timeout::Error)

    Re-raised after logging timeout status

  • (StandardError)

    Re-raised after logging error status



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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/ruby_llm/agents/core/instrumentation.rb', line 46

def instrument_execution_with_attempts(models_to_try:, &block)
  started_at = Time.current
  @last_response = nil
  @status_update_completed = false
  raised_exception = nil
  completion_error = nil

  attempt_tracker = AttemptTracker.new

  # Create execution record with running status and fallback chain
  execution = create_running_execution(started_at, fallback_chain: models_to_try)
  self.execution_id = execution&.id

  # Use catch to intercept successful early returns from the block
  # The block uses `throw :execution_success, result` instead of `return`
  result = catch(:execution_success) do
    yield(attempt_tracker)
    # If we reach here normally (no throw), the block completed without success
    # This happens when AllModelsExhaustedError is raised
    nil
  rescue Timeout::Error, Reliability::TotalTimeoutError => e
    raised_exception = e
    begin
      complete_execution_with_attempts(
        execution,
        attempt_tracker: attempt_tracker,
        completed_at: Time.current,
        status: "timeout",
        error: e
      )
      @status_update_completed = true
    rescue => completion_err
      completion_error = completion_err
    end
    raise
  rescue => e
    raised_exception = e
    begin
      complete_execution_with_attempts(
        execution,
        attempt_tracker: attempt_tracker,
        completed_at: Time.current,
        status: "error",
        error: e
      )
      @status_update_completed = true
    rescue => completion_err
      completion_error = completion_err
    end
    raise
  ensure
    # Only run emergency fallback if we haven't completed AND we're not in success path
    # The success path completion happens AFTER the catch block
    unless @status_update_completed || !$!
      actual_error = completion_error || raised_exception || $!
      mark_execution_failed!(execution, error: actual_error)
    end
  end

  # If we caught a successful throw, complete the execution properly
  # result will be non-nil if throw :execution_success was called
  if result && !@status_update_completed
    begin
      complete_execution_with_attempts(
        execution,
        attempt_tracker: attempt_tracker,
        completed_at: Time.current,
        status: "success"
      )
      @status_update_completed = true
    rescue => e
      Rails.logger.error("[RubyLLM::Agents] Failed to complete successful execution: #{e.class}: #{e.message}")
      mark_execution_failed!(execution, error: e)
    end
  end

  result
end