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
@@ -1570,3 +1570,94 @@ func TestSaveTownSettings(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestLookupAgentConfigWithRigSettings verifies that lookupAgentConfig checks
|
||||
// rig-level agents first, then town-level agents, then built-ins.
|
||||
func TestLookupAgentConfigWithRigSettings(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rigSettings *RigSettings
|
||||
townSettings *TownSettings
|
||||
expectedCommand string
|
||||
expectedFrom string
|
||||
}{
|
||||
{
|
||||
name: "rig-custom-agent",
|
||||
rigSettings: &RigSettings{
|
||||
Agent: "default-rig-agent",
|
||||
Agents: map[string]*RuntimeConfig{
|
||||
"rig-custom-agent": {
|
||||
Command: "custom-rig-cmd",
|
||||
Args: []string{"--rig-flag"},
|
||||
},
|
||||
},
|
||||
},
|
||||
townSettings: &TownSettings{
|
||||
Agents: map[string]*RuntimeConfig{
|
||||
"town-custom-agent": {
|
||||
Command: "custom-town-cmd",
|
||||
Args: []string{"--town-flag"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCommand: "custom-rig-cmd",
|
||||
expectedFrom: "rig",
|
||||
},
|
||||
{
|
||||
name: "town-custom-agent",
|
||||
rigSettings: &RigSettings{
|
||||
Agents: map[string]*RuntimeConfig{
|
||||
"other-rig-agent": {
|
||||
Command: "other-rig-cmd",
|
||||
},
|
||||
},
|
||||
},
|
||||
townSettings: &TownSettings{
|
||||
Agents: map[string]*RuntimeConfig{
|
||||
"town-custom-agent": {
|
||||
Command: "custom-town-cmd",
|
||||
Args: []string{"--town-flag"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCommand: "custom-town-cmd",
|
||||
expectedFrom: "town",
|
||||
},
|
||||
{
|
||||
name: "unknown-agent",
|
||||
rigSettings: nil,
|
||||
townSettings: nil,
|
||||
expectedCommand: "claude",
|
||||
expectedFrom: "builtin",
|
||||
},
|
||||
{
|
||||
name: "claude",
|
||||
rigSettings: &RigSettings{
|
||||
Agent: "claude",
|
||||
},
|
||||
townSettings: &TownSettings{
|
||||
Agents: map[string]*RuntimeConfig{
|
||||
"claude": {
|
||||
Command: "custom-claude",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCommand: "custom-claude",
|
||||
expectedFrom: "town",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
rc := lookupAgentConfig(tt.name, tt.townSettings, tt.rigSettings)
|
||||
|
||||
if rc == nil {
|
||||
t.Errorf("lookupAgentConfig(%s) returned nil", tt.name)
|
||||
}
|
||||
|
||||
if rc.Command != tt.expectedCommand {
|
||||
t.Errorf("lookupAgentConfig(%s).Command = %s, want %s", tt.name, rc.Command, tt.expectedCommand)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user