openlayer 0.13.0 → 0.14.0

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: 38d97c7dc6d09d2ea4852014e96e016573128b020ea8f8ffdac1577c473848c7
4
- data.tar.gz: 1c92b52d855cfac5e77f9e1843e8850d49b464ec705b2363a3274a93271c8baf
3
+ metadata.gz: 7df732e3f7923ec58467e297ca5fe1fb8ff35ae552c66d55740e0087edd72962
4
+ data.tar.gz: ad8e4d93a70d7164d0ec01028749d2ece806a538804dce306804846d56db4dbb
5
5
  SHA512:
6
- metadata.gz: 46f56b7dc1b9d178ddbfe539b4614f6793ad3da4b4fd6d486bb6c6d63b296bf107c12e7be1de525a1ebaf4b6d0ba58414045335f7aebf46141bffcd74e68f528
7
- data.tar.gz: b6a492133574f6a77598d7abb6cf73b0b75376c72b3b030eeb8e9f8aac82641c2dee0cfed42478d65ea3aa235775651a37bea8c58cd2fb12e1b4c64ed33b5ed0
6
+ metadata.gz: 201e0fdc1d72da7b17b45dc9e73ea971d56d36dada8f691b324ee0852dd95be44e8061bf6ef21122e11f108f2ac33a51255fde830e3b9655b118f7b35912101d
7
+ data.tar.gz: 7619b1e64944741e9335620a0e60e0f4e3de5f638bba1fafd080c86c21ebf61aa71110384157f95063dcf170b6562cd3437e21406eb66aa2e0dbd7f22966e2d8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.14.0 (2026-07-06)
4
+
5
+ Full Changelog: [v0.13.1...v0.14.0](https://github.com/openlayer-ai/openlayer-ruby/compare/v0.13.1...v0.14.0)
6
+
7
+ ### Features
8
+
9
+ * **closes OPEN-11569:** support additional columns in ConversationalSearchService tracer ([e5cd8df](https://github.com/openlayer-ai/openlayer-ruby/commit/e5cd8df9335795f7296b394ea007caea3b090475))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * **client:** send content-type header for requests with an omitted optional body ([1778b7d](https://github.com/openlayer-ai/openlayer-ruby/commit/1778b7d71ddf2c244be71648141b84666f81addd))
15
+
16
+
17
+ ### Chores
18
+
19
+ * **internal:** bound formatter parallelism to CPU count ([f8781d0](https://github.com/openlayer-ai/openlayer-ruby/commit/f8781d074e80fc95497513b400c601e246998729))
20
+
21
+ ## 0.13.1 (2026-05-14)
22
+
23
+ Full Changelog: [v0.13.0...v0.13.1](https://github.com/openlayer-ai/openlayer-ruby/compare/v0.13.0...v0.13.1)
24
+
25
+ ### Bug Fixes
26
+
27
+ * **client:** elide content type header on requests without body ([cd44915](https://github.com/openlayer-ai/openlayer-ruby/commit/cd44915000d0ae58ac459cb8798ea7418603d1f0))
28
+
3
29
  ## 0.13.0 (2026-05-07)
4
30
 
5
31
  Full Changelog: [v0.12.2...v0.13.0](https://github.com/openlayer-ai/openlayer-ruby/compare/v0.12.2...v0.13.0)
data/README.md CHANGED
@@ -17,7 +17,7 @@ To use this gem, install via Bundler by adding the following to your application
17
17
  <!-- x-release-please-start-version -->
18
18
 
19
19
  ```ruby
20
- gem "openlayer", "~> 0.13.0"
20
+ gem "openlayer", "~> 0.14.0"
21
21
  ```
22
22
 
23
23
  <!-- x-release-please-end -->
@@ -21,15 +21,25 @@ module Openlayer
21
21
  # Openlayer::Integrations::GoogleConversationalSearchTracer.trace_client(
22
22
  # google_client,
23
23
  # openlayer_client: openlayer,
24
- # inference_pipeline_id: 'your-pipeline-id'
24
+ # inference_pipeline_id: 'your-pipeline-id',
25
+ # additional_columns: { environment: 'production' }
25
26
  # )
26
27
  #
27
- # # Now all answer_query calls are automatically traced
28
+ # # Now all answer_query calls are automatically traced! Pass
29
+ # # additional_columns on an individual call to attach data (like your
30
+ # # own trace ID) to just that row; it takes precedence over the
31
+ # # static defaults above on a key conflict.
28
32
  # response = google_client.answer_query(
29
33
  # serving_config: "projects/.../servingConfigs/default",
30
- # query: { text: "What is the meaning of life?" }
34
+ # query: { text: "What is the meaning of life?" },
35
+ # additional_columns: { trace_id: "abc-123" }
31
36
  # )
32
37
  class GoogleConversationalSearchTracer
38
+ # Row keys computed by this tracer. Any key in a caller-supplied
39
+ # additional_columns hash matching one of these is dropped, so custom
40
+ # data can never overwrite core trace fields.
41
+ RESERVED_ROW_KEYS = [:query, :answer, :latency_ms, :timestamp, :metadata, :steps, :context, :session_id, :user_id].freeze
42
+
33
43
  # Enable tracing on a Google ConversationalSearchService client
34
44
  #
35
45
  # @param client [Google::Cloud::DiscoveryEngine::V1::ConversationalSearchService::Client]
@@ -42,8 +52,12 @@ module Openlayer
42
52
  # Optional session ID to use for all traces. Takes precedence over auto-extracted sessions.
43
53
  # @param user_id [String, nil]
44
54
  # Optional user ID to use for all traces.
55
+ # @param additional_columns [Hash, nil]
56
+ # Optional static column values merged into every trace sent through this client (e.g. `{ environment: 'production' }`).
57
+ # A value passed to an individual answer_query call takes precedence over these on a key conflict. Keys colliding
58
+ # with a reserved row column (query, answer, latency_ms, timestamp, metadata, steps, context, session_id, user_id) are dropped.
45
59
  # @return [void]
46
- def self.trace_client(client, openlayer_client:, inference_pipeline_id:, session_id: nil, user_id: nil)
60
+ def self.trace_client(client, openlayer_client:, inference_pipeline_id:, session_id: nil, user_id: nil, additional_columns: {})
47
61
  # Store original method reference
48
62
  original_answer_query = client.method(:answer_query)
49
63
 
@@ -52,6 +66,10 @@ module Openlayer
52
66
  # Capture start time
53
67
  start_time = Time.now
54
68
 
69
+ # Extract per-call additional columns before forwarding to the
70
+ # real client; Google's client never sees this key
71
+ call_additional_columns = kwargs.delete(:additional_columns)
72
+
55
73
  # Execute the original method
56
74
  response = original_answer_query.call(*args, **kwargs, &block)
57
75
 
@@ -69,7 +87,9 @@ module Openlayer
69
87
  openlayer_client: openlayer_client,
70
88
  inference_pipeline_id: inference_pipeline_id,
71
89
  session_id: session_id,
72
- user_id: user_id
90
+ user_id: user_id,
91
+ additional_columns: additional_columns,
92
+ call_additional_columns: call_additional_columns
73
93
  )
74
94
  rescue StandardError => e
75
95
  # Never break the user's application due to tracing errors
@@ -95,8 +115,10 @@ module Openlayer
95
115
  # @param inference_pipeline_id [String] Pipeline ID
96
116
  # @param session_id [String, nil] Optional session ID (takes precedence over auto-extracted)
97
117
  # @param user_id [String, nil] Optional user ID
118
+ # @param additional_columns [Hash, nil] Optional static column values (see {.trace_client})
119
+ # @param call_additional_columns [Hash, nil] Optional per-call column values; takes precedence over additional_columns
98
120
  # @return [void]
99
- def self.send_trace(args:, kwargs:, response:, start_time:, end_time:, openlayer_client:, inference_pipeline_id:, session_id: nil, user_id: nil)
121
+ def self.send_trace(args:, kwargs:, response:, start_time:, end_time:, openlayer_client:, inference_pipeline_id:, session_id: nil, user_id: nil, additional_columns: {}, call_additional_columns: {})
100
122
  # Calculate latency
101
123
  latency_ms = ((end_time - start_time) * 1000).round(2)
102
124
 
@@ -199,6 +221,12 @@ module Openlayer
199
221
  trace_data[:config][:userIdColumnName] = "user_id"
200
222
  end
201
223
 
224
+ # Merge additional columns (per-call values take precedence over
225
+ # static defaults; keys colliding with reserved row columns are
226
+ # dropped so custom data can never corrupt core trace fields)
227
+ extra_columns = resolve_additional_columns(additional_columns, call_additional_columns)
228
+ trace_data[:rows][0].merge!(extra_columns) unless extra_columns.empty?
229
+
202
230
  # Send to Openlayer
203
231
  openlayer_client
204
232
  .inference_pipelines
@@ -594,6 +622,45 @@ module Openlayer
594
622
  nil
595
623
  end
596
624
 
625
+ # Merge static and per-call additional columns into a single Hash of
626
+ # extra row columns. Call-level values take precedence over static
627
+ # ones on key conflict, and any key colliding with a reserved row
628
+ # column is dropped.
629
+ #
630
+ # @param static_columns [Object] Value passed to trace_client (expected Hash)
631
+ # @param call_columns [Object] Value passed to an individual answer_query call (expected Hash)
632
+ # @return [Hash] Extra columns safe to merge onto a trace row
633
+ def self.resolve_additional_columns(static_columns, call_columns)
634
+ merged = normalize_additional_columns(static_columns).merge(normalize_additional_columns(call_columns))
635
+
636
+ merged.each_with_object({}) do |(key, value), result|
637
+ if RESERVED_ROW_KEYS.include?(key)
638
+ warn_if_debug("[Openlayer] additional_columns key :#{key} collides with a reserved column and was ignored")
639
+ else
640
+ result[key] = value
641
+ end
642
+ end
643
+ end
644
+
645
+ # Normalize an additional_columns value into a Hash with Symbol keys.
646
+ # Non-Hash input (or a key that can't be a Symbol) is dropped rather
647
+ # than raising, so a caller mistake can never break tracing.
648
+ #
649
+ # @param columns [Object] Expected to be a Hash of column name => value
650
+ # @return [Hash]
651
+ def self.normalize_additional_columns(columns)
652
+ return {} unless columns.is_a?(Hash)
653
+
654
+ columns.each_with_object({}) do |(key, value), result|
655
+ next unless key.respond_to?(:to_sym)
656
+
657
+ result[key.to_sym] = value
658
+ end
659
+ rescue StandardError => e
660
+ warn_if_debug("[Openlayer] Failed to normalize additional columns: #{e.message}")
661
+ {}
662
+ end
663
+
597
664
  # Safely extract a field from an object
598
665
  #
599
666
  # @param obj [Object] Object to extract from
@@ -659,6 +726,8 @@ module Openlayer
659
726
  :extract_session,
660
727
  :extract_user_pseudo_id,
661
728
  :extract_query_understanding_info,
729
+ :resolve_additional_columns,
730
+ :normalize_additional_columns,
662
731
  :safe_extract,
663
732
  :safe_count,
664
733
  :extract_timestamp
@@ -306,6 +306,11 @@ module Openlayer
306
306
  Openlayer::Internal::Util.deep_merge(*[req[:body], opts[:extra_body]].compact)
307
307
  end
308
308
 
309
+ # Generated methods always pass `req[:body]` for operations that define a
310
+ # request body, so only elide the content-type header when the operation
311
+ # has no body at all, not when an optional body param was omitted.
312
+ headers.delete("content-type") if body.nil? && !req.key?(:body)
313
+
309
314
  url = Openlayer::Internal::Util.join_parsed_uri(
310
315
  @base_url_components,
311
316
  {**req, path: path, query: query}
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Openlayer
4
- VERSION = "0.13.0"
4
+ VERSION = "0.14.0"
5
5
  end
@@ -10,7 +10,8 @@ module Openlayer
10
10
  openlayer_client: Openlayer::Client,
11
11
  inference_pipeline_id: String,
12
12
  session_id: T.nilable(String),
13
- user_id: T.nilable(String)
13
+ user_id: T.nilable(String),
14
+ additional_columns: T::Hash[Symbol, T.untyped]
14
15
  ).void
15
16
  end
16
17
  def self.trace_client(
@@ -18,7 +19,8 @@ module Openlayer
18
19
  openlayer_client:,
19
20
  inference_pipeline_id:,
20
21
  session_id: nil,
21
- user_id: nil
22
+ user_id: nil,
23
+ additional_columns: {}
22
24
  )
23
25
  end
24
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openlayer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Openlayer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-07 00:00:00.000000000 Z
11
+ date: 2026-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cgi