Skip to content

Commit 77a5398

Browse files
Ralph Agentclaude
andcommitted
🐛 Fix media generation crash when generating both banner and logo
Replace global dspy.configure() with scoped dspy.context() to avoid cross-event-loop RuntimeError. Make LangFuse observability conditional on credentials being present. Improve media step UX with spacing and "Both" as default choice. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e0ff60f commit 77a5398

2 files changed

Lines changed: 31 additions & 11 deletions

File tree

onboard.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ def media() -> None:
497497

498498
project_name = _read_pyproject_name()
499499

500+
rprint()
500501
theme = questionary.text(
501502
"Describe the visual theme/style for your project assets:",
502503
default="modern, clean, minimalist tech aesthetic",
@@ -506,7 +507,8 @@ def media() -> None:
506507

507508
choice = questionary.select(
508509
"What would you like to generate?",
509-
choices=["Banner only", "Logo only", "Both", "Skip"],
510+
choices=["Both", "Banner only", "Logo only", "Skip"],
511+
default="Both",
510512
).ask()
511513
if choice is None:
512514
raise typer.Abort()

utils/llm/dspy_inference.py

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
import os
12
from collections.abc import Callable
23
from typing import Any
34

45
import dspy
5-
from langfuse import observe
66
from litellm.exceptions import RateLimitError, ServiceUnavailableError
77
from loguru import logger as log
88
from tenacity import (
@@ -14,7 +14,13 @@
1414

1515
from common import global_config
1616
from common.flags import client
17-
from utils.llm.dspy_langfuse import LangFuseDSPYCallback
17+
18+
19+
def _langfuse_configured() -> bool:
20+
"""Check if LangFuse credentials are present in environment."""
21+
return bool(
22+
os.environ.get("LANGFUSE_PUBLIC_KEY") and os.environ.get("LANGFUSE_SECRET_KEY")
23+
)
1824

1925

2026
class DSPYInference:
@@ -43,12 +49,13 @@ def __init__(
4349
if self.fallback_model_name is not None
4450
else None
4551
)
46-
if observe:
47-
# Initialize a LangFuseDSPYCallback and configure the LM instance for generation tracing
52+
self.dspy_config: dict[str, Any] = {"lm": self.lm}
53+
if observe and _langfuse_configured():
54+
from utils.llm.dspy_langfuse import LangFuseDSPYCallback
55+
4856
self.callback = LangFuseDSPYCallback(pred_signature)
49-
dspy.configure(lm=self.lm, callbacks=[self.callback])
50-
else:
51-
dspy.configure(lm=self.lm)
57+
self.dspy_config["callbacks"] = [self.callback]
58+
self._use_langfuse_observe = observe and _langfuse_configured()
5259

5360
# Agent Intiialization
5461
if len(tools) > 0:
@@ -81,7 +88,9 @@ async def _run_with_retry(
8188
lm: dspy.LM,
8289
**kwargs: Any,
8390
) -> Any:
84-
return await self.inference_module_async(**kwargs, lm=lm)
91+
config = {**self.dspy_config, "lm": lm}
92+
with dspy.context(**config):
93+
return await self.inference_module_async(**kwargs, lm=lm)
8594

8695
def _build_lm(
8796
self,
@@ -98,8 +107,7 @@ def _build_lm(
98107
max_tokens=max_tokens,
99108
)
100109

101-
@observe()
102-
async def run(
110+
async def _run_inner(
103111
self,
104112
**kwargs: Any,
105113
) -> Any:
@@ -127,3 +135,13 @@ async def run(
127135
log.error(f"Error in run: {str(e)}")
128136
raise
129137
return result
138+
139+
async def run(
140+
self,
141+
**kwargs: Any,
142+
) -> Any:
143+
if self._use_langfuse_observe:
144+
from langfuse import observe as langfuse_observe
145+
146+
return await langfuse_observe()(self._run_inner)(**kwargs)
147+
return await self._run_inner(**kwargs)

0 commit comments

Comments
 (0)