Skip to content
Merged
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
6 changes: 5 additions & 1 deletion langfuse/_client/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ def _flatten_and_serialize_metadata(
metadata_attributes[prefix] = _serialize(metadata)
else:
for key, value in metadata.items():
metadata_attributes[f"{prefix}.{key}"] = _serialize(value)
metadata_attributes[f"{prefix}.{key}"] = (
value
if isinstance(value, str) or isinstance(value, int)
else _serialize(value)
)

return metadata_attributes
2 changes: 1 addition & 1 deletion tests/test_core_sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async def update_generation(i, langfuse: Langfuse):
# Verify metadata
observation = generation_obs[0]
assert observation.name == str(i)
assert observation.metadata["count"] == f"{i}"
assert observation.metadata["count"] == i


def test_flush():
Expand Down
39 changes: 16 additions & 23 deletions tests/test_otel.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,9 @@ def test_span_attributes(self, langfuse_client, memory_exporter):
output_data = json.loads(
attributes[LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT]
)
metadata_data = json.loads(
attributes[f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.session"]
)
metadata_data = attributes[
f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.session"
]

# Verify attribute values
assert input_data == {"prompt": "Test prompt"}
Expand Down Expand Up @@ -425,9 +425,7 @@ def test_trace_update(self, langfuse_client, memory_exporter):
tags = list(attributes[LangfuseOtelSpanAttributes.TRACE_TAGS])

input_data = json.loads(attributes[LangfuseOtelSpanAttributes.TRACE_INPUT])
metadata = json.loads(
attributes[f"{LangfuseOtelSpanAttributes.TRACE_METADATA}.trace-meta"]
)
metadata = attributes[f"{LangfuseOtelSpanAttributes.TRACE_METADATA}.trace-meta"]

# Check attribute values
assert sorted(tags) == sorted(["tag1", "tag2"])
Expand Down Expand Up @@ -501,11 +499,9 @@ def test_complex_scenario(self, langfuse_client, memory_exporter):
)

# Parse metadata
proc_metadata = json.loads(
proc["attributes"][
f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.step"
]
)
proc_metadata = proc["attributes"][
f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.step"
]
assert proc_metadata == "processing"

# Parse input/output JSON
Expand Down Expand Up @@ -980,12 +976,14 @@ def test_complex_metadata_serialization(self):
assert (
f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.key2" in simple_result
)
assert simple_result[
f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.key1"
] == _serialize("value1")
assert simple_result[
f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.key2"
] == _serialize(123)
assert (
simple_result[f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.key1"]
== "value1"
)
assert (
simple_result[f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.key2"]
== 123
)

# Test case 3: Nested dict (will be flattened in current implementation)
nested_dict = {
Expand Down Expand Up @@ -1037,7 +1035,7 @@ def test_complex_metadata_serialization(self):

# The nested structures are serialized as JSON strings
assert json.loads(complex_result[level1_key]) == complex_dict["level1"]
assert complex_result[sibling_key] == _serialize("value")
assert complex_result[sibling_key] == "value"

def test_nested_metadata_updates(self):
"""Test that nested metadata updates don't overwrite unrelated keys."""
Expand Down Expand Up @@ -2130,11 +2128,6 @@ async def async_task(parent_span, task_id):
)
assert output["result"] == f"Task {i} completed"

metadata = self.verify_json_attribute(
task_span, f"{LangfuseOtelSpanAttributes.OBSERVATION_METADATA}.task_id"
)
assert metadata == i

# Verify main span output
main_output = self.verify_json_attribute(
main, LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT
Expand Down