Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lib/langfuse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,13 @@ def propagate_attributes(user_id: nil, session_id: nil, metadata: nil, version:
#
# @param name [String] Score name (required)
# @param value [Numeric, Integer, String] Score value (type depends on data_type)
# @param id [String, nil] Score ID
# @param trace_id [String, nil] Trace ID to associate with the score
# @param session_id [String, nil] Session ID to associate with the score
# @param observation_id [String, nil] Observation ID to associate with the score
# @param comment [String, nil] Optional comment
# @param metadata [Hash, nil] Optional metadata hash
# @param environment [String, nil] Optional environment
# @param data_type [Symbol] Data type (:numeric, :boolean, :categorical)
# @return [void]
# @raise [ArgumentError] if validation fails
Expand All @@ -207,15 +210,18 @@ def propagate_attributes(user_id: nil, session_id: nil, metadata: nil, version:
# @example Categorical score
# Langfuse.create_score(name: "category", value: "high", trace_id: "abc123", data_type: :categorical)
# rubocop:disable Metrics/ParameterLists
def create_score(name:, value:, trace_id: nil, observation_id: nil, comment: nil, metadata: nil,
data_type: :numeric)
def create_score(name:, value:, id: nil, trace_id: nil, session_id: nil, observation_id: nil, comment: nil,
metadata: nil, environment: nil, data_type: :numeric)
client.create_score(
name: name,
value: value,
id: id,
trace_id: trace_id,
session_id: session_id,
observation_id: observation_id,
comment: comment,
metadata: metadata,
environment: environment,
data_type: data_type
)
end
Expand Down
12 changes: 10 additions & 2 deletions lib/langfuse/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -283,12 +283,17 @@ def dataset_run_url(dataset_id:, dataset_run_id:)

# Create a score event and queue it for batching
#
# You may only provide one of the following: trace_id (with optional observation_id), session_id, or dataset_run_id; observation_id requires a trace_id.
#
# @param name [String] Score name (required)
# @param value [Numeric, Integer, String] Score value (type depends on data_type)
# @param id [String, nil] Score ID
# @param trace_id [String, nil] Trace ID to associate with the score
# @param session_id [String, nil] Session ID to associate with the score
# @param observation_id [String, nil] Observation ID to associate with the score
# @param comment [String, nil] Optional comment
# @param metadata [Hash, nil] Optional metadata hash
# @param environment [String, nil] Optional environment
# @param data_type [Symbol] Data type (:numeric, :boolean, :categorical)
# @param dataset_run_id [String, nil] Optional dataset run ID to associate with the score
# @param config_id [String, nil] Optional score config ID
Expand All @@ -304,15 +309,18 @@ def dataset_run_url(dataset_id:, dataset_run_id:)
# @example Categorical score
# client.create_score(name: "category", value: "high", trace_id: "abc123", data_type: :categorical)
# rubocop:disable Metrics/ParameterLists
def create_score(name:, value:, trace_id: nil, observation_id: nil, comment: nil, metadata: nil,
data_type: :numeric, dataset_run_id: nil, config_id: nil)
def create_score(name:, value:, id: nil, trace_id: nil, session_id: nil, observation_id: nil, comment: nil,
metadata: nil, environment: nil, data_type: :numeric, dataset_run_id: nil, config_id: nil)
@score_client.create(
name: name,
value: value,
id: id,
trace_id: trace_id,
session_id: session_id,
observation_id: observation_id,
comment: comment,
metadata: metadata,
environment: environment,
data_type: data_type,
dataset_run_id: dataset_run_id,
config_id: config_id
Expand Down
25 changes: 18 additions & 7 deletions lib/langfuse/score_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,13 @@ def initialize(api_client:, config:)
#
# @param name [String] Score name (required)
# @param value [Numeric, Integer, String] Score value (type depends on data_type)
# @param id [String, nil] Score ID
# @param trace_id [String, nil] Trace ID to associate with the score
# @param session_id [String, nil] Session ID to associate with the score
# @param observation_id [String, nil] Observation ID to associate with the score
# @param comment [String, nil] Optional comment
# @param metadata [Hash, nil] Optional metadata hash
# @param environment [String, nil] Optional environment
# @param data_type [Symbol] Data type (:numeric, :boolean, :categorical)
# @param dataset_run_id [String, nil] Optional dataset run ID to associate with the score
# @param config_id [String, nil] Optional score config ID
Expand All @@ -70,19 +73,22 @@ def initialize(api_client:, config:)
# @example Categorical score
# create(name: "category", value: "high", trace_id: "abc123", data_type: :categorical)
# rubocop:disable Metrics/ParameterLists
def create(name:, value:, trace_id: nil, observation_id: nil, comment: nil, metadata: nil,
data_type: :numeric, dataset_run_id: nil, config_id: nil)
def create(name:, value:, id: nil, trace_id: nil, session_id: nil, observation_id: nil, comment: nil,
metadata: nil, environment: nil, data_type: :numeric, dataset_run_id: nil, config_id: nil)
Comment on lines +76 to +77
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing validation for mutually exclusive parameters. The documentation in lib/langfuse/client.rb:286 states that only one of trace_id, session_id, or dataset_run_id should be provided, but there's no code enforcing this constraint.

Suggested change
def create(name:, value:, id: nil, trace_id: nil, session_id: nil, observation_id: nil, comment: nil,
metadata: nil, environment: nil, data_type: :numeric, dataset_run_id: nil, config_id: nil)
def create(name:, value:, id: nil, trace_id: nil, session_id: nil, observation_id: nil, comment: nil,
metadata: nil, environment: nil, data_type: :numeric, dataset_run_id: nil, config_id: nil)
validate_name(name)
validate_score_identifiers(trace_id: trace_id, session_id: session_id, observation_id: observation_id, dataset_run_id: dataset_run_id)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

validate_name(name)
normalized_value = normalize_value(value, data_type)
data_type_str = Types::SCORE_DATA_TYPES[data_type] || raise(ArgumentError, "Invalid data_type: #{data_type}")

event = build_score_event(
name: name,
value: normalized_value,
id: id,
trace_id: trace_id,
session_id: session_id,
observation_id: observation_id,
comment: comment,
metadata: metadata,
environment: environment,
data_type: data_type_str,
dataset_run_id: dataset_run_id,
config_id: config_id
Expand Down Expand Up @@ -204,25 +210,30 @@ def shutdown
#
# @param name [String] Score name
# @param value [Object] Normalized score value
# @param id [String, nil] Score ID
# @param trace_id [String, nil] Trace ID
# @param session_id [String, nil] Session ID
# @param observation_id [String, nil] Observation ID
# @param comment [String, nil] Comment
# @param metadata [Hash, nil] Metadata
# @param environment [String, nil] Environment
# @param data_type [String] Data type string (NUMERIC, BOOLEAN, CATEGORICAL)
# @return [Hash] Event hash
# rubocop:disable Metrics/ParameterLists
def build_score_event(name:, value:, trace_id:, observation_id:, comment:, metadata:, data_type:,
dataset_run_id: nil, config_id: nil)
# rubocop:disable Metrics/ParameterLists, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def build_score_event(name:, value:, id:, trace_id:, session_id:, observation_id:, comment:, metadata:,
environment:, data_type:, dataset_run_id: nil, config_id: nil)
body = {
id: SecureRandom.uuid,
id: id || SecureRandom.uuid,
name: name,
value: value,
dataType: data_type
}
body[:traceId] = trace_id if trace_id
body[:sessionId] = session_id if session_id
body[:observationId] = observation_id if observation_id
body[:comment] = comment if comment
body[:metadata] = metadata if metadata
body[:environment] = environment if environment
body[:datasetRunId] = dataset_run_id if dataset_run_id
body[:configId] = config_id if config_id

Expand All @@ -233,7 +244,7 @@ def build_score_event(name:, value:, trace_id:, observation_id:, comment:, metad
body: body
}
end
# rubocop:enable Metrics/ParameterLists
# rubocop:enable Metrics/ParameterLists, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

# Normalize and validate score value based on data type
#
Expand Down
39 changes: 38 additions & 1 deletion spec/langfuse/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1434,10 +1434,13 @@ class << self
expect(score_client).to receive(:create).with(
name: "quality",
value: 0.85,
id: nil,
trace_id: "abc123",
session_id: nil,
observation_id: nil,
comment: nil,
metadata: nil,
environment: nil,
data_type: :numeric,
dataset_run_id: nil,
config_id: nil
Expand All @@ -1446,15 +1449,18 @@ class << self
client.create_score(name: "quality", value: 0.85, trace_id: "abc123")
end

it "passes all parameters to score_client" do
it "passes all parameters to score_client, identified by trace_id" do
score_client = client.instance_variable_get(:@score_client)
expect(score_client).to receive(:create).with(
name: "quality",
value: 0.85,
id: "my-score",
trace_id: "abc123",
session_id: nil,
observation_id: "def456",
comment: "High quality",
metadata: { source: "manual" },
environment: "production",
data_type: :boolean,
dataset_run_id: nil,
config_id: nil
Expand All @@ -1463,10 +1469,41 @@ class << self
client.create_score(
name: "quality",
value: 0.85,
id: "my-score",
trace_id: "abc123",
observation_id: "def456",
comment: "High quality",
metadata: { source: "manual" },
environment: "production",
data_type: :boolean
)
end

it "passes all parameters to score_client, identified by session_id" do
score_client = client.instance_variable_get(:@score_client)
expect(score_client).to receive(:create).with(
name: "quality",
value: 0.85,
id: "my-score",
trace_id: nil,
session_id: "ghi789",
observation_id: nil,
comment: "High quality",
metadata: { source: "manual" },
environment: "production",
data_type: :boolean,
dataset_run_id: nil,
config_id: nil
)

client.create_score(
name: "quality",
value: 0.85,
id: "my-score",
session_id: "ghi789",
comment: "High quality",
metadata: { source: "manual" },
environment: "production",
data_type: :boolean
)
end
Expand Down
30 changes: 27 additions & 3 deletions spec/langfuse/score_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@
score_client.flush
end

it "includes id when provided" do
expect(api_client).to receive(:send_batch).with(array_including(
hash_including(
body: hash_including(id: "my-score")
)
))

score_client.create(name: "quality", value: 0.85, id: "my-score")
score_client.flush
end

it "includes trace_id when provided" do
expect(api_client).to receive(:send_batch).with(array_including(
hash_including(
Expand All @@ -73,6 +84,17 @@
score_client.flush
end

it "includes session_id when provided" do
expect(api_client).to receive(:send_batch).with(array_including(
hash_including(
body: hash_including(sessionId: "ghi789")
)
))

score_client.create(name: "quality", value: 0.85, session_id: "ghi789")
score_client.flush
end

it "includes observation_id when provided" do
expect(api_client).to receive(:send_batch).with(array_including(
hash_including(
Expand All @@ -84,12 +106,13 @@
score_client.flush
end

it "includes comment and metadata when provided" do
it "includes comment and metadata and environment when provided" do
expect(api_client).to receive(:send_batch).with(array_including(
hash_including(
body: hash_including(
comment: "High quality",
metadata: { source: "manual" }
metadata: { source: "manual" },
environment: "production"
)
)
))
Expand All @@ -98,7 +121,8 @@
name: "quality",
value: 0.85,
comment: "High quality",
metadata: { source: "manual" }
metadata: { source: "manual" },
environment: "production"
)
score_client.flush
end
Expand Down