From 1d02ba8936b57dd5216a46913e0f6bb9ca28c305 Mon Sep 17 00:00:00 2001 From: claude Date: Sun, 6 Sep 2026 13:49:50 +0400 Subject: [PATCH] router: add ActionResolutionMethod type and ResolvedBy field to Slots Five disjoint values tracking which component selected the exact function: grammar_fixed, grammar_matcher, extractor_raw, extractor_llm_text, fallback_matcher. Slots.ResolvedBy carries provenance at the selection point. --- internal/dialogue/session.go | 4 ++++ internal/router/intent.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/internal/dialogue/session.go b/internal/dialogue/session.go index 5bd1a57..2e38f84 100644 --- a/internal/dialogue/session.go +++ b/internal/dialogue/session.go @@ -31,6 +31,10 @@ type Slots struct { Fn string Args []string HasFn bool + // ResolvedBy — which component selected the exact function. Mirrors + // router.Slots.ResolvedBy. Carried as a string because dialogue cannot + // import router (import cycle). + ResolvedBy string } // Turn represents one utterance in a multi-turn dialogue history. diff --git a/internal/router/intent.go b/internal/router/intent.go index a538fe2..dde57c0 100644 --- a/internal/router/intent.go +++ b/internal/router/intent.go @@ -74,6 +74,34 @@ const ( IntentSystem Intent = "system" ) +// ActionResolutionMethod — which component actually selected the exact +// function. Recorded for observability so a trace can name the selection +// mechanism without re-deriving it from the route producer and surrounding +// claims. Five disjoint values; empty means no function was resolved. +type ActionResolutionMethod string + +const ( + // ActionResolutionGrammarFixed — a stage-0 grammar hardcodes a fixed + // canonical fn (praxis lifecycle, task-status). No matcher involved. + ActionResolutionGrammarFixed ActionResolutionMethod = "grammar_fixed" + + // ActionResolutionGrammarMatcher — a stage-0 grammar invokes the + // ActMatcher to select fn (wakeword-act fast path). + ActionResolutionGrammarMatcher ActionResolutionMethod = "grammar_matcher" + + // ActionResolutionExtractorRaw — post-route Extractor.Acts.Match over + // the original/raw routed utterance. + ActionResolutionExtractorRaw ActionResolutionMethod = "extractor_raw" + + // ActionResolutionExtractorLLMText — the LLM produced cleaned + // Slots.Text, then Extractor.Acts.Match selected fn from it. + ActionResolutionExtractorLLMText ActionResolutionMethod = "extractor_llm_text" + + // ActionResolutionFallbackMatcher — ResolveActionCandidate ran the + // fallback matcher because routing/extraction left HasFn=false. + ActionResolutionFallbackMatcher ActionResolutionMethod = "fallback_matcher" +) + // Slots — per-intent extracted arguments (stage 2). Not every field is set for // every intent; the Intent decides which matter. A slot that doesn't parse // leaves its Has* flag false — the daemon's SLM last-resort lane picks it up @@ -93,6 +121,11 @@ type Slots struct { Args []string HasFn bool + // ResolvedBy — which component actually selected the exact function. + // Set when Fn is set; empty when HasFn is false. Travels with the slot + // so provenance is known at the selection point, not reconstructed later. + ResolvedBy ActionResolutionMethod + // Fact: structured (key,value) the loop will evaluate predicates against. // "drank water" → key=water; "slept 6h" → key=sleep, value=6h. The value // is the raw string the daemon json-encodes before WriteFact.