From 7788cf4b44fb1e6677ecc6ca596772d686f40d98 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Tue, 25 Aug 2026 19:17:34 +0300 Subject: [PATCH] Preserve location context for travel follow-ups --- cmd/core-runtime/main.go | 10 +++++++--- modules/interaction/domain/semantics_test.go | 8 ++++++++ modules/interaction/domain/travel.go | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/cmd/core-runtime/main.go b/cmd/core-runtime/main.go index 5487027..c81ecc9 100644 --- a/cmd/core-runtime/main.go +++ b/cmd/core-runtime/main.go @@ -511,6 +511,7 @@ func main() { } var effectiveTaskMessage = interactiondomain.StripAssistantVocative(utterance.Content) creativeUserRequest := interactiondomain.IsCreativeRequest(utterance.Content) + locationReply := interactiondomain.LocationContextReply(utterance.Content) continuationMessage := "" travelContinuation := false var previousTask *interaction.HumanUtterance @@ -532,7 +533,7 @@ func main() { log.Printf("interaction principal history loaded: %d utterances", len(recentUserHistory)) } conversationHistory = append(conversationHistory, recentUserHistory...) - if !creativeUserRequest { + if !creativeUserRequest && locationReply == "" { if continuation := interactiondomain.ContinueLocalSearch(effectiveTaskMessage, conversationHistory); continuation != "" { continuationMessage = continuation effectiveTaskMessage = continuation @@ -599,8 +600,11 @@ func main() { } } } - locationReply := interactiondomain.LocationContextReply(utterance.Content) if locationReply != "" { + continuationMessage = "" + travelContinuation = false + effectiveTaskMessage = interactiondomain.StripAssistantVocative(utterance.Content) + previousTask = nil semantic.Reply = locationReply semantic.NeedsCognition = false semantic.Interpretation.NeedsCognition = false @@ -778,7 +782,7 @@ func main() { replies = append(replies, "По запросу «"+part+"»: "+clarification) continue } - searchQuery := interactiondomain.TravelSearchQuery(part, now) + searchQuery := interactiondomain.TravelResearchQuery(part, conversationHistory, now) researchCtx, cancelResearch := context.WithTimeout(r.Context(), 8*time.Second) result, researchErr := researchClient.SearchWeb(researchCtx, epistemics.WebSearchRequest{ Plan: epistemics.ResearchPlan{ID: epistemics.ResearchPlanID(fmt.Sprintf("plan:%s:%d", planID, index)), Question: searchQuery, SourceClasses: []string{"web-search"}, FreshnessPolicy: "current"}, diff --git a/modules/interaction/domain/semantics_test.go b/modules/interaction/domain/semantics_test.go index aa4eb65..712aed2 100644 --- a/modules/interaction/domain/semantics_test.go +++ b/modules/interaction/domain/semantics_test.go @@ -159,6 +159,14 @@ func TestTravelSearchQueryCarriesNearestFlightDate(t *testing.T) { } } +func TestTravelResearchQueryUsesKnownOriginForDistance(t *testing.T) { + history := []interaction.HumanUtterance{{Content: "я сейчас в Москве"}} + got := TravelResearchQuery("сколько километров до Сочи?", history, time.Time{}) + if !strings.Contains(got, "точка отправления: Москве") || !strings.Contains(got, "расстояние по прямой и по дороге") { + t.Fatalf("distance query lost route context: %q", got) + } +} + func TestInterpretUtteranceDirectiveRecordsOutcomeWithoutExecution(t *testing.T) { result := interpretForTest(t, "Поменяй базу на УПО1.", activeFocus("upo", "УПО"), "") if result.Interpretation.SpeechAct != interaction.SpeechActDirective { diff --git a/modules/interaction/domain/travel.go b/modules/interaction/domain/travel.go index 05a9725..cc8a726 100644 --- a/modules/interaction/domain/travel.go +++ b/modules/interaction/domain/travel.go @@ -21,6 +21,21 @@ func TravelSearchQuery(message string, now time.Time) string { return cleaned + " сегодня " + now.Format("02.01.2006") } +// TravelResearchQuery keeps route and distance questions tied to a known +// origin before they reach a generic web search. The history is semantic +// context, not a list of example-specific answers. +func TravelResearchQuery(message string, history []interaction.HumanUtterance, now time.Time) string { + query := TravelSearchQuery(message, now) + tokens := semanticTokens(StripAssistantVocative(message)) + if containsStemInTokens(tokens, "расстоян", "километр", "добрат", "маршрут") { + if origin := travelContextOrigin(history); origin != "" && !containsStemInTokens(tokens, "из", "откуда", "от") { + query += " точка отправления: " + origin + } + query += " расстояние по прямой и по дороге" + } + 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. -- 2.54.0