payloop 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8afd4c12089fbda44abae722ada80ee75413b18d043aa7c8b5ab23b4c77e15c8
4
- data.tar.gz: 7b9b9bc476434ef3c4b83dde77cde3ec0a506627324b1275decbdce16ba5ee42
3
+ metadata.gz: 79647d261089034fcabaf8bc8f02468c22a4dafac253f0e3b387bf169f0fe410
4
+ data.tar.gz: 5d7796139816c6f880d0acfa0e364065480835def4e1f98fa9fd30004a1cab6b
5
5
  SHA512:
6
- metadata.gz: a07580586b5a649a60c6eb1dd7823de6f33af0243379b11517225db7546b8b87cd8ad3bea690ce626628d3117f78aecc2faf46dbf3e3a51378234d2045409d28
7
- data.tar.gz: ca34c48b13d65ac23d9b65a0217bc66d0b0e7b548c6395c7f3f2e9da805d4d242c3f9590b2f0650639d2cacf74144368f951e74bd1af98a4eb35f3146a0da165
6
+ metadata.gz: e87d2509afeee593b39cd9ab7a519f2fde382aaa939fecaa370cf4817aa38009a5c68a3550444052dbf0867a6162c6a3cd5771cfb039a4f812b280a9e3bb29f6
7
+ data.tar.gz: d7ac74462b724bce7178e6588d41bb6e91e4bf5ec98ff067bd41164cf17b4fd570892eacdb633b797fc3aab1857503cd4cf88998ad95d675be647980fd0f85d0
data/CHANGELOG.md CHANGED
@@ -20,3 +20,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
20
20
  - Streaming response support
21
21
  - Thread-safe configuration
22
22
  - Comprehensive error handling
23
+
24
+ ## [0.0.2] - 2025-10-25
25
+
26
+ ### Fixed
27
+ - Corrected Payloop request payload structure as needed
28
+
29
+ ## [0.0.3] - 2025-10-27
30
+
31
+ ### Fixed
32
+ - Corrected Payloop request payload structure for Google GenAI
data/README.md CHANGED
@@ -27,3 +27,54 @@ Our SDK reference provides documentation for:
27
27
  - Code samples to illustrate our SDK and API
28
28
 
29
29
  Check it out here: [developers.trypayloop.com](https://developers.trypayloop.com)
30
+
31
+ # Releasing a New Version
32
+
33
+ To release a new version of the Payloop Ruby gem (e.g., version 0.0.2):
34
+
35
+ 1. **Update the version number** in [lib/payloop/version.rb](lib/payloop/version.rb):
36
+ ```ruby
37
+ VERSION = "0.0.2"
38
+ ```
39
+
40
+ 2. **Update the CHANGELOG** in [CHANGELOG.md](CHANGELOG.md):
41
+ - Add a new section for the version with today's date
42
+ - Document all changes under appropriate categories (Added, Changed, Fixed, etc.)
43
+ - Follow the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format
44
+
45
+ 3. **Commit your changes**:
46
+ ```bash
47
+ git add lib/payloop/version.rb CHANGELOG.md
48
+ git commit -m "Bump version to 0.0.2"
49
+ ```
50
+
51
+ 4. **Run tests and linting** to ensure everything passes:
52
+ ```bash
53
+ bundle exec rake
54
+ ```
55
+
56
+ 5. **Create a git tag** for the release:
57
+ ```bash
58
+ git tag -a v0.0.2 -m "Release version 0.0.2"
59
+ ```
60
+
61
+ 6. **Push changes and tags** to GitHub:
62
+ ```bash
63
+ git push origin main
64
+ git push origin v0.0.2
65
+ ```
66
+
67
+ 7. **Build and release the gem** to RubyGems:
68
+ ```bash
69
+ bundle exec rake build
70
+ bundle exec rake release
71
+ ```
72
+
73
+ Note: You'll need RubyGems credentials configured. The `rake release` task will:
74
+ - Build the gem
75
+ - Push it to RubyGems.org
76
+ - Create a GitHub release (if configured)
77
+
78
+ 8. **Verify the release**:
79
+ - Check [rubygems.org/gems/payloop](https://rubygems.org/gems/payloop) to confirm the new version is published
80
+ - Test installation: `gem install payloop -v 0.0.2`
@@ -36,12 +36,7 @@ module Payloop
36
36
  end
37
37
 
38
38
  # Set attribution for cost tracking
39
- def attribution(parent_id:, parent_name: nil, subsidiary_id: nil, subsidiary_name: nil,
40
- parent_uuid: nil, subsidiary_uuid: nil)
41
- # Support deprecated parameters
42
- parent_id ||= parent_uuid
43
- subsidiary_id ||= subsidiary_uuid
44
-
39
+ def attribution(parent_id:, parent_name: nil, subsidiary_id: nil, subsidiary_name: nil)
45
40
  attr = Attribution.new(
46
41
  parent_id: parent_id,
47
42
  parent_name: parent_name,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Payloop
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.3"
5
5
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "constants"
4
+
3
5
  module Payloop
4
6
  module Wrappers
5
7
  # Wrapper for Anthropic Ruby client
@@ -64,13 +66,13 @@ module Payloop
64
66
 
65
67
  # Submit analytics
66
68
  payloop_submit_analytics(
67
- provider: "anthropic",
68
69
  method: :create,
69
70
  args: args,
70
71
  kwargs: params,
71
72
  response: response,
72
73
  start_time: start_time,
73
- end_time: Time.now
74
+ end_time: Time.now,
75
+ title: ANTHROPIC_CLIENT_TITLE
74
76
  )
75
77
 
76
78
  response
@@ -78,13 +80,13 @@ module Payloop
78
80
  params = kwargs.any? ? kwargs : (args.first || {})
79
81
 
80
82
  payloop_submit_error_analytics(
81
- provider: "anthropic",
82
83
  method: :create,
83
84
  args: args,
84
85
  kwargs: params,
85
86
  error: e,
86
87
  start_time: start_time,
87
- end_time: Time.now
88
+ end_time: Time.now,
89
+ title: ANTHROPIC_CLIENT_TITLE
88
90
  )
89
91
 
90
92
  raise e
@@ -19,7 +19,6 @@ module Payloop
19
19
 
20
20
  # Submit analytics asynchronously
21
21
  payloop_submit_analytics(
22
- provider: provider_name,
23
22
  method: method_name,
24
23
  args: args,
25
24
  kwargs: kwargs,
@@ -32,7 +31,6 @@ module Payloop
32
31
  rescue StandardError => e
33
32
  # Submit error analytics
34
33
  payloop_submit_error_analytics(
35
- provider: provider_name,
36
34
  method: method_name,
37
35
  args: args,
38
36
  kwargs: kwargs,
@@ -45,39 +43,41 @@ module Payloop
45
43
  end
46
44
  end
47
45
 
48
- def payloop_submit_analytics(provider:, method:, args:, kwargs:, response:, start_time:, end_time:)
46
+ def payloop_submit_analytics(method:, args:, kwargs:, response:, start_time:, end_time:, provider: nil, title: nil)
49
47
  collector = instance_variable_get(:@payloop_collector)
50
48
  config = instance_variable_get(:@payloop_config)
51
49
 
52
50
  return unless collector && config
53
51
 
54
52
  payload = build_payload(
55
- provider: provider,
56
53
  query: extract_query(method, args, kwargs),
57
54
  response: extract_response(response),
58
55
  start_time: start_time,
59
56
  end_time: end_time,
60
57
  config: config,
61
- status: "succeeded"
58
+ status: "succeeded",
59
+ provider: provider,
60
+ title: title
62
61
  )
63
62
 
64
63
  collector.submit_async(payload)
65
64
  end
66
65
 
67
- def payloop_submit_error_analytics(provider:, method:, args:, kwargs:, error:, start_time:, end_time:)
66
+ def payloop_submit_error_analytics(method:, args:, kwargs:, error:, start_time:, end_time:, provider: nil, title: nil)
68
67
  collector = instance_variable_get(:@payloop_collector)
69
68
  config = instance_variable_get(:@payloop_config)
70
69
 
71
70
  return unless collector && config
72
71
 
73
72
  payload = build_payload(
74
- provider: provider,
75
73
  query: extract_query(method, args, kwargs),
76
74
  response: { error: error.message, class: error.class.name },
77
75
  start_time: start_time,
78
76
  end_time: end_time,
79
77
  config: config,
80
78
  status: "failed",
79
+ provider: provider,
80
+ title: title,
81
81
  exception: error.message
82
82
  )
83
83
 
@@ -100,16 +100,49 @@ module Payloop
100
100
  when String
101
101
  { text: response }
102
102
  else
103
- if response.respond_to?(:to_h)
103
+ # Try various serialization methods
104
+ if response.respond_to?(:as_json)
105
+ deep_copy(response.as_json)
106
+ elsif response.respond_to?(:to_h)
104
107
  deep_copy(response.to_h)
105
108
  elsif response.respond_to?(:to_hash)
106
109
  deep_copy(response.to_hash)
107
110
  else
108
- { raw: response.to_s }
111
+ # Extract instance variables for objects without serialization methods
112
+ extract_instance_variables(response)
113
+ end
114
+ end
115
+ rescue StandardError => e
116
+ # If extraction fails, try to provide useful debug info
117
+ { raw: response.to_s, error: e.message }
118
+ end
119
+
120
+ def extract_instance_variables(obj)
121
+ result = {}
122
+ obj.instance_variables.each do |var|
123
+ key = var.to_s.delete("@").to_sym
124
+ value = obj.instance_variable_get(var)
125
+ result[key] = serialize_value(value)
126
+ end
127
+ result
128
+ end
129
+
130
+ def serialize_value(value)
131
+ case value
132
+ when Hash
133
+ value.transform_values { |v| serialize_value(v) }
134
+ when Array
135
+ value.map { |v| serialize_value(v) }
136
+ when String, Numeric, TrueClass, FalseClass, NilClass
137
+ value
138
+ else
139
+ # Recursively extract instance variables for nested objects
140
+ if value.respond_to?(:instance_variables)
141
+ extract_instance_variables(value)
142
+ else
143
+ value.to_s
109
144
  end
110
145
  end
111
- rescue StandardError
112
- { raw: response.to_s }
113
146
  end
114
147
 
115
148
  def deep_copy(obj)
@@ -122,13 +155,13 @@ module Payloop
122
155
  end
123
156
  end
124
157
 
125
- def build_payload(provider:, query:, response:, start_time:, end_time:, config:, status:, exception: nil)
158
+ def build_payload(query:, response:, start_time:, end_time:, config:, status:, provider: nil, title: nil, exception: nil)
126
159
  {
127
160
  attribution: config.attribution&.to_h,
128
161
  conversation: {
129
162
  client: {
130
163
  provider: provider,
131
- title: provider,
164
+ title: title,
132
165
  version: nil
133
166
  },
134
167
  query: query,
@@ -148,8 +181,8 @@ module Payloop
148
181
  }
149
182
  },
150
183
  time: {
151
- start: start_time.iso8601(3),
152
- end: end_time.iso8601(3)
184
+ start: start_time.to_f,
185
+ end: end_time.to_f
153
186
  },
154
187
  tx: {
155
188
  uuid: config.tx_uuid
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Payloop
4
+ module Wrappers
5
+ # Client title constants for analytics
6
+ OPENAI_CLIENT_TITLE = "openai"
7
+ ANTHROPIC_CLIENT_TITLE = "anthropic"
8
+ GOOGLE_CLIENT_TITLE = "google"
9
+ end
10
+ end
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "constants"
4
+
3
5
  module Payloop
4
6
  module Wrappers
5
- # Wrapper for Google GenerativeAI Ruby client
7
+ # Wrapper for Google GenerativeAI Ruby client (google-genai gem)
6
8
  class Google
7
9
  def initialize(config, collector)
8
10
  @config = config
@@ -15,6 +17,9 @@ module Payloop
15
17
  # Prevent double registration
16
18
  return client if client.instance_variable_defined?(:@payloop_registered)
17
19
 
20
+ # Patch response class after client is validated (ensures gem is loaded)
21
+ patch_response_class!
22
+
18
23
  # Store references in client instance
19
24
  client.instance_variable_set(:@payloop_config, @config)
20
25
  client.instance_variable_set(:@payloop_collector, @collector)
@@ -35,6 +40,20 @@ module Payloop
35
40
  "Client does not appear to be a valid Google GenAI client (missing models method)"
36
41
  end
37
42
 
43
+ # Monkey-patch the GenerateContentResponse class to include missing fields
44
+ def patch_response_class!
45
+ # Check if the constant exists and hasn't been patched yet
46
+ return unless defined?(::Google::Genai::Types::GenerateContentResponse)
47
+ return if ::Google::Genai::Types::GenerateContentResponse.instance_variable_defined?(:@_payloop_patched)
48
+
49
+ ::Google::Genai::Types::GenerateContentResponse.class_eval do
50
+ # Use camelCase to match Google's API response keys
51
+ attr_accessor :modelVersion, :usageMetadata, :responseId, :createTime
52
+ end
53
+
54
+ ::Google::Genai::Types::GenerateContentResponse.instance_variable_set(:@_payloop_patched, true)
55
+ end
56
+
38
57
  def wrap_generate_content_method(client)
39
58
  # Get the models resource
40
59
  models_resource = client.models
@@ -65,13 +84,13 @@ module Payloop
65
84
 
66
85
  # Submit analytics
67
86
  payloop_submit_analytics(
68
- provider: "google",
69
87
  method: :generate_content,
70
88
  args: args,
71
89
  kwargs: params,
72
90
  response: response,
73
91
  start_time: start_time,
74
- end_time: Time.now
92
+ end_time: Time.now,
93
+ title: GOOGLE_CLIENT_TITLE
75
94
  )
76
95
 
77
96
  response
@@ -79,13 +98,13 @@ module Payloop
79
98
  params = kwargs.any? ? kwargs : (args.first || {})
80
99
 
81
100
  payloop_submit_error_analytics(
82
- provider: "google",
83
101
  method: :generate_content,
84
102
  args: args,
85
103
  kwargs: params,
86
104
  error: e,
87
105
  start_time: start_time,
88
- end_time: Time.now
106
+ end_time: Time.now,
107
+ title: GOOGLE_CLIENT_TITLE
89
108
  )
90
109
 
91
110
  raise e
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "constants"
4
+
3
5
  module Payloop
4
6
  module Wrappers
5
7
  # Wrapper for OpenAI Ruby client (ruby-openai gem)
@@ -48,25 +50,25 @@ module Payloop
48
50
 
49
51
  # Submit analytics
50
52
  payloop_submit_analytics(
51
- provider: "openai",
52
53
  method: :chat,
53
54
  args: [],
54
- kwargs: { parameters: parameters },
55
+ kwargs: parameters,
55
56
  response: response,
56
57
  start_time: start_time,
57
- end_time: Time.now
58
+ end_time: Time.now,
59
+ title: OPENAI_CLIENT_TITLE
58
60
  )
59
61
 
60
62
  response
61
63
  rescue StandardError => e
62
64
  payloop_submit_error_analytics(
63
- provider: "openai",
64
65
  method: :chat,
65
66
  args: [],
66
- kwargs: { parameters: parameters },
67
+ kwargs: parameters,
67
68
  error: e,
68
69
  start_time: start_time,
69
- end_time: Time.now
70
+ end_time: Time.now,
71
+ title: OPENAI_CLIENT_TITLE
70
72
  )
71
73
 
72
74
  raise e
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: payloop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Payloop
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-14 00:00:00.000000000 Z
11
+ date: 2025-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -47,6 +47,7 @@ files:
47
47
  - lib/payloop/version.rb
48
48
  - lib/payloop/wrappers/anthropic.rb
49
49
  - lib/payloop/wrappers/base.rb
50
+ - lib/payloop/wrappers/constants.rb
50
51
  - lib/payloop/wrappers/google.rb
51
52
  - lib/payloop/wrappers/openai.rb
52
53
  homepage: https://trypayloop.com