Files
YunShu/registry.go
titor c4a0e3ef53 feat: v2.3.0 流式输出 + 日志系统 + 会议室架构全面升级
- 流式输出: 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
2026-05-16 17:21:29 +08:00

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()
}