From 056c8cc9f5197285a96931c31049f4ddcc3e75f2 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Tue, 25 Aug 2026 14:43:15 +0300 Subject: [PATCH] Route marketplace search and bear drawing --- cmd/core-runtime/household_scenario_test.go | 20 ++++++++++++++++++++ modules/interaction/domain/chat.go | 5 ++++- modules/interaction/domain/chat_test.go | 5 ++++- tests/household_scenarios/scenarios.json | 4 ++-- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/cmd/core-runtime/household_scenario_test.go b/cmd/core-runtime/household_scenario_test.go index dd0ed2a..109683d 100644 --- a/cmd/core-runtime/household_scenario_test.go +++ b/cmd/core-runtime/household_scenario_test.go @@ -35,3 +35,23 @@ func TestHouseholdCreativeRouteDoesNotUseResearch(t *testing.T) { t.Fatal("creative request was not recognized") } } + +func TestHouseholdMarketplaceBrandSearchUsesResearchRoute(t *testing.T) { + candidate := interactiondomain.BuildDeterministicCandidate("найди на WB бренд marka-wear", "", time.Unix(10, 0).UnixMilli()) + routes := buildChatRoutePlan(interactiondomain.SemanticResult{NeedsCognition: candidate.NeedsCognition, CapabilityHints: candidate.CapabilityHints}) + if !hasChatRoute(routes, chatRouteResearch) { + t.Fatalf("marketplace brand request did not select research route: candidate=%+v routes=%+v", candidate, routes) + } +} + +func TestHouseholdBearDrawingUsesCreativeLocalRoute(t *testing.T) { + candidate := interactiondomain.BuildDeterministicCandidate("нарисуй бурого медведя", "", time.Unix(10, 0).UnixMilli()) + for _, hint := range candidate.CapabilityHints { + if capability.CapabilityKind(hint) == capability.CapabilityKindWebResearch { + t.Fatalf("bear drawing selected web research: %+v", candidate) + } + } + if got := interactiondomain.CreativeDeterministicReply("нарисуй бурого медведя"); got != "🐻" { + t.Fatalf("bear drawing fallback=%q", got) + } +} diff --git a/modules/interaction/domain/chat.go b/modules/interaction/domain/chat.go index 1812ed1..d3694a4 100644 --- a/modules/interaction/domain/chat.go +++ b/modules/interaction/domain/chat.go @@ -558,7 +558,7 @@ func sourceDependentQuestion(primary, secondary interaction.SpeechAct, tokens [] } currentCue := containsStemInTokens(tokens, "сейчас", "сегодня", "текущ", "актуаль", "последн", "прямо") observedStateCue := containsStemInTokens(tokens, "погод", "температур", "осад", "ветер", "курс", "цен", "стоим", "новост", "распис", "событ", "статус", "доступен", "работает", "запущен", "срок") || approximateToken(tokens, "погод", 2) - placeSearchCue := containsStemInTokens(tokens, "ресторан", "кафе", "отел", "магаз", "мест", "ближ", "адрес", "организац") + placeSearchCue := containsStemInTokens(tokens, "ресторан", "кафе", "отел", "магаз", "мест", "ближ", "адрес", "организац", "бренд", "товар", "артикул", "продавец", "маркетплейс", "wildberries", "wb") travelSearchCue := containsStemInTokens(tokens, "билет", "рейс", "поезд", "автобус", "перелет", "перелёт", "отправлен", "прибыт") return currentCue || observedStateCue || placeSearchCue || travelSearchCue } @@ -665,6 +665,9 @@ func CreativeDeterministicReply(message string) string { if containsStemInTokens(tokens, "нарис", "рису", "изобраз") && containsStemInTokens(tokens, "круг", "окруж") { return "◯" } + if containsStemInTokens(tokens, "нарис", "рису", "изобраз") && containsStemInTokens(tokens, "медвед", "мишк") { + return "🐻" + } return "" } diff --git a/modules/interaction/domain/chat_test.go b/modules/interaction/domain/chat_test.go index dee93cc..642abad 100644 --- a/modules/interaction/domain/chat_test.go +++ b/modules/interaction/domain/chat_test.go @@ -156,7 +156,7 @@ func TestSourceDependentQuestionRequestsWebResearchWithoutEntityBranch(t *testin } func TestSourceDependentQuestionToleratesTyposAndPlaceSearch(t *testing.T) { - for _, message := range []string{"какая пугода в Сочи", "найди ближайший ресторан в Сочи", "найди билеты до Ялты"} { + for _, message := range []string{"какая пугода в Сочи", "найди ближайший ресторан в Сочи", "найди билеты до Ялты", "найди на WB бренд marka-wear"} { candidate := BuildDeterministicCandidate(message, "", time.Unix(10, 0).UnixMilli()) seen := false for _, hint := range candidate.CapabilityHints { @@ -247,6 +247,9 @@ func TestInterpretCreativeRequestDoesNotRequireExternalEvidence(t *testing.T) { if got := CreativeFallbackReply("расскажи сказку о колобке"); !strings.Contains(got, "Колоб") { t.Fatalf("story fallback = %q", got) } + if got := CreativeDeterministicReply("нарисуй бурого медведя"); got != "🐻" { + t.Fatalf("bear reply = %q", got) + } } func containsString(values []string, expected string) bool { diff --git a/tests/household_scenarios/scenarios.json b/tests/household_scenarios/scenarios.json index 9ea5d80..741d2df 100644 --- a/tests/household_scenarios/scenarios.json +++ b/tests/household_scenarios/scenarios.json @@ -9,7 +9,7 @@ { "id": "SCN-HH-002", "category": "current_information", - "messages": ["я сейчас в Москве", "какая погода в Питере?", "проверь цену на RTX 4090"], + "messages": ["я сейчас в Москве", "какая погода в Питере?", "проверь цену на RTX 4090", "найди на WB бренд marka-wear"], "must": ["current facts use web research or an explicit source path", "location and time defaults are applied when confidence is high", "answer synthesizes evidence"], "must_not": ["raw search snippets", "search-engine query URLs as the answer", "unsupported certainty"] }, @@ -44,7 +44,7 @@ { "id": "SCN-HH-007", "category": "creative_conversation", - "messages": ["нарисуй круг", "расскажи сказку о Колобке", "придумай шутку"], + "messages": ["нарисуй круг", "нарисуй бурого медведя", "расскажи сказку о Колобке", "придумай шутку"], "must": ["creative requests avoid irrelevant web search", "simple safe output can use a local fast path", "rich output uses cognition when available"], "must_not": ["technical evidence refusal for a creative request", "provider name replacing Domovoy identity"] },