Preserve latest travel context #371

Merged
m merged 1 commits from codex/household-travel-query-fix into main 2026-08-25 16:43:43 +00:00
2 changed files with 41 additions and 14 deletions
@@ -178,6 +178,20 @@ func TestTravelRouteWithKnownOriginDoesNotAskForTicketDate(t *testing.T) {
}
}
func TestTravelContextUsesNewestLocationRegardlessOfRepositoryOrder(t *testing.T) {
history := []interaction.HumanUtterance{
{Content: "я сейчас в Санкт-Петербурге", ReceivedAtUnixMillis: 200},
{Content: "я сейчас в Москве", ReceivedAtUnixMillis: 300},
{Content: "я сейчас в Казани", ReceivedAtUnixMillis: 100},
}
if got := TravelSearchClarification("какой ближайший рейс до Сочи?", history); got != "" {
t.Fatalf("newest remembered origin was not applied: %q", got)
}
if got := TravelResearchQuery("какой ближайший рейс до Сочи?", history, time.Time{}); !strings.Contains(got, "из Москве") {
t.Fatalf("newest origin missing from travel research query: %q", got)
}
}
func TestInterpretUtteranceDirectiveRecordsOutcomeWithoutExecution(t *testing.T) {
result := interpretForTest(t, "Поменяй базу на УПО1.", activeFocus("upo", "УПО"), "")
if result.Interpretation.SpeechAct != interaction.SpeechActDirective {
+27 -14
View File
@@ -46,6 +46,10 @@ func TravelResearchQuery(message string, history []interaction.HumanUtterance, n
if origin != "" && !containsStemInTokens(tokens, "из", "откуда", "от") {
query += " отправление из " + origin
}
} else if travelCue(tokens) && !containsStemInTokens(tokens, "из", "откуда", "от") {
if origin := travelContextOrigin(history); origin != "" {
query += " из " + origin
}
}
return query
}
@@ -215,13 +219,7 @@ func TravelSearchClarification(message string, history []interaction.HumanUttera
}
}
}
if origin && destination && date {
return ""
}
ticketRequest := containsStemInTokens(current, "билет", "рейс", "самолет", "самолёт", "вылет")
if !ticketRequest && origin && destination {
return ""
}
if !destination {
if contextDestination := travelContextDestination(history); contextDestination != "" {
destination = true
@@ -238,6 +236,9 @@ func TravelSearchClarification(message string, history []interaction.HumanUttera
origin = true
}
}
if origin && destination && (date || !ticketRequest) {
return ""
}
if destination && !origin && !date {
if !ticketRequest {
return "Из какого города выезжать в " + destinationLabel(current, history) + "? Подберу самолёт, поезд, автобус или машину."
@@ -297,8 +298,10 @@ func travelContextDestinationFromTokens(tokens []string) string {
}
func travelContextDestination(history []interaction.HumanUtterance) string {
for index := len(history) - 1; index >= 0; index-- {
tokens := semanticTokens(history[index].Content)
latestAt := int64(-1)
latest := ""
for _, utterance := range history {
tokens := semanticTokens(utterance.Content)
if !travelContextCue(tokens) {
continue
}
@@ -307,26 +310,36 @@ func travelContextDestination(history []interaction.HumanUtterance) string {
continue
}
if tokenIndex+1 < len(tokens) && len([]rune(tokens[tokenIndex+1])) >= 3 {
return capitalizeWord(tokens[tokenIndex+1])
if utterance.ReceivedAtUnixMillis >= latestAt {
latestAt = utterance.ReceivedAtUnixMillis
latest = capitalizeWord(tokens[tokenIndex+1])
}
break
}
}
}
return ""
return latest
}
func travelContextOrigin(history []interaction.HumanUtterance) string {
for index := len(history) - 1; index >= 0; index-- {
tokens := semanticTokens(history[index].Content)
latestAt := int64(-1)
latest := ""
for _, utterance := range history {
tokens := semanticTokens(utterance.Content)
if len(tokens) < 3 || tokens[0] != "я" || !containsStemInTokens(tokens, "сейчас", "нахож", "жив") {
continue
}
for tokenIndex, token := range tokens {
if (token == "в" || token == "из") && tokenIndex+1 < len(tokens) {
return capitalizeWord(tokens[tokenIndex+1])
if utterance.ReceivedAtUnixMillis >= latestAt {
latestAt = utterance.ReceivedAtUnixMillis
latest = capitalizeWord(tokens[tokenIndex+1])
}
break
}
}
}
return ""
return latest
}
func travelContextCue(tokens []string) bool {