feat: M7 Elfs — sub-agents with router-integrated spawning

internal/elf/:
- BackgroundElf: runs on own goroutine with independent engine,
  history, and provider. No shared mutable state.
- Manager: spawns elfs via router.Select() (picks best arm per
  task type), tracks lifecycle, WaitAll(), CancelAll(), Cleanup().

internal/tool/agent/:
- Agent tool: LLM can call 'agent' to spawn sub-agents.
  Supports task_type hint for routing, wait/background mode.
  5-minute timeout, context cancellation propagated.

Concurrent tool execution:
- Read-only tools (fs.read, fs.grep, fs.glob, etc.) execute in
  parallel via goroutines.
- Write tools (bash, fs.write, fs.edit) execute sequentially.
- Partition by tool.IsReadOnly().

TUI: /elf command explains how to use sub-agents.
5 elf tests. Exit criteria: parent spawns 3 background elfs on
different providers, collects and synthesizes results.
This commit is contained in:
2026-04-03 19:16:46 +02:00
parent ec9a918da9
commit 07c739795c
7 changed files with 826 additions and 54 deletions
+13
View File
@@ -29,6 +29,8 @@ import (
"somegit.dev/Owlibou/gnoma/internal/tui"
tea "charm.land/bubbletea/v2"
"somegit.dev/Owlibou/gnoma/internal/elf"
"somegit.dev/Owlibou/gnoma/internal/tool/agent"
"somegit.dev/Owlibou/gnoma/internal/tool/bash"
"somegit.dev/Owlibou/gnoma/internal/tool/fs"
"somegit.dev/Owlibou/gnoma/internal/tool/sysinfo"
@@ -141,6 +143,9 @@ func main() {
// Register system_info tool backed by the inventory
reg.Register(sysinfo.New(inventory))
// Elf manager (created now, agent tool registered after router exists)
// We'll register the agent tool after the router is created below
// Create router and register the provider as a single arm
// (M4 foundation: one provider from CLI. Multi-provider routing comes with config.)
rtr := router.New(router.Config{Logger: logger})
@@ -174,6 +179,14 @@ func main() {
logger.Debug("local models discovered", "count", len(localModels))
}
// Create elf manager and register agent tool
elfMgr := elf.NewManager(elf.ManagerConfig{
Router: rtr,
Tools: reg,
Logger: logger,
})
reg.Register(agent.New(elfMgr))
// Create firewall
fw := security.NewFirewall(security.FirewallConfig{
ScanOutgoing: true,