the unplaceable word rides a typed error, not the message (V-634)
Recovering it by cutting on quotes in err.Error() meant the reply depended on the wording of an error string. UnknownTargetError carries the word and errors.Is still holds.
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/kami/maven/internal/mcp"
|
||||
"github.com/kami/maven/internal/phraser"
|
||||
@@ -66,8 +65,12 @@ func (h *reactiveHandler) actionAct(ctx context.Context, dec router.Decision) st
|
||||
// nothing ran. Saying which word she could not place is the whole
|
||||
// answer: he either renames it or gives the row an alias that
|
||||
// carries the target, and both are one turn away (V-634).
|
||||
return phraser.A(phraser.ActUnknownTarget,
|
||||
map[string]string{"name": unknownTargetOf(err, dec.Slots.Args)})
|
||||
word := ""
|
||||
var unknown *tool.UnknownTargetError
|
||||
if errors.As(err, &unknown) {
|
||||
word = unknown.Target
|
||||
}
|
||||
return phraser.A(phraser.ActUnknownTarget, map[string]string{"name": word})
|
||||
case errors.Is(err, tool.ErrNeedsAuthedSurface):
|
||||
// Irreversible (internal/tool/risk.go). A confirm turn would not
|
||||
// help: everything that proposed this act — the STT, the router,
|
||||
@@ -102,17 +105,3 @@ func (h *reactiveHandler) actionAct(ctx context.Context, dec router.Decision) st
|
||||
return phraser.A(phraser.ActDone, nil)
|
||||
}
|
||||
|
||||
// unknownTargetOf pulls the word the executor could not place out of its error,
|
||||
// falling back to the first arg. The word is what makes the reply usable, and a
|
||||
// reply naming no word would send him to the log.
|
||||
func unknownTargetOf(err error, args []string) string {
|
||||
if _, rest, ok := strings.Cut(err.Error(), `"`); ok {
|
||||
if word, _, ok := strings.Cut(rest, `"`); ok && word != "" {
|
||||
return word
|
||||
}
|
||||
}
|
||||
if len(args) > 0 {
|
||||
return args[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
+16
-1
@@ -84,6 +84,17 @@ var (
|
||||
ErrUnknownTarget = errors.New("the act names a target the system cannot have")
|
||||
)
|
||||
|
||||
// UnknownTargetError carries the word the executor could not place, because the
|
||||
// reply names it: "«роутер» — не знаю такой цели" is actionable and "не
|
||||
// получилось" sends him to the log. errors.Is(err, ErrUnknownTarget) holds.
|
||||
type UnknownTargetError struct{ Target string }
|
||||
|
||||
func (e *UnknownTargetError) Error() string {
|
||||
return fmt.Sprintf("%s: %q", ErrUnknownTarget, e.Target)
|
||||
}
|
||||
|
||||
func (e *UnknownTargetError) Unwrap() error { return ErrUnknownTarget }
|
||||
|
||||
// MCPCaller is the seam for an act that is an MCP tool call rather than a
|
||||
// process (Vikunja #251). internal/mcp.Manager satisfies it via CallPositional.
|
||||
// nil ⇒ MCP is not configured, and an MCP row refuses to run rather than
|
||||
@@ -160,7 +171,7 @@ func (e *Executor) Exec(ctx context.Context, name string, args []string, confirm
|
||||
// since a task title is not a target, and a house row drops the spoken args.
|
||||
if !isMCPRow(t.Cmd) && !isHouseRow(t.Cmd) {
|
||||
if bad, ok := firstUnknownTarget(args); !ok {
|
||||
return "", fmt.Errorf("%w: %q", ErrUnknownTarget, bad)
|
||||
return "", &UnknownTargetError{Target: bad}
|
||||
}
|
||||
}
|
||||
// The tier decides, not the column (Vikunja #449). RiskOf reads the row and
|
||||
@@ -290,6 +301,10 @@ func (m *Matcher) Match(utterance string) (string, []string, bool) {
|
||||
// sentence. "перезагрузи роутер" is the case: restart is a real tool and
|
||||
// "роутер" is a real word, and `systemctl restart роутер` is neither.
|
||||
//
|
||||
// Every process row this box enables takes a system identifier (systemctl,
|
||||
// docker, journalctl, df). A process row that legitimately wanted Russian text
|
||||
// would want a different dispatch, not a hole in this check.
|
||||
//
|
||||
// It deliberately does not try to guess the right target. Identity is Nexus's
|
||||
// (CLAUDE.md § "The ecosystem"), and a target Nexus resolves reaches Hexis
|
||||
// through handleHexisAct before this executor is asked.
|
||||
|
||||
Reference in New Issue
Block a user