langfuse-ruby 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/.github/workflows/ci.yml +47 -0
- data/.github/workflows/release.yml +51 -0
- data/.gitignore +81 -0
- data/CHANGELOG.md +49 -0
- data/FINAL_SUMMARY.md +191 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +102 -0
- data/LICENSE +21 -0
- data/PROJECT_SUMMARY.md +263 -0
- data/PUBLISH_GUIDE.md +300 -0
- data/README.md +436 -0
- data/RELEASE_CHECKLIST.md +130 -0
- data/Rakefile +23 -0
- data/examples/basic_tracing.rb +196 -0
- data/examples/prompt_management.rb +283 -0
- data/langfuse-ruby.gemspec +51 -0
- data/lib/langfuse/client.rb +278 -0
- data/lib/langfuse/errors.rb +9 -0
- data/lib/langfuse/evaluation.rb +267 -0
- data/lib/langfuse/generation.rb +190 -0
- data/lib/langfuse/prompt.rb +209 -0
- data/lib/langfuse/span.rb +166 -0
- data/lib/langfuse/trace.rb +155 -0
- data/lib/langfuse/utils.rb +41 -0
- data/lib/langfuse/version.rb +3 -0
- data/lib/langfuse.rb +40 -0
- data/scripts/release.sh +120 -0
- data/scripts/verify_release.rb +139 -0
- data/test_basic.rb +183 -0
- data/test_offline.rb +329 -0
- metadata +232 -0
@@ -0,0 +1,190 @@
|
|
1
|
+
module Langfuse
|
2
|
+
class Generation
|
3
|
+
attr_reader :id, :trace_id, :name, :start_time, :end_time, :completion_start_time,
|
4
|
+
:model, :model_parameters, :input, :output, :usage, :metadata, :level,
|
5
|
+
:status_message, :parent_observation_id, :version, :client
|
6
|
+
|
7
|
+
def initialize(client:, trace_id:, id: nil, name: nil, start_time: nil, end_time: nil,
|
8
|
+
completion_start_time: nil, model: nil, model_parameters: nil, input: nil,
|
9
|
+
output: nil, usage: nil, metadata: nil, level: nil, status_message: nil,
|
10
|
+
parent_observation_id: nil, version: nil, **kwargs)
|
11
|
+
@client = client
|
12
|
+
@id = id || Utils.generate_id
|
13
|
+
@trace_id = trace_id
|
14
|
+
@name = name
|
15
|
+
@start_time = start_time
|
16
|
+
@end_time = end_time
|
17
|
+
@completion_start_time = completion_start_time
|
18
|
+
@model = model
|
19
|
+
@model_parameters = model_parameters || {}
|
20
|
+
@input = input
|
21
|
+
@output = output
|
22
|
+
@usage = usage || {}
|
23
|
+
@metadata = metadata || {}
|
24
|
+
@level = level
|
25
|
+
@status_message = status_message
|
26
|
+
@parent_observation_id = parent_observation_id
|
27
|
+
@version = version
|
28
|
+
@kwargs = kwargs
|
29
|
+
|
30
|
+
# Create the generation
|
31
|
+
create_generation
|
32
|
+
end
|
33
|
+
|
34
|
+
def update(name: nil, end_time: nil, completion_start_time: nil, model: nil,
|
35
|
+
model_parameters: nil, input: nil, output: nil, usage: nil, metadata: nil,
|
36
|
+
level: nil, status_message: nil, version: nil, **kwargs)
|
37
|
+
@name = name if name
|
38
|
+
@end_time = end_time if end_time
|
39
|
+
@completion_start_time = completion_start_time if completion_start_time
|
40
|
+
@model = model if model
|
41
|
+
@model_parameters.merge!(model_parameters) if model_parameters
|
42
|
+
@input = input if input
|
43
|
+
@output = output if output
|
44
|
+
@usage.merge!(usage) if usage
|
45
|
+
@metadata.merge!(metadata) if metadata
|
46
|
+
@level = level if level
|
47
|
+
@status_message = status_message if status_message
|
48
|
+
@version = version if version
|
49
|
+
@kwargs.merge!(kwargs)
|
50
|
+
|
51
|
+
update_generation
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def end(output: nil, end_time: nil, usage: nil, **kwargs)
|
56
|
+
@end_time = end_time || Utils.current_timestamp
|
57
|
+
@output = output if output
|
58
|
+
@usage.merge!(usage) if usage
|
59
|
+
@kwargs.merge!(kwargs)
|
60
|
+
|
61
|
+
update_generation
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
def span(name: nil, start_time: nil, end_time: nil, input: nil, output: nil,
|
66
|
+
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
67
|
+
@client.span(
|
68
|
+
trace_id: @trace_id,
|
69
|
+
name: name,
|
70
|
+
start_time: start_time,
|
71
|
+
end_time: end_time,
|
72
|
+
input: input,
|
73
|
+
output: output,
|
74
|
+
metadata: metadata,
|
75
|
+
level: level,
|
76
|
+
status_message: status_message,
|
77
|
+
parent_observation_id: @id,
|
78
|
+
version: version,
|
79
|
+
**kwargs
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def generation(name: nil, start_time: nil, end_time: nil, completion_start_time: nil,
|
84
|
+
model: nil, model_parameters: nil, input: nil, output: nil, usage: nil,
|
85
|
+
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
86
|
+
@client.generation(
|
87
|
+
trace_id: @trace_id,
|
88
|
+
name: name,
|
89
|
+
start_time: start_time,
|
90
|
+
end_time: end_time,
|
91
|
+
completion_start_time: completion_start_time,
|
92
|
+
model: model,
|
93
|
+
model_parameters: model_parameters,
|
94
|
+
input: input,
|
95
|
+
output: output,
|
96
|
+
usage: usage,
|
97
|
+
metadata: metadata,
|
98
|
+
level: level,
|
99
|
+
status_message: status_message,
|
100
|
+
parent_observation_id: @id,
|
101
|
+
version: version,
|
102
|
+
**kwargs
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
def score(name:, value:, data_type: nil, comment: nil, **kwargs)
|
107
|
+
@client.score(
|
108
|
+
observation_id: @id,
|
109
|
+
name: name,
|
110
|
+
value: value,
|
111
|
+
data_type: data_type,
|
112
|
+
comment: comment,
|
113
|
+
**kwargs
|
114
|
+
)
|
115
|
+
end
|
116
|
+
|
117
|
+
def get_url
|
118
|
+
"#{@client.host}/trace/#{@trace_id}?observation=#{@id}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def to_dict
|
122
|
+
{
|
123
|
+
id: @id,
|
124
|
+
trace_id: @trace_id,
|
125
|
+
name: @name,
|
126
|
+
start_time: @start_time,
|
127
|
+
end_time: @end_time,
|
128
|
+
completion_start_time: @completion_start_time,
|
129
|
+
model: @model,
|
130
|
+
model_parameters: @model_parameters,
|
131
|
+
input: @input,
|
132
|
+
output: @output,
|
133
|
+
usage: @usage,
|
134
|
+
metadata: @metadata,
|
135
|
+
level: @level,
|
136
|
+
status_message: @status_message,
|
137
|
+
parent_observation_id: @parent_observation_id,
|
138
|
+
version: @version
|
139
|
+
}.merge(@kwargs).compact
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
|
144
|
+
def create_generation
|
145
|
+
data = {
|
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)
|
165
|
+
end
|
166
|
+
|
167
|
+
def update_generation
|
168
|
+
data = {
|
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)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module Langfuse
|
2
|
+
class Prompt
|
3
|
+
attr_reader :id, :name, :version, :prompt, :config, :labels, :tags, :type, :created_at, :updated_at
|
4
|
+
|
5
|
+
def initialize(data)
|
6
|
+
@data = data.is_a?(Hash) ? Utils.deep_symbolize_keys(data) : data
|
7
|
+
|
8
|
+
@id = @data[:id]
|
9
|
+
@name = @data[:name]
|
10
|
+
@version = @data[:version]
|
11
|
+
@prompt = @data[:prompt]
|
12
|
+
@config = @data[:config] || {}
|
13
|
+
@labels = @data[:labels] || []
|
14
|
+
@tags = @data[:tags] || []
|
15
|
+
@type = @data[:type]
|
16
|
+
@created_at = @data[:created_at]
|
17
|
+
@updated_at = @data[:updated_at]
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_langchain_prompt
|
21
|
+
# Convert Langfuse prompt format to LangChain format
|
22
|
+
case @type
|
23
|
+
when 'text'
|
24
|
+
text_to_langchain_prompt
|
25
|
+
when 'chat'
|
26
|
+
chat_to_langchain_prompt
|
27
|
+
else
|
28
|
+
raise ValidationError, "Unsupported prompt type: #{@type}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def compile(variables = {})
|
33
|
+
# Compile prompt with variables
|
34
|
+
case @type
|
35
|
+
when 'text'
|
36
|
+
compile_text_prompt(variables)
|
37
|
+
when 'chat'
|
38
|
+
compile_chat_prompt(variables)
|
39
|
+
else
|
40
|
+
raise ValidationError, "Unsupported prompt type: #{@type}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_dict
|
45
|
+
{
|
46
|
+
id: @id,
|
47
|
+
name: @name,
|
48
|
+
version: @version,
|
49
|
+
prompt: @prompt,
|
50
|
+
config: @config,
|
51
|
+
labels: @labels,
|
52
|
+
tags: @tags,
|
53
|
+
type: @type,
|
54
|
+
created_at: @created_at,
|
55
|
+
updated_at: @updated_at
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def text_to_langchain_prompt
|
62
|
+
# Convert text prompt to LangChain PromptTemplate format
|
63
|
+
{
|
64
|
+
_type: "prompt",
|
65
|
+
input_variables: extract_variables(@prompt),
|
66
|
+
template: @prompt
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def chat_to_langchain_prompt
|
71
|
+
# Convert chat prompt to LangChain ChatPromptTemplate format
|
72
|
+
messages = @prompt.map do |message|
|
73
|
+
{
|
74
|
+
_type: "#{message[:role]}_message",
|
75
|
+
content: message[:content],
|
76
|
+
input_variables: extract_variables(message[:content])
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
{
|
81
|
+
_type: "chat",
|
82
|
+
messages: messages,
|
83
|
+
input_variables: messages.flat_map { |m| m[:input_variables] }.uniq
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def compile_text_prompt(variables)
|
88
|
+
compiled = @prompt.dup
|
89
|
+
variables.each do |key, value|
|
90
|
+
compiled.gsub!("{{#{key}}}", value.to_s)
|
91
|
+
compiled.gsub!("{#{key}}", value.to_s)
|
92
|
+
end
|
93
|
+
compiled
|
94
|
+
end
|
95
|
+
|
96
|
+
def compile_chat_prompt(variables)
|
97
|
+
@prompt.map do |message|
|
98
|
+
compiled_content = message[:content].dup
|
99
|
+
variables.each do |key, value|
|
100
|
+
compiled_content.gsub!("{{#{key}}}", value.to_s)
|
101
|
+
compiled_content.gsub!("{#{key}}", value.to_s)
|
102
|
+
end
|
103
|
+
|
104
|
+
{
|
105
|
+
role: message[:role],
|
106
|
+
content: compiled_content
|
107
|
+
}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def extract_variables(text)
|
112
|
+
# Extract variables from template text (supports {{var}} and {var} formats)
|
113
|
+
variables = []
|
114
|
+
|
115
|
+
# Match {{variable}} format
|
116
|
+
text.scan(/\{\{(\w+)\}\}/) do |match|
|
117
|
+
variables << match[0]
|
118
|
+
end
|
119
|
+
|
120
|
+
# Match {variable} format
|
121
|
+
text.scan(/\{(\w+)\}/) do |match|
|
122
|
+
variables << match[0] unless variables.include?(match[0])
|
123
|
+
end
|
124
|
+
|
125
|
+
variables
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class PromptTemplate
|
130
|
+
attr_reader :template, :input_variables
|
131
|
+
|
132
|
+
def initialize(template:, input_variables: [])
|
133
|
+
@template = template
|
134
|
+
@input_variables = input_variables
|
135
|
+
end
|
136
|
+
|
137
|
+
def format(variables = {})
|
138
|
+
compiled = @template.dup
|
139
|
+
variables.each do |key, value|
|
140
|
+
compiled.gsub!("{{#{key}}}", value.to_s)
|
141
|
+
compiled.gsub!("{#{key}}", value.to_s)
|
142
|
+
end
|
143
|
+
compiled
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.from_template(template)
|
147
|
+
variables = extract_variables(template)
|
148
|
+
new(template: template, input_variables: variables)
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def self.extract_variables(text)
|
154
|
+
variables = []
|
155
|
+
|
156
|
+
# Match {{variable}} format
|
157
|
+
text.scan(/\{\{(\w+)\}\}/) do |match|
|
158
|
+
variables << match[0]
|
159
|
+
end
|
160
|
+
|
161
|
+
# Match {variable} format
|
162
|
+
text.scan(/\{(\w+)\}/) do |match|
|
163
|
+
variables << match[0] unless variables.include?(match[0])
|
164
|
+
end
|
165
|
+
|
166
|
+
variables
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class ChatPromptTemplate
|
171
|
+
attr_reader :messages, :input_variables
|
172
|
+
|
173
|
+
def initialize(messages:, input_variables: [])
|
174
|
+
@messages = messages
|
175
|
+
@input_variables = input_variables
|
176
|
+
end
|
177
|
+
|
178
|
+
def format(variables = {})
|
179
|
+
@messages.map do |message|
|
180
|
+
compiled_content = message[:content].dup
|
181
|
+
variables.each do |key, value|
|
182
|
+
compiled_content.gsub!("{{#{key}}}", value.to_s)
|
183
|
+
compiled_content.gsub!("{#{key}}", value.to_s)
|
184
|
+
end
|
185
|
+
|
186
|
+
{
|
187
|
+
role: message[:role],
|
188
|
+
content: compiled_content
|
189
|
+
}
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def self.from_messages(messages)
|
194
|
+
input_variables = []
|
195
|
+
|
196
|
+
messages.each do |message|
|
197
|
+
message[:content].scan(/\{\{(\w+)\}\}/) do |match|
|
198
|
+
input_variables << match[0] unless input_variables.include?(match[0])
|
199
|
+
end
|
200
|
+
|
201
|
+
message[:content].scan(/\{(\w+)\}/) do |match|
|
202
|
+
input_variables << match[0] unless input_variables.include?(match[0])
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
new(messages: messages, input_variables: input_variables)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module Langfuse
|
2
|
+
class Span
|
3
|
+
attr_reader :id, :trace_id, :name, :start_time, :end_time, :input, :output,
|
4
|
+
:metadata, :level, :status_message, :parent_observation_id, :version, :client
|
5
|
+
|
6
|
+
def initialize(client:, trace_id:, id: nil, name: nil, start_time: nil, end_time: nil,
|
7
|
+
input: nil, 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
|
14
|
+
@end_time = end_time
|
15
|
+
@input = input
|
16
|
+
@output = output
|
17
|
+
@metadata = metadata || {}
|
18
|
+
@level = level
|
19
|
+
@status_message = status_message
|
20
|
+
@parent_observation_id = parent_observation_id
|
21
|
+
@version = version
|
22
|
+
@kwargs = kwargs
|
23
|
+
|
24
|
+
# Create the span
|
25
|
+
create_span
|
26
|
+
end
|
27
|
+
|
28
|
+
def update(name: nil, end_time: nil, input: nil, output: nil, metadata: nil,
|
29
|
+
level: nil, status_message: nil, version: nil, **kwargs)
|
30
|
+
@name = name if name
|
31
|
+
@end_time = end_time if end_time
|
32
|
+
@input = input if input
|
33
|
+
@output = output if output
|
34
|
+
@metadata.merge!(metadata) if metadata
|
35
|
+
@level = level if level
|
36
|
+
@status_message = status_message if status_message
|
37
|
+
@version = version if version
|
38
|
+
@kwargs.merge!(kwargs)
|
39
|
+
|
40
|
+
update_span
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def end(output: nil, end_time: nil, **kwargs)
|
45
|
+
@end_time = end_time || Utils.current_timestamp
|
46
|
+
@output = output if output
|
47
|
+
@kwargs.merge!(kwargs)
|
48
|
+
|
49
|
+
update_span
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def span(name: nil, start_time: nil, end_time: nil, input: nil, output: nil,
|
54
|
+
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
55
|
+
@client.span(
|
56
|
+
trace_id: @trace_id,
|
57
|
+
name: name,
|
58
|
+
start_time: start_time,
|
59
|
+
end_time: end_time,
|
60
|
+
input: input,
|
61
|
+
output: output,
|
62
|
+
metadata: metadata,
|
63
|
+
level: level,
|
64
|
+
status_message: status_message,
|
65
|
+
parent_observation_id: @id,
|
66
|
+
version: version,
|
67
|
+
**kwargs
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def generation(name: nil, start_time: nil, end_time: nil, completion_start_time: nil,
|
72
|
+
model: nil, model_parameters: nil, input: nil, output: nil, usage: nil,
|
73
|
+
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
74
|
+
@client.generation(
|
75
|
+
trace_id: @trace_id,
|
76
|
+
name: name,
|
77
|
+
start_time: start_time,
|
78
|
+
end_time: end_time,
|
79
|
+
completion_start_time: completion_start_time,
|
80
|
+
model: model,
|
81
|
+
model_parameters: model_parameters,
|
82
|
+
input: input,
|
83
|
+
output: output,
|
84
|
+
usage: usage,
|
85
|
+
metadata: metadata,
|
86
|
+
level: level,
|
87
|
+
status_message: status_message,
|
88
|
+
parent_observation_id: @id,
|
89
|
+
version: version,
|
90
|
+
**kwargs
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def score(name:, value:, data_type: nil, comment: nil, **kwargs)
|
95
|
+
@client.score(
|
96
|
+
observation_id: @id,
|
97
|
+
name: name,
|
98
|
+
value: value,
|
99
|
+
data_type: data_type,
|
100
|
+
comment: comment,
|
101
|
+
**kwargs
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def get_url
|
106
|
+
"#{@client.host}/trace/#{@trace_id}?observation=#{@id}"
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_dict
|
110
|
+
{
|
111
|
+
id: @id,
|
112
|
+
trace_id: @trace_id,
|
113
|
+
name: @name,
|
114
|
+
start_time: @start_time,
|
115
|
+
end_time: @end_time,
|
116
|
+
input: @input,
|
117
|
+
output: @output,
|
118
|
+
metadata: @metadata,
|
119
|
+
level: @level,
|
120
|
+
status_message: @status_message,
|
121
|
+
parent_observation_id: @parent_observation_id,
|
122
|
+
version: @version
|
123
|
+
}.merge(@kwargs).compact
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def create_span
|
129
|
+
data = {
|
130
|
+
id: @id,
|
131
|
+
trace_id: @trace_id,
|
132
|
+
name: @name,
|
133
|
+
start_time: @start_time,
|
134
|
+
end_time: @end_time,
|
135
|
+
input: @input,
|
136
|
+
output: @output,
|
137
|
+
metadata: @metadata,
|
138
|
+
level: @level,
|
139
|
+
status_message: @status_message,
|
140
|
+
parent_observation_id: @parent_observation_id,
|
141
|
+
version: @version
|
142
|
+
}.merge(@kwargs).compact
|
143
|
+
|
144
|
+
@client.enqueue_event('span-create', data)
|
145
|
+
end
|
146
|
+
|
147
|
+
def update_span
|
148
|
+
data = {
|
149
|
+
id: @id,
|
150
|
+
trace_id: @trace_id,
|
151
|
+
name: @name,
|
152
|
+
start_time: @start_time,
|
153
|
+
end_time: @end_time,
|
154
|
+
input: @input,
|
155
|
+
output: @output,
|
156
|
+
metadata: @metadata,
|
157
|
+
level: @level,
|
158
|
+
status_message: @status_message,
|
159
|
+
parent_observation_id: @parent_observation_id,
|
160
|
+
version: @version
|
161
|
+
}.merge(@kwargs).compact
|
162
|
+
|
163
|
+
@client.enqueue_event('span-update', data)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module Langfuse
|
2
|
+
class Trace
|
3
|
+
attr_reader :id, :name, :user_id, :session_id, :version, :release, :input, :output,
|
4
|
+
:metadata, :tags, :timestamp, :client
|
5
|
+
|
6
|
+
def initialize(client:, id:, name: nil, user_id: nil, session_id: nil, version: nil,
|
7
|
+
release: nil, input: nil, output: nil, metadata: nil, tags: nil,
|
8
|
+
timestamp: nil, **kwargs)
|
9
|
+
@client = client
|
10
|
+
@id = id
|
11
|
+
@name = name
|
12
|
+
@user_id = user_id
|
13
|
+
@session_id = session_id
|
14
|
+
@version = version
|
15
|
+
@release = release
|
16
|
+
@input = input
|
17
|
+
@output = output
|
18
|
+
@metadata = metadata || {}
|
19
|
+
@tags = tags || []
|
20
|
+
@timestamp = timestamp
|
21
|
+
@kwargs = kwargs
|
22
|
+
|
23
|
+
# Create the trace
|
24
|
+
create_trace
|
25
|
+
end
|
26
|
+
|
27
|
+
def update(name: nil, user_id: nil, session_id: nil, version: nil, release: nil,
|
28
|
+
input: nil, output: nil, metadata: nil, tags: nil, **kwargs)
|
29
|
+
@name = name if name
|
30
|
+
@user_id = user_id if user_id
|
31
|
+
@session_id = session_id if session_id
|
32
|
+
@version = version if version
|
33
|
+
@release = release if release
|
34
|
+
@input = input if input
|
35
|
+
@output = output if output
|
36
|
+
@metadata.merge!(metadata) if metadata
|
37
|
+
@tags.concat(tags) if tags
|
38
|
+
@kwargs.merge!(kwargs)
|
39
|
+
|
40
|
+
update_trace
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def span(name: nil, start_time: nil, end_time: nil, input: nil, output: nil,
|
45
|
+
metadata: nil, level: nil, status_message: nil, parent_observation_id: nil,
|
46
|
+
version: nil, **kwargs)
|
47
|
+
@client.span(
|
48
|
+
trace_id: @id,
|
49
|
+
name: name,
|
50
|
+
start_time: start_time,
|
51
|
+
end_time: end_time,
|
52
|
+
input: input,
|
53
|
+
output: output,
|
54
|
+
metadata: metadata,
|
55
|
+
level: level,
|
56
|
+
status_message: status_message,
|
57
|
+
parent_observation_id: parent_observation_id,
|
58
|
+
version: version,
|
59
|
+
**kwargs
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
def generation(name: nil, start_time: nil, end_time: nil, completion_start_time: nil,
|
64
|
+
model: nil, model_parameters: nil, input: nil, output: nil, usage: nil,
|
65
|
+
metadata: nil, level: nil, status_message: nil, parent_observation_id: nil,
|
66
|
+
version: nil, **kwargs)
|
67
|
+
@client.generation(
|
68
|
+
trace_id: @id,
|
69
|
+
name: name,
|
70
|
+
start_time: start_time,
|
71
|
+
end_time: end_time,
|
72
|
+
completion_start_time: completion_start_time,
|
73
|
+
model: model,
|
74
|
+
model_parameters: model_parameters,
|
75
|
+
input: input,
|
76
|
+
output: output,
|
77
|
+
usage: usage,
|
78
|
+
metadata: metadata,
|
79
|
+
level: level,
|
80
|
+
status_message: status_message,
|
81
|
+
parent_observation_id: parent_observation_id,
|
82
|
+
version: version,
|
83
|
+
**kwargs
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def score(name:, value:, data_type: nil, comment: nil, **kwargs)
|
88
|
+
@client.score(
|
89
|
+
trace_id: @id,
|
90
|
+
name: name,
|
91
|
+
value: value,
|
92
|
+
data_type: data_type,
|
93
|
+
comment: comment,
|
94
|
+
**kwargs
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
def get_url
|
99
|
+
"#{@client.host}/trace/#{@id}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_dict
|
103
|
+
{
|
104
|
+
id: @id,
|
105
|
+
name: @name,
|
106
|
+
user_id: @user_id,
|
107
|
+
session_id: @session_id,
|
108
|
+
version: @version,
|
109
|
+
release: @release,
|
110
|
+
input: @input,
|
111
|
+
output: @output,
|
112
|
+
metadata: @metadata,
|
113
|
+
tags: @tags,
|
114
|
+
timestamp: @timestamp
|
115
|
+
}.merge(@kwargs).compact
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def create_trace
|
121
|
+
data = {
|
122
|
+
id: @id,
|
123
|
+
name: @name,
|
124
|
+
user_id: @user_id,
|
125
|
+
session_id: @session_id,
|
126
|
+
version: @version,
|
127
|
+
release: @release,
|
128
|
+
input: @input,
|
129
|
+
output: @output,
|
130
|
+
metadata: @metadata,
|
131
|
+
tags: @tags,
|
132
|
+
timestamp: @timestamp
|
133
|
+
}.merge(@kwargs).compact
|
134
|
+
|
135
|
+
@client.enqueue_event('trace-create', data)
|
136
|
+
end
|
137
|
+
|
138
|
+
def update_trace
|
139
|
+
data = {
|
140
|
+
id: @id,
|
141
|
+
name: @name,
|
142
|
+
user_id: @user_id,
|
143
|
+
session_id: @session_id,
|
144
|
+
version: @version,
|
145
|
+
release: @release,
|
146
|
+
input: @input,
|
147
|
+
output: @output,
|
148
|
+
metadata: @metadata,
|
149
|
+
tags: @tags
|
150
|
+
}.merge(@kwargs).compact
|
151
|
+
|
152
|
+
@client.enqueue_event('trace-update', data)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|