304 lines
8.6 KiB
Markdown
304 lines
8.6 KiB
Markdown
# Subagent Orchestration Enhancement
|
|
|
|
This document describes the enhanced Task tool with proper subagent orchestration support using plugin agents.
|
|
|
|
## Overview
|
|
|
|
The Task tool has been enhanced to support a new architecture for spawning and managing specialized subagents. The system now integrates with the plugin system's `AgentDefinition` type, allowing both built-in and plugin-provided agents to be orchestrated.
|
|
|
|
## Key Components
|
|
|
|
### 1. SubagentConfig
|
|
|
|
Configuration structure for spawning subagents:
|
|
|
|
```rust
|
|
pub struct SubagentConfig {
|
|
/// Agent type/name (e.g., "code-reviewer", "explore")
|
|
pub agent_type: String,
|
|
|
|
/// Task prompt for the agent
|
|
pub prompt: String,
|
|
|
|
/// Optional model override
|
|
pub model: Option<String>,
|
|
|
|
/// Tool whitelist (if None, uses agent's default)
|
|
pub tools: Option<Vec<String>>,
|
|
|
|
/// Parsed agent definition (if from plugin)
|
|
pub definition: Option<AgentDefinition>,
|
|
}
|
|
```
|
|
|
|
**Builder Pattern:**
|
|
```rust
|
|
let config = SubagentConfig::new("explore".to_string(), "Find all Rust files".to_string())
|
|
.with_model("claude-3-opus".to_string())
|
|
.with_tools(vec!["read".to_string(), "glob".to_string()]);
|
|
```
|
|
|
|
### 2. SubagentRegistry
|
|
|
|
Thread-safe registry for tracking available agents:
|
|
|
|
```rust
|
|
pub struct SubagentRegistry {
|
|
agents: Arc<RwLock<HashMap<String, AgentDefinition>>>,
|
|
}
|
|
```
|
|
|
|
**Key Methods:**
|
|
|
|
- `new()` - Create empty registry
|
|
- `register_builtin()` - Register built-in agents
|
|
- `register_from_plugins(Vec<AgentDefinition>)` - Register plugin agents
|
|
- `get(name: &str)` - Get agent by name
|
|
- `list()` - List all agents with descriptions
|
|
- `contains(name: &str)` - Check if agent exists
|
|
- `agent_names()` - Get all agent names
|
|
|
|
**Usage:**
|
|
```rust
|
|
let registry = SubagentRegistry::new();
|
|
registry.register_builtin();
|
|
|
|
// Load plugin agents
|
|
let plugin_manager = PluginManager::new();
|
|
plugin_manager.load_all()?;
|
|
let plugin_agents = plugin_manager.load_all_agents();
|
|
registry.register_from_plugins(plugin_agents);
|
|
|
|
// Use registry
|
|
if let Some(agent) = registry.get("explore") {
|
|
println!("Agent: {} - {}", agent.name, agent.description);
|
|
}
|
|
```
|
|
|
|
### 3. Built-in Agents
|
|
|
|
The system includes six specialized built-in agents:
|
|
|
|
#### explore
|
|
- **Purpose:** Codebase exploration
|
|
- **Tools:** read, glob, grep, ls
|
|
- **Color:** blue
|
|
- **Use Cases:** Finding files, understanding structure
|
|
|
|
#### plan
|
|
- **Purpose:** Implementation planning
|
|
- **Tools:** read, glob, grep
|
|
- **Color:** green
|
|
- **Use Cases:** Designing architectures, creating strategies
|
|
|
|
#### code-reviewer
|
|
- **Purpose:** Code analysis
|
|
- **Tools:** read, grep, glob (read-only)
|
|
- **Color:** yellow
|
|
- **Use Cases:** Quality review, bug detection
|
|
|
|
#### test-writer
|
|
- **Purpose:** Test creation
|
|
- **Tools:** read, write, edit, grep, glob
|
|
- **Color:** cyan
|
|
- **Use Cases:** Writing unit tests, integration tests
|
|
|
|
#### doc-writer
|
|
- **Purpose:** Documentation
|
|
- **Tools:** read, write, edit, grep, glob
|
|
- **Color:** magenta
|
|
- **Use Cases:** Writing READMEs, API docs
|
|
|
|
#### refactorer
|
|
- **Purpose:** Code refactoring
|
|
- **Tools:** read, write, edit, grep, glob (no bash)
|
|
- **Color:** red
|
|
- **Use Cases:** Improving structure, applying patterns
|
|
|
|
## Future Implementation
|
|
|
|
The following functions will be implemented to complete the orchestration system:
|
|
|
|
### spawn_subagent
|
|
|
|
```rust
|
|
/// Spawn a subagent with the given configuration
|
|
pub async fn spawn_subagent<P: LlmProvider>(
|
|
provider: &P,
|
|
registry: &SubagentRegistry,
|
|
config: SubagentConfig,
|
|
perms: &PermissionManager,
|
|
) -> Result<String>
|
|
```
|
|
|
|
**Behavior:**
|
|
1. Look up agent definition from registry or config
|
|
2. Extract system prompt and tool whitelist from definition
|
|
3. Build full prompt combining system prompt + task
|
|
4. Create filtered permission manager if tool whitelist specified
|
|
5. Run agent loop with system prompt
|
|
6. Return result string
|
|
|
|
### spawn_parallel
|
|
|
|
```rust
|
|
/// Spawn multiple subagents in parallel and collect results
|
|
pub async fn spawn_parallel<P: LlmProvider + Clone>(
|
|
provider: &P,
|
|
registry: &SubagentRegistry,
|
|
configs: Vec<SubagentConfig>,
|
|
perms: &PermissionManager,
|
|
) -> Vec<Result<String>>
|
|
```
|
|
|
|
**Behavior:**
|
|
1. Create futures for each config
|
|
2. Execute all in parallel using `join_all`
|
|
3. Return vector of results
|
|
|
|
**Note:** Requires `PermissionManager` to implement `Clone`. This may need to be added to the permissions crate.
|
|
|
|
## Integration Points
|
|
|
|
### With Plugin System
|
|
|
|
```rust
|
|
use plugins::PluginManager;
|
|
use tools_task::SubagentRegistry;
|
|
|
|
let mut plugin_manager = PluginManager::new();
|
|
plugin_manager.load_all()?;
|
|
|
|
let registry = SubagentRegistry::new();
|
|
registry.register_builtin();
|
|
registry.register_from_plugins(plugin_manager.load_all_agents());
|
|
```
|
|
|
|
### With Agent Core
|
|
|
|
The subagent execution will integrate with `agent-core` by:
|
|
1. Calling the same `run_agent_loop` function used by main agent
|
|
2. Passing filtered tool definitions based on agent's tool whitelist
|
|
3. Using agent-specific system prompts
|
|
4. Inheriting parent's permission manager (or creating restricted copy)
|
|
|
|
### With Permission System
|
|
|
|
Subagents respect the permission system:
|
|
- Tool whitelist from agent definition restricts available tools
|
|
- Permission manager checks are still applied
|
|
- Parent's mode (plan/acceptEdits/code) is inherited
|
|
|
|
## Example Usage Patterns
|
|
|
|
### Basic Exploration
|
|
|
|
```rust
|
|
let registry = SubagentRegistry::new();
|
|
registry.register_builtin();
|
|
|
|
let config = SubagentConfig::new(
|
|
"explore".to_string(),
|
|
"Find all test files in the codebase".to_string()
|
|
);
|
|
|
|
let result = spawn_subagent(&provider, ®istry, config, &perms).await?;
|
|
println!("Found files:\n{}", result);
|
|
```
|
|
|
|
### Parallel Analysis
|
|
|
|
```rust
|
|
let configs = vec![
|
|
SubagentConfig::new("explore".to_string(), "Find all Rust files".to_string()),
|
|
SubagentConfig::new("code-reviewer".to_string(), "Review auth module".to_string()),
|
|
SubagentConfig::new("test-writer".to_string(), "Check test coverage".to_string()),
|
|
];
|
|
|
|
let results = spawn_parallel(&provider, ®istry, configs, &perms).await;
|
|
|
|
for (i, result) in results.iter().enumerate() {
|
|
match result {
|
|
Ok(output) => println!("Agent {} completed:\n{}", i, output),
|
|
Err(e) => eprintln!("Agent {} failed: {}", i, e),
|
|
}
|
|
}
|
|
```
|
|
|
|
### Custom Plugin Agent
|
|
|
|
```rust
|
|
// Plugin provides custom-analyzer agent
|
|
let config = SubagentConfig::new(
|
|
"custom-analyzer".to_string(),
|
|
"Analyze security vulnerabilities".to_string()
|
|
);
|
|
|
|
if registry.contains("custom-analyzer") {
|
|
let result = spawn_subagent(&provider, ®istry, config, &perms).await?;
|
|
} else {
|
|
eprintln!("Agent not found. Available: {:?}", registry.agent_names());
|
|
}
|
|
```
|
|
|
|
## Migration Guide
|
|
|
|
### From Legacy Subagent API
|
|
|
|
The legacy `Subagent` struct and keyword-based matching is still available for backward compatibility:
|
|
|
|
```rust
|
|
// Legacy API (still works)
|
|
let agent = Subagent::new(
|
|
"reader".to_string(),
|
|
"Read-only agent".to_string(),
|
|
vec!["read".to_string()],
|
|
vec![Tool::Read, Tool::Grep],
|
|
);
|
|
```
|
|
|
|
**Migrate to new API:**
|
|
1. Use `SubagentRegistry` instead of custom keyword matching
|
|
2. Use `SubagentConfig` instead of direct agent instantiation
|
|
3. Use `spawn_subagent` instead of manual tool execution
|
|
|
|
## Testing
|
|
|
|
Run tests:
|
|
```bash
|
|
cargo test -p tools-task
|
|
```
|
|
|
|
All tests pass, including:
|
|
- Registry builtin registration
|
|
- Plugin agent registration
|
|
- Config builder pattern
|
|
- Legacy API backward compatibility
|
|
|
|
## Dependencies
|
|
|
|
- `plugins` - For `AgentDefinition` type
|
|
- `parking_lot` - For `RwLock` in thread-safe registry
|
|
- `permissions` - For tool permission checks
|
|
- `color-eyre` - For error handling
|
|
- `serde` / `serde_json` - For serialization
|
|
|
|
## Future Work
|
|
|
|
1. **Implement spawn_subagent:** Complete the actual subagent spawning logic
|
|
2. **Add Clone to PermissionManager:** Required for parallel execution
|
|
3. **System Prompt Support:** Ensure agent loop respects system prompts
|
|
4. **Tool Filtering:** Implement filtered tool definitions based on whitelist
|
|
5. **Progress Tracking:** Add hooks for monitoring subagent progress
|
|
6. **Error Recovery:** Handle subagent failures gracefully
|
|
7. **Resource Limits:** Add timeout and resource constraints
|
|
8. **Inter-Agent Communication:** Allow agents to share context
|
|
|
|
## Related Files
|
|
|
|
- `/home/cnachtigall/data/git/projects/Owlibou/owlen/crates/tools/task/src/lib.rs` - Main implementation
|
|
- `/home/cnachtigall/data/git/projects/Owlibou/owlen/crates/tools/task/Cargo.toml` - Dependencies
|
|
- `/home/cnachtigall/data/git/projects/Owlibou/owlen/crates/platform/plugins/src/lib.rs` - AgentDefinition type
|
|
- `/home/cnachtigall/data/git/projects/Owlibou/owlen/crates/core/agent/src/lib.rs` - Agent execution loop
|
|
- `/home/cnachtigall/data/git/projects/Owlibou/owlen/crates/platform/permissions/src/lib.rs` - Permission system
|