router: set ResolvedBy at each function selection point
Assign provenance where the exact fn is produced: - grammar_fixed: praxis/task-status grammars hardcode fn - grammar_matcher: wakeword-act grammar invokes ActMatcher - extractor_raw: Extractor.Extract matches over raw utterance - extractor_llm_text: fillSlots LLM backfill matches cleaned text - fallback_matcher: ResolveActionCandidate runs the fallback matcher ResolveActionCandidate propagates Slots.ResolvedBy into ActionCandidate.ResolvedBy. No selection behavior changes.
This commit is contained in:
@@ -22,6 +22,11 @@ type ActionCandidate struct {
|
||||
// here. Carried for observability; not used for dispatch.
|
||||
Producer RouteProducer
|
||||
|
||||
// ResolvedBy — which component actually selected the exact function.
|
||||
// Carried from the routing decision's Slots.ResolvedBy. Five disjoint
|
||||
// values; empty when no function was resolved.
|
||||
ResolvedBy ActionResolutionMethod
|
||||
|
||||
// Confidence — the routing confidence from the decision. Carried for
|
||||
// observability; not used for dispatch.
|
||||
Confidence float64
|
||||
@@ -146,6 +151,7 @@ func ResolveActionCandidate(dec Decision, m ActMatcher) ActionCandidate {
|
||||
Args: dec.Slots.Args,
|
||||
Source: ActionSourceRoute,
|
||||
Producer: dec.Producer,
|
||||
ResolvedBy: dec.Slots.ResolvedBy,
|
||||
Confidence: dec.Confidence,
|
||||
}
|
||||
}
|
||||
@@ -158,6 +164,7 @@ func ResolveActionCandidate(dec Decision, m ActMatcher) ActionCandidate {
|
||||
Args: args,
|
||||
Source: ActionSourceMatcher,
|
||||
Producer: dec.Producer,
|
||||
ResolvedBy: ActionResolutionFallbackMatcher,
|
||||
Confidence: dec.Confidence,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ func PraxisGrammars() []Grammar {
|
||||
Stage: 0,
|
||||
Intent: IntentAct,
|
||||
Confidence: 1.0,
|
||||
Slots: Slots{Fn: c.Fn, HasFn: true, Value: c.Ref},
|
||||
Slots: Slots{Fn: c.Fn, HasFn: true, Value: c.Ref, ResolvedBy: ActionResolutionGrammarFixed},
|
||||
}, true
|
||||
},
|
||||
},
|
||||
@@ -226,7 +226,7 @@ func PraxisGrammars() []Grammar {
|
||||
Stage: 0,
|
||||
Intent: IntentAct,
|
||||
Confidence: 1.0,
|
||||
Slots: Slots{Fn: "list_attention", HasFn: true},
|
||||
Slots: Slots{Fn: "list_attention", HasFn: true, ResolvedBy: ActionResolutionGrammarFixed},
|
||||
}, true
|
||||
},
|
||||
},
|
||||
@@ -238,7 +238,7 @@ func PraxisGrammars() []Grammar {
|
||||
Stage: 0,
|
||||
Intent: IntentAct,
|
||||
Confidence: 1.0,
|
||||
Slots: Slots{Fn: "list_changes", HasFn: true},
|
||||
Slots: Slots{Fn: "list_changes", HasFn: true, ResolvedBy: ActionResolutionGrammarFixed},
|
||||
}, true
|
||||
},
|
||||
},
|
||||
@@ -261,7 +261,7 @@ func PraxisGrammars() []Grammar {
|
||||
// Text, not Value: entityAttentionCapability reads Value
|
||||
// first and that slot means an item id everywhere else in
|
||||
// the Praxis dispatch.
|
||||
Slots: Slots{Fn: "entity_attention", HasFn: true, Text: subject},
|
||||
Slots: Slots{Fn: "entity_attention", HasFn: true, Text: subject, ResolvedBy: ActionResolutionGrammarFixed},
|
||||
}, true
|
||||
},
|
||||
},
|
||||
@@ -284,7 +284,7 @@ func praxisServiceAttentionDecision(utterance string) (Decision, bool) {
|
||||
Stage: 0,
|
||||
Intent: IntentAct,
|
||||
Confidence: 1,
|
||||
Slots: Slots{Fn: "entity_attention", HasFn: true, Text: tokens[3]},
|
||||
Slots: Slots{Fn: "entity_attention", HasFn: true, Text: tokens[3], ResolvedBy: ActionResolutionGrammarFixed},
|
||||
}, true
|
||||
}
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ func (r *Router) fillMatchedSlots(ctx context.Context, d *Decision, now time.Tim
|
||||
d.Slots.Key, d.Slots.Value, d.Slots.HasKey = ex.Key, ex.Value, ex.HasKey
|
||||
}
|
||||
if !d.Slots.HasFn && ex.HasFn {
|
||||
d.Slots.Fn, d.Slots.Args, d.Slots.HasFn = ex.Fn, ex.Args, ex.HasFn
|
||||
d.Slots.Fn, d.Slots.Args, d.Slots.HasFn, d.Slots.ResolvedBy = ex.Fn, ex.Args, ex.HasFn, ex.ResolvedBy
|
||||
}
|
||||
return ex
|
||||
}
|
||||
@@ -320,6 +320,7 @@ func (r *Router) fillSlots(ctx context.Context, d *Decision, now time.Time) {
|
||||
d.Slots.Text != "" && d.Slots.Text != d.Utterance {
|
||||
if fn, args, ok := r.extractor.Acts.Match(d.Slots.Text); ok {
|
||||
d.Slots.Fn, d.Slots.Args, d.Slots.HasFn = fn, args, true
|
||||
d.Slots.ResolvedBy = ActionResolutionExtractorLLMText
|
||||
}
|
||||
}
|
||||
// The extractor's Text is the raw utterance, which is the payload for a
|
||||
|
||||
@@ -73,6 +73,7 @@ func (e Extractor) Extract(ctx context.Context, intent Intent, utterance string,
|
||||
s.Fn = fn
|
||||
s.Args = args
|
||||
s.HasFn = true
|
||||
s.ResolvedBy = ActionResolutionExtractorRaw
|
||||
}
|
||||
}
|
||||
case IntentFact:
|
||||
|
||||
@@ -99,7 +99,7 @@ func DefaultGrammars(actMatcher ActMatcher) []Grammar {
|
||||
Stage: 0,
|
||||
Intent: IntentAct,
|
||||
Confidence: 1.0,
|
||||
Slots: Slots{Fn: fn, Args: args, HasFn: true, Text: rest},
|
||||
Slots: Slots{Fn: fn, Args: args, HasFn: true, Text: rest, ResolvedBy: ActionResolutionGrammarMatcher},
|
||||
}, true
|
||||
},
|
||||
},
|
||||
|
||||
@@ -389,7 +389,7 @@ func TaskStatusGrammar() Grammar {
|
||||
// which is the pairing handlePraxisAct uses for an item and its
|
||||
// reference. Empty Text is a claim, not a refusal: the daemon
|
||||
// asks which task, having the list she does not.
|
||||
Slots: Slots{Fn: TaskStatusFn, HasFn: true, Value: c.Status, Text: c.Text},
|
||||
Slots: Slots{Fn: TaskStatusFn, HasFn: true, Value: c.Status, Text: c.Text, ResolvedBy: ActionResolutionGrammarFixed},
|
||||
}, true
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user