- 流式输出: SSE 逐 token 接收, \\n\n\ 段落缓冲后 mdprint 彩色渲染 - 日志系统: charmbracelet/log v2 双写(stderr + log.yml), yunshu log 命令 - 会议室架构: dialog(main) + weather/profile/note(sub) 多 Agent 编排 - 泛型工具注册: NewTool[T] 反射推导 JSON Schema, 类型安全 - 安全加固: safeMemoryPath 三段校验(EvalSymlinks+Rel), maxToolCalls=2 - 性能优化: sync.Once 延迟加载, note 一步完成, obs/summary 合并 - Prompt 适配: 流式输出原则(先调工具不说话), 单 Agent 查询跳过 obs+summary - 文档: AGENTS.md + architecture.md + changelog.md 全部同步至 v2.3.0
93 lines
1.8 KiB
Go
93 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
type AgentRegistry struct {
|
|
mains map[string]*AgentDef
|
|
subs map[string]*AgentDef
|
|
}
|
|
|
|
func ScanAgents() *AgentRegistry {
|
|
r := &AgentRegistry{
|
|
mains: make(map[string]*AgentDef),
|
|
subs: make(map[string]*AgentDef),
|
|
}
|
|
|
|
dirs := []string{
|
|
"agents",
|
|
filepath.Join(ConfigDir(), "agents"),
|
|
}
|
|
|
|
seen := make(map[string]bool)
|
|
|
|
for _, dir := range dirs {
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, e := range entries {
|
|
if e.IsDir() || !strings.HasSuffix(e.Name(), ".md") || seen[e.Name()] {
|
|
continue
|
|
}
|
|
seen[e.Name()] = true
|
|
|
|
agentPath := filepath.Join(dir, e.Name())
|
|
def, err := LoadAgent(agentPath)
|
|
if err != nil {
|
|
warnLog("跳过 agent", "file", e.Name(), "err", err)
|
|
continue
|
|
}
|
|
|
|
switch def.Type {
|
|
case "main":
|
|
r.mains[def.Name] = def
|
|
case "sub":
|
|
r.subs[def.Name] = def
|
|
}
|
|
}
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
func (r *AgentRegistry) GetMain(name string) *AgentDef {
|
|
return r.mains[name]
|
|
}
|
|
|
|
func (r *AgentRegistry) GetSub(name string) *AgentDef {
|
|
return r.subs[name]
|
|
}
|
|
|
|
func (r *AgentRegistry) ListMains() []*AgentDef {
|
|
list := make([]*AgentDef, 0, len(r.mains))
|
|
for _, def := range r.mains {
|
|
list = append(list, def)
|
|
}
|
|
return list
|
|
}
|
|
|
|
func (r *AgentRegistry) ListSubs() []*AgentDef {
|
|
list := make([]*AgentDef, 0, len(r.subs))
|
|
for _, def := range r.subs {
|
|
list = append(list, def)
|
|
}
|
|
return list
|
|
}
|
|
|
|
func (r *AgentRegistry) String() string {
|
|
var b strings.Builder
|
|
b.WriteString(fmt.Sprintf("mains: %d, subs: %d\n", len(r.mains), len(r.subs)))
|
|
for _, def := range r.mains {
|
|
b.WriteString(fmt.Sprintf(" [main] %s: %s\n", def.Name, def.Description))
|
|
}
|
|
for _, def := range r.subs {
|
|
b.WriteString(fmt.Sprintf(" [sub] %s: %s\n", def.Name, def.Description))
|
|
}
|
|
return b.String()
|
|
}
|