Project the command types through the intent gate surface #76
@@ -26,9 +26,25 @@ type MatchResult struct {
|
||||
Missing []SlotQuestion
|
||||
// Commands 是库层展开的命令列表(I1);Router 消费它做唯一裁决。
|
||||
// guard_hit/expectation_hit 被折叠为 fallback 时为空。
|
||||
Commands []agentintent.Command
|
||||
Commands []Command
|
||||
}
|
||||
|
||||
// 命令类型经闸门投影(别名):生态库按边界规则只许本包导入,
|
||||
// Router/runmgr 等消费方只依赖本包表面。
|
||||
type (
|
||||
Command = agentintent.Command
|
||||
ActionRef = agentintent.ActionRef
|
||||
)
|
||||
|
||||
const (
|
||||
CommandStart = agentintent.CommandStart
|
||||
ActionAuto = agentintent.ActionAuto
|
||||
ActionCommand = agentintent.ActionCommand
|
||||
ActionWorkflow = agentintent.ActionWorkflow
|
||||
ActionBlueprint = agentintent.ActionBlueprint
|
||||
ActionHandler = agentintent.ActionHandler
|
||||
)
|
||||
|
||||
type Gate struct {
|
||||
mu sync.RWMutex
|
||||
reg *agentintent.Registry
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
agentintent "agent-intent/intent"
|
||||
|
||||
"agent-system-backend/internal/intentgate"
|
||||
core "agent-system-core"
|
||||
)
|
||||
@@ -64,14 +62,14 @@ func Decide(res intentgate.MatchResult, env Env) Decision {
|
||||
if res.Branch != "matched" {
|
||||
return d
|
||||
}
|
||||
var start *agentintent.Command
|
||||
var start *intentgate.Command
|
||||
for i := range res.Commands {
|
||||
if res.Commands[i].Kind == agentintent.CommandStart {
|
||||
if res.Commands[i].Kind == intentgate.CommandStart {
|
||||
start = &res.Commands[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
action := agentintent.ActionRef{Kind: agentintent.ActionAuto, ID: res.ID}
|
||||
action := intentgate.ActionRef{Kind: intentgate.ActionAuto, ID: res.ID}
|
||||
if start != nil {
|
||||
d.StartFound = true
|
||||
action = start.Action
|
||||
@@ -80,13 +78,13 @@ func Decide(res intentgate.MatchResult, env Env) Decision {
|
||||
}
|
||||
}
|
||||
switch action.Kind {
|
||||
case agentintent.ActionCommand:
|
||||
case intentgate.ActionCommand:
|
||||
if env.HasCommand != nil && env.HasCommand(action.ID) {
|
||||
d.Kind, d.CommandID = KindCommand, action.ID
|
||||
return d
|
||||
}
|
||||
d.Reason = "声明的命令不存在:" + action.ID
|
||||
case agentintent.ActionWorkflow:
|
||||
case intentgate.ActionWorkflow:
|
||||
if env.WorkflowFor != nil {
|
||||
if def, ok := env.WorkflowFor(action.ID); ok {
|
||||
d.Kind, d.Workflow = KindWorkflow, def
|
||||
@@ -94,7 +92,7 @@ func Decide(res intentgate.MatchResult, env Env) Decision {
|
||||
}
|
||||
}
|
||||
d.Reason = "声明的工作流未注册:" + action.ID
|
||||
case agentintent.ActionBlueprint:
|
||||
case intentgate.ActionBlueprint:
|
||||
if env.SquadReady {
|
||||
d.Kind, d.Blueprint = KindSquad, action.ID
|
||||
return d
|
||||
|
||||
@@ -3,19 +3,17 @@ package route
|
||||
import (
|
||||
"testing"
|
||||
|
||||
agentintent "agent-intent/intent"
|
||||
|
||||
"agent-system-backend/internal/intentgate"
|
||||
"agent-system-backend/internal/intentgate"
|
||||
core "agent-system-core"
|
||||
)
|
||||
|
||||
func startCmd(action agentintent.ActionRef) agentintent.Command {
|
||||
return agentintent.Command{Kind: agentintent.CommandStart, Action: action}
|
||||
func startCmd(action intentgate.ActionRef) intentgate.Command {
|
||||
return intentgate.Command{Kind: intentgate.CommandStart, Action: action}
|
||||
}
|
||||
|
||||
func TestDecideAutoPrefersCommandThenWorkflow(t *testing.T) {
|
||||
in := intentgate.MatchResult{Branch: "matched", ID: "demo.x",
|
||||
Commands: []agentintent.Command{startCmd(agentintent.ActionRef{Kind: agentintent.ActionAuto, ID: "demo.x"})}}
|
||||
Commands: []intentgate.Command{startCmd(intentgate.ActionRef{Kind: intentgate.ActionAuto, ID: "demo.x"})}}
|
||||
d := Decide(in, Env{HasCommand: func(string) bool { return true }})
|
||||
if d.Kind != KindCommand || d.CommandID != "demo.x" {
|
||||
t.Fatalf("auto command = %+v", d)
|
||||
@@ -36,26 +34,26 @@ func TestDecideAutoPrefersCommandThenWorkflow(t *testing.T) {
|
||||
func TestDecideExplicitKinds(t *testing.T) {
|
||||
mk := func(kind, id string) intentgate.MatchResult {
|
||||
return intentgate.MatchResult{Branch: "matched", ID: "demo.x",
|
||||
Commands: []agentintent.Command{startCmd(agentintent.ActionRef{Kind: kind, ID: id})}}
|
||||
Commands: []intentgate.Command{startCmd(intentgate.ActionRef{Kind: kind, ID: id})}}
|
||||
}
|
||||
if d := Decide(mk(agentintent.ActionCommand, "cmd-1"), Env{HasCommand: func(id string) bool { return id == "cmd-1" }}); d.Kind != KindCommand || d.CommandID != "cmd-1" {
|
||||
if d := Decide(mk(intentgate.ActionCommand, "cmd-1"), Env{HasCommand: func(id string) bool { return id == "cmd-1" }}); d.Kind != KindCommand || d.CommandID != "cmd-1" {
|
||||
t.Fatalf("explicit command = %+v", d)
|
||||
}
|
||||
d := Decide(mk(agentintent.ActionCommand, "nope"), Env{
|
||||
d := Decide(mk(intentgate.ActionCommand, "nope"), Env{
|
||||
WorkflowFor: func(string) (core.WorkflowDef, bool) { return core.WorkflowDef{ID: "wf"}, true },
|
||||
})
|
||||
if d.Kind != KindTurn || d.Reason == "" {
|
||||
t.Fatalf("unresolvable command = %+v", d)
|
||||
}
|
||||
if d := Decide(mk(agentintent.ActionWorkflow, "wf-1"), Env{
|
||||
if d := Decide(mk(intentgate.ActionWorkflow, "wf-1"), Env{
|
||||
WorkflowFor: func(id string) (core.WorkflowDef, bool) { return core.WorkflowDef{ID: id}, true },
|
||||
}); d.Kind != KindWorkflow || d.Workflow.ID != "wf-1" {
|
||||
t.Fatalf("explicit workflow = %+v", d)
|
||||
}
|
||||
if d := Decide(mk(agentintent.ActionBlueprint, "bp-1"), Env{SquadReady: true}); d.Kind != KindSquad || d.Blueprint != "bp-1" {
|
||||
if d := Decide(mk(intentgate.ActionBlueprint, "bp-1"), Env{SquadReady: true}); d.Kind != KindSquad || d.Blueprint != "bp-1" {
|
||||
t.Fatalf("blueprint = %+v", d)
|
||||
}
|
||||
if d := Decide(mk(agentintent.ActionBlueprint, "bp-1"), Env{}); d.Kind != KindTurn || d.Reason == "" {
|
||||
if d := Decide(mk(intentgate.ActionBlueprint, "bp-1"), Env{}); d.Kind != KindTurn || d.Reason == "" {
|
||||
t.Fatalf("blueprint without squad = %+v", d)
|
||||
}
|
||||
}
|
||||
@@ -73,9 +71,9 @@ func TestDecideNonMatchedAndLegacyFallback(t *testing.T) {
|
||||
|
||||
func TestSlotsFromStartCommand(t *testing.T) {
|
||||
in := intentgate.MatchResult{Branch: "matched", ID: "demo.x",
|
||||
Commands: []agentintent.Command{{
|
||||
Kind: agentintent.CommandStart,
|
||||
Action: agentintent.ActionRef{Kind: agentintent.ActionAuto, ID: "demo.x"},
|
||||
Commands: []intentgate.Command{{
|
||||
Kind: intentgate.CommandStart,
|
||||
Action: intentgate.ActionRef{Kind: intentgate.ActionAuto, ID: "demo.x"},
|
||||
Slots: map[string]string{"topic": "电机"},
|
||||
}}}
|
||||
d := Decide(in, Env{HasCommand: func(string) bool { return true }})
|
||||
|
||||
Reference in New Issue
Block a user