diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-16 14:15:27 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-16 14:15:27 +0200 |
| commit | 4a1f1166ac27b9016a4e7b4d1468c2410ac1213d (patch) | |
| tree | ea45d6bdf3366a1acb748495ede41374210d1ec5 | |
| parent | 460cd4456790092ea42a8848bb0ea517a1174fca (diff) | |
| download | desktop-assistant-4a1f1166ac27b9016a4e7b4d1468c2410ac1213d.tar.gz desktop-assistant-4a1f1166ac27b9016a4e7b4d1468c2410ac1213d.zip | |
Mark the errors that end a reply
Every client sees every event, so a command error from one client, such as
opening a conversation another just deleted, reached a canvas watching a
reply and was taken as that reply's end: the canvas stopped rendering
tokens the daemon kept streaming. An error from the reply thread now
carries turn: true; command errors carry none.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | assistant.py | 12 | ||||
| -rw-r--r-- | docs/superpowers/specs/2026-10-16-text-daemon-design.md | 2 |
2 files changed, 9 insertions, 5 deletions
diff --git a/assistant.py b/assistant.py index db527a5..777ceba 100644 --- a/assistant.py +++ b/assistant.py @@ -548,7 +548,9 @@ def reply(mine, text): with lock: if turn == mine: cur["pending"] = None - emit({"type": "error", "message": str(e) or type(e).__name__}) + # turn: this error ended the reply. Command errors carry no + # turn and must not end a reply another client is watching. + emit({"type": "error", "message": str(e) or type(e).__name__, "turn": True}) emit({"type": "state", "state": "idle"}) @@ -824,7 +826,8 @@ def test(): script["replies"] = [['data: {"error": {"message": "context full"}}\n\n']] CFG["thinking"] = False send(type="ask", text="too much") - assert until("error")[-1]["message"] == "context full" + e = until("error")[-1] + assert e["message"] == "context full" and e["turn"] is True assert script["body"]["chat_template_kwargs"]["enable_thinking"] is False CFG["thinking"] = True # Stop mid-stream: no token after done, nothing saved. @@ -865,7 +868,8 @@ def test(): ({"type": "ask", "text": None}, "bad text"), ({"type": "search", "q": 3}, "bad query")): send(**cmd) - assert until("error")[-1]["message"] == why, cmd + e = until("error")[-1] + assert e["message"] == why and "turn" not in e, cmd # a command error assert cur["id"] == conv # none of them touched the conversation real, DB = DB, None # every query now raises send(type="list") @@ -887,7 +891,7 @@ def test(): # llama-server down: an error, not a dead thread. CFG["llm"] = "http://127.0.0.1:9/v1" send(type="ask", text="anyone?") - assert until("error")[-1]["type"] == "error" + assert until("error")[-1]["turn"] is True assert until("state")[-1]["state"] == "idle" and cur["pending"] is None # A second client gets hello with the conversation so far. c2 = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) diff --git a/docs/superpowers/specs/2026-10-16-text-daemon-design.md b/docs/superpowers/specs/2026-10-16-text-daemon-design.md index 58d0240..223af38 100644 --- a/docs/superpowers/specs/2026-10-16-text-daemon-design.md +++ b/docs/superpowers/specs/2026-10-16-text-daemon-design.md @@ -102,7 +102,7 @@ Outbound: | `token` | `delta` | | `tool` | `name`, `done` (false when it starts, true when it returns) | | `done` | `id`: the conversation the turn was saved in; `stopped`: true for a reply that was stopped | -| `error` | `message` | +| `error` | `message`; `turn`: true when the error ended the reply in flight, absent for a command error | | `ctx` | `used`, `max` | | `conversations` | `items`: `[{id, title, updated}]`, newest first | | `conversation` | `id`, `turns`: `[{user, reply, tools}]` | |
