Skip to content

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

Description

@philluiz2323

Summary

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

The timer arm is a substring test, so please set a timer for 10 minutes
routes fine. The reminder arms are prefix tests, so a leading please
pushes them off the anchor and every polite reminder falls through to the LLM.

The asymmetry is the bug: the same politeness token is harmless on one arm of
the same if and fatal on the other.

Repro (on main)

utterance on main expected
Please remind me to check the pasta in 5 minutes ABSTAIN set_timer{seconds: 300, label: check the pasta}
Please remind me to take the trash out in 20 minutes ABSTAIN set_timer{seconds: 1200, label: take the trash out}
Please remind us to leave in 10 minutes ABSTAIN set_timer{seconds: 600, label: leave}
Please set a timer for 10 minutes set_timer{600, timer} unchanged (already works)

Remind me to check the pasta in 5 minutes routes today.

Root cause

Two coupled anchors, not one:

  1. The entry gate text.starts_with("remind me ") / ("remind us ") never
    matches, so the function returns None immediately.
  2. Even if it did, reminder_style is computed from the same two prefixes.
    With please still attached it would be false, so reminder_label would
    skip the task-first scan and the call would be labelled timer rather than
    check the pasta — a silently degraded reminder instead of an absent one.

So stripping has to happen before both the gate and the reminder_style
computation, not just in front of the gate.

Proposed fix

Strip a single leading please at the top of timer_request, before the
gate and before reminder_style is derived, and tokenize the stripped text.
Mirrors the leading-please strips already in
scene_or_routine_activation_request, play_media_request, and
shopping_list_add_request. The trailing-please label trim already in
timer_request is unaffected.

text.starts_with("remind ") in the label fallback must read the stripped text
too, so a polite reminder with no extractable label still defaults to
reminder and not timer.

Acceptance

  • please remind me/us … emits the same set_timer seconds and label as
    the bare form
  • Existing timer / trailing-please / compound-duration behavior unchanged
  • Focused regression test fails on main, passes with the fix
  • No prompt growth; 4096 Jetson contract untouched

Labels / scope

Tool-dispatch correctness (deterministic quick-router).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions