Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion crates/genie-core/src/tools/quick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2774,7 +2774,24 @@ fn home_status_target(text: &str) -> Option<String> {
}

if contains_any(&target, &["freezer", "garage freezer"]) {
return Some(if target.contains("garage") {
// Keep a qualifier the caller named, like the sibling branches here
// (switches, covers, locks, lights, dryer) already do: this branch
// special-cased "garage" and canonicalized every other target
// unconditionally, so "is the basement freezer on" reported the bare
// "freezer" — a different appliance from the one asked about. Key on
// the device word's position, exactly like the dryer branch above: a
// qualifier precedes the device ("basement freezer"), while a leftover
// state word trails it, so only a genuinely qualified target is
// preserved. The word-order variant "freezer in the garage" still
// canonicalizes through the garage arm.
let names_a_qualified_freezer = target.split_whitespace().count() > 1
&& matches!(
target.split_whitespace().next_back(),
Some("freezer" | "freezers")
);
return Some(if names_a_qualified_freezer {
target
} else if target.contains("garage") {
Comment on lines 2776 to +2794

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Qualified “too warm” requests still lose their qualifier.

The earlier freezer fast path at Line 2479 through Line 2484 returns "freezer" or "garage freezer" before this branch runs. Thus, "Is the basement freezer too warm?" still targets the bare freezer, and the new regression test does not catch it. Reuse this qualifier-preserving logic there and add qualified too warm/freezers coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/genie-core/src/tools/quick.rs` around lines 2776 - 2794, Update the
earlier freezer “too warm” fast path around the existing qualifier-preserving
logic so qualified requests such as “basement freezer” retain their qualifier
instead of returning bare “freezer.” Reuse the same device-position
qualification behavior used by this branch, and add regression coverage for
qualified “too warm” requests, including the plural “freezers” form.

"garage freezer".into()
} else {
"freezer".into()
Expand Down Expand Up @@ -6342,6 +6359,32 @@ mod tests {
assert_eq!(call.name, "memory_recall");
}

#[test]
fn freezer_status_keeps_a_named_qualifier() {
// "Is the basement freezer on?" asks about the basement freezer. The
// freezer branch special-cased "garage" and canonicalized every other
// target to the bare "freezer", so the caller's qualifier was silently
// dropped and a different appliance was reported — the same
// unconditional collapse the dryer branch fixed. A qualifier precedes
// the device word, so key on its position like the dryer branch does.
for (utterance, entity) in [
("Is the basement freezer on?", "basement freezer"),
("check the basement freezer", "basement freezer"),
("Is the kitchen freezer on?", "kitchen freezer"),
// Canonical and garage forms are unchanged. (The bare "is the
// garage freezer on" is a semantic memory question by design, and
// "freezer in the garage" is claimed by the garage/covers branch
// earlier, so the garage arm's guardrail is the priority too-warm
// path.)
("Is the freezer on?", "freezer"),
("Sarah: Is the garage freezer too warm?", "garage freezer"),
] {
let call = route(utterance).unwrap_or_else(|| panic!("no route for {utterance:?}"));
assert_eq!(call.name, "home_status", "{utterance:?}");
assert_eq!(call.arguments["entity"], entity, "{utterance:?}");
}
}

#[test]
fn routes_explicit_memory_search_to_memory_recall() {
let call = route("search memory for Jared").unwrap();
Expand Down
Loading