aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-26 08:59:10 +0200
committerDanilo M. <danix@danix.xyz>2026-09-26 08:59:10 +0200
commitf2eec537da3de403b3201a8631e15ba6c491752d (patch)
tree3bac911cfe791989b336b039406e23c6f06fcdb5
parentbe9719e61feab28612499680be9efd7411c5254f (diff)
downloaddesktop-assistant-f2eec537da3de403b3201a8631e15ba6c491752d.tar.gz
desktop-assistant-f2eec537da3de403b3201a8631e15ba6c491752d.zip
Pause during games too, not only in presentation mode
The status registry's effective presentation is the OR of the manual flag and status.gaming, which the shell's game detector writes; statusctl presentation get reads only the manual half and printed 0 with a game running. presenting() now reads both files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--AGENTS.md9
-rw-r--r--assistant.py25
2 files changed, 27 insertions, 7 deletions
diff --git a/AGENTS.md b/AGENTS.md
index 0e58c38..9542840 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -194,6 +194,13 @@ utterance to whisper. No keybind, no VAD.
No watcher needed. Considered and not chosen: skipping when another app
already records from the mic (`pactl list source-outputs`, sound server is
PipeWire with the Pulse API); fallback if presentation mode gets forgotten.
+- **Games (2026-09-26):** the shell's game detector writes a separate
+ `status.gaming`, and the registry's effective presentation is
+ `presentation OR gaming`. `statusctl presentation get` reads only the
+ manual half: it printed `0` with pcsx2 running, so the assistant would
+ have answered during games. `presenting()` now reads both files (the
+ registry's documented interface). Live: press ignored with pcsx2
+ running, normal again after it closed.
### Push-to-talk round trip with whisper-server (2026-09-25)
@@ -440,8 +447,6 @@ mic, TTS, glue); push-to-talk came for free from the mic button. Open, in
no particular order:
- **Run as a service/autostart** (it currently runs by hand).
-- **Check presentation mode during games:** `statusctl presentation get`
- reads the stored flag; confirm it is 1 while a game holds it on.
- **Latency:** STT ~1.2 s is the biggest share; the double encoder pass
(detect + transcribe) is the target if it matters.
- **Phase 2 tools:** tools that write or modify (events, messages,
diff --git a/assistant.py b/assistant.py
index 7724b73..3bd4b20 100644
--- a/assistant.py
+++ b/assistant.py
@@ -119,12 +119,20 @@ def mic_on():
return out.rstrip().endswith("values=on")
-def presenting():
+def presenting(d=None):
# During calls the user turns on presentation mode; the button then
- # belongs to the call, not to us.
- r = subprocess.run([os.path.expanduser("~/bin/statusctl"), "presentation", "get"],
- capture_output=True, text=True)
- return r.stdout.strip() == "1"
+ # belongs to the call, not to us. Presentation is the OR of the manual
+ # flag and the game detector's (quickshell status registry: the files are
+ # its interface); `statusctl presentation get` reads only the manual half.
+ d = d or os.environ.get("XDG_RUNTIME_DIR", "/tmp")
+
+ def flag(name):
+ try:
+ with open(os.path.join(d, f"status.{name}")) as f:
+ return f.read().strip() == "1"
+ except OSError: # a missing file means off
+ return False
+ return flag("presentation") or flag("gaming")
def latin(text):
@@ -500,6 +508,13 @@ def test():
assert run_tool(tools, "nope", "{}", d) == "error: no tool named nope"
assert run_tool(tools, "echo", "{bad", d) == "error: arguments are not valid JSON"
assert run_tool(tools, "echo", "[1]", d) == "error: arguments are not valid JSON"
+ with tempfile.TemporaryDirectory() as d:
+ assert not presenting(d)
+ for name, value, want in (("gaming", "1", True), ("gaming", "0", False),
+ ("presentation", "1\n", True)):
+ with open(os.path.join(d, f"status.{name}"), "w") as f:
+ f.write(value)
+ assert presenting(d) == want, (name, value)
calls = {}
collect_calls(calls, [{"index": 0, "id": "c1", "type": "function",
"function": {"name": "weather", "arguments": "{"}}])