feat(v0.0.2): LiteLLM model adapter + Langfuse telemetry alongside AgentOps - #12
feat(v0.0.2): LiteLLM model adapter + Langfuse telemetry alongside AgentOps#12nadyyym wants to merge 2 commits into
Conversation
…de AgentOps Replace the native-Gemini-only model factory with a LiteLLM adapter so any provider can be selected per agent via the *_MODEL env vars, and add Langfuse as a second, concurrent telemetry backend next to AgentOps. LLM choice - shared/model_factory.py: build_gemini() -> build_model() returning LiteLlm. Bare model names (e.g. the legacy "gemini-3-flash-preview") auto-prefix to the gemini/ provider, so existing env values keep working. Mirrors GOOGLE_API_KEY into GEMINI_API_KEY (litellm's gemini provider reads the latter). Retries via litellm num_retries (LLM_NUM_RETRIES, default 6). - upsell_agent / dwh_analyst / signal_agent: import build_model. Telemetry (side by side, each env-gated, concurrent) - shared/observability.py: init_observability() inits AgentOps (AGENTOPS_API_KEY) and Langfuse (LANGFUSE_PUBLIC_KEY/SECRET_KEY) independently and idempotently. Langfuse via OpenInference GoogleADKInstrumentor. - shared/litellm_otel.py: bridges LiteLLM token/cost usage onto the active OTel span so Langfuse records usage for LiteLLM-fronted models. - Agents call init_observability() at import (ADK loads modules directly); inline agentops.init() blocks removed. v0.0.2/__init__.py also inits. requirements: litellm, langfuse, openinference-instrumentation-google-adk, anthropic (unpinned pending first build). .env.example: GEMINI_API_KEY, LANGFUSE_*, LLM_NUM_RETRIES, provider-prefix note. Telemetry slices ported from feat/mason-flash3-batched-grounded; this PR is the focused litellm+langfuse subset (no batching/dryfit/memory-bank). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@Sashmark97 this pr lets me:
Tested and it all works. Could you merge pls? |
✅ E2E validation on Railway (gemini-3-flash)Deployed this branch to the dedicated Railway env What this PR changes — validated ✅Build / boot — build SUCCESS; uvicorn came up clean with no LiteLLM adapter → gemini-3-flash — run returned HTTP 200 (315s) with Langfuse alongside AgentOps — one trace
Crucially, token+cost are populated — the prior 2026-05-03 traces on this env show
Caveat — signal output was 0 (NOT caused by this PR)The run promoted 0 signals (recall/precision 0/0). Root cause from
i.e. the warehouse-profiling step returned an empty table allowlist, so the SQL policy guard blocked everything before the discovery loop started. gemini-3-flash itself produced correct queries ( VerdictThe two things this PR ships — LiteLLM model routing and Langfuse telemetry alongside AgentOps — are validated end-to-end on gemini-3-flash. The 0-signal result is an unrelated warehouse-profiling issue in the master-based pipeline. |
🔁 Re-run with the harness bug fixed — litellm + Langfuse confirmed; signal score blocked by a separate Mason bugFollow-up to the comment above. The 0-signal / empty-allowlist result there was my harness mistake, not this PR: I minted the Mason session directly ( Fix: register the session first via Re-run on gemini-3-flash (registered session) — pipeline executes end-to-end
What this PR ships — re-confirmed ✅
|
Address PR #12 review: - signal_agent/agent.py: quota handling caught only the native ADK _ResourceExhaustedError, which never fires after the LiteLLM switch (429s now raise litellm.exceptions.RateLimitError). Add an import-guarded catch of RateLimitError alongside it via _QUOTA_EXHAUSTED_ERRORS, preserving the graceful-exit / quota_exhausted_error behavior. - requirements.txt: pin the 4 new deps to versions resolved by docker build against google-adk==1.33.0 (litellm==1.88.0, langfuse==4.7.1, openinference-instrumentation-google-adk==0.1.15, anthropic==0.107.1); drop the stale "pin after first build" / 1.19.0 comment. - .env.example: note that the old GEMINI_RETRY_* backoff/jitter knobs are no longer read (LiteLLM only exposes LLM_NUM_RETRIES). Verified in the built image: LiteLlm accepts num_retries (stored in _additional_args) and signal_agent.agent imports cleanly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Two focused changes to the v0.0.2 agent pipeline:
*_MODELenv vars (gemini/...,anthropic/...,vertex_ai/..., etc.).This is the focused litellm + langfuse subset extracted from
feat/mason-flash3-batched-grounded; the batching / dryfit_e2e / memory-bank grounding work from that branch is intentionally left out.LLM choice
shared/model_factory.py:build_gemini()→build_model()returningLiteLlm.gemini-3-flash-previewstill in.env.example) auto-prefix togemini/, so existing env values keep working unchanged.GOOGLE_API_KEY→GEMINI_API_KEY(litellm's gemini provider reads the latter) so the switch doesn't silently break auth.num_retries(LLM_NUM_RETRIES, default 6), replacing the native GeminiHttpRetryOptions. The oldGEMINI_RETRY_*backoff/jitter knobs are no longer read.upsell_agent/dwh_analyst/signal_agentupdated to importbuild_model.signal_agent/agent.pyquota handling now catches both the native ADK_ResourceExhaustedErrorandlitellm.exceptions.RateLimitError(post-LiteLLM, 429s surface as the latter), preserving the graceful-exit /quota_exhausted_errorbehavior.Telemetry (side by side, env-gated, concurrent)
shared/observability.py:init_observability()inits AgentOps (AGENTOPS_API_KEY) and Langfuse (LANGFUSE_PUBLIC_KEY+LANGFUSE_SECRET_KEY,LANGFUSE_HOST) independently and idempotently. Langfuse is wired via OpenInference'sGoogleADKInstrumentor.shared/litellm_otel.py: bridges LiteLLM token/cost usage onto the active OTel span (OpenInference doesn't capture usage from LiteLLM-fronted models, so without this Langfuse shows zero tokens/cost).init_observability()at import time (ADK loads agent modules directly); the inlineagentops.init()blocks are removed and centralized.v0.0.2/__init__.pyalso inits as a belt-and-suspenders entry point.Deps / config
requirements.txt:litellm,langfuse,openinference-instrumentation-google-adk,anthropic— pinned againstgoogle-adk==1.33.0via a successfuldocker build:litellm==1.88.0,langfuse==4.7.1,openinference-instrumentation-google-adk==0.1.15,anthropic==0.107.1..env.example: addsGEMINI_API_KEY,LANGFUSE_PUBLIC_KEY/SECRET_KEY/HOST,LLM_NUM_RETRIES, a note on the<provider>/<model>format, and a note that the oldGEMINI_RETRY_*knobs are no longer read.Validation
docker buildon the repo Dockerfile (python:3.11-slim) succeeds with the pinned deps againstgoogle-adk==1.33.0.google.adk.models.lite_llm.LiteLlmexists, acceptsnum_retries=6(forwarded tolitellm.completion, stored in_additional_args), andsignal_agent.agentimports cleanly with the dual-exception quota guard./runwas not exercised — it needs Langfuse + PostHog secrets. Please run a smoke/runand confirm traces appear in Langfuse + AgentOps before merge.🤖 Generated with Claude Code