Skip to content

fix(quick-router): accept a leading please on remind me/us commands - #923

Closed
joaovictor712 wants to merge 1 commit into
GeniePod:mainfrom
joaovictor712:fix/remind-me-leading-please
Closed

fix(quick-router): accept a leading please on remind me/us commands#923
joaovictor712 wants to merge 1 commit into
GeniePod:mainfrom
joaovictor712:fix/remind-me-leading-please

Conversation

@joaovictor712

@joaovictor712 joaovictor712 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #920. The timer gate mixes a substring test with two prefix tests:

text.contains("timer")
    || text.starts_with("remind me ")
    || text.starts_with("remind us ")

so one politeness token was harmless on one arm and fatal on the others.
please set a timer for 10 minutes still routed — it contains timer — while
every polite reminder fell through to the LLM.

utterance before after
Please remind me to check the pasta in 5 minutes ABSTAIN set_timer{300, "check the pasta"}
Please remind me to take the trash out in 20 minutes ABSTAIN set_timer{1200, "take the trash out"}
Please remind us to leave in 10 minutes ABSTAIN set_timer{600, "leave"}
Please remind me in 5 minutes to check the oven ABSTAIN set_timer{300, "check the oven"}
Please set a timer for 10 minutes set_timer{600, "timer"} unchanged

Changes

  • Strip a single leading please at the top of timer_request, mirroring
    scene_or_routine_activation_request, play_media_request, and
    shopping_list_add_request.
  • The placement matters as much as the strip. reminder_style is derived from
    the same two prefixes and selects the task-first label scan, so stripping
    only in front of the gate would not be enough: a reminder that squeaked
    through on the timer arm with please still attached would be labelled
    timer instead of check the pasta — a silently degraded reminder rather
    than an absent one, which is the harder failure to notice. Stripping before
    both the gate and reminder_style fixes seconds and label together.
  • Tokenization runs on the stripped text, so every duration span and label
    index stays consistent. The label fallback reads the stripped text too, so a
    polite reminder with no extractable task still defaults to reminder rather
    than timer. The trailing-please label trim is untouched.
  • New regression test reminder_accepts_a_leading_please.

Real Behavior Proof

  • I have built and run the affected code locally (or noted why I could not).
  • I have verified the change end-to-end on Jetson hardware.
  • I have NOT verified on Jetson hardware, and I explain the equivalent verification path or validation gap below.

Tested profile / hardware (check all that apply):

  • jetson
  • raspberry_pi
  • portable_sbc
  • laptop
  • mac
  • CI-only / docs-only
  • Not run locally

What I ran

x86_64 Linux laptop (Ubuntu 22.04 LTS, kernel 6.8.0-136-generic,
rustc 1.96.0 / cargo 1.96.0). No Jetson available to me — see the validation
gap below.

cargo test -p genie-core
cargo clippy -p genie-core --all-targets
cargo fmt -p genie-core -- --check

Plus a temporary probe binding route() directly over the affected utterances,
so I could read the emitted ToolCall — specifically the label, since the
degraded-label failure mode above is invisible to a "does it route" check. The
probe was removed before committing; only the permanent regression test
remains.

What I observed

Probe output on this branch:

please remind me to check the pasta in 5 minutes     -> set_timer {"label":"check the pasta","seconds":300}
please remind me to take the trash out in 20 minutes -> set_timer {"label":"take the trash out","seconds":1200}
please remind us to leave in 10 minutes              -> set_timer {"label":"leave","seconds":600}
please remind me in 10 minutes                       -> set_timer {"label":"reminder","seconds":600}
please remind me to buy milk                         -> ABSTAIN

The first three printed ABSTAIN on main. The fourth confirms the fallback
label is reminder, not timer — i.e. the strip landed ahead of
reminder_style, not merely ahead of the gate. The fifth confirms that
stripping politeness does not invent a timer for an utterance with no duration
to parse.

cargo test -p genie-core: 1005 lib tests passed, 0 failed, 6 ignored, and
all integration suites green. cargo clippy --all-targets produced no
warnings; cargo fmt --check produced no diff.

Validation gap

I could not verify on Jetson hardware. The equivalent verification path: this
change is confined to crates/genie-core/src/tools/quick.rs, a pure
string→ToolCall function with no I/O, no async, no hardware dependency, and
no model involvement. Its entire contract is which ToolCall comes out for a
given utterance, asserted directly above. The emitted call is byte-identical to
the one the bare utterance already produces and already dispatches on Jetson
today, so the timer subsystem downstream sees nothing new. Nothing in the diff
touches audio, the dashboard, or the model prompt.

Test plan

  1. Cherry-pick reminder_accepts_a_leading_please onto main alone and run it
    — fails on the first case.
  2. Check out this branch, rerun — passes.
  3. On a device, say "please remind me to check the pasta in 5 minutes" and
    confirm the timer arms with the label "check the pasta" (not "timer") and
    without an LLM round-trip.

Notes for reviewers

  • The test asserts the polite call equals the bare call by name and
    arguments for three utterances, so a partial fix that got the duration right
    and the label wrong would still fail.
  • No prompt growth, no new dependencies. The 4096-token Jetson context contract
    is untouched.
  • Behavior is unchanged for every utterance that does not begin with please .

The timer gate mixes a substring test with two prefix tests:

    text.contains("timer")
        || text.starts_with("remind me ")
        || text.starts_with("remind us ")

so one politeness token was harmless on one arm and fatal on the others.
"please set a timer for 10 minutes" still routed — it contains "timer" —
while every polite reminder fell through to the LLM:

  "please remind me to check the pasta in 5 minutes"    -> ABSTAIN
  "please remind me to take the trash out in 20 minutes" -> ABSTAIN
  "please remind us to leave in 10 minutes"              -> ABSTAIN

Strip a single leading "please " at the top of timer_request, before the
gate, mirroring scene_or_routine_activation_request, play_media_request,
and shopping_list_add_request.

Placing the strip ahead of reminder_style matters as much as the gate.
That flag is derived from the same two prefixes and selects the
task-first label scan, so a reminder that squeaked past the gate on the
"timer" arm with "please" still attached would be labelled "timer"
rather than "check the pasta" — a silently degraded reminder instead of
an absent one. The label fallback reads the stripped text for the same
reason, so a polite reminder with no extractable task still defaults to
"reminder".

Tokenization now runs on the stripped text, so every duration and label
index stays consistent. The trailing-"please" label trim is unchanged.

Closes GeniePod#920
@github-actions

Copy link
Copy Markdown

Closing this PR automatically because @galuis116 currently has 3 open PRs in this repository.

The current limit is 2 open PRs per contributor. Please keep only the highest-signal PRs open, finish or close existing work, then reopen this PR if it is still needed.

Current PR: #923

@github-actions github-actions Bot added the bug Something isn't working label Jul 30, 2026
@github-actions github-actions Bot closed this Jul 30, 2026
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ad9781f9-a4e9-4ab7-b136-3335a60fd830

📥 Commits

Reviewing files that changed from the base of the PR and between 02a577d and 203da42.

📒 Files selected for processing (1)
  • crates/genie-core/src/tools/quick.rs

📝 Walkthrough

Walkthrough

The timer/reminder quick router now removes a leading "please " before routing and label extraction. Regression tests cover polite reminder variants, matching durations and labels, fallback labels, and abstention without a parseable duration.

Changes

Timer and reminder routing

Layer / File(s) Summary
Normalize reminder requests and test routing
crates/genie-core/src/tools/quick.rs
timer_request strips leading politeness before its routing gate and reminder-style detection. Tests verify set_timer arguments, fallback labels, and abstention behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: bug

Suggested reviewers: matedev01, yurii214, ultrahighsuper

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] quick-router: a leading "please" on "remind me/us …" drops the reminder — the timer gate anchors on the prefix

1 participant