Skip to content

Add streamed tool calls for Anthropic and expand Mistral tool support#151

Merged
wachterjohannes merged 3 commits into
0.4from
feature/mistral-tools-anthropic-stream-tools
Jun 2, 2026
Merged

Add streamed tool calls for Anthropic and expand Mistral tool support#151
wachterjohannes merged 3 commits into
0.4from
feature/mistral-tools-anthropic-stream-tools

Conversation

@wachterjohannes

@wachterjohannes wachterjohannes commented Jun 2, 2026

Copy link
Copy Markdown
Member

Summary

  • Anthropic streaming tool callsAnthropicChatAdapter now assembles tool invocations from the streamed tool_use start block (id + name) and the following input_json_delta fragments, decoding the concatenated JSON once the stream signals stop_reason: "tool_use". Previously tool calls were only supported on non-streamed responses.
  • Fail-fast argument decoding — malformed or truncated argument JSON now throws (JSON_THROW_ON_ERROR) instead of silently producing an empty-argument tool call. A genuine no-argument call still resolves to [].
  • Response model extendedCreateStreamedResponseDelta / CreateStreamedResponse carry the new tool-call fields (id, name, input, partial_json) and only require index + type.
  • Mistral tool support expandedModel::toolsSupported() now covers small, medium, large, nemo and pixtral-large (was large-only), reflecting the models that actually support function calling.

Tests

  • New testHandleRequestStreamedWithTools (anthropic-adapter) covering the full streamed tool-call flow.
  • New testCreateStreamedWithTools (anthropic) verifying parsing of tool_use and input_json_delta deltas.
  • Mistral exception tests updated to use tiny (still unsupported) now that medium supports tools.

Validation

✅ PHPUnit, ✅ PHPStan, ✅ PHP-CS-Fixer / Rector — all green across the anthropic, anthropic-adapter and mistral packages.

Summary by CodeRabbit

  • New Features

    • Tool calls now supported in streamed Anthropic chat responses with proper JSON argument handling.
    • Tool functionality expanded to SMALL, MEDIUM, LARGE, NEMO, and PIXTRAL_LARGE Mistral models.
  • Tests

    • Added comprehensive test coverage for streamed tool handling in Anthropic adapter.
    • Updated Mistral model tool support tests for expanded model compatibility.

Anthropic streaming now assembles tool invocations from the "tool_use"
start block and the following "input_json_delta" fragments, decoding the
concatenated JSON once the stream signals stop_reason "tool_use".
Malformed or truncated argument JSON fails fast instead of being silently
dropped.

Mistral tool support is expanded beyond the large model to small, medium,
nemo and pixtral-large, which all support function calling.
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@wachterjohannes, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 47 minutes and 51 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a02233cc-9d88-4b09-ab9f-7070dcbeed78

📥 Commits

Reviewing files that changed from the base of the PR and between 489c437 and 1fb7985.

⛔ Files ignored due to path filters (24)
  • composer.lock is excluded by !**/*.lock
  • integrations/symfony/composer.lock is excluded by !**/*.lock
  • packages/anthropic-adapter/composer.lock is excluded by !**/*.lock
  • packages/anthropic/composer.lock is excluded by !**/*.lock
  • packages/api-client/composer.lock is excluded by !**/*.lock
  • packages/chat/composer.lock is excluded by !**/*.lock
  • packages/completion/composer.lock is excluded by !**/*.lock
  • packages/decision-tree/composer.lock is excluded by !**/*.lock
  • packages/elasticsearch-embeddings-store/composer.lock is excluded by !**/*.lock
  • packages/embeddings/composer.lock is excluded by !**/*.lock
  • packages/experts/composer.lock is excluded by !**/*.lock
  • packages/fireworksai-adapter/composer.lock is excluded by !**/*.lock
  • packages/google-gemini-adapter/composer.lock is excluded by !**/*.lock
  • packages/image/composer.lock is excluded by !**/*.lock
  • packages/mistral-adapter/composer.lock is excluded by !**/*.lock
  • packages/mistral/composer.lock is excluded by !**/*.lock
  • packages/ollama-adapter/composer.lock is excluded by !**/*.lock
  • packages/ollama/composer.lock is excluded by !**/*.lock
  • packages/openai-adapter/composer.lock is excluded by !**/*.lock
  • packages/prompt-template/composer.lock is excluded by !**/*.lock
  • packages/qdrant-embeddings-store/composer.lock is excluded by !**/*.lock
  • packages/tools/composer.lock is excluded by !**/*.lock
  • projects/chat/composer.lock is excluded by !**/*.lock
  • projects/readme-generator/composer.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • packages/mistral/tests/Unit/Resources/ChatTest.php
  • projects/chat/config/reference.php

Walkthrough

This PR implements streamed tool-call handling for the Anthropic adapter and expands tool support in the Mistral adapter. The Anthropic changes extend response types to carry tool metadata, rework the streaming loop to accumulate and synthesize tool messages, and validate the flow end-to-end. The Mistral changes broaden tool support from one model to five.

Changes

Anthropic Streamed Tool Support

Layer / File(s) Summary
Response Delta Type Extensions
packages/anthropic/src/Responses/Messages/CreateStreamedResponseDelta.php, packages/anthropic/src/Responses/Messages/CreateStreamedResponse.php
CreateStreamedResponseDelta becomes nullable on text and gains id, name, input, partialJson fields to carry tool-use block and JSON delta payloads; from() validation now requires only index and type. CreateStreamedResponse PHPDoc expanded to document the broader content shape union.
Adapter Streamed Tool Implementation
packages/anthropic/src/DataFixtures.php, packages/anthropic-adapter/src/Chat/AnthropicChatAdapter.php
Adapter's createStreamedMessages() accumulates streamed tool_use blocks by index, concatenates input_json_delta fragments into per-tool JSON strings, emits text deltas in-stream, and synthesizes final AIChatToolCall messages when stopReason indicates tool invocation. Added buildToolCalls() and decodeArguments() helpers with strict JSON error handling. Test fixture added for streamed tool responses.
Integration Tests and Baseline Adjustment
packages/anthropic/tests/Unit/Resources/MessagesTest.php, packages/anthropic-adapter/tests/Unit/Chat/AnthropicChatAdapterTest.php, packages/anthropic-adapter/phpstan-baseline.neon
New test testCreateStreamedWithTools() validates core tool response parsing; new test testHandleRequestStreamedWithTools() validates adapter-level tool aggregation across chunks. PHPStan baseline count updated from 1 to 2 for adapter test assertions.

Mistral Tool Support Broadening

Layer / File(s) Summary
Tool Support Broadening
packages/mistral/src/Model.php, packages/mistral/tests/Unit/Resources/ChatTest.php
Model::toolsSupported() now returns true for SMALL, MEDIUM, LARGE, NEMO, and PIXTRAL_LARGE; two negative-path tool tests updated to use Model::TINY instead of Model::MEDIUM for clearer validation of unsupported-model rejection.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • modelflow-ai/.github#146: Both PRs modify packages/anthropic-adapter/src/Chat/AnthropicChatAdapter.php and adapter tests to implement Anthropic tool-call handling, with this PR extending specifically the streamed tool-delta accumulation behavior.

🐰 A Tool-Call Dream

Streams of tools now flow with grace,
JSON fragments find their place,
Anthropic whispers, Mistral spreads,
Tool support blooms where code treads.
Rabbit cheers this feature quest! 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the two main changes: adding streamed tool calls for Anthropic and expanding Mistral tool support, which align with the substantial modifications across adapter and response model classes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/mistral-tools-anthropic-stream-tools

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/mistral/tests/Unit/Resources/ChatTest.php (2)

314-324: ⚡ Quick win

Consider renaming test method to reflect actual intent.

Now that multiple models support tools, the name testCreateStreamedWithToolsForNoneLarge is misleading. The test validates rejection of tool calls for unsupported models. Additionally, "NoneLarge" appears to be a typo.

Suggested rename: testCreateStreamedWithToolsForUnsupportedModel

📝 Proposed rename
-    public function testCreateStreamedWithToolsForNoneLarge(): void
+    public function testCreateStreamedWithToolsForUnsupportedModel(): void
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mistral/tests/Unit/Resources/ChatTest.php` around lines 314 - 324,
Rename the PHPUnit test method testCreateStreamedWithToolsForNoneLarge to a name
that reflects its intent; update the method declaration in class ChatTest from
testCreateStreamedWithToolsForNoneLarge to
testCreateStreamedWithToolsForUnsupportedModel so it clearly indicates the test
verifies rejection of tool calls for unsupported models (keep the body,
assertions and references to createStreamed,
DataFixtures::CHAT_CREATE_REQUEST_WITH_TOOLS, and Model::TINY unchanged).

158-170: ⚡ Quick win

Consider renaming test method to reflect actual intent.

Now that multiple models (SMALL, MEDIUM, LARGE, NEMO, PIXTRAL_LARGE) support tools, the name testCreateWithToolsForNonLargeModel is misleading. The test validates rejection of tool calls for unsupported models, not "non-large" models specifically.

Suggested rename: testCreateWithToolsForUnsupportedModel

📝 Proposed rename
-    public function testCreateWithToolsForNonLargeModel(): void
+    public function testCreateWithToolsForUnsupportedModel(): void
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mistral/tests/Unit/Resources/ChatTest.php` around lines 158 - 170,
Rename the test method to reflect that it asserts rejection for models that do
not support tools: change the method name testCreateWithToolsForNonLargeModel to
testCreateWithToolsForUnsupportedModel inside the ChatTest class; update any
references or usages (e.g., the test method definition itself and any test suite
metadata) so the method still executes, keeping the body that sets $requestData
= DataFixtures::CHAT_CREATE_REQUEST_WITH_TOOLS and $requestData['model'] =
Model::TINY->value and the assertions around
$this->expectException(\InvalidArgumentException::class) and
$chat->create($requestData).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/mistral/tests/Unit/Resources/ChatTest.php`:
- Around line 314-324: Rename the PHPUnit test method
testCreateStreamedWithToolsForNoneLarge to a name that reflects its intent;
update the method declaration in class ChatTest from
testCreateStreamedWithToolsForNoneLarge to
testCreateStreamedWithToolsForUnsupportedModel so it clearly indicates the test
verifies rejection of tool calls for unsupported models (keep the body,
assertions and references to createStreamed,
DataFixtures::CHAT_CREATE_REQUEST_WITH_TOOLS, and Model::TINY unchanged).
- Around line 158-170: Rename the test method to reflect that it asserts
rejection for models that do not support tools: change the method name
testCreateWithToolsForNonLargeModel to testCreateWithToolsForUnsupportedModel
inside the ChatTest class; update any references or usages (e.g., the test
method definition itself and any test suite metadata) so the method still
executes, keeping the body that sets $requestData =
DataFixtures::CHAT_CREATE_REQUEST_WITH_TOOLS and $requestData['model'] =
Model::TINY->value and the assertions around
$this->expectException(\InvalidArgumentException::class) and
$chat->create($requestData).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7dd94684-26e8-42fa-afaa-168aecaa6a30

📥 Commits

Reviewing files that changed from the base of the PR and between eae686d and 489c437.

📒 Files selected for processing (9)
  • packages/anthropic-adapter/phpstan-baseline.neon
  • packages/anthropic-adapter/src/Chat/AnthropicChatAdapter.php
  • packages/anthropic-adapter/tests/Unit/Chat/AnthropicChatAdapterTest.php
  • packages/anthropic/src/DataFixtures.php
  • packages/anthropic/src/Responses/Messages/CreateStreamedResponse.php
  • packages/anthropic/src/Responses/Messages/CreateStreamedResponseDelta.php
  • packages/anthropic/tests/Unit/Resources/MessagesTest.php
  • packages/mistral/src/Model.php
  • packages/mistral/tests/Unit/Resources/ChatTest.php

The tests now reject tool calls for Model::TINY, so name them
ForUnsupportedModel instead of the outdated ForNonLarge/ForNoneLarge.
@wachterjohannes wachterjohannes merged commit 38621c3 into 0.4 Jun 2, 2026
86 checks passed
@wachterjohannes wachterjohannes deleted the feature/mistral-tools-anthropic-stream-tools branch June 2, 2026 06:28
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.

1 participant