agentscope-ai / agentscope-ai/agentscope

[Bug]: Mid-stream failures can leave orphan tool_calls and brick sessions

Aberta
#1,888 4 comentários 0 reações 0 responsáveis Ver no GitHub
Linguagem predominante
Python
Estrelas
31.6k
Forks
3.5k
Merge médio
1d 16h
PRs com merge (30d)
103

Descrição

### Describe the bug

In AgentScope Python 2.0.2, a chat run can fail after an assistant tool call has been appended to `AgentState.context`, but before the matching `ToolResultBlock` is recorded and persisted.

The persisted session can then contain an assistant message with `tool_calls` but no matching tool result. On the next turn, OpenAI-compatible providers reject the conversation history with an error like:

```text
An assistant message with "tool_calls" must be followed by tool messages responding to each "tool_call_id"
```

After that, every retry of the same session can fail again, so the session is effectively bricked until the stored context is manually repaired or deleted.

### Expected behavior

If a run is interrupted or crashes while a tool call is pending, AgentScope should persist a valid recovery state before the exception escapes. For example, the pending tool call could be closed with an interrupted/error `ToolResultBlock`, so the next run does not send invalid tool-call history to the model provider.

### Actual behavior

A mid-stream failure can leave an orphan tool call in persisted session state. The next run reuses that invalid context and fails at provider validation before the agent can recover naturally.

### Related issues / prior art

This appears related to earlier Python reports of provider-side tool-call validation errors:

- https://github.com/agentscope-ai/agentscope/issues/772
- https://github.com/agentscope-ai/agentscope/issues/815
- https://github.com/agentscope-ai/agentscope/issues/1711

The Java implementation also had a very similar pending-tool-call recovery problem:

- https://github.com/agentscope-ai/agentscope-java/issues/951
- https://github.com/agentscope-ai/agentscope-java/pull/956

The Java fix added a `PendingToolRecoveryHook` that synthesizes error tool results for pending tool calls. Python may need an equivalent recovery point in the app/chat service or agent middleware layer.

### Suggested fix

Add a Python-side recovery mechanism for persisted agent state:

1. Before a run, scan `AgentState.context` for assistant tool calls that do not have matching tool results, and synthesize interrupted/error `ToolResultBlock`s.
2. During a run, wrap the streaming/chat execution path in `try` / `finally` or equivalent middleware so pending tool calls are repaired and persisted when an exception occurs.
3. Add regression tests that simulate a failure after a tool call is emitted but before its tool result is persisted, then verify the next run does not fail with provider validation errors.

This would avoid downstream applications needing to monkey-patch private `ChatService` internals to keep sessions recoverable.

### Environment

- AgentScope Python: 2.0.2
- Python: 3.12
- Storage: persisted app session state
- Providers: OpenAI-compatible tool-call validation

Guia de contribuição

Abrir o guia de contribuição

Direção de pesquisa

Start with the chat execution flow where assistant `tool_calls` are appended to `AgentState.context` and persisted session state is written in the app/chat service or agent middleware. Then inspect the run/exception handling path and add recovery logic that scans for unmatched tool calls and writes interrupted/error `ToolResultBlock`s before the run exits. Add a regression test that simulates a crash between tool-call emission and result persistence, then rerun the same session and verify provider validation does not fail on missing tool responses.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
python
Domínio
tooling
Tipo de issue
Bug
Dificuldade
3/5
Tempo estimado
1-2 dias
Status de atividade
Ativa
Clareza
Razoavelmente clara
Facilidade para iniciantes
70/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.