Skip to content

fix(api): generate Mistral-compliant tool-call ids#1997

Open
sam-fakhreddine wants to merge 1 commit into
jundot:mainfrom
sam-fakhreddine:fix/tool-call-id-mistral
Open

fix(api): generate Mistral-compliant tool-call ids#1997
sam-fakhreddine wants to merge 1 commit into
jundot:mainfrom
sam-fakhreddine:fix/tool-call-id-mistral

Conversation

@sam-fakhreddine

Copy link
Copy Markdown

Fixes #1995.

Problem

omlx generates tool-call ids as call_<8 hex> (e.g. call_49c89af0). Mistral /
tekken (MistralCommonBackend) validates tool_call_id against [a-zA-Z0-9]
with a length of exactly 9 and rejects anything else when the assistant turn
is replayed on the next request:

HTTP 500: Tool call id was call_49c89af0 but must be a-z, A-Z, 0-9,
with a length of 9

So the first turn works and the second 500s — on the id the server itself
generated. Every multi-turn tool loop with Devstral / Mistral-Small breaks.

Fix

Centralize id creation in shared_models.generate_tool_call_id():

return f"call{uuid.uuid4().hex[:5]}"   # "call" + 5 hex = exactly 9 alphanumeric

Valid for Mistral and still an opaque, recognizable id for OpenAI / Anthropic
clients (which treat the id as opaque — nothing in the codebase matches on the
call_ prefix). Replaces all 17 inline f"call_{uuid.uuid4().hex[:8]}"
sites across tool_calling.py (10), server.py (3), anthropic_utils.py (2)
and responses_utils.py (2), and drops the now-unused uuid import where it was
only used for ids.

Tests

tests/test_shared_models.py::TestGenerateToolCallId — asserts the id is exactly
9 chars, matches [a-zA-Z0-9], has no underscore, and is unique across many
draws.

omlx minted tool-call ids as "call_<8 hex>" (13 chars, underscore). Mistral /
tekken (MistralCommonBackend) validates tool_call_id against [a-zA-Z0-9] with a
length of exactly 9 and rejects anything else when the assistant turn is
replayed on the next request -> HTTP 500 on multi-turn tool loops with Devstral,
Mistral-Small, etc. The first turn worked; the second 500'd on the id the server
itself generated.

Centralizes id creation in shared_models.generate_tool_call_id() -> "call" + 5
hex = exactly 9 alphanumeric chars: valid for Mistral and still an opaque id for
OpenAI / Anthropic clients. Replaces all 17 inline call-sites across
tool_calling.py, anthropic_utils.py, responses_utils.py and server.py (dropping
the now-unused uuid import where it was only used for ids). Adds unit tests
asserting the [a-zA-Z0-9]{9} constraint.
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.

Tool-call ids (call_<8hex>) rejected by Mistral/tekken on multi-turn loops — HTTP 500

1 participant