feat(api): per-agent unified control + clear_memory + delete_cache
- Manager: RegisterUnifiedAgent/UnregisterUnifiedAgent/StopUnifiedAgent/
IsUnifiedAgentRunning/UptimeSeconds — cancela goroutines individuales sin
matar el launcher
- Manager: UptimeSeconds en AgentStatus via startedAt map
- api/server: AgentController interface + WithController/WithDataDir builders
+ rutas POST /agents/{id}/clear_memory y /agents/{id}/delete_cache
- api/handlers: handleStartAgent/Stop/Restart delegan a controller en modo
unified; Messages24h enriquecido via queryMessages24h (cache 30s)
- api/handlers: handleClearMemory — para la goroutine, borra messages+facts de
memory.db, responde {status,messages_deleted,facts_deleted}
- api/handlers: handleDeleteCache — para la goroutine, elimina crypto/ y cache/,
responde {status,paths_deleted}
- launcher/registry: launchGoroutine extrae goroutine con contexto per-agente;
deps.procMgr hookea RegisterUnified; startAgent permite relanzar via reload
- launcher/main: agentController implementa api.AgentController sobre registry;
mgr compartido entre API y registry; WithController+WithDataDir cableados
Co-Authored-By: fn-orquestador <noreply@fn-registry>
This commit is contained in:
+33
-10
@@ -116,14 +116,18 @@ func main() {
|
||||
logger.Info("orchestrator initialized")
|
||||
}
|
||||
|
||||
// ── Process manager (shared: API reflection + per-agent goroutine hooks) ──
|
||||
mgr := newProcessManager(logDir)
|
||||
|
||||
// ── Shared dependencies for agent registry ──
|
||||
deps := &launchDeps{
|
||||
agentBus: agentBus,
|
||||
orch: orch,
|
||||
logDir: logDir,
|
||||
logLevel: lvl,
|
||||
parentCtx: ctx,
|
||||
secPolicy: secPolicy,
|
||||
agentBus: agentBus,
|
||||
orch: orch,
|
||||
logDir: logDir,
|
||||
logLevel: lvl,
|
||||
parentCtx: ctx,
|
||||
secPolicy: secPolicy,
|
||||
procMgr: mgr,
|
||||
}
|
||||
registry := newAgentRegistry(deps)
|
||||
|
||||
@@ -281,10 +285,11 @@ func main() {
|
||||
if key == "" {
|
||||
logger.Warn("api-port set but AGENTS_API_KEY is empty — HTTP API disabled (set AGENTS_API_KEY in .env)")
|
||||
} else {
|
||||
// Build a process.Manager that reflects the live launcher state.
|
||||
// The manager uses run/ for PID files and agents/*/config.yaml for discovery.
|
||||
mgr := newProcessManager(logDir)
|
||||
srv := api.New(mgr, key, apiPort, logger)
|
||||
// mgr already created above; share it between API and registry.
|
||||
ctrl := &agentController{reg: registry, mgr: mgr}
|
||||
srv := api.New(mgr, key, apiPort, logger).
|
||||
WithController(ctrl).
|
||||
WithDataDir("agents")
|
||||
go func() {
|
||||
if err := srv.Run(ctx); err != nil {
|
||||
logger.Error("api server stopped", "err", err)
|
||||
@@ -400,6 +405,24 @@ func newProcessManager(logDir string) *process.Manager {
|
||||
return process.NewManager("run", "agents/*/config.yaml", "bin/launcher")
|
||||
}
|
||||
|
||||
// agentController adapts agentRegistry + process.Manager to the api.AgentController
|
||||
// interface, allowing the HTTP API to start/stop individual agent goroutines without
|
||||
// restarting the whole launcher process.
|
||||
type agentController struct {
|
||||
reg *agentRegistry
|
||||
mgr *process.Manager
|
||||
}
|
||||
|
||||
// StopUnifiedAgent cancels the per-agent goroutine context without stopping the launcher.
|
||||
func (c *agentController) StopUnifiedAgent(id string) error {
|
||||
return c.mgr.StopUnifiedAgent(id)
|
||||
}
|
||||
|
||||
// StartUnifiedAgent re-launches the agent goroutine for the given ID.
|
||||
func (c *agentController) StartUnifiedAgent(id string) error {
|
||||
return c.reg.startAgent(id, rulesFor)
|
||||
}
|
||||
|
||||
// isSpecialConfig checks whether a config path belongs to a middleware special
|
||||
// (e.g. orchestrator) by detecting a "special:" top-level key with a non-empty
|
||||
// id. This avoids config.Load() failing with "agent.id is required" when the
|
||||
|
||||
Reference in New Issue
Block a user