agentscope-ai / agentscope-ai/agentscope
[Bug]: Realtime event streams can terminate immediately after close and reconnect
- 主要言語
- Python
- スター
- 31.5k
- フォーク
- 3.5k
- 平均マージ
- 1日 23時間
- マージ済み PR(30日)
- 95
説明
### Prerequisites
- [x] I have searched the existing [issues](https://github.com/agentscope-ai/agentscope/issues) and [discussions](https://github.com/agentscope-ai/agentscope/discussions), and this is not a duplicate.
- [x] This is a bug, not a usage question. (For questions, please use [Discussions](https://github.com/agentscope-ai/agentscope/discussions/new?category=general) instead.)
### Background / Description
## English
The OpenAI, Gemini, DashScope, and xAI realtime adapters allocate their event queue once in `__init__`. Calling `close()` cancels the reader task, whose `finally` block enqueues a `SessionEndedEvent` followed by the `None` end-of-stream sentinel. A later `connect()` starts a new reader without clearing or replacing that queue.
After an explicit close and reconnect, the new `events()` iterator can consume the previous session's terminal event and sentinel and stop before reading the new session's events. The provider WebSocket may be connected and receive input while its audio, transcript, and tool-call events remain unread.
Expected behavior: the same realtime model or agent instance can be explicitly closed and connected again without terminal events from the previous session ending the new event stream.
Actual behavior: the new event iterator terminates at the stale sentinel.
## 中文
OpenAI、Gemini、DashScope 和 xAI realtime adapter 都只在初始化时创建一次事件队列。`close()` 取消 reader 后,reader 的 `finally` 会写入 `SessionEndedEvent` 和 `None` 结束哨兵;再次 `connect()` 却不会清空或替换队列。
因此,同一实例显式关闭后重新连接时,新 `events()` 可能先读到旧 session 的结束哨兵并立即退出,而新 session 的事件留在队列中。预期重新连接后的事件流只受新 session 控制。
### Error Messages
```shell
No exception is required. A queue-level reproduction prints:
['SessionEndedEvent']
ResponseCreatedEvent
The ResponseCreatedEvent belongs to the new session but remains queued after the iterator has ended.
中文:该问题不需要抛出异常即可复现;上述输出表明新 session 的事件仍留在已经结束迭代的队列中。
```
### Steps to Reproduce
```python
import asyncio
from agentscope.credential import OpenAICredential
from agentscope.realtime import OpenAIRealtimeModel
from agentscope.realtime import _events as events
async def main() -> None:
model = OpenAIRealtimeModel(
"gpt-realtime-2.1",
OpenAICredential(api_key="unused"),
)
# These are enqueued by the previous reader's finally block on close.
model._queue.put_nowait(events.SessionEndedEvent(reason="previous close"))
model._queue.put_nowait(None)
# Simulate the first event received by the new connection.
model._queue.put_nowait(events.ResponseCreatedEvent(item_id="new-session"))
print([type(event).__name__ async for event in model.events()])
print(type(model._queue.get_nowait()).__name__)
asyncio.run(main())
```
The same queue lifecycle is present in all four provider adapters.
中文:以上代码模拟旧 reader 在关闭时留下终止事件和哨兵,再放入新连接的首个事件;迭代器会在读取新事件前结束。四个 provider adapter 均存在相同的队列生命周期。
### Environment
- AgentScope Version: 2.0.8 (main at 0fe41c07)
- Python Version: 3.12.14
- OS: macOS 26.6.2 arm64
コントリビューションガイド
評価
この issue はまだ評価されていません。