Fix a desktop-session freeze (forced logout/reboot) caused by the overlay's AT-SPI caret tracker: it subscribed to the high-frequency object:text-caret-moved signal and made synchronous, blocking AT-SPI reads from inside the event handler, re-entering the a11y dispatcher and getting stormed by the app's own xdotool typing until GNOME stopped responding. Now track focus changes only and read the caret rectangle lazily, once, when the overlay shows — never on the hot path. Fuse voice-routing feedback into the overlay instead of a desktop notification: show the matched preset's emoji, name, and spoken keyword on a banner, narrate the phase (Transcribing -> Rewriting), and stream the LLM rewrite into the bubble token-by-token. Redundant per-dictation notifications are suppressed when the overlay is present (errors still notify); headless/overlay-off is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
42 lines
1.3 KiB
Python
42 lines
1.3 KiB
Python
"""Streaming the LLM rewrite into the overlay (so you watch the model write).
|
|
|
|
`llm.chat(..., on_token=cb)` must parse an OpenAI-style SSE stream, hand each
|
|
content delta to the callback, and still return the complete text.
|
|
"""
|
|
|
|
import io
|
|
|
|
import blitztext.llm as llm
|
|
|
|
|
|
def test_read_stream_accumulates_and_calls_back():
|
|
sse = (
|
|
'data: {"choices":[{"delta":{"content":"Hel"}}]}\n'
|
|
"\n" # keep-alive blank line
|
|
'data: {"choices":[{"delta":{"content":"lo"}}]}\n'
|
|
'data: {"choices":[{"delta":{}}]}\n' # role-only / empty delta
|
|
": comment line\n" # SSE comment, ignored
|
|
"data: [DONE]\n"
|
|
'data: {"choices":[{"delta":{"content":"X"}}]}\n' # after DONE -> ignored
|
|
)
|
|
tokens = []
|
|
out = llm._read_stream(io.BytesIO(sse.encode("utf-8")), tokens.append)
|
|
|
|
assert out == "Hello"
|
|
assert tokens == ["Hel", "lo"]
|
|
|
|
|
|
def test_read_stream_survives_callback_errors():
|
|
sse = (
|
|
'data: {"choices":[{"delta":{"content":"a"}}]}\n'
|
|
'data: {"choices":[{"delta":{"content":"b"}}]}\n'
|
|
"data: [DONE]\n"
|
|
)
|
|
|
|
def boom(_delta):
|
|
raise RuntimeError("UI exploded")
|
|
|
|
# A failing UI callback must not break accumulation / delivery.
|
|
out = llm._read_stream(io.BytesIO(sse.encode("utf-8")), boom)
|
|
assert out == "ab"
|