boxcars 0.8.1 → 0.8.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: e76c5930ad4510169e7b27bca16789e5e8b72f1627f8e05546fe6450a649416a
4
- data.tar.gz: 7a3a1f3e8eb58674481f57e814b68d797135f5ea41856629bbbae9f17743e429
3
+ metadata.gz: 93e000d3596a656454fb5c76becff8c5d5b4bbb33fe75f91598aceb0526c8d48
4
+ data.tar.gz: 87d3db350a3faa94cb367fbd600749ed584f0868cd8298469b7bef6c9434e93e
5
5
  SHA512:
6
- metadata.gz: 0b660877e4644a88e4a024512be55b2eeb5ea5cae8fb72a66f117a7ebfca2eefce6f2cfc10587afd9083b03b40e38c0fb30ca56ffbd4ce6723c09f2bf886acdf
7
- data.tar.gz: f17d7b1cc975749780feecf2dfca65056332e98bb6b2a3ef40cbe0663820ed66ee51f88776910590b8c27a8ec4fcfe586c188ee7126c99127e4dd410d4e7f8fb
6
+ metadata.gz: d3028c6cbaec10e84597c3a68e2f8f6c88b336b4be50144b04349662afa647d9c266d00debc14c0370bda0bb2150472cf69e347def8fcdc5d3682fc6c2d19512
7
+ data.tar.gz: 98a10191a8cd96cf85d91f9d5f1f38f07fa29fc7521f55bfd67c500a21fb23b3ef7d4ba7a16df1cc1d35f2a7486fe9ba18f11ab922e288895533ed2197766601
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.8.2](https://github.com/BoxcarsAI/boxcars/tree/v0.8.2) (2025-06-04)
4
+
5
+ [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.8.1...v0.8.2)
6
+
7
+ ## [v0.8.1](https://github.com/BoxcarsAI/boxcars/tree/v0.8.1) (2025-06-03)
8
+
9
+ [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.8.0...v0.8.1)
10
+
3
11
  ## [v0.8.0](https://github.com/BoxcarsAI/boxcars/tree/v0.8.0) (2025-06-03)
4
12
 
5
13
  [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.7.7...v0.8.0)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- boxcars (0.8.1)
4
+ boxcars (0.8.3)
5
5
  faraday-retry (~> 2.0)
6
6
  google_search_results (~> 2.2)
7
7
  gpt4all (~> 0.0.5)
@@ -56,10 +56,10 @@ GEM
56
56
  async (>= 1.25)
57
57
  base64 (0.3.0)
58
58
  benchmark (0.4.1)
59
- bigdecimal (3.2.1)
59
+ bigdecimal (3.2.2)
60
60
  concurrent-ruby (1.3.5)
61
61
  connection_pool (2.5.3)
62
- console (1.30.2)
62
+ console (1.31.0)
63
63
  fiber-annotation
64
64
  fiber-local (~> 1.1)
65
65
  json
@@ -74,7 +74,7 @@ GEM
74
74
  domain_name (0.6.20240107)
75
75
  dotenv (3.1.8)
76
76
  drb (2.2.3)
77
- dynamicschema (1.0.0.beta04)
77
+ dynamicschema (1.0.0)
78
78
  erb (5.0.1)
79
79
  event_stream_parser (1.0.0)
80
80
  faraday (2.13.1)
@@ -132,7 +132,7 @@ GEM
132
132
  mime-types (3.7.0)
133
133
  logger
134
134
  mime-types-data (~> 3.2025, >= 3.2025.0507)
135
- mime-types-data (3.2025.0527)
135
+ mime-types-data (3.2025.0603)
136
136
  minitest (5.25.5)
137
137
  multi_json (1.15.0)
138
138
  multipart-post (2.4.1)
@@ -211,7 +211,7 @@ GEM
211
211
  diff-lcs (>= 1.2.0, < 2.0)
212
212
  rspec-support (~> 3.13.0)
213
213
  rspec-support (3.13.4)
214
- rubocop (1.75.8)
214
+ rubocop (1.76.1)
215
215
  json (~> 2.3)
216
216
  language_server-protocol (~> 3.17.0.2)
217
217
  lint_roller (~> 1.1.0)
@@ -219,10 +219,10 @@ GEM
219
219
  parser (>= 3.3.0.2)
220
220
  rainbow (>= 2.2.2, < 4.0)
221
221
  regexp_parser (>= 2.9.3, < 3.0)
222
- rubocop-ast (>= 1.44.0, < 2.0)
222
+ rubocop-ast (>= 1.45.0, < 2.0)
223
223
  ruby-progressbar (~> 1.7)
224
224
  unicode-display_width (>= 2.4.0, < 4.0)
225
- rubocop-ast (1.44.1)
225
+ rubocop-ast (1.45.1)
226
226
  parser (>= 3.3.7.2)
227
227
  prism (~> 1.4)
228
228
  rubocop-rake (0.6.0)
data/README.md CHANGED
@@ -351,17 +351,30 @@ Set up observability by configuring a backend:
351
351
  ```ruby
352
352
  # Using PostHog backend
353
353
  require 'boxcars/observability_backends/posthog_backend'
354
+ require 'posthog'
355
+
356
+ # Create a PostHog client with your desired configuration
357
+ posthog_client = PostHog::Client.new(
358
+ api_key: ENV['POSTHOG_API_KEY'] || 'your_posthog_api_key',
359
+ host: 'https://app.posthog.com', # or your self-hosted instance
360
+ on_error: proc { |status, body|
361
+ Rails.logger.warn "PostHog error: #{status} - #{body}"
362
+ }
363
+ )
354
364
 
355
365
  Boxcars.configure do |config|
356
- config.observability_backend = Boxcars::PosthogBackend.new(
357
- api_key: ENV['POSTHOG_API_KEY'] || 'your_posthog_api_key',
358
- host: 'https://app.posthog.com' # or your self-hosted instance
359
- )
366
+ config.observability_backend = Boxcars::PosthogBackend.new(client: posthog_client)
360
367
  end
361
368
 
362
369
  # Using multiple backends
363
370
  require 'boxcars/observability_backends/multi_backend'
364
- backend1 = Boxcars::PosthogBackend.new(api_key: ENV['POSTHOG_API_KEY'])
371
+
372
+ # Create PostHog client
373
+ posthog_client = PostHog::Client.new(
374
+ api_key: ENV['POSTHOG_API_KEY'],
375
+ host: 'https://app.posthog.com'
376
+ )
377
+ backend1 = Boxcars::PosthogBackend.new(client: posthog_client)
365
378
  backend2 = YourCustomBackend.new
366
379
 
367
380
  Boxcars.configure do |config|
@@ -440,14 +453,18 @@ The PostHog backend requires the `posthog-ruby` gem:
440
453
  gem 'posthog-ruby'
441
454
 
442
455
  # Configure the backend
456
+ require 'posthog'
457
+
458
+ posthog_client = PostHog::Client.new(
459
+ api_key: ENV['POSTHOG_API_KEY'],
460
+ host: 'https://app.posthog.com',
461
+ on_error: proc { |status, body|
462
+ Rails.logger.warn "PostHog error: #{status} - #{body}"
463
+ }
464
+ )
465
+
443
466
  Boxcars.configure do |config|
444
- config.observability_backend = Boxcars::PosthogBackend.new(
445
- api_key: ENV['POSTHOG_API_KEY'],
446
- host: 'https://app.posthog.com',
447
- on_error: proc { |status, body|
448
- Rails.logger.warn "PostHog error: #{status} - #{body}"
449
- }
450
- )
467
+ config.observability_backend = Boxcars::PosthogBackend.new(client: posthog_client)
451
468
  end
452
469
  ```
453
470
 
@@ -79,12 +79,16 @@ module Boxcars
79
79
  )
80
80
  end
81
81
 
82
- _gemini_handle_call_outcome(response_data:)
82
+ # If there's an error, raise it to maintain backward compatibility with existing tests
83
+ raise response_data[:error] if response_data[:error]
84
+
85
+ response_data
83
86
  end
84
87
 
85
88
  def run(question, **)
86
89
  prompt = Prompt.new(template: question)
87
- answer = client(prompt:, inputs: {}, **)
90
+ response_data = client(prompt:, inputs: {}, **)
91
+ answer = _gemini_handle_call_outcome(response_data:)
88
92
  Boxcars.debug("Answer: #{answer}", :cyan)
89
93
  answer
90
94
  end
@@ -71,12 +71,16 @@ module Boxcars
71
71
  )
72
72
  end
73
73
 
74
- _groq_handle_call_outcome(response_data:)
74
+ # If there's an error, raise it to maintain backward compatibility with existing tests
75
+ raise response_data[:error] if response_data[:error]
76
+
77
+ response_data
75
78
  end
76
79
 
77
80
  def run(question, **)
78
81
  prompt = Prompt.new(template: question)
79
- answer = client(prompt:, inputs: {}, **)
82
+ response_data = client(prompt:, inputs: {}, **)
83
+ answer = _groq_handle_call_outcome(response_data:)
80
84
  Boxcars.debug("Answer: #{answer}", :cyan)
81
85
  answer
82
86
  end
@@ -128,6 +128,7 @@ module Boxcars
128
128
  # Called by Engine#generate to check the response from the client.
129
129
  # @param response [Hash] The parsed JSON response from the OpenAI API.
130
130
  # @raise [Boxcars::Error] if the response contains an error.
131
+ # rubocop:disable Naming/PredicateMethod
131
132
  def check_response(response)
132
133
  if response.is_a?(Hash) && response["error"]
133
134
  err_details = response["error"]
@@ -136,6 +137,7 @@ module Boxcars
136
137
  end
137
138
  true
138
139
  end
140
+ # rubocop:enable Naming/PredicateMethod
139
141
 
140
142
  def run(question, **)
141
143
  prompt = Prompt.new(template: question)
@@ -57,12 +57,39 @@ module Boxcars
57
57
  # Includes prompt, completion, and total tokens used.
58
58
  inkeys = %w[completion_tokens prompt_tokens total_tokens].freeze
59
59
  prompts.each_slice(batch_size) do |sub_prompts|
60
- sub_prompts.each do |sprompts, inputs|
61
- response = client(prompt: sprompts, inputs:, **params)
62
- check_response(response)
63
- choices.concat(response["choices"])
64
- usage_keys = inkeys & response["usage"].keys
65
- usage_keys.each { |key| token_usage[key] = token_usage[key].to_i + response["usage"][key] }
60
+ sub_prompts.each do |sprompt, inputs|
61
+ client_response = client(prompt: sprompt, inputs:, **params)
62
+
63
+ # Handle different response formats:
64
+ # - New format: response_data hash with :parsed_json key (Groq, Gemini)
65
+ # - Legacy format: direct API response hash (OpenAI, others)
66
+ api_response_hash = if client_response.is_a?(Hash) && client_response.key?(:parsed_json)
67
+ client_response[:parsed_json]
68
+ else
69
+ client_response
70
+ end
71
+
72
+ # Ensure we have a hash to work with
73
+ unless api_response_hash.is_a?(Hash)
74
+ raise TypeError, "Expected Hash from client method, got #{api_response_hash.class}: #{api_response_hash.inspect}"
75
+ end
76
+
77
+ check_response(api_response_hash)
78
+
79
+ current_choices = api_response_hash["choices"]
80
+ if current_choices.is_a?(Array)
81
+ choices.concat(current_choices)
82
+ else
83
+ Boxcars.logger&.warn "No 'choices' found in API response: #{api_response_hash.inspect}"
84
+ end
85
+
86
+ api_usage = api_response_hash["usage"]
87
+ if api_usage.is_a?(Hash)
88
+ usage_keys = inkeys & api_usage.keys
89
+ usage_keys.each { |key| token_usage[key] = token_usage[key].to_i + api_usage[key] }
90
+ else
91
+ Boxcars.logger&.warn "No 'usage' data found in API response: #{api_response_hash.inspect}"
92
+ end
66
93
  end
67
94
  end
68
95
 
@@ -9,10 +9,13 @@ module Boxcars
9
9
  #
10
10
  # Example Usage:
11
11
  # require 'boxcars/observability_backends/posthog_backend'
12
- # Boxcars::Observability.backend = Boxcars::PosthogBackend.new(
12
+ # require 'posthog'
13
+ #
14
+ # client = PostHog::Client.new(
13
15
  # api_key: 'YOUR_POSTHOG_API_KEY',
14
16
  # host: 'https://app.posthog.com' # or your self-hosted instance
15
17
  # )
18
+ # Boxcars::Observability.backend = Boxcars::PosthogBackend.new(client: client)
16
19
  #
17
20
  # # To track user-specific events, ensure :user_id is present in properties
18
21
  # Boxcars::Observability.track(
@@ -23,32 +26,18 @@ module Boxcars
23
26
  include Boxcars::ObservabilityBackend
24
27
 
25
28
  # Initializes the PosthogBackend.
26
- # Configures the PostHog client with the provided API key and host.
29
+ # Accepts a pre-configured PostHog client instance.
27
30
  #
28
- # @param api_key [String] Your PostHog project API key.
29
- # @param host [String] The PostHog API host. Defaults to 'https://app.posthog.com'.
30
- # @param _personal_api_key [String, nil] Optional: A personal API key for server-side operations if needed.
31
- # @param on_error [Proc, nil] Optional: A lambda/proc to call when an error occurs during event capture.
32
- # It receives the error code and error body as arguments.
33
- # Defaults to a proc that logs the error to stderr.
31
+ # @param client [PostHog::Client] A configured PostHog client instance.
34
32
  # @raise [LoadError] if the 'posthog-ruby' gem is not available.
35
- def initialize(api_key:, host: 'https://app.posthog.com', _personal_api_key: nil, on_error: nil)
33
+ def initialize(client:)
36
34
  begin
37
35
  require 'posthog'
38
36
  rescue LoadError
39
37
  raise LoadError, "The 'posthog-ruby' gem is required to use PosthogBackend. Please add it to your Gemfile."
40
38
  end
41
39
 
42
- @on_error_proc = on_error || proc do |status, body|
43
- Boxcars.error("PostHog error: Status #{status}, Body: #{body}", :red)
44
- end
45
-
46
- # The posthog-ruby gem uses a simpler API
47
- @posthog_client = PostHog::Client.new(
48
- api_key:,
49
- host:,
50
- on_error: @on_error_proc
51
- )
40
+ @posthog_client = client
52
41
  end
53
42
 
54
43
  # Tracks an event with PostHog.
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Boxcars
4
4
  # The current version of the gem.
5
- VERSION = "0.8.1"
5
+ VERSION = "0.8.3"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boxcars
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francis Sullivan