From eb44b124ef83b0dd81c05734e7b204a40b021446 Mon Sep 17 00:00:00 2001 From: Igor Artemenko Date: Tue, 10 Feb 2026 16:33:59 +0000 Subject: [PATCH 1/4] Let users include session_id and environment when creating scores --- lib/langfuse.rb | 8 ++++++-- lib/langfuse/client.rb | 8 ++++++-- lib/langfuse/score_client.rb | 20 ++++++++++++++------ spec/langfuse/client_spec.rb | 6 ++++++ spec/langfuse/score_client_spec.rb | 19 ++++++++++++++++--- 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/lib/langfuse.rb b/lib/langfuse.rb index 6697dc8..2b76efe 100644 --- a/lib/langfuse.rb +++ b/lib/langfuse.rb @@ -191,9 +191,11 @@ 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 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 @@ -207,15 +209,17 @@ 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:, 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, trace_id: trace_id, + session_id: session_id, observation_id: observation_id, comment: comment, metadata: metadata, + environment: environment, data_type: data_type ) end diff --git a/lib/langfuse/client.rb b/lib/langfuse/client.rb index fc201e7..a59fdc7 100644 --- a/lib/langfuse/client.rb +++ b/lib/langfuse/client.rb @@ -286,9 +286,11 @@ def dataset_run_url(dataset_id:, dataset_run_id:) # @param name [String] Score name (required) # @param value [Numeric, Integer, String] Score value (type depends on data_type) # @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 @@ -304,15 +306,17 @@ 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:, 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, 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 diff --git a/lib/langfuse/score_client.rb b/lib/langfuse/score_client.rb index b69fee9..9a9bb99 100644 --- a/lib/langfuse/score_client.rb +++ b/lib/langfuse/score_client.rb @@ -52,9 +52,11 @@ def initialize(api_client:, config:) # @param name [String] Score name (required) # @param value [Numeric, Integer, String] Score value (type depends on data_type) # @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 @@ -70,8 +72,8 @@ 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:, 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) normalized_value = normalize_value(value, data_type) data_type_str = Types::SCORE_DATA_TYPES[data_type] || raise(ArgumentError, "Invalid data_type: #{data_type}") @@ -80,9 +82,11 @@ def create(name:, value:, trace_id: nil, observation_id: nil, comment: nil, meta name: name, value: normalized_value, 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 @@ -205,14 +209,16 @@ def shutdown # @param name [String] Score name # @param value [Object] Normalized score value # @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:, trace_id:, session_id:, observation_id:, comment:, metadata:, environment:, + data_type:, dataset_run_id: nil, config_id: nil) body = { id: SecureRandom.uuid, name: name, @@ -220,9 +226,11 @@ def build_score_event(name:, value:, trace_id:, observation_id:, comment:, metad 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 @@ -233,7 +241,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 # diff --git a/spec/langfuse/client_spec.rb b/spec/langfuse/client_spec.rb index 10ebba4..47a7582 100644 --- a/spec/langfuse/client_spec.rb +++ b/spec/langfuse/client_spec.rb @@ -1435,9 +1435,11 @@ class << self name: "quality", value: 0.85, 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 @@ -1452,9 +1454,11 @@ class << self name: "quality", value: 0.85, trace_id: "abc123", + session_id: "ghi789", observation_id: "def456", comment: "High quality", metadata: { source: "manual" }, + environment: "production", data_type: :boolean, dataset_run_id: nil, config_id: nil @@ -1464,9 +1468,11 @@ class << self name: "quality", value: 0.85, trace_id: "abc123", + session_id: "ghi789", observation_id: "def456", comment: "High quality", metadata: { source: "manual" }, + environment: "production", data_type: :boolean ) end diff --git a/spec/langfuse/score_client_spec.rb b/spec/langfuse/score_client_spec.rb index 4528445..261e408 100644 --- a/spec/langfuse/score_client_spec.rb +++ b/spec/langfuse/score_client_spec.rb @@ -73,6 +73,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( @@ -84,12 +95,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" ) ) )) @@ -98,7 +110,8 @@ name: "quality", value: 0.85, comment: "High quality", - metadata: { source: "manual" } + metadata: { source: "manual" }, + environment: "production" ) score_client.flush end From a21c80a01a5efe07c456143bad5f59a46c060fd0 Mon Sep 17 00:00:00 2001 From: Igor Artemenko Date: Tue, 10 Feb 2026 18:53:08 +0000 Subject: [PATCH 2/4] Let users create scores with explicit IDs --- lib/langfuse/client.rb | 6 ++++-- lib/langfuse/score_client.rb | 13 ++++++++----- spec/langfuse/client_spec.rb | 3 +++ spec/langfuse/score_client_spec.rb | 11 +++++++++++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/langfuse/client.rb b/lib/langfuse/client.rb index a59fdc7..fa2aca7 100644 --- a/lib/langfuse/client.rb +++ b/lib/langfuse/client.rb @@ -285,6 +285,7 @@ def dataset_run_url(dataset_id:, dataset_run_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 @@ -306,11 +307,12 @@ 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, session_id: nil, observation_id: nil, comment: nil, metadata: nil, - environment: 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, diff --git a/lib/langfuse/score_client.rb b/lib/langfuse/score_client.rb index 9a9bb99..8dccfb6 100644 --- a/lib/langfuse/score_client.rb +++ b/lib/langfuse/score_client.rb @@ -51,6 +51,7 @@ 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 @@ -72,8 +73,8 @@ 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, 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) normalized_value = normalize_value(value, data_type) data_type_str = Types::SCORE_DATA_TYPES[data_type] || raise(ArgumentError, "Invalid data_type: #{data_type}") @@ -81,6 +82,7 @@ def create(name:, value:, trace_id: nil, session_id: nil, observation_id: nil, c event = build_score_event( name: name, value: normalized_value, + id: id, trace_id: trace_id, session_id: session_id, observation_id: observation_id, @@ -208,6 +210,7 @@ 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 @@ -217,10 +220,10 @@ def shutdown # @param data_type [String] Data type string (NUMERIC, BOOLEAN, CATEGORICAL) # @return [Hash] Event hash # rubocop:disable Metrics/ParameterLists, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity - def build_score_event(name:, value:, trace_id:, session_id:, observation_id:, comment:, metadata:, environment:, - data_type:, dataset_run_id: nil, config_id: nil) + 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 diff --git a/spec/langfuse/client_spec.rb b/spec/langfuse/client_spec.rb index 47a7582..f2b9e9d 100644 --- a/spec/langfuse/client_spec.rb +++ b/spec/langfuse/client_spec.rb @@ -1434,6 +1434,7 @@ 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, @@ -1453,6 +1454,7 @@ class << self expect(score_client).to receive(:create).with( name: "quality", value: 0.85, + id: "my-score", trace_id: "abc123", session_id: "ghi789", observation_id: "def456", @@ -1467,6 +1469,7 @@ class << self client.create_score( name: "quality", value: 0.85, + id: "my-score", trace_id: "abc123", session_id: "ghi789", observation_id: "def456", diff --git a/spec/langfuse/score_client_spec.rb b/spec/langfuse/score_client_spec.rb index 261e408..f82c46d 100644 --- a/spec/langfuse/score_client_spec.rb +++ b/spec/langfuse/score_client_spec.rb @@ -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( From 0f96a4687e4f370a04a473e60f461a4eb0153950 Mon Sep 17 00:00:00 2001 From: Igor Artemenko Date: Tue, 10 Feb 2026 19:04:16 +0000 Subject: [PATCH 3/4] Clarify requirements for setting different IDs --- lib/langfuse/client.rb | 2 ++ spec/langfuse/client_spec.rb | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/langfuse/client.rb b/lib/langfuse/client.rb index fa2aca7..b879f43 100644 --- a/lib/langfuse/client.rb +++ b/lib/langfuse/client.rb @@ -283,6 +283,8 @@ 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 diff --git a/spec/langfuse/client_spec.rb b/spec/langfuse/client_spec.rb index f2b9e9d..3637d7a 100644 --- a/spec/langfuse/client_spec.rb +++ b/spec/langfuse/client_spec.rb @@ -1449,14 +1449,14 @@ 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: "ghi789", + session_id: nil, observation_id: "def456", comment: "High quality", metadata: { source: "manual" }, @@ -1471,7 +1471,6 @@ class << self value: 0.85, id: "my-score", trace_id: "abc123", - session_id: "ghi789", observation_id: "def456", comment: "High quality", metadata: { source: "manual" }, @@ -1479,6 +1478,35 @@ class << self 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 end describe "#score_active_observation" do From cf591e6a03d7c77b78555dac501c1b9edad148dc Mon Sep 17 00:00:00 2001 From: Igor Artemenko Date: Tue, 10 Feb 2026 19:11:39 +0000 Subject: [PATCH 4/4] Add ID to convenience method --- lib/langfuse.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/langfuse.rb b/lib/langfuse.rb index 2b76efe..bcbb3a6 100644 --- a/lib/langfuse.rb +++ b/lib/langfuse.rb @@ -190,6 +190,7 @@ 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 @@ -209,11 +210,12 @@ 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, session_id: nil, observation_id: nil, comment: nil, metadata: nil, - environment: 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,