langfuse-rb 0.1.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.
data/lib/langfuse.rb ADDED
@@ -0,0 +1,457 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "langfuse/version"
4
+ require_relative "langfuse/types"
5
+
6
+ # Langfuse Ruby SDK
7
+ #
8
+ # Official Ruby SDK for Langfuse, providing LLM tracing, observability,
9
+ # and prompt management capabilities.
10
+ #
11
+ # @example Global configuration (Rails initializer)
12
+ # Langfuse.configure do |config|
13
+ # config.public_key = ENV['LANGFUSE_PUBLIC_KEY']
14
+ # config.secret_key = ENV['LANGFUSE_SECRET_KEY']
15
+ # config.cache_ttl = 120
16
+ # end
17
+ #
18
+ # @example Using the global client
19
+ # client = Langfuse.client
20
+ # prompt = client.get_prompt("greeting")
21
+ #
22
+ module Langfuse
23
+ class Error < StandardError; end
24
+ class ConfigurationError < Error; end
25
+ class ApiError < Error; end
26
+ class NotFoundError < ApiError; end
27
+ class UnauthorizedError < ApiError; end
28
+ end
29
+
30
+ require_relative "langfuse/config"
31
+ require_relative "langfuse/prompt_cache"
32
+ require_relative "langfuse/rails_cache_adapter"
33
+ require_relative "langfuse/cache_warmer"
34
+ require_relative "langfuse/api_client"
35
+ require_relative "langfuse/otel_setup"
36
+ require_relative "langfuse/otel_attributes"
37
+ require_relative "langfuse/propagation"
38
+ require_relative "langfuse/span_processor"
39
+ require_relative "langfuse/observations"
40
+ require_relative "langfuse/score_client"
41
+ require_relative "langfuse/text_prompt_client"
42
+ require_relative "langfuse/chat_prompt_client"
43
+ require_relative "langfuse/client"
44
+
45
+ # rubocop:disable Metrics/ModuleLength
46
+ module Langfuse
47
+ # rubocop:disable Metrics/ClassLength
48
+ class << self
49
+ attr_writer :configuration
50
+
51
+ # Returns the global configuration object
52
+ #
53
+ # @return [Config] the global configuration
54
+ def configuration
55
+ @configuration ||= Config.new
56
+ end
57
+
58
+ # Configure Langfuse globally
59
+ #
60
+ # @yield [Config] the configuration object
61
+ # @return [Config] the configured configuration
62
+ #
63
+ # @example
64
+ # Langfuse.configure do |config|
65
+ # config.public_key = ENV['LANGFUSE_PUBLIC_KEY']
66
+ # config.secret_key = ENV['LANGFUSE_SECRET_KEY']
67
+ # end
68
+ def configure
69
+ yield(configuration)
70
+
71
+ # Auto-initialize OpenTelemetry
72
+ OtelSetup.setup(configuration)
73
+
74
+ configuration
75
+ end
76
+
77
+ # Returns the global singleton client
78
+ #
79
+ # @return [Client] the global client instance
80
+ def client
81
+ @client ||= Client.new(configuration)
82
+ end
83
+
84
+ # Shutdown Langfuse and flush any pending traces and scores
85
+ #
86
+ # Call this when shutting down your application to ensure
87
+ # all traces and scores are sent to Langfuse.
88
+ #
89
+ # @param timeout [Integer] Timeout in seconds
90
+ # @return [void]
91
+ #
92
+ # @example In a Rails initializer or shutdown hook
93
+ # at_exit { Langfuse.shutdown }
94
+ #
95
+ def shutdown(timeout: 30)
96
+ client.shutdown if @client
97
+ OtelSetup.shutdown(timeout: timeout)
98
+ end
99
+
100
+ # Force flush all pending traces
101
+ #
102
+ # @param timeout [Integer] Timeout in seconds
103
+ # @return [void]
104
+ def force_flush(timeout: 30)
105
+ OtelSetup.force_flush(timeout: timeout)
106
+ end
107
+
108
+ # Propagate trace-level attributes to all spans created within this context.
109
+ #
110
+ # This method sets attributes on the currently active span AND automatically
111
+ # propagates them to all new child spans created within the block. This is the
112
+ # recommended way to set trace-level attributes like user_id, session_id, and metadata
113
+ # dimensions that should be consistently applied across all observations in a trace.
114
+ #
115
+ # **IMPORTANT**: Call this as early as possible within your trace/workflow. Only the
116
+ # currently active span and spans created after entering this context will have these
117
+ # attributes. Pre-existing spans will NOT be retroactively updated.
118
+ #
119
+ # @param user_id [String, nil] User identifier (≤200 characters)
120
+ # @param session_id [String, nil] Session identifier (≤200 characters)
121
+ # @param metadata [Hash<String, String>, nil] Additional metadata (all values ≤200 characters)
122
+ # @param version [String, nil] Version identifier (≤200 characters)
123
+ # @param tags [Array<String>, nil] List of tags (each ≤200 characters)
124
+ # @param as_baggage [Boolean] If true, propagates via OpenTelemetry baggage for cross-service propagation
125
+ # @yield Block within which attributes are propagated
126
+ # @return [Object] The result of the block
127
+ #
128
+ # @example Basic usage
129
+ # Langfuse.propagate_attributes(user_id: "user_123", session_id: "session_abc") do
130
+ # Langfuse.observe("operation") do |span|
131
+ # # Current span has user_id and session_id
132
+ # span.start_observation("child") do |child|
133
+ # # Child span inherits user_id and session_id
134
+ # end
135
+ # end
136
+ # end
137
+ #
138
+ # @example With metadata and tags
139
+ # Langfuse.propagate_attributes(
140
+ # user_id: "user_123",
141
+ # metadata: { environment: "production", region: "us-east" },
142
+ # tags: ["api", "v2"]
143
+ # ) do
144
+ # # All spans inherit these attributes
145
+ # end
146
+ #
147
+ # @example Cross-service propagation
148
+ # Langfuse.propagate_attributes(
149
+ # user_id: "user_123",
150
+ # as_baggage: true
151
+ # ) do
152
+ # # Attributes propagate via HTTP headers
153
+ # end
154
+ def propagate_attributes(user_id: nil, session_id: nil, metadata: nil, version: nil, tags: nil,
155
+ as_baggage: false, &)
156
+ Propagation.propagate_attributes(
157
+ user_id: user_id,
158
+ session_id: session_id,
159
+ metadata: metadata,
160
+ version: version,
161
+ tags: tags,
162
+ as_baggage: as_baggage,
163
+ &
164
+ )
165
+ end
166
+
167
+ # Create a score event and queue it for batching
168
+ #
169
+ # @param name [String] Score name (required)
170
+ # @param value [Numeric, Integer, String] Score value (type depends on data_type)
171
+ # @param trace_id [String, nil] Trace ID to associate with the score
172
+ # @param observation_id [String, nil] Observation ID to associate with the score
173
+ # @param comment [String, nil] Optional comment
174
+ # @param metadata [Hash, nil] Optional metadata hash
175
+ # @param data_type [Symbol] Data type (:numeric, :boolean, :categorical)
176
+ # @return [void]
177
+ # @raise [ArgumentError] if validation fails
178
+ #
179
+ # @example Numeric score
180
+ # Langfuse.create_score(name: "quality", value: 0.85, trace_id: "abc123")
181
+ #
182
+ # @example Boolean score
183
+ # Langfuse.create_score(name: "passed", value: true, trace_id: "abc123", data_type: :boolean)
184
+ #
185
+ # @example Categorical score
186
+ # Langfuse.create_score(name: "category", value: "high", trace_id: "abc123", data_type: :categorical)
187
+ # rubocop:disable Metrics/ParameterLists
188
+ def create_score(name:, value:, trace_id: nil, observation_id: nil, comment: nil, metadata: nil,
189
+ data_type: :numeric)
190
+ client.create_score(
191
+ name: name,
192
+ value: value,
193
+ trace_id: trace_id,
194
+ observation_id: observation_id,
195
+ comment: comment,
196
+ metadata: metadata,
197
+ data_type: data_type
198
+ )
199
+ end
200
+ # rubocop:enable Metrics/ParameterLists
201
+
202
+ # Create a score for the currently active observation (from OTel span)
203
+ #
204
+ # Extracts observation_id and trace_id from the active OpenTelemetry span.
205
+ #
206
+ # @param name [String] Score name (required)
207
+ # @param value [Numeric, Integer, String] Score value
208
+ # @param comment [String, nil] Optional comment
209
+ # @param metadata [Hash, nil] Optional metadata hash
210
+ # @param data_type [Symbol] Data type (:numeric, :boolean, :categorical)
211
+ # @return [void]
212
+ # @raise [ArgumentError] if no active span or validation fails
213
+ #
214
+ # @example
215
+ # Langfuse.observe("operation") do |obs|
216
+ # Langfuse.score_active_observation(name: "accuracy", value: 0.92)
217
+ # end
218
+ def score_active_observation(name:, value:, comment: nil, metadata: nil, data_type: :numeric)
219
+ client.score_active_observation(
220
+ name: name,
221
+ value: value,
222
+ comment: comment,
223
+ metadata: metadata,
224
+ data_type: data_type
225
+ )
226
+ end
227
+
228
+ # Create a score for the currently active trace (from OTel span)
229
+ #
230
+ # Extracts trace_id from the active OpenTelemetry span.
231
+ #
232
+ # @param name [String] Score name (required)
233
+ # @param value [Numeric, Integer, String] Score value
234
+ # @param comment [String, nil] Optional comment
235
+ # @param metadata [Hash, nil] Optional metadata hash
236
+ # @param data_type [Symbol] Data type (:numeric, :boolean, :categorical)
237
+ # @return [void]
238
+ # @raise [ArgumentError] if no active span or validation fails
239
+ #
240
+ # @example
241
+ # Langfuse.observe("operation") do |obs|
242
+ # Langfuse.score_active_trace(name: "overall_quality", value: 5)
243
+ # end
244
+ def score_active_trace(name:, value:, comment: nil, metadata: nil, data_type: :numeric)
245
+ client.score_active_trace(
246
+ name: name,
247
+ value: value,
248
+ comment: comment,
249
+ metadata: metadata,
250
+ data_type: data_type
251
+ )
252
+ end
253
+
254
+ # Force flush all queued score events
255
+ #
256
+ # Sends all queued score events to the API immediately.
257
+ #
258
+ # @return [void]
259
+ #
260
+ # @example
261
+ # Langfuse.flush_scores
262
+ def flush_scores
263
+ client.flush_scores if @client
264
+ end
265
+
266
+ # Reset global configuration and client (useful for testing)
267
+ #
268
+ # @return [void]
269
+ def reset!
270
+ client.shutdown if @client
271
+ OtelSetup.shutdown(timeout: 5) if OtelSetup.initialized?
272
+ @configuration = nil
273
+ @client = nil
274
+ rescue StandardError
275
+ # Ignore shutdown errors during reset (e.g., in tests)
276
+ @configuration = nil
277
+ @client = nil
278
+ end
279
+
280
+ # Creates a new observation (root or child)
281
+ #
282
+ # This is the module-level factory method that creates observations of any type.
283
+ # It can create root observations (when parent_span_context is nil) or child
284
+ # observations (when parent_span_context is provided).
285
+ #
286
+ # @param name [String] Descriptive name for the observation
287
+ # @param attrs [Hash, Types::SpanAttributes, Types::GenerationAttributes, nil] Observation attributes
288
+ # @param as_type [Symbol, String] Observation type (:span, :generation, :event, etc.)
289
+ # @param parent_span_context [OpenTelemetry::Trace::SpanContext, nil] Parent span context for child observations
290
+ # @param start_time [Time, Integer, nil] Optional start time (Time object or Unix timestamp in nanoseconds)
291
+ # @param skip_validation [Boolean] Skip validation (for internal use). Defaults to false.
292
+ # @return [BaseObservation] The observation wrapper (Span, Generation, or Event)
293
+ #
294
+ # @example Create root span
295
+ # span = Langfuse.start_observation("root-operation", { input: {...} })
296
+ #
297
+ # @example Create child generation
298
+ # child = Langfuse.start_observation("llm-call", { model: "gpt-4" },
299
+ # as_type: :generation,
300
+ # parent_span_context: parent.otel_span.context)
301
+ def start_observation(name, attrs = {}, as_type: :span, parent_span_context: nil, start_time: nil,
302
+ skip_validation: false)
303
+ type_str = as_type.to_s
304
+
305
+ unless skip_validation || valid_observation_type?(as_type)
306
+ valid_types = OBSERVATION_TYPES.values.sort.join(", ")
307
+ raise ArgumentError, "Invalid observation type: #{type_str}. Valid types: #{valid_types}"
308
+ end
309
+
310
+ otel_tracer = otel_tracer()
311
+ otel_span = create_otel_span(
312
+ name: name,
313
+ start_time: start_time,
314
+ parent_span_context: parent_span_context,
315
+ otel_tracer: otel_tracer
316
+ )
317
+
318
+ # Serialize attributes
319
+ # Only set attributes if span is still recording (should always be true here, but guard for safety)
320
+ if otel_span.recording?
321
+ otel_attrs = OtelAttributes.create_observation_attributes(type_str, attrs.to_h)
322
+ otel_attrs.each { |key, value| otel_span.set_attribute(key, value) }
323
+ end
324
+
325
+ # Wrap in appropriate class
326
+ observation = wrap_otel_span(otel_span, type_str, otel_tracer, attributes: attrs)
327
+
328
+ # Events auto-end immediately when created
329
+ observation.end if type_str == OBSERVATION_TYPES[:event]
330
+
331
+ observation
332
+ end
333
+
334
+ # User-facing convenience method for creating root observations
335
+ #
336
+ # @param name [String] Descriptive name for the observation
337
+ # @param attrs [Hash] Observation attributes (optional positional or keyword)
338
+ # @param as_type [Symbol, String] Observation type (:span, :generation, :event, etc.)
339
+ # @yield [observation] Optional block that receives the observation object
340
+ # @yieldparam observation [BaseObservation] The observation object
341
+ # @return [BaseObservation, Object] The observation (or block return value if block given)
342
+ #
343
+ # @example Block-based API (auto-ends)
344
+ # Langfuse.observe("operation") do |obs|
345
+ # result = perform_operation
346
+ # obs.update(output: result)
347
+ # end
348
+ #
349
+ # @example Stateful API (manual end)
350
+ # obs = Langfuse.observe("operation", input: { data: "test" })
351
+ # obs.update(output: { result: "success" })
352
+ # obs.end
353
+ def observe(name, attrs = {}, as_type: :span, **kwargs, &block)
354
+ # Merge positional attrs and keyword kwargs
355
+ merged_attrs = attrs.to_h.merge(kwargs)
356
+ observation = start_observation(name, merged_attrs, as_type: as_type)
357
+
358
+ if block
359
+ # Block-based API: auto-ends when block completes
360
+ # Set context and execute block
361
+ current_context = OpenTelemetry::Context.current
362
+ result = OpenTelemetry::Context.with_current(
363
+ OpenTelemetry::Trace.context_with_span(observation.otel_span, parent_context: current_context)
364
+ ) do
365
+ block.call(observation)
366
+ end
367
+ # Only end if not already ended (events auto-end in start_observation)
368
+ observation.end unless as_type.to_s == OBSERVATION_TYPES[:event]
369
+ result
370
+ else
371
+ # Stateful API - return observation
372
+ # Events already auto-ended in start_observation
373
+ observation
374
+ end
375
+ end
376
+
377
+ # Registry mapping observation type strings to their wrapper classes
378
+ OBSERVATION_TYPE_REGISTRY = {
379
+ OBSERVATION_TYPES[:generation] => Generation,
380
+ OBSERVATION_TYPES[:embedding] => Embedding,
381
+ OBSERVATION_TYPES[:event] => Event,
382
+ OBSERVATION_TYPES[:agent] => Agent,
383
+ OBSERVATION_TYPES[:tool] => Tool,
384
+ OBSERVATION_TYPES[:chain] => Chain,
385
+ OBSERVATION_TYPES[:retriever] => Retriever,
386
+ OBSERVATION_TYPES[:evaluator] => Evaluator,
387
+ OBSERVATION_TYPES[:guardrail] => Guardrail,
388
+ OBSERVATION_TYPES[:span] => Span
389
+ }.freeze
390
+
391
+ private
392
+
393
+ # Validates that an observation type is valid
394
+ #
395
+ # Checks if the provided type (symbol or string) matches a valid observation type
396
+ # in the OBSERVATION_TYPES constant.
397
+ #
398
+ # @param type [Symbol, String, Object] The observation type to validate
399
+ # @return [Boolean] true if valid, false otherwise
400
+ #
401
+ # @example
402
+ # valid_observation_type?(:span) # => true
403
+ # valid_observation_type?("span") # => true
404
+ # valid_observation_type?(:invalid) # => false
405
+ # valid_observation_type?(nil) # => false
406
+ def valid_observation_type?(type)
407
+ return false unless type.respond_to?(:to_sym)
408
+
409
+ OBSERVATION_TYPES.key?(type.to_sym)
410
+ rescue TypeError
411
+ false
412
+ end
413
+
414
+ # Gets the OpenTelemetry tracer for Langfuse
415
+ #
416
+ # @return [OpenTelemetry::SDK::Trace::Tracer] The OTel tracer
417
+ def otel_tracer
418
+ OpenTelemetry.tracer_provider.tracer("langfuse-rb", Langfuse::VERSION)
419
+ end
420
+
421
+ # Creates an OpenTelemetry span (root or child)
422
+ #
423
+ # @param name [String] Span name
424
+ # @param start_time [Time, Integer, nil] Optional start time
425
+ # @param parent_span_context [OpenTelemetry::Trace::SpanContext, nil] Parent span context
426
+ # @param otel_tracer [OpenTelemetry::SDK::Trace::Tracer] The OTel tracer
427
+ # @return [OpenTelemetry::SDK::Trace::Span] The created span
428
+ def create_otel_span(name:, otel_tracer:, start_time: nil, parent_span_context: nil)
429
+ if parent_span_context
430
+ # Create child span with parent context
431
+ # Create a non-recording span from the parent context to set in context
432
+ parent_span = OpenTelemetry::Trace.non_recording_span(parent_span_context)
433
+ parent_context = OpenTelemetry::Trace.context_with_span(parent_span)
434
+ OpenTelemetry::Context.with_current(parent_context) do
435
+ otel_tracer.start_span(name, start_timestamp: start_time)
436
+ end
437
+ else
438
+ # Create root span
439
+ otel_tracer.start_span(name, start_timestamp: start_time)
440
+ end
441
+ end
442
+
443
+ # Wraps an OpenTelemetry span in the appropriate observation class
444
+ #
445
+ # @param otel_span [OpenTelemetry::SDK::Trace::Span] The OTel span
446
+ # @param type_str [String] Observation type string
447
+ # @param otel_tracer [OpenTelemetry::SDK::Trace::Tracer] The OTel tracer
448
+ # @param attributes [Hash, nil] Optional attributes
449
+ # @return [BaseObservation] Appropriate observation wrapper instance
450
+ def wrap_otel_span(otel_span, type_str, otel_tracer, attributes: nil)
451
+ observation_class = OBSERVATION_TYPE_REGISTRY[type_str] || Span
452
+ observation_class.new(otel_span, otel_tracer, attributes: attributes)
453
+ end
454
+ end
455
+ # rubocop:enable Metrics/ClassLength
456
+ end
457
+ # rubocop:enable Metrics/ModuleLength
metadata ADDED
@@ -0,0 +1,177 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: langfuse-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - SimplePractice
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: faraday-retry
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: mustache
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.1'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.1'
54
+ - !ruby/object:Gem::Dependency
55
+ name: opentelemetry-api
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.2'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.2'
68
+ - !ruby/object:Gem::Dependency
69
+ name: opentelemetry-common
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.21'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.21'
82
+ - !ruby/object:Gem::Dependency
83
+ name: opentelemetry-exporter-otlp
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.28'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.28'
96
+ - !ruby/object:Gem::Dependency
97
+ name: opentelemetry-sdk
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.4'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.4'
110
+ - !ruby/object:Gem::Dependency
111
+ name: base64
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '0.2'
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '0.2'
124
+ description: Official Ruby SDK for Langfuse, providing LLM tracing, observability,
125
+ and prompt management capabilities
126
+ email:
127
+ - open-source-langfuse-rb@simplepractice.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - CHANGELOG.md
133
+ - LICENSE
134
+ - README.md
135
+ - lib/langfuse.rb
136
+ - lib/langfuse/api_client.rb
137
+ - lib/langfuse/cache_warmer.rb
138
+ - lib/langfuse/chat_prompt_client.rb
139
+ - lib/langfuse/client.rb
140
+ - lib/langfuse/config.rb
141
+ - lib/langfuse/observations.rb
142
+ - lib/langfuse/otel_attributes.rb
143
+ - lib/langfuse/otel_setup.rb
144
+ - lib/langfuse/prompt_cache.rb
145
+ - lib/langfuse/propagation.rb
146
+ - lib/langfuse/rails_cache_adapter.rb
147
+ - lib/langfuse/score_client.rb
148
+ - lib/langfuse/span_processor.rb
149
+ - lib/langfuse/text_prompt_client.rb
150
+ - lib/langfuse/types.rb
151
+ - lib/langfuse/version.rb
152
+ homepage: https://github.com/simplepractice/langfuse-rb
153
+ licenses:
154
+ - MIT
155
+ metadata:
156
+ homepage_uri: https://github.com/simplepractice/langfuse-rb
157
+ source_code_uri: https://github.com/simplepractice/langfuse-rb
158
+ changelog_uri: https://github.com/simplepractice/langfuse-rb/blob/main/CHANGELOG.md
159
+ rubygems_mfa_required: 'true'
160
+ rdoc_options: []
161
+ require_paths:
162
+ - lib
163
+ required_ruby_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: 3.2.0
168
+ required_rubygems_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ requirements: []
174
+ rubygems_version: 3.7.2
175
+ specification_version: 4
176
+ summary: Ruby SDK for Langfuse - LLM observability and prompt management
177
+ test_files: []