From b4234d761dc2c6c8101896a0ead630ce92a28053 Mon Sep 17 00:00:00 2001 From: Sriram Venkat Date: Tue, 22 Sep 2026 18:02:44 -0700 Subject: [PATCH 1/2] fix: intent-agnostic entity-question wording, clarify script/scene action Two small wording fixes to interpret.py's build_questions(), both backed by measured evidence: 1. The `entity` question was hardcoded to command-oriented phrasing ("which device should receive this?"), but it's answered in the same fan-out call as `action`, before get_state vs. turn_on/off is known. Measured in a comparable Jev-backed integration: for a get_state-style question, identical entity candidates, command phrasing put none_of_these ahead of the one real match at 58% confidence; "which device is this about?" put the real match ahead at 69%. Reworded to be intent-agnostic at no cost to the single-call design. 2. The `turn_on` action description didn't address a script/scene whose own name reads like a question. Reproduced directly against this repo's real question shapes with a live TypeSafe call against a real house's `script.get_weather` entity: "run the get weather script" scored action=none_of_these at 0.98 confidence and fell back silently instead of running the script. Added a clarifying clause; the equivalent fix in a sibling Jev integration resolved the same failure mode (information_request -> smarthome_command misclassification on the identical phrase). No test hardcodes the changed strings (checked all of tests/*.py). --- custom_components/jev/interpret.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/custom_components/jev/interpret.py b/custom_components/jev/interpret.py index 9539184..2dbdc58 100644 --- a/custom_components/jev/interpret.py +++ b/custom_components/jev/interpret.py @@ -156,7 +156,10 @@ def build_questions( # No lock wording here on purpose. The agent does not control # locks, and Home Assistant's on/off convention for them runs the # opposite way round from speech. See CONTROLLABLE in snapshot.py. - "turn_on": "Switch something on, open it, or start it", + "turn_on": "Switch something on, open it, or start it — including " + "running a named script or activating a scene, even when its own " + "name reads like a question (a script called \"get_weather\" is " + "still something to run, not something to ask)", "turn_off": "Switch something off, close it, or stop it", "toggle": "Flip whatever state it is in now", "set_brightness": "Change how bright a light is", @@ -194,7 +197,17 @@ def build_questions( ), "entity": Choice( { - "question": "Which device should receive this?", + # Worded to fit a status check as well as a command: this + # question is answered in the same request as `action`, before + # get_state vs. turn_on/off is known, and command-only phrasing + # measurably shifts probability away from the right entity on a + # query. Measured in a comparable Jev-backed integration, same + # entity list either way: for a get_state-style question with + # one real matching entity plus none_of_these, "which device + # should receive the command" put none_of_these ahead at 58% + # confidence; "which device is this about" put the real + # entity ahead at 69% — wording alone flipped the answer. + "question": "Which device is this about?", "background": "Match on the name and on the room. Pick " "none_of_these when no single device is meant.", }, From c63197d0653014d028845270acb5dd35d3436b84 Mon Sep 17 00:00:00 2001 From: Sriram Venkat Date: Tue, 22 Sep 2026 23:03:22 -0700 Subject: [PATCH 2/2] address review: shorten turn_on wording, trim comment, no em dashes - Shortened the turn_on description to one line, per-request token cost - Cut the entity-question comment to one line explaining why the wording fits both intents; the measured numbers belonged in the PR description, not a code comment about what this code doesn't show - Removed em dashes - ruff format --check and ruff check both pass on the changed file --- custom_components/jev/interpret.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/custom_components/jev/interpret.py b/custom_components/jev/interpret.py index 2dbdc58..4e83f75 100644 --- a/custom_components/jev/interpret.py +++ b/custom_components/jev/interpret.py @@ -156,10 +156,8 @@ def build_questions( # No lock wording here on purpose. The agent does not control # locks, and Home Assistant's on/off convention for them runs the # opposite way round from speech. See CONTROLLABLE in snapshot.py. - "turn_on": "Switch something on, open it, or start it — including " - "running a named script or activating a scene, even when its own " - "name reads like a question (a script called \"get_weather\" is " - "still something to run, not something to ask)", + "turn_on": "Switch something on, open it, start it, " + "or run a script or scene", "turn_off": "Switch something off, close it, or stop it", "toggle": "Flip whatever state it is in now", "set_brightness": "Change how bright a light is", @@ -197,16 +195,8 @@ def build_questions( ), "entity": Choice( { - # Worded to fit a status check as well as a command: this - # question is answered in the same request as `action`, before - # get_state vs. turn_on/off is known, and command-only phrasing - # measurably shifts probability away from the right entity on a - # query. Measured in a comparable Jev-backed integration, same - # entity list either way: for a get_state-style question with - # one real matching entity plus none_of_these, "which device - # should receive the command" put none_of_these ahead at 58% - # confidence; "which device is this about" put the real - # entity ahead at 69% — wording alone flipped the answer. + # Answered in the same request as action, so it must fit a + # status check too. "question": "Which device is this about?", "background": "Match on the name and on the room. Pick " "none_of_these when no single device is meant.",