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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +51 -0
- data/lib/payloop/client.rb +1 -6
- data/lib/payloop/version.rb +1 -1
- data/lib/payloop/wrappers/anthropic.rb +6 -4
- data/lib/payloop/wrappers/base.rb +48 -15
- data/lib/payloop/wrappers/constants.rb +10 -0
- data/lib/payloop/wrappers/google.rb +24 -5
- data/lib/payloop/wrappers/openai.rb +8 -6
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 79647d261089034fcabaf8bc8f02468c22a4dafac253f0e3b387bf169f0fe410
|
|
4
|
+
data.tar.gz: 5d7796139816c6f880d0acfa0e364065480835def4e1f98fa9fd30004a1cab6b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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`
|
data/lib/payloop/client.rb
CHANGED
|
@@ -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,
|
data/lib/payloop/version.rb
CHANGED
|
@@ -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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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:
|
|
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.
|
|
152
|
-
end: end_time.
|
|
184
|
+
start: start_time.to_f,
|
|
185
|
+
end: end_time.to_f
|
|
153
186
|
},
|
|
154
187
|
tx: {
|
|
155
188
|
uuid: config.tx_uuid
|
|
@@ -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:
|
|
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:
|
|
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.
|
|
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-
|
|
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
|