fix: add namespace, model, and provider to langfuse metadata so we can filter (#565)

This commit is contained in:
Rajat Ahuja 2026-04-20 16:30:35 -04:00 committed by GitHub
parent 51497f174f
commit 2c50791642
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 81 additions and 2 deletions

View File

@ -31,6 +31,7 @@ from .runtime import (
effective_temperature,
plan_attempt,
resolve_runtime_model_config,
update_current_langfuse_observation,
)
from .tool_loop import execute_tool_loop
from .types import (
@ -193,13 +194,19 @@ async def honcho_llm_call(
current_attempt.set(1)
def _get_attempt_plan() -> AttemptPlan:
return plan_attempt(
plan = plan_attempt(
runtime_model_config=runtime_model_config,
attempt=current_attempt.get(),
retry_attempts=retry_attempts,
call_thinking_budget_tokens=thinking_budget_tokens,
call_reasoning_effort=reasoning_effort,
)
update_current_langfuse_observation(
plan.provider,
plan.model,
name=track_name,
)
return plan
async def _call_with_provider_selection() -> (
HonchoLLMCallResponse[Any] | AsyncIterator[HonchoLLMCallStreamChunk]

View File

@ -21,6 +21,7 @@ from src.config import (
ModelConfig,
ModelTransport,
resolve_model_config,
settings,
)
from .registry import backend_for_provider, client_for_model_config
@ -32,6 +33,33 @@ logger = logging.getLogger(__name__)
current_attempt: ContextVar[int] = ContextVar("current_attempt", default=0)
def update_current_langfuse_observation(
provider: ModelTransport,
model: str,
*,
name: str | None = None,
) -> None:
"""Best-effort annotation of the current Langfuse span with LLM routing."""
if not settings.LANGFUSE_PUBLIC_KEY:
return
try:
from langfuse import get_client
update_kwargs: dict[str, Any] = {
"metadata": {
"namespace": settings.NAMESPACE,
"provider": provider,
"model": model,
}
}
if name is not None:
update_kwargs["name"] = name
get_client().update_current_span(**update_kwargs)
except Exception as exc: # pragma: no cover - best-effort telemetry
logger.debug("Failed to update Langfuse span metadata: %s", exc)
@dataclass(frozen=True)
class AttemptPlan:
"""Per-attempt plan produced by `plan_attempt`.
@ -204,4 +232,5 @@ __all__ = [
"resolve_backend_for_plan",
"resolve_runtime_model_config",
"select_model_config_for_attempt",
"update_current_langfuse_observation",
]

View File

@ -23,7 +23,12 @@ from openai.types.chat.chat_completion_message import ChatCompletionMessage
from openai.types.completion_usage import CompletionUsage
from pydantic import BaseModel, Field
from src.config import ConfiguredModelSettings, ModelConfig, ResolvedFallbackConfig
from src.config import (
ConfiguredModelSettings,
ModelConfig,
ResolvedFallbackConfig,
settings,
)
from src.exceptions import LLMError, ValidationException
from src.llm import (
CLIENTS,
@ -905,6 +910,44 @@ class TestMainLLMCallFunction:
assert response.content == "No retry response"
async def test_track_name_updates_langfuse_span_name(self):
"""track_name should rename the top-level Langfuse span."""
mock_llm_client = AsyncMock(spec=AsyncAnthropic)
mock_response = Mock()
mock_response.content = [TextBlock(text="Named response", type="text")]
mock_response.usage = Usage(input_tokens=5, output_tokens=5)
mock_response.stop_reason = "stop"
mock_llm_client.messages.create = AsyncMock(return_value=mock_response)
mock_langfuse_client = Mock()
with (
patch.dict(CLIENTS, {"anthropic": mock_llm_client}),
patch.object(settings, "LANGFUSE_PUBLIC_KEY", "test-public-key"),
patch("langfuse.get_client", return_value=mock_langfuse_client),
):
response = await honcho_llm_call(
model_config=ConfiguredModelSettings(
model="claude-4-sonnet",
transport="anthropic",
),
prompt="Hello",
max_tokens=100,
enable_retry=False,
track_name="Dialectic Agent",
)
assert response.content == "Named response"
mock_langfuse_client.update_current_span.assert_called_once_with(
name="Dialectic Agent",
metadata={
"namespace": settings.NAMESPACE,
"provider": "anthropic",
"model": "claude-4-sonnet",
},
)
class TestEdgeCases:
"""Tests for edge cases and boundary conditions"""