Files
Agent-Squad/squad/topology.go
T
weichen f3a67ced9c
ci / vet-and-test (pull_request) Successful in 24s
ci / docker-checkout-hostgateway (pull_request) Successful in 1s
Add the topology surface with loop, router, and deadline mechanics (Q2 WP1)
Why: the completion doc Q2 requires twelve builtin topologies each with
a scripted-backend conformance; today the engine has only the
standard/leader mode string with no topology abstraction, no loop
re-arm (cycles are fail-closed by design), no in-graph routing, and no
run deadline.
Evidence: GOWORK=off go vet + go test -count=1 green across squad and
all three adapter modules; ten conformance/validation tests:
sequential, parallel, loop-until-field (exact iteration count +
persisted LoopRuns), loop-budget-exhausted (loop_exhausted event, run
still completes), router-selects-branch (loser skipped, run NOT
degraded), router-no-match fail-closed, evaluator-optimizer (draft
re-armed via loop body until verdict=pass), long-running deadline
(pending steps skipped, degraded closeout), unknown/primitive/
unregistered-driver fail-closed, builtin registry completeness (12).
Impact: additive — Topology/Deadline on RunOptions, Topology on
Blueprint, Loop/LoopRuns/Branches/Handoff on StepSpec; empty topology
keeps byte-identical standard behavior; MaxIterations is the total
iteration cap (first run included); router-skipped steps are exempt
from degraded derivation; runParallel now preserves the first specific
RunFailed error instead of re-wrapping via failStep; deadline metadata
uses RFC3339Nano (second-precision RFC3339 truncated sub-second
deadlines into instant expiry).
Refs: Agent-System-Documents#44 (Q2 plan WP1)
2026-10-08 00:03:24 +00:00

131 lines
4.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package squad
import "fmt"
// topology.go — 拓扑一等化(Q2):内置拓扑名注册表。
// 拓扑不新造执行面:graph 类编译为 Steps 图(Q1 机制),leader 走既有
// Mode 委派循环,driver 类由引擎按名分发(review/group_chat/task_board),
// primitive 类是跨拓扑原语(handoff/mailbox),不可单独作为运行拓扑。
// 未知名与不可运行Kind一律 fail-closed。
// 内置拓扑名(completion doc Q2 清单的 12 种)。
const (
TopologySequential = "sequential"
TopologyParallel = "parallel"
TopologyLoop = "loop"
TopologyRouter = "router"
TopologyLeader = "leader"
TopologyHandoff = "handoff"
TopologyGroupChat = "group_chat"
TopologyReview = "review"
TopologyEvaluatorOptimizer = "evaluator_optimizer"
TopologyLongRunning = "long_running"
TopologyTaskBoard = "task_board"
TopologyMailbox = "mailbox"
)
// TopologyKind 是拓扑的执行形态。
type TopologyKind string
const (
// TopologyGraph 编译为 Steps 图,由 flowDriver.advance 执行。
TopologyGraph TopologyKind = "graph"
// TopologyMode 走既有 Mode 分支(leader 委派循环)。
TopologyMode TopologyKind = "mode"
// TopologyDriver 由引擎按名分发到专用驱动。
TopologyDriver TopologyKind = "driver"
// TopologyPrimitive 是跨拓扑原语,不可单独运行。
TopologyPrimitive TopologyKind = "primitive"
)
// TopologySpec 是一个内置拓扑的注册项。
type TopologySpec struct {
Name string
Kind TopologyKind
}
// builtinTopologies 是 12 种内置拓扑的注册表(唯一权威清单)。
var builtinTopologies = []TopologySpec{
{Name: TopologySequential, Kind: TopologyGraph},
{Name: TopologyParallel, Kind: TopologyGraph},
{Name: TopologyLoop, Kind: TopologyGraph},
{Name: TopologyRouter, Kind: TopologyGraph},
{Name: TopologyLeader, Kind: TopologyMode},
{Name: TopologyHandoff, Kind: TopologyPrimitive},
{Name: TopologyGroupChat, Kind: TopologyDriver},
{Name: TopologyReview, Kind: TopologyDriver},
{Name: TopologyEvaluatorOptimizer, Kind: TopologyGraph},
{Name: TopologyLongRunning, Kind: TopologyGraph},
{Name: TopologyTaskBoard, Kind: TopologyDriver},
{Name: TopologyMailbox, Kind: TopologyPrimitive},
}
// BuiltinTopologies 返回内置拓扑清单(只读副本)。
func BuiltinTopologies() []TopologySpec {
out := make([]TopologySpec, len(builtinTopologies))
copy(out, builtinTopologies)
return out
}
// LookupTopology 按名查注册项。
func LookupTopology(name string) (TopologySpec, bool) {
for _, t := range builtinTopologies {
if t.Name == name {
return t, true
}
}
return TopologySpec{}, false
}
// registeredDrivers 是已接线的 driver 拓扑(WP 增量逐个点亮;未点亮 = fail-closed)。
var registeredDrivers = map[string]bool{}
// RegisterTopologyDriver 由驱动实现方在 init/装配时点亮一个 driver 拓扑。
func RegisterTopologyDriver(name string) error {
spec, ok := LookupTopology(name)
if !ok {
return fmt.Errorf("topology: 未注册的拓扑名 %q", name)
}
if spec.Kind != TopologyDriver {
return fmt.Errorf("topology: %q 不是 driver 类(kind=%s)", name, spec.Kind)
}
registeredDrivers[name] = true
return nil
}
// checkTopology 校验一次运行的有效拓扑名,返回其 Kind。
// 空名 = 未声明(standard 图行为,兼容既有调用方)。
// 未注册名 / primitive 单跑 / driver 未点亮都 fail-closed。
func checkTopology(name string) (TopologyKind, error) {
if name == "" {
return TopologyGraph, nil
}
spec, ok := LookupTopology(name)
if !ok {
return "", fmt.Errorf("topology: 未知拓扑 %q(内置清单:%s)", name, topologyNames())
}
switch spec.Kind {
case TopologyGraph, TopologyMode:
return spec.Kind, nil
case TopologyPrimitive:
return "", fmt.Errorf("topology: %q 是跨拓扑原语,不可单独作为运行拓扑", name)
case TopologyDriver:
if !registeredDrivers[name] {
return "", fmt.Errorf("topology: %q 驱动未注册(fail-closed)", name)
}
return spec.Kind, nil
}
return "", fmt.Errorf("topology: %q kind 非法", name)
}
func topologyNames() string {
s := ""
for i, t := range builtinTopologies {
if i > 0 {
s += ", "
}
s += t.Name
}
return s
}