feat: launcher descubre agentes en _specials/ con validacion de tipo
El launcher ahora escanea agents/_specials/*/config.yaml ademas de agents/*/config.yaml para descubrir agentes del sistema con identidad Matrix (ej: father-bot). Los SpecialConfig ya cargados (orchestrator) se detectan y saltan via isSpecialConfig() para evitar errores de validacion. Tambien actualiza dev-scripts/_common.sh para que config_path_for() y list_agents_raw() incluyan _specials/ en la busqueda. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@ import (
|
|||||||
_ "github.com/enmanuel/agents/agents/asistente-2"
|
_ "github.com/enmanuel/agents/agents/asistente-2"
|
||||||
_ "github.com/enmanuel/agents/agents/meteorologo"
|
_ "github.com/enmanuel/agents/agents/meteorologo"
|
||||||
_ "github.com/enmanuel/agents/agents/test-personality"
|
_ "github.com/enmanuel/agents/agents/test-personality"
|
||||||
|
_ "github.com/enmanuel/agents/agents/_specials/father-bot"
|
||||||
testbot "github.com/enmanuel/agents/agents/test-bot"
|
testbot "github.com/enmanuel/agents/agents/test-bot"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -51,6 +52,10 @@ func main() {
|
|||||||
if len(configPaths) == 0 {
|
if len(configPaths) == 0 {
|
||||||
matches, _ := filepath.Glob("agents/*/config.yaml")
|
matches, _ := filepath.Glob("agents/*/config.yaml")
|
||||||
configPaths = matches
|
configPaths = matches
|
||||||
|
// Also discover agent-type specials (e.g. father-bot).
|
||||||
|
// SpecialConfig middleware (orchestrator) is handled separately.
|
||||||
|
specials, _ := filepath.Glob("agents/_specials/*/config.yaml")
|
||||||
|
configPaths = append(configPaths, specials...)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
@@ -143,9 +148,22 @@ func main() {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// ── Start normal agents ──
|
// ── Start normal agents ──
|
||||||
|
// Build a set of special IDs already loaded (e.g. orchestrator)
|
||||||
|
// so the discovery loop skips them instead of failing on validation.
|
||||||
|
loadedSpecials := make(map[string]bool)
|
||||||
|
if orch != nil {
|
||||||
|
loadedSpecials[orch.cfg.Special.ID] = true
|
||||||
|
}
|
||||||
|
|
||||||
var scannerOnce scanOnce
|
var scannerOnce scanOnce
|
||||||
for _, path := range configPaths {
|
for _, path := range configPaths {
|
||||||
path := path
|
path := path
|
||||||
|
|
||||||
|
// Skip configs that belong to already-loaded specials.
|
||||||
|
if isSpecialConfig(path, loadedSpecials) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
cfg, err := config.Load(path)
|
cfg, err := config.Load(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("failed to load config", "path", path, "err", err)
|
logger.Error("failed to load config", "path", path, "err", err)
|
||||||
@@ -337,3 +355,18 @@ func parseLogLevel(level string) slog.Level {
|
|||||||
func newLogger(level string) *slog.Logger {
|
func newLogger(level string) *slog.Logger {
|
||||||
return slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: parseLogLevel(level)}))
|
return slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: parseLogLevel(level)}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isSpecialConfig checks whether a config path belongs to a special agent
|
||||||
|
// that was already loaded (e.g. orchestrator). It reads the YAML to detect
|
||||||
|
// a "special:" top-level key. This avoids config.Load() failing with
|
||||||
|
// validation errors for SpecialConfig files.
|
||||||
|
func isSpecialConfig(path string, loadedSpecials map[string]bool) bool {
|
||||||
|
if len(loadedSpecials) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
cfg, err := config.LoadSpecial(path)
|
||||||
|
if err != nil {
|
||||||
|
return false // not a valid special config → let Load() handle it
|
||||||
|
}
|
||||||
|
return loadedSpecials[cfg.Special.ID]
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,9 +51,10 @@ read_pid() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Map agent ID to its config path by scanning agent directories.
|
# Map agent ID to its config path by scanning agent directories.
|
||||||
|
# Also scans agents/_specials/ for privileged system agents (e.g. father-bot).
|
||||||
config_path_for() {
|
config_path_for() {
|
||||||
local target_id="$1"
|
local target_id="$1"
|
||||||
for cfg in agents/*/config.yaml; do
|
for cfg in agents/*/config.yaml agents/_specials/*/config.yaml; do
|
||||||
[[ -f "$cfg" ]] || continue
|
[[ -f "$cfg" ]] || continue
|
||||||
local id
|
local id
|
||||||
id=$(grep -m1 '^ id:' "$cfg" | awk '{print $2}')
|
id=$(grep -m1 '^ id:' "$cfg" | awk '{print $2}')
|
||||||
@@ -150,8 +151,9 @@ is_launcher_running() {
|
|||||||
|
|
||||||
# ── Agent discovery ────────────────────────────────────────────────────────
|
# ── Agent discovery ────────────────────────────────────────────────────────
|
||||||
# Prints: id|version|enabled|description (one line per agent)
|
# Prints: id|version|enabled|description (one line per agent)
|
||||||
|
# Also scans agents/_specials/ for privileged system agents.
|
||||||
list_agents_raw() {
|
list_agents_raw() {
|
||||||
for cfg in agents/*/config.yaml; do
|
for cfg in agents/*/config.yaml agents/_specials/*/config.yaml; do
|
||||||
[[ -f "$cfg" ]] || continue
|
[[ -f "$cfg" ]] || continue
|
||||||
local id version enabled desc
|
local id version enabled desc
|
||||||
id=$(grep -m1 '^ id:' "$cfg" | awk '{print $2}')
|
id=$(grep -m1 '^ id:' "$cfg" | awk '{print $2}')
|
||||||
|
|||||||
Reference in New Issue
Block a user