feat: use RegisterService + ServiceFor — proper instance lifecycle

- agentic.PrepSubsystem implements Startable/Stoppable
- monitor.Subsystem implements Startable/Stoppable (OnStartup/OnShutdown)
- Register factories use c.RegisterService() — auto-discovers interfaces
- Register factories return instances via Result.Value
- main.go uses ServiceFor[T]() instead of ConfigGet — typed retrieval
- No more c.Config().Set("x.instance") workaround

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-24 17:42:16 +00:00
parent d9e7fa092b
commit adafee0f18
6 changed files with 37 additions and 47 deletions

View file

@ -302,9 +302,9 @@ func main() {
})
// Retrieve service instances from conclave for MCP tool registration
agenticSvc := core.ConfigGet[*agentic.PrepSubsystem](c.Config(), "agentic.instance")
monitorSvc := core.ConfigGet[*monitor.Subsystem](c.Config(), "monitor.instance")
brainSvc := core.ConfigGet[*brain.DirectSubsystem](c.Config(), "brain.instance")
agenticSvc, _ := core.ServiceFor[*agentic.PrepSubsystem](c, "agentic")
monitorSvc, _ := core.ServiceFor[*monitor.Subsystem](c, "monitor")
brainSvc, _ := core.ServiceFor[*brain.DirectSubsystem](c, "brain")
// Process service (lifecycle management)
procFactory := process.NewService(process.Options{})

View file

@ -87,6 +87,17 @@ func (s *PrepSubsystem) SetCore(c *core.Core) {
s.core = c
}
// OnStartup implements core.Startable — starts the queue runner.
func (s *PrepSubsystem) OnStartup(ctx context.Context) error {
s.StartRunner()
return nil
}
// OnShutdown implements core.Stoppable — freezes the queue.
func (s *PrepSubsystem) OnShutdown(ctx context.Context) error {
s.frozen = true
return nil
}
func envOr(key, fallback string) string {
if v := core.Env(key); v != "" {

View file

@ -7,16 +7,8 @@ import (
)
// Register is the service factory for core.WithService.
// It creates the PrepSubsystem, wires Core, registers lifecycle hooks,
// and registers IPC handlers — all during Core construction.
//
// core.New(
// core.WithService(agentic.Register),
// )
// Register is the service factory for core.WithService.
// It creates the PrepSubsystem, wires Core, registers lifecycle hooks,
// and registers IPC handlers — all during Core construction.
// The PrepSubsystem instance is stored in Config for retrieval by MCP.
// Creates the PrepSubsystem, registers it via RegisterService (auto-discovers
// Startable/Stoppable), loads config, and wires IPC handlers.
//
// core.New(
// core.WithService(agentic.Register),
@ -31,21 +23,10 @@ func Register(c *core.Core) core.Result {
c.Config().Set("agents.rates", cfg.Rates)
c.Config().Set("agents.dispatch", cfg.Dispatch)
c.Service("agentic", core.Service{
OnStart: func() core.Result {
prep.StartRunner()
return core.Result{OK: true}
},
OnStop: func() core.Result {
prep.frozen = true
return core.Result{OK: true}
},
})
// Register instance — lifecycle hooks wired via Startable/Stoppable if implemented
c.RegisterService("agentic", prep)
RegisterHandlers(c, prep)
// Store instance for MCP tool registration
c.Config().Set("agentic.instance", prep)
return core.Result{OK: true}
return core.Result{Value: prep, OK: true}
}

View file

@ -7,18 +7,13 @@ import (
)
// Register is the service factory for core.WithService.
// Brain has no lifecycle hooks — it's a stateless API proxy.
// Brain is a stateless API proxy — no lifecycle hooks.
//
// core.New(
// core.WithService(brain.Register),
// )
func Register(c *core.Core) core.Result {
brn := NewDirect()
c.Service("brain", core.Service{})
// Store instance for MCP tool registration
c.Config().Set("brain.instance", brn)
return core.Result{OK: true}
c.RegisterService("brain", brn)
return core.Result{Value: brn, OK: true}
}

View file

@ -251,6 +251,17 @@ func (m *Subsystem) Start(ctx context.Context) {
}()
}
// OnStartup implements core.Startable — starts the monitoring loop.
func (m *Subsystem) OnStartup(ctx context.Context) error {
m.Start(ctx)
return nil
}
// OnShutdown implements core.Stoppable — stops the monitoring loop.
func (m *Subsystem) OnShutdown(ctx context.Context) error {
return m.Shutdown(ctx)
}
// Shutdown stops the monitoring loop and waits for it to exit.
//
// _ = mon.Shutdown(ctx)

View file

@ -8,8 +8,8 @@ import (
)
// Register is the service factory for core.WithService.
// It creates the monitor subsystem, wires Core for IPC,
// and registers lifecycle hooks.
// Creates the monitor subsystem, registers via RegisterService,
// and wires IPC handlers for agent lifecycle events.
//
// core.New(
// core.WithService(monitor.Register),
@ -18,12 +18,7 @@ func Register(c *core.Core) core.Result {
mon := New()
mon.core = c
c.Service("monitor", core.Service{
OnStart: func() core.Result {
mon.Start(c.Context())
return core.Result{OK: true}
},
})
c.RegisterService("monitor", mon)
// Register IPC handler for agent lifecycle events
c.RegisterAction(func(c *core.Core, msg core.Message) core.Result {
@ -36,8 +31,5 @@ func Register(c *core.Core) core.Result {
return core.Result{OK: true}
})
// Store instance for MCP tool registration
c.Config().Set("monitor.instance", mon)
return core.Result{OK: true}
return core.Result{Value: mon, OK: true}
}