langfuse-ruby 0.1.2 → 0.1.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 +4 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +1 -1
- data/README.md +111 -20
- data/docs/TYPE_VALIDATION_TROUBLESHOOTING.md +202 -0
- data/examples/auto_flush_control.rb +205 -0
- data/examples/basic_tracing.rb +0 -12
- data/examples/connection_config_demo.rb +15 -1
- data/examples/event_usage.rb +145 -0
- data/lib/langfuse/client.rb +161 -52
- data/lib/langfuse/event.rb +63 -0
- data/lib/langfuse/generation.rb +19 -40
- data/lib/langfuse/span.rb +17 -0
- data/lib/langfuse/trace.rb +17 -34
- data/lib/langfuse/utils.rb +23 -1
- data/lib/langfuse/version.rb +1 -1
- data/lib/langfuse.rb +4 -1
- data/test_offline.rb +93 -101
- metadata +6 -3
- data/.github/workflows/ci.yml +0 -47
@@ -10,6 +10,8 @@ puts "\n📋 默认配置信息:"
|
|
10
10
|
puts " 默认主机: #{Langfuse.configuration.host}"
|
11
11
|
puts " 默认超时: #{Langfuse.configuration.timeout}秒"
|
12
12
|
puts " 默认重试: #{Langfuse.configuration.retries}次"
|
13
|
+
puts " 默认刷新间隔: #{Langfuse.configuration.flush_interval}秒"
|
14
|
+
puts " 默认自动刷新: #{Langfuse.configuration.auto_flush}"
|
13
15
|
|
14
16
|
# 方法 1: 使用测试密钥创建客户端(仅用于演示)
|
15
17
|
puts "\n📝 方法 1: 直接参数配置"
|
@@ -17,7 +19,9 @@ puts '代码示例:'
|
|
17
19
|
puts 'client = Langfuse.new('
|
18
20
|
puts " public_key: 'pk-lf-your-public-key',"
|
19
21
|
puts " secret_key: 'sk-lf-your-secret-key',"
|
20
|
-
puts " host: 'https://us.cloud.langfuse.com'"
|
22
|
+
puts " host: 'https://us.cloud.langfuse.com',"
|
23
|
+
puts ' flush_interval: 10, # 每10秒刷新一次'
|
24
|
+
puts ' auto_flush: true # 启用自动刷新(默认)'
|
21
25
|
puts ')'
|
22
26
|
|
23
27
|
# 使用测试密钥创建客户端
|
@@ -31,6 +35,8 @@ puts '✅ 客户端配置成功'
|
|
31
35
|
puts " 主机: #{test_client.host}"
|
32
36
|
puts " 超时: #{test_client.timeout}秒"
|
33
37
|
puts " 重试: #{test_client.retries}次"
|
38
|
+
puts " 刷新间隔: #{test_client.flush_interval}秒"
|
39
|
+
puts " 自动刷新: #{test_client.auto_flush}"
|
34
40
|
|
35
41
|
# 方法 2: 全局配置
|
36
42
|
puts "\n📝 方法 2: 全局配置"
|
@@ -40,6 +46,8 @@ puts " config.public_key = 'pk-lf-your-public-key'"
|
|
40
46
|
puts " config.secret_key = 'sk-lf-your-secret-key'"
|
41
47
|
puts " config.host = 'https://us.cloud.langfuse.com'"
|
42
48
|
puts ' config.debug = true'
|
49
|
+
puts ' config.flush_interval = 10 # 每10秒刷新一次'
|
50
|
+
puts ' config.auto_flush = true # 启用自动刷新'
|
43
51
|
puts 'end'
|
44
52
|
|
45
53
|
Langfuse.configure do |config|
|
@@ -49,6 +57,8 @@ Langfuse.configure do |config|
|
|
49
57
|
config.debug = true
|
50
58
|
config.timeout = 60
|
51
59
|
config.retries = 5
|
60
|
+
config.flush_interval = 10
|
61
|
+
config.auto_flush = true
|
52
62
|
end
|
53
63
|
|
54
64
|
global_client = Langfuse.new
|
@@ -57,6 +67,8 @@ puts " 主机: #{global_client.host}"
|
|
57
67
|
puts " 调试模式: #{global_client.debug}"
|
58
68
|
puts " 超时: #{global_client.timeout}秒"
|
59
69
|
puts " 重试: #{global_client.retries}次"
|
70
|
+
puts " 刷新间隔: #{global_client.flush_interval}秒"
|
71
|
+
puts " 自动刷新: #{global_client.auto_flush}"
|
60
72
|
|
61
73
|
# 方法 3: 环境变量配置
|
62
74
|
puts "\n📝 方法 3: 环境变量配置"
|
@@ -64,6 +76,8 @@ puts '设置环境变量:'
|
|
64
76
|
puts "export LANGFUSE_PUBLIC_KEY='pk-lf-your-public-key'"
|
65
77
|
puts "export LANGFUSE_SECRET_KEY='sk-lf-your-secret-key'"
|
66
78
|
puts "export LANGFUSE_HOST='https://us.cloud.langfuse.com'"
|
79
|
+
puts 'export LANGFUSE_FLUSH_INTERVAL=10'
|
80
|
+
puts 'export LANGFUSE_AUTO_FLUSH=true'
|
67
81
|
puts ''
|
68
82
|
puts '然后使用:'
|
69
83
|
puts 'client = Langfuse.new'
|
@@ -0,0 +1,145 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'langfuse'
|
4
|
+
|
5
|
+
# Initialize the Langfuse client
|
6
|
+
client = Langfuse.new(
|
7
|
+
public_key: ENV['LANGFUSE_PUBLIC_KEY'],
|
8
|
+
secret_key: ENV['LANGFUSE_SECRET_KEY'],
|
9
|
+
host: ENV['LANGFUSE_HOST'] || 'https://cloud.langfuse.com'
|
10
|
+
)
|
11
|
+
|
12
|
+
puts '🎯 Starting event usage example...'
|
13
|
+
|
14
|
+
# Example 1: Create a trace and add events
|
15
|
+
puts "\n📝 Example 1: Creating events within a trace"
|
16
|
+
|
17
|
+
trace = client.trace(
|
18
|
+
name: 'user-workflow',
|
19
|
+
user_id: 'user-123',
|
20
|
+
session_id: 'session-456',
|
21
|
+
input: { action: 'start_workflow' }
|
22
|
+
)
|
23
|
+
|
24
|
+
puts "Created trace: #{trace.id}"
|
25
|
+
|
26
|
+
# Create a generic event
|
27
|
+
event1 = trace.event(
|
28
|
+
name: 'user_login',
|
29
|
+
input: { username: 'john_doe', login_method: 'oauth' },
|
30
|
+
output: { success: true, user_id: 'user-123' },
|
31
|
+
metadata: {
|
32
|
+
ip_address: '192.168.1.1',
|
33
|
+
user_agent: 'Mozilla/5.0...'
|
34
|
+
}
|
35
|
+
)
|
36
|
+
|
37
|
+
puts "Created event: #{event1.id}"
|
38
|
+
|
39
|
+
# Create another event with custom level
|
40
|
+
event2 = trace.event(
|
41
|
+
name: 'data_processing',
|
42
|
+
input: { data_size: 1024, format: 'json' },
|
43
|
+
output: { processed_records: 100, errors: 0 },
|
44
|
+
level: 'INFO',
|
45
|
+
metadata: {
|
46
|
+
processing_time_ms: 250,
|
47
|
+
memory_usage: '45MB'
|
48
|
+
}
|
49
|
+
)
|
50
|
+
|
51
|
+
puts "Created event: #{event2.id}"
|
52
|
+
|
53
|
+
# Example 2: Creating events from spans
|
54
|
+
puts "\n🔗 Example 2: Creating events from spans"
|
55
|
+
|
56
|
+
span = trace.span(
|
57
|
+
name: 'data-validation',
|
58
|
+
input: { data: 'raw_data' }
|
59
|
+
)
|
60
|
+
|
61
|
+
# Create an event within the span
|
62
|
+
validation_event = span.event(
|
63
|
+
name: 'validation_check',
|
64
|
+
input: { rules: %w[required format length] },
|
65
|
+
output: { valid: true, warnings: [] },
|
66
|
+
metadata: { validation_time_ms: 15 }
|
67
|
+
)
|
68
|
+
|
69
|
+
puts "Created span event: #{validation_event.id}"
|
70
|
+
|
71
|
+
# End the span
|
72
|
+
span.end(output: { validation_result: 'passed' })
|
73
|
+
|
74
|
+
# Example 3: Creating events from generations
|
75
|
+
puts "\n🤖 Example 3: Creating events from generations"
|
76
|
+
|
77
|
+
generation = trace.generation(
|
78
|
+
name: 'text-generation',
|
79
|
+
model: 'gpt-3.5-turbo',
|
80
|
+
input: [{ role: 'user', content: 'Hello, how are you?' }],
|
81
|
+
output: { content: 'I am doing well, thank you!' },
|
82
|
+
usage: { prompt_tokens: 12, completion_tokens: 8, total_tokens: 20 }
|
83
|
+
)
|
84
|
+
|
85
|
+
# Create an event for content filtering
|
86
|
+
filter_event = generation.event(
|
87
|
+
name: 'content_filter',
|
88
|
+
input: { text: 'I am doing well, thank you!' },
|
89
|
+
output: {
|
90
|
+
filtered: false,
|
91
|
+
flags: [],
|
92
|
+
confidence: 0.95
|
93
|
+
},
|
94
|
+
metadata: {
|
95
|
+
filter_model: 'content-filter-v1',
|
96
|
+
processing_time_ms: 5
|
97
|
+
}
|
98
|
+
)
|
99
|
+
|
100
|
+
puts "Created generation event: #{filter_event.id}"
|
101
|
+
|
102
|
+
# Example 4: Error event
|
103
|
+
puts "\n❌ Example 4: Error event"
|
104
|
+
|
105
|
+
error_event = trace.event(
|
106
|
+
name: 'error_occurred',
|
107
|
+
input: { operation: 'database_query' },
|
108
|
+
output: {
|
109
|
+
error: true,
|
110
|
+
message: 'Connection timeout',
|
111
|
+
code: 'DB_TIMEOUT'
|
112
|
+
},
|
113
|
+
level: 'ERROR',
|
114
|
+
status_message: 'Database connection failed',
|
115
|
+
metadata: {
|
116
|
+
retry_count: 3,
|
117
|
+
last_attempt: Time.now.iso8601
|
118
|
+
}
|
119
|
+
)
|
120
|
+
|
121
|
+
puts "Created error event: #{error_event.id}"
|
122
|
+
|
123
|
+
puts "Trace URL: #{trace.get_url}"
|
124
|
+
|
125
|
+
# Example 5: Direct event creation via client
|
126
|
+
puts "\n🎯 Example 5: Direct event creation via client"
|
127
|
+
|
128
|
+
direct_event = client.event(
|
129
|
+
trace_id: trace.id,
|
130
|
+
name: 'audit_log',
|
131
|
+
input: { action: 'workflow_completed', user_id: 'user-123' },
|
132
|
+
output: { logged: true, log_id: 'audit-789' },
|
133
|
+
metadata: {
|
134
|
+
timestamp: Time.now.iso8601,
|
135
|
+
source: 'audit_system'
|
136
|
+
}
|
137
|
+
)
|
138
|
+
|
139
|
+
puts "Created direct event: #{direct_event.id}"
|
140
|
+
|
141
|
+
puts "\n✅ Event usage example completed!"
|
142
|
+
puts 'Check the Langfuse dashboard to see all events in the trace.'
|
143
|
+
|
144
|
+
# Flush events to ensure they're sent
|
145
|
+
client.flush
|
data/lib/langfuse/client.rb
CHANGED
@@ -6,22 +6,29 @@ require 'concurrent'
|
|
6
6
|
|
7
7
|
module Langfuse
|
8
8
|
class Client
|
9
|
-
attr_reader :public_key, :secret_key, :host, :debug, :timeout, :retries
|
9
|
+
attr_reader :public_key, :secret_key, :host, :debug, :timeout, :retries, :flush_interval, :auto_flush
|
10
10
|
|
11
|
-
def initialize(public_key: nil, secret_key: nil, host: nil, debug: false, timeout: 30, retries: 3
|
11
|
+
def initialize(public_key: nil, secret_key: nil, host: nil, debug: false, timeout: 30, retries: 3,
|
12
|
+
flush_interval: nil, auto_flush: nil)
|
12
13
|
@public_key = public_key || ENV['LANGFUSE_PUBLIC_KEY'] || Langfuse.configuration.public_key
|
13
14
|
@secret_key = secret_key || ENV['LANGFUSE_SECRET_KEY'] || Langfuse.configuration.secret_key
|
14
15
|
@host = host || ENV['LANGFUSE_HOST'] || Langfuse.configuration.host
|
15
16
|
@debug = debug || Langfuse.configuration.debug
|
16
17
|
@timeout = timeout || Langfuse.configuration.timeout
|
17
18
|
@retries = retries || Langfuse.configuration.retries
|
19
|
+
@flush_interval = flush_interval || ENV['LANGFUSE_FLUSH_INTERVAL']&.to_i || Langfuse.configuration.flush_interval
|
20
|
+
@auto_flush = if auto_flush.nil?
|
21
|
+
ENV['LANGFUSE_AUTO_FLUSH'] == 'false' ? false : Langfuse.configuration.auto_flush
|
22
|
+
else
|
23
|
+
auto_flush
|
24
|
+
end
|
18
25
|
|
19
26
|
raise AuthenticationError, 'Public key is required' unless @public_key
|
20
27
|
raise AuthenticationError, 'Secret key is required' unless @secret_key
|
21
28
|
|
22
29
|
@connection = build_connection
|
23
30
|
@event_queue = Concurrent::Array.new
|
24
|
-
@flush_thread = start_flush_thread
|
31
|
+
@flush_thread = start_flush_thread if @auto_flush
|
25
32
|
end
|
26
33
|
|
27
34
|
# Trace operations
|
@@ -91,6 +98,25 @@ module Langfuse
|
|
91
98
|
)
|
92
99
|
end
|
93
100
|
|
101
|
+
# Event operations
|
102
|
+
def event(trace_id:, name:, start_time: nil, input: nil, output: nil, metadata: nil,
|
103
|
+
level: nil, status_message: nil, parent_observation_id: nil, version: nil, **kwargs)
|
104
|
+
Event.new(
|
105
|
+
client: self,
|
106
|
+
trace_id: trace_id,
|
107
|
+
name: name,
|
108
|
+
start_time: start_time,
|
109
|
+
input: input,
|
110
|
+
output: output,
|
111
|
+
metadata: metadata,
|
112
|
+
level: level,
|
113
|
+
status_message: status_message,
|
114
|
+
parent_observation_id: parent_observation_id,
|
115
|
+
version: version,
|
116
|
+
**kwargs
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
94
120
|
# Prompt operations
|
95
121
|
def get_prompt(name, version: nil, label: nil, cache_ttl_seconds: 60)
|
96
122
|
cache_key = "prompt:#{name}:#{version}:#{label}"
|
@@ -158,29 +184,22 @@ module Langfuse
|
|
158
184
|
enqueue_event('score-create', data)
|
159
185
|
end
|
160
186
|
|
161
|
-
# HTTP methods
|
162
|
-
def get(path, params = {})
|
163
|
-
request(:get, path, params: params)
|
164
|
-
end
|
165
|
-
|
166
|
-
def post(path, data = {})
|
167
|
-
request(:post, path, json: data)
|
168
|
-
end
|
169
|
-
|
170
|
-
def put(path, data = {})
|
171
|
-
request(:put, path, json: data)
|
172
|
-
end
|
173
|
-
|
174
|
-
def delete(path, params = {})
|
175
|
-
request(:delete, path, params: params)
|
176
|
-
end
|
177
|
-
|
178
|
-
def patch(path, data = {})
|
179
|
-
request(:patch, path, json: data)
|
180
|
-
end
|
181
|
-
|
182
187
|
# Event queue management
|
183
188
|
def enqueue_event(type, body)
|
189
|
+
# 验证事件类型是否有效
|
190
|
+
valid_types = %w[
|
191
|
+
trace-create
|
192
|
+
generation-create generation-update
|
193
|
+
span-create span-update
|
194
|
+
event-create
|
195
|
+
score-create
|
196
|
+
]
|
197
|
+
|
198
|
+
unless valid_types.include?(type)
|
199
|
+
puts "Warning: Invalid event type '#{type}'. Skipping event." if @debug
|
200
|
+
return
|
201
|
+
end
|
202
|
+
|
184
203
|
event = {
|
185
204
|
id: Utils.generate_id,
|
186
205
|
type: type,
|
@@ -198,32 +217,99 @@ module Langfuse
|
|
198
217
|
events = @event_queue.shift(@event_queue.length)
|
199
218
|
return if events.empty?
|
200
219
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
220
|
+
send_batch(events)
|
221
|
+
end
|
222
|
+
|
223
|
+
def shutdown
|
224
|
+
@flush_thread&.kill if @auto_flush
|
225
|
+
flush unless @event_queue.empty?
|
226
|
+
end
|
227
|
+
|
228
|
+
private
|
229
|
+
|
230
|
+
def debug_event_data(events)
|
231
|
+
return unless @debug
|
232
|
+
|
233
|
+
puts "\n=== Event Data Debug Information ==="
|
234
|
+
events.each_with_index do |event, index|
|
235
|
+
puts "Event #{index + 1}:"
|
236
|
+
puts " ID: #{event[:id]}"
|
237
|
+
puts " Type: #{event[:type]}"
|
238
|
+
puts " Timestamp: #{event[:timestamp]}"
|
239
|
+
puts " Body keys: #{event[:body]&.keys || 'nil'}"
|
240
|
+
|
241
|
+
# 检查常见的问题
|
242
|
+
puts ' ⚠️ WARNING: Empty or nil type!' if event[:type].nil? || event[:type].to_s.empty?
|
243
|
+
|
244
|
+
puts ' ⚠️ WARNING: Empty body!' if event[:body].nil?
|
245
|
+
|
246
|
+
puts ' ---'
|
247
|
+
end
|
248
|
+
puts "=== End Debug Information ===\n"
|
249
|
+
end
|
250
|
+
|
251
|
+
def send_batch(events)
|
252
|
+
# 调试事件数据
|
253
|
+
debug_event_data(events)
|
254
|
+
|
255
|
+
# 验证事件数据
|
256
|
+
valid_events = events.select do |event|
|
257
|
+
if event[:type].nil? || event[:type].to_s.empty?
|
258
|
+
puts "Warning: Event with empty type detected, skipping: #{event[:id]}" if @debug
|
259
|
+
false
|
260
|
+
elsif event[:body].nil?
|
261
|
+
puts "Warning: Event with empty body detected, skipping: #{event[:id]}" if @debug
|
262
|
+
false
|
263
|
+
else
|
264
|
+
true
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
if valid_events.empty?
|
269
|
+
puts 'No valid events to send' if @debug
|
270
|
+
return
|
271
|
+
end
|
272
|
+
|
273
|
+
batch_data = build_batch_data(valid_events)
|
274
|
+
puts "Sending batch data: #{batch_data}" if @debug
|
209
275
|
|
210
276
|
begin
|
211
277
|
response = post('/api/public/ingestion', batch_data)
|
212
|
-
puts "Flushed #{
|
278
|
+
puts "Flushed #{valid_events.length} events" if @debug
|
279
|
+
response
|
213
280
|
rescue StandardError => e
|
214
281
|
puts "Failed to flush events: #{e.message}" if @debug
|
215
282
|
# Re-queue events on failure
|
216
|
-
|
283
|
+
valid_events.each { |event| @event_queue << event }
|
217
284
|
raise
|
218
285
|
end
|
219
286
|
end
|
220
287
|
|
221
|
-
def
|
222
|
-
|
223
|
-
|
288
|
+
def build_batch_data(events)
|
289
|
+
{
|
290
|
+
batch: events,
|
291
|
+
metadata: Utils.deep_camelize_keys({
|
292
|
+
batch_size: events.length,
|
293
|
+
sdk_name: 'langfuse-ruby',
|
294
|
+
sdk_version: Langfuse::VERSION
|
295
|
+
})
|
296
|
+
}
|
224
297
|
end
|
225
298
|
|
226
|
-
|
299
|
+
def start_flush_thread
|
300
|
+
return unless @auto_flush
|
301
|
+
|
302
|
+
Thread.new do
|
303
|
+
loop do
|
304
|
+
sleep(@flush_interval) # Configurable flush interval
|
305
|
+
begin
|
306
|
+
flush unless @event_queue.empty?
|
307
|
+
rescue StandardError => e
|
308
|
+
puts "Error in flush thread: #{e.message}" if @debug
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
227
313
|
|
228
314
|
def build_connection
|
229
315
|
Faraday.new(url: @host) do |conn|
|
@@ -248,6 +334,27 @@ module Langfuse
|
|
248
334
|
end
|
249
335
|
end
|
250
336
|
|
337
|
+
# HTTP methods
|
338
|
+
def get(path, params = {})
|
339
|
+
request(:get, path, params: params)
|
340
|
+
end
|
341
|
+
|
342
|
+
def post(path, data = {})
|
343
|
+
request(:post, path, json: data)
|
344
|
+
end
|
345
|
+
|
346
|
+
def put(path, data = {})
|
347
|
+
request(:put, path, json: data)
|
348
|
+
end
|
349
|
+
|
350
|
+
def delete(path, params = {})
|
351
|
+
request(:delete, path, params: params)
|
352
|
+
end
|
353
|
+
|
354
|
+
def patch(path, data = {})
|
355
|
+
request(:patch, path, json: data)
|
356
|
+
end
|
357
|
+
|
251
358
|
def request(method, path, params: {}, json: nil)
|
252
359
|
retries_left = @retries
|
253
360
|
|
@@ -293,25 +400,27 @@ module Langfuse
|
|
293
400
|
when 429
|
294
401
|
raise RateLimitError, "Rate limit exceeded: #{response.body}"
|
295
402
|
when 400..499
|
296
|
-
|
403
|
+
# 为 400 错误提供更详细的错误信息
|
404
|
+
error_details = ''
|
405
|
+
if response.body.is_a?(Hash) && response.body['error']
|
406
|
+
error_details = "\nError details: #{response.body['error']}"
|
407
|
+
elsif response.body.is_a?(String)
|
408
|
+
error_details = "\nError details: #{response.body}"
|
409
|
+
end
|
410
|
+
|
411
|
+
# 特别处理类型验证错误
|
412
|
+
unless response.body.to_s.include?('invalid_union') || response.body.to_s.include?('discriminator')
|
413
|
+
raise ValidationError, "Client error (#{response.status}): #{response.body}#{error_details}"
|
414
|
+
end
|
415
|
+
|
416
|
+
raise ValidationError,
|
417
|
+
"Event type validation failed (#{response.status}): The event type or structure is invalid. Please check the event format.#{error_details}"
|
418
|
+
|
297
419
|
when 500..599
|
298
420
|
raise APIError, "Server error (#{response.status}): #{response.body}"
|
299
421
|
else
|
300
422
|
raise APIError, "Unexpected response (#{response.status}): #{response.body}"
|
301
423
|
end
|
302
424
|
end
|
303
|
-
|
304
|
-
def start_flush_thread
|
305
|
-
Thread.new do
|
306
|
-
loop do
|
307
|
-
sleep(5) # Flush every 5 seconds
|
308
|
-
begin
|
309
|
-
flush unless @event_queue.empty?
|
310
|
-
rescue StandardError => e
|
311
|
-
puts "Error in flush thread: #{e.message}" if @debug
|
312
|
-
end
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
425
|
end
|
317
426
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Langfuse
|
2
|
+
class Event
|
3
|
+
attr_reader :id, :trace_id, :name, :start_time, :input, :output, :metadata,
|
4
|
+
:level, :status_message, :parent_observation_id, :version, :client
|
5
|
+
|
6
|
+
def initialize(client:, trace_id:, name:, id: nil, start_time: nil, input: nil,
|
7
|
+
output: nil, metadata: nil, level: nil, status_message: nil,
|
8
|
+
parent_observation_id: nil, version: nil, **kwargs)
|
9
|
+
@client = client
|
10
|
+
@id = id || Utils.generate_id
|
11
|
+
@trace_id = trace_id
|
12
|
+
@name = name
|
13
|
+
@start_time = start_time || Utils.current_timestamp
|
14
|
+
@input = input
|
15
|
+
@output = output
|
16
|
+
@metadata = metadata || {}
|
17
|
+
@level = level
|
18
|
+
@status_message = status_message
|
19
|
+
@parent_observation_id = parent_observation_id
|
20
|
+
@version = version
|
21
|
+
@kwargs = kwargs
|
22
|
+
|
23
|
+
# Create the event
|
24
|
+
create_event
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_dict
|
28
|
+
{
|
29
|
+
id: @id,
|
30
|
+
trace_id: @trace_id,
|
31
|
+
name: @name,
|
32
|
+
start_time: @start_time,
|
33
|
+
input: @input,
|
34
|
+
output: @output,
|
35
|
+
metadata: @metadata,
|
36
|
+
level: @level,
|
37
|
+
status_message: @status_message,
|
38
|
+
parent_observation_id: @parent_observation_id,
|
39
|
+
version: @version
|
40
|
+
}.merge(@kwargs).compact
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def create_event
|
46
|
+
data = {
|
47
|
+
id: @id,
|
48
|
+
trace_id: @trace_id,
|
49
|
+
name: @name,
|
50
|
+
start_time: @start_time,
|
51
|
+
input: @input,
|
52
|
+
output: @output,
|
53
|
+
metadata: @metadata,
|
54
|
+
level: @level,
|
55
|
+
status_message: @status_message,
|
56
|
+
parent_observation_id: @parent_observation_id,
|
57
|
+
version: @version
|
58
|
+
}.merge(@kwargs).compact
|
59
|
+
|
60
|
+
@client.enqueue_event('event-create', data)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/langfuse/generation.rb
CHANGED
@@ -103,6 +103,23 @@ module Langfuse
|
|
103
103
|
)
|
104
104
|
end
|
105
105
|
|
106
|
+
def event(name:, start_time: nil, input: nil, output: nil, metadata: nil,
|
107
|
+
level: nil, status_message: nil, version: nil, **kwargs)
|
108
|
+
@client.event(
|
109
|
+
trace_id: @trace_id,
|
110
|
+
name: name,
|
111
|
+
start_time: start_time,
|
112
|
+
input: input,
|
113
|
+
output: output,
|
114
|
+
metadata: metadata,
|
115
|
+
level: level,
|
116
|
+
status_message: status_message,
|
117
|
+
parent_observation_id: @id,
|
118
|
+
version: version,
|
119
|
+
**kwargs
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
106
123
|
def score(name:, value:, data_type: nil, comment: nil, **kwargs)
|
107
124
|
@client.score(
|
108
125
|
observation_id: @id,
|
@@ -142,49 +159,11 @@ module Langfuse
|
|
142
159
|
private
|
143
160
|
|
144
161
|
def create_generation
|
145
|
-
|
146
|
-
id: @id,
|
147
|
-
trace_id: @trace_id,
|
148
|
-
name: @name,
|
149
|
-
start_time: @start_time,
|
150
|
-
end_time: @end_time,
|
151
|
-
completion_start_time: @completion_start_time,
|
152
|
-
model: @model,
|
153
|
-
model_parameters: @model_parameters,
|
154
|
-
input: @input,
|
155
|
-
output: @output,
|
156
|
-
usage: @usage,
|
157
|
-
metadata: @metadata,
|
158
|
-
level: @level,
|
159
|
-
status_message: @status_message,
|
160
|
-
parent_observation_id: @parent_observation_id,
|
161
|
-
version: @version
|
162
|
-
}.merge(@kwargs).compact
|
163
|
-
|
164
|
-
@client.enqueue_event('generation-create', data)
|
162
|
+
@client.enqueue_event('generation-create', to_dict)
|
165
163
|
end
|
166
164
|
|
167
165
|
def update_generation
|
168
|
-
|
169
|
-
id: @id,
|
170
|
-
trace_id: @trace_id,
|
171
|
-
name: @name,
|
172
|
-
start_time: @start_time,
|
173
|
-
end_time: @end_time,
|
174
|
-
completion_start_time: @completion_start_time,
|
175
|
-
model: @model,
|
176
|
-
model_parameters: @model_parameters,
|
177
|
-
input: @input,
|
178
|
-
output: @output,
|
179
|
-
usage: @usage,
|
180
|
-
metadata: @metadata,
|
181
|
-
level: @level,
|
182
|
-
status_message: @status_message,
|
183
|
-
parent_observation_id: @parent_observation_id,
|
184
|
-
version: @version
|
185
|
-
}.merge(@kwargs).compact
|
186
|
-
|
187
|
-
@client.enqueue_event('generation-update', data)
|
166
|
+
@client.enqueue_event('generation-update', to_dict)
|
188
167
|
end
|
189
168
|
end
|
190
169
|
end
|
data/lib/langfuse/span.rb
CHANGED
@@ -91,6 +91,23 @@ module Langfuse
|
|
91
91
|
)
|
92
92
|
end
|
93
93
|
|
94
|
+
def event(name:, start_time: nil, input: nil, output: nil, metadata: nil,
|
95
|
+
level: nil, status_message: nil, version: nil, **kwargs)
|
96
|
+
@client.event(
|
97
|
+
trace_id: @trace_id,
|
98
|
+
name: name,
|
99
|
+
start_time: start_time,
|
100
|
+
input: input,
|
101
|
+
output: output,
|
102
|
+
metadata: metadata,
|
103
|
+
level: level,
|
104
|
+
status_message: status_message,
|
105
|
+
parent_observation_id: @id,
|
106
|
+
version: version,
|
107
|
+
**kwargs
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
94
111
|
def score(name:, value:, data_type: nil, comment: nil, **kwargs)
|
95
112
|
@client.score(
|
96
113
|
observation_id: @id,
|