merge Gen2 household acceptance fixes
CI / test (push) Failing after 38s

This commit is contained in:
m
2026-08-29 23:28:15 +03:00
8 changed files with 97 additions and 12 deletions
+10 -1
View File
@@ -157,7 +157,10 @@ func main() {
mux.Handle("/readyz", health.ReadinessHandler{Runtime: "core-runtime", Probes: []health.Probe{
health.TCPProbe("postgres", envOr("POSTGRES_HOST", "postgres"), envOr("POSTGRES_PORT", "5432")),
health.HTTPProbe(readinessClient, strings.TrimRight(envOr("CONTINUITY_RUNTIME_URL", "http://continuity-runtime:8081"), "/")+"/healthz"),
health.HTTPProbe(readinessClient, strings.TrimRight(envOr("COGNITIVE_RUNTIME_URL", "http://cognitive-worker:8083"), "/")+"/healthz"),
// A running worker is not necessarily ready to serve cognitive traffic.
// Keep deterministic paths alive, but do not advertise overall readiness
// while the cognitive dependency is still warming.
health.HTTPProbe(readinessClient, strings.TrimRight(envOr("COGNITIVE_RUNTIME_URL", "http://cognitive-worker:8083"), "/")+"/readyz"),
}})
admissionPolicy := capability.AdmissionPolicy{ID: envOr("COGNITIVE_ADMISSION_POLICY_ID", "creator-advisory-local-v1"), MaxConcurrent: envInt("COGNITIVE_ADMISSION_MAX_CONCURRENT", 1), MaxAcceptedPerHour: envInt("COGNITIVE_ADMISSION_MAX_ACCEPTED_PER_HOUR", 60), MaxInputBytes: envInt("COGNITIVE_ADMISSION_MAX_INPUT_BYTES", 80<<10), MaxOutputBytes: envInt("COGNITIVE_ADMISSION_MAX_OUTPUT_BYTES", 16<<10)}
mux.HandleFunc("POST /v1/internal/cognitive/admission", func(w http.ResponseWriter, r *http.Request) {
@@ -806,6 +809,12 @@ func main() {
ReceivedAtUnixMillis: utterance.ReceivedAtUnixMillis,
}
helpPath := workdomain.DetermineHelpPath(planningInput)
// Introspection requests are read-only household UX. A cognitive
// candidate must not reinterpret them as an executable delegation.
switch semantic.InformationRequestKind {
case interaction.InformationRequestCapabilityInventory, interaction.InformationRequestLocalCapabilityInventory, interaction.InformationRequestCognitiveModelInventory, interaction.InformationRequestCognitiveCurrentModel, interaction.InformationRequestCognitiveChannelStatus, interaction.InformationRequestCognitiveRecovery, interaction.InformationRequestMemoryInventory:
helpPath = work.HelpPath{}
}
if responseErr == nil && responseResult.Handled {
helpPath = work.HelpPath{}
}
+13 -2
View File
@@ -258,10 +258,17 @@ services:
LOCAL_IMAGE_MODEL: ${LOCAL_IMAGE_MODEL:-z_image_turbo_bf16.safetensors}
COGNITIVE_OWNER_PRINCIPAL_ID: domovoy-creator-principal
COGNITIVE_ALLOW_CANARY: "true"
depends_on: [core-runtime, cognitive-lifeboat]
volumes:
- assistant_core_secrets:/run/secrets:ro
networks: [default, llm-local]
depends_on:
core-runtime: { condition: service_started }
cognitive-lifeboat: { condition: service_healthy }
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8083/healthz >/dev/null && wget -qO- http://localhost:8083/readyz >/dev/null"]
interval: 10s
timeout: 5s
retries: 20
cognitive-lifeboat:
image: ghcr.io/ggml-org/llama.cpp:server
@@ -328,7 +335,11 @@ services:
COGNITIVE_RUNTIME_URL: http://cognitive-worker:8083
AGENT_WORKER_URL: http://agent-worker:8090
ASSISTANT_BUILD_REVISION: ${ASSISTANT_SOURCE_REVISION:-unknown}
depends_on: [core-runtime, continuity-runtime, commit-runtime, cognitive-worker]
depends_on:
core-runtime: { condition: service_started }
continuity-runtime: { condition: service_started }
commit-runtime: { condition: service_started }
cognitive-worker: { condition: service_healthy }
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8084/healthz >/dev/null"]
interval: 10s
+11 -1
View File
@@ -616,6 +616,9 @@ func sourceDependentQuestion(primary, secondary interaction.SpeechAct, tokens []
if !inquiry {
return false
}
if focusIntrospectionQuestion(tokens) {
return false
}
currentCue := containsStemInTokens(tokens, "сейчас", "сегодня", "текущ", "актуаль", "последн", "прямо")
observedStateCue := containsStemInTokens(tokens, "погод", "температур", "осад", "ветер", "курс", "цен", "стоим", "новост", "распис", "событ", "статус", "доступен", "работает", "запущен", "срок") || approximateToken(tokens, "погод", 2)
placeSearchCue := containsStemInTokens(tokens, "ресторан", "кафе", "отел", "магаз", "мест", "ближ", "адрес", "организац", "бренд", "товар", "артикул", "продавец", "маркетплейс", "wildberries", "wb")
@@ -710,7 +713,7 @@ func informationRequestKind(message string, candidate interaction.SemanticCandid
if cognitiveSubject && inventoryRequest && inventoryCue {
return interaction.InformationRequestCognitiveModelInventory
}
capabilitySubject := containsStemInTokens(tokens, "уме", "возможност", "способн", "capabilit") || (containsMeaningfulInterrogative(tokens) && containsToken(tokens, "можешь"))
capabilitySubject := containsStemInTokens(tokens, "уме", "возможност", "способн", "доступн", "инструмент", "capabilit") || (containsMeaningfulInterrogative(tokens) && containsToken(tokens, "можешь"))
if inquiry && capabilitySubject {
if containsStemInTokens(tokens, "без", "внешн", "локальн") && containsStemInTokens(tokens, "модел", "ии", "ai") {
return interaction.InformationRequestLocalCapabilityInventory
@@ -727,6 +730,13 @@ func informationRequestKind(message string, candidate interaction.SemanticCandid
return ""
}
func focusIntrospectionQuestion(tokens []string) bool {
if containsStemInTokens(tokens, "фокус", "focus", "контекст") && (containsStemInTokens(tokens, "сейчас", "текущ", "работ", "контекст") || containsMeaningfulInterrogative(tokens)) {
return true
}
return containsStemInTokens(tokens, "над", "делаем", "работаем") && containsStemInTokens(tokens, "сейчас", "текущ", "мы")
}
func LocationContextReply(message string) string {
if location := personalCurrentLocation(message); location != "" {
return "Запомнил: сейчас вы в " + location + "."
+1
View File
@@ -142,6 +142,7 @@ func TestInformationRequestsAreClassifiedOnceByInteraction(t *testing.T) {
{"почему ты не смог найти ответ?", interaction.InformationRequestResearchFailureExplanation},
{"что ты можешь сделать без внешних моделей?", interaction.InformationRequestLocalCapabilityInventory},
{"что ты умеешь?", interaction.InformationRequestCapabilityInventory},
{"что доступно в этом чате?", interaction.InformationRequestCapabilityInventory},
{"проверь состояние локального канала", interaction.InformationRequestCognitiveChannelStatus},
{"нет связи с ИИ, восстанови канал", interaction.InformationRequestCognitiveRecovery},
{"сообщии список моделей", interaction.InformationRequestCognitiveModelInventory},
+32 -3
View File
@@ -18,6 +18,7 @@ type PersonalMemory struct {
type PersonalMemoryFact struct {
Kind string
Subject string
Value string
ConfidenceMillis int64
SourceUtteranceID interaction.HumanUtteranceID
@@ -54,6 +55,7 @@ func CompilePersonalMemory(history []interaction.HumanUtterance) PersonalMemory
if preference := personalPreference(utterance.Content); preference != "" {
preferences = append(preferences, PersonalMemoryFact{
Kind: "PREFERENCE",
Subject: preferenceSubject(preference),
Value: preference,
ConfidenceMillis: 900,
SourceUtteranceID: utterance.ID,
@@ -75,6 +77,21 @@ func CompilePersonalMemory(history []interaction.HumanUtterance) PersonalMemory
return result
}
// LatestPreference returns the current value for a semantic subject while
// retaining older facts for historical evidence.
func (m PersonalMemory) LatestPreference(subject string) (PersonalMemoryFact, bool) {
var latest PersonalMemoryFact
for _, fact := range m.Facts {
if fact.Kind != "PREFERENCE" || fact.Subject != subject {
continue
}
if latest.Kind == "" || fact.ObservedAtUnixMillis >= latest.ObservedAtUnixMillis {
latest = fact
}
}
return latest, latest.Kind != ""
}
func (m PersonalMemory) CurrentLocation() string {
for _, fact := range m.Facts {
if fact.Kind == personalMemoryCurrentLocation {
@@ -112,11 +129,16 @@ func RecallPersonalPreference(history []interaction.HumanUtterance, question str
if !strings.Contains(lowerQuestion, "цвет") || (!strings.Contains(lowerQuestion, "какой") && !strings.Contains(lowerQuestion, "назвал")) {
return ""
}
for _, fact := range CompilePersonalMemory(history).Facts {
if fact.Kind != "PREFERENCE" || !strings.Contains(strings.ToLower(fact.Value), "цвет") {
memory := CompilePersonalMemory(history)
for _, fact := range memory.Facts {
if fact.Kind != "PREFERENCE" || fact.Subject != "тестовый цвет" {
continue
}
value := strings.TrimSpace(fact.Value)
current, ok := memory.LatestPreference(fact.Subject)
if !ok || current.SourceUtteranceID != fact.SourceUtteranceID {
continue
}
value := strings.TrimSpace(current.Value)
if separator := strings.Index(value, "—"); separator >= 0 {
value = strings.TrimSpace(value[separator+len("—"):])
}
@@ -127,6 +149,13 @@ func RecallPersonalPreference(history []interaction.HumanUtterance, question str
return ""
}
func preferenceSubject(preference string) string {
if separator := strings.Index(preference, "—"); separator >= 0 {
return strings.TrimSpace(preference[:separator])
}
return strings.TrimSpace(preference)
}
func personalCurrentLocation(message string) string {
tokens := semanticTokens(message)
if len(tokens) < 4 || tokens[0] != "я" || !containsStemInTokens(tokens, "сейчас", "нахож", "жив") {
@@ -48,3 +48,17 @@ func TestRecallPersonalPreferenceUsesProjectedAssertion(t *testing.T) {
t.Fatalf("answer=%q", answer)
}
}
func TestCompilePersonalMemoryRanksCurrentSubjectWithoutDroppingHistory(t *testing.T) {
memory := CompilePersonalMemory([]interaction.HumanUtterance{
{ID: "old", Content: "запомни: мой тестовый цвет — фиолетовый", ReceivedAtUnixMillis: 100},
{ID: "new", Content: "запомни: мой тестовый цвет — acceptance-m5-синий-914", ReceivedAtUnixMillis: 200},
})
current, ok := memory.LatestPreference("тестовый цвет")
if !ok || current.Value != "тестовый цвет — acceptance-m5-синий-914" {
t.Fatalf("current=%+v ok=%t", current, ok)
}
if len(memory.Facts) != 2 {
t.Fatalf("historical evidence was dropped: %+v", memory.Facts)
}
}
+9 -5
View File
@@ -86,9 +86,12 @@ func InterpretUtterance(utterance interaction.HumanUtterance, projects []situati
result.Relations = append(result.Relations, relations...)
}
result.Reply = semanticReply(utterance.Content, result, previousFocus)
if isCurrentFocusQuestion(utterance.Content, selectedCandidate.PrimarySpeechAct) && previousFocus != nil {
if isCurrentFocusQuestion(utterance.Content, selectedCandidate.PrimarySpeechAct) {
result.NeedsCognition = false
result.Interpretation.NeedsCognition = false
result.CapabilityHints = nil
selectedCandidate.CapabilityHints = nil
result.Candidates[0] = selectedCandidate
}
return result, nil
}
@@ -343,8 +346,10 @@ func semanticReply(message string, result SemanticResult, previousFocus *situati
case interaction.SpeechActRejection:
return "Понял."
case interaction.SpeechActQuestion:
lower := strings.ToLower(message)
if previousFocus != nil && (strings.Contains(lower, "сейчас") || strings.Contains(lower, "что мы") || strings.Contains(lower, "делаем")) {
if focusIntrospectionQuestion(semanticTokens(message)) {
if previousFocus == nil {
return "Сейчас активный Focus не выбран."
}
return "Сейчас в фокусе: " + previousFocus.ProjectDisplayName + "."
}
if result.Interpretation.Applicability == interaction.SemanticNeedsBroaderInterpret || result.Interpretation.Applicability == interaction.SemanticLowConfidence {
@@ -385,8 +390,7 @@ func isCurrentFocusQuestion(message string, act interaction.SpeechAct) bool {
if act != interaction.SpeechActQuestion {
return false
}
lower := strings.ToLower(message)
return strings.Contains(lower, "сейчас") || strings.Contains(lower, "что мы") || strings.Contains(lower, "делаем")
return focusIntrospectionQuestion(semanticTokens(message))
}
func hasCorrectionMeaning(candidate interaction.SemanticCandidate, utterance interaction.HumanUtterance) bool {
@@ -293,6 +293,13 @@ func TestInterpretUtteranceQuestionAboutCurrentWorkUsesFocus(t *testing.T) {
}
}
func TestInterpretUtteranceEnglishFocusIntrospectionStaysLocal(t *testing.T) {
result := interpretForTest(t, "Какой сейчас Focus разговора?", activeFocus("assistant", "Assistant"), "")
if result.Reply != "Сейчас в фокусе: Assistant." || result.NeedsCognition || len(result.CapabilityHints) != 0 {
t.Fatalf("focus introspection escaped local route: %+v", result)
}
}
func TestInterpretUtteranceInheritedFocusForThere(t *testing.T) {
result := interpretForTest(t, "Добавь туда новую настройку.", activeFocus("assistant", "Assistant"), "")
if len(result.Projects) != 1 || result.Projects[0].ProjectID != "assistant" || result.Projects[0].Provenance != situation.ProjectResolutionInheritedFocus {