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.
@@ -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