mirror of
https://github.com/HeyPuter/puter.git
synced 2026-09-26 15:15:58 +00:00
feat(ai): forward Mistral prompt_mode so magistral can emit separable thinking
Live-probing magistral-small-latest showed the model inlines its reasoning as
answer prose in a flat string — no ThinkChunk content, no markers, nothing a
client can separate. Mistral's chunked thinking shape is requested via
`prompt_mode: 'reasoning'`, which the provider previously dropped on the
floor: there was no way to even ask for it.
`custom.prompt_mode` now forwards to the SDK's `promptMode`, following the
BytePlus custom-params precedent. Opt-in rather than a default because the
API rejects the mode where the account/model lacks it ('Reasoning prompt
mode is not enabled for this model', code 3051) — verified end-to-end: the
3051 travels back through the stack, which also proves the parameter is
delivered. The moment Mistral enables the mode, the ThinkChunk content flows
into the existing splitter and comes out as `message.reasoning` and
`reasoning` stream chunks with no further changes.
Co-Authored-By: Claude Fable 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
4aa66c7c9b
commit
4199a2506d
@@ -210,6 +210,51 @@ describe('MistralAIProvider.complete request shape', () => {
|
||||
expect(args.temperature).toBe(0.4);
|
||||
});
|
||||
|
||||
it('forwards custom.prompt_mode as the SDK promptMode', async () => {
|
||||
const { provider } = makeProvider();
|
||||
completeMock.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: { role: 'assistant', content: 'ok' },
|
||||
finishReason: 'stop',
|
||||
},
|
||||
],
|
||||
usage: { promptTokens: 1, completionTokens: 1 },
|
||||
});
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'magistral-small-latest',
|
||||
messages: [{ role: 'user', content: 'think' }],
|
||||
custom: { prompt_mode: 'reasoning' },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(completeMock.mock.calls[0]![0].promptMode).toBe('reasoning');
|
||||
});
|
||||
|
||||
it('omits promptMode when custom does not carry prompt_mode', async () => {
|
||||
const { provider } = makeProvider();
|
||||
completeMock.mockResolvedValueOnce({
|
||||
choices: [
|
||||
{
|
||||
message: { role: 'assistant', content: 'ok' },
|
||||
finishReason: 'stop',
|
||||
},
|
||||
],
|
||||
usage: { promptTokens: 1, completionTokens: 1 },
|
||||
});
|
||||
|
||||
await withTestActor(() =>
|
||||
provider.complete({
|
||||
model: 'mistral-small-2603',
|
||||
messages: [{ role: 'user', content: 'hi' }],
|
||||
}),
|
||||
);
|
||||
|
||||
expect('promptMode' in completeMock.mock.calls[0]![0]).toBe(false);
|
||||
});
|
||||
|
||||
it('omits the `tools` key when no tools are supplied', async () => {
|
||||
const { provider } = makeProvider();
|
||||
completeMock.mockResolvedValueOnce(baseCompletion);
|
||||
|
||||
@@ -152,7 +152,19 @@ export class MistralAIProvider implements IChatProvider {
|
||||
temperature,
|
||||
normalize,
|
||||
response,
|
||||
custom,
|
||||
}: ICompleteArguments): Promise<IChatCompleteResult> {
|
||||
// Mistral's reasoning prompt mode: with `prompt_mode: 'reasoning'`,
|
||||
// magistral models return their thinking as structured ThinkChunk
|
||||
// content (which the splitter below separates into `reasoning`)
|
||||
// instead of inlining it as answer prose. Opt-in passthrough rather
|
||||
// than a default because the API rejects it on accounts/models where
|
||||
// the mode is not enabled ('Reasoning prompt mode is not enabled for
|
||||
// this model', code 3051).
|
||||
const customParams =
|
||||
custom && typeof custom === 'object' && !Array.isArray(custom)
|
||||
? (custom as { prompt_mode?: 'reasoning' | null })
|
||||
: {};
|
||||
messages = await OpenAIUtil.process_input_messages(messages);
|
||||
messages = this.#coerceImageUrls(messages);
|
||||
for (const message of messages) {
|
||||
@@ -177,6 +189,9 @@ export class MistralAIProvider implements IChatProvider {
|
||||
]({
|
||||
model: selectedModel.id,
|
||||
...(tools ? { tools: tools as any[] } : {}),
|
||||
...(customParams.prompt_mode !== undefined
|
||||
? { promptMode: customParams.prompt_mode }
|
||||
: {}),
|
||||
messages,
|
||||
maxTokens: max_tokens,
|
||||
temperature,
|
||||
|
||||
Reference in New Issue
Block a user