Skip to content

Commit 8cd08a0

Browse files
committed
fix: upgrade all backend deps and fix langfuse/litellm/instructor compat
- Upgrade all pinned deps to latest (litellm 1.82.0, fastapi 0.135.1, sentry-sdk 2.54.0, clerk-backend-api 5.0.2, etc.) - Pin langfuse to v2.60.10 (v3 removed sdk_integration param that litellm passes, causing TypeError in production) - Add TraceWrapper to langfuse service mapping v3-style start_span/ start_generation calls to v2 span/generation methods - Remove Bot icon from model selector loading state
1 parent 5783126 commit 8cd08a0

File tree

4 files changed

+1149
-701
lines changed

4 files changed

+1149
-701
lines changed

backend/pyproject.toml

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,43 @@ classifiers = [
1111
]
1212
requires-python = ">=3.11"
1313
dependencies = [
14-
"python-dotenv==1.0.1",
15-
"litellm==1.80.7",
16-
"click==8.1.7",
17-
"requests==2.32.3",
18-
"packaging==24.1",
19-
"setuptools==75.3.0",
20-
"pytest==8.3.3",
21-
"pytest-asyncio==0.24.0",
22-
"fastapi==0.123.7",
23-
"uvicorn==0.38.0",
24-
"python-multipart==0.0.20",
25-
"redis>=7.1.0",
26-
"aiohttp==3.13.2",
27-
"supabase>=2.25.0",
28-
"pyjwt==2.10.1",
29-
"certifi==2024.2.2",
30-
"daytona>=0.121.0",
14+
"python-dotenv==1.2.2",
15+
"litellm==1.82.0",
16+
"click==8.3.1",
17+
"requests==2.32.5",
18+
"packaging>=23.2,<26.0",
19+
"setuptools==82.0.0",
20+
"pytest==9.0.2",
21+
"pytest-asyncio==1.3.0",
22+
"fastapi==0.135.1",
23+
"uvicorn==0.41.0",
24+
"python-multipart==0.0.22",
25+
"redis>=7.3.0",
26+
"aiohttp==3.13.3",
27+
"supabase>=2.28.0",
28+
"pyjwt==2.11.0",
29+
"certifi==2026.2.25",
30+
"daytona>=0.149.0",
3131
"openai==2.8.1",
32-
"tavily-python==0.7.13",
33-
"Pillow>=10.4.0",
34-
"mcp==1.23.1",
32+
"tavily-python==0.7.22",
33+
"Pillow>=12.1.1",
34+
"mcp==1.26.0",
3535
"httpx>=0.28.1",
36-
"mailtrap==2.3.0",
37-
"sentry-sdk[fastapi]==2.47.0",
38-
"gunicorn>=23.0.0",
39-
"cryptography>=41.0.0",
36+
"mailtrap==2.4.0",
37+
"sentry-sdk[fastapi]==2.54.0",
38+
"gunicorn>=25.1.0",
39+
"cryptography>=46.0.5",
4040
"structlog==25.5.0",
41-
"google-genai>=1.53.0",
42-
"numpy>=1.24.0",
43-
"langfuse==3.10.5",
44-
"polar-sdk>=0.28.0",
45-
"clerk-backend-api==4.1.2",
46-
"composio>=0.9.4",
41+
"google-genai>=1.66.0",
42+
"numpy>=2.4.2",
43+
"langfuse==2.60.10",
44+
"polar-sdk>=0.30.0",
45+
"clerk-backend-api==5.0.2",
46+
"composio>=0.11.2",
4747
"email-validator>=2.0.0",
48-
"instructor>=1.7.0",
49-
"tenacity>=8.2.0",
50-
"inngest>=0.5.15",
48+
"instructor>=1.14.5",
49+
"tenacity>=9.1.4",
50+
"inngest>=0.5.17",
5151
"slowapi>=0.1.9",
5252
]
5353

@@ -61,7 +61,7 @@ package = false
6161

6262
[dependency-groups]
6363
dev = [
64-
"ruff==0.11.12",
64+
"ruff==0.15.5",
6565
]
6666

6767
[tool.ruff]

backend/services/langfuse.py

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
"""Langfuse integration service using v3 SDK.
1+
"""Langfuse integration service using v2 SDK.
22
3-
Clean implementation without backwards compatibility wrappers.
3+
Provides v3-style method aliases (start_span, start_generation) on top of
4+
the v2 API so callers can use either naming convention.
45
"""
56

67
from langfuse import Langfuse
@@ -25,39 +26,80 @@ def update(self, **_kwargs) -> "MockObservation":
2526
def end(self, **kwargs) -> None:
2627
pass
2728

29+
def span(self, name: str = "", **_kwargs) -> "MockObservation":
30+
return MockObservation()
31+
2832
def start_span(self, name: str = "", **_kwargs) -> "MockObservation":
2933
return MockObservation()
3034

35+
def generation(self, name: str = "", **_kwargs) -> "MockObservation":
36+
return MockObservation()
37+
3138
def start_generation(self, name: str = "", **_kwargs) -> "MockObservation":
3239
return MockObservation()
3340

34-
def event(self, name: str, **kwargs) -> None:
41+
def event(self, name: str = "", **kwargs) -> None:
3542
"""Log an event (no-op for mock)."""
3643

3744

45+
class TraceWrapper:
46+
"""Wraps a v2 StatefulTraceClient to add v3-style aliases."""
47+
48+
def __init__(self, trace):
49+
self._trace = trace
50+
51+
def span(self, name: str = "", **kwargs):
52+
return self._trace.span(name=name, **kwargs)
53+
54+
def start_span(self, name: str = "", **kwargs):
55+
"""v3-style alias for span()."""
56+
return self._trace.span(name=name, **kwargs)
57+
58+
def generation(self, name: str = "", **kwargs):
59+
return self._trace.generation(name=name, **kwargs)
60+
61+
def start_generation(self, name: str = "", **kwargs):
62+
"""v3-style alias for generation()."""
63+
return self._trace.generation(name=name, **kwargs)
64+
65+
def update(self, **kwargs):
66+
return self._trace.update(**kwargs)
67+
68+
def end(self, **kwargs):
69+
if hasattr(self._trace, "end"):
70+
return self._trace.end(**kwargs)
71+
72+
def event(self, name: str = "", **kwargs):
73+
if hasattr(self._trace, "event"):
74+
return self._trace.event(name=name, **kwargs)
75+
76+
def __getattr__(self, name):
77+
return getattr(self._trace, name)
78+
79+
3880
# Initialize Langfuse client
3981
langfuse: Langfuse | None = None
4082

4183
try:
4284
if enabled:
4385
langfuse = Langfuse(public_key=public_key, secret_key=secret_key, host=host)
44-
logger.info("Langfuse v3 initialized successfully (enabled=True)")
86+
logger.info("Langfuse initialized successfully (enabled=True)")
4587
else:
46-
logger.info("Langfuse v3 disabled (no credentials)")
88+
logger.info("Langfuse disabled (no credentials)")
4789
except Exception as e:
4890
logger.warning(f"Failed to initialize Langfuse: {e!s}")
4991
langfuse = None
5092

5193

5294
def log_event(trace, name: str, **kwargs) -> None:
53-
"""Log an event to a trace as a short-lived span (v3 pattern).
95+
"""Log an event to a trace as a short-lived span.
5496
55-
In Langfuse v3, events are represented as spans that are immediately ended.
97+
Creates a span that is immediately ended.
5698
"""
5799
if trace is None:
58100
return
59101
try:
60-
span = trace.start_span(name=name)
102+
span = trace.span(name=name)
61103
update_kwargs = {}
62104
if "level" in kwargs:
63105
update_kwargs["level"] = kwargs["level"]
@@ -77,32 +119,30 @@ def log_event(trace, name: str, **kwargs) -> None:
77119

78120

79121
def safe_trace(name: str, **kwargs):
80-
"""Create a Langfuse trace/span with error handling.
122+
"""Create a Langfuse trace with error handling.
81123
82-
Returns the root span observation object that supports:
83-
- .start_span(name, **kwargs) -> child span
84-
- .start_generation(name, model, **kwargs) -> generation
124+
Returns a TraceWrapper that supports both v2 and v3 method names:
125+
- .span() / .start_span() -> child span
126+
- .generation() / .start_generation() -> generation
85127
- .update(**kwargs) -> update observation
86128
- .end(**kwargs) -> end observation
87129
"""
88130
try:
89131
if langfuse and enabled:
90-
# Create root span
91-
span_kwargs = {"name": name}
132+
trace_kwargs = {"name": name}
92133

93-
# Map common trace parameters
94134
if "session_id" in kwargs:
95-
span_kwargs["session_id"] = kwargs["session_id"]
135+
trace_kwargs["session_id"] = kwargs["session_id"]
96136
if "user_id" in kwargs:
97-
span_kwargs["user_id"] = kwargs["user_id"]
137+
trace_kwargs["user_id"] = kwargs["user_id"]
98138
if "metadata" in kwargs:
99-
span_kwargs["metadata"] = kwargs["metadata"]
139+
trace_kwargs["metadata"] = kwargs["metadata"]
100140
if "input" in kwargs:
101-
span_kwargs["input"] = kwargs["input"]
141+
trace_kwargs["input"] = kwargs["input"]
102142
if "tags" in kwargs:
103-
span_kwargs["tags"] = kwargs["tags"]
143+
trace_kwargs["tags"] = kwargs["tags"]
104144

105-
return langfuse.start_span(**span_kwargs)
145+
return TraceWrapper(langfuse.trace(**trace_kwargs))
106146
return MockObservation()
107147
except Exception as e:
108148
logger.warning(f"Failed to create Langfuse trace '{name}': {e!s}")

0 commit comments

Comments
 (0)