Symptom
Forcing a brain restart via `/resume`, the Restart Agent menu item, or the implicit prefs-save restart leaves the renderer in a stuck "streaming" UI state:
- Status badge stays on "thinking…".
- Stop button stays visible; Send hidden.
- Input field accepts text but submits get queued instead of fired.
- `streaming === true` never flips back to false.
User has to Ctrl+R the window to escape.
Why
Renderer's `streaming` flag flips to false only on the brain's `agent_end` event (`app.ts` chat-stream handler). `agent.stop()` in main kills the brain process; the brain never gets a chance to emit `agent_end`; the renderer waits forever.
Proposed fix
`AgentManager.stop()` already calls `setStatus("stopped")`, which the renderer receives via `agent:status`. Wire the renderer's `onAgentStatus` handler to also reset turn state:
```ts
window.orbit.onAgentStatus((status, msg) => {
setStatusBadge(status, msg);
if (status === "stopped" || status === "error") {
streaming = false;
sendBtn.classList.remove("hidden");
abortBtn.classList.add("hidden");
// any other turn-end cleanup
}
...
});
```
Or factor the turn-end cleanup into `resetUiForFreshContext` and call it on stopped/error transitions. Either works.
Files
- `app/src/renderer/app.ts` — `onAgentStatus` handler (~line 1918) + a small reset helper.
Repro
- Send a slow prompt.
- Type `/resume` while it's streaming.
- Watch: brain restarts cleanly per `/tmp/orbit.log` but UI stays stuck on "thinking…".
Related
Symptom
Forcing a brain restart via `/resume`, the Restart Agent menu item, or the implicit prefs-save restart leaves the renderer in a stuck "streaming" UI state:
User has to Ctrl+R the window to escape.
Why
Renderer's `streaming` flag flips to false only on the brain's `agent_end` event (`app.ts` chat-stream handler). `agent.stop()` in main kills the brain process; the brain never gets a chance to emit `agent_end`; the renderer waits forever.
Proposed fix
`AgentManager.stop()` already calls `setStatus("stopped")`, which the renderer receives via `agent:status`. Wire the renderer's `onAgentStatus` handler to also reset turn state:
```ts
window.orbit.onAgentStatus((status, msg) => {
setStatusBadge(status, msg);
if (status === "stopped" || status === "error") {
streaming = false;
sendBtn.classList.remove("hidden");
abortBtn.classList.add("hidden");
// any other turn-end cleanup
}
...
});
```
Or factor the turn-end cleanup into `resetUiForFreshContext` and call it on stopped/error transitions. Either works.
Files
Repro
Related