Files
desklock/gateway/tests/test_commands.py
T
jpmschweitzerandClaude Opus 4.8 6b7fbb60c9 feat(gateway): voice command service
Recognize simple device commands in the transcript and act on them without
a Tatlock round-trip. commands.match() maps volume up/down, mute/unmute,
"set volume to N", and "goes to eleven"/max to a "command" message sent
straight to the device; the utterance never reaches the LLM. Matching is
deliberately precise so real requests ("set an alarm for a quarter to
eleven") are not hijacked. Adds the "command" message to the device
protocol in docs/architecture.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKPbR6DY2JygHbyLjxm7Uu
2026-07-15 21:29:00 +02:00

62 lines
2.4 KiB
Python

from desklock_gateway import commands
def test_mute_and_unmute() -> None:
assert commands.match("mute") == {"type": "command", "action": "mute"}
assert commands.match("mute the volume") == {"type": "command", "action": "mute"}
# "unmute" contains "mute" — must resolve to unmute
assert commands.match("unmute") == {"type": "command", "action": "unmute"}
def test_relative_up_down() -> None:
assert commands.match("volume up") == {"type": "command", "action": "volume_up"}
assert commands.match("louder please") == {"type": "command", "action": "volume_up"}
assert commands.match("turn it up") == {"type": "command", "action": "volume_up"}
assert commands.match("volume down") == {"type": "command", "action": "volume_down"}
assert commands.match("a bit quieter") == {"type": "command", "action": "volume_down"}
assert commands.match("turn it down") == {"type": "command", "action": "volume_down"}
def test_set_to_number_digit_and_word() -> None:
assert commands.match("set volume to 7") == {
"type": "command",
"action": "volume_set",
"level": 7,
}
assert commands.match("volume to seven") == {
"type": "command",
"action": "volume_set",
"level": 7,
}
assert commands.match("volume 3") == {"type": "command", "action": "volume_set", "level": 3}
# clamps into 0..11
assert commands.match("set volume to 50") == {
"type": "command",
"action": "volume_set",
"level": 11,
}
def test_goes_to_eleven() -> None:
assert commands.match("this one goes to eleven") == {
"type": "command",
"action": "volume_set",
"level": 11,
}
assert commands.match("set volume to eleven") == {
"type": "command",
"action": "volume_set",
"level": 11,
}
assert commands.match("crank it") == {"type": "command", "action": "volume_set", "level": 11}
assert commands.match("max volume") == {"type": "command", "action": "volume_set", "level": 11}
def test_non_commands_fall_through_to_llm() -> None:
# these must NOT be hijacked from Tatlock
assert commands.match("what's the weather tomorrow") is None
assert commands.match("set an alarm for a quarter to eleven") is None
assert commands.match("turn up the heating in the lounge") is None
assert commands.match("") is None
assert commands.match("tell me a joke") is None