Skip to content

Commit abc17a4

Browse files
committed
fix: preserve system prompts for Mistral Chat Completions
1 parent 0fa4888 commit abc17a4

3 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎packages/local-runtime-v2/src/service/model-system/resolution/local-model-resolver.test.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,10 @@ describe('LocalModelResolver custom provider compat overrides', () => {
14471447
expect(await systemPromptRoleFor(undefined)).toBe('developer');
14481448
});
14491449

1450+
it('keeps the system role for a thinking model on the Mistral API', async () => {
1451+
expect(await systemPromptRoleFor(undefined, 'https://api.mistral.ai/v1')).toBe('system');
1452+
});
1453+
14501454
it.each([
14511455
'https://api.siliconflow.cn/v1',
14521456
'https://api.siliconflow.com/v1',
@@ -1474,6 +1478,8 @@ describe('LocalModelResolver custom provider compat overrides', () => {
14741478
it.each([
14751479
['https://api.openai.com/v1', 'developer'],
14761480
['https://api.deepseek.com/v1', 'system'],
1481+
['https://api.mistral.ai.example/v1', 'developer'],
1482+
['https://gateway.example/api.mistral.ai/v1', 'developer'],
14771483
['https://api.siliconflow.cn.example/v1', 'developer'],
14781484
['https://gateway.example/api.siliconflow.cn/v1', 'developer'],
14791485
['https://api.siliconflow.com.example/v1', 'developer'],
@@ -1493,6 +1499,12 @@ describe('LocalModelResolver custom provider compat overrides', () => {
14931499
expect(await systemPromptRoleFor(undefined, baseURL)).toBe(role);
14941500
});
14951501

1502+
it('honors an explicit developer-role override on the Mistral API', async () => {
1503+
expect(
1504+
await systemPromptRoleFor({ supportsDeveloperRole: true }, 'https://api.mistral.ai/v1'),
1505+
).toBe('developer');
1506+
});
1507+
14961508
it.each([
14971509
'https://api.siliconflow.cn/v1',
14981510
'https://api.siliconflow.com/v1',

‎third_party/pi-mono/MINIMAX_CHANGES.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ This directory vendors `pi-mono` as source so MiniMax can patch, validate, and s
1313

1414
No upstream source files are changed in the baseline import.
1515

16+
### 2026-09-19 — preserve the system role for Mistral Chat Completions
17+
18+
- Reason: thinking-enabled custom OpenAI-compatible connections to `api.mistral.ai` emitted `developer`, which is absent from the [Mistral Chat Completions message contract](https://docs.mistral.ai/api/endpoint/chat). [OpenClaw's compatibility defaults](https://github.com/openclaw/openclaw/blob/e2bcb1614de060927121bd72de850cee3a08d308/packages/ai/src/transports/openai-completions-compat.ts#L184-L210) also disable this role for the Mistral public endpoint.
19+
- Affected package: `packages/ai` (`@earendil-works/pi-ai`), OpenAI Completions compatibility detection.
20+
- Change: default to `system` only on the exact Mistral API host. Preserve thinking, explicit compatibility overrides, all other request options, and other endpoints. Native Mistral transport is unchanged.
21+
- Upstream PR: not opened.
22+
- Validation: outgoing-payload regressions in `packages/local-runtime-v2/src/service/model-system/resolution/local-model-resolver.test.ts`; the endpoint regression fails before the fix. No live Mistral requests or full CLI acceptance were performed; the decision is based on the official contract and current upstream implementation.
23+
1624
### 2026-09-19 — preserve the system role for SiliconFlow
1725

1826
- Reason: thinking-enabled OpenAI-compatible requests sent the `developer` role, which is absent from SiliconFlow's documented message schema.

‎third_party/pi-mono/packages/ai/src/providers/openai-completions.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,7 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet
10951095
/^https?:\/\/(?:dashscope(?:-intl|-us)?|(?:coding(?:-intl)?|cn-hongkong)\.dashscope)\.aliyuncs\.com(?::\d+)?(?:\/|$)/i.test(baseUrl) ||
10961096
/^https?:\/\/[a-z0-9-]+\.(?:cn-beijing|cn-hongkong|ap-southeast-1|ap-northeast-1|eu-central-1|us-east-1)\.maas\.aliyuncs\.com(?::\d+)?(?:\/|$)/i.test(baseUrl);
10971097
const isSiliconFlow = /^https?:\/\/api\.siliconflow\.(?:cn|com)(?::\d+)?(?:\/|$)/i.test(baseUrl);
1098+
const isMistralApi = /^https?:\/\/api\.mistral\.ai(?::\d+)?(?:\/|$)/i.test(baseUrl);
10981099
const isOpenRouter = provider === "openrouter" || baseUrl.includes("openrouter.ai");
10991100
const isCloudflareWorkersAI = provider === "cloudflare-workers-ai" || baseUrl.includes("api.cloudflare.com");
11001101
const isCloudflareAiGateway = provider === "cloudflare-ai-gateway" || baseUrl.includes("gateway.ai.cloudflare.com");
@@ -1130,7 +1131,11 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet
11301131
return {
11311132
supportsStore: !isNonStandard,
11321133
supportsDeveloperRole:
1133-
!isKimiCoding && !isDashScope && !isSiliconFlow && (isOpenRouterDeveloperRoleModel || (!isNonStandard && !isOpenRouter)),
1134+
!isKimiCoding &&
1135+
!isDashScope &&
1136+
!isSiliconFlow &&
1137+
!isMistralApi &&
1138+
(isOpenRouterDeveloperRoleModel || (!isNonStandard && !isOpenRouter)),
11341139
supportsReasoningEffort:
11351140
!isGrok && !isZai && !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia && !isAntLing,
11361141
supportsUsageInStreaming: true,

0 commit comments

Comments
 (0)