Class: PatientLLM::Callback

Inherits:
Object
  • Object
show all
Defined in:
lib/patient_llm/callback.rb

Overview

Callback class that receives async HTTP responses from PatientHttp and dispatches to the user's callback.

When the response contains tool calls and a handler is available for them, this class executes them automatically and re-issues the request until the model returns a final text response or a tool raises HaltError. Tool handlers are resolved from the user callback itself when it implements handles_tool?/invoke_tool (as Agent subclasses do), falling back to the global PromptBuilder tool registry. Iteration is capped at the resolved max_tool_iterations for the request (default MAX_TOOL_ITERATIONS).

The user callback receives a PromptBuilder::Response object. Access the response text via response.text, token usage via response.usage, and model id via response.model.

Constant Summary collapse

MAX_TOOL_ITERATIONS =

Default maximum number of tool-execution rounds before the loop stops and routes a PatientHttp::RequestError (error type :max_tool_iterations) to the user callback's on_error method. Configurable per provider or per request with the max_tool_iterations option.

10
CALLBACK_PARAMS =

Supported keyword parameters for each user callback method, along with the one parameter that must always be declared.

{
  on_complete: {allowed: %i[session provider llm_response callback_args http_response request_id]},
  on_tool_use: {allowed: %i[session provider llm_response callback_args http_response request_id]},
  on_error: {allowed: %i[session provider callback_args error http_response request_id], required: :error}
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.validate_callback_class!(callback_class) ⇒ void

This method returns an undefined value.

Validate that a user callback class declares supported keyword parameters.

Each defined callback method must use keyword parameters drawn from the supported set for that method and must declare the required parameter (error is required for on_error). A **kwargs splat is permitted and receives every available value.

Parameters:

  • callback_class (Class)

    The user callback class

Raises:

  • (ArgumentError)

    If a method uses positional or unsupported parameters



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/patient_llm/callback.rb', line 45

def self.validate_callback_class!(callback_class)
  CALLBACK_PARAMS.each do |method_name, spec|
    next unless callback_class.method_defined?(method_name)

    params = callback_class.instance_method(method_name).parameters
    splat = params.any? { |type, _| type == :keyrest }
    declared = []
    params.each do |type, name|
      case type
      when :key, :keyreq
        declared << name
      when :keyrest, :block
        next
      else
        raise ArgumentError, "#{callback_class}##{method_name} must use keyword parameters; found positional parameter #{name.inspect}"
      end
    end

    allowed = Array(spec[:allowed])
    unknown = declared - allowed
    unless unknown.empty?
      raise ArgumentError, "#{callback_class}##{method_name} has unsupported parameter(s): #{unknown.map(&:inspect).join(", ")}. Allowed: #{allowed.map(&:inspect).join(", ")}"
    end

    required = Array(spec[:required])
    unless splat || required.empty? || (required & declared).any?
      raise ArgumentError, "#{callback_class}##{method_name} must declare the #{required.map(&:inspect).join(", ")} keyword parameter(s)"
    end
  end
end

Instance Method Details

#on_complete(response) ⇒ void

This method returns an undefined value.

Handle a successful LLM completion response.

Parameters:

  • response (PatientHttp::Response)

    The async HTTP response



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/patient_llm/callback.rb', line 80

def on_complete(response)
  callback_args = response.callback_args
  session = restore_session(callback_args)
  provider_name = callback_args[:provider]
  user_callback = resolve_user_callback(callback_args)
  original_request_id = callback_args.fetch(:original_request_id, nil) || response.request_id

  prepare_user_callback(user_callback, session: session, provider: provider_name, callback_args: callback_args, http_response: response, request_id: original_request_id)

  serializer = resolve_serializer(callback_args)
  llm_response = PromptBuilder::Response.parse(response.json, serializer)

  if should_auto_execute_tools?(llm_response, user_callback)
    continue_tool_loop(session, provider_name, llm_response, callback_args, response, user_callback, original_request_id)
  else
    session.add_response(llm_response)
    invoke_user_callback(user_callback, :on_complete, session: session, provider: provider_name, llm_response: llm_response, callback_args: user_callback_args(callback_args), http_response: response, request_id: original_request_id)
  end
end

#on_error(error) ⇒ void

This method returns an undefined value.

Handle an error during an LLM request.

Parameters:

  • error (PatientHttp::Error)

    The error



104
105
106
107
108
109
110
111
112
113
# File 'lib/patient_llm/callback.rb', line 104

def on_error(error)
  callback_args = error.callback_args
  session = restore_session(callback_args)
  provider_name = callback_args[:provider]
  http_response = error.respond_to?(:response) ? error.response : nil
  original_request_id = callback_args.fetch(:original_request_id, nil) || http_response&.request_id
  user_callback = resolve_user_callback(callback_args)
  prepare_user_callback(user_callback, session: session, provider: provider_name, callback_args: callback_args, http_response: http_response, request_id: original_request_id)
  invoke_user_callback(user_callback, :on_error, session: session, provider: provider_name, callback_args: user_callback_args(callback_args), error: error, http_response: http_response, request_id: original_request_id)
end