Wire the squad native adapter instead of the core registration

Why: Backend has to keep the same squad runs after the core stopped importing agent-native. The adapter module owns the concrete client.
Evidence: GOWORK=off go test -count=1 ./internal/... passed.
Impact: AgentNativeOptions now returns the adapter config. Default roles still use the agent-system backend.
Refs: D1
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-03 13:42:04 +00:00
co-authored by Cursor
parent 6d38f17302
commit b8e8cfb754
9 changed files with 26 additions and 25 deletions
+6 -3
View File
@@ -6,17 +6,19 @@ require (
agent-command v0.0.0
agent-intent v0.0.0
agent-native v0.0.0
agent-squad v0.0.0-00010101000000-000000000000
agent-squad v0.0.0
agent-squad/adapters/native v0.0.0
agent-system-core v0.0.0
error-code-system v0.0.0
github.com/jackc/pgx/v5 v5.9.2
github.com/ledongthuc/pdf v0.0.0-20260907135840-6c8c28e0e8a0
github.com/redis/go-redis/v9 v9.14.0
golang.org/x/crypto v0.56.0
logging-system v0.0.0
modernc.org/sqlite v1.60.1
)
require (
error-code-system v0.0.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
@@ -30,7 +32,6 @@ require (
golang.org/x/sync v0.23.0 // indirect
golang.org/x/sys v0.48.0 // indirect
golang.org/x/text v0.41.0 // indirect
logging-system v0.0.0 // indirect
modernc.org/libc v1.77.1 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.12.1 // indirect
@@ -40,6 +41,8 @@ replace agent-intent => ./deps/agent-intent
replace agent-squad => ./deps/agent-squad
replace agent-squad/adapters/native => ./deps/agent-squad/adapters/native
replace agent-native => ./deps/agent-native
replace agent-system-core => ./deps/agent-system-core
+4 -4
View File
@@ -26,7 +26,7 @@ import (
agentllm "agent-native/runtime/llm"
agentmcp "agent-native/runtime/mcp"
agenttools "agent-native/runtime/tools"
squad "agent-squad/squad"
nativeadp "agent-squad/adapters/native"
"agent-system-backend/internal/bus"
"agent-system-backend/internal/cardsvc"
"agent-system-backend/internal/cmdbus"
@@ -142,13 +142,13 @@ func Run(opt Options) error {
// 模型走 settings.models.chat 同一路由;搜索/解释器/MCP/技能根复用产品配置;
// 委派桥接产品 SpawnSubagent。主模型未配置时返回未启用(不阻塞产品)。
var pluginHost *plugins.Host
squadadapter.AgentNativeOptions = func(rc squadadapter.Ctx) (squad.AgentNativeConfig, bool) {
squadadapter.AgentNativeOptions = func(rc squadadapter.Ctx) (nativeadp.Config, bool) {
effNow := setSvc.Effective(store.OwnerDefault, "")
route := runtime.ResolveChatModel(core.AgentProfile{}, effNow)
if route.Model == "" || route.Base == "" {
return squad.AgentNativeConfig{}, false
return nativeadp.Config{}, false
}
cfg := squad.AgentNativeConfig{
cfg := nativeadp.Config{
Client: &agentllm.Client{BaseURL: route.Base, APIKey: route.Key, HTTPClient: &http.Client{}},
DefaultModel: route.Model,
MaxTurns: 0,
+1 -2
View File
@@ -6,7 +6,6 @@ import (
"fmt"
"strings"
"agent-native/exec"
agentllm "agent-native/runtime/llm"
"agent-squad/squad"
"agent-system-backend/internal/squadadapter"
@@ -34,7 +33,7 @@ func (s *SquadRunner) Execute(rc RunCtx) error {
var streamed strings.Builder
var toolParts []core.Part
textIdx := 0
onEvent := func(ev exec.ProcessEvent) {
onEvent := func(ev squad.ProcessEvent) {
switch ev.Type {
case "text_delta":
if ev.Text == "" {
+6 -6
View File
@@ -17,8 +17,8 @@ import (
"path/filepath"
"strings"
"agent-native/exec"
"agent-native/runtime/subagent"
nativeadp "agent-squad/adapters/native"
"agent-squad/squad"
"agent-system-backend/internal/quality"
core "agent-system-core"
@@ -171,7 +171,7 @@ func profileForRole(role string) string {
}
}
func (b *stepBackend) Execute(ctx context.Context, req exec.Request) (*exec.Result, error) {
func (b *stepBackend) Execute(ctx context.Context, req squad.ExecRequest) (*squad.ExecResult, error) {
task := strings.TrimSpace(req.Prompt)
if task == "" {
task = req.Instructions
@@ -187,7 +187,7 @@ func (b *stepBackend) Execute(ctx context.Context, req exec.Request) (*exec.Resu
} else {
out, err = b.rc.SpawnSubagent(name, task, hint)
}
res := &exec.Result{Success: err == nil, Logs: firstNonEmpty(out.Summary, "子代理完成")}
res := &squad.ExecResult{Success: err == nil, Logs: firstNonEmpty(out.Summary, "子代理完成")}
if err != nil {
res.ErrorReason = err.Error()
return res, nil
@@ -290,7 +290,7 @@ func isHoldStatus(s string) bool {
// AgentNativeOptions 可选组合根注入:返回配置且启用时,为每次小队运行注册
// "agent-native" 内核后端工厂(模型/搜索/执行/MCP/技能根由组合根从 settings
// 解析;Subagent 工厂经 rc 桥接产品 SpawnSubagent)。
var AgentNativeOptions func(rc Ctx) (squad.AgentNativeConfig, bool)
var AgentNativeOptions func(rc Ctx) (nativeadp.Config, bool)
// SubagentFactory 把内核委派端口(delegate_task)桥接到产品 SpawnSubagent:
// 委派信息集(目标/输入/写范围/非目标/完成判据/交付物)拼装为任务书,
@@ -334,12 +334,12 @@ func SubagentFactory(rc Ctx) subagent.Factory {
// 不因工厂注册而切换(对齐 parity 渐进启用条款)。
func buildBackends(rc Ctx) *squad.BackendResolver {
backends := squad.NewBackendResolver()
backends.Register("agent-system", func(role squad.RoleSpec) (exec.Backend, error) {
backends.Register("agent-system", func(role squad.RoleSpec) (squad.Executor, error) {
return &stepBackend{rc: rc, role: role}, nil
})
if AgentNativeOptions != nil {
if cfg, ok := AgentNativeOptions(rc); ok {
backends.RegisterAgentNativeFull(cfg)
nativeadp.RegisterFull(backends, cfg)
}
}
return backends
+2 -3
View File
@@ -6,7 +6,6 @@ import (
"strings"
"testing"
"agent-native/exec"
"agent-native/runtime/subagent"
"agent-squad/squad"
core "agent-system-core"
@@ -145,7 +144,7 @@ func TestStepRoleMapsToProfile(t *testing.T) {
for _, tc := range cases {
rc := &agentFakeRc{subagentFakeRc: subagentFakeRc{payload: core.AgentResultPayload{Text: "ok"}}}
b := &stepBackend{rc: rc, role: squad.RoleSpec{Role: tc.role, Name: "显示名"}}
res, err := b.Execute(context.Background(), exec.Request{Prompt: "做这件事", WorkDir: dir, Targets: []string{"output.md"}})
res, err := b.Execute(context.Background(), squad.ExecRequest{Prompt: "做这件事", WorkDir: dir, Targets: []string{"output.md"}})
if err != nil || !res.Success {
t.Fatalf("%s: %+v %v", tc.role, res, err)
}
@@ -155,7 +154,7 @@ func TestStepRoleMapsToProfile(t *testing.T) {
}
plain := &subagentFakeRc{payload: core.AgentResultPayload{Text: "ok"}}
b := &stepBackend{rc: plain, role: squad.RoleSpec{Role: "writer", Name: "撰稿"}}
if _, err := b.Execute(context.Background(), exec.Request{Prompt: "写", WorkDir: dir}); err != nil {
if _, err := b.Execute(context.Background(), squad.ExecRequest{Prompt: "写", WorkDir: dir}); err != nil {
t.Fatal(err)
}
if plain.gotName != "撰稿" {
+4 -4
View File
@@ -7,9 +7,9 @@ import (
"path/filepath"
"strings"
"agent-native/exec"
agentllm "agent-native/runtime/llm"
"agent-native/runtime/tools"
nativeadp "agent-squad/adapters/native"
"agent-squad/squad"
"agent-system-backend/internal/quality"
)
@@ -19,7 +19,7 @@ type EntryOptions struct {
DataDir string
Goal string
HostTools []tools.Tool
OnEvent func(ev exec.ProcessEvent)
OnEvent func(ev squad.ProcessEvent)
Stream agentllm.StreamFunc
Router squad.Router
Checker squad.Checker
@@ -43,7 +43,7 @@ func RunEntry(rc Ctx, opt EntryOptions) (EntryResult, error) {
if strings.TrimSpace(opt.Goal) == "" {
return EntryResult{}, fmt.Errorf("squad entry: goal text is empty")
}
cfg, enabled := squad.AgentNativeConfig{}, false
cfg, enabled := nativeadp.Config{}, false
if AgentNativeOptions != nil {
cfg, enabled = AgentNativeOptions(rc)
}
@@ -84,7 +84,7 @@ func RunEntry(rc Ctx, opt EntryOptions) (EntryResult, error) {
}
}
backends := buildBackends(rc)
backends.RegisterAgentNativeFull(cfg)
nativeadp.RegisterFull(backends, cfg)
checker := opt.Checker
if checker == nil {