package main import ( "context" "strings" "github.com/kami/maven/internal/router" ) // attentionMarkers — the offline floor under the attention topic (topics.go). // The seeds decide when the embedder is there; this answers when it is not, and // it stays a substring list on purpose for the reason the other floors do: a // narrow test made blind beats a broad guess made blind. // // "что нового" is deliberately absent: the feeds source claims it, and it // still should — a question about news is a question about the feeds she // reads. This list is about the operational state of his things. var attentionMarkers = []string{ "внимани", "что требует", "что не так", "что важн", "что срочн", "needs attention", "what needs looking", } // isAttentionQuery reports whether the utterance asks what needs looking at. // Called through turnIsAbout, never directly. func isAttentionQuery(u string) bool { s := strings.ToLower(strings.TrimSpace(u)) if s == "" { return false } for _, m := range attentionMarkers { if strings.Contains(s, m) { return true } } return false } // queryAttention answers "что требует внимания?" from Praxis. // // The capability was already built and already degraded correctly, and no // utterance could reach it (Vikunja #475). Its aliases live on the act // dispatch, and the question routes to IntentQuery, so it fell through every // source to the web search and came back with an encyclopedia article about // the concept of attention — worse than silence, because it reads as an // answer. // // Placed above the recall sources and well above the personal boundary: this // is operational state about his things, and a notes pass would otherwise // answer it from whatever he once wrote about a server. An unconfigured or // absent Praxis falls through rather than claiming the turn, the same // convention queryHome and queryNetwork follow. A Praxis that is configured // and down does claim it, and says it cannot reach the service — that is the // degradation the ecosystem contract asks for, and it comes from the same // handler the act path uses. func (h *reactiveHandler) queryAttention(ctx context.Context, t *queryTurn) (string, bool) { if !h.turnIsAbout(ctx, t, topicAttend, isAttentionQuery) { return "", false } if h.ecosystem == nil || h.ecosystem.praxis == nil { return "", false } reply := h.handlePraxisAct(ctx, router.Decision{ Utterance: t.dec.Utterance, Intent: router.IntentAct, Slots: router.Slots{Fn: "list_attention", HasFn: true}, }) if reply == "" { return "", false } return reply, true }