The canonical openai_codex SDK can complete a turn successfully without emitting any `message.delta` events: the final assistant text arrives only as an `ItemCompletedNotification` whose item is an `agentMessage`. Before this change `_stream_thread_run` would loop through the stream, see no delta text, return, and Studio would emit only the empty usage + stop + `[DONE]` frames -- the user sees a blank reply for what was actually a complete answer. Track agent-message texts collected during the stream loop and, if no streamed deltas came through, yield the last one before returning. The buffered `thread.run()` fallback is still gated by the existing `emitted_any` flag so it never replays a turn that already executed side effects (file writes, shell commands). `_completed_agent_message_text` accepts both the upstream object shape (`ItemCompletedNotification(item.root.text=...)`) and the dict shape pre-release builds and tests use, so it works across SDK revs without an explicit version gate. Tests: new regression `test_empty_stream_falls_back_to_completed_agent_message` exercises a fake SDK whose `turn().stream()` yields only an `item.completed` event with an `agentMessage`; the test asserts the final text reaches the visible chat output and that the buffered `run()` path is NOT re-executed. |
||
|---|---|---|
| .. | ||
| assets | ||
| auth | ||
| core | ||
| loggers | ||
| models | ||
| plugins | ||
| requirements | ||
| routes | ||
| state | ||
| storage | ||
| tests | ||
| utils | ||
| __init__.py | ||
| _platform_compat.py | ||
| colab.py | ||
| main.py | ||
| run.py | ||
| startup_banner.py | ||