langfuse-ruby 0.1.4 → 0.1.6
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/.github/workflows/ci.yml +11 -11
- data/.github/workflows/release.yml +8 -9
- data/.rubocop.yml +66 -0
- data/CHANGELOG.md +34 -1
- data/CLAUDE.md +100 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +7 -3
- data/Makefile +73 -0
- data/README.md +92 -9
- data/Rakefile +4 -2
- data/docs/FINAL_SUMMARY.md +11 -10
- data/docs/PUBLISH_GUIDE.md +2 -2
- data/docs/README.md +3 -3
- data/docs/RELEASE_CHECKLIST.md +44 -13
- data/examples/auto_flush_control.rb +3 -2
- data/examples/basic_tracing.rb +6 -5
- data/examples/connection_config_demo.rb +1 -0
- data/examples/event_usage.rb +3 -2
- data/examples/prompt_management.rb +3 -2
- data/examples/simplified_usage.rb +126 -0
- data/examples/url_encoding_demo.rb +57 -0
- data/langfuse-ruby.gemspec +6 -2
- data/lib/langfuse/client.rb +160 -3
- data/lib/langfuse/errors.rb +2 -0
- data/lib/langfuse/evaluation.rb +14 -12
- data/lib/langfuse/event.rb +21 -5
- data/lib/langfuse/generation.rb +155 -5
- data/lib/langfuse/null_objects.rb +74 -0
- data/lib/langfuse/observation_types.rb +61 -0
- data/lib/langfuse/prompt.rb +2 -2
- data/lib/langfuse/span.rb +162 -7
- data/lib/langfuse/trace.rb +152 -1
- data/lib/langfuse/utils.rb +7 -0
- data/lib/langfuse/version.rb +3 -1
- data/lib/langfuse.rb +128 -2
- data/scripts/release.sh +1 -1
- data/{test_offline.rb → scripts/test_offline.rb} +5 -4
- data/scripts/verify_release.rb +5 -4
- metadata +27 -9
- data/docs/TYPE_VALIDATION_TROUBLESHOOTING.md +0 -202
data/lib/langfuse/evaluation.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Langfuse
|
|
2
4
|
class Evaluation
|
|
3
5
|
attr_reader :id, :name, :value, :data_type, :comment, :trace_id, :observation_id, :created_at
|
|
@@ -84,10 +86,10 @@ module Langfuse
|
|
|
84
86
|
|
|
85
87
|
class ExactMatchEvaluator < BaseEvaluator
|
|
86
88
|
def initialize(name: 'exact_match', description: 'Exact match evaluator')
|
|
87
|
-
super
|
|
89
|
+
super
|
|
88
90
|
end
|
|
89
91
|
|
|
90
|
-
def evaluate(
|
|
92
|
+
def evaluate(_input, output, expected: nil, context: nil)
|
|
91
93
|
return create_score(value: 0, comment: 'No expected value provided') unless expected
|
|
92
94
|
|
|
93
95
|
score = output.to_s.strip == expected.to_s.strip ? 1 : 0
|
|
@@ -104,7 +106,7 @@ module Langfuse
|
|
|
104
106
|
@case_sensitive = case_sensitive
|
|
105
107
|
end
|
|
106
108
|
|
|
107
|
-
def evaluate(
|
|
109
|
+
def evaluate(_input, output, expected: nil, context: nil)
|
|
108
110
|
return create_score(value: 0, comment: 'No expected value provided') unless expected
|
|
109
111
|
|
|
110
112
|
output_str = @case_sensitive ? output.to_s : output.to_s.downcase
|
|
@@ -125,11 +127,11 @@ module Langfuse
|
|
|
125
127
|
@max_length = max_length
|
|
126
128
|
end
|
|
127
129
|
|
|
128
|
-
def evaluate(
|
|
130
|
+
def evaluate(_input, output, expected: nil, context: nil)
|
|
129
131
|
length = output.to_s.length
|
|
130
132
|
|
|
131
133
|
if @min_length && @max_length
|
|
132
|
-
score = length
|
|
134
|
+
score = length.between?(@min_length, @max_length) ? 1 : 0
|
|
133
135
|
comment = score == 1 ? "Length #{length} within range" : "Length #{length} outside range #{@min_length}-#{@max_length}"
|
|
134
136
|
elsif @min_length
|
|
135
137
|
score = length >= @min_length ? 1 : 0
|
|
@@ -156,7 +158,7 @@ module Langfuse
|
|
|
156
158
|
@pattern = pattern.is_a?(Regexp) ? pattern : Regexp.new(pattern)
|
|
157
159
|
end
|
|
158
160
|
|
|
159
|
-
def evaluate(
|
|
161
|
+
def evaluate(_input, output, expected: nil, context: nil)
|
|
160
162
|
match = @pattern.match(output.to_s)
|
|
161
163
|
score = match ? 1 : 0
|
|
162
164
|
|
|
@@ -169,10 +171,10 @@ module Langfuse
|
|
|
169
171
|
|
|
170
172
|
class SimilarityEvaluator < BaseEvaluator
|
|
171
173
|
def initialize(name: 'similarity', description: 'Similarity evaluator')
|
|
172
|
-
super
|
|
174
|
+
super
|
|
173
175
|
end
|
|
174
176
|
|
|
175
|
-
def evaluate(
|
|
177
|
+
def evaluate(_input, output, expected: nil, context: nil)
|
|
176
178
|
return create_score(value: 0, comment: 'No expected value provided') unless expected
|
|
177
179
|
|
|
178
180
|
# Simple character-based similarity (Levenshtein distance)
|
|
@@ -230,10 +232,10 @@ module Langfuse
|
|
|
230
232
|
def evaluate(input, output, expected: nil, context: nil)
|
|
231
233
|
# This is a placeholder for LLM-based evaluation
|
|
232
234
|
# In a real implementation, you would call an LLM API here
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
235
|
+
@prompt_template.gsub('{input}', input.to_s)
|
|
236
|
+
.gsub('{output}', output.to_s)
|
|
237
|
+
.gsub('{expected}', expected.to_s)
|
|
238
|
+
.gsub('{context}', context.to_s)
|
|
237
239
|
|
|
238
240
|
# Simulate LLM response (in real implementation, call actual LLM)
|
|
239
241
|
score = rand(0.0..1.0).round(2)
|
data/lib/langfuse/event.rb
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Langfuse
|
|
2
4
|
class Event
|
|
3
5
|
attr_reader :id, :trace_id, :name, :start_time, :input, :output, :metadata,
|
|
4
|
-
:level, :status_message, :parent_observation_id, :version, :client
|
|
6
|
+
:level, :status_message, :parent_observation_id, :version, :as_type, :client
|
|
5
7
|
|
|
6
8
|
def initialize(client:, trace_id:, name:, id: nil, start_time: nil, input: nil,
|
|
7
9
|
output: nil, metadata: nil, level: nil, status_message: nil,
|
|
8
|
-
parent_observation_id: nil, version: nil, **kwargs)
|
|
10
|
+
parent_observation_id: nil, version: nil, as_type: nil, **kwargs)
|
|
9
11
|
@client = client
|
|
10
12
|
@id = id || Utils.generate_id
|
|
11
13
|
@trace_id = trace_id
|
|
@@ -18,6 +20,7 @@ module Langfuse
|
|
|
18
20
|
@status_message = status_message
|
|
19
21
|
@parent_observation_id = parent_observation_id
|
|
20
22
|
@version = version
|
|
23
|
+
@as_type = validate_as_type(as_type)
|
|
21
24
|
@kwargs = kwargs
|
|
22
25
|
|
|
23
26
|
# Create the event
|
|
@@ -25,7 +28,7 @@ module Langfuse
|
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
def to_dict
|
|
28
|
-
{
|
|
31
|
+
data = {
|
|
29
32
|
id: @id,
|
|
30
33
|
trace_id: @trace_id,
|
|
31
34
|
name: @name,
|
|
@@ -37,11 +40,22 @@ module Langfuse
|
|
|
37
40
|
status_message: @status_message,
|
|
38
41
|
parent_observation_id: @parent_observation_id,
|
|
39
42
|
version: @version
|
|
40
|
-
}
|
|
43
|
+
}
|
|
44
|
+
data[:type] = @as_type if @as_type
|
|
45
|
+
data.merge(@kwargs).compact
|
|
41
46
|
end
|
|
42
47
|
|
|
43
48
|
private
|
|
44
49
|
|
|
50
|
+
def validate_as_type(type)
|
|
51
|
+
return nil if type.nil?
|
|
52
|
+
|
|
53
|
+
type_str = type.to_s
|
|
54
|
+
raise ValidationError, "Invalid observation type: #{type}. Valid types are: #{ObservationType::ALL.join(', ')}" unless ObservationType.valid?(type_str)
|
|
55
|
+
|
|
56
|
+
type_str
|
|
57
|
+
end
|
|
58
|
+
|
|
45
59
|
def create_event
|
|
46
60
|
data = {
|
|
47
61
|
id: @id,
|
|
@@ -55,7 +69,9 @@ module Langfuse
|
|
|
55
69
|
status_message: @status_message,
|
|
56
70
|
parent_observation_id: @parent_observation_id,
|
|
57
71
|
version: @version
|
|
58
|
-
}
|
|
72
|
+
}
|
|
73
|
+
data[:type] = @as_type if @as_type
|
|
74
|
+
data = data.merge(@kwargs).compact
|
|
59
75
|
|
|
60
76
|
@client.enqueue_event('event-create', data)
|
|
61
77
|
end
|
data/lib/langfuse/generation.rb
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Langfuse
|
|
2
4
|
class Generation
|
|
3
5
|
attr_reader :id, :trace_id, :name, :start_time, :end_time, :completion_start_time,
|
|
4
6
|
:model, :model_parameters, :input, :output, :usage, :metadata, :level,
|
|
5
|
-
:status_message, :parent_observation_id, :version, :client
|
|
7
|
+
:status_message, :parent_observation_id, :version, :as_type, :client
|
|
6
8
|
|
|
7
9
|
def initialize(client:, trace_id:, id: nil, name: nil, start_time: nil, end_time: nil,
|
|
8
10
|
completion_start_time: nil, model: nil, model_parameters: nil, input: nil,
|
|
9
11
|
output: nil, usage: nil, metadata: nil, level: nil, status_message: nil,
|
|
10
|
-
parent_observation_id: nil, version: nil, **kwargs)
|
|
12
|
+
parent_observation_id: nil, version: nil, as_type: nil, **kwargs)
|
|
11
13
|
@client = client
|
|
12
14
|
@id = id || Utils.generate_id
|
|
13
15
|
@trace_id = trace_id
|
|
@@ -25,6 +27,7 @@ module Langfuse
|
|
|
25
27
|
@status_message = status_message
|
|
26
28
|
@parent_observation_id = parent_observation_id
|
|
27
29
|
@version = version
|
|
30
|
+
@as_type = validate_as_type(as_type)
|
|
28
31
|
@kwargs = kwargs
|
|
29
32
|
|
|
30
33
|
# Create the generation
|
|
@@ -62,8 +65,9 @@ module Langfuse
|
|
|
62
65
|
self
|
|
63
66
|
end
|
|
64
67
|
|
|
68
|
+
# Create a child span
|
|
65
69
|
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)
|
|
70
|
+
metadata: nil, level: nil, status_message: nil, version: nil, as_type: nil, **kwargs)
|
|
67
71
|
@client.span(
|
|
68
72
|
trace_id: @trace_id,
|
|
69
73
|
name: name,
|
|
@@ -76,10 +80,12 @@ module Langfuse
|
|
|
76
80
|
status_message: status_message,
|
|
77
81
|
parent_observation_id: @id,
|
|
78
82
|
version: version,
|
|
83
|
+
as_type: as_type,
|
|
79
84
|
**kwargs
|
|
80
85
|
)
|
|
81
86
|
end
|
|
82
87
|
|
|
88
|
+
# Create a child generation
|
|
83
89
|
def generation(name: nil, start_time: nil, end_time: nil, completion_start_time: nil,
|
|
84
90
|
model: nil, model_parameters: nil, input: nil, output: nil, usage: nil,
|
|
85
91
|
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
|
@@ -103,6 +109,7 @@ module Langfuse
|
|
|
103
109
|
)
|
|
104
110
|
end
|
|
105
111
|
|
|
112
|
+
# Create a child event
|
|
106
113
|
def event(name:, start_time: nil, input: nil, output: nil, metadata: nil,
|
|
107
114
|
level: nil, status_message: nil, version: nil, **kwargs)
|
|
108
115
|
@client.event(
|
|
@@ -120,6 +127,138 @@ module Langfuse
|
|
|
120
127
|
)
|
|
121
128
|
end
|
|
122
129
|
|
|
130
|
+
# Convenience methods for enhanced observation types
|
|
131
|
+
|
|
132
|
+
# Create a child agent observation
|
|
133
|
+
def agent(name: nil, start_time: nil, end_time: nil, input: nil, output: nil,
|
|
134
|
+
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
|
135
|
+
span(
|
|
136
|
+
name: name,
|
|
137
|
+
start_time: start_time,
|
|
138
|
+
end_time: end_time,
|
|
139
|
+
input: input,
|
|
140
|
+
output: output,
|
|
141
|
+
metadata: metadata,
|
|
142
|
+
level: level,
|
|
143
|
+
status_message: status_message,
|
|
144
|
+
version: version,
|
|
145
|
+
as_type: ObservationType::AGENT,
|
|
146
|
+
**kwargs
|
|
147
|
+
)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Create a child tool observation
|
|
151
|
+
def tool(name: nil, start_time: nil, end_time: nil, input: nil, output: nil,
|
|
152
|
+
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
|
153
|
+
span(
|
|
154
|
+
name: name,
|
|
155
|
+
start_time: start_time,
|
|
156
|
+
end_time: end_time,
|
|
157
|
+
input: input,
|
|
158
|
+
output: output,
|
|
159
|
+
metadata: metadata,
|
|
160
|
+
level: level,
|
|
161
|
+
status_message: status_message,
|
|
162
|
+
version: version,
|
|
163
|
+
as_type: ObservationType::TOOL,
|
|
164
|
+
**kwargs
|
|
165
|
+
)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Create a child chain observation
|
|
169
|
+
def chain(name: nil, start_time: nil, end_time: nil, input: nil, output: nil,
|
|
170
|
+
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
|
171
|
+
span(
|
|
172
|
+
name: name,
|
|
173
|
+
start_time: start_time,
|
|
174
|
+
end_time: end_time,
|
|
175
|
+
input: input,
|
|
176
|
+
output: output,
|
|
177
|
+
metadata: metadata,
|
|
178
|
+
level: level,
|
|
179
|
+
status_message: status_message,
|
|
180
|
+
version: version,
|
|
181
|
+
as_type: ObservationType::CHAIN,
|
|
182
|
+
**kwargs
|
|
183
|
+
)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Create a child retriever observation
|
|
187
|
+
def retriever(name: nil, start_time: nil, end_time: nil, input: nil, output: nil,
|
|
188
|
+
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
|
189
|
+
span(
|
|
190
|
+
name: name,
|
|
191
|
+
start_time: start_time,
|
|
192
|
+
end_time: end_time,
|
|
193
|
+
input: input,
|
|
194
|
+
output: output,
|
|
195
|
+
metadata: metadata,
|
|
196
|
+
level: level,
|
|
197
|
+
status_message: status_message,
|
|
198
|
+
version: version,
|
|
199
|
+
as_type: ObservationType::RETRIEVER,
|
|
200
|
+
**kwargs
|
|
201
|
+
)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Create a child embedding observation
|
|
205
|
+
def embedding(name: nil, start_time: nil, end_time: nil, input: nil, output: nil,
|
|
206
|
+
model: nil, usage: nil, metadata: nil, level: nil, status_message: nil,
|
|
207
|
+
version: nil, **kwargs)
|
|
208
|
+
merged_metadata = (metadata || {}).merge(
|
|
209
|
+
{ model: model, usage: usage }.compact
|
|
210
|
+
)
|
|
211
|
+
span(
|
|
212
|
+
name: name,
|
|
213
|
+
start_time: start_time,
|
|
214
|
+
end_time: end_time,
|
|
215
|
+
input: input,
|
|
216
|
+
output: output,
|
|
217
|
+
metadata: merged_metadata.empty? ? nil : merged_metadata,
|
|
218
|
+
level: level,
|
|
219
|
+
status_message: status_message,
|
|
220
|
+
version: version,
|
|
221
|
+
as_type: ObservationType::EMBEDDING,
|
|
222
|
+
**kwargs
|
|
223
|
+
)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Create a child evaluator observation
|
|
227
|
+
def evaluator(name: nil, start_time: nil, end_time: nil, input: nil, output: nil,
|
|
228
|
+
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
|
229
|
+
span(
|
|
230
|
+
name: name,
|
|
231
|
+
start_time: start_time,
|
|
232
|
+
end_time: end_time,
|
|
233
|
+
input: input,
|
|
234
|
+
output: output,
|
|
235
|
+
metadata: metadata,
|
|
236
|
+
level: level,
|
|
237
|
+
status_message: status_message,
|
|
238
|
+
version: version,
|
|
239
|
+
as_type: ObservationType::EVALUATOR,
|
|
240
|
+
**kwargs
|
|
241
|
+
)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Create a child guardrail observation
|
|
245
|
+
def guardrail(name: nil, start_time: nil, end_time: nil, input: nil, output: nil,
|
|
246
|
+
metadata: nil, level: nil, status_message: nil, version: nil, **kwargs)
|
|
247
|
+
span(
|
|
248
|
+
name: name,
|
|
249
|
+
start_time: start_time,
|
|
250
|
+
end_time: end_time,
|
|
251
|
+
input: input,
|
|
252
|
+
output: output,
|
|
253
|
+
metadata: metadata,
|
|
254
|
+
level: level,
|
|
255
|
+
status_message: status_message,
|
|
256
|
+
version: version,
|
|
257
|
+
as_type: ObservationType::GUARDRAIL,
|
|
258
|
+
**kwargs
|
|
259
|
+
)
|
|
260
|
+
end
|
|
261
|
+
|
|
123
262
|
def score(name:, value:, data_type: nil, comment: nil, **kwargs)
|
|
124
263
|
@client.score(
|
|
125
264
|
observation_id: @id,
|
|
@@ -136,7 +275,7 @@ module Langfuse
|
|
|
136
275
|
end
|
|
137
276
|
|
|
138
277
|
def to_dict
|
|
139
|
-
{
|
|
278
|
+
data = {
|
|
140
279
|
id: @id,
|
|
141
280
|
trace_id: @trace_id,
|
|
142
281
|
name: @name,
|
|
@@ -153,11 +292,22 @@ module Langfuse
|
|
|
153
292
|
status_message: @status_message,
|
|
154
293
|
parent_observation_id: @parent_observation_id,
|
|
155
294
|
version: @version
|
|
156
|
-
}
|
|
295
|
+
}
|
|
296
|
+
data[:type] = @as_type if @as_type
|
|
297
|
+
data.merge(@kwargs).compact
|
|
157
298
|
end
|
|
158
299
|
|
|
159
300
|
private
|
|
160
301
|
|
|
302
|
+
def validate_as_type(type)
|
|
303
|
+
return nil if type.nil?
|
|
304
|
+
|
|
305
|
+
type_str = type.to_s
|
|
306
|
+
raise ValidationError, "Invalid observation type: #{type}. Valid types are: #{ObservationType::ALL.join(', ')}" unless ObservationType.valid?(type_str)
|
|
307
|
+
|
|
308
|
+
type_str
|
|
309
|
+
end
|
|
310
|
+
|
|
161
311
|
def create_generation
|
|
162
312
|
@client.enqueue_event('generation-create', to_dict)
|
|
163
313
|
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Langfuse
|
|
4
|
+
# NullGeneration provides a no-op generation object for graceful degradation.
|
|
5
|
+
# Used when Langfuse is unavailable or trace creation fails.
|
|
6
|
+
class NullGeneration
|
|
7
|
+
def update(**) = self
|
|
8
|
+
def end(**) = self
|
|
9
|
+
def span(**) = NullSpan.new
|
|
10
|
+
def generation(**) = NullGeneration.new
|
|
11
|
+
def event(**) = NullEvent.new
|
|
12
|
+
def agent(**) = NullSpan.new
|
|
13
|
+
def tool(**) = NullSpan.new
|
|
14
|
+
def chain(**) = NullSpan.new
|
|
15
|
+
def retriever(**) = NullSpan.new
|
|
16
|
+
def embedding(**) = NullSpan.new
|
|
17
|
+
def evaluator(**) = NullSpan.new
|
|
18
|
+
def guardrail(**) = NullSpan.new
|
|
19
|
+
def score(**) = nil
|
|
20
|
+
def get_url = nil
|
|
21
|
+
def to_dict = {}
|
|
22
|
+
def id = nil
|
|
23
|
+
def trace_id = nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# NullSpan provides a no-op span object for graceful degradation.
|
|
27
|
+
class NullSpan
|
|
28
|
+
def update(**) = self
|
|
29
|
+
def end(**) = self
|
|
30
|
+
def span(**) = NullSpan.new
|
|
31
|
+
def generation(**) = NullGeneration.new
|
|
32
|
+
def event(**) = NullEvent.new
|
|
33
|
+
def agent(**) = NullSpan.new
|
|
34
|
+
def tool(**) = NullSpan.new
|
|
35
|
+
def chain(**) = NullSpan.new
|
|
36
|
+
def retriever(**) = NullSpan.new
|
|
37
|
+
def embedding(**) = NullSpan.new
|
|
38
|
+
def evaluator(**) = NullSpan.new
|
|
39
|
+
def guardrail(**) = NullSpan.new
|
|
40
|
+
def score(**) = nil
|
|
41
|
+
def get_url = nil
|
|
42
|
+
def to_dict = {}
|
|
43
|
+
def id = nil
|
|
44
|
+
def trace_id = nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# NullEvent provides a no-op event object for graceful degradation.
|
|
48
|
+
class NullEvent
|
|
49
|
+
def to_dict = {}
|
|
50
|
+
def id = nil
|
|
51
|
+
def trace_id = nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# NullTrace provides a no-op trace object for graceful degradation.
|
|
55
|
+
# Used when Langfuse is unavailable or trace creation fails.
|
|
56
|
+
# Ensures calling code doesn't break when Langfuse has issues.
|
|
57
|
+
class NullTrace
|
|
58
|
+
def update(**) = self
|
|
59
|
+
def span(**) = NullSpan.new
|
|
60
|
+
def generation(**) = NullGeneration.new
|
|
61
|
+
def event(**) = NullEvent.new
|
|
62
|
+
def agent(**) = NullSpan.new
|
|
63
|
+
def tool(**) = NullSpan.new
|
|
64
|
+
def chain(**) = NullSpan.new
|
|
65
|
+
def retriever(**) = NullSpan.new
|
|
66
|
+
def embedding(**) = NullSpan.new
|
|
67
|
+
def evaluator(**) = NullSpan.new
|
|
68
|
+
def guardrail(**) = NullSpan.new
|
|
69
|
+
def score(**) = nil
|
|
70
|
+
def get_url = nil
|
|
71
|
+
def to_dict = {}
|
|
72
|
+
def id = nil
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Langfuse
|
|
4
|
+
# Valid observation types for Langfuse
|
|
5
|
+
# These types provide semantic meaning to observations in traces
|
|
6
|
+
module ObservationType
|
|
7
|
+
# Core observation types (existing)
|
|
8
|
+
SPAN = 'span'
|
|
9
|
+
GENERATION = 'generation'
|
|
10
|
+
EVENT = 'event'
|
|
11
|
+
|
|
12
|
+
# Enhanced observation types (new in 2025)
|
|
13
|
+
AGENT = 'agent' # Agent workflows and reasoning
|
|
14
|
+
TOOL = 'tool' # Tool/function calls
|
|
15
|
+
CHAIN = 'chain' # Chain operations (e.g., retrieval chains)
|
|
16
|
+
RETRIEVER = 'retriever' # Data retrieval (vector stores, databases)
|
|
17
|
+
EMBEDDING = 'embedding' # Embedding generation
|
|
18
|
+
EVALUATOR = 'evaluator' # Evaluation/scoring functions
|
|
19
|
+
GUARDRAIL = 'guardrail' # Safety filters and content moderation
|
|
20
|
+
|
|
21
|
+
# All valid observation types
|
|
22
|
+
ALL = [
|
|
23
|
+
SPAN,
|
|
24
|
+
GENERATION,
|
|
25
|
+
EVENT,
|
|
26
|
+
AGENT,
|
|
27
|
+
TOOL,
|
|
28
|
+
CHAIN,
|
|
29
|
+
RETRIEVER,
|
|
30
|
+
EMBEDDING,
|
|
31
|
+
EVALUATOR,
|
|
32
|
+
GUARDRAIL
|
|
33
|
+
].freeze
|
|
34
|
+
|
|
35
|
+
# Types that are aliases for span (use span-create/span-update events)
|
|
36
|
+
SPAN_BASED = [
|
|
37
|
+
SPAN,
|
|
38
|
+
AGENT,
|
|
39
|
+
TOOL,
|
|
40
|
+
CHAIN,
|
|
41
|
+
RETRIEVER,
|
|
42
|
+
EMBEDDING,
|
|
43
|
+
EVALUATOR,
|
|
44
|
+
GUARDRAIL
|
|
45
|
+
].freeze
|
|
46
|
+
|
|
47
|
+
# Validate if a type is valid
|
|
48
|
+
def self.valid?(type)
|
|
49
|
+
return true if type.nil? # nil is valid (defaults to base type)
|
|
50
|
+
|
|
51
|
+
ALL.include?(type.to_s)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Check if type uses span events
|
|
55
|
+
def self.span_based?(type)
|
|
56
|
+
return true if type.nil?
|
|
57
|
+
|
|
58
|
+
SPAN_BASED.include?(type.to_s)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
data/lib/langfuse/prompt.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Langfuse
|
|
2
4
|
class Prompt
|
|
3
5
|
attr_reader :id, :name, :version, :prompt, :config, :labels, :tags, :type, :created_at, :updated_at
|
|
@@ -148,8 +150,6 @@ module Langfuse
|
|
|
148
150
|
new(template: template, input_variables: variables)
|
|
149
151
|
end
|
|
150
152
|
|
|
151
|
-
private
|
|
152
|
-
|
|
153
153
|
def self.extract_variables(text)
|
|
154
154
|
variables = []
|
|
155
155
|
|