fix: Fixes agent graph tool calls in fanned out graphs#123
fix: Fixes agent graph tool calls in fanned out graphs#123jsonbailey wants to merge 6 commits intomainfrom
Conversation
…ring - Add _coalesce_tool_messages_for_openai to fix parallel fan-out causing OpenAI 400 errors when sibling branch tool_calls have no ToolMessages - Add LDMetricsCallbackHandler for per-node token/tool/latency tracking - Add build_structured_tools with async callable support via inspect - Replace fan-out static edges with LLM-driven handoff tools (Command(goto=)) - Switch WorkflowState.messages to add_messages reducer - Add parallel_tool_calls=False when handoff tools present - Remove _coalesce_tool_messages_for_openai (no longer needed with handoffs) - Demote diagnostic logs to debug; exclude handoff tools from LD tracking - Consolidate token extraction to use get_ai_usage_from_response - Fix TestBuildTools to import build_structured_tools; cover async callables Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
a9f1d88 to
7c5d067
Compare
- Remove tool_registry parameter from create_langchain_model (matches main) - Remove _resolve_tools_for_langchain (no longer needed) - Remove BaseMessage import (unused) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use isinstance(gen, ChatGeneration) to type-narrow in callback handler - Declare model as Any to accommodate Runnable return type from bind_tools - Fix bind_kwargs type annotation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
packages/ai-providers/server-ai-langchain/src/ldai_langchain/langgraph_agent_graph_runner.py
Show resolved
Hide resolved
…e node A static loop-back edge from the tools node conflicted with Command(goto=child) emitted by handoff tools, causing both to fire as a fan-out. Fix by replacing the static edge with a conditional edge in the mixed case: after the ToolNode runs, route back to the parent only when the last message is from a functional tool; route to END when it is from a handoff (Command already handles routing to the target agent). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9dec085. Configure here.
| if hasattr(msg, 'name') and msg.name: | ||
| return END if msg.name in ht_names else parent_key | ||
| break | ||
| return parent_key |
There was a problem hiding this comment.
Unconditional break prevents backward scan in router
Medium Severity
The break on line 218 is at the for-loop level (same indentation as if), not inside the if block. This means if the very last message doesn't have a truthy .name, the loop exits immediately without checking any earlier messages. The for msg in reversed(...) pattern implies a backward scan, but the unconditional break makes the loop always terminate after one iteration, rendering reversed() useless. If the last message in state ever lacks a truthy name, the router silently defaults to looping back to the parent instead of finding the most recent named message.
Reviewed by Cursor Bugbot for commit 9dec085. Configure here.


Note
Medium Risk
Refactors LangGraph graph construction, tool binding, and routing logic; mistakes could cause incorrect agent traversal or tool execution/metrics attribution in production agent graphs.
Overview
Fixes LangGraph execution for multi-child (previously fan-out) agent graphs by introducing explicit handoff tools (
transfer_to_*) that route viaCommand(goto=...), disabling parallel tool calls during handoff, and adding conditional tool-node loopback logic when a node has both functional tools and handoff tools.Adds
build_structured_tools()to wrap LD tool definitions as LangChainStructuredTool(sync/async supported) and skips unsupported/built-in tool types. IntroducesLDMetricsCallbackHandlerto collect per-node tokens/durations/tool calls via LangChain callbacks and flush them to LaunchDarkly trackers after the run; tests are updated/added to cover the new routing behavior and callback-based tracking.Reviewed by Cursor Bugbot for commit 9dec085. Bugbot is set up for automated code reviews on this repo. Configure here.