feat: Add rig-level custom agent support (#12)
* feat: Add rig-level custom agent support Implement rig-level custom agent configuration support to enable per-rig agent definitions in <rig>/settings/config.json, following the same pattern as town-level agents in settings/config.json. Changes: - Added RigSettings.Agents field to internal/config/types.go - Added DefaultRigAgentRegistryPath() and LoadRigAgentRegistry() functions to internal/config/agents.go - Updated ResolveAgentConfigWithOverride() to accept and pass rigSettings parameter - Updated GetRuntimeCommandWithAgentOverride() to use rigSettings when available - Updated GetRuntimeCommandWithPromptAndAgentOverride() to use rigSettings - Updated all Build*WithOverride functions to pass rigSettings This fixes the issue where rig-level agent settings were loaded but ignored by lookupAgentConfig, enabling per-rig custom agents for polecats and crew members. * test: Add rig-level custom agent tests Added comprehensive unit tests for rig agent registry functions: - TestDefaultRigAgentRegistryPath: verifies path construction - TestLoadRigAgentRegistry: verifies file loading and JSON parsing - TestLookupAgentConfigWithRigSettings: verifies agent lookup priority (rig > town > builtin) Added placeholder integration test for future CI/CD setup. * initial commit * fix: resolve compilation errors in rig-level custom agent support - Add missing RigAgentRegistryPath function (alias for DefaultRigAgentRegistryPath) - Restore ResolveAgentConfigWithOverride function that was incorrectly removed - Fix ResolveAgentConfig to return single value (not triple) - Add initRegistryLocked() call to LoadRigAgentRegistry to prevent nil panic - Fix DefaultRigAgentRegistryPath to use rigPath directly (not parent dir) - Fix test file syntax errors (remove EOF artifacts) - Fix test parameter order for lookupAgentConfig calls - Fix test expectations to match correct custom agent override behavior * test: implement rig-level custom agent integration test - Add stub agent script that simulates AI agent with Q&A capability - Test ResolveAgentConfig correctly picks up rig-level agents - Test BuildPolecatStartupCommand includes custom agent command - Test ResolveAgentConfigWithOverride respects rig agents - Test rig agents override town agents with same name - Add tmux integration test that spawns session and verifies output - Stub agent echoes 'STUB_AGENT_STARTED' and handles ping/pong Q&A - All tests pass including real tmux session verification * docs: add OpenCode custom agent example to reference - Show settings/agents.json format for advanced configs - Include OpenCode example with session resume flags - Document OPENCODE_PERMISSION env var for autonomous mode * fix: improve rig-level agent support with docs and test fixes - Add rig-level agent documentation to reference.md - Document agent resolution order (rig → town → built-in) - Deduplicate LoadAgentRegistry/LoadRigAgentRegistry into shared helper - Fix test isolation in TestLoadRigAgentRegistry - Fix nil pointer dereference in test assertions (use t.Fatal not t.Error)
This commit is contained in:
committed by
Steve Yegge
parent
2de2d6b7e4
commit
00a59dec44
@@ -824,6 +824,9 @@ func ResolveAgentConfig(townRoot, rigPath string) *RuntimeConfig {
|
||||
// Load custom agent registry if it exists
|
||||
_ = LoadAgentRegistry(DefaultAgentRegistryPath(townRoot))
|
||||
|
||||
// Load rig-level custom agent registry if it exists (for per-rig custom agents)
|
||||
_ = LoadRigAgentRegistry(RigAgentRegistryPath(rigPath))
|
||||
|
||||
// Determine which agent name to use
|
||||
agentName := ""
|
||||
if rigSettings != nil && rigSettings.Agent != "" {
|
||||
@@ -834,8 +837,7 @@ func ResolveAgentConfig(townRoot, rigPath string) *RuntimeConfig {
|
||||
agentName = "claude" // ultimate fallback
|
||||
}
|
||||
|
||||
// Look up the agent configuration
|
||||
return lookupAgentConfig(agentName, townSettings)
|
||||
return lookupAgentConfig(agentName, townSettings, rigSettings)
|
||||
}
|
||||
|
||||
// ResolveAgentConfigWithOverride resolves the agent configuration for a rig, with an optional override.
|
||||
@@ -864,6 +866,9 @@ func ResolveAgentConfigWithOverride(townRoot, rigPath, agentOverride string) (*R
|
||||
// Load custom agent registry if it exists
|
||||
_ = LoadAgentRegistry(DefaultAgentRegistryPath(townRoot))
|
||||
|
||||
// Load rig-level custom agent registry if it exists (for per-rig custom agents)
|
||||
_ = LoadRigAgentRegistry(RigAgentRegistryPath(rigPath))
|
||||
|
||||
// Determine which agent name to use
|
||||
agentName := ""
|
||||
if agentOverride != "" {
|
||||
@@ -876,13 +881,21 @@ func ResolveAgentConfigWithOverride(townRoot, rigPath, agentOverride string) (*R
|
||||
agentName = "claude" // ultimate fallback
|
||||
}
|
||||
|
||||
// If an override is requested, validate it exists.
|
||||
// If an override is requested, validate it exists
|
||||
if agentOverride != "" {
|
||||
// Check rig-level custom agents first
|
||||
if rigSettings != nil && rigSettings.Agents != nil {
|
||||
if custom, ok := rigSettings.Agents[agentName]; ok && custom != nil {
|
||||
return fillRuntimeDefaults(custom), agentName, nil
|
||||
}
|
||||
}
|
||||
// Then check town-level custom agents
|
||||
if townSettings.Agents != nil {
|
||||
if custom, ok := townSettings.Agents[agentName]; ok && custom != nil {
|
||||
return fillRuntimeDefaults(custom), agentName, nil
|
||||
}
|
||||
}
|
||||
// Then check built-in presets
|
||||
if preset := GetAgentPresetByName(agentName); preset != nil {
|
||||
return RuntimeConfigFromPreset(AgentPreset(agentName)), agentName, nil
|
||||
}
|
||||
@@ -890,13 +903,20 @@ func ResolveAgentConfigWithOverride(townRoot, rigPath, agentOverride string) (*R
|
||||
}
|
||||
|
||||
// Normal lookup path (no override)
|
||||
return lookupAgentConfig(agentName, townSettings), agentName, nil
|
||||
return lookupAgentConfig(agentName, townSettings, rigSettings), agentName, nil
|
||||
}
|
||||
|
||||
// lookupAgentConfig looks up an agent by name.
|
||||
// First checks town's custom agents, then built-in presets from agents.go.
|
||||
func lookupAgentConfig(name string, townSettings *TownSettings) *RuntimeConfig {
|
||||
// First check town's custom agents
|
||||
// Checks rig-level custom agents first, then town's custom agents, then built-in presets from agents.go.
|
||||
func lookupAgentConfig(name string, townSettings *TownSettings, rigSettings *RigSettings) *RuntimeConfig {
|
||||
// First check rig's custom agents (NEW - fix for rig-level agent support)
|
||||
if rigSettings != nil && rigSettings.Agents != nil {
|
||||
if custom, ok := rigSettings.Agents[name]; ok && custom != nil {
|
||||
return fillRuntimeDefaults(custom)
|
||||
}
|
||||
}
|
||||
|
||||
// Then check town's custom agents (existing)
|
||||
if townSettings != nil && townSettings.Agents != nil {
|
||||
if custom, ok := townSettings.Agents[name]; ok && custom != nil {
|
||||
return fillRuntimeDefaults(custom)
|
||||
|
||||
Reference in New Issue
Block a user