Skip to content

Commit 4afcf12

Browse files
fix(langextract): improve error handling, test reliability, and reduce code duplication
- Add LangextractSink.bridge_context_events() helper method to centralize context emitter setup - Fix silent exception swallowing in langextract render command - now properly reports bridge failures - Add proper skipif guard for optional dependency tests - Use callback pattern for clean separation of CLI concerns Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
1 parent 8463cf8 commit 4afcf12

File tree

4 files changed

+49
-26
lines changed

4 files changed

+49
-26
lines changed

src/praisonai/praisonai/cli/app.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,15 @@ def _setup_langextract_observability(*, verbose: bool = False) -> None:
7070
# Bridge the context emitter so regular Agent.start / tool calls / LLM
7171
# responses are captured as well. Without this, typical single-agent
7272
# flows produce an empty trace (no agent_start/end, no tool events).
73-
try:
74-
from praisonaiagents.trace.context_events import (
75-
ContextTraceEmitter,
76-
set_context_emitter,
77-
)
78-
context_emitter = ContextTraceEmitter(
79-
sink=sink.context_sink(),
80-
session_id="praisonai-cli",
81-
enabled=True,
82-
)
83-
set_context_emitter(context_emitter)
84-
except Exception as e: # pragma: no cover - defensive
73+
def warn_handler(msg: str):
8574
if verbose:
86-
typer.echo(f"Warning: could not bridge context emitter: {e}", err=True)
75+
typer.echo(f"Warning: {msg}", err=True)
76+
77+
LangextractSink.bridge_context_events(
78+
sink=sink,
79+
session_id="praisonai-cli",
80+
warn_callback=warn_handler
81+
)
8782

8883
except ImportError:
8984
# Gracefully degrade if langextract not installed

src/praisonai/praisonai/cli/commands/langextract.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -82,19 +82,17 @@ def render(
8282

8383
# Also bridge the context emitter so real agent runtime events
8484
# (agent_start/end, tool_call_*, llm_response) are captured.
85-
try:
86-
from praisonaiagents.trace.context_events import (
87-
ContextTraceEmitter,
88-
set_context_emitter,
89-
)
90-
context_emitter = ContextTraceEmitter(
91-
sink=sink.context_sink(),
92-
session_id="praisonai-langextract-render",
93-
enabled=True,
94-
)
95-
set_context_emitter(context_emitter)
96-
except Exception:
97-
pass
85+
from praisonai.observability.langextract import LangextractSink
86+
87+
def warn_handler(msg: str):
88+
# Warn user about bridge failure since this command specifically generates traces
89+
typer.echo(f"Warning: {msg}", err=True)
90+
91+
LangextractSink.bridge_context_events(
92+
sink=sink,
93+
session_id="praisonai-langextract-render",
94+
warn_callback=warn_handler
95+
)
9896

9997
try:
10098
# Run the workflow

src/praisonai/praisonai/observability/langextract.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,35 @@ def context_sink(self) -> "_ContextToActionBridge":
154154
"""
155155
return _ContextToActionBridge(self)
156156

157+
@staticmethod
158+
def bridge_context_events(sink: "LangextractSink", session_id: str, warn_callback=None) -> None:
159+
"""
160+
Helper method to set up context event bridging for the given sink.
161+
162+
Args:
163+
sink: LangextractSink instance to bridge
164+
session_id: Session ID for the context emitter
165+
warn_callback: Optional callback function for warnings, called with message string
166+
"""
167+
try:
168+
from praisonaiagents.trace.context_events import (
169+
ContextTraceEmitter,
170+
set_context_emitter,
171+
)
172+
context_emitter = ContextTraceEmitter(
173+
sink=sink.context_sink(),
174+
session_id=session_id,
175+
enabled=True,
176+
)
177+
set_context_emitter(context_emitter)
178+
except ImportError:
179+
# Context emitter bridging is optional if not available
180+
if warn_callback:
181+
warn_callback("ContextTraceEmitter not available")
182+
except Exception as e:
183+
if warn_callback:
184+
warn_callback(f"could not bridge context emitter: {e}")
185+
157186
# ---- TraceSinkProtocol -------------------------------------------------
158187

159188
def emit(self, event: ActionEvent) -> None:

src/praisonai/tests/unit/test_langextract_sink.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ def test_bridge_maps_context_events_to_action_events(self):
407407
assert "agent_end" in types
408408
assert sink._source_text == "Write a haiku"
409409

410+
@pytest.mark.skipif(not _langextract_available(), reason="langextract not installed")
410411
def test_setup_observability_registers_context_emitter(self):
411412
"""`--observe langextract` must install the bridge on the context emitter."""
412413
import praisonai.cli.app as cli_app

0 commit comments

Comments
 (0)