farion1231 / farion1231/cc-switch
Bug: proxy produces empty content messages causing 400 error with llama.cpp
- Dominant language
- Rust
- Stars
- 133k
- Forks
- 9.2k
- Avg merge
- 3d 20h
- Merged PRs (30d)
- 48
Description
The cc-switch proxy in `src-tauri/src/proxy/providers/transform.rs` has two bugs in the Anthropic → OpenAI message conversion that produce empty content messages, which causes llama.cpp to reject with 400 Bad Request:
```
messages.0: all messages must have non-empty content except for the optional final assistant message
```
## Bug 1 (lines 98-114 + 201-210): System messages with empty text are not filtered
When the Anthropic request's `system` field is an array with a content block containing `"text": ""`, line 105 passes the `Some(text)` guard because `Some("")` is not `None`. A system message with `content: ""` is created. Then in `normalize_openai_system_messages` (line 201), the `system_count == 1` branch has NO content validation — the empty system message passes through untouched as `messages[0]`.
Compare with the `system_count > 1` branch (line 224) which correctly filters with `Some(Value::String(text)) if !text.is_empty()`.
**Fix**: Add `!text.is_empty()` guard at line 105, or add empty-content filtering in the `system_count == 1` branch.
## Bug 2 (lines 363-368): Assistant messages with tool_use but no text get `content: null`
When an assistant message's content array contains only `tool_use` blocks (no `text` blocks), `content_parts` is empty but `tool_calls` is non-empty. The code sets `msg["content"] = Value::Null` (line 368). While valid per OpenAI spec, llama.cpp rejects null content on non-final assistant messages.
**Fix**: When `content_parts` is empty but `tool_calls` is non-empty, either omit the `content` key entirely or set it to an empty string `""`.
## Reproduction
1. Set up cc-switch with `apiFormat: "openai_chat"` pointing to a local llama.cpp server
2. Send any request that triggers tool use or has system prompts with empty text blocks
3. llama.cpp returns 400
## Environment
- macOS
- cc-switch latest
- llama.cpp server with Qwen3 model
Contributor guide
Research direction
Start in src-tauri/src/proxy/providers/transform.rs, especially the Anthropic system conversion around lines 98-114 and normalization around lines 201-224. Inspect the assistant conversion around lines 363-368, then reproduce against a local llama.cpp server using empty system text and tool_use-only assistant content. Done means the conversion no longer emits rejected empty or null messages and the request succeeds without a 400 response.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100