From b1323896c87808fc8b55c043a50357fe44ec817d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AC=E6=98=8E?= <83812544+Ed1s0nZ@users.noreply.github.com> Date: Thu, 2 Jul 2026 11:55:23 +0800 Subject: [PATCH] Add files via upload --- internal/multiagent/eino_orchestration.go | 64 ++++++++------ .../plan_execute_executor_handlers_test.go | 85 +++++++++++++++++++ internal/multiagent/runner.go | 1 + 3 files changed, 122 insertions(+), 28 deletions(-) create mode 100644 internal/multiagent/plan_execute_executor_handlers_test.go diff --git a/internal/multiagent/eino_orchestration.go b/internal/multiagent/eino_orchestration.go index 1ca95069..434429dd 100644 --- a/internal/multiagent/eino_orchestration.go +++ b/internal/multiagent/eino_orchestration.go @@ -80,34 +80,9 @@ func NewPlanExecuteRoot(ctx context.Context, a *PlanExecuteRootArgs) (adk.Resuma return nil, fmt.Errorf("plan_execute replanner: %w", err) } - // 组装 executor handler 栈,顺序与 Deep/Supervisor 主代理一致(outermost first)。 - var execHandlers []adk.ChatModelAgentMiddleware - // 1. patchtoolcalls, reduction, toolsearch, plantask(来自 prependEinoMiddlewares) - if len(a.ExecPreMiddlewares) > 0 { - execHandlers = append(execHandlers, a.ExecPreMiddlewares...) - } - // 2. filesystem 中间件(可选) - if a.FilesystemMiddleware != nil { - execHandlers = append(execHandlers, a.FilesystemMiddleware) - } - // 3. skill 中间件(可选) - if a.SkillMiddleware != nil { - execHandlers = append(execHandlers, a.SkillMiddleware) - } - // 4. pre-summarization normalize + continuation dedup, then summarization (与 Deep/Supervisor 一致) - if a.AppCfg != nil { - sumMw, sumErr := newEinoSummarizationMiddleware(ctx, a.ExecModel, a.AppCfg, a.MwCfg, a.ConversationID, a.DB, a.ProjectID, a.Logger) - if sumErr != nil { - return nil, fmt.Errorf("plan_execute executor summarization: %w", sumErr) - } - execHandlers = appendEinoChatModelTailMiddlewares(execHandlers, einoChatModelTailConfig{ - logger: a.Logger, - phase: "plan_execute_executor", - summarization: sumMw, - modelName: a.ModelName, - conversationID: a.ConversationID, - trace: a.ModelFacingTrace, - }) + execHandlers, err := buildPlanExecuteExecutorHandlers(ctx, a) + if err != nil { + return nil, err } executor, err := newPlanExecuteExecutor(ctx, &planexecute.ExecutorConfig{ Model: a.ExecModel, @@ -130,6 +105,39 @@ func NewPlanExecuteRoot(ctx context.Context, a *PlanExecuteRootArgs) (adk.Resuma }) } +// buildPlanExecuteExecutorHandlers 组装 Executor 中间件栈(outermost first),与 Deep/Supervisor 主代理对齐: +// ExecPreMiddlewares(patch / reduction / toolsearch / plantask)→ filesystem → skill → summarization tail。 +func buildPlanExecuteExecutorHandlers(ctx context.Context, a *PlanExecuteRootArgs) ([]adk.ChatModelAgentMiddleware, error) { + if a == nil { + return nil, fmt.Errorf("plan_execute: args 为空") + } + var execHandlers []adk.ChatModelAgentMiddleware + if len(a.ExecPreMiddlewares) > 0 { + execHandlers = append(execHandlers, a.ExecPreMiddlewares...) + } + if a.FilesystemMiddleware != nil { + execHandlers = append(execHandlers, a.FilesystemMiddleware) + } + if a.SkillMiddleware != nil { + execHandlers = append(execHandlers, a.SkillMiddleware) + } + if a.AppCfg != nil { + sumMw, sumErr := newEinoSummarizationMiddleware(ctx, a.ExecModel, a.AppCfg, a.MwCfg, a.ConversationID, a.DB, a.ProjectID, a.Logger) + if sumErr != nil { + return nil, fmt.Errorf("plan_execute executor summarization: %w", sumErr) + } + execHandlers = appendEinoChatModelTailMiddlewares(execHandlers, einoChatModelTailConfig{ + logger: a.Logger, + phase: "plan_execute_executor", + summarization: sumMw, + modelName: a.ModelName, + conversationID: a.ConversationID, + trace: a.ModelFacingTrace, + }) + } + return execHandlers, nil +} + // planExecutePlannerGenInput 将 orchestrator instruction 作为 SystemMessage 注入 planner 输入。 // 返回 nil 时 Eino 使用内置默认 planner prompt。 func planExecutePlannerGenInput( diff --git a/internal/multiagent/plan_execute_executor_handlers_test.go b/internal/multiagent/plan_execute_executor_handlers_test.go new file mode 100644 index 00000000..3252831e --- /dev/null +++ b/internal/multiagent/plan_execute_executor_handlers_test.go @@ -0,0 +1,85 @@ +package multiagent + +import ( + "context" + "fmt" + "testing" + + "cyberstrike-ai/internal/config" + + "github.com/cloudwego/eino/adk" + "github.com/cloudwego/eino/components/tool" +) + +type stubChatModelAgentMiddleware struct { + adk.BaseChatModelAgentMiddleware + tag string +} + +func stubMW(tag string) adk.ChatModelAgentMiddleware { + return &stubChatModelAgentMiddleware{tag: tag} +} + +func TestBuildPlanExecuteExecutorHandlers_IncludesExecPreMiddlewares(t *testing.T) { + t.Parallel() + pre := []adk.ChatModelAgentMiddleware{ + stubMW("patch"), + stubMW("reduction"), + } + + got, err := buildPlanExecuteExecutorHandlers(context.Background(), &PlanExecuteRootArgs{ + ExecPreMiddlewares: pre, + FilesystemMiddleware: stubMW("filesystem"), + SkillMiddleware: stubMW("skill"), + }) + if err != nil { + t.Fatalf("buildPlanExecuteExecutorHandlers: %v", err) + } + if len(got) != 4 { + t.Fatalf("expected 4 pre-tail handlers (2 pre + fs + skill), got %d", len(got)) + } + for i, want := range []string{"patch", "reduction", "filesystem", "skill"} { + st, ok := got[i].(*stubChatModelAgentMiddleware) + if !ok || st.tag != want { + t.Fatalf("handler[%d]: got %#v want tag %q", i, got[i], want) + } + } +} + +func stubTools(n int) []tool.BaseTool { + out := make([]tool.BaseTool, n) + for i := 0; i < n; i++ { + out[i] = stubTool{name: fmt.Sprintf("t%d", i)} + } + return out +} + +func TestBuildPlanExecuteExecutorHandlers_NilArgs(t *testing.T) { + t.Parallel() + if _, err := buildPlanExecuteExecutorHandlers(context.Background(), nil); err == nil { + t.Fatal("expected error for nil args") + } +} + +func TestPrependEinoMiddlewares_Main_IncludesPatch(t *testing.T) { + t.Parallel() + ctx := context.Background() + mw := configMultiAgentEinoMiddlewareForTest() + mw.ReductionEnable = false + mw.ToolSearchEnable = false + mw.PlantaskEnable = false + _, extra, _, err := prependEinoMiddlewares(ctx, mw, einoMWMain, stubTools(25), nil, "", "conv-test", "", nil) + if err != nil { + t.Fatalf("prependEinoMiddlewares: %v", err) + } + if len(extra) == 0 { + t.Fatal("expected patch middleware on einoMWMain when patch_tool_calls enabled") + } +} + +func configMultiAgentEinoMiddlewareForTest() *config.MultiAgentEinoMiddlewareConfig { + patch := true + return &config.MultiAgentEinoMiddlewareConfig{ + PatchToolCalls: &patch, + } +} diff --git a/internal/multiagent/runner.go b/internal/multiagent/runner.go index 0c38c6c8..e1927dee 100644 --- a/internal/multiagent/runner.go +++ b/internal/multiagent/runner.go @@ -474,6 +474,7 @@ func RunDeepAgent( ProjectID: projectID, Logger: logger, ModelName: appCfg.OpenAI.Model, + // 与 Deep/Supervisor 主代理同源:patch / reduction / toolsearch / plantask(见 buildPlanExecuteExecutorHandlers)。 ExecPreMiddlewares: mainOrchestratorPre, SkillMiddleware: einoSkillMW, FilesystemMiddleware: peFsMw,