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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +60 -0
- data/LICENSE +21 -0
- data/README.md +106 -0
- data/lib/langfuse/api_client.rb +330 -0
- data/lib/langfuse/cache_warmer.rb +219 -0
- data/lib/langfuse/chat_prompt_client.rb +98 -0
- data/lib/langfuse/client.rb +338 -0
- data/lib/langfuse/config.rb +135 -0
- data/lib/langfuse/observations.rb +615 -0
- data/lib/langfuse/otel_attributes.rb +275 -0
- data/lib/langfuse/otel_setup.rb +123 -0
- data/lib/langfuse/prompt_cache.rb +131 -0
- data/lib/langfuse/propagation.rb +471 -0
- data/lib/langfuse/rails_cache_adapter.rb +200 -0
- data/lib/langfuse/score_client.rb +321 -0
- data/lib/langfuse/span_processor.rb +61 -0
- data/lib/langfuse/text_prompt_client.rb +67 -0
- data/lib/langfuse/types.rb +353 -0
- data/lib/langfuse/version.rb +5 -0
- data/lib/langfuse.rb +457 -0
- metadata +177 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
5
|
+
module Langfuse
|
|
6
|
+
# Configuration object for Langfuse client
|
|
7
|
+
#
|
|
8
|
+
# @example Global configuration
|
|
9
|
+
# Langfuse.configure do |config|
|
|
10
|
+
# config.public_key = ENV['LANGFUSE_PUBLIC_KEY']
|
|
11
|
+
# config.secret_key = ENV['LANGFUSE_SECRET_KEY']
|
|
12
|
+
# config.cache_ttl = 120
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# @example Per-client configuration
|
|
16
|
+
# config = Langfuse::Config.new do |c|
|
|
17
|
+
# c.public_key = "pk_..."
|
|
18
|
+
# c.secret_key = "sk_..."
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
class Config
|
|
22
|
+
# @return [String, nil] Langfuse public API key
|
|
23
|
+
attr_accessor :public_key
|
|
24
|
+
|
|
25
|
+
# @return [String, nil] Langfuse secret API key
|
|
26
|
+
attr_accessor :secret_key
|
|
27
|
+
|
|
28
|
+
# @return [String] Base URL for Langfuse API
|
|
29
|
+
attr_accessor :base_url
|
|
30
|
+
|
|
31
|
+
# @return [Integer] HTTP request timeout in seconds
|
|
32
|
+
attr_accessor :timeout
|
|
33
|
+
|
|
34
|
+
# @return [Logger] Logger instance for debugging
|
|
35
|
+
attr_accessor :logger
|
|
36
|
+
|
|
37
|
+
# @return [Integer] Cache TTL in seconds
|
|
38
|
+
attr_accessor :cache_ttl
|
|
39
|
+
|
|
40
|
+
# @return [Integer] Maximum number of cached items
|
|
41
|
+
attr_accessor :cache_max_size
|
|
42
|
+
|
|
43
|
+
# @return [Symbol] Cache backend (:memory or :rails)
|
|
44
|
+
attr_accessor :cache_backend
|
|
45
|
+
|
|
46
|
+
# @return [Integer] Lock timeout in seconds for distributed cache stampede protection
|
|
47
|
+
attr_accessor :cache_lock_timeout
|
|
48
|
+
|
|
49
|
+
# @return [Boolean] Use async processing for traces (requires ActiveJob)
|
|
50
|
+
attr_accessor :tracing_async
|
|
51
|
+
|
|
52
|
+
# @return [Integer] Number of events to batch before sending
|
|
53
|
+
attr_accessor :batch_size
|
|
54
|
+
|
|
55
|
+
# @return [Integer] Interval in seconds to flush buffered events
|
|
56
|
+
attr_accessor :flush_interval
|
|
57
|
+
|
|
58
|
+
# @return [Symbol] ActiveJob queue name for async processing
|
|
59
|
+
attr_accessor :job_queue
|
|
60
|
+
|
|
61
|
+
# Default values
|
|
62
|
+
DEFAULT_BASE_URL = "https://cloud.langfuse.com"
|
|
63
|
+
DEFAULT_TIMEOUT = 5
|
|
64
|
+
DEFAULT_CACHE_TTL = 60
|
|
65
|
+
DEFAULT_CACHE_MAX_SIZE = 1000
|
|
66
|
+
DEFAULT_CACHE_BACKEND = :memory
|
|
67
|
+
DEFAULT_CACHE_LOCK_TIMEOUT = 10
|
|
68
|
+
DEFAULT_TRACING_ASYNC = true
|
|
69
|
+
DEFAULT_BATCH_SIZE = 50
|
|
70
|
+
DEFAULT_FLUSH_INTERVAL = 10
|
|
71
|
+
DEFAULT_JOB_QUEUE = :default
|
|
72
|
+
|
|
73
|
+
# Initialize a new Config object
|
|
74
|
+
#
|
|
75
|
+
# @yield [config] Optional block for configuration
|
|
76
|
+
# @yieldparam config [Config] The config instance
|
|
77
|
+
def initialize
|
|
78
|
+
@public_key = ENV.fetch("LANGFUSE_PUBLIC_KEY", nil)
|
|
79
|
+
@secret_key = ENV.fetch("LANGFUSE_SECRET_KEY", nil)
|
|
80
|
+
@base_url = ENV.fetch("LANGFUSE_BASE_URL", DEFAULT_BASE_URL)
|
|
81
|
+
@timeout = DEFAULT_TIMEOUT
|
|
82
|
+
@cache_ttl = DEFAULT_CACHE_TTL
|
|
83
|
+
@cache_max_size = DEFAULT_CACHE_MAX_SIZE
|
|
84
|
+
@cache_backend = DEFAULT_CACHE_BACKEND
|
|
85
|
+
@cache_lock_timeout = DEFAULT_CACHE_LOCK_TIMEOUT
|
|
86
|
+
@tracing_async = DEFAULT_TRACING_ASYNC
|
|
87
|
+
@batch_size = DEFAULT_BATCH_SIZE
|
|
88
|
+
@flush_interval = DEFAULT_FLUSH_INTERVAL
|
|
89
|
+
@job_queue = DEFAULT_JOB_QUEUE
|
|
90
|
+
@logger = default_logger
|
|
91
|
+
|
|
92
|
+
yield(self) if block_given?
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Validate the configuration
|
|
96
|
+
#
|
|
97
|
+
# @raise [ConfigurationError] if configuration is invalid
|
|
98
|
+
# @return [void]
|
|
99
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
100
|
+
def validate!
|
|
101
|
+
raise ConfigurationError, "public_key is required" if public_key.nil? || public_key.empty?
|
|
102
|
+
raise ConfigurationError, "secret_key is required" if secret_key.nil? || secret_key.empty?
|
|
103
|
+
raise ConfigurationError, "base_url cannot be empty" if base_url.nil? || base_url.empty?
|
|
104
|
+
raise ConfigurationError, "timeout must be positive" if timeout.nil? || timeout <= 0
|
|
105
|
+
raise ConfigurationError, "cache_ttl must be non-negative" if cache_ttl.nil? || cache_ttl.negative?
|
|
106
|
+
raise ConfigurationError, "cache_max_size must be positive" if cache_max_size.nil? || cache_max_size <= 0
|
|
107
|
+
|
|
108
|
+
if cache_lock_timeout.nil? || cache_lock_timeout <= 0
|
|
109
|
+
raise ConfigurationError,
|
|
110
|
+
"cache_lock_timeout must be positive"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
validate_cache_backend!
|
|
114
|
+
end
|
|
115
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
def default_logger
|
|
120
|
+
if defined?(Rails) && Rails.respond_to?(:logger)
|
|
121
|
+
Rails.logger
|
|
122
|
+
else
|
|
123
|
+
Logger.new($stdout, level: Logger::WARN)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def validate_cache_backend!
|
|
128
|
+
valid_backends = %i[memory rails]
|
|
129
|
+
return if valid_backends.include?(cache_backend)
|
|
130
|
+
|
|
131
|
+
raise ConfigurationError,
|
|
132
|
+
"cache_backend must be one of #{valid_backends.inspect}, got #{cache_backend.inspect}"
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|