paid_ruby 0.1.1 → 0.1.2
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/lib/gemconfig.rb +1 -0
- data/lib/paid_ruby/agents/client.rb +20 -10
- data/lib/paid_ruby/contacts/client.rb +10 -16
- data/lib/paid_ruby/customers/client.rb +4 -4
- data/lib/paid_ruby/orders/client.rb +14 -12
- data/lib/paid_ruby/orders/lines/client.rb +2 -2
- data/lib/paid_ruby/tracing/logging.rb +32 -0
- data/lib/paid_ruby/tracing/tracing.rb +93 -0
- data/lib/paid_ruby/tracing/wrappers/open_ai_wrapper.rb +132 -0
- data/lib/paid_ruby/types/billing_frequency.rb +3 -3
- data/lib/paid_ruby/types/pricing.rb +9 -2
- data/lib/paid_ruby/types/pricing_model_type.rb +1 -0
- data/lib/paid_ruby/types/signal.rb +9 -2
- data/lib/paid_ruby/usage/client.rb +4 -2
- data/lib/paid_ruby.rb +28 -0
- data/lib/requests.rb +2 -2
- metadata +62 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b2054795e06be38ede1daa5465842367cfef452cd91ecc6b1122a66a8942d99
|
4
|
+
data.tar.gz: ba513d072353748c62740300308ce64102e215441123d037891dae820f000231
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0792683c410f927576c39efef7549ce4dc88b2730f681142f4556620af55bd283e391ce501adc85ba453555cafb7a1bbabf11c1e2c45613b74adbff4700d0828'
|
7
|
+
data.tar.gz: 6f6f145c2f60fa277a67bf8ff983de8f0ae5877fd2dcf3519afb8756805e5323d8ee373ddcbdcfaafc511121622b7f978ca5a281c3e13797de5196f71dd89a48
|
data/lib/gemconfig.rb
CHANGED
@@ -60,6 +60,7 @@ end
|
|
60
60
|
# @param description [String]
|
61
61
|
# @param agent_code [String]
|
62
62
|
# @param external_id [String]
|
63
|
+
# @param active [Boolean]
|
63
64
|
# @param request_options [Paid::RequestOptions]
|
64
65
|
# @return [Paid::Agent]
|
65
66
|
# @example
|
@@ -68,8 +69,12 @@ end
|
|
68
69
|
# environment: Paid::Environment::PRODUCTION,
|
69
70
|
# token: "YOUR_AUTH_TOKEN"
|
70
71
|
# )
|
71
|
-
# api.agents.create(
|
72
|
-
|
72
|
+
# api.agents.create(
|
73
|
+
# name: "Acme Agent",
|
74
|
+
# description: "Acme Agent is an AI agent that does things.",
|
75
|
+
# external_id: "acme-agent"
|
76
|
+
# )
|
77
|
+
def create(name:, description:, agent_code: nil, external_id: nil, active: nil, request_options: nil)
|
73
78
|
response = @request_client.conn.post do | req |
|
74
79
|
unless request_options&.timeout_in_seconds.nil?
|
75
80
|
req.options.timeout = request_options.timeout_in_seconds
|
@@ -81,7 +86,7 @@ end
|
|
81
86
|
unless request_options.nil? || request_options&.additional_query_parameters.nil?
|
82
87
|
req.params = { **(request_options&.additional_query_parameters || {}) }.compact
|
83
88
|
end
|
84
|
-
req.body = { **(request_options&.additional_body_parameters || {}), name: name, description: description, agentCode: agent_code, externalId: external_id }.compact
|
89
|
+
req.body = { **(request_options&.additional_body_parameters || {}), name: name, description: description, agentCode: agent_code, externalId: external_id, active: active }.compact
|
85
90
|
req.url "#{@request_client.get_url(request_options: request_options)}/agents"
|
86
91
|
end
|
87
92
|
Paid::Agent.from_json(json_object: response.body)
|
@@ -131,7 +136,7 @@ end
|
|
131
136
|
# environment: Paid::Environment::PRODUCTION,
|
132
137
|
# token: "YOUR_AUTH_TOKEN"
|
133
138
|
# )
|
134
|
-
# api.agents.update(agent_id: "agentId", request: {
|
139
|
+
# api.agents.update(agent_id: "agentId", request: { name: "Acme Agent (Updated)", agent_attributes: [{ name: "Emails sent signal", active: true, pricing: { event_name: "emails_sent", taxable: true, charge_type: USAGE, pricing_model: PER_UNIT, billing_frequency: MONTHLY, price_points: { "USD": { tiers: [{ min_quantity: 0, max_quantity: 10, unit_price: 100 }, { min_quantity: 11, max_quantity: 100, unit_price: 90 }, { min_quantity: 101, unit_price: 80 }] } } } }] })
|
135
140
|
def update(agent_id:, request:, request_options: nil)
|
136
141
|
response = @request_client.conn.put do | req |
|
137
142
|
unless request_options&.timeout_in_seconds.nil?
|
@@ -222,7 +227,7 @@ end
|
|
222
227
|
# environment: Paid::Environment::PRODUCTION,
|
223
228
|
# token: "YOUR_AUTH_TOKEN"
|
224
229
|
# )
|
225
|
-
# api.agents.update_by_external_id(external_id: "externalId", request: {
|
230
|
+
# api.agents.update_by_external_id(external_id: "externalId", request: { name: "Acme Agent (Updated)", agent_attributes: [{ name: "Emails sent signal", active: true, pricing: { event_name: "emails_sent", taxable: true, charge_type: USAGE, pricing_model: PER_UNIT, billing_frequency: MONTHLY, price_points: { "USD": { unit_price: 150 } } } }] })
|
226
231
|
def update_by_external_id(external_id:, request:, request_options: nil)
|
227
232
|
response = @request_client.conn.put do | req |
|
228
233
|
unless request_options&.timeout_in_seconds.nil?
|
@@ -317,6 +322,7 @@ end
|
|
317
322
|
# @param description [String]
|
318
323
|
# @param agent_code [String]
|
319
324
|
# @param external_id [String]
|
325
|
+
# @param active [Boolean]
|
320
326
|
# @param request_options [Paid::RequestOptions]
|
321
327
|
# @return [Paid::Agent]
|
322
328
|
# @example
|
@@ -325,8 +331,12 @@ end
|
|
325
331
|
# environment: Paid::Environment::PRODUCTION,
|
326
332
|
# token: "YOUR_AUTH_TOKEN"
|
327
333
|
# )
|
328
|
-
# api.agents.create(
|
329
|
-
|
334
|
+
# api.agents.create(
|
335
|
+
# name: "Acme Agent",
|
336
|
+
# description: "Acme Agent is an AI agent that does things.",
|
337
|
+
# external_id: "acme-agent"
|
338
|
+
# )
|
339
|
+
def create(name:, description:, agent_code: nil, external_id: nil, active: nil, request_options: nil)
|
330
340
|
Async do
|
331
341
|
response = @request_client.conn.post do | req |
|
332
342
|
unless request_options&.timeout_in_seconds.nil?
|
@@ -339,7 +349,7 @@ end
|
|
339
349
|
unless request_options.nil? || request_options&.additional_query_parameters.nil?
|
340
350
|
req.params = { **(request_options&.additional_query_parameters || {}) }.compact
|
341
351
|
end
|
342
|
-
req.body = { **(request_options&.additional_body_parameters || {}), name: name, description: description, agentCode: agent_code, externalId: external_id }.compact
|
352
|
+
req.body = { **(request_options&.additional_body_parameters || {}), name: name, description: description, agentCode: agent_code, externalId: external_id, active: active }.compact
|
343
353
|
req.url "#{@request_client.get_url(request_options: request_options)}/agents"
|
344
354
|
end
|
345
355
|
Paid::Agent.from_json(json_object: response.body)
|
@@ -392,7 +402,7 @@ end
|
|
392
402
|
# environment: Paid::Environment::PRODUCTION,
|
393
403
|
# token: "YOUR_AUTH_TOKEN"
|
394
404
|
# )
|
395
|
-
# api.agents.update(agent_id: "agentId", request: {
|
405
|
+
# api.agents.update(agent_id: "agentId", request: { name: "Acme Agent (Updated)", agent_attributes: [{ name: "Emails sent signal", active: true, pricing: { event_name: "emails_sent", taxable: true, charge_type: USAGE, pricing_model: PER_UNIT, billing_frequency: MONTHLY, price_points: { "USD": { tiers: [{ min_quantity: 0, max_quantity: 10, unit_price: 100 }, { min_quantity: 11, max_quantity: 100, unit_price: 90 }, { min_quantity: 101, unit_price: 80 }] } } } }] })
|
396
406
|
def update(agent_id:, request:, request_options: nil)
|
397
407
|
Async do
|
398
408
|
response = @request_client.conn.put do | req |
|
@@ -489,7 +499,7 @@ end
|
|
489
499
|
# environment: Paid::Environment::PRODUCTION,
|
490
500
|
# token: "YOUR_AUTH_TOKEN"
|
491
501
|
# )
|
492
|
-
# api.agents.update_by_external_id(external_id: "externalId", request: {
|
502
|
+
# api.agents.update_by_external_id(external_id: "externalId", request: { name: "Acme Agent (Updated)", agent_attributes: [{ name: "Emails sent signal", active: true, pricing: { event_name: "emails_sent", taxable: true, charge_type: USAGE, pricing_model: PER_UNIT, billing_frequency: MONTHLY, price_points: { "USD": { unit_price: 150 } } } }] })
|
493
503
|
def update_by_external_id(external_id:, request:, request_options: nil)
|
494
504
|
Async do
|
495
505
|
response = @request_client.conn.put do | req |
|
@@ -76,16 +76,13 @@ end
|
|
76
76
|
# token: "YOUR_AUTH_TOKEN"
|
77
77
|
# )
|
78
78
|
# api.contacts.create(
|
79
|
+
# customer_external_id: "acme-inc",
|
79
80
|
# salutation: MR,
|
80
|
-
# first_name: "
|
81
|
-
# last_name: "
|
82
|
-
# email: "
|
83
|
-
# billing_street: "billingStreet",
|
84
|
-
# billing_city: "billingCity",
|
85
|
-
# billing_country: "billingCountry",
|
86
|
-
# billing_postal_code: "billingPostalCode"
|
81
|
+
# first_name: "John",
|
82
|
+
# last_name: "Doe",
|
83
|
+
# email: "john.doe@example.com"
|
87
84
|
# )
|
88
|
-
def create(external_id: nil, customer_id: nil, customer_external_id: nil, salutation:, first_name:, last_name:, email:, phone: nil, billing_street
|
85
|
+
def create(external_id: nil, customer_id: nil, customer_external_id: nil, salutation:, first_name:, last_name:, email:, phone: nil, billing_street: nil, billing_city: nil, billing_state_province: nil, billing_country: nil, billing_postal_code: nil, request_options: nil)
|
89
86
|
response = @request_client.conn.post do | req |
|
90
87
|
unless request_options&.timeout_in_seconds.nil?
|
91
88
|
req.options.timeout = request_options.timeout_in_seconds
|
@@ -283,16 +280,13 @@ end
|
|
283
280
|
# token: "YOUR_AUTH_TOKEN"
|
284
281
|
# )
|
285
282
|
# api.contacts.create(
|
283
|
+
# customer_external_id: "acme-inc",
|
286
284
|
# salutation: MR,
|
287
|
-
# first_name: "
|
288
|
-
# last_name: "
|
289
|
-
# email: "
|
290
|
-
# billing_street: "billingStreet",
|
291
|
-
# billing_city: "billingCity",
|
292
|
-
# billing_country: "billingCountry",
|
293
|
-
# billing_postal_code: "billingPostalCode"
|
285
|
+
# first_name: "John",
|
286
|
+
# last_name: "Doe",
|
287
|
+
# email: "john.doe@example.com"
|
294
288
|
# )
|
295
|
-
def create(external_id: nil, customer_id: nil, customer_external_id: nil, salutation:, first_name:, last_name:, email:, phone: nil, billing_street
|
289
|
+
def create(external_id: nil, customer_id: nil, customer_external_id: nil, salutation:, first_name:, last_name:, email:, phone: nil, billing_street: nil, billing_city: nil, billing_state_province: nil, billing_country: nil, billing_postal_code: nil, request_options: nil)
|
296
290
|
Async do
|
297
291
|
response = @request_client.conn.post do | req |
|
298
292
|
unless request_options&.timeout_in_seconds.nil?
|
@@ -82,7 +82,7 @@ end
|
|
82
82
|
# environment: Paid::Environment::PRODUCTION,
|
83
83
|
# token: "YOUR_AUTH_TOKEN"
|
84
84
|
# )
|
85
|
-
# api.customers.create(name: "
|
85
|
+
# api.customers.create(name: "Acme, Inc.", external_id: "acme-inc")
|
86
86
|
def create(name:, external_id: nil, phone: nil, employee_count: nil, annual_revenue: nil, tax_exempt_status: nil, creation_source: nil, website: nil, billing_address: nil, request_options: nil)
|
87
87
|
response = @request_client.conn.post do | req |
|
88
88
|
unless request_options&.timeout_in_seconds.nil?
|
@@ -154,7 +154,7 @@ end
|
|
154
154
|
# environment: Paid::Environment::PRODUCTION,
|
155
155
|
# token: "YOUR_AUTH_TOKEN"
|
156
156
|
# )
|
157
|
-
# api.customers.update(customer_id: "customerId", request: {
|
157
|
+
# api.customers.update(customer_id: "customerId", request: { name: "Acme, Inc. (Updated)", phone: "123-456-7890", employee_count: 101, annual_revenue: 1000001 })
|
158
158
|
def update(customer_id:, request:, request_options: nil)
|
159
159
|
response = @request_client.conn.put do | req |
|
160
160
|
unless request_options&.timeout_in_seconds.nil?
|
@@ -368,7 +368,7 @@ end
|
|
368
368
|
# environment: Paid::Environment::PRODUCTION,
|
369
369
|
# token: "YOUR_AUTH_TOKEN"
|
370
370
|
# )
|
371
|
-
# api.customers.create(name: "
|
371
|
+
# api.customers.create(name: "Acme, Inc.", external_id: "acme-inc")
|
372
372
|
def create(name:, external_id: nil, phone: nil, employee_count: nil, annual_revenue: nil, tax_exempt_status: nil, creation_source: nil, website: nil, billing_address: nil, request_options: nil)
|
373
373
|
Async do
|
374
374
|
response = @request_client.conn.post do | req |
|
@@ -444,7 +444,7 @@ end
|
|
444
444
|
# environment: Paid::Environment::PRODUCTION,
|
445
445
|
# token: "YOUR_AUTH_TOKEN"
|
446
446
|
# )
|
447
|
-
# api.customers.update(customer_id: "customerId", request: {
|
447
|
+
# api.customers.update(customer_id: "customerId", request: { name: "Acme, Inc. (Updated)", phone: "123-456-7890", employee_count: 101, annual_revenue: 1000001 })
|
448
448
|
def update(customer_id:, request:, request_options: nil)
|
449
449
|
Async do
|
450
450
|
response = @request_client.conn.put do | req |
|
@@ -79,13 +79,14 @@ end
|
|
79
79
|
# token: "YOUR_AUTH_TOKEN"
|
80
80
|
# )
|
81
81
|
# api.orders.create(
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
# start_date: "
|
86
|
-
#
|
82
|
+
# customer_external_id: "acme-inc",
|
83
|
+
# name: "Acme Order",
|
84
|
+
# description: "Acme Order is an order for Acme, Inc.",
|
85
|
+
# start_date: "2025-01-01",
|
86
|
+
# end_date: "2026-01-01",
|
87
|
+
# currency: "USD"
|
87
88
|
# )
|
88
|
-
def create(customer_id
|
89
|
+
def create(customer_id: nil, customer_external_id: nil, billing_contact_id: nil, name:, description: nil, start_date:, end_date: nil, currency:, order_lines: nil, request_options: nil)
|
89
90
|
response = @request_client.conn.post do | req |
|
90
91
|
unless request_options&.timeout_in_seconds.nil?
|
91
92
|
req.options.timeout = request_options.timeout_in_seconds
|
@@ -258,13 +259,14 @@ end
|
|
258
259
|
# token: "YOUR_AUTH_TOKEN"
|
259
260
|
# )
|
260
261
|
# api.orders.create(
|
261
|
-
#
|
262
|
-
#
|
263
|
-
#
|
264
|
-
# start_date: "
|
265
|
-
#
|
262
|
+
# customer_external_id: "acme-inc",
|
263
|
+
# name: "Acme Order",
|
264
|
+
# description: "Acme Order is an order for Acme, Inc.",
|
265
|
+
# start_date: "2025-01-01",
|
266
|
+
# end_date: "2026-01-01",
|
267
|
+
# currency: "USD"
|
266
268
|
# )
|
267
|
-
def create(customer_id
|
269
|
+
def create(customer_id: nil, customer_external_id: nil, billing_contact_id: nil, name:, description: nil, start_date:, end_date: nil, currency:, order_lines: nil, request_options: nil)
|
268
270
|
Async do
|
269
271
|
response = @request_client.conn.post do | req |
|
270
272
|
unless request_options&.timeout_in_seconds.nil?
|
@@ -31,7 +31,7 @@ module Paid
|
|
31
31
|
# environment: Paid::Environment::PRODUCTION,
|
32
32
|
# token: "YOUR_AUTH_TOKEN"
|
33
33
|
# )
|
34
|
-
# api.orders.lines.update(order_id: "orderId")
|
34
|
+
# api.orders.lines.update(order_id: "orderId", lines: [{ agent_external_id: "acme-agent", name: "Order Line One", description: "Order Line One is an order line for Acme, Inc." }, { agent_external_id: "acme-agent-2", name: "Order Line Two", description: "Order Line Two is an order line for Acme, Inc." }])
|
35
35
|
def update(order_id:, lines: nil, request_options: nil)
|
36
36
|
response = @request_client.conn.put do | req |
|
37
37
|
unless request_options&.timeout_in_seconds.nil?
|
@@ -74,7 +74,7 @@ end
|
|
74
74
|
# environment: Paid::Environment::PRODUCTION,
|
75
75
|
# token: "YOUR_AUTH_TOKEN"
|
76
76
|
# )
|
77
|
-
# api.orders.lines.update(order_id: "orderId")
|
77
|
+
# api.orders.lines.update(order_id: "orderId", lines: [{ agent_external_id: "acme-agent", name: "Order Line One", description: "Order Line One is an order line for Acme, Inc." }, { agent_external_id: "acme-agent-2", name: "Order Line Two", description: "Order Line Two is an order line for Acme, Inc." }])
|
78
78
|
def update(order_id:, lines: nil, request_options: nil)
|
79
79
|
Async do
|
80
80
|
response = @request_client.conn.put do | req |
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
module Paid
|
6
|
+
module Tracing
|
7
|
+
# Provides a central logger for the gem.
|
8
|
+
# The log level can be configured via the PAID_LOG_LEVEL environment variable.
|
9
|
+
# Supported levels are DEBUG, INFO, WARN, ERROR, FATAL.
|
10
|
+
# If the variable is not set, the level defaults to FATAL to suppress output.
|
11
|
+
module Logging
|
12
|
+
def self.logger
|
13
|
+
@logger ||= begin
|
14
|
+
log_level_str = ENV["PAID_LOG_LEVEL"]&.upcase
|
15
|
+
level = if log_level_str && Logger.const_defined?(log_level_str)
|
16
|
+
Logger.const_get(log_level_str)
|
17
|
+
else
|
18
|
+
# Default to a level that shows no logs unless explicitly configured.
|
19
|
+
Logger::FATAL
|
20
|
+
end
|
21
|
+
|
22
|
+
logger = Logger.new($stdout)
|
23
|
+
logger.level = level
|
24
|
+
logger.formatter = proc do |severity, _datetime, _progname, msg|
|
25
|
+
"[Paid SDK] #{severity}: #{msg}\n"
|
26
|
+
end
|
27
|
+
logger
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "opentelemetry/sdk"
|
4
|
+
require "opentelemetry/exporter/otlp"
|
5
|
+
require_relative "logging"
|
6
|
+
|
7
|
+
module Paid
|
8
|
+
module Tracing
|
9
|
+
@token = nil
|
10
|
+
|
11
|
+
# Context keys to propagate external_customer_id and token to child spans.
|
12
|
+
# These are just keys, not the values themselves.
|
13
|
+
PAID_EXTERNAL_CUSTOMER_ID_KEY = OpenTelemetry::Context.create_key("paid.external_customer_id")
|
14
|
+
PAID_TOKEN_KEY = OpenTelemetry::Context.create_key("paid.token")
|
15
|
+
|
16
|
+
# @param api_key [String]
|
17
|
+
def self.initialize_tracing(api_key:)
|
18
|
+
endpoint = "https://collector.agentpaid.io:4318/v1/traces"
|
19
|
+
# endpoint = "http://localhost:4318/v1/traces"
|
20
|
+
|
21
|
+
@token = api_key
|
22
|
+
|
23
|
+
exporter = OpenTelemetry::Exporter::OTLP::Exporter.new(
|
24
|
+
endpoint: endpoint,
|
25
|
+
headers: {}
|
26
|
+
)
|
27
|
+
span_processor = OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(exporter)
|
28
|
+
|
29
|
+
OpenTelemetry::SDK.configure do |c|
|
30
|
+
c.add_span_processor(span_processor)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Add an at_exit hook to ensure spans are flushed before the script exits.
|
34
|
+
at_exit do
|
35
|
+
OpenTelemetry.tracer_provider.shutdown
|
36
|
+
end
|
37
|
+
|
38
|
+
Logging.logger.info("Paid tracing initialized successfully")
|
39
|
+
rescue StandardError => e
|
40
|
+
Logging.logger.error("Failed to initialize Paid tracing: #{e.message}")
|
41
|
+
raise
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.token
|
45
|
+
@token
|
46
|
+
end
|
47
|
+
|
48
|
+
# Getter for the OpenAI wrapper to retrieve the external_customer_id from the context.
|
49
|
+
def self.get_external_customer_id_from_context
|
50
|
+
OpenTelemetry::Context.current.value(PAID_EXTERNAL_CUSTOMER_ID_KEY)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Getter for the OpenAI wrapper to retrieve the token from the context.
|
54
|
+
def self.get_token_from_context
|
55
|
+
OpenTelemetry::Context.current.value(PAID_TOKEN_KEY)
|
56
|
+
end
|
57
|
+
|
58
|
+
# @param external_customer_id [String]
|
59
|
+
# @param args [Array]
|
60
|
+
# @param block [Proc]
|
61
|
+
def self.capture(*args, external_customer_id:, &block)
|
62
|
+
token = self.token
|
63
|
+
unless token
|
64
|
+
Logging.logger.warn("No token found - tracing is not initialized and will not be captured")
|
65
|
+
return yield(*args) if block_given?
|
66
|
+
end
|
67
|
+
|
68
|
+
new_context_values = {
|
69
|
+
PAID_EXTERNAL_CUSTOMER_ID_KEY => external_customer_id,
|
70
|
+
PAID_TOKEN_KEY => token
|
71
|
+
}
|
72
|
+
|
73
|
+
# Execute the block within a new context containing our values.
|
74
|
+
OpenTelemetry::Context.with_values(new_context_values) do
|
75
|
+
tracer = OpenTelemetry.tracer_provider.tracer("paid.ruby")
|
76
|
+
|
77
|
+
tracer.in_span("paid.ruby:#{external_customer_id}") do |span|
|
78
|
+
span.set_attribute("external_customer_id", external_customer_id)
|
79
|
+
span.set_attribute("token", token)
|
80
|
+
|
81
|
+
begin
|
82
|
+
result = yield(*args) if block_given?
|
83
|
+
span.status = OpenTelemetry::Trace::Status.ok("Success")
|
84
|
+
result
|
85
|
+
rescue StandardError => e
|
86
|
+
span.status = OpenTelemetry::Trace::Status.error("Error: #{e.message}")
|
87
|
+
raise e
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "openai"
|
4
|
+
require_relative "../tracing"
|
5
|
+
|
6
|
+
module Paid
|
7
|
+
module Tracing
|
8
|
+
module Wrappers
|
9
|
+
# A wrapper around the OpenAI::Client that provides automatic tracing for API calls.
|
10
|
+
class PaidOpenAI
|
11
|
+
def initialize(openai_client:)
|
12
|
+
@openai_client = openai_client
|
13
|
+
@tracer = OpenTelemetry.tracer_provider.tracer("paid.ruby")
|
14
|
+
end
|
15
|
+
|
16
|
+
# Wraps the OpenAI#chat method to create a child span.
|
17
|
+
def chat(parameters:)
|
18
|
+
wrap_call(operation: "chat", model: parameters[:model]) do
|
19
|
+
@openai_client.chat(parameters: parameters)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Wraps the OpenAI#embeddings method to create a child span.
|
24
|
+
def embeddings(parameters:)
|
25
|
+
wrap_call(operation: "embeddings", model: parameters[:model]) do
|
26
|
+
@openai_client.embeddings(parameters: parameters)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns a wrapper for the images API.
|
31
|
+
def images
|
32
|
+
ImagesWrapper.new(openai_client: @openai_client, tracer: @tracer)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# A private wrapper for the OpenAI Images API.
|
38
|
+
class ImagesWrapper
|
39
|
+
def initialize(openai_client:, tracer:)
|
40
|
+
@openai_client = openai_client
|
41
|
+
@tracer = tracer
|
42
|
+
end
|
43
|
+
|
44
|
+
def generate(parameters:)
|
45
|
+
current_span = OpenTelemetry::Trace.current_span
|
46
|
+
unless current_span.context.valid?
|
47
|
+
Paid::Tracing::Logging.logger.warn("No active span found, calling OpenAI directly without tracing.")
|
48
|
+
return @openai_client.images.generate(parameters: parameters)
|
49
|
+
end
|
50
|
+
|
51
|
+
external_customer_id = Paid::Tracing.get_external_customer_id_from_context
|
52
|
+
token = Paid::Tracing.get_token_from_context
|
53
|
+
model = parameters[:model] || "dall-e-3"
|
54
|
+
span_name = "trace.images #{model}"
|
55
|
+
|
56
|
+
@tracer.in_span(span_name) do |span|
|
57
|
+
attributes = {
|
58
|
+
"gen_ai.request.model" => model,
|
59
|
+
"gen_ai.system" => "openai",
|
60
|
+
"gen_ai.operation.name" => "image_generation"
|
61
|
+
}
|
62
|
+
attributes["external_customer_id"] = external_customer_id if external_customer_id
|
63
|
+
attributes["token"] = token if token
|
64
|
+
span.add_attributes(attributes)
|
65
|
+
|
66
|
+
begin
|
67
|
+
response = @openai_client.images.generate(parameters: parameters)
|
68
|
+
span.add_attributes({
|
69
|
+
"gen_ai.image.count" => parameters[:n] || 1,
|
70
|
+
"gen_ai.image.size" => parameters[:size] || "1024x1024",
|
71
|
+
"gen_ai.image.quality" => parameters[:quality] || "standard"
|
72
|
+
})
|
73
|
+
span.status = OpenTelemetry::Trace::Status.ok("Success")
|
74
|
+
response
|
75
|
+
rescue StandardError => e
|
76
|
+
span.record_exception(e)
|
77
|
+
span.status = OpenTelemetry::Trace::Status.error("Error: #{e.message}")
|
78
|
+
raise e
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def wrap_call(operation:, model:, &block)
|
85
|
+
current_span = OpenTelemetry::Trace.current_span
|
86
|
+
unless current_span.context.valid?
|
87
|
+
Paid::Tracing::Logging.logger.warn("No active span found, calling OpenAI directly without tracing.")
|
88
|
+
return yield
|
89
|
+
end
|
90
|
+
|
91
|
+
external_customer_id = Paid::Tracing.get_external_customer_id_from_context
|
92
|
+
token = Paid::Tracing.get_token_from_context
|
93
|
+
model_name = model || "unknown"
|
94
|
+
span_name = "trace.#{operation} #{model_name}"
|
95
|
+
|
96
|
+
@tracer.in_span(span_name) do |span|
|
97
|
+
attributes = {
|
98
|
+
"gen_ai.system" => "openai",
|
99
|
+
"gen_ai.operation.name" => operation
|
100
|
+
}
|
101
|
+
attributes["external_customer_id"] = external_customer_id if external_customer_id
|
102
|
+
attributes["token"] = token if token
|
103
|
+
span.add_attributes(attributes)
|
104
|
+
|
105
|
+
begin
|
106
|
+
response = yield
|
107
|
+
add_response_attributes(span, response)
|
108
|
+
span.status = OpenTelemetry::Trace::Status.ok("Success")
|
109
|
+
response
|
110
|
+
rescue StandardError => e
|
111
|
+
span.record_exception(e)
|
112
|
+
span.status = OpenTelemetry::Trace::Status.error("Error: #{e.message}")
|
113
|
+
raise e
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_response_attributes(span, response)
|
119
|
+
return unless response.is_a?(Hash) && response.dig("usage")
|
120
|
+
|
121
|
+
attributes = {
|
122
|
+
"gen_ai.usage.input_tokens" => response.dig("usage", "prompt_tokens"),
|
123
|
+
"gen_ai.usage.output_tokens" => response.dig("usage", "completion_tokens"),
|
124
|
+
"gen_ai.response.model" => response.dig("model")
|
125
|
+
}.compact
|
126
|
+
|
127
|
+
span.add_attributes(attributes)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -11,6 +11,8 @@ module Paid
|
|
11
11
|
attr_reader :event_name
|
12
12
|
# @return [Boolean]
|
13
13
|
attr_reader :taxable
|
14
|
+
# @return [Float]
|
15
|
+
attr_reader :credit_cost
|
14
16
|
# @return [Paid::ChargeType]
|
15
17
|
attr_reader :charge_type
|
16
18
|
# @return [Paid::PricingModelType]
|
@@ -29,21 +31,23 @@ module Paid
|
|
29
31
|
|
30
32
|
# @param event_name [String]
|
31
33
|
# @param taxable [Boolean]
|
34
|
+
# @param credit_cost [Float]
|
32
35
|
# @param charge_type [Paid::ChargeType]
|
33
36
|
# @param pricing_model [Paid::PricingModelType]
|
34
37
|
# @param billing_frequency [Paid::BillingFrequency]
|
35
38
|
# @param price_points [Hash{String => Paid::AgentPricePoint}]
|
36
39
|
# @param additional_properties [OpenStruct] Additional properties unmapped to the current class definition
|
37
40
|
# @return [Paid::Pricing]
|
38
|
-
def initialize(event_name: OMIT, taxable:, charge_type:, pricing_model:, billing_frequency:, price_points:, additional_properties: nil)
|
41
|
+
def initialize(event_name: OMIT, taxable:, credit_cost: OMIT, charge_type:, pricing_model:, billing_frequency:, price_points:, additional_properties: nil)
|
39
42
|
@event_name = event_name if event_name != OMIT
|
40
43
|
@taxable = taxable
|
44
|
+
@credit_cost = credit_cost if credit_cost != OMIT
|
41
45
|
@charge_type = charge_type
|
42
46
|
@pricing_model = pricing_model
|
43
47
|
@billing_frequency = billing_frequency
|
44
48
|
@price_points = price_points
|
45
49
|
@additional_properties = additional_properties
|
46
|
-
@_field_set = { "eventName": event_name, "taxable": taxable, "chargeType": charge_type, "pricingModel": pricing_model, "billingFrequency": billing_frequency, "pricePoints": price_points }.reject do | _k, v |
|
50
|
+
@_field_set = { "eventName": event_name, "taxable": taxable, "creditCost": credit_cost, "chargeType": charge_type, "pricingModel": pricing_model, "billingFrequency": billing_frequency, "pricePoints": price_points }.reject do | _k, v |
|
47
51
|
v == OMIT
|
48
52
|
end
|
49
53
|
end
|
@@ -56,6 +60,7 @@ end
|
|
56
60
|
parsed_json = JSON.parse(json_object)
|
57
61
|
event_name = parsed_json["eventName"]
|
58
62
|
taxable = parsed_json["taxable"]
|
63
|
+
credit_cost = parsed_json["creditCost"]
|
59
64
|
charge_type = parsed_json["chargeType"]
|
60
65
|
pricing_model = parsed_json["pricingModel"]
|
61
66
|
billing_frequency = parsed_json["billingFrequency"]
|
@@ -66,6 +71,7 @@ end
|
|
66
71
|
new(
|
67
72
|
event_name: event_name,
|
68
73
|
taxable: taxable,
|
74
|
+
credit_cost: credit_cost,
|
69
75
|
charge_type: charge_type,
|
70
76
|
pricing_model: pricing_model,
|
71
77
|
billing_frequency: billing_frequency,
|
@@ -88,6 +94,7 @@ end
|
|
88
94
|
def self.validate_raw(obj:)
|
89
95
|
obj.event_name&.is_a?(String) != false || raise("Passed value for field obj.event_name is not the expected type, validation failed.")
|
90
96
|
obj.taxable.is_a?(Boolean) != false || raise("Passed value for field obj.taxable is not the expected type, validation failed.")
|
97
|
+
obj.credit_cost&.is_a?(Float) != false || raise("Passed value for field obj.credit_cost is not the expected type, validation failed.")
|
91
98
|
obj.charge_type.is_a?(Paid::ChargeType) != false || raise("Passed value for field obj.charge_type is not the expected type, validation failed.")
|
92
99
|
obj.pricing_model.is_a?(Paid::PricingModelType) != false || raise("Passed value for field obj.pricing_model is not the expected type, validation failed.")
|
93
100
|
obj.billing_frequency.is_a?(Paid::BillingFrequency) != false || raise("Passed value for field obj.billing_frequency is not the expected type, validation failed.")
|
@@ -8,6 +8,8 @@ module Paid
|
|
8
8
|
attr_reader :event_name
|
9
9
|
# @return [String]
|
10
10
|
attr_reader :agent_id
|
11
|
+
# @return [String]
|
12
|
+
attr_reader :external_agent_id
|
11
13
|
# @return [String]
|
12
14
|
attr_reader :customer_id
|
13
15
|
# @return [Hash{String => Object}]
|
@@ -22,17 +24,19 @@ module Paid
|
|
22
24
|
|
23
25
|
# @param event_name [String]
|
24
26
|
# @param agent_id [String]
|
27
|
+
# @param external_agent_id [String]
|
25
28
|
# @param customer_id [String]
|
26
29
|
# @param data [Hash{String => Object}]
|
27
30
|
# @param additional_properties [OpenStruct] Additional properties unmapped to the current class definition
|
28
31
|
# @return [Paid::Signal]
|
29
|
-
def initialize(event_name: OMIT, agent_id: OMIT, customer_id: OMIT, data: OMIT, additional_properties: nil)
|
32
|
+
def initialize(event_name: OMIT, agent_id: OMIT, external_agent_id: OMIT, customer_id: OMIT, data: OMIT, additional_properties: nil)
|
30
33
|
@event_name = event_name if event_name != OMIT
|
31
34
|
@agent_id = agent_id if agent_id != OMIT
|
35
|
+
@external_agent_id = external_agent_id if external_agent_id != OMIT
|
32
36
|
@customer_id = customer_id if customer_id != OMIT
|
33
37
|
@data = data if data != OMIT
|
34
38
|
@additional_properties = additional_properties
|
35
|
-
@_field_set = { "event_name": event_name, "agent_id": agent_id, "customer_id": customer_id, "data": data }.reject do | _k, v |
|
39
|
+
@_field_set = { "event_name": event_name, "agent_id": agent_id, "external_agent_id": external_agent_id, "customer_id": customer_id, "data": data }.reject do | _k, v |
|
36
40
|
v == OMIT
|
37
41
|
end
|
38
42
|
end
|
@@ -45,11 +49,13 @@ end
|
|
45
49
|
parsed_json = JSON.parse(json_object)
|
46
50
|
event_name = parsed_json["event_name"]
|
47
51
|
agent_id = parsed_json["agent_id"]
|
52
|
+
external_agent_id = parsed_json["external_agent_id"]
|
48
53
|
customer_id = parsed_json["customer_id"]
|
49
54
|
data = parsed_json["data"]
|
50
55
|
new(
|
51
56
|
event_name: event_name,
|
52
57
|
agent_id: agent_id,
|
58
|
+
external_agent_id: external_agent_id,
|
53
59
|
customer_id: customer_id,
|
54
60
|
data: data,
|
55
61
|
additional_properties: struct
|
@@ -70,6 +76,7 @@ end
|
|
70
76
|
def self.validate_raw(obj:)
|
71
77
|
obj.event_name&.is_a?(String) != false || raise("Passed value for field obj.event_name is not the expected type, validation failed.")
|
72
78
|
obj.agent_id&.is_a?(String) != false || raise("Passed value for field obj.agent_id is not the expected type, validation failed.")
|
79
|
+
obj.external_agent_id&.is_a?(String) != false || raise("Passed value for field obj.external_agent_id is not the expected type, validation failed.")
|
73
80
|
obj.customer_id&.is_a?(String) != false || raise("Passed value for field obj.customer_id is not the expected type, validation failed.")
|
74
81
|
obj.data&.is_a?(Hash) != false || raise("Passed value for field obj.data is not the expected type, validation failed.")
|
75
82
|
end
|
@@ -19,6 +19,7 @@ module Paid
|
|
19
19
|
# @param signals [Array<Hash>] Request of type Array<Paid::Signal>, as a Hash
|
20
20
|
# * :event_name (String)
|
21
21
|
# * :agent_id (String)
|
22
|
+
# * :external_agent_id (String)
|
22
23
|
# * :customer_id (String)
|
23
24
|
# * :data (Hash{String => Object})
|
24
25
|
# @param request_options [Paid::RequestOptions]
|
@@ -29,7 +30,7 @@ module Paid
|
|
29
30
|
# environment: Paid::Environment::PRODUCTION,
|
30
31
|
# token: "YOUR_AUTH_TOKEN"
|
31
32
|
# )
|
32
|
-
# api.usage.record_bulk
|
33
|
+
# api.usage.record_bulk(signals: [{ }, { }, { }])
|
33
34
|
def record_bulk(signals: nil, request_options: nil)
|
34
35
|
response = @request_client.conn.post do | req |
|
35
36
|
unless request_options&.timeout_in_seconds.nil?
|
@@ -62,6 +63,7 @@ end
|
|
62
63
|
# @param signals [Array<Hash>] Request of type Array<Paid::Signal>, as a Hash
|
63
64
|
# * :event_name (String)
|
64
65
|
# * :agent_id (String)
|
66
|
+
# * :external_agent_id (String)
|
65
67
|
# * :customer_id (String)
|
66
68
|
# * :data (Hash{String => Object})
|
67
69
|
# @param request_options [Paid::RequestOptions]
|
@@ -72,7 +74,7 @@ end
|
|
72
74
|
# environment: Paid::Environment::PRODUCTION,
|
73
75
|
# token: "YOUR_AUTH_TOKEN"
|
74
76
|
# )
|
75
|
-
# api.usage.record_bulk
|
77
|
+
# api.usage.record_bulk(signals: [{ }, { }, { }])
|
76
78
|
def record_bulk(signals: nil, request_options: nil)
|
77
79
|
Async do
|
78
80
|
response = @request_client.conn.post do | req |
|
data/lib/paid_ruby.rb
CHANGED
@@ -9,6 +9,8 @@ require_relative "paid_ruby/contacts/client"
|
|
9
9
|
require_relative "paid_ruby/orders/client"
|
10
10
|
require_relative "paid_ruby/usage/client"
|
11
11
|
require_relative "extensions/batch"
|
12
|
+
require_relative "paid_ruby/tracing/tracing"
|
13
|
+
require_relative "paid_ruby/tracing/wrappers/open_ai_wrapper"
|
12
14
|
|
13
15
|
module Paid
|
14
16
|
class Client
|
@@ -44,6 +46,19 @@ module Paid
|
|
44
46
|
@orders = Paid::OrdersClient.new(request_client: @request_client)
|
45
47
|
@usage = Paid::BatchUsageClient.new(request_client: @request_client)
|
46
48
|
end
|
49
|
+
|
50
|
+
def initialize_tracing
|
51
|
+
token = @request_client.token
|
52
|
+
api_key = token.gsub(/^Bearer /, "")
|
53
|
+
Paid::Tracing.initialize_tracing(api_key: api_key)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param external_customer_id [String]
|
57
|
+
# @param args [Array]
|
58
|
+
# @param block [Proc]
|
59
|
+
def capture(*args, external_customer_id:, &block)
|
60
|
+
Paid::Tracing.capture(*args, external_customer_id: external_customer_id, &block)
|
61
|
+
end
|
47
62
|
end
|
48
63
|
|
49
64
|
class AsyncClient
|
@@ -79,5 +94,18 @@ module Paid
|
|
79
94
|
@orders = Paid::AsyncOrdersClient.new(request_client: @async_request_client)
|
80
95
|
@usage = Paid::AsyncBatchUsageClient.new(request_client: @async_request_client)
|
81
96
|
end
|
97
|
+
|
98
|
+
def initialize_tracing
|
99
|
+
token = @async_request_client.token
|
100
|
+
api_key = token.gsub(/^Bearer /, "")
|
101
|
+
Paid::Tracing.initialize_tracing(api_key: api_key)
|
102
|
+
end
|
103
|
+
|
104
|
+
# @param external_customer_id [String]
|
105
|
+
# @param args [Array]
|
106
|
+
# @param block [Proc]
|
107
|
+
def capture(*args, external_customer_id:, &block)
|
108
|
+
Paid::Tracing.capture(*args, external_customer_id: external_customer_id, &block)
|
109
|
+
end
|
82
110
|
end
|
83
111
|
end
|
data/lib/requests.rb
CHANGED
@@ -47,7 +47,7 @@ end
|
|
47
47
|
end
|
48
48
|
# @return [Hash{String => String}]
|
49
49
|
def get_headers
|
50
|
-
headers = { "X-Fern-Language": 'Ruby', "X-Fern-SDK-Name": 'paid_ruby', "X-Fern-SDK-Version": '0.1.
|
50
|
+
headers = { "X-Fern-Language": 'Ruby', "X-Fern-SDK-Name": 'paid_ruby', "X-Fern-SDK-Version": '0.1.2' }
|
51
51
|
headers["Authorization"] = ((@token.is_a? Method) ? @token.call : @token) unless @token.nil?
|
52
52
|
headers
|
53
53
|
end
|
@@ -92,7 +92,7 @@ end
|
|
92
92
|
end
|
93
93
|
# @return [Hash{String => String}]
|
94
94
|
def get_headers
|
95
|
-
headers = { "X-Fern-Language": 'Ruby', "X-Fern-SDK-Name": 'paid_ruby', "X-Fern-SDK-Version": '0.1.
|
95
|
+
headers = { "X-Fern-Language": 'Ruby', "X-Fern-SDK-Name": 'paid_ruby', "X-Fern-SDK-Version": '0.1.2' }
|
96
96
|
headers["Authorization"] = ((@token.is_a? Method) ? @token.call : @token) unless @token.nil?
|
97
97
|
headers
|
98
98
|
end
|
metadata
CHANGED
@@ -1,15 +1,70 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paid_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ''
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: opentelemetry-api
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.5'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '1.5'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: opentelemetry-exporter-otlp
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.30.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.30.0
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: opentelemetry-sdk
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.8'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.8'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: ruby-openai
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '8.1'
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '8.1'
|
13
68
|
- !ruby/object:Gem::Dependency
|
14
69
|
name: faraday
|
15
70
|
requirement: !ruby/object:Gem::Requirement
|
@@ -105,6 +160,9 @@ files:
|
|
105
160
|
- lib/paid_ruby/customers/client.rb
|
106
161
|
- lib/paid_ruby/orders/client.rb
|
107
162
|
- lib/paid_ruby/orders/lines/client.rb
|
163
|
+
- lib/paid_ruby/tracing/logging.rb
|
164
|
+
- lib/paid_ruby/tracing/tracing.rb
|
165
|
+
- lib/paid_ruby/tracing/wrappers/open_ai_wrapper.rb
|
108
166
|
- lib/paid_ruby/types/address.rb
|
109
167
|
- lib/paid_ruby/types/agent.rb
|
110
168
|
- lib/paid_ruby/types/agent_attribute.rb
|
@@ -141,7 +199,6 @@ metadata:
|
|
141
199
|
homepage_uri: https://github.com/paid-ai/paid-ruby
|
142
200
|
source_code_uri: https://github.com/paid-ai/paid-ruby
|
143
201
|
changelog_uri: https://github.com/paid-ai/paid-ruby/blob/master/CHANGELOG.md
|
144
|
-
post_install_message:
|
145
202
|
rdoc_options: []
|
146
203
|
require_paths:
|
147
204
|
- lib
|
@@ -156,8 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
156
213
|
- !ruby/object:Gem::Version
|
157
214
|
version: '0'
|
158
215
|
requirements: []
|
159
|
-
rubygems_version: 3.
|
160
|
-
signing_key:
|
216
|
+
rubygems_version: 3.6.7
|
161
217
|
specification_version: 4
|
162
218
|
summary: ''
|
163
219
|
test_files: []
|