You've already forked agentic-coding-workflow
ACP / MCP
This commit is contained in:
@@ -41,6 +41,9 @@ type SupervisorConfig struct {
|
||||
EventMaxPayload int
|
||||
EventTruncateField int
|
||||
ShutdownGrace time.Duration
|
||||
// AgentHomesDir 是 agent CLI 受管 home 的根目录(<DataDir>/agent-homes)。
|
||||
// 空串时跳过配置物化与重定向 env 注入(部分测试)。
|
||||
AgentHomesDir string
|
||||
}
|
||||
|
||||
// Supervisor 是 ACP 子进程总管。
|
||||
@@ -154,10 +157,24 @@ func (s *Supervisor) GetRelay(sid uuid.UUID) *Relay {
|
||||
// handshake 失败时调用 Kill 回滚并返回错误。调用方(SessionService)负责前置的
|
||||
// worktree 占用与 acp_sessions 行 INSERT;本方法仅负责 OS 层资源与协议层握手。
|
||||
func (s *Supervisor) Spawn(ctx context.Context, sess *Session, kind *AgentKind, extraEnv map[string]string) (*Process, error) {
|
||||
envMap, err := decryptEnv(s.crypto, kind.EncryptedEnv)
|
||||
// 受管 home:物化 DB 中的配置文件并注入重定向 env(优先级最低,可被
|
||||
// AgentKind env / extraEnv 覆盖)。AgentHomesDir 未配置时跳过(部分测试)。
|
||||
envMap := map[string]string{}
|
||||
if s.cfg.AgentHomesDir != "" {
|
||||
home, err := s.materializeAgentHome(ctx, kind)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("materialize agent home: %w", err)
|
||||
}
|
||||
envMap = agentHomeEnv(home, kind.ClientType)
|
||||
}
|
||||
|
||||
kindEnv, err := decryptEnv(s.crypto, kind.EncryptedEnv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range kindEnv {
|
||||
envMap[k] = v
|
||||
}
|
||||
|
||||
// System override: extraEnv overrides agent_kinds same-name keys (spec §6.1 #11)
|
||||
for k, v := range extraEnv {
|
||||
@@ -251,7 +268,7 @@ func (s *Supervisor) Spawn(ctx context.Context, sess *Session, kind *AgentKind,
|
||||
ToolAllowlist: kind.ToolAllowlist,
|
||||
})
|
||||
|
||||
if err := s.handshake(ctx, sess, relay, proc); err != nil {
|
||||
if err := s.handshake(ctx, sess, kind, relay, proc, extraEnv); err != nil {
|
||||
s.log.Error("acp.handshake_failed", "session_id", sess.ID, "err", err.Error())
|
||||
s.Kill(ctx, sess.ID, s.cfg.KillGrace)
|
||||
return nil, err
|
||||
@@ -261,14 +278,32 @@ func (s *Supervisor) Spawn(ctx context.Context, sess *Session, kind *AgentKind,
|
||||
|
||||
// handshake 发送 initialize → session/new,并把返回的 agent session id + pid
|
||||
// 持久化到 acp_sessions 行(status → running)。SpawnTimeout 是整个握手的硬上限。
|
||||
func (s *Supervisor) handshake(ctx context.Context, sess *Session, relay *Relay, proc *Process) error {
|
||||
// session/new 同时下发 mcpServers:ACW 自家 MCP(extraEnv 中的 per-session
|
||||
// token)+ AgentKind 第三方 MCP,按 initialize 声明的 mcpCapabilities 过滤。
|
||||
func (s *Supervisor) handshake(ctx context.Context, sess *Session, kind *AgentKind,
|
||||
relay *Relay, proc *Process, extraEnv map[string]string) error {
|
||||
hsCtx, cancel := context.WithTimeout(ctx, s.cfg.SpawnTimeout)
|
||||
defer cancel()
|
||||
|
||||
if _, err := relay.Call(hsCtx, "initialize", handlers.BuildInitializeParams("dev")); err != nil {
|
||||
initResp, err := relay.Call(hsCtx, "initialize", handlers.BuildInitializeParams("dev"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("initialize: %w", err)
|
||||
}
|
||||
resp, err := relay.Call(hsCtx, "session/new", handlers.BuildSessionNewParams(sess.CwdPath))
|
||||
var ir handlers.InitializeResult
|
||||
if err := json.Unmarshal(initResp.Result, &ir); err != nil {
|
||||
// 能力解析失败不阻断握手:按无 http/sse 能力处理(仅基线 stdio 可下发)。
|
||||
s.log.Warn("acp.handshake.parse_initialize_result", "session_id", sess.ID, "err", err.Error())
|
||||
}
|
||||
httpOK, sseOK := ir.McpCapabilities()
|
||||
|
||||
specs, err := decryptMCPServers(s.crypto, kind.EncryptedMCPServers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mcpServers := buildMcpServers(specs, extraEnv[EnvMCPURL], extraEnv[EnvMCPToken],
|
||||
httpOK, sseOK, s.log, sess.ID)
|
||||
|
||||
resp, err := relay.Call(hsCtx, "session/new", handlers.BuildSessionNewParams(sess.CwdPath, mcpServers))
|
||||
if err != nil {
|
||||
return fmt.Errorf("session/new: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user