Form nearest flight searches from route context #389

Merged
m merged 1 commits from codex/household-travel-query-fix into main 2026-08-25 20:39:43 +00:00
3 changed files with 24 additions and 8 deletions
-5
View File
@@ -534,10 +534,6 @@ func main() {
}
conversationHistory = append(conversationHistory, recentUserHistory...)
personalMemory := interactiondomain.CompilePersonalMemory(conversationHistory)
// Context selection must stay observable without logging the user's
// message or personal fact values. These flags let an operator distinguish
// a missing derived fact from a later routing or clarification decision.
personalMemoryHasCurrentLocation := personalMemory.CurrentLocation() != ""
if !creativeUserRequest && locationReply == "" {
if continuation := interactiondomain.ContinueLocalSearch(effectiveTaskMessage, conversationHistory); continuation != "" {
continuationMessage = continuation
@@ -654,7 +650,6 @@ func main() {
deterministicSpeechAct := semantic.Interpretation.SpeechAct
deterministicReply := semantic.Reply
routePlan := buildChatRoutePlan(semantic)
log.Printf("chat context state: current_location=%t research_route=%t clarification=%s", personalMemoryHasCurrentLocation, hasChatRoute(routePlan, chatRouteResearch), semantic.Interpretation.Clarification)
cognitiveAttempted := false
cognitiveAvailable := true
semanticInterpretationRequested := shouldRequestSemanticInterpretation(semantic)
+2 -2
View File
@@ -209,8 +209,8 @@ func TestNearestPlaneUsesTravelContextAndCurrentDay(t *testing.T) {
now := time.Date(2026, time.August, 25, 18, 0, 0, 0, time.UTC)
history := []interaction.HumanUtterance{{Content: "я сейчас в Москве", ReceivedAtUnixMillis: 100}}
query := TravelResearchQuery("найди ближайший самолет до Казани", history, now)
if !strings.Contains(query, "сегодня 25.08.2026") || !strings.Contains(query, "пункт отправления: Москве") {
t.Fatalf("nearest plane query lost current context: %q", query)
if query != "ближайшие авиарейсы Москве Казани сегодня 25.08.2026" {
t.Fatalf("nearest plane search formulation lost current context: %q", query)
}
if got := TravelSearchClarification("найди ближайший самолет до Казани", history); got != "" {
t.Fatalf("known origin and nearest-time meaning should proceed, got %q", got)
+22 -1
View File
@@ -47,7 +47,12 @@ func TravelResearchQuery(message string, history []interaction.HumanUtterance, n
query += " отправление из " + origin
}
} else if travelCue(tokens) && !containsStemInTokens(tokens, "из", "откуда", "от") {
if origin := travelContextOrigin(history); origin != "" {
origin := travelContextOrigin(history)
destination := travelContextDestinationFromTokens(tokens)
if nearestAirTravelRequest(tokens) && origin != "" && destination != "" {
return nearestAirTravelSearchQuery(origin, destination, now)
}
if origin != "" {
// Preserve the remembered location as an explicit search parameter
// instead of guessing its grammatical form in the user's language.
query += " пункт отправления: " + origin
@@ -56,6 +61,18 @@ func TravelResearchQuery(message string, history []interaction.HumanUtterance, n
return query
}
// nearestAirTravelSearchQuery is a capability-local search formulation, not a
// provider or place lookup. It removes conversational imperatives while
// preserving the two user-derived route endpoints and the implicit current-day
// meaning of "ближайший".
func nearestAirTravelSearchQuery(origin, destination string, now time.Time) string {
query := "ближайшие авиарейсы " + origin + " " + destination + " сегодня"
if !now.IsZero() {
query += " " + now.Format("02.01.2006")
}
return query
}
// StripAssistantVocative removes a leading assistant name used as an address.
// The original utterance remains the historical source; this value is only for
// interpretation, cognitive prompts and external queries.
@@ -371,6 +388,10 @@ func travelCue(tokens []string) bool {
return containsStemInTokens(tokens, "билет", "рейс", "самолет", "самолёт", "вылет", "поезд", "автобус", "перелет", "перелёт")
}
func nearestAirTravelRequest(tokens []string) bool {
return containsStemInTokens(tokens, "ближ") && containsStemInTokens(tokens, "самолет", "самолёт", "авиарейс", "перелет", "перелёт")
}
func travelFollowUpCue(tokens []string) bool {
return containsStemInTokens(tokens, "куда", "откуда", "маршрут", "летим", "дата", "число")
}