fix(analytics): handle new Langfuse trace input format after PR#33#40
Conversation
PR#33 removed the eval wrapper span (start_as_current_observation), making
the LangGraph callback the trace root. The top-level input is now a list of
LangChain message dicts instead of {"intent": ...}, causing AttributeError
in the trace comparison pipeline.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughUpdated Langfuse adapter's load_trace to extract task formulation from ChangesLangfuse Input Shape Handling
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@analytics/trace_comparison_rules/src/langfuse_adapter.py`:
- Around line 73-85: The extracted task formulation from raw_input may be
non-string (m.get("content")), so ensure trace.task_formulation is either a
string or None: after obtaining the candidate (from raw_input dict or the
next(...) for list items), check isinstance(candidate, str) and assign it to
trace.task_formulation only if true; otherwise, either set
trace.task_formulation = None or convert safely to a string representation
(e.g., json.dumps(candidate)) before assigning. Update the logic around
raw_input, the dict branch (raw_input.get("intent")), and the list branch (the
next(...) generator that reads m.get("content")) to include this
validation/conversion so downstream code that calls .strip() on
trace.task_formulation is safe.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 33464d9b-e979-4bbb-a3cb-384206320906
📒 Files selected for processing (1)
analytics/trace_comparison_rules/src/langfuse_adapter.py
haroldship
left a comment
There was a problem hiding this comment.
Looks good to me, CodeRabbit comment is minor. Up to you if you want to include it.
Address PR review: LangChain message `content` may be a list (multi-modal blocks), so extracting it directly could break downstream code that calls .strip() and string concatenation on task_formulation. Only assign when the candidate is a string; otherwise leave as None (downstream already handles None with an "Unknown Task" fallback). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adapt trace comparison analytics to new Langfuse format
Related Issue
Fixes #33 (downstream breakage)
Closes #43
Description
The trace comparison analytics pipeline crashed with
AttributeError: 'list' object has no attribute 'get'after PR#33 was merged.Type of Changes
Root Cause
LangfuseAdapter.load_trace()assumed the top-levelinputfield of a Langfuse trace was always a dict{"intent": "...", "task_name": "...", ...}— set explicitly by the oldstart_as_current_observation(input={...})eval wrapper span.PR#33 removed that wrapper span and made the LangGraph
CallbackHandlerthe trace root. LangGraph records the raw message list passed toagent.invokeas the trace input, sodata["input"]is now a list of{"role": ..., "content": ...}dicts. Calling.get("intent")on a list raisesAttributeError.Solution
Handle both formats in
langfuse_adapter.py:input["intent"]directlycontentfrom the firstuser-role message, which is the task intent string passed toHumanMessage(content=intent)Testing
./scripts/analyze.sh --analytics trace_compare --config all_trajectories.confno longer crashes)Checklist
Summary by CodeRabbit