feat: desacoplar launcher del registro estatico de agentes
Introduce un registro global de reglas en agents/registry.go con Register() y GetRules(). Cada paquete de agente se auto-registra via init(), eliminando la necesidad de editar manualmente el map rulesRegistry en cmd/launcher/main.go. Cambios: - agents/registry.go: nuevo registro global con sync.RWMutex - agents/*/agent.go: cada agente llama agents.Register() en init() - agents/_template/agent.go: placeholder AGENT_ID_PLACEHOLDER para scaffold - cmd/launcher/main.go: elimina rulesRegistry, usa blank imports + agents.GetRules() para obtener reglas por agent ID Patron: init() + blank import (estandar Go: database/sql, image codecs) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,16 @@
|
|||||||
// Package _template es un agente plantilla (no lanzable).
|
// Package _template es un agente plantilla (no lanzable).
|
||||||
// Sirve como referencia canonica para crear nuevos agentes.
|
// Sirve como referencia canonica para crear nuevos agentes.
|
||||||
|
// Al crear un nuevo agente, new-agent.sh reemplaza _template y AGENT_ID_PLACEHOLDER.
|
||||||
package _template
|
package _template
|
||||||
|
|
||||||
import "github.com/enmanuel/agents/pkg/decision"
|
import (
|
||||||
|
"github.com/enmanuel/agents/agents"
|
||||||
|
"github.com/enmanuel/agents/pkg/decision"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
agents.Register("AGENT_ID_PLACEHOLDER", Rules)
|
||||||
|
}
|
||||||
|
|
||||||
// Rules devuelve las reglas de este agente (vacio para el template).
|
// Rules devuelve las reglas de este agente (vacio para el template).
|
||||||
func Rules() []decision.Rule {
|
func Rules() []decision.Rule {
|
||||||
|
|||||||
@@ -3,9 +3,14 @@
|
|||||||
package asistente2
|
package asistente2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/enmanuel/agents/agents"
|
||||||
"github.com/enmanuel/agents/pkg/decision"
|
"github.com/enmanuel/agents/pkg/decision"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
agents.Register("asistente-2", Rules)
|
||||||
|
}
|
||||||
|
|
||||||
// Rules returns the decision rules for the asistente-2 bot.
|
// Rules returns the decision rules for the asistente-2 bot.
|
||||||
// Note: !help is now handled by the built-in command system.
|
// Note: !help is now handled by the built-in command system.
|
||||||
func Rules() []decision.Rule {
|
func Rules() []decision.Rule {
|
||||||
|
|||||||
@@ -3,9 +3,14 @@
|
|||||||
package assistant
|
package assistant
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/enmanuel/agents/agents"
|
||||||
"github.com/enmanuel/agents/pkg/decision"
|
"github.com/enmanuel/agents/pkg/decision"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
agents.Register("assistant-bot", Rules)
|
||||||
|
}
|
||||||
|
|
||||||
// Rules returns the decision rules for the assistant bot.
|
// Rules returns the decision rules for the assistant bot.
|
||||||
// Note: !help is now handled by the built-in command system.
|
// Note: !help is now handled by the built-in command system.
|
||||||
func Rules() []decision.Rule {
|
func Rules() []decision.Rule {
|
||||||
|
|||||||
@@ -3,9 +3,14 @@
|
|||||||
package meteorologo
|
package meteorologo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/enmanuel/agents/agents"
|
||||||
"github.com/enmanuel/agents/pkg/decision"
|
"github.com/enmanuel/agents/pkg/decision"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
agents.Register("meteorologo", Rules)
|
||||||
|
}
|
||||||
|
|
||||||
// Rules returns the decision rules for the meteorologo bot.
|
// Rules returns the decision rules for the meteorologo bot.
|
||||||
func Rules() []decision.Rule {
|
func Rules() []decision.Rule {
|
||||||
return []decision.Rule{
|
return []decision.Rule{
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// Package agents provides a global registry for agent rule factories.
|
||||||
|
//
|
||||||
|
// Each agent package self-registers via init() using Register.
|
||||||
|
// The launcher retrieves rules via GetRules without importing agent
|
||||||
|
// packages explicitly (only blank imports are needed).
|
||||||
|
package agents
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/enmanuel/agents/pkg/decision"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RulesFunc is a factory that returns the decision rules for an agent.
|
||||||
|
type RulesFunc func() []decision.Rule
|
||||||
|
|
||||||
|
var (
|
||||||
|
registryMu sync.RWMutex
|
||||||
|
registry = make(map[string]RulesFunc)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Register adds a rule factory for the given agent ID.
|
||||||
|
// Intended to be called from init() in each agent package.
|
||||||
|
// Panics if the same ID is registered twice (catches copy-paste errors early).
|
||||||
|
func Register(id string, fn RulesFunc) {
|
||||||
|
registryMu.Lock()
|
||||||
|
defer registryMu.Unlock()
|
||||||
|
|
||||||
|
if _, exists := registry[id]; exists {
|
||||||
|
panic("agents.Register: duplicate agent id: " + id)
|
||||||
|
}
|
||||||
|
registry[id] = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRules returns the rule factory for the given agent ID.
|
||||||
|
// Returns nil if no rules are registered (the agent is command-only).
|
||||||
|
func GetRules(id string) RulesFunc {
|
||||||
|
registryMu.RLock()
|
||||||
|
defer registryMu.RUnlock()
|
||||||
|
return registry[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisteredIDs returns a sorted list of all registered agent IDs.
|
||||||
|
// Useful for debugging and diagnostics.
|
||||||
|
func RegisteredIDs() []string {
|
||||||
|
registryMu.RLock()
|
||||||
|
defer registryMu.RUnlock()
|
||||||
|
|
||||||
|
ids := make([]string, 0, len(registry))
|
||||||
|
for id := range registry {
|
||||||
|
ids = append(ids, id)
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
// resetRegistry clears all registrations (for testing only).
|
||||||
|
func resetRegistry() {
|
||||||
|
registryMu.Lock()
|
||||||
|
defer registryMu.Unlock()
|
||||||
|
registry = make(map[string]RulesFunc)
|
||||||
|
}
|
||||||
+11
-14
@@ -20,9 +20,6 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/enmanuel/agents/agents"
|
"github.com/enmanuel/agents/agents"
|
||||||
assistantagent "github.com/enmanuel/agents/agents/assistant-bot"
|
|
||||||
asistente2agent "github.com/enmanuel/agents/agents/asistente-2"
|
|
||||||
meteorologoagent "github.com/enmanuel/agents/agents/meteorologo"
|
|
||||||
"github.com/enmanuel/agents/internal/config"
|
"github.com/enmanuel/agents/internal/config"
|
||||||
"github.com/enmanuel/agents/pkg/decision"
|
"github.com/enmanuel/agents/pkg/decision"
|
||||||
"github.com/enmanuel/agents/pkg/orchestration"
|
"github.com/enmanuel/agents/pkg/orchestration"
|
||||||
@@ -31,15 +28,12 @@ import (
|
|||||||
agentlog "github.com/enmanuel/agents/shell/logger"
|
agentlog "github.com/enmanuel/agents/shell/logger"
|
||||||
orchshell "github.com/enmanuel/agents/shell/orchestration"
|
orchshell "github.com/enmanuel/agents/shell/orchestration"
|
||||||
shellsecurity "github.com/enmanuel/agents/shell/security"
|
shellsecurity "github.com/enmanuel/agents/shell/security"
|
||||||
)
|
|
||||||
|
|
||||||
// rulesRegistry maps agent IDs to their rule factories.
|
// Blank imports: each agent self-registers its rules via init().
|
||||||
// Add a new entry here when you create a new agent package.
|
_ "github.com/enmanuel/agents/agents/assistant-bot"
|
||||||
var rulesRegistry = map[string]func() []decision.Rule{
|
_ "github.com/enmanuel/agents/agents/asistente-2"
|
||||||
"assistant-bot": assistantagent.Rules,
|
_ "github.com/enmanuel/agents/agents/meteorologo"
|
||||||
"asistente-2": asistente2agent.Rules,
|
)
|
||||||
"meteorologo": meteorologoagent.Rules,
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var (
|
var (
|
||||||
@@ -289,10 +283,13 @@ func startOrchestrator(agentBus *bus.Bus, logger *slog.Logger) (*orchHandle, err
|
|||||||
return &orchHandle{orchestrator: orch, cfg: cfg}, nil
|
return &orchHandle{orchestrator: orch, cfg: cfg}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rulesFor retrieves the rule factory for the given agent ID from the
|
||||||
|
// global registry (populated by init() in each agent package).
|
||||||
|
// Returns nil if no rules are registered (command-only bot).
|
||||||
func rulesFor(agentID string, logger *slog.Logger) []decision.Rule {
|
func rulesFor(agentID string, logger *slog.Logger) []decision.Rule {
|
||||||
factory, ok := rulesRegistry[agentID]
|
factory := agents.GetRules(agentID)
|
||||||
if !ok {
|
if factory == nil {
|
||||||
logger.Warn("no rules registered for agent, using empty ruleset", "id", agentID)
|
logger.Warn("no rules registered for agent, using empty ruleset (command-only)", "id", agentID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return factory()
|
return factory()
|
||||||
|
|||||||
Reference in New Issue
Block a user