Module: Payloop::Wrappers::Base
- Defined in:
- lib/payloop/wrappers/base.rb
Overview
Base functionality for all provider wrappers
Instance Method Summary collapse
- #payloop_merge_streaming_chunk(accumulated, chunk) ⇒ Object
- #payloop_normalize_openai_chunk(chunk) ⇒ Object
- #payloop_submit_analytics(method:, args:, kwargs:, response:, start_time:, end_time:, provider: nil, title: nil, version: nil, status: "succeeded", exception: nil) ⇒ Object
-
#payloop_submit_error_analytics(method:, args:, kwargs:, error:, start_time:, end_time:, provider: nil, title: nil, version: nil, response: nil) ⇒ Object
Submit a failed-call payload to the collector.
- #payloop_wrap_method(method_name, _provider_name) ⇒ Object
Instance Method Details
#payloop_merge_streaming_chunk(accumulated, chunk) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/payloop/wrappers/base.rb', line 94 def payloop_merge_streaming_chunk(accumulated, chunk) chunk.each do |key, value| if accumulated.key?(key) case accumulated[key] when Hash payloop_merge_streaming_chunk(accumulated[key], value) if value.is_a?(Hash) when Array # Concatenate arrays (matches Python SDK behavior: data[key].extend(chunk_value)) accumulated[key].concat(value) if value.is_a?(Array) else accumulated[key] = value end else accumulated[key] = value end end accumulated end |
#payloop_normalize_openai_chunk(chunk) ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/payloop/wrappers/base.rb', line 113 def payloop_normalize_openai_chunk(chunk) # Normalize OpenAI streaming chunks to match Python SDK format # Ensure delta objects have all keys present with null values return chunk unless chunk.is_a?(Hash) if chunk["choices"].is_a?(Array) chunk["choices"].each do |choice| next unless choice.is_a?(Hash) && choice.key?("delta") delta = choice["delta"] next unless delta.is_a?(Hash) # Add missing keys with nil values to match Python SDK delta["role"] ||= nil unless delta.key?("role") delta["content"] ||= nil unless delta.key?("content") delta["refusal"] ||= nil unless delta.key?("refusal") delta["tool_calls"] ||= nil unless delta.key?("tool_calls") delta["function_call"] ||= nil unless delta.key?("function_call") end end chunk end |
#payloop_submit_analytics(method:, args:, kwargs:, response:, start_time:, end_time:, provider: nil, title: nil, version: nil, status: "succeeded", exception: nil) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/payloop/wrappers/base.rb', line 46 def payloop_submit_analytics(method:, args:, kwargs:, response:, start_time:, end_time:, provider: nil, title: nil, version: nil, status: "succeeded", exception: nil) collector = instance_variable_get(:@payloop_collector) config = instance_variable_get(:@payloop_config) return unless collector && config payload = build_payload( query: extract_query(method, args, kwargs), response: extract_response(response), start_time: start_time, end_time: end_time, config: config, status: status, provider: provider, title: title, version: version, exception: exception ) collector.submit_async(payload) end |
#payloop_submit_error_analytics(method:, args:, kwargs:, error:, start_time:, end_time:, provider: nil, title: nil, version: nil, response: nil) ⇒ Object
Submit a failed-call payload to the collector. ‘response:` is optional —when omitted, the default `{ error:, class: }` shape is used. Wrappers that preserve richer data on error (e.g. Groq’s streaming wrapper merging accumulated chunks with error info via build_error_response) pass it explicitly; the backend extractor reads whatever fields it can from the supplied hash and falls back gracefully on missing keys.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/payloop/wrappers/base.rb', line 76 def payloop_submit_error_analytics(method:, args:, kwargs:, error:, start_time:, end_time:, provider: nil, title: nil, version: nil, response: nil) payloop_submit_analytics( method: method, args: args, kwargs: kwargs, response: response || { error: error., class: error.class.name }, start_time: start_time, end_time: end_time, provider: provider, title: title, version: version, status: "failed", exception: error. ) end |
#payloop_wrap_method(method_name, _provider_name) ⇒ Object
9 10 11 12 13 14 15 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 |
# File 'lib/payloop/wrappers/base.rb', line 9 def payloop_wrap_method(method_name, _provider_name) return if method(method_name).source_location&.first&.include?("payloop") original_method = instance_method(method_name) define_method(method_name) do |*args, **kwargs, &block| start_time = Time.now # Call original method response = original_method.bind(self).call(*args, **kwargs, &block) # Submit analytics asynchronously payloop_submit_analytics( method: method_name, args: args, kwargs: kwargs, response: response, start_time: start_time, end_time: Time.now ) response rescue StandardError => e # Submit error analytics payloop_submit_error_analytics( method: method_name, args: args, kwargs: kwargs, error: e, start_time: start_time, end_time: Time.now ) raise e end end |