Preserve location context for travel follow-ups #368

Merged
m merged 2 commits from codex/household-travel-context-fix into main 2026-08-25 16:22:05 +00:00
3 changed files with 30 additions and 3 deletions
+7 -3
View File
@@ -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"},
@@ -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 {
+15
View File
@@ -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.