diff --git a/packages/local-runtime-v2/src/service/model-system/resolution/local-model-resolver.test.ts b/packages/local-runtime-v2/src/service/model-system/resolution/local-model-resolver.test.ts index 15c483616..b3bd4e53c 100644 --- a/packages/local-runtime-v2/src/service/model-system/resolution/local-model-resolver.test.ts +++ b/packages/local-runtime-v2/src/service/model-system/resolution/local-model-resolver.test.ts @@ -1448,6 +1448,21 @@ describe('LocalModelResolver custom provider compat overrides', () => { }); it.each([ + 'https://dashscope.aliyuncs.com/compatible-mode/v1', + 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1', + 'https://dashscope-us.aliyuncs.com/compatible-mode/v1', + 'https://cn-hongkong.dashscope.aliyuncs.com/compatible-mode/v1', + 'https://coding.dashscope.aliyuncs.com/v1', + 'https://coding-intl.dashscope.aliyuncs.com/v1', + 'https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1', + 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1', + 'https://trial.cn-beijing.maas.aliyuncs.com/compatible-mode/v1', + 'https://example-workspace.cn-beijing.maas.aliyuncs.com/compatible-mode/v1', + 'https://example-workspace.cn-hongkong.maas.aliyuncs.com/compatible-mode/v1', + 'https://example-workspace.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1', + 'https://example-workspace.ap-northeast-1.maas.aliyuncs.com/compatible-mode/v1', + 'https://example-workspace.eu-central-1.maas.aliyuncs.com/compatible-mode/v1', + 'https://example-workspace.us-east-1.maas.aliyuncs.com/compatible-mode/v1', 'https://api.kimi.com/coding/v1', 'https://api.kimi.ai/coding/v1', ])('keeps the system role for a thinking model at %s', async (baseURL) => { @@ -1458,12 +1473,33 @@ describe('LocalModelResolver custom provider compat overrides', () => { ['https://api.openai.com/v1', 'developer'], ['https://api.moonshot.cn/v1', 'system'], ['https://api.moonshot.ai/v1', 'system'], + ['https://dashscope.aliyuncs.com.example/v1', 'developer'], + ['https://gateway.example/dashscope.aliyuncs.com/v1', 'developer'], + ['https://coding.dashscope.aliyuncs.com.example/v1', 'developer'], + ['https://token-plan.cn-beijing.maas.aliyuncs.com.example/v1', 'developer'], + ['https://gateway.example/token-plan.cn-beijing.maas.aliyuncs.com/v1', 'developer'], + ['https://example-workspace.unknown-region.maas.aliyuncs.com/v1', 'developer'], + ['https://example-workspace.cn-beijing.aliyuncs.com/v1', 'developer'], ['https://api.kimi.com.example/v1', 'developer'], ['https://gateway.example/api.kimi.com/coding/v1', 'developer'], ])('preserves the system prompt role for %s', async (baseURL, role) => { expect(await systemPromptRoleFor(undefined, baseURL)).toBe(role); }); + it.each([ + 'https://dashscope.aliyuncs.com/compatible-mode/v1', + 'https://coding.dashscope.aliyuncs.com/v1', + 'https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1', + 'https://example-workspace.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1', + ])('honors an explicit developer-role override on %s', async (baseURL) => { + expect( + await systemPromptRoleFor( + { supportsDeveloperRole: true }, + baseURL, + ), + ).toBe('developer'); + }); + it('honors an explicit developer-role override on a Kimi Coding endpoint', async () => { expect( await systemPromptRoleFor( diff --git a/third_party/pi-mono/MINIMAX_CHANGES.md b/third_party/pi-mono/MINIMAX_CHANGES.md index 1fb61c3f4..66bfb52cf 100644 --- a/third_party/pi-mono/MINIMAX_CHANGES.md +++ b/third_party/pi-mono/MINIMAX_CHANGES.md @@ -13,6 +13,15 @@ This directory vendors `pi-mono` as source so MiniMax can patch, validate, and s No upstream source files are changed in the baseline import. +### 2026-09-19 — preserve the system role for DashScope + +- Reason: DashScope endpoints were treated as supporting the `developer` role, causing thinking-enabled OpenAI-compatible conversations to send an unsupported system-prompt role. +- Affected package: `packages/ai` (`@earendil-works/pi-ai`), OpenAI Completions compatibility detection. +- Change: default to the `system` role for official DashScope regional and Coding Plan hosts, plus workspace, trial, and Token Plan hosts under the documented regional `maas.aliyuncs.com` domains. Preserve thinking, other request options, explicit compatibility overrides, and other providers. +- References: [official endpoint list](https://help.aliyun.com/en/model-studio/base-url), [Coding Plan role rejection](https://github.com/openclaw/openclaw/issues/23575), [Token Plan role rejection](https://github.com/earendil-works/pi/issues/7723), and [merged OpenClaw DashScope fix](https://github.com/openclaw/openclaw/pull/24675). +- Upstream PR: not opened. +- Validation: request-payload regressions in `packages/local-runtime-v2/src/service/model-system/resolution/local-model-resolver.test.ts`, including official endpoints, unrelated hosts, and explicit compatibility overrides. + ### 2026-09-19 — preserve the system role for Kimi Coding - Reason: Kimi Coding endpoints were treated as supporting the `developer` role, causing thinking-enabled OpenAI-compatible conversations to send an unsupported system-prompt role. diff --git a/third_party/pi-mono/packages/ai/src/providers/openai-completions.ts b/third_party/pi-mono/packages/ai/src/providers/openai-completions.ts index 26026fd1b..2b3a94283 100644 --- a/third_party/pi-mono/packages/ai/src/providers/openai-completions.ts +++ b/third_party/pi-mono/packages/ai/src/providers/openai-completions.ts @@ -1091,6 +1091,9 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet provider === "together" || baseUrl.includes("api.together.ai") || baseUrl.includes("api.together.xyz"); const isMoonshot = provider === "moonshotai" || provider === "moonshotai-cn" || baseUrl.includes("api.moonshot."); const isKimiCoding = /^https?:\/\/api\.kimi\.(?:com|ai)(?::\d+)?(?:\/|$)/i.test(baseUrl); + const isDashScope = + /^https?:\/\/(?:dashscope(?:-intl|-us)?|(?:coding(?:-intl)?|cn-hongkong)\.dashscope)\.aliyuncs\.com(?::\d+)?(?:\/|$)/i.test(baseUrl) || + /^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); const isOpenRouter = provider === "openrouter" || baseUrl.includes("openrouter.ai"); const isCloudflareWorkersAI = provider === "cloudflare-workers-ai" || baseUrl.includes("api.cloudflare.com"); const isCloudflareAiGateway = provider === "cloudflare-ai-gateway" || baseUrl.includes("gateway.ai.cloudflare.com"); @@ -1125,7 +1128,8 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet return { supportsStore: !isNonStandard, - supportsDeveloperRole: !isKimiCoding && (isOpenRouterDeveloperRoleModel || (!isNonStandard && !isOpenRouter)), + supportsDeveloperRole: + !isKimiCoding && !isDashScope && (isOpenRouterDeveloperRoleModel || (!isNonStandard && !isOpenRouter)), supportsReasoningEffort: !isGrok && !isZai && !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia && !isAntLing, supportsUsageInStreaming: true,