mavend: centralize action validation boundary (slice 4)
This commit is contained in:
@@ -107,7 +107,7 @@ var praxisCapabilities = []praxisCapability{
|
||||
// handlePraxisAct — dispatches ecosystem tool acts through the Praxis tools API.
|
||||
// Returns "" when the act is not a Praxis verb (the caller falls through to the
|
||||
// system command executor). Returns a reply string otherwise.
|
||||
func (h *reactiveHandler) handlePraxisAct(ctx context.Context, dec router.Decision) string {
|
||||
func (h *reactiveHandler) handlePraxisAct(ctx context.Context, dec router.Decision, candidate router.ActionCandidate) string {
|
||||
if h.ecosystem == nil || h.ecosystem.praxis == nil {
|
||||
return ""
|
||||
}
|
||||
@@ -127,7 +127,7 @@ func (h *reactiveHandler) handlePraxisAct(ctx context.Context, dec router.Decisi
|
||||
}
|
||||
for _, capability := range praxisCapabilities {
|
||||
for _, alias := range capability.aliases() {
|
||||
if alias == dec.Slots.Fn {
|
||||
if alias == candidate.Fn {
|
||||
return capability.handle(ctx, h, px, dec)
|
||||
}
|
||||
}
|
||||
@@ -657,7 +657,7 @@ func (h *reactiveHandler) resolveEntityCandidates(ctx context.Context, refs []st
|
||||
// handleHexisAct — resolves entity references through Nexus and executes
|
||||
// matching capabilities through Hexis. Returns a reply string when handled,
|
||||
// or "" to fall through to the system command executor.
|
||||
func (h *reactiveHandler) handleHexisAct(ctx context.Context, dec router.Decision) string {
|
||||
func (h *reactiveHandler) handleHexisAct(ctx context.Context, dec router.Decision, candidate router.ActionCandidate) string {
|
||||
// This method is intentionally callable outside runTurn by ecosystem
|
||||
// harnesses. Refuse before correlation ids, Nexus resolution or capability
|
||||
// discovery so the no-op sentinel can never leak into Hexis as a verb.
|
||||
@@ -721,7 +721,7 @@ func (h *reactiveHandler) handleHexisAct(ctx context.Context, dec router.Decisio
|
||||
// Match the user's verb to a capability by name/description. Collect all
|
||||
// matches: more than one is itself ambiguous, so we ask rather than pick
|
||||
// the first (ecosystem invariant: no arbitrary target for mutation).
|
||||
verb := dec.Slots.Fn
|
||||
verb := candidate.Fn
|
||||
if verb == "" {
|
||||
verb = dec.Slots.Text
|
||||
}
|
||||
@@ -732,7 +732,7 @@ func (h *reactiveHandler) handleHexisAct(ctx context.Context, dec router.Decisio
|
||||
// round then: the phrase is the haystack and the capability name is what we
|
||||
// look for in it (Vikunja #476). Only when the fn slot is empty — a matched
|
||||
// fn is a single verb and containment already means what it says.
|
||||
loose := !dec.Slots.HasFn
|
||||
loose := !candidate.ActionResolved()
|
||||
var matches []*hexisclient.Capability
|
||||
for i, c := range caps {
|
||||
name := strings.ToLower(c.Name)
|
||||
@@ -858,7 +858,16 @@ func (h *reactiveHandler) hexisBeforeClarify(ctx context.Context, dec router.Dec
|
||||
if dec.Intent != router.IntentAct || dec.Slots.HasFn || !router.ActHasEntityTarget(dec) {
|
||||
return ""
|
||||
}
|
||||
return h.handleHexisAct(ctx, dec)
|
||||
// Resolve the action candidate. Use the matcher when available; when the
|
||||
// handler has no matcher (ecosystem-only test harnesses), build an
|
||||
// unresolved candidate directly — the matcher would not have matched either.
|
||||
var candidate router.ActionCandidate
|
||||
if h.matcher != nil {
|
||||
candidate = h.resolveAction(ctx, dec)
|
||||
} else {
|
||||
candidate = router.ResolveActionCandidate(dec, nil)
|
||||
}
|
||||
return h.handleHexisAct(ctx, dec, candidate)
|
||||
}
|
||||
|
||||
// attentionCannotTell returns the hedge to say instead of an all-clear, or ""
|
||||
|
||||
Reference in New Issue
Block a user