Skip to content

Fix logging for parallel tool calls in Langfuse hook#6

Open
junwai7159 wants to merge 1 commit into
langfuse:mainfrom
junwai7159:fix/parallel-tool-calls
Open

Fix logging for parallel tool calls in Langfuse hook#6
junwai7159 wants to merge 1 commit into
langfuse:mainfrom
junwai7159:fix/parallel-tool-calls

Conversation

@junwai7159

Copy link
Copy Markdown

Problem

When a turn fires several tools in parallel (e.g. 3 WebFetch calls at once or multiple subagents launched together via Agent), only the last tool span shows up in Langfuse. The rest silently vanish.

Root cause

Claude Code writes one logical assistant message (single message.id) as several transcript rows: the thinking/text rows first, then one row per parallel tool_use block, and these rows can be interleaved with tool_result rows. build_turns() de-dupes assistant rows by message.id with a "latest row wins" assignment:

mid = get_message_id(msg) or f"noid:{len(assistant_order)}"
if mid not in assistant_latest:
    assistant_order.append(mid)
assistant_latest[mid] = msg  # overwrites; earlier tool_use rows are lost

So every parallel tool call but the last gets overwritten before emit.

Raw transcript evidence

A real turn that fired 4 parallel Read calls. These are 4 separate JSONL rows (distinct uuid + timestamp), but all share one message.id and each carries a single tool_use block (fields trimmed to the relevant ones):

// row 1
{
  "message": {
    "id": "msg_bdrk_…je4ivmq",
    "role": "assistant",
    "content": [
      {
        "type": "tool_use",
        "id": "toolu_…HV2",
        "name": "Read",
        "input": {
          "file_path": ".../subagent_one.md"
        }
      }
    ]
  },
  "uuid": "334452ca-…",
  "timestamp": "2026-06-19T08:42:41.885Z"
}

// row 2
{
  "message": {
    "id": "msg_bdrk_…je4ivmq",
    "role": "assistant",
    "content": [
      {
        "type": "tool_use",
        "id": "toolu_…8q4",
        "name": "Read",
        "input": {
          "file_path": ".../subagent_two.md"
        }
      }
    ]
  },
  "uuid": "d3cfa674-…",
  "timestamp": "2026-06-19T08:42:42.885Z"
}

// row 3
{
  "message": {
    "id": "msg_bdrk_…je4ivmq",
    "role": "assistant",
    "content": [
      {
        "type": "tool_use",
        "id": "toolu_…y4J",
        "name": "Read",
        "input": {
          "file_path": ".../subagent_three.md"
        }
      }
    ]
  },
  "uuid": "bd31bb32-…",
  "timestamp": "2026-06-19T08:42:42.921Z"
}

// row 4
{
  "message": {
    "id": "msg_bdrk_…je4ivmq",
    "role": "assistant",
    "content": [
      {
        "type": "tool_use",
        "id": "toolu_…PFY",
        "name": "Read",
        "input": {
          "file_path": ".../subagent_four.md"
        }
      }
    ]
  },
  "uuid": "7e37ddc2-…",
  "timestamp": "2026-06-19T08:42:43.139Z"
}

All four rows hash to the same key in assistant_latest, so the dict assignment keeps only row 4 (subagent_four.md) — rows 1–3 are silently overwritten and never emitted to Langfuse.

Note the rows aren't contiguous in the file either: tool_result rows for the earlier calls interleave between them, so a positional fix wouldn't be safe — merging by message.id is.

Fix

Merge the content blocks across rows that share a message.id instead of overwriting, so all tool_use blocks survive.

Metadata (model, usage, timestamp) is identical across the split rows, so the first row's values are kept.

Notes

  • No behavior change for single-tool turns.
  • Only affects turns traced after the fix; turns already recorded in ~/.claude/state/langfuse_state.json are not rewritten.

Ensure parallel tool calls are logged correctly to Langfuse by fixing conditional handling and adding clearer context to log entries in hooks/langfuse_hook.py
@CLAassistant

CLAassistant commented Jun 22, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants