You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Custom providers with OpenAI Chat wire backed by Chinese OpenAI-compat endpoints (Qwen via DashScope, DeepSeek, GLM, Moonshot, etc.) fail with:
```
CodesignError: 400 developer is not one of ['system', 'assistant', 'user', 'tool', 'function'] - 'messages.[0].role'
CodesignError: 400 角色信息不正确
```
`packages/providers/src/index.ts::synthesizeWireModel` hardcodes `reasoning: true` for every synthesized model. pi-ai's openai-responses-shared / openai-chat adapters check `model.reasoning` and pick the message role accordingly:
So every custom provider gets `role: 'developer'` injected into `messages[0]`, but DashScope and friends strictly enforce the classic OpenAI whitelist `['system','assistant','user','tool','function']`. `developer` is an OpenAI-only role (Responses API, GPT-5 family). Treating it as universal breaks the rest of the OpenAI-compat ecosystem.
Impact
Entire Chinese OpenAI-compat ecosystem is broken: Qwen, DeepSeek, GLM (`glm-4`+), Moonshot (`kimi`), Aliyun DashScope, etc. — easily the majority of mainland users
Test connection passes (because `/models` does not exercise the role whitelist), so users discover the failure only when they try to generate
Expected
For OpenAI Chat wire + a non-openai.com baseUrl, emit `role: 'system'` instead of `'developer'`.
Proposed Fix
In `packages/providers/src/index.ts::synthesizeWireModel`, do not blanket-set `reasoning: true`:
`wire === 'anthropic-messages'` → Anthropic has no role-vs-reasoning coupling → unchanged
`wire === 'openai-chat'` → default `reasoning: false` unless baseUrl is `api.openai.com` AND model id matches a known reasoning family (`gpt-5*`, `o1*`, `o3*`). For everything else, `reasoning: false` → pi-ai emits `role: 'system'` → compat gateways accept it
Test Plan
`packages/providers/src/index.test.ts`: synthesized PiModel for a non-openai host on openai-chat → `reasoning === false`
Same path with `api.openai.com` + `gpt-5` model id → `reasoning === true` preserved
Summary
Custom providers with OpenAI Chat wire backed by Chinese OpenAI-compat endpoints (Qwen via DashScope, DeepSeek, GLM, Moonshot, etc.) fail with:
```
CodesignError: 400 developer is not one of ['system', 'assistant', 'user', 'tool', 'function'] - 'messages.[0].role'
CodesignError: 400 角色信息不正确
```
Reproduced with: `custom-dashscope-jhub` / `qwen3.6-plus` (v0.1.3).
Root Cause
`packages/providers/src/index.ts::synthesizeWireModel` hardcodes `reasoning: true` for every synthesized model. pi-ai's openai-responses-shared / openai-chat adapters check `model.reasoning` and pick the message role accordingly:
```js
// @mariozechner/pi-ai — dist/providers/openai-responses-shared.js
const role = model.reasoning ? "developer" : "system";
messages.push({ role, content: sanitizeSurrogates(context.systemPrompt) });
```
So every custom provider gets `role: 'developer'` injected into `messages[0]`, but DashScope and friends strictly enforce the classic OpenAI whitelist `['system','assistant','user','tool','function']`. `developer` is an OpenAI-only role (Responses API, GPT-5 family). Treating it as universal breaks the rest of the OpenAI-compat ecosystem.
Impact
Expected
For OpenAI Chat wire + a non-openai.com baseUrl, emit `role: 'system'` instead of `'developer'`.
Proposed Fix
In `packages/providers/src/index.ts::synthesizeWireModel`, do not blanket-set `reasoning: true`:
Test Plan
Related
cc @hqhq1025