mirror of
https://github.com/hwchase17/langchain.git
synced 2026-04-25 01:16:55 +00:00
When a langsmith `@traceable` function invokes a LangChain Runnable or LangGraph subgraph, the callback manager's `_configure` function injects the `@traceable` RunTree into the `LangChainTracer`'s `run_map` so that child runs can resolve their parent for trace nesting. However, since the RunTree was created outside the tracer's callback lifecycle, `_end_trace` never removes it. The entry persists in `run_map` indefinitely, retaining the full RunTree and its entire child tree. In applications with nested subgraph invocations (e.g. an outer investigation graph delegating to skill agent subgraphs, each compiled as their own `StateGraph`), this causes RunTree objects to accumulate linearly with every call. **Fix:** Track which `run_map` entries were injected externally via a shared `_external_run_ids` refcount dict on `_TracerCore`. When `_start_trace` adds a child under an external parent, it increments the count. When `_end_trace` finishes a child, it decrements — and evicts the external parent from `run_map` once the last child completes. The refcount (rather than a simple set) is necessary because a single external parent may have multiple sibling children in the callback chain (e.g. a `prompt | llm` `RunnableSequence`). Only truly external runs are tracked — the `_configure` guard `if run_id_str not in handler.run_map` prevents tracer-managed runs from being misclassified.