"""Local intent recognition — pure string logic, no hardware or display. The interesting tests are the negative ones: this feature's whole risk is swallowing something that was meant for the server. """ import sys from pathlib import Path import pytest from bolt_pet import intents sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) @pytest.mark.parametrize("said, expected", [ ("stop", "stop"), ("Stop!", "stop"), ("never mind", "stop"), ("be quiet", "stop"), ("go to sleep", "nap"), ("take a nap", "nap"), ("goodnight", "nap"), ("wake up", "wake"), ("come here", "come"), ("follow my cursor", "come"), ("get out of the way", "go_away"), ("hide", "go_away"), ("say that again", "repeat"), ("what did you say?", "repeat"), ("go for a walk", "wander_on"), ("stay put", "wander_off"), ("sit", "wander_off"), ("use your normal voice", "voice_reset"), ("go back to your normal voice", "voice_reset"), ("be yourself again", "voice_reset"), ]) def test_recognized_phrases(said, expected): intent = intents.recognize(said) assert intent is not None and intent.name == expected @pytest.mark.parametrize("said", [ # Each of these starts with (or contains) an intent phrase, and every one is # a real request. A substring match would eat all of them. "stop the docker container", "stop the deploy and tell me what broke", "can you hide the window that's covering my terminal", "come up with a name for this branch", "repeat the last command but with sudo", "what did you say the disk usage was on the server", "move the config file to the backup directory", "sit down and write me a haiku about kubernetes", "what time is it", "go to sleep mode on the server", "", " ", # Pure filler leaves an empty string, which must not match anything. "hey bolt", "okay bolt please", ]) def test_real_requests_are_left_for_the_server(said): assert intents.recognize(said) is None def test_filler_is_stripped_from_both_ends(): assert intents.normalize("Hey Bolt, could you please just stop now?") == "stop" assert intents.normalize("okay, come here buddy") == "come here" def test_normalize_returns_empty_for_pure_filler(): assert intents.normalize("hey bolt") == "" assert intents.normalize("...") == "" def test_intents_carry_ui_actions_in_the_pet_actions_shape(): """The action dicts go straight to PetWindow.apply_action, so they have to match the vocabulary pet_actions.parse produces — no new UI cases.""" assert intents.recognize("come here").action == {"action": "move", "anchor": "cursor"} assert intents.recognize("stay put").action == {"action": "wander", "enabled": False} assert intents.recognize("go to sleep").action == {"action": "nap", "enabled": True} def test_stop_says_nothing(): """Answering "okay!" when told to be quiet defeats the purpose.""" intent = intents.recognize("be quiet") assert intent.speak == "" and intent.action is None def test_a_phrase_claimed_by_two_intents_fails_at_import(monkeypatch): """Without this guard the phrase would silently bind to whichever intent was declared last — a table edit that looks fine and misbehaves on a mic.""" monkeypatch.setattr(intents, "_TABLE", ( (intents.Intent("stop"), ("enough",)), (intents.Intent("nap"), ("enough",)), )) with pytest.raises(ValueError, match="claimed by both"): intents._build() def test_a_phrase_of_pure_filler_fails_at_import(monkeypatch): """It would normalise to "" and then match any all-filler utterance.""" monkeypatch.setattr(intents, "_TABLE", ((intents.Intent("stop"), ("please bolt",)),)) with pytest.raises(ValueError, match="normalises to nothing"): intents._build() def test_every_table_phrase_round_trips(): for phrase, intent in intents._BY_PHRASE.items(): assert phrase, "a phrase normalised to nothing" assert intents.recognize(phrase) is intent