Fix Galileo logging to match Langfuse across all endpoint types.

Stop skipping ingest when output is empty and log embeddings with a placeholder so embedding, speech, and other non-text responses are recorded like Langfuse.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Sameer Kankute 2026-06-08 19:20:53 +05:30
parent 79fd09e2db
commit 44efc95522
No known key found for this signature in database
2 changed files with 57 additions and 11 deletions

View file

@ -517,7 +517,7 @@ class GalileoObserve(CustomLogger):
"""
Mirror Langfuse _get_langfuse_input_output_content for Galileo ingest.
Returns (input_text, output_text, messages_for_span). output_text None skips ingest.
Returns (input_text, output_text, messages_for_span).
"""
call_type = kwargs.get("call_type")
prompt = self._build_prompt(kwargs)
@ -530,10 +530,11 @@ class GalileoObserve(CustomLogger):
return self._prompt_to_input_text(prompt), status_message, prompt
if response_obj is not None and (
call_type == "embedding"
call_type in ("embedding", "aembedding")
or isinstance(response_obj, litellm.EmbeddingResponse)
):
return self._prompt_to_input_text(prompt), None, prompt
# Match Langfuse OTEL: log embeddings without serializing vectors.
return self._prompt_to_input_text(prompt), "embedding-output", prompt
if response_obj is not None and isinstance(response_obj, litellm.ModelResponse):
output = self._get_chat_content_for_galileo(response_obj)
@ -627,7 +628,7 @@ class GalileoObserve(CustomLogger):
kwargs.get("messages") or [],
)
return self._prompt_to_input_text(prompt), None, kwargs.get("messages") or []
return self._prompt_to_input_text(prompt), "", kwargs.get("messages") or []
def get_output_str_from_response(
self, response_obj: Any, kwargs: Dict[str, Any]
@ -713,10 +714,7 @@ class GalileoObserve(CustomLogger):
kwargs=kwargs, response_obj=response_obj
)
if output_text is None:
verbose_logger.debug(
"Galileo Logger: skipping %s — no text output to log", _call_type
)
return
output_text = ""
raw_start = slo.get("startTime")
raw_end = slo.get("endTime")

View file

@ -357,12 +357,18 @@ def test_galileo_record_to_v2_span_with_tags_and_offset():
def test_galileo_get_output_str_variants(galileo_v2_env):
logger = GalileoObserve()
assert logger.get_output_str_from_response(None, {}) is None
assert logger.get_output_str_from_response(None, {}) == ""
assert (
logger.get_output_str_from_response(
EmbeddingResponse(), {"call_type": "embedding"}
)
is None
== "embedding-output"
)
assert (
logger.get_output_str_from_response(
EmbeddingResponse(), {"call_type": "aembedding"}
)
== "embedding-output"
)
text_resp = TextCompletionResponse()
@ -414,7 +420,7 @@ def test_galileo_get_output_str_variants(galileo_v2_env):
{"call_type": "acompletion", "messages": [{"role": "user", "content": "hi"}]},
)
assert logger.get_output_str_from_response("not-a-supported-type", {}) is None
assert logger.get_output_str_from_response("not-a-supported-type", {}) == ""
def test_galileo_get_input_output_error_status_message(galileo_v2_env):
@ -445,6 +451,48 @@ def test_galileo_get_output_str_rerank_response(galileo_v2_env):
assert '"relevance_score": 0.98' in output
@pytest.mark.asyncio
async def test_galileo_async_log_success_embedding(galileo_v2_env):
import datetime
logger = GalileoObserve()
embedding_response = EmbeddingResponse(
data=[{"object": "embedding", "embedding": [0.1, 0.2, 0.3], "index": 0}]
)
mock_response = MagicMock()
mock_response.is_success = True
mock_response.status_code = 201
with patch.object(logger.async_httpx_handler, "post", return_value=mock_response):
await logger.async_log_success_event(
kwargs={
"call_type": "aembedding",
"model": "text-embedding-3-small",
"input": "hello world",
"standard_logging_object": {
"call_type": "aembedding",
"model": "text-embedding-3-small",
"prompt_tokens": 2,
"completion_tokens": 0,
"total_tokens": 2,
"response_cost": 0.0,
"startTime": datetime.datetime(
2026, 5, 25, 12, 0, 0, tzinfo=datetime.timezone.utc
).timestamp(),
"endTime": datetime.datetime(
2026, 5, 25, 12, 0, 1, tzinfo=datetime.timezone.utc
).timestamp(),
},
},
response_obj=embedding_response,
start_time=datetime.datetime(2026, 5, 25, 12, 0, 0),
end_time=datetime.datetime(2026, 5, 25, 12, 0, 1),
)
assert logger.in_memory_records == []
@pytest.mark.asyncio
async def test_galileo_async_log_success_rerank(galileo_v2_env):
import datetime