Repository navigation
Conversation
Mistral streams a tool call's id and name only on the first delta; continuation deltas carry only the index and an arguments fragment, so the mistralai SDK fills their id with its default "null". Keying the aggregation dict by id therefore landed every continuation fragment in a spurious "null" bucket: the toolUse block carrying the real id was emitted with an empty input, and the event loop dropped the spurious block as incomplete. With parallel tool calls, fragments of different tools merged into that single bucket. Key the deltas by index instead, matching the OpenAI, LiteLLM, SageMaker and Writer providers.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
MistralModel.streamaggregated streamed tool-call deltas in a dict keyed bytool_call.id(strands-py/src/strands/models/mistral.py:538before this change). Mistral sends a tool call'sidandnameonly on the first delta; continuation deltas carry only theindexand anargumentsfragment, and the mistralai SDK fills the missingidwith its default"null"(ToolCall.id: Optional[str] = "null"in mistralai 2.x). Every continuation fragment therefore landed in a spurious"null"bucket:toolUseblock carrying the real id was emitted with only the first delta's emptyarguments, so the event loop parsed its input as{}(strands/event_loop/streaming.py:301-302) and the tool executed without its argumentsname=""/toolUseId="null"carried the fragments and was dropped as an incomplete tool use (strands/event_loop/streaming.py:318)"null"bucketKeying the dict by
tool_call.indexkeeps each tool's fragments under the delta that carries its id and name, matching the OpenAI (openai.py:780), LiteLLM (litellm.py:518), SageMaker (sagemaker.py:475), and Writer (writer.py:441) providers.Related Issues
None — no existing issue found for this bug.
Documentation PR
Not needed — no public API change; internal aggregation fix only.
Type of Change
Bug fix
Testing
Two regression tests in
tests/strands/models/test_mistral.pystream (1) a single fragmented tool call and (2) two parallel tool calls, with continuation deltas carryingid="null"as the mistralai SDK fills in. Both fail on the previous id-keyed aggregation and pass with this change.Run from
strands-py/(project venv, Python 3.12):.venv/bin/python -m pytest tests/strands/models/test_mistral.py -k fragmented -q→2 passed, 59 deselected(on unpatchedmain:2 failed, 59 deselected).venv/bin/python -m pytest tests/strands/models/test_mistral.py -q→61 passed.venv/bin/python -m pytest tests/ -q→6973 passed, 31 skipped.venv/bin/ruff format --check→727 files already formatted.venv/bin/ruff check→All checks passed!.venv/bin/mypy ./src ./tests_typing→ blocked locally by a pre-existing environment mismatch: the venv's installedsmithy_*packages use Python 3.12-only syntax while the repo pinspython_version = "3.10", and the failure is identical on unmodifiedmain. With--python-version 3.12it completes over 327 files with only a pre-existing unused-ignore in_exception_notes.py(an artifact of overriding the target version); this change adds no mypy errors.hatch run prepareitself could not run in this environment (hatch env creation fails building a native dependency), so the constituent checks above were run directly.hatch run prepareChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.