Dynamically fork sub-agents at any step based on task requirements instead of using fixed agent counts. Linearize hierarchical trajectories into unified sequences for GRPO training. Demonstrates 6.36x more sub-agents than baselines via learned orchestration.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Dynamically fork sub-agents at any step based on task requirements instead of using fixed agent counts. Linearize hierarchical trajectories into unified sequences for GRPO training. Demonstrates 6.36x more sub-agents than baselines via learned orchestration.
WideSeek: Breadth Scaling via Dynamic Multi-Agent Forking
Traditional multi-agent systems use fixed agent counts, but task complexity varies: some steps need multiple exploratory agents, others work fine with a single path. WideSeek enables dynamic agent forking—the main agent autonomously creates variable numbers of sub-agents at each step. This is trained end-to-end via GRPO by linearizing hierarchical execution traces into single unified sequences.
The key insight is that agent forking is itself a learnable skill. By treating multi-agent trajectories as extended single sequences, WideSeek applies standard policy optimization to learn when and how many agents to spawn.
Core Concept
WideSeek operates on two principles:
Dynamic Agent Forking: Main agent can call call_subagent(task) any number of times, creating sub-agents on-demand to parallelize work.
Unified Trajectory Training: All agent trajectories (main + sub-agents) are linearized into a single sequence, then optimized with GRPO as if from one agent.
This unifies multi-agent coordination with policy optimization.
Architecture Overview
Main Agent: Orchestrates task decomposition; can fork sub-agents dynamically
Sub-Agent Pool: Execute assigned subtasks in parallel with isolated contexts
Trajectory Linearization: Convert tree of agent decisions into linear sequence
GRPO Optimizer: Standard group relative policy optimization on linearized trajectories
Shared Model: Single LLM backbone for all agents (main and sub)
Tool Restrictions: Sub-agents have subset of main agent's tools (e.g., search, no forking)
Implementation
Step 1: Design Agent Forking Interface
Create the tool that allows dynamic sub-agent creation.
"""
Create and return a new sub-agent.
Args:
subtask: Specific task for sub-agent
tools: Available tools for sub-agent
parent_context: Context from parent agent
Returns:
Sub-agent instance
"""
if
not
self
return
None
self
1
self
1
self
return
class
SubAgent
def
__init__
self, task: str, available_tools: List[str],
context: str, depth: int
"""Lightweight sub-agent for specific subtask."""
self
self
self
self
self
self
None
def
execute
self, model
str
"""Execute subtask and return result."""
# Construct prompt with restricted tools
f"""You are a sub-agent working on: {self.task}
Available tools: {', '.join(self.available_tools)}
Note: You cannot fork new agents. Complete this task and report result.
Context: {self.context}"""
0.7
512
self
"type"
"thought"
"content"
self
return
Step 2: Implement Trajectory Linearization
Convert multi-agent tree execution into linear sequence for GRPO.
# Trajectory linearizationclassTrajectoryLinearizer:
def__init__(self):
"""Convert hierarchical agent executions to linear sequences."""self.linearized = []
deflinearize_execution(self, main_trajectory: List[dict],
subagent_trajectories: Dict[int, List[dict]]) -> List[dict]:
"""
Convert tree of agent trajectories into single linear sequence.
Args:
main_trajectory: Main agent's thought/action sequence
subagent_trajectories: Dict mapping agent_id to trajectory
Returns:
Single linearized trajectory for GRPO
"""
linearized = []
# Add main agent thoughtsfor step in main_trajectory:
if step.get("type") == "thought":
linearized.append({
"agent": "main",
"content": step["content"],
"type": "thought"
})
elif step.get("type") == "fork":
# Record fork decision
fork_id = step.get("fork_id")
task = step.get("task")
linearized.append({
"agent": "main",
"content": f"[FORK {fork_id}: {task}]",
"type": "fork"
})
# Append sub-agent trajectory inlineif fork_id in subagent_trajectories:
for substep in subagent_trajectories[fork_id]:
linearized.append({
"agent": f"sub_{fork_id}",
"content": substep.get("content"),
"type": "thought"
})
# Record sub-agent result
result = step.get("result")
linearized.append({
"agent": f"sub_{fork_id}",
"content": f"[RESULT: {result}]",
"type": "result"
})
elif step.get("type") == "action":
linearized.append({
"agent": "main",
"content": step["content"],
"type": "action"
})
return linearized
defcompute_sequence_loss(self, linearized: List[dict],
logits: torch.Tensor) -> torch.Tensor:
"""
Compute loss for linearized sequence (for gradient updates).
Args:
linearized: Linearized trajectory
logits: Model logits for each token
Returns:
Loss tensor
"""# Standard language modeling loss on flattened sequence
loss = torch.nn.functional.cross_entropy(
logits.view(-1, logits.shape[-1]),
self._tokenize_trajectory(linearized).view(-1)
)
return loss
def_tokenize_trajectory(self, linearized: List[dict]) -> torch.Tensor:
"""Convert trajectory to token IDs."""
text = " ".join([step["content"] for step in linearized])
# Pseudo-code: actual implementation uses model's tokenizerreturn torch.tensor([])
Step 3: Implement GRPO Training for Multi-Agent Trajectories
Extend GRPO to optimize linearized multi-agent sequences.
# Multi-agent GRPO trainingdeftrain_multi_agent_grpo(
model: nn.Module,
dataset: List[dict],
num_epochs: int = 10,
group_size: int = 4,
max_agents: int = 8):
"""
Train model with dynamic agent forking via GRPO.
Args:
model: Shared backbone for all agents
dataset: Tasks to solve
num_epochs: Training epochs
group_size: GRPO group size
max_agents: Max sub-agents per task
"""
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-5)
for epoch inrange(num_epochs):
# Group tasks for GRPOfor group_idx inrange(0, len(dataset), group_size):
group = dataset[group_idx:group_idx + group_size]
group_rewards = []
trajectories = []
for task in group:
# Execute main agent (with dynamic forking)
main_agent = Agent(
task=task["description"],
can_fork=True,
max_agents=max_agents
)
# Main agent execution: may fork sub-agents
main_trajectory, subagent_trajectories = main_agent.execute(model)
# Linearize for GRPO
linearizer = TrajectoryLinearizer()
linearized = linearizer.linearize_execution(
main_trajectory,
subagent_trajectories
)
# Evaluate final result
final_output = main_agent.result
reward = evaluate_solution(final_output, task["target"])
group_rewards.append(reward)
trajectories.append((linearized, reward))
# GRPO: compute advantages and update
group_tensor = torch.tensor(group_rewards, dtype=torch.float32)
group_mean = group_tensor.mean()
for linearized, reward in trajectories:
advantage = reward - group_mean
if advantage != 0:
# Compute loss on linearized trajectory
logits = model.forward(linearized)
loss = linearizer.compute_sequence_loss(linearized, logits)
# Scale by advantage
scaled_loss = loss * advantage
scaled_loss.backward()
optimizer.step()
optimizer.zero_grad()
print(f"Epoch {epoch}: avg_reward={group_tensor.mean():.4f}")
return model
classAgent:
def__init__(self, task: str, can_fork: bool = True,
max_agents: int = 8):
"""Main agent with optional forking."""self.task = task
self.can_fork = can_fork
self.max_agents = max_agents
self.trajectory = []
self.subagent_trajectories = {}
self.result = Noneself.fork_count = 0defexecute(self, model) -> Tuple[List[dict], Dict]:
"""Execute agent with possible sub-agent forking."""
system_prompt = f"Solve this task: {self.task}"for step inrange(10): # Max reasoning steps# Generate thought
thought = model.generate(system_prompt, max_tokens=256)
self.trajectory.append({
"type": "thought",
"content": thought
})
# Decide if forking helps (learned by GRPO)ifself.can_fork andself.fork_count < self.max_agents:
fork_decision = should_fork(model, thought, self.task)
if fork_decision:
# Create sub-agent for specific sub-task
subtask = extract_subtask(thought)
subagent = SubAgent(
task=subtask,
available_tools=["search", "calculate"],
context=self.task,
depth=1
)
result = subagent.execute(model)
self.fork_count += 1self.subagent_trajectories[self.fork_count] = subagent.trajectory
self.trajectory.append({
"type": "fork",
"fork_id": self.fork_count,
"task": subtask,
"result": result
})
# Try to solve (check if done)if is_task_complete(thought):
self.result = extract_answer(thought)
breakreturnself.trajectory, self.subagent_trajectories
Step 4: Evaluation and Metric Computation
Track multi-agent metrics.
# Multi-agent evaluationdefevaluate_multi_agent_solution(
result: str,
target: str,
num_agents_spawned: int = 0,
total_tokens: int = 0) -> dict:
"""
Evaluate solution accounting for multi-agent aspects.
Returns:
Dict with correctness, efficiency, and agent metrics
"""
correct = is_correct(result, target)
# Reward includes solution quality
base_reward = 1.0if correct else0.0# Penalize excessive agent spawning if not needed
agent_penalty = 0.1 * num_agents_spawned if num_agents_spawned > 3else0.0# Reward efficient multi-agent useif num_agents_spawned > 0and correct:
efficiency_bonus = 0.1# Bonus for parallelizationreturn {
"reward": base_reward - agent_penalty + (efficiency_bonus if num_agents_spawned > 0else0),
"correct": correct,
"agents_spawned": num_agents_spawned,
"tokens_total": total_tokens
}
Practical Guidance
When to use WideSeek:
Complex tasks with variable decomposition needs
Scenarios where parallelization is beneficial
Problems where agent depth/breadth tradeoff varies per instance
End-to-end learning of orchestration is desired
When not to use:
Simple single-path tasks
Real-time systems where agent coordination overhead matters
Scenarios requiring consistent agent behavior
Tasks with fixed decomposition structures (use static multi-agent)
Common Pitfalls:
Too many agents: Linearization becomes unwieldy; cap at 4-8
Fork scheduling imbalance: Some tasks over-fork, others under-fork
Communication gaps: Sub-agents can't see sibling results; pass context
Training instability: Multi-agent GRPO more volatile; use smaller learning rates
Key results: 6.36× more sub-agents than baselines via learned scheduling. WideSeekBench with 5,156 tasks. Code and trained 8B models released. Demonstrates breadth scaling as alternative to depth.