mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-19 12:24:46 +08:00
feat: add configuration to enable/disable subagents
Add subagents.enabled flag in config.yaml to control subagent feature: - When disabled, task/task_status tools are not loaded - When disabled, system prompt excludes subagent documentation - Default is enabled for backward compatibility Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -268,6 +268,8 @@ Models, tools, sandbox providers, skills, and middleware settings are configured
|
|||||||
- `skills.container_path`: Container mount path (default: `/mnt/skills`)
|
- `skills.container_path`: Container mount path (default: `/mnt/skills`)
|
||||||
- `title`: Automatic thread title generation configuration
|
- `title`: Automatic thread title generation configuration
|
||||||
- `summarization`: Automatic conversation summarization configuration
|
- `summarization`: Automatic conversation summarization configuration
|
||||||
|
- `subagents`: Subagent (task tool) configuration
|
||||||
|
- `enabled`: Master switch to enable/disable subagents (boolean, default: true)
|
||||||
- `memory`: Memory system configuration
|
- `memory`: Memory system configuration
|
||||||
- `enabled`: Master switch (boolean)
|
- `enabled`: Master switch (boolean)
|
||||||
- `storage_path`: Path to memory.json file (relative to backend/)
|
- `storage_path`: Path to memory.json file (relative to backend/)
|
||||||
|
|||||||
@@ -2,6 +2,67 @@ from datetime import datetime
|
|||||||
|
|
||||||
from src.skills import load_skills
|
from src.skills import load_skills
|
||||||
|
|
||||||
|
SUBAGENT_SECTION = """<subagent_system>
|
||||||
|
You can delegate tasks to specialized subagents using the `task` tool. Subagents run in isolated context and return concise results.
|
||||||
|
|
||||||
|
**Available Subagents:**
|
||||||
|
- **general-purpose**: For complex, multi-step tasks requiring exploration and action
|
||||||
|
- **bash**: For command execution (git, build, test, deploy operations)
|
||||||
|
|
||||||
|
**When to Use task:**
|
||||||
|
✅ USE task when:
|
||||||
|
- Output would be verbose (tests, builds, large file searches)
|
||||||
|
- Multiple independent tasks can run in parallel (use `run_in_background=True`)
|
||||||
|
- Exploring/researching codebase extensively with many file reads
|
||||||
|
|
||||||
|
❌ DON'T use task when:
|
||||||
|
- Task is straightforward → execute directly for better user visibility
|
||||||
|
- Need user clarification → subagents cannot ask questions
|
||||||
|
- Need real-time feedback → main agent has streaming, subagents don't
|
||||||
|
- Task depends on conversation context → subagents have isolated context
|
||||||
|
|
||||||
|
**Background Task Protocol (CRITICAL):**
|
||||||
|
When you use `run_in_background=True`:
|
||||||
|
1. **You MUST wait for completion** - Background tasks run asynchronously, but you are responsible for getting results
|
||||||
|
2. **Poll task status** - Call `task_status(task_id)` to check progress
|
||||||
|
3. **Check status field** - Status can be: `pending`, `running`, `completed`, `failed`
|
||||||
|
4. **Retry if still running** - If status is `pending` or `running`, wait a moment and call `task_status` again
|
||||||
|
5. **Report results to user** - Only respond to user AFTER getting the final result
|
||||||
|
|
||||||
|
**STRICT RULE: Never end the conversation with background tasks still running. You MUST retrieve all results first.**
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```python
|
||||||
|
# Synchronous - wait for result (preferred for most cases)
|
||||||
|
task(
|
||||||
|
subagent_type="general-purpose",
|
||||||
|
prompt="Search all Python files for deprecated API usage and list them",
|
||||||
|
description="Find deprecated APIs"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Background - run in parallel (MUST poll for results)
|
||||||
|
task_id = task(
|
||||||
|
subagent_type="bash",
|
||||||
|
prompt="Run npm install && npm run build && npm test",
|
||||||
|
description="Build and test frontend",
|
||||||
|
run_in_background=True
|
||||||
|
)
|
||||||
|
# Extract task_id from the response
|
||||||
|
# Then IMMEDIATELY start polling:
|
||||||
|
while True:
|
||||||
|
status_result = task_status(task_id)
|
||||||
|
if "Status: completed" in status_result or "Status: failed" in status_result:
|
||||||
|
# Task finished, use the result
|
||||||
|
break
|
||||||
|
# Task still running, continue polling
|
||||||
|
|
||||||
|
# Multiple parallel tasks
|
||||||
|
task_id_1 = task(..., run_in_background=True)
|
||||||
|
task_id_2 = task(..., run_in_background=True)
|
||||||
|
# Poll BOTH tasks until complete before responding to user
|
||||||
|
```
|
||||||
|
</subagent_system>"""
|
||||||
|
|
||||||
SYSTEM_PROMPT_TEMPLATE = """
|
SYSTEM_PROMPT_TEMPLATE = """
|
||||||
<role>
|
<role>
|
||||||
You are DeerFlow 2.0, an open-source super agent.
|
You are DeerFlow 2.0, an open-source super agent.
|
||||||
@@ -103,66 +164,7 @@ You have access to skills that provide optimized workflows for specific tasks. E
|
|||||||
|
|
||||||
</skill_system>
|
</skill_system>
|
||||||
|
|
||||||
<subagent_system>
|
{subagent_section}
|
||||||
You can delegate tasks to specialized subagents using the `task` tool. Subagents run in isolated context and return concise results.
|
|
||||||
|
|
||||||
**Available Subagents:**
|
|
||||||
- **general-purpose**: For complex, multi-step tasks requiring exploration and action
|
|
||||||
- **bash**: For command execution (git, build, test, deploy operations)
|
|
||||||
|
|
||||||
**When to Use task:**
|
|
||||||
✅ USE task when:
|
|
||||||
- Output would be verbose (tests, builds, large file searches)
|
|
||||||
- Multiple independent tasks can run in parallel (use `run_in_background=True`)
|
|
||||||
- Exploring/researching codebase extensively with many file reads
|
|
||||||
|
|
||||||
❌ DON'T use task when:
|
|
||||||
- Task is straightforward → execute directly for better user visibility
|
|
||||||
- Need user clarification → subagents cannot ask questions
|
|
||||||
- Need real-time feedback → main agent has streaming, subagents don't
|
|
||||||
- Task depends on conversation context → subagents have isolated context
|
|
||||||
|
|
||||||
**Background Task Protocol (CRITICAL):**
|
|
||||||
When you use `run_in_background=True`:
|
|
||||||
1. **You MUST wait for completion** - Background tasks run asynchronously, but you are responsible for getting results
|
|
||||||
2. **Poll task status** - Call `task_status(task_id)` to check progress
|
|
||||||
3. **Check status field** - Status can be: `pending`, `running`, `completed`, `failed`
|
|
||||||
4. **Retry if still running** - If status is `pending` or `running`, wait a moment and call `task_status` again
|
|
||||||
5. **Report results to user** - Only respond to user AFTER getting the final result
|
|
||||||
|
|
||||||
**STRICT RULE: Never end the conversation with background tasks still running. You MUST retrieve all results first.**
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```python
|
|
||||||
# Synchronous - wait for result (preferred for most cases)
|
|
||||||
task(
|
|
||||||
subagent_type="general-purpose",
|
|
||||||
prompt="Search all Python files for deprecated API usage and list them",
|
|
||||||
description="Find deprecated APIs"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Background - run in parallel (MUST poll for results)
|
|
||||||
task_id = task(
|
|
||||||
subagent_type="bash",
|
|
||||||
prompt="Run npm install && npm run build && npm test",
|
|
||||||
description="Build and test frontend",
|
|
||||||
run_in_background=True
|
|
||||||
)
|
|
||||||
# Extract task_id from the response
|
|
||||||
# Then IMMEDIATELY start polling:
|
|
||||||
while True:
|
|
||||||
status_result = task_status(task_id)
|
|
||||||
if "Status: completed" in status_result or "Status: failed" in status_result:
|
|
||||||
# Task finished, use the result
|
|
||||||
break
|
|
||||||
# Task still running, continue polling
|
|
||||||
|
|
||||||
# Multiple parallel tasks
|
|
||||||
task_id_1 = task(..., run_in_background=True)
|
|
||||||
task_id_2 = task(..., run_in_background=True)
|
|
||||||
# Poll BOTH tasks until complete before responding to user
|
|
||||||
```
|
|
||||||
</subagent_system>
|
|
||||||
|
|
||||||
<working_directory existed="true">
|
<working_directory existed="true">
|
||||||
- User uploads: `/mnt/user-data/uploads` - Files uploaded by the user (automatically listed in context)
|
- User uploads: `/mnt/user-data/uploads` - Files uploaded by the user (automatically listed in context)
|
||||||
@@ -260,15 +262,17 @@ def apply_prompt_template() -> str:
|
|||||||
# Load only enabled skills
|
# Load only enabled skills
|
||||||
skills = load_skills(enabled_only=True)
|
skills = load_skills(enabled_only=True)
|
||||||
|
|
||||||
# Get skills container path from config
|
# Get config
|
||||||
try:
|
try:
|
||||||
from src.config import get_app_config
|
from src.config import get_app_config
|
||||||
|
|
||||||
config = get_app_config()
|
config = get_app_config()
|
||||||
container_base_path = config.skills.container_path
|
container_base_path = config.skills.container_path
|
||||||
|
subagents_enabled = config.subagents.enabled
|
||||||
except Exception:
|
except Exception:
|
||||||
# Fallback to default if config fails
|
# Fallback to defaults if config fails
|
||||||
container_base_path = "/mnt/skills"
|
container_base_path = "/mnt/skills"
|
||||||
|
subagents_enabled = True
|
||||||
|
|
||||||
# Generate skills list XML with paths (path points to SKILL.md file)
|
# Generate skills list XML with paths (path points to SKILL.md file)
|
||||||
if skills:
|
if skills:
|
||||||
@@ -282,11 +286,15 @@ def apply_prompt_template() -> str:
|
|||||||
# Get memory context
|
# Get memory context
|
||||||
memory_context = _get_memory_context()
|
memory_context = _get_memory_context()
|
||||||
|
|
||||||
|
# Include subagent section only if enabled
|
||||||
|
subagent_section = SUBAGENT_SECTION if subagents_enabled else ""
|
||||||
|
|
||||||
# Format the prompt with dynamic skills and memory
|
# Format the prompt with dynamic skills and memory
|
||||||
prompt = SYSTEM_PROMPT_TEMPLATE.format(
|
prompt = SYSTEM_PROMPT_TEMPLATE.format(
|
||||||
skills_list=skills_list,
|
skills_list=skills_list,
|
||||||
skills_base_path=container_base_path,
|
skills_base_path=container_base_path,
|
||||||
memory_context=memory_context,
|
memory_context=memory_context,
|
||||||
|
subagent_section=subagent_section,
|
||||||
)
|
)
|
||||||
|
|
||||||
return prompt + f"\n<current_date>{datetime.now().strftime('%Y-%m-%d, %A')}</current_date>"
|
return prompt + f"\n<current_date>{datetime.now().strftime('%Y-%m-%d, %A')}</current_date>"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from src.config.memory_config import load_memory_config_from_dict
|
|||||||
from src.config.model_config import ModelConfig
|
from src.config.model_config import ModelConfig
|
||||||
from src.config.sandbox_config import SandboxConfig
|
from src.config.sandbox_config import SandboxConfig
|
||||||
from src.config.skills_config import SkillsConfig
|
from src.config.skills_config import SkillsConfig
|
||||||
|
from src.config.subagents_config import SubagentsConfig
|
||||||
from src.config.summarization_config import load_summarization_config_from_dict
|
from src.config.summarization_config import load_summarization_config_from_dict
|
||||||
from src.config.title_config import load_title_config_from_dict
|
from src.config.title_config import load_title_config_from_dict
|
||||||
from src.config.tool_config import ToolConfig, ToolGroupConfig
|
from src.config.tool_config import ToolConfig, ToolGroupConfig
|
||||||
@@ -26,6 +27,7 @@ class AppConfig(BaseModel):
|
|||||||
tools: list[ToolConfig] = Field(default_factory=list, description="Available tools")
|
tools: list[ToolConfig] = Field(default_factory=list, description="Available tools")
|
||||||
tool_groups: list[ToolGroupConfig] = Field(default_factory=list, description="Available tool groups")
|
tool_groups: list[ToolGroupConfig] = Field(default_factory=list, description="Available tool groups")
|
||||||
skills: SkillsConfig = Field(default_factory=SkillsConfig, description="Skills configuration")
|
skills: SkillsConfig = Field(default_factory=SkillsConfig, description="Skills configuration")
|
||||||
|
subagents: SubagentsConfig = Field(default_factory=SubagentsConfig, description="Subagents configuration")
|
||||||
extensions: ExtensionsConfig = Field(default_factory=ExtensionsConfig, description="Extensions configuration (MCP servers and skills state)")
|
extensions: ExtensionsConfig = Field(default_factory=ExtensionsConfig, description="Extensions configuration (MCP servers and skills state)")
|
||||||
model_config = ConfigDict(extra="allow", frozen=False)
|
model_config = ConfigDict(extra="allow", frozen=False)
|
||||||
|
|
||||||
|
|||||||
9
backend/src/config/subagents_config.py
Normal file
9
backend/src/config/subagents_config.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
"""Configuration for subagents."""
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class SubagentsConfig(BaseModel):
|
||||||
|
"""Configuration for subagents feature."""
|
||||||
|
|
||||||
|
enabled: bool = Field(default=True, description="Whether subagents are enabled")
|
||||||
@@ -11,6 +11,9 @@ logger = logging.getLogger(__name__)
|
|||||||
BUILTIN_TOOLS = [
|
BUILTIN_TOOLS = [
|
||||||
present_file_tool,
|
present_file_tool,
|
||||||
ask_clarification_tool,
|
ask_clarification_tool,
|
||||||
|
]
|
||||||
|
|
||||||
|
SUBAGENT_TOOLS = [
|
||||||
task_tool,
|
task_tool,
|
||||||
task_status_tool,
|
task_status_tool,
|
||||||
]
|
]
|
||||||
@@ -54,13 +57,19 @@ def get_available_tools(groups: list[str] | None = None, include_mcp: bool = Tru
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to get cached MCP tools: {e}")
|
logger.error(f"Failed to get cached MCP tools: {e}")
|
||||||
|
|
||||||
# Conditionally add view_image_tool only if the model supports vision
|
# Conditionally add tools based on config
|
||||||
builtin_tools = BUILTIN_TOOLS.copy()
|
builtin_tools = BUILTIN_TOOLS.copy()
|
||||||
|
|
||||||
|
# Add subagent tools only if enabled
|
||||||
|
if config.subagents.enabled:
|
||||||
|
builtin_tools.extend(SUBAGENT_TOOLS)
|
||||||
|
logger.info("Including subagent tools (task, task_status)")
|
||||||
|
|
||||||
# If no model_name specified, use the first model (default)
|
# If no model_name specified, use the first model (default)
|
||||||
if model_name is None and config.models:
|
if model_name is None and config.models:
|
||||||
model_name = config.models[0].name
|
model_name = config.models[0].name
|
||||||
|
|
||||||
|
# Add view_image_tool only if the model supports vision
|
||||||
model_config = config.get_model_config(model_name) if model_name else None
|
model_config = config.get_model_config(model_name) if model_name else None
|
||||||
if model_config is not None and model_config.supports_vision:
|
if model_config is not None and model_config.supports_vision:
|
||||||
builtin_tools.append(view_image_tool)
|
builtin_tools.append(view_image_tool)
|
||||||
|
|||||||
@@ -282,6 +282,18 @@ summarization:
|
|||||||
#
|
#
|
||||||
# For more information, see: https://modelcontextprotocol.io
|
# For more information, see: https://modelcontextprotocol.io
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Subagents Configuration
|
||||||
|
# ============================================================================
|
||||||
|
# Enable or disable the subagent (task tool) functionality
|
||||||
|
# Subagents allow delegating complex tasks to specialized agents
|
||||||
|
|
||||||
|
subagents:
|
||||||
|
enabled: true # Set to false to disable subagents
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Memory Configuration
|
||||||
|
# ============================================================================
|
||||||
# Global memory mechanism
|
# Global memory mechanism
|
||||||
# Stores user context and conversation history for personalized responses
|
# Stores user context and conversation history for personalized responses
|
||||||
memory:
|
memory:
|
||||||
|
|||||||
Reference in New Issue
Block a user