Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/providers/mistral.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,31 @@
```
## Provider-specific options

### Reasoning Effort

Adjustable reasoning is currently supported by `mistral-small-latest` via the `reasoning_effort` parameter.

```php
use Prism\Prism\Facades\Prism;

$response = Prism::text()
->using('mistral', 'mistral-small-latest')
->withPrompt('Solve this logic problem step by step.')
->withProviderOptions([ // [!code focus]
'reasoning_effort' => 'high', // [!code focus]
]) // [!code focus]
->asText();

// Access the final answer
echo $response->text;

// Access the reasoning process
echo $response->additionalContent['thinking'];
```

More details in the official Mistral documentation:
https://docs.mistral.ai/capabilities/reasoning/adjustable

## Reasoning Models
### Using Reasoning Models

Expand Down
1 change: 1 addition & 0 deletions src/Providers/Mistral/Handlers/Stream.php
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ protected function sendRequest(Request $request): Response
], Arr::whereNotNull([
'temperature' => $request->temperature(),
'top_p' => $request->topP(),
'reasoning_effort' => $request->providerOptions('reasoning_effort'),
'tools' => ToolMap::map($request->tools()),
'tool_choice' => ToolChoiceMap::map($request->toolChoice()),
]))
Expand Down
1 change: 1 addition & 0 deletions src/Providers/Mistral/Handlers/Structured.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ protected function sendRequest(Request $request): ClientResponse
], Arr::whereNotNull([
'temperature' => $request->temperature(),
'top_p' => $request->topP(),
'reasoning_effort' => $request->providerOptions('reasoning_effort'),
'response_format' => ['type' => 'json_object'],
]))
);
Expand Down
1 change: 1 addition & 0 deletions src/Providers/Mistral/Handlers/Text.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ protected function sendRequest(Request $request): ClientResponse
], Arr::whereNotNull([
'temperature' => $request->temperature(),
'top_p' => $request->topP(),
'reasoning_effort' => $request->providerOptions('reasoning_effort'),
'tools' => ToolMap::map($request->tools()),
'tool_choice' => ToolChoiceMap::map($request->toolChoice()),
]))
Expand Down
19 changes: 19 additions & 0 deletions tests/Providers/Mistral/MistralTextTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,25 @@
expect($response->steps->last())
->additionalContent->thinking->toBe($expectedThinking);
});

it('forwards reasoning_effort provider option', function (): void {
FixtureResponse::fakeResponseSequence('v1/chat/completions', 'mistral/generate-text-with-a-prompt');

Prism::text()
->using(Provider::Mistral, 'mistral-small-latest')
->withPrompt('Who are you?')
->withProviderOptions([
'reasoning_effort' => 'high',
])
->generate();

Http::assertSent(function (Request $request): bool {
$payload = $request->data();

return isset($payload['reasoning_effort'])
&& $payload['reasoning_effort'] === 'high';
});
});
});

describe('Image support', function (): void {
Expand Down
27 changes: 27 additions & 0 deletions tests/Providers/Mistral/StreamTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Tests\Providers\Mistral;

use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
use Prism\Prism\Enums\FinishReason;
use Prism\Prism\Enums\Provider;
Expand Down Expand Up @@ -248,6 +249,32 @@
});
});

it('forwards reasoning_effort provider option for streaming requests', function (): void {
Http::fake([
'*' => Http::response(
"data: {\"choices\": [{\"delta\": {\"content\": \"Hello\"}}]}\n\ndata: {\"choices\": [{\"delta\": {\"content\": \" world\"}, \"finish_reason\": \"stop\"}]}\n\n",
200,
['Content-Type' => 'text/event-stream']
),
])->preventStrayRequests();

Prism::text()
->using(Provider::Mistral, 'mistral-small-latest')
->withPrompt('Test')
->withProviderOptions([
'reasoning_effort' => 'high',
])
->asStream()
->current();

Http::assertSent(function (Request $request): bool {
$data = $request->data();

return isset($data['reasoning_effort'])
&& $data['reasoning_effort'] === 'high';
});
});

it('can handle event types correctly', function (): void {
FixtureResponse::fakeStreamResponses('v1/chat/completions', 'mistral/stream-with-tools-1');

Expand Down
32 changes: 32 additions & 0 deletions tests/Providers/Mistral/StructuredTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Prism\Prism\Enums\Provider;
use Prism\Prism\Facades\Prism;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
use Prism\Prism\Schema\BooleanSchema;
use Prism\Prism\Schema\ObjectSchema;
use Prism\Prism\Schema\StringSchema;
Expand Down Expand Up @@ -51,3 +53,33 @@
expect($response->usage->promptTokens)->toBe(45);
expect($response->usage->completionTokens)->toBe(34);
});

it('forwards reasoning_effort provider option for structured requests', function (): void {
FixtureResponse::fakeResponseSequence('chat/completions', 'mistral/structured');

$schema = new ObjectSchema(
'output',
'the output object',
[
new StringSchema('weather', 'The weather forecast'),
],
['weather']
);

Prism::structured()
->withSchema($schema)
->using(Provider::Mistral, 'mistral-large-latest')
->withPrompt('What is the weather?')
->withProviderOptions([
'reasoning_effort' => 'high',
])
->asStructured();

Http::assertSent(function (Request $request): bool {
$payload = $request->data();

return isset($payload['reasoning_effort'])
&& $payload['reasoning_effort'] === 'high';
});
});