agentscope-ai / agentscope-ai/QwenPaw
[Bug]: Gemini returns 400 "Requests ending with a model turn are not supported" after background tool completion
- Lingua principale
- TypeScript
- Stelle
- 35k
- Fork
- 3.1k
- Merge medio
- 1g 13h
- PR unite (30g)
- 228
Descrizione
## QwenPaw Version
2.2.0
Verified with:
```bash
qwenpaw --version
```
Output:
```text
QwenPaw, version 2.2.0
```
## Description
When using a Gemini model, QwenPaw can fail immediately after an offloaded/background tool call completes or is interrupted.
The next model request returns:
```text
openai.BadRequestError: Error code: 400 - {
'error': {
'code': 400,
'message': 'Requests ending with a model turn are not supported.',
'status': 'INVALID_ARGUMENT'
}
}
```
Investigation of the QwenPaw error dump shows that the final message in `agent_state.state.context` is an automatically injected background-tool notification with:
```text
role="assistant"
name="system"
```
For example:
```text
Background tool call `execute_shell_command` (...)
completed with state=interrupted. Result below.
```
This message is generated by `make_offload_hint_msg()` in:
```text
qwenpaw/tool_calls/_hint.py
```
QwenPaw 2.2.0 currently contains:
```python
return Msg(
name="system",
role="assistant",
content=[notification] + result_blocks,
)
```
When this notification becomes the final context message before the next inference, Gemini sees the conversation as ending with a model/assistant turn and rejects the request with:
```text
Requests ending with a model turn are not supported.
```
QwenPaw 2.2.0 already appears to flatten the previous `ToolResultBlock` structure, so this is not the orphan tool-result pairing issue. The remaining issue is specifically that the offload completion notification is still emitted with `role="assistant"`.
A local workaround changing:
```diff
return Msg(
name="system",
- role="assistant",
+ role="user",
content=[notification] + result_blocks,
)
```
successfully passes Python syntax validation and prevents the runtime notification from producing a trailing assistant/model turn.
Semantically, this notification is also closer to an external/runtime input than a model-generated assistant response.
**Related PR(s):** N/A
**Security considerations:** None identified.
## Component(s) Affected
* [x] Core / Backend (app, agents, config, providers, utils, local_models)
* [ ] Console (frontend web UI)
* [ ] Channels (DingTalk, Feishu, QQ, Discord, iMessage, etc.)
* [ ] Skills
* [ ] CLI
* [ ] Documentation (website)
* [ ] Tests
* [ ] CI/CD
* [ ] Scripts / Deploy
## Environment
* **QwenPaw version:** 2.2.0
* **OS:** Linux container
* **Install method:** Python virtual environment / pip-based installation
* **Python version (if applicable):** 3.11
* **Package path:** `/app/venv/lib/python3.11/site-packages/qwenpaw/`
* **Model/provider:** Gemini through an OpenAI-compatible API gateway
* **Channel where observed:** Feishu
## Steps to Reproduce
1. Configure QwenPaw 2.2.0 to use a Gemini model.
2. Start a conversation and invoke a tool such as `execute_shell_command`.
3. Let the command exceed the foreground execution period so that QwenPaw offloads it to background execution.
4. Wait for the background tool call to complete or become interrupted.
5. QwenPaw injects a completion notification generated by `make_offload_hint_msg()`.
6. QwenPaw performs the next model inference.
7. Gemini returns:
```text
400 INVALID_ARGUMENT
Requests ending with a model turn are not supported.
```
The corresponding error dump in my case was:
```text
/tmp/qwenpaw_query_error_rn1nsw14.json
```
Inspection of `.agent_state.state.context` showed the final messages as approximately:
```text
context[3]:
role="assistant"
context[4]:
role="assistant"
name="system"
content:
Background tool call `execute_shell_command` (...)
completed with state=interrupted.
Result below.
```
The second message is produced by:
```python
def make_offload_hint_msg(entry: Any) -> Any:
...
return Msg(
name="system",
role="assistant",
content=[notification] + result_blocks,
)
```
## Actual vs Expected
* **Actual:**
After a background/offloaded tool call completes or is interrupted, QwenPaw inserts the completion notification as an `assistant` message.
The resulting conversation ends with an assistant/model turn:
```text
assistant
→ system-notification with role="assistant"
→ next Gemini inference
```
Gemini rejects the request with:
```text
400: Requests ending with a model turn are not supported.
```
* **Expected:**
A runtime-generated background tool completion notification should not leave the conversation in a trailing assistant/model state before the next model invocation.
For Gemini-compatible providers, the next inference should proceed normally after the background tool completion notification.
One possible fix is to emit this runtime notification as an input/user turn:
```python
return Msg(
name="system",
role="user",
content=[notification] + result_blocks,
)
```
Alternatively, QwenPaw could handle this at the provider/formatter layer, but the automatically injected runtime notification should not result in an invalid trailing model turn.
Guida per i contributori
Apri la guida per i contributori
Direzione di ricerca
Inspect `qwenpaw/tool_calls/_hint.py`, especially `make_offload_hint_msg(entry)`, where the injected completion notification is built with `role='assistant'`. Trace how that `Msg` is appended into `.agent_state.state.context` and then sent to the next model call for Gemini-compatible providers. Reproduce with an offloaded `execute_shell_command`, wait for completion/interruption, and inspect the last context message role before the next request. Done when the notification is no longer a trailing assistant turn and the next inference does not return the 400 INVALID_ARGUMENT error.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- python
- Ambito
- backend
- Tipo di issue
- Bug
- Difficoltà
- 1/5
- Tempo stimato
- Meno di un'ora
- Stato di attività
- Attiva
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 58/100