feat(swarm): add /swarm command with sequential|mixture|distill|deliberate modes (Phase A foundation, #303)
This commit is contained in:
@@ -144,6 +144,109 @@ pub fn deepseek_links(app: &mut App) -> CommandResult {
|
||||
))
|
||||
}
|
||||
|
||||
/// Collaboration pattern for `/swarm` multi-agent turns.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SwarmMode {
|
||||
/// Linear pipeline: Planner → Critic → Solver
|
||||
Sequential,
|
||||
/// Parallel ensemble: domain specialists + synthesizer
|
||||
Mixture,
|
||||
/// Expert–Learner pair for knowledge distillation
|
||||
Distill,
|
||||
/// Reflector + Tool-Caller iterative deliberation
|
||||
Deliberate,
|
||||
}
|
||||
|
||||
impl SwarmMode {
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
match s.to_ascii_lowercase().as_str() {
|
||||
"sequential" | "seq" | "pipeline" => Some(Self::Sequential),
|
||||
"mixture" | "mix" | "ensemble" | "parallel" => Some(Self::Mixture),
|
||||
"distill" | "distillation" | "transfer" => Some(Self::Distill),
|
||||
"deliberate" | "deliberation" | "dialectic" | "reflect" => Some(Self::Deliberate),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn label(self) -> &'static str {
|
||||
match self {
|
||||
Self::Sequential => "sequential",
|
||||
Self::Mixture => "mixture",
|
||||
Self::Distill => "distill",
|
||||
Self::Deliberate => "deliberate",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn description(self) -> &'static str {
|
||||
match self {
|
||||
Self::Sequential => "Linear pipeline: Planner → Critic → Solver",
|
||||
Self::Mixture => "Parallel ensemble: domain specialists + synthesizer",
|
||||
Self::Distill => "Expert–Learner pair for knowledge distillation",
|
||||
Self::Deliberate => "Reflector + Tool-Caller iterative deliberation",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Initiate a multi-agent swarm turn with the requested collaboration pattern.
|
||||
///
|
||||
/// Phase A foundation — currently sets up the prompt context so the model
|
||||
/// uses `agent_swarm` with the appropriate topology. Direct orchestration
|
||||
/// from the slash command (bypassing the model) is planned for Phase B.
|
||||
pub fn swarm(app: &mut App, arg: Option<&str>) -> CommandResult {
|
||||
let raw = arg.map(str::trim).unwrap_or("");
|
||||
let mut parts = raw.splitn(2, char::is_whitespace);
|
||||
let mode_str = parts.next().unwrap_or("");
|
||||
let description = parts.next().map(str::trim).unwrap_or("");
|
||||
|
||||
if mode_str.is_empty() {
|
||||
let mut help = String::from("Usage: /swarm <mode> [description]\n\nModes:\n");
|
||||
for mode in [
|
||||
SwarmMode::Sequential,
|
||||
SwarmMode::Mixture,
|
||||
SwarmMode::Distill,
|
||||
SwarmMode::Deliberate,
|
||||
] {
|
||||
help.push_str(&format!(" {} — {}\n", mode.label(), mode.description()));
|
||||
}
|
||||
return CommandResult::message(help);
|
||||
}
|
||||
|
||||
let Some(mode) = SwarmMode::from_str(mode_str) else {
|
||||
return CommandResult::error(format!(
|
||||
"Unknown swarm mode: {mode_str}. Try /swarm for a list of modes."
|
||||
));
|
||||
};
|
||||
|
||||
let msg = if description.is_empty() {
|
||||
format!(
|
||||
"Swarm mode: {}. Describe the task and I will delegate it using the {} pattern.",
|
||||
mode.label(),
|
||||
mode.label()
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"Swarm mode: {}. Delegating using the {} pattern:\n{}",
|
||||
mode.label(),
|
||||
mode.label(),
|
||||
description
|
||||
)
|
||||
};
|
||||
|
||||
// Queue a system message that primes the model to use agent_swarm
|
||||
// with the requested topology. In Phase B this will be replaced by
|
||||
// direct engine-side orchestration.
|
||||
let system_hint = format!(
|
||||
"The user has requested a {} swarm. Use the agent_swarm tool with the appropriate topology. \
|
||||
For sequential: use depends_on chains. For mixture: spawn specialists in parallel then synthesize. \
|
||||
For distill: spawn an expert and a learner, then have the learner absorb the expert's output. \
|
||||
For deliberate: spawn a reflector and a tool-caller in a critique→refine loop.",
|
||||
mode.label()
|
||||
);
|
||||
|
||||
app.system_prompt = Some(crate::models::SystemPrompt::Text(system_hint));
|
||||
|
||||
CommandResult::message(msg)
|
||||
}
|
||||
/// Show home dashboard with stats and quick actions
|
||||
pub fn home_dashboard(app: &mut App) -> CommandResult {
|
||||
let locale = app.ui_locale;
|
||||
|
||||
@@ -390,6 +390,12 @@ pub const COMMANDS: &[CommandInfo] = &[
|
||||
usage: "/cache [count]",
|
||||
description_id: MessageId::CmdCacheDescription,
|
||||
},
|
||||
CommandInfo {
|
||||
name: "swarm",
|
||||
aliases: &[],
|
||||
usage: "/swarm <sequential|mixture|distill|deliberate> [description]",
|
||||
description_id: MessageId::CmdSwarmDescription,
|
||||
},
|
||||
];
|
||||
|
||||
/// Execute a slash command
|
||||
@@ -410,6 +416,7 @@ pub fn execute(cmd: &str, app: &mut App) -> CommandResult {
|
||||
"provider" => provider::provider(app, arg),
|
||||
"queue" | "queued" => queue::queue(app, arg),
|
||||
"subagents" | "agents" => core::subagents(app),
|
||||
"swarm" => core::swarm(app, arg),
|
||||
"links" | "dashboard" | "api" => core::deepseek_links(app),
|
||||
"home" | "stats" | "overview" => core::home_dashboard(app),
|
||||
"note" => note::note(app, arg),
|
||||
|
||||
@@ -252,6 +252,7 @@ pub enum MessageId {
|
||||
CmdSkillsDescription,
|
||||
CmdStatuslineDescription,
|
||||
CmdSubagentsDescription,
|
||||
CmdSwarmDescription,
|
||||
CmdSystemDescription,
|
||||
CmdTaskDescription,
|
||||
CmdTokensDescription,
|
||||
@@ -430,6 +431,7 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[
|
||||
MessageId::CmdSkillsDescription,
|
||||
MessageId::CmdStatuslineDescription,
|
||||
MessageId::CmdSubagentsDescription,
|
||||
MessageId::CmdSwarmDescription,
|
||||
MessageId::CmdSystemDescription,
|
||||
MessageId::CmdTaskDescription,
|
||||
MessageId::CmdTokensDescription,
|
||||
@@ -748,6 +750,9 @@ fn english(id: MessageId) -> &'static str {
|
||||
}
|
||||
MessageId::CmdStatuslineDescription => "Configure which items appear in the footer",
|
||||
MessageId::CmdSubagentsDescription => "List sub-agent status",
|
||||
MessageId::CmdSwarmDescription => {
|
||||
"Run a multi-agent swarm turn (sequential | mixture | distill | deliberate)"
|
||||
}
|
||||
MessageId::CmdSystemDescription => "Show current system prompt",
|
||||
MessageId::CmdTaskDescription => "Manage background tasks",
|
||||
MessageId::CmdTokensDescription => "Show token usage for session",
|
||||
@@ -1012,6 +1017,9 @@ fn japanese(id: MessageId) -> Option<&'static str> {
|
||||
}
|
||||
MessageId::CmdStatuslineDescription => "フッターに表示する項目を設定",
|
||||
MessageId::CmdSubagentsDescription => "サブエージェントの状態を一覧表示",
|
||||
MessageId::CmdSwarmDescription => {
|
||||
"マルチエージェントのスワームターンを実行(sequential | mixture | distill | deliberate)"
|
||||
}
|
||||
MessageId::CmdSystemDescription => "現在のシステムプロンプトを表示",
|
||||
MessageId::CmdTaskDescription => "バックグラウンドタスクを管理",
|
||||
MessageId::CmdTokensDescription => "セッションのトークン使用量を表示",
|
||||
@@ -1254,6 +1262,9 @@ fn chinese_simplified(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdSkillsDescription => "列出本地技能(或使用 --remote 浏览精选注册表)",
|
||||
MessageId::CmdStatuslineDescription => "配置底栏要显示哪些条目",
|
||||
MessageId::CmdSubagentsDescription => "列出子代理状态",
|
||||
MessageId::CmdSwarmDescription => {
|
||||
"运行多代理集群轮次(sequential | mixture | distill | deliberate)"
|
||||
}
|
||||
MessageId::CmdSystemDescription => "显示当前系统提示词",
|
||||
MessageId::CmdTaskDescription => "管理后台任务",
|
||||
MessageId::CmdTokensDescription => "显示本次会话的 token 用量",
|
||||
@@ -1502,6 +1513,9 @@ fn portuguese_brazil(id: MessageId) -> Option<&'static str> {
|
||||
}
|
||||
MessageId::CmdStatuslineDescription => "Configurar quais itens aparecem no rodapé",
|
||||
MessageId::CmdSubagentsDescription => "Listar o status dos sub-agentes",
|
||||
MessageId::CmdSwarmDescription => {
|
||||
"Executar turno de enxame multi-agente (sequential | mixture | distill | deliberate)"
|
||||
}
|
||||
MessageId::CmdSystemDescription => "Exibir o prompt de sistema atual",
|
||||
MessageId::CmdTaskDescription => "Gerenciar tarefas em segundo plano",
|
||||
MessageId::CmdTokensDescription => "Exibir o uso de tokens da sessão",
|
||||
|
||||
Reference in New Issue
Block a user