You've already forked agentic-coding-workflow
bugfix
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package mcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
|
||||
"github.com/yan1h/agent-coding-workflow/internal/infra/errs"
|
||||
)
|
||||
|
||||
// OrchestratorBridge 是 mcp 调用 orchestrator 服务的窄桥接接口(orchestrator →
|
||||
// mcp 的既有依赖边由 orchestrator 实现该接口,mcp 不反向 import orchestrator,避免循环)。
|
||||
type OrchestratorBridge interface {
|
||||
// RequestSubtask 让运行中的 agent 为其当前编排 step 派生一个子 step。
|
||||
// parentACPSessionID 是调用方所在的 acp session(从 AuthSession 解析);
|
||||
// 返回新建子 step 的 id。
|
||||
RequestSubtask(ctx context.Context, parentACPSessionID uuid.UUID, phase string, prompt string, agentKindID *uuid.UUID) (subtaskID string, err error)
|
||||
}
|
||||
|
||||
// registerOrchestratorTools 注册编排器相关 MCP 工具。
|
||||
func registerOrchestratorTools(srv *mcpsdk.Server, deps ServerDeps) {
|
||||
registerRequestSubtask(srv, deps)
|
||||
}
|
||||
|
||||
// ===== request_subtask =====
|
||||
|
||||
type requestSubtaskIn struct {
|
||||
Phase string `json:"phase,omitempty" jsonschema:"target phase for the subtask (defaults to the parent step phase)"`
|
||||
Prompt string `json:"prompt" jsonschema:"prompt for the child agent"`
|
||||
AgentKindID string `json:"agent_kind_id,omitempty" jsonschema:"optional agent kind UUID for the subtask"`
|
||||
}
|
||||
|
||||
type requestSubtaskOut struct {
|
||||
OK bool `json:"ok"`
|
||||
StepID string `json:"step_id"`
|
||||
}
|
||||
|
||||
func registerRequestSubtask(srv *mcpsdk.Server, deps ServerDeps) {
|
||||
mcpsdk.AddTool(srv,
|
||||
&mcpsdk.Tool{
|
||||
Name: "request_subtask",
|
||||
Description: "Ask the orchestrator to spawn a child step (sub-agent) for the current run, subject to depth and fan-out limits. Only callable from within an active agent session.",
|
||||
},
|
||||
func(ctx context.Context, _ *mcpsdk.CallToolRequest, in requestSubtaskIn) (*mcpsdk.CallToolResult, requestSubtaskOut, error) {
|
||||
if err := CheckToolFromCtx(ctx, "request_subtask"); err != nil {
|
||||
return nil, requestSubtaskOut{}, err
|
||||
}
|
||||
if deps.Orchestrator == nil {
|
||||
return nil, requestSubtaskOut{}, errs.New(errs.CodeNotFound, "orchestrator not enabled")
|
||||
}
|
||||
// request_subtask 是 create_acp_session 的逆向闸门:只有在 session 内的
|
||||
// agent(system token)可调,普通用户/admin token 不可(它们走 StartRun)。
|
||||
sess, ok := FromContext(ctx)
|
||||
if !ok {
|
||||
return nil, requestSubtaskOut{}, errs.New(errs.CodeInternal, "mcp: AuthSession missing")
|
||||
}
|
||||
if sess.Issuer != IssuerSystem {
|
||||
return nil, requestSubtaskOut{}, errs.New(errs.CodeForbidden,
|
||||
"request_subtask is only callable from within an agent session")
|
||||
}
|
||||
if sess.ACPSessionID == nil || *sess.ACPSessionID == uuid.Nil {
|
||||
return nil, requestSubtaskOut{}, errs.New(errs.CodeForbidden,
|
||||
"calling token is not bound to an acp session")
|
||||
}
|
||||
if in.Prompt == "" {
|
||||
return nil, requestSubtaskOut{}, errs.New(errs.CodeInvalidInput, "prompt is required")
|
||||
}
|
||||
|
||||
var akID *uuid.UUID
|
||||
if in.AgentKindID != "" {
|
||||
id, perr := uuid.Parse(in.AgentKindID)
|
||||
if perr != nil {
|
||||
return nil, requestSubtaskOut{}, errs.Wrap(perr, errs.CodeInvalidInput, "agent_kind_id parse")
|
||||
}
|
||||
akID = &id
|
||||
}
|
||||
|
||||
stepID, err := deps.Orchestrator.RequestSubtask(ctx, *sess.ACPSessionID, in.Phase, in.Prompt, akID)
|
||||
if err != nil {
|
||||
return nil, requestSubtaskOut{}, err
|
||||
}
|
||||
return nil, requestSubtaskOut{OK: true, StepID: stepID}, nil
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user