Skip to content

Duplicate same-name parallel tool calls collapse to a single execution #1431

Description

@ajbozarth

Summary

When a model requests the same tool more than once in a single response (parallel tool calling — e.g. search({"q": "X"}) and search({"q": "Y"}) in one turn), Mellea executes only the last call and silently drops the rest.

Root cause

Model tool calls are stored in a dict keyed by tool name:

  • ModelOutputThunk.tool_calls: dict[str, ModelToolCall] (mellea/core/base.py)
  • Populated per backend via model_tool_calls[tool_name] = ModelToolCall(...):
    • mellea/helpers/openai_compatible_helpers.py (OpenAI-compatible, LiteLLM, Watsonx)
    • mellea/backends/ollama.py

Because the key is the tool name, a second call to the same name overwrites the first before execution. _acall_tools (mellea/stdlib/functional.py) then iterates the collapsed dict, so the tool runs once and produces a single ToolMessage. The dropped call's result never returns to the model.

This dates to the initial commit and predates parallel tool calling being common; the "one call per tool name per turn" assumption is no longer valid for current OpenAI/Anthropic-style APIs.

Impact

  • Correctness (primary): parallel calls to the same tool with different arguments lose all but the last. Affects tool execution and the messages fed back to the model — not just observability.
  • Observability (symptom): the mellea.tool.calls metric and the execute_tool span each fire once instead of N times. This faithfully reflects that only one call executed — the telemetry is correct about a broken execution. No telemetry code needs to change.

Suggested fix

Key tool calls by the provider-supplied call id rather than by name. ModelToolCall.tool_call_id (added in #1430) is the field a fix would key on. This is a data-model change (dict[str, ModelToolCall] → keyed by call id, or a list) touching core/base.py and all four backend extraction sites; no telemetry code needs to change — the correct span/metric cardinality falls out automatically once execution stops collapsing.

Related

Metadata

Metadata

Assignees

Labels

area/toolsTool framework, Bash/Python tools, tool call lifecyclebugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions