confirm answers match whole words from the lexicon (V-567)
classifyConfirm was a substring test over bare stems, so "погода", "дальше", "надо" and "давление" all read as "да", and "покажи" and "около" read as "ок". resolveConfirm runs before routing, so a question about the weather executed a parked destructive act. Reproduced on the box: with "restart nonexistent-xyz" parked, "какая погода" answered "не получилось выполнить команду". The yes and no answers are now two closed sets in internal/lexicon, matched as whole tokens longest-first, and the WHOLE utterance must be answer words and filler — a leading "давай" does not make "давай посмотрим погоду" an answer. Anything else is confirmUnknown, which now leaves the confirm parked instead of disarming it: an utterance that is not an answer is not a cancellation either. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -65,6 +65,7 @@ func mustLoad() lexiconFile {
|
||||
"day_offsets", "weekdays", "months_genitive", "hours_spoken",
|
||||
"not_place_after_v", "parts_of_day", "reminder_verbs", "half_hour",
|
||||
"filler_particles", "task_done_words", "task_drop_words",
|
||||
"confirm_yes", "confirm_no",
|
||||
} {
|
||||
s, ok := f.Sets[name]
|
||||
if !ok || (len(s.Words) == 0 && len(s.Values) == 0) {
|
||||
@@ -121,6 +122,16 @@ func ReminderVerbs() []string { return words("reminder_verbs") }
|
||||
// notes say: an imperative exactly, a stative by lemma.
|
||||
func TaskDoneWords() []string { return words("task_done_words") }
|
||||
|
||||
// ConfirmYes returns the words that answer a parked confirm with yes, and
|
||||
// ConfirmNo the ones that answer it with no. Some members are multi-word ("не
|
||||
// надо"), so a caller matches longest-first over tokens rather than looking up
|
||||
// one word at a time. See the sets' notes for why neither may be matched as a
|
||||
// substring.
|
||||
func ConfirmYes() []string { return words("confirm_yes") }
|
||||
|
||||
// ConfirmNo — see ConfirmYes.
|
||||
func ConfirmNo() []string { return words("confirm_no") }
|
||||
|
||||
// TaskDropWords — see TaskDoneWords.
|
||||
func TaskDropWords() []string { return words("task_drop_words") }
|
||||
|
||||
|
||||
@@ -197,6 +197,22 @@
|
||||
"drop", "remove", "cancel",
|
||||
"передумал", "передумала", "неактуально"
|
||||
]
|
||||
},
|
||||
"confirm_yes": {
|
||||
"note": "The whole vocabulary of saying yes to a parked confirm, Russian and English. Closed because it is her question that is being answered: she asked \"да или нет\", and the answers to that question can be listed. Matched as whole tokens and never as substrings — \"погода\", \"давление\" and \"дальше\" all contain \"да\", and a substring test executed a destructive act when he asked about the weather (V-567). Words that merely sound agreeable — \"хорошо\", \"ладно\", \"точно\" — are deliberately absent: they open a sentence about something else as often as they answer, and an unclear answer must route rather than execute.",
|
||||
"words": [
|
||||
"да", "ага", "угу", "давай", "давайте", "конечно",
|
||||
"подтверждаю", "подтверди", "подтвердить", "выполняй", "валяй",
|
||||
"yes", "yeah", "yep", "yup", "ok", "okay", "sure", "confirm", "affirmative"
|
||||
]
|
||||
},
|
||||
"confirm_no": {
|
||||
"note": "The answers that decline a parked confirm. Same matching rule as confirm_yes and the same reason. The multi-word members are here rather than assembled by a caller because \"надо\" alone is not an answer and \"не надо\" is the opposite of one: the two must land on opposite sides, and only the phrase says which. \"не\" on its own is NOT a member — \"не забудь купить хлеб\" is a reminder, not a refusal.",
|
||||
"words": [
|
||||
"нет", "неа", "нельзя", "отмена", "отмени", "отменить", "отставить",
|
||||
"стоп", "стой", "не надо", "не нужно", "не стоит", "не сейчас", "не хочу",
|
||||
"no", "nope", "nah", "negative", "cancel", "stop", "don't", "dont"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user