From ba5cc60c15eb4ee79d149a52b55a896ffabc298f Mon Sep 17 00:00:00 2001 From: Mikhail Date: Mon, 24 Aug 2026 20:00:52 +0300 Subject: [PATCH] fix: route conversational questions to local cognition --- cmd/creator-web/chat_test.go | 47 ++++++++++++++++++- cmd/creator-web/server.go | 14 +++++- ...00292-development-mode-runtime-access.json | 1 + 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/cmd/creator-web/chat_test.go b/cmd/creator-web/chat_test.go index 858d933..5f3723d 100644 --- a/cmd/creator-web/chat_test.go +++ b/cmd/creator-web/chat_test.go @@ -158,7 +158,7 @@ func TestChatMessageDoesNotExposeUnverifiedQuestionAsFact(t *testing.T) { _ = json.NewEncoder(w).Encode(identity.CreatorSession{ActorID: "actor-1", PrincipalID: "principal-1"}) case r.Method == http.MethodPost && r.URL.Path == "/v1/creator/chat/messages": w.WriteHeader(http.StatusCreated) - _ = json.NewEncoder(w).Encode(interaction.ChatMessageResponse{ConversationID: "conversation-1", UtteranceID: "utterance-1", SpeechAct: interaction.SpeechActQuestion, NeedsCognition: true, FallbackText: "небезопасная модельная догадка"}) + _ = json.NewEncoder(w).Encode(interaction.ChatMessageResponse{ConversationID: "conversation-1", UtteranceID: "utterance-1", SpeechAct: interaction.SpeechActQuestion, NeedsCognition: true, CapabilityHints: []capability.CapabilityKind{capability.CapabilityKindWebResearch}, FallbackText: "небезопасная модельная догадка"}) default: t.Fatalf("unexpected core route %s %s", r.Method, r.URL.Path) } @@ -189,6 +189,51 @@ func TestChatMessageDoesNotExposeUnverifiedQuestionAsFact(t *testing.T) { } } +func TestChatMessageUsesLocalAdvisoryForOrdinaryConversationalQuestion(t *testing.T) { + core := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch { + case r.Method == http.MethodGet && r.URL.Path == "/v1/creator/sessions/current": + _ = json.NewEncoder(w).Encode(identity.CreatorSession{ActorID: "actor-1", PrincipalID: "principal-1"}) + case r.Method == http.MethodPost && r.URL.Path == "/v1/creator/chat/messages": + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(interaction.ChatMessageResponse{ConversationID: "conversation-1", UtteranceID: "utterance-1", SpeechAct: interaction.SpeechActQuestion, NeedsCognition: true, FallbackText: "fallback"}) + default: + t.Fatalf("unexpected core route %s %s", r.Method, r.URL.Path) + } + })) + defer core.Close() + cognitiveRuntime := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/v1/advisories" { + t.Fatalf("unexpected cognitive path %s", r.URL.Path) + } + var request cognitive.GatewayAdvisoryRequest + if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + t.Fatal(err) + } + _ = json.NewEncoder(w).Encode(cognitive.GatewayAdvisoryResponse{Version: cognitive.CreatorAdvisoryV1, RequestID: request.RequestID, AdvisoryText: "Я рядом. Давай поговорим.", FinishReason: cognitive.FinishCompleted}) + })) + defer cognitiveRuntime.Close() + handler, err := newHandler(core.URL, "http://continuity", "http://commit", core.Client(), cognitiveRuntime.URL) + if err != nil { + t.Fatal(err) + } + request := httptest.NewRequest(http.MethodPost, "/api/chat/messages", strings.NewReader(`{"message":"Как ты?"}`)) + request.Header.Set("Authorization", "Bearer session-token") + request.Header.Set("Content-Type", "application/json") + recorder := httptest.NewRecorder() + handler.ServeHTTP(recorder, request) + if recorder.Code != http.StatusOK { + t.Fatalf("expected status 200, got %d body=%s", recorder.Code, recorder.Body.String()) + } + var response browserChatResponse + if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil { + t.Fatal(err) + } + if response.ReplyText != "Я рядом. Давай поговорим." || response.Cognition != string(cognitive.FinishCompleted) { + t.Fatalf("unexpected conversational response: %#v", response) + } +} + func TestChatMessageReturnsHumanCapabilityMetadata(t *testing.T) { core := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch { diff --git a/cmd/creator-web/server.go b/cmd/creator-web/server.go index 9017013..ab3faf9 100644 --- a/cmd/creator-web/server.go +++ b/cmd/creator-web/server.go @@ -468,7 +468,7 @@ func (g *gateway) handleChatMessage(w http.ResponseWriter, r *http.Request) { saved.NeedsCognition = false } } - if saved.SpeechAct == interaction.SpeechActQuestion && saved.InformationRequestKind == "" && !saved.ResearchBacked && !saved.WorkPlanned && saved.Clarification != interaction.ClarificationRequired && !asksAttention(browserRequest.Message) { + if requiresVerifiedQuestion(saved, browserRequest.Message) { reply = truthfulVerificationRequiredReply() cognition = "verification_required" saved.NeedsCognition = false @@ -514,6 +514,18 @@ func (g *gateway) handleChatMessage(w http.ResponseWriter, r *http.Request) { }) } +func requiresVerifiedQuestion(saved interaction.ChatMessageResponse, message string) bool { + if saved.SpeechAct != interaction.SpeechActQuestion || saved.InformationRequestKind != "" || saved.ResearchBacked || saved.WorkPlanned || saved.Clarification == interaction.ClarificationRequired || asksAttention(message) { + return false + } + for _, hint := range saved.CapabilityHints { + if hint == capability.CapabilityKindWebResearch || hint == capability.CapabilityKindVerifyFact { + return true + } + } + return false +} + func truthfulVerificationRequiredReply() string { return "Я не могу сейчас подтвердить этот факт по проверенному источнику, поэтому не буду придумывать ответ. Для проверки используйте официальный сайт соответствующей службы или надёжный сервис с текущими данными; когда подключён research-маршрут, Домовой сможет проверить это сам." } diff --git a/dev/tasks/DEV-000292-development-mode-runtime-access.json b/dev/tasks/DEV-000292-development-mode-runtime-access.json index 60b0f2c..56db178 100644 --- a/dev/tasks/DEV-000292-development-mode-runtime-access.json +++ b/dev/tasks/DEV-000292-development-mode-runtime-access.json @@ -11,6 +11,7 @@ "paths": [ "cmd/cognitive-worker/**", "cmd/core-runtime/**", + "cmd/creator-web/**", "adapters/models/**", "contracts/cognitive/**", "modules/interaction/domain/**", -- 2.54.0