feat: DeerFlow 2.0 core capabilities — Phase 1.0 + 1.1
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

Phase 1.0 — Butler Mode UI:
- Hide "自动化" and "技能市场" entries from sidebar navigation
- Remove AutomationPanel and SkillMarket view rendering from App.tsx
- Simplify MainViewType to only 'chat'
- Main interface is now: chat + conversation list + detail panel only

Phase 1.1 — Mode Differentiation:
- Add subagent_enabled field to ChatModeConfig (Rust), StreamChatRequest (Tauri),
  gateway-client, kernel-client, saas-relay-client, and streamStore
- TaskTool is now only registered when subagent_enabled=true (Ultra mode)
- System prompt includes sub-agent delegation instructions only in Ultra mode
- Frontend transmits subagent_enabled from ChatMode config through the full stack

This connects the 4-tier mode selector (Flash/Thinking/Pro/Ultra) to actual
backend behavioral differences — Ultra mode now truly enables sub-agent delegation.
This commit is contained in:
iven
2026-04-06 12:46:43 +08:00
parent 9c346ed6fb
commit cb140b5151
10 changed files with 72 additions and 105 deletions

View File

@@ -4,12 +4,13 @@ use tokio::sync::mpsc;
use zclaw_types::{AgentId, Result};
/// Chat mode configuration passed from the frontend.
/// Controls thinking, reasoning, and plan mode behavior.
/// Controls thinking, reasoning, plan mode, and sub-agent behavior.
#[derive(Debug, Clone)]
pub struct ChatModeConfig {
pub thinking_enabled: Option<bool>,
pub reasoning_effort: Option<String>,
pub plan_mode: Option<bool>,
pub subagent_enabled: Option<bool>,
}
use zclaw_runtime::{AgentLoop, tool::builtin::PathValidator};
@@ -45,7 +46,8 @@ impl Kernel {
let model = self.config.model().to_string();
// Create agent loop with model configuration
let tools = self.create_tool_registry();
let subagent_enabled = chat_mode.as_ref().and_then(|m| m.subagent_enabled).unwrap_or(false);
let tools = self.create_tool_registry(subagent_enabled);
let mut loop_runner = AgentLoop::new(
*agent_id,
self.driver.clone(),
@@ -92,7 +94,10 @@ impl Kernel {
}
// Build system prompt with skill information injected
let system_prompt = self.build_system_prompt_with_skills(agent_config.system_prompt.as_ref()).await;
let system_prompt = self.build_system_prompt_with_skills(
agent_config.system_prompt.as_ref(),
subagent_enabled,
).await;
let loop_runner = loop_runner.with_system_prompt(&system_prompt);
// Run the loop
@@ -147,7 +152,8 @@ impl Kernel {
let model = self.config.model().to_string();
// Create agent loop with model configuration
let tools = self.create_tool_registry();
let subagent_enabled = chat_mode.as_ref().and_then(|m| m.subagent_enabled).unwrap_or(false);
let tools = self.create_tool_registry(subagent_enabled);
let mut loop_runner = AgentLoop::new(
*agent_id,
self.driver.clone(),
@@ -197,7 +203,10 @@ impl Kernel {
// Use external prompt if provided, otherwise build default
let system_prompt = match system_prompt_override {
Some(prompt) => prompt,
None => self.build_system_prompt_with_skills(agent_config.system_prompt.as_ref()).await,
None => self.build_system_prompt_with_skills(
agent_config.system_prompt.as_ref(),
subagent_enabled,
).await,
};
let loop_runner = loop_runner.with_system_prompt(&system_prompt);
@@ -206,8 +215,13 @@ impl Kernel {
loop_runner.run_streaming(session_id, message).await
}
/// Build a system prompt with skill information injected
pub(super) async fn build_system_prompt_with_skills(&self, base_prompt: Option<&String>) -> String {
/// Build a system prompt with skill information injected.
/// When `subagent_enabled` is true, adds sub-agent delegation instructions.
pub(super) async fn build_system_prompt_with_skills(
&self,
base_prompt: Option<&String>,
subagent_enabled: bool,
) -> String {
// Get skill list asynchronously
let skills = self.skills.list().await;
@@ -215,7 +229,8 @@ impl Kernel {
.map(|p| p.clone())
.unwrap_or_else(|| "You are a helpful AI assistant.".to_string());
// Inject skill information with categories
// Inject skill metadata only (progressive loading pattern from DeerFlow).
// Full skill content is loaded on-demand via `load_skill_content` tool.
if !skills.is_empty() {
prompt.push_str("\n\n## Available Skills\n\n");
prompt.push_str("You have access to specialized skills. Analyze user intent and autonomously call `execute_skill` with the appropriate skill_id.\n\n");
@@ -245,6 +260,21 @@ impl Kernel {
prompt.push_str("User: \"分析腾讯财报\" → Intent: Financial analysis → Call: execute_skill(\"finance-tracker\", {...})\n");
}
// Sub-agent delegation instructions (Ultra mode only)
if subagent_enabled {
prompt.push_str("\n\n## Sub-Agent Delegation\n\n");
prompt.push_str("You can delegate complex sub-tasks to sub-agents using the `task` tool. This enables parallel execution of independent work.\n\n");
prompt.push_str("### When to use sub-agents:\n");
prompt.push_str("- Complex tasks that can be decomposed into independent parallel sub-tasks\n");
prompt.push_str("- Research tasks requiring multiple independent searches\n");
prompt.push_str("- Tasks requiring different expertise areas simultaneously\n\n");
prompt.push_str("### Guidelines:\n");
prompt.push_str("- Break complex work into clear, self-contained sub-tasks\n");
prompt.push_str("- Each sub-task should have a clear objective and expected output\n");
prompt.push_str("- Synthesize sub-agent results into a coherent final response\n");
prompt.push_str("- Maximum 3 concurrent sub-agents — batch if more are needed\n");
}
prompt
}

View File

@@ -162,18 +162,22 @@ impl Kernel {
})
}
/// Create a tool registry with built-in tools
pub(crate) fn create_tool_registry(&self) -> ToolRegistry {
/// Create a tool registry with built-in tools.
/// When `subagent_enabled` is false, TaskTool is excluded to prevent
/// the LLM from attempting sub-agent delegation in non-Ultra modes.
pub(crate) fn create_tool_registry(&self, subagent_enabled: bool) -> ToolRegistry {
let mut tools = ToolRegistry::new();
zclaw_runtime::tool::builtin::register_builtin_tools(&mut tools);
// Register TaskTool with driver and memory for sub-agent delegation
let task_tool = zclaw_runtime::tool::builtin::TaskTool::new(
self.driver.clone(),
self.memory.clone(),
self.config.model(),
);
tools.register(Box::new(task_tool));
// Register TaskTool only when sub-agent mode is enabled (Ultra mode)
if subagent_enabled {
let task_tool = zclaw_runtime::tool::builtin::TaskTool::new(
self.driver.clone(),
self.memory.clone(),
self.config.model(),
);
tools.register(Box::new(task_tool));
}
tools
}