mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-25 05:10:58 +02:00
Add files via upload
This commit is contained in:
@@ -17,6 +17,12 @@ import (
|
||||
// OrchestratorMarkdownFilename 固定文件名:存在则视为 Deep 主代理定义,且不参与子代理列表。
|
||||
const OrchestratorMarkdownFilename = "orchestrator.md"
|
||||
|
||||
// OrchestratorPlanExecuteMarkdownFilename plan_execute 模式主代理(规划侧)专用 Markdown 文件名。
|
||||
const OrchestratorPlanExecuteMarkdownFilename = "orchestrator-plan-execute.md"
|
||||
|
||||
// OrchestratorSupervisorMarkdownFilename supervisor 模式主代理专用 Markdown 文件名。
|
||||
const OrchestratorSupervisorMarkdownFilename = "orchestrator-supervisor.md"
|
||||
|
||||
// FrontMatter 对应 Markdown 文件头部字段(与文档示例一致)。
|
||||
type FrontMatter struct {
|
||||
Name string `yaml:"name"`
|
||||
@@ -39,26 +45,58 @@ type OrchestratorMarkdown struct {
|
||||
|
||||
// MarkdownDirLoad 一次扫描 agents 目录的结果(子代理不含主代理文件)。
|
||||
type MarkdownDirLoad struct {
|
||||
SubAgents []config.MultiAgentSubConfig
|
||||
Orchestrator *OrchestratorMarkdown
|
||||
FileEntries []FileAgent // 含主代理与所有子代理,供管理 API 列表
|
||||
SubAgents []config.MultiAgentSubConfig
|
||||
Orchestrator *OrchestratorMarkdown // Deep 主代理
|
||||
OrchestratorPlanExecute *OrchestratorMarkdown // plan_execute 规划主代理
|
||||
OrchestratorSupervisor *OrchestratorMarkdown // supervisor 监督主代理
|
||||
FileEntries []FileAgent // 含主代理与所有子代理,供管理 API 列表
|
||||
}
|
||||
|
||||
// IsOrchestratorMarkdown 判断该文件是否表示主代理:固定文件名 orchestrator.md,或 front matter kind: orchestrator。
|
||||
// OrchestratorMarkdownKind 按固定文件名返回主代理类型:deep、plan_execute、supervisor;否则返回空。
|
||||
func OrchestratorMarkdownKind(filename string) string {
|
||||
base := filepath.Base(strings.TrimSpace(filename))
|
||||
switch {
|
||||
case strings.EqualFold(base, OrchestratorPlanExecuteMarkdownFilename):
|
||||
return "plan_execute"
|
||||
case strings.EqualFold(base, OrchestratorSupervisorMarkdownFilename):
|
||||
return "supervisor"
|
||||
case strings.EqualFold(base, OrchestratorMarkdownFilename):
|
||||
return "deep"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// IsOrchestratorMarkdown 判断该文件是否占用 **Deep** 主代理槽位:orchestrator.md、或 kind: orchestrator(不含 plan_execute / supervisor 专用文件名)。
|
||||
func IsOrchestratorMarkdown(filename string, fm FrontMatter) bool {
|
||||
base := filepath.Base(strings.TrimSpace(filename))
|
||||
switch OrchestratorMarkdownKind(base) {
|
||||
case "plan_execute", "supervisor":
|
||||
return false
|
||||
}
|
||||
if strings.EqualFold(base, OrchestratorMarkdownFilename) {
|
||||
return true
|
||||
}
|
||||
return strings.EqualFold(strings.TrimSpace(fm.Kind), "orchestrator")
|
||||
}
|
||||
|
||||
// IsOrchestratorLikeMarkdown 是否应在前端/API 中显示为「主代理类」文件。
|
||||
func IsOrchestratorLikeMarkdown(filename string, kind string) bool {
|
||||
if OrchestratorMarkdownKind(filename) != "" {
|
||||
return true
|
||||
}
|
||||
return IsOrchestratorMarkdown(filename, FrontMatter{Kind: kind})
|
||||
}
|
||||
|
||||
// WantsMarkdownOrchestrator 保存前判断是否会把该文件作为主代理(用于唯一性校验)。
|
||||
func WantsMarkdownOrchestrator(filename string, kindField string, raw string) bool {
|
||||
base := filepath.Base(strings.TrimSpace(filename))
|
||||
if OrchestratorMarkdownKind(base) != "" {
|
||||
return true
|
||||
}
|
||||
if strings.EqualFold(strings.TrimSpace(kindField), "orchestrator") {
|
||||
return true
|
||||
}
|
||||
base := filepath.Base(strings.TrimSpace(filename))
|
||||
if strings.EqualFold(base, OrchestratorMarkdownFilename) {
|
||||
return true
|
||||
}
|
||||
@@ -286,7 +324,7 @@ func collectMarkdownBasenames(dir string) ([]string, error) {
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// LoadMarkdownAgentsDir 扫描 agents 目录:拆出至多一个主代理与其余子代理。
|
||||
// LoadMarkdownAgentsDir 扫描 agents 目录:拆出 Deep / plan_execute / supervisor 主代理各至多一个,及其余子代理。
|
||||
func LoadMarkdownAgentsDir(dir string) (*MarkdownDirLoad, error) {
|
||||
out := &MarkdownDirLoad{}
|
||||
names, err := collectMarkdownBasenames(dir)
|
||||
@@ -303,6 +341,38 @@ func LoadMarkdownAgentsDir(dir string) (*MarkdownDirLoad, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", n, err)
|
||||
}
|
||||
switch OrchestratorMarkdownKind(n) {
|
||||
case "plan_execute":
|
||||
if out.OrchestratorPlanExecute != nil {
|
||||
return nil, fmt.Errorf("agents: 仅能定义一个 %s,已有 %s", OrchestratorPlanExecuteMarkdownFilename, out.OrchestratorPlanExecute.Filename)
|
||||
}
|
||||
orch, err := orchestratorFromParsed(n, fm, body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", n, err)
|
||||
}
|
||||
out.OrchestratorPlanExecute = orch
|
||||
out.FileEntries = append(out.FileEntries, FileAgent{
|
||||
Filename: n,
|
||||
Config: orchestratorConfigFromOrchestrator(orch),
|
||||
IsOrchestrator: true,
|
||||
})
|
||||
continue
|
||||
case "supervisor":
|
||||
if out.OrchestratorSupervisor != nil {
|
||||
return nil, fmt.Errorf("agents: 仅能定义一个 %s,已有 %s", OrchestratorSupervisorMarkdownFilename, out.OrchestratorSupervisor.Filename)
|
||||
}
|
||||
orch, err := orchestratorFromParsed(n, fm, body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", n, err)
|
||||
}
|
||||
out.OrchestratorSupervisor = orch
|
||||
out.FileEntries = append(out.FileEntries, FileAgent{
|
||||
Filename: n,
|
||||
Config: orchestratorConfigFromOrchestrator(orch),
|
||||
IsOrchestrator: true,
|
||||
})
|
||||
continue
|
||||
}
|
||||
if IsOrchestratorMarkdown(n, fm) {
|
||||
if out.Orchestrator != nil {
|
||||
return nil, fmt.Errorf("agents: 仅能定义一个主代理(Deep 协调者),已有 %s,又与 %s 冲突", out.Orchestrator.Filename, n)
|
||||
@@ -335,6 +405,13 @@ func ParseMarkdownSubAgent(filename string, content string) (config.MultiAgentSu
|
||||
if err != nil {
|
||||
return config.MultiAgentSubConfig{}, err
|
||||
}
|
||||
if OrchestratorMarkdownKind(filename) != "" {
|
||||
orch, err := orchestratorFromParsed(filename, fm, body)
|
||||
if err != nil {
|
||||
return config.MultiAgentSubConfig{}, err
|
||||
}
|
||||
return orchestratorConfigFromOrchestrator(orch), nil
|
||||
}
|
||||
if IsOrchestratorMarkdown(filename, fm) {
|
||||
orch, err := orchestratorFromParsed(filename, fm, body)
|
||||
if err != nil {
|
||||
|
||||
@@ -64,3 +64,34 @@ func TestLoadMarkdownAgentsDir_DuplicateOrchestrator(t *testing.T) {
|
||||
t.Fatal("expected duplicate orchestrator error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadMarkdownAgentsDir_ModeOrchestratorsCoexist(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
write := func(name, body string) {
|
||||
t.Helper()
|
||||
if err := os.WriteFile(filepath.Join(dir, name), []byte(body), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
write(OrchestratorMarkdownFilename, "---\nname: Deep\n---\n\ndeep\n")
|
||||
write(OrchestratorPlanExecuteMarkdownFilename, "---\nname: PE\n---\n\npe\n")
|
||||
write(OrchestratorSupervisorMarkdownFilename, "---\nname: SV\n---\n\nsv\n")
|
||||
write("worker.md", "---\nid: worker\nname: Worker\n---\n\nw\n")
|
||||
|
||||
load, err := LoadMarkdownAgentsDir(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if load.Orchestrator == nil || load.Orchestrator.Instruction != "deep" {
|
||||
t.Fatalf("deep: %+v", load.Orchestrator)
|
||||
}
|
||||
if load.OrchestratorPlanExecute == nil || load.OrchestratorPlanExecute.Instruction != "pe" {
|
||||
t.Fatalf("pe: %+v", load.OrchestratorPlanExecute)
|
||||
}
|
||||
if load.OrchestratorSupervisor == nil || load.OrchestratorSupervisor.Instruction != "sv" {
|
||||
t.Fatalf("sv: %+v", load.OrchestratorSupervisor)
|
||||
}
|
||||
if len(load.SubAgents) != 1 || load.SubAgents[0].ID != "worker" {
|
||||
t.Fatalf("subs: %+v", load.SubAgents)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user