refactor(squad): inject Options + backend factory, drop config.Config dependency
CI / go-vet (pull_request) Failing after 10s
CI / short-tests-report (pull_request) Failing after 36s
CI / backup-restore-drill (pull_request) Successful in 27s
CI / web (pull_request) Successful in 30s

KTD1 first step (in-repo decoupling, behavior preserved):
- squad.Options{BackendName, BackendTimeout, DataDir, NewBackend} replaces
  *config.Config; defaults applied in withDefaults
- backend construction injected by caller (bizdev assembly): credentials,
  environment and concurrency stay product-side; nil factory fails closed
  instead of silently degrading to Stub
- verified: go vet ./... clean, squad/bizdev short tests pass
This commit is contained in:
2026-09-29 05:09:54 +00:00
parent beea8a21e5
commit 72c0996b74
2 changed files with 50 additions and 13 deletions
+9 -1
View File
@@ -10,6 +10,7 @@ import (
"strings"
"time"
"chat-agent-system/internal/agent"
"chat-agent-system/internal/app/uow"
"chat-agent-system/internal/authz"
"chat-agent-system/internal/config"
@@ -192,7 +193,14 @@ func NewService(cfg *config.Config) (*Service, error) {
svc := &Service{
cfg: cfg,
kb: kb.NewClient(cfg),
squad: squad.NewService(cfg),
squad: squad.NewService(squad.Options{
BackendName: cfg.AgentBackend,
BackendTimeout: cfg.AgentTimeout,
DataDir: cfg.DataDir,
NewBackend: func(name string) agent.Backend {
return agent.NewBackend(name, cfg)
},
}),
ctxMgr: ctxMgr,
cas: casStore,
materialIndex: matIndex,
+41 -12
View File
@@ -10,7 +10,6 @@ import (
"time"
"chat-agent-system/internal/agent"
"chat-agent-system/internal/config"
"chat-agent-system/internal/quote"
"chat-agent-system/internal/stream"
"chat-agent-system/internal/workflowdef"
@@ -109,18 +108,42 @@ type SquadService interface {
ResumeOrModifyWorkspace(ctx context.Context, req ModifyWorkflowRequest) (*SquadRunResult, error)
}
// Options 是 Squad 依赖注入的唯一配置面;不反向依赖主仓 config.Config,
// 为独立模块做准备(见多仓方案 KTD1)。
type Options struct {
// BackendName 为执行后端名(空 = 由调用方默认)。
BackendName string
// BackendTimeout 为单次执行超时;零值由调用方默认。
BackendTimeout time.Duration
// DataDir 为工作区根(任务目录挂在其下)。
DataDir string
// NewBackend 由调用方注入的后端工厂(Core 装配:凭证、环境、并发上限
// 留在产品侧)。nil 时返回错误,不静默降级 Stub。
NewBackend func(name string) agent.Backend
}
func (o Options) withDefaults() Options {
if o.BackendName == "" {
o.BackendName = "pi-agent"
}
if o.BackendTimeout <= 0 {
o.BackendTimeout = 10 * time.Minute
}
return o
}
// Service SquadService 实现
type Service struct {
cfg *config.Config
opts Options
engine *WorkspaceEngine
driver *WorkflowDriver
gate *QualityGate
}
func NewService(cfg *config.Config) *Service {
func NewService(opts Options) *Service {
engine := NewWorkspaceEngine()
return &Service{
cfg: cfg,
opts: opts.withDefaults(),
engine: engine,
driver: NewWorkflowDriver(engine),
gate: NewQualityGate(),
@@ -207,12 +230,12 @@ func (s *Service) ExecuteTask(ctx context.Context, req SquadRunRequest) (*SquadR
workDir := req.WorkDir
if workDir == "" {
ts := time.Now().UnixNano()
workDir = filepath.Join(s.cfg.DataDir, "workspaces", "bizdev", fmt.Sprintf("%s_%d", req.TaskKey, ts))
workDir = filepath.Join(s.opts.DataDir, "workspaces", "bizdev", fmt.Sprintf("%s_%d", req.TaskKey, ts))
}
backendName := req.Backend
if backendName == "" {
backendName = s.cfg.AgentBackend
backendName = s.opts.BackendName
}
// 1. 初始化工作区目录体系
@@ -258,10 +281,13 @@ func (s *Service) ExecuteTask(ctx context.Context, req SquadRunRequest) (*SquadR
streamer.EmitPhase("squad_assembly", fmt.Sprintf("正在组建并启动【%s】智能体小队(后端: %s)...", TaskArtifactTitle(req.TaskKey), backendName), "leader", 0, 0, 5)
}
backend := agent.NewBackend(backendName, s.cfg)
if s.opts.NewBackend == nil {
return nil, fmt.Errorf("squad: NewBackend factory not injected")
}
backend := s.opts.NewBackend(backendName)
timeout := req.Timeout
if timeout <= 0 {
timeout = s.cfg.AgentTimeout
timeout = s.opts.BackendTimeout
}
execOpts := ExecuteOptions{
Timeout: timeout,
@@ -397,9 +423,12 @@ func repairBudgetForSquadTask(req SquadRunRequest) int {
func (s *Service) ExecuteWorkflow(ctx context.Context, wsDir string, backendName string, opts ExecuteOptions) (*SquadRunResult, error) {
start := time.Now()
if backendName == "" {
backendName = s.cfg.AgentBackend
backendName = s.opts.BackendName
}
backend := agent.NewBackend(backendName, s.cfg)
if s.opts.NewBackend == nil {
return nil, fmt.Errorf("squad: NewBackend factory not injected")
}
backend := s.opts.NewBackend(backendName)
execRes, err := s.driver.Execute(ctx, wsDir, backend, opts)
if err != nil {
@@ -491,12 +520,12 @@ func (s *Service) ResumeOrModifyWorkspace(ctx context.Context, req ModifyWorkflo
backendName := req.Backend
if backendName == "" {
backendName = s.cfg.AgentBackend
backendName = s.opts.BackendName
}
timeout := req.Timeout
if timeout <= 0 {
timeout = s.cfg.AgentTimeout
timeout = s.opts.BackendTimeout
}
opts := ExecuteOptions{