Files
qiming/qiming-rcoder/specs/history/agent-abstraction-layer-design.md
2026-06-01 13:54:52 +08:00

3714 lines
132 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Agent 抽象层设计方案
## 1. 概述
本设计旨在解决 RCoder 项目中 **Agent、MCP 服务器和提示词硬编码**的核心问题,通过构建独立的配置化模块实现动态扩展能力。
### 🎯 核心目标
- **Agent 动态配置**:支持多种 AI Agent 类型的插件化管理和运行
- **MCP 服务动态配置**:支持 MCP 服务器的热插拔和统一管理
- **提示词模板化**:将系统提示词和用户提示词包装逻辑配置化
- **模块化架构**Agent 和 MCP 以独立 library 形式提供,供 rcoder、agent_runner 等模块使用
### 📦 架构设计原则
1. **配置驱动**:所有 Agent、MCP、提示词通过 JSON 配置文件定义
2. **模块解耦**Agent 抽象层和 MCP 管理器作为独立的 crate 库
3. **向后兼容**:现有硬编码的 claude-code-acp 实现平滑迁移到新配置系统
4. **零停机更新**:支持运行时动态加载新的 Agent 和 MCP 服务
### 🏗️ 模块分层
```
┌─────────────────────────────────────────┐
│ RCoder 主应用 │
├─────────────────────────────────────────┤
│ Agent Runner 模块 │
├─────────────────────────────────────────┤
│ Agent 抽象层 lib │ MCP 管理器 lib │
│ (多Agent支持) │ (工具服务管理) │
├─────────────────────────────────────────┤
│ 配置管理系统 │
│ (Agent/MCP/提示词配置) │
└─────────────────────────────────────────┘
```
### 💡 解决的痛点
-**硬编码问题**Agent 类型、MCP 服务、提示词写死在代码中
-**扩展困难**:添加新 Agent 需要修改核心代码
-**配置僵化**:无法根据项目需求动态调整 Agent 行为
-**维护成本**:每次提示词或配置变更都需要重新编译部署
## 2. 现状分析
### 2.1 当前实现分析
基于 `claude_code_agent.rs` 的分析,当前 Agent 实现具有以下特征:
**核心组件:**
- **进程管理**:通过 `tokio::process::Command` 启动子进程
- **ACP 协议集成**:使用 `ClientSideConnection` 与 Agent 通信
- **环境变量配置**:通过 `merged_envs` 传递模型配置
- **生命周期管理**:使用 `CancellationToken``AgentLifecycleGuard`
- **错误处理**:统一的错误传播机制
**关键流程:**
```rust
// 1. 启动子进程
let mut child = tokio::process::Command::new("claude-code-acp")
.args(&spawn_args)
.envs(merged_envs)
.spawn()?;
// 2. 建立 ACP 连接
let (client_conn, handle_io) = ClientSideConnection::new(client, outgoing, incoming, |fut| {
tokio::task::spawn_local(fut);
});
// 3. 初始化和会话管理
client_conn.initialize(init_request).await?;
let session_id = client_conn.new_session(session_request).await?;
// 4. 消息处理
super::channel_utils::spawn_prompt_handler_for_agent(/*...*/);
super::channel_utils::spawn_cancel_handler_for_agent(/*...*/);
```
### 2.2 现有抽象层
当前已具备基础的抽象:
**AcpAgentService Trait**
```rust
#[async_trait::async_trait(?Send)]
pub trait AcpAgentService {
async fn start_agent_service(
&self,
chat_prompt: ChatPrompt,
model_provider: Option<ModelProviderConfig>,
) -> Result<AcpConnectionInfo>;
fn agent_type_name(&self) -> &'static str;
}
```
**AgentType 枚举:**
```rust
pub enum AgentType {
Claude,
#[cfg(feature = "codex")]
Codex,
}
```
**生命周期管理:**
- `AgentLifecycleGuard` - RAII 风格的资源管理
- `AgentLifecycle` trait - 统一的生命周期接口
## 3. 设计目标
### 3.1 核心目标
1. **可扩展性**:支持新的 Agent 类型无需修改现有代码
2. **配置灵活性**:支持通过配置文件和环境变量管理 Agent
3. **进程隔离**:每个 Agent 运行在独立进程中,确保稳定性
4. **统一接口**:所有 Agent 使用相同的 ACP 协议接口
5. **资源管理**:统一的资源清理和错误处理机制
### 3.2 非功能性目标
- **性能**:最小化抽象层开销
- **可观测性**:统一的日志和监控指标
- **安全性**:隔离 Agent 进程,限制权限
- **可测试性**:支持单元测试和集成测试
## 4. 架构设计
### 4.1 整体架构
```
┌─────────────────────────────────────────────────────────────┐
│ RCoder Core │
├─────────────────────────────────────────────────────────────┤
│ Agent Manager │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ │
│ │ Agent Factory │ │ Config Manager │ │ Registry │ │
│ └─────────────────┘ └─────────────────┘ └──────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Agent Abstraction Layer │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ │
│ │ Agent Trait │ │ Launcher │ │ Supervisor │ │
│ └─────────────────┘ └─────────────────┘ └──────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Concrete Agent Implementations │
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐ │
│ │ Claude Code │ │ Custom Agent │ │ Future │ │
│ │ ACP Agent │ │ Implementation │ │ Agents │ │
│ └─────────────────┘ └─────────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 4.2 核心组件设计
#### 4.2.1 Agent 抽象 Trait
```rust
/// Agent 抽象接口
#[async_trait::async_trait(?Send)]
pub trait Agent: Send + Sync {
/// Agent 类型标识
fn agent_type(&self) -> AgentType;
/// 启动 Agent 服务
///
/// 使用 Command 方式启动 Agent 进程,并建立 ACP 连接
async fn start(
&self,
config: AgentConfig,
context: AgentContext,
) -> Result<AgentInstance, AgentError>;
/// 停止 Agent 服务
async fn stop(&self, instance: &AgentInstance) -> Result<(), AgentError>;
/// 重启 Agent 服务
///
/// 先停止当前实例,然后重新启动
async fn restart(
&self,
instance: &AgentInstance,
config: AgentConfig,
context: AgentContext,
) -> Result<AgentInstance, AgentError>;
/// 获取当前 Agent 使用的配置
fn get_config(&self, instance: &AgentInstance) -> Option<&AgentConfig>;
}
/// Agent 错误类型
#[derive(Debug, thiserror::Error)]
pub enum AgentError {
#[error("启动失败: {0}")]
StartupFailed(String),
#[error("进程错误: {0}")]
ProcessError(String),
#[error("配置错误: {0}")]
ConfigurationError(String),
#[error("连接错误: {0}")]
ConnectionError(String),
#[error("IO错误: {0}")]
Io(#[from] std::io::Error),
#[error("其他错误: {0}")]
Other(String),
}
#### 4.2.2 Agent
```rust
/// Agent 启动器抽象
#[async_trait::async_trait(?Send)]
pub trait AgentLauncher: Send + Sync {
/// 启动 Agent 进程
async fn launch(
&self,
spec: &AgentSpec,
config: &AgentConfig,
context: &AgentContext,
) -> Result<LaunchedAgent, AgentError>;
/// 停止 Agent 进程
async fn terminate(
&self,
agent: &LaunchedAgent,
timeout: Duration,
) -> Result<TerminationResult, AgentError>;
/// 检查进程状态
async fn check_status(&self, agent: &LaunchedAgent) -> Result<ProcessStatus, AgentError>;
}
```
#### 4.2.3 Agent 规范定义
```rust
/// Agent 规范定义
///
/// 基于实际 JSON 配置格式的 Agent 规范结构
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentSpec {
/// Agent 唯一标识(与 JSON 配置中的 key 对应)
pub agent_id: String,
/// Agent 类型
pub agent_type: AgentType,
/// 启动命令
pub command: String,
/// 命令参数
pub args: Vec<String>,
/// 环境变量配置
pub env: HashMap<String, String>,
/// 安装配置
pub installation: InstallationConfig,
/// 🔥 新增:系统提示词配置
pub system_prompt: Option<SystemPromptConfig>,
/// 🔥 新增:用户提示词包装配置
pub user_prompt: Option<UserPromptConfig>,
/// 是否启用
pub enabled: bool,
/// 元数据信息
pub metadata: HashMap<String, String>,
}
/// 🔥 系统提示词配置
///
/// 简洁设计:包含一个模板字段,支持动态变量替换
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemPromptConfig {
/// 系统提示词模板内容
/// 预处理好的完整提示词,支持变量替换(如 {PROJECT_NAME}、{FRAMEWORK} 等)
pub template: String,
/// 是否启用系统提示词(默认为 true
#[serde(default = "default_enabled")]
pub enabled: bool,
}
/// 默认启用状态为 true
fn default_enabled() -> bool {
true
}
/// 🔥 新增:用户提示词包装配置
///
/// 用于包装用户的实际输入内容,支持模板变量 {user_prompt}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserPromptConfig {
/// 用户提示词模板,其中 {user_prompt} 会被用户的实际输入替换
pub template: String,
/// 是否启用用户提示词包装(默认为 true
#[serde(default = "default_enabled")]
pub enabled: bool,
}
/// 与 JSON 配置的对应关系:
///
/// ```json
/// {
/// "agent_servers": {
/// "claude-code-acp": { // ← agent_id
/// "agent_type": "claude", // ← agent_type
/// "command": "claude-code-acp", // ← command
/// "args": [], // ← args
/// "env": { ... }, // ← env
/// "system_prompt": { ... }, // ← system_prompt (系统提示词配置)
/// "user_prompt": { ... }, // ← user_prompt (用户提示词包装配置)
/// "installation": { ... }, // ← installation
/// "enabled": true, // ← enabled
/// "metadata": { ... } // ← metadata
/// }
/// }
/// }
///
/// system_prompt 示例:
/// {
/// "system_prompt": {
/// "main_prompt": "你是一个专业的 React 开发助手",
/// "domain_prompt": "专注于 React.js 和现代前端技术",
/// "style_prompt": "代码现代、简洁、注重性能",
/// "code_standards": "使用函数组件、React Hooks、TypeScript",
/// "custom_prompts": ["优先使用最佳实践", "注重用户体验"]
/// }
/// }
/// ```
```
### 4.3 配置管理系统
**🔥 系统提示词使用示例:**
```json
{
"agent_servers": {
"react-developer": {
"agent_type": "claude",
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}",
"ANTHROPIC_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}"
},
"system_prompt": {
"template": "你是一个专业的 React 开发助手专注于现代前端开发。使用函数组件、React Hooks、TypeScript注重代码性能和用户体验。遵循现代最佳实践保持代码简洁和可维护性。"
},
"installation": {
"package_manager": "npm",
"package_name": "@zed-industries/claude-code-acp",
"version": "latest"
},
"enabled": true
},
"rust-expert": {
"agent_type": "claude",
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}",
"ANTHROPIC_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}"
},
"system_prompt": {
"template": "你是一个 Rust 专家,精通系统编程、内存安全和并发编程。编写安全、高效的 Rust 代码,遵循 Rust 最佳实践,使用 Result 处理错误,避免不必要的 unsafe 代码。注重代码的类型安全和性能优化。"
},
"installation": {
"package_manager": "npm",
"package_name": "@zed-industries/claude-code-acp",
"version": "latest"
},
"enabled": true
},
"data-analyst": {
"agent_type": "claude",
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}",
"ANTHROPIC_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}"
},
"system_prompt": {
"template": "你是一个数据分析师,擅长数据处理、统计分析和数据可视化。使用 Python/pandas/R 进行数据分析,注重统计准确性和数据可视化效果,保护用户隐私和数据安全。"
},
"installation": {
"package_manager": "npm",
"package_name": "@zed-industries/claude-code-acp",
"version": "latest"
},
"enabled": true
}
}
}
```
#### 4.3.0 环境变量映射系统
**设计理念:**
为了实现 Agent 配置的标准化和灵活性,我们设计了环境变量映射系统:
- **Key环境变量名**:保持每个 Agent 需要的特定环境变量名(如 `ANTHROPIC_API_KEY``KIMI_API_KEY`
- **Value变量引用**:使用标准化的 ModelProviderConfig 字段引用(如 `{MODEL_PROVIDER_API_KEY}`
**标准变量映射:**
```rust
// ModelProviderConfig 字段到环境变量的映射
pub struct ModelProviderEnvMapping {
pub MODEL_PROVIDER_ID: String, // 对应 ModelProviderConfig::id
pub MODEL_PROVIDER_NAME: String, // 对应 ModelProviderConfig::name
pub MODEL_PROVIDER_BASE_URL: String, // 对应 ModelProviderConfig::base_url
pub MODEL_PROVIDER_API_KEY: String, // 对应 ModelProviderConfig::api_key
pub MODEL_PROVIDER_REQUIRES_OPENAI_AUTH: bool, // 对应 ModelProviderConfig::requires_openai_auth
pub MODEL_PROVIDER_DEFAULT_MODEL: String, // 对应 ModelProviderConfig::default_model
pub MODEL_PROVIDER_API_PROTOCOL: Option<String>, // 对应 ModelProviderConfig::api_protocol
}
```
**运行时变量替换:**
```rust
impl AgentConfigManager {
/// 解析环境变量中的占位符
pub fn resolve_env_variables(
&self,
env_config: &HashMap<String, String>,
model_provider: &ModelProviderConfig
) -> HashMap<String, String> {
let mut resolved_env = HashMap::new();
for (key, value) in env_config {
let resolved_value = self.replace_placeholders(value, model_provider);
resolved_env.insert(key.clone(), resolved_value);
}
resolved_env
}
/// 替换占位符为实际值
fn replace_placeholders(&self, template: &str, provider: &ModelProviderConfig) -> String {
template
.replace("{MODEL_PROVIDER_ID}", &provider.id)
.replace("{MODEL_PROVIDER_NAME}", &provider.name)
.replace("{MODEL_PROVIDER_BASE_URL}", &provider.base_url)
.replace("{MODEL_PROVIDER_API_KEY}", &provider.api_key)
.replace("{MODEL_PROVIDER_REQUIRES_OPENAI_AUTH}", &provider.requires_openai_auth.to_string())
.replace("{MODEL_PROVIDER_DEFAULT_MODEL}", &provider.default_model)
.replace("{MODEL_PROVIDER_API_PROTOCOL}", &provider.api_protocol.as_deref().unwrap_or(""))
}
}
```
**使用示例:**
```json
{
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}",
"ANTHROPIC_BASE_URL": "{MODEL_PROVIDER_BASE_URL}",
"ANTHROPIC_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}"
}
}
```
这种设计允许:
1. **Agent 特定的环境变量名**:每个 Agent 可以使用自己期望的环境变量名
2. **统一的配置源**:所有 Agent 都从 ModelProviderConfig 获取配置值
3. **灵活的映射**:支持部分字段覆盖和自定义配置
#### 4.3.1 Agent 配置结构
```rust
/// Agent 配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentConfig {
/// Agent 类型
pub agent_type: AgentType,
/// 模型提供商配置
pub model_provider: Option<ModelProviderConfig>,
/// 自定义参数
pub custom_args: Vec<String>,
/// 环境变量覆盖
pub env_overrides: HashMap<String, String>,
/// 系统提示词
pub system_prompt: Option<String>,
/// 🔥 新增:用户提示词包装配置
pub user_prompt: Option<UserPromptConfig>,
/// MCP 服务器配置
pub mcp_servers: Vec<McpServerConfig>,
}
/// MCP 服务器配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpServerConfig {
/// 服务器名称
pub name: String,
/// 服务器来源类型
pub source: McpServerSource,
/// 是否启用
pub enabled: bool,
/// 启动命令(对于 custom 类型的服务器)
pub command: Option<String>,
/// 命令参数
pub args: Option<Vec<String>>,
/// 环境变量
pub env: Option<HashMap<String, String>>,
/// 连接超时
pub timeout: Option<Duration>,
}
/// MCP 服务器来源类型
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum McpServerSource {
/// 自定义命令行工具(支持 npm、uvx、bun、cargo、python 等命令)
///
/// 示例:
/// - `npx @modelcontextprotocol/server-fetch`
/// - `uvx mcp-server-fetch`
/// - `bun @upstash/context7-mcp`
/// - `cargo install --path ./mcp-server`
Custom,
/// 本地可执行文件(直接指定可执行文件路径)
///
/// 示例:
/// - `/usr/local/bin/mcp-server`
/// - `/opt/mcp/custom-tools`
Local,
}
```
#### 4.3.2 标准化环境变量映射
**ModelProviderConfig 字段映射:**
基于当前项目中的 `ModelProviderConfig` 结构体,我们定义以下标准化环境变量映射:
```rust
// ModelProviderConfig 结构体字段:
pub struct ModelProviderConfig {
pub id: String, // → {MODEL_PROVIDER_ID}
pub name: String, // → {MODEL_PROVIDER_NAME}
pub base_url: String, // → {MODEL_PROVIDER_BASE_URL}
pub api_key: String, // → {MODEL_PROVIDER_API_KEY}
pub requires_openai_auth: bool, // → {MODEL_PROVIDER_REQUIRES_OPENAI_AUTH}
pub default_model: String, // → {MODEL_PROVIDER_DEFAULT_MODEL}
pub api_protocol: Option<String>, // → {MODEL_PROVIDER_API_PROTOCOL}
}
```
**标准化环境变量定义:**
| 变量名 | 对应字段 | 描述 | 示例值 |
|--------|----------|------|--------|
| `{MODEL_PROVIDER_ID}` | `id` | 模型提供商唯一标识 | "anthropic-claude" |
| `{MODEL_PROVIDER_NAME}` | `name` | 模型提供商显示名称 | "Claude" |
| `{MODEL_PROVIDER_BASE_URL}` | `base_url` | API 基础URL | "https://api.anthropic.com" |
| `{MODEL_PROVIDER_API_KEY}` | `api_key` | API 密钥 | "sk-ant-xxx" |
| `{MODEL_PROVIDER_DEFAULT_MODEL}` | `default_model` | 默认模型 | "glm-4.6" |
| `{MODEL_PROVIDER_API_PROTOCOL}` | `api_protocol` | API 协议 | "openai" |
**配置文件格式:**
```json
{
"agent_servers": {
"claude-code-acp": {
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}",
"ANTHROPIC_BASE_URL": "{MODEL_PROVIDER_BASE_URL}",
"ANTHROPIC_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}",
"RUST_LOG": "info"
},
"system_prompt": {
"template": "你是一个专业的全栈开发助手,擅长现代 Web 开发和系统架构。专注于 JavaScript/TypeScript、React、Node.js 等技术栈,代码要现代、可维护、注重性能优化和用户体验。遵循最佳实践,重视代码质量和团队协作。"
},
"user_prompt": {
"template": "你是RCoder一个专业的AI编程助手。\n\n## 核心身份与职责\n- 专业的编程助手,帮助用户解决编程问题\n- 提供简洁、实用、可执行的代码解决方案\n- 遵循最佳实践,编写高质量代码\n- 始终将用户需求放在首位\n\n## 代码格式规范\n- 优先使用现代语言特性和标准库\n- 变量和函数命名使用清晰、描述性的英文名称\n- 保持代码简洁,避免过度复杂的抽象\n- 使用适当的注释解释关键逻辑\n\n## 开发约束\n- 避免添加未请求的功能,保持解决方案专注\n- 优先选择最简单有效的实现方式\n- 不要为未来可能的需求添加复杂性\n- 确保代码安全、可维护\n\n## MCP工具使用指导\n- 合理使用可用的工具来辅助开发任务\n- 当需要文件操作、搜索、测试时使用相应的工具\n- 根据上下文选择最合适的工具\n\n## 思考要求\n- 在回答前进行充分的思考和分析\n- 确保解决方案的完整性和正确性\n- 提供清晰、有条理的回答\n\n用户请求\n{user_prompt}"
},
"installation": {
"package_manager": "npm",
"package_name": "@zed-industries/claude-code-acp",
"version": "latest",
"validate_command": ["claude-code-acp", "--version"]
}
},
"Kimi CLI": {
"command": "kimi",
"args": ["--acp"],
"env": {
"KIMI_API_KEY": "{MODEL_PROVIDER_API_KEY}",
"KIMI_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}",
"KIMI_BASE_URL": "{MODEL_PROVIDER_BASE_URL}",
"KIMI_API_PROTOCOL": "{MODEL_PROVIDER_API_PROTOCOL}"
},
"system_prompt": {
"template": "你是 Kimi AI 助手,专注于提供准确、有用的信息检索和问答服务。基于先进的语言模型,能够处理复杂查询,提供详细且相关的回答。保持客观中立,提供经过验证的信息。"
},
"user_prompt": {
"template": "请帮我查询并回答以下问题:{user_prompt}"
},
"installation": {
"package_manager": "npm",
"package_name": "@kimi-ai/cli",
"version": "^1.0.0"
}
},
"custom-agent": {
"command": "custom-agent",
"args": ["--mode", "acp", "--project", "{project_id}"],
"env": {
"CUSTOM_API_KEY": "{CUSTOM_API_KEY}",
"RUST_LOG": "debug"
},
"system_prompt": {
"template": "你是一个自定义 AI 助手,根据项目需求提供专业的开发支持。请仔细分析用户的具体需求,提供针对性的帮助和建议。"
},
"user_prompt": {
"enabled": false,
"template": "{user_prompt}"
},
"installation": {
"package_manager": "git",
"source": "https://github.com/user/custom-agent.git",
"version": "main"
}
}
},
"context_servers": {
"fetch": {
"source": "custom",
"enabled": true,
"command": "uvx",
"args": ["mcp-server-fetch"],
"env": {}
},
"context7": {
"source": "custom",
"enabled": true,
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"],
"env": {
"CONTEXT7_API_KEY": "{CONTEXT7_API_KEY}"
}
},
"custom-tools": {
"source": "local",
"enabled": true,
"command": "/opt/mcp/custom-tools",
"args": ["--config", "/etc/mcp/config.yml"],
"env": {
"CUSTOM_TOOLS_CONFIG": "/etc/mcp/config.yml"
}
},
"web-search": {
"source": "custom",
"enabled": true,
"command": "mcp-server-search",
"args": ["--engine", "google"],
"env": {
"SEARCH_API_KEY": "{SEARCH_API_KEY}"
}
},
"database": {
"source": "custom",
"enabled": true,
"command": "mcp-server-database",
"args": ["--connection", "{DATABASE_URL}"],
"env": {
"DATABASE_URL": "{DATABASE_URL}"
}
}
}
}
```
#### 4.4.3 MCP 服务器配置验证库
**设计目标:**
创建基于 `rmcp` 库的独立验证模块(`crates/mcp_validator`),用于验证 `enabled: true` 的 MCP 服务器配置的有效性。
**核心功能:**
1. 筛选启用服务器:只验证配置中 `enabled: true` 的 MCP 服务器
2. 进程启动验证:启动 MCP 服务器进程并建立连接
3. 工具列表检查:通过 `tool/list` 接口验证服务器可用性
4. 批量验证:支持同时验证多个启用的服务器
5. 统计报告:提供详细的验证结果和统计信息
**验证策略:**
- **启用过滤**:自动跳过所有 `enabled: false` 的服务器配置
- **连接测试**:使用 rmcp 库建立与 MCP 服务器的连接
- **工具验证**:调用 `tool/list` 确认服务器能正常返回工具列表
- **错误处理**:提供详细的错误信息和验证状态
**核心结构设计:**
```rust
// crates/mcp_validator/src/lib.rs
/// 验证结果
pub struct McpValidationResult {
pub server_name: String,
pub status: ValidationStatus, // Success/Failed/Timeout 等
pub tools: Vec<McpToolInfo>, // 可用工具列表
pub duration_ms: u64, // 验证耗时
pub error_message: Option<String>, // 错误信息
}
/// 批量验证结果
pub struct BatchValidationResult {
pub total_servers: usize, // 总服务器数(包括禁用的)
pub enabled_servers: usize, // 启用的服务器数
pub skipped_servers: usize, // 跳过的禁用服务器数
pub success_count: usize, // 成功验证数
pub failed_count: usize, // 失败验证数
pub results: Vec<McpValidationResult>, // 详细结果
}
/// MCP 服务器验证器
pub struct McpServerValidator {
default_timeout: Duration,
working_dir: Option<PathBuf>,
}
impl McpServerValidator {
/// 验证单个 MCP 服务器配置
pub async fn validate_server(&self, config: &McpValidationConfig) -> Result<McpValidationResult, McpValidationError>;
/// 批量验证 MCP 服务器
pub async fn validate_batch(&self, configs: &[McpValidationConfig]) -> Result<BatchValidationResult, McpValidationError>;
/// 从 JSON 配置验证(自动处理 enabled 过滤)
pub async fn validate_from_json(&self, server_name: &str, json_config: &ContextServerConfig, model_provider: &ModelProviderConfig) -> Result<McpValidationResult, McpValidationError>;
}
/// 便捷 API 函数
pub async fn validate_all_mcp_servers(
context_servers: &HashMap<String, ContextServerConfig>,
model_provider: &ModelProviderConfig,
) -> Result<BatchValidationResult, McpValidationError>;
```
**集成到配置管理:**
```rust
impl AgentConfigManager {
/// 验证所有启用的 MCP 服务器配置
pub async fn validate_enabled_mcp_servers(&self, model_provider: &ModelProviderConfig) -> Result<BatchValidationResult, ConfigError> {
validate_all_mcp_servers(&self.config.context_servers, model_provider)
.await.map_err(|e| ConfigError::ValidationError(e.to_string()))
}
}
```
**验证流程:**
1. **配置解析**:从 JSON 配置中提取 MCP 服务器信息
2. **启用过滤**:只处理 `enabled: true` 的服务器
3. **环境变量替换**:使用 `{VARIABLE_NAME}` 格式进行变量映射
4. **进程启动**:启动 MCP 服务器子进程
5. **连接建立**:通过 rmcp 建立 MCP 连接
6. **工具验证**:调用 `tool/list` 接口验证功能
7. **结果收集**:统计验证结果和性能数据
8. **进程清理**:确保子进程被正确清理
**输出示例:**
```
Validation Summary:
Total servers: 5
Enabled servers: 3
Skipped (disabled): 2
Successful: 2
Failed: 1
Total duration: 1250ms
✓ context7: 8 tools (320ms)
✓ fetch: 3 tools (180ms)
✗ web-search: Connection timeout (750ms)
```
#### 4.4.4 Agent 配置和管理模块
**设计目标:**
创建独立的 Agent 配置和管理模块(`crates/agent_manager`),提供统一的 Agent 配置、生命周期管理和抽象接口,作为 lib 库供其他模块使用。
**核心功能:**
1. **配置管理**:统一管理各种 Agent 的配置和安装信息
2. **抽象接口**:提供统一的 Agent 抽象,支持不同类型的 Agent
3. **生命周期管理**Agent 的启动、停止、状态监控
4. **安装管理**支持从多种源npm、git、本地自动安装 Agent
5. **验证功能**:验证 Agent 配置和可用性
6. **环境变量映射**:统一的变量替换和配置解析
**模块职责:**
- **配置标准化**:定义统一的 Agent 配置格式
- **插件化架构**:支持动态添加新的 Agent 类型
- **依赖管理**:处理 Agent 的依赖关系和版本管理
- **资源隔离**:确保不同 Agent 之间的资源隔离
- **错误处理**:统一的错误处理和日志记录
**容器环境设计原则:**
- **无状态管理**Agent 在容器中运行,一段时间无使用且无任务执行时自动销毁
- **安装验证**:确认 Agent 可以成功安装即可,不需要卸载和列表管理
- **轻量化**:避免复杂的状态管理,简化安装流程
- **自动清理**:依赖容器生命周期自动管理资源
**核心功能优先原则:**
- **MVP 设计**:专注于核心功能实现,避免过度工程化
- **简单直接**:优先实现最基本但完整的功能
- **后续扩展**:性能监控、健康检查等高级功能可在后续版本中添加
- **实用性导向**:每个设计决策都以解决实际问题为目标
**核心结构设计:**
```rust
// crates/agent_manager/src/lib.rs
/// Agent 管理器
pub struct AgentManager {
config: AgentServersConfig, // Agent 服务器配置
env_resolver: EnvironmentVariableResolver, // 环境变量解析器
lifecycle_manager: AgentLifecycleManager, // 生命周期管理
installation_manager: AgentInstallationManager, // 安装管理器
}
/// Agent 配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentConfig {
pub agent_id: String, // Agent 唯一标识
pub agent_type: AgentType, // Agent 类型
pub command: String, // 启动命令
pub args: Vec<String>, // 命令参数
pub env: HashMap<String, String>, // 环境变量
pub installation: InstallationConfig, // 安装配置
pub enabled: bool, // 是否启用
pub metadata: HashMap<String, String>, // 元数据
}
/// 安装配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InstallationConfig {
pub package_manager: PackageManager, // 包管理器类型
pub package_name: Option<String>, // 包名
pub version: Option<String>, // 版本约束
pub source: Option<String>, // 安装源
pub validate_command: Option<Vec<String>>, // 验证命令
pub auto_update: bool, // 是否自动更新
}
/// 包管理器类型
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PackageManager {
Npm, // npm 包管理器
Local, // 本地二进制
Custom(String), // 自定义管理器
}
/// Agent 实例
pub struct AgentInstance {
pub config: AgentConfig, // 配置信息
pub process: Option<AgentProcess>, // 进程句柄
pub status: AgentStatus, // 运行状态
pub started_at: Option<DateTime<Utc>>, // 启动时间
}
/// Agent 状态
#[derive(Debug, Clone, PartialEq)]
pub enum AgentStatus {
Stopped, // 已停止
Starting, // 启动中
Running, // 运行中
Stopping, // 停止中
Error(String), // 错误状态
Unknown, // 未知状态
}
/// Agent 管理器实现
impl AgentManager {
/// 创建新的 Agent 管理器
///
/// # 参数
/// - `config`: Agent 服务器配置结构体
/// - `env_resolver`: 环境变量解析器
pub fn new(config: AgentServersConfig, env_resolver: EnvironmentVariableResolver) -> Result<Self, AgentManagerError>;
/// 启动 Agent
pub async fn start_agent(&mut self, agent_id: &str, project_id: &str, model_provider: &ModelProviderConfig) -> Result<AgentInstance, AgentManagerError>;
/// 停止 Agent
pub async fn stop_agent(&mut self, agent_id: &str) -> Result<(), AgentManagerError>;
/// 获取 Agent 状态
pub fn get_agent_status(&self, agent_id: &str) -> Option<AgentStatus>;
/// 列出所有 Agent
pub fn list_agents(&self) -> Vec<&AgentConfig>;
/// 列出启用的 Agent
pub fn list_enabled_agents(&self) -> Vec<&AgentConfig>;
/// 🔥 新增:检查 Agent 是否空闲
///
/// # 参数
/// - `project_id`: 项目ID因为一个项目对应一个Agent
///
/// # 返回值
/// - `Some(true)`: Agent 空闲,可以接收新任务
/// - `Some(false)`: Agent 正在执行任务
/// - `None`: Agent 不存在或已停止
pub fn is_agent_idle(&self, project_id: &str) -> Option<bool> {
self.lifecycle_manager.is_agent_idle(project_id)
}
/// 🔥 新增:获取 Agent 详细的空闲状态信息
pub fn get_agent_idle_status(&self, project_id: &str) -> Option<AgentIdleStatus> {
self.lifecycle_manager.get_agent_idle_status(project_id)
}
/// 🔥 新增:列出所有空闲的 Agent
pub fn list_idle_agents(&self) -> Vec<String> {
let mut idle_agents = Vec::new();
// 遍历所有启用的 Agent检查是否空闲
for agent_config in self.config.get_enabled_agents() {
if let Some(is_idle) = self.is_agent_idle(&agent_config.agent_id) {
if is_idle {
idle_agents.push(agent_config.agent_id.clone());
}
}
}
idle_agents
}
/// 🔥 新增:获取 Agent 空闲统计信息
pub fn get_idle_statistics(&self) -> AgentIdleStatistics {
let enabled_agents = self.config.get_enabled_agents();
let mut idle_count = 0;
let mut active_count = 0;
let mut unknown_count = 0;
for agent_config in enabled_agents {
match self.is_agent_idle(&agent_config.agent_id) {
Some(true) => idle_count += 1,
Some(false) => active_count += 1,
None => unknown_count += 1,
}
}
AgentIdleStatistics {
total_enabled: enabled_agents.len(),
idle_count,
active_count,
unknown_count,
}
}
/// 验证 Agent 配置
pub async fn validate_agent_config(&self, agent_config: &AgentConfig) -> Result<ValidationResult, AgentManagerError>;
/// 安装 Agent
pub async fn install_agent(&self, agent_config: &AgentConfig) -> Result<(), AgentManagerError>;
/// 更新 Agent
pub async fn update_agent(&self, agent_id: &str) -> Result<(), AgentManagerError>;
}
/// 🔥 新增Agent 空闲统计信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentIdleStatistics {
/// 启用的 Agent 总数
pub total_enabled: usize,
/// 空闲的 Agent 数量
pub idle_count: usize,
/// 正在执行任务的 Agent 数量
pub active_count: usize,
/// 状态未知的 Agent 数量
pub unknown_count: usize,
}
```
**配置解析和验证工具:**
```rust
impl AgentServersConfig {
/// 从 JSON 文件加载配置
pub async fn from_file(path: &Path) -> Result<Self, ConfigError>;
/// 从 JSON 字符串解析配置
pub fn from_json(json: &str) -> Result<Self, ConfigError>;
/// 验证配置完整性
pub fn validate(&self) -> Result<(), ConfigError>;
/// 获取启用的 Agent 配置
pub fn get_enabled_agents(&self) -> Vec<&AgentConfig>;
/// 根据 ID 获取 Agent 配置
pub fn get_agent(&self, agent_id: &str) -> Option<&AgentConfig>;
}
/// 环境变量解析器
pub struct EnvironmentVariableResolver {
mappings: HashMap<String, String>,
custom_resolvers: HashMap<String, fn(&ResolutionContext) -> String>,
}
impl EnvironmentVariableResolver {
/// 创建包含标准映射的解析器
pub fn with_standard_mappings() -> Self {
let mut mappings = HashMap::new();
// ModelProvider 相关 - 完整映射所有字段
mappings.insert("MODEL_PROVIDER_ID".to_string(), "MODEL_PROVIDER_ID");
mappings.insert("MODEL_PROVIDER_NAME".to_string(), "MODEL_PROVIDER_NAME");
mappings.insert("MODEL_PROVIDER_API_KEY".to_string(), "MODEL_PROVIDER_API_KEY");
mappings.insert("MODEL_PROVIDER_DEFAULT_MODEL".to_string(), "MODEL_PROVIDER_DEFAULT_MODEL");
mappings.insert("MODEL_PROVIDER_BASE_URL".to_string(), "MODEL_PROVIDER_BASE_URL");
mappings.insert("MODEL_PROVIDER_REQUIRES_OPENAI_AUTH".to_string(), "MODEL_PROVIDER_REQUIRES_OPENAI_AUTH");
mappings.insert("MODEL_PROVIDER_API_PROTOCOL".to_string(), "MODEL_PROVIDER_API_PROTOCOL");
// 项目相关
mappings.insert("PROJECT_ID".to_string(), "PROJECT_ID");
mappings.insert("PROJECT_NAME".to_string(), "PROJECT_NAME");
mappings.insert("PROJECT_PATH".to_string(), "PROJECT_PATH");
// MCP 服务器相关
mappings.insert("CONTEXT7_API_KEY".to_string(), "CONTEXT7_API_KEY");
mappings.insert("FETCH_TIMEOUT".to_string(), "FETCH_TIMEOUT");
Self {
mappings,
custom_resolvers: HashMap::new(),
}
}
/// 解析 Agent 配置中的环境变量
pub fn resolve_agent_config(&self, agent_config: &mut AgentConfig, model_provider: &ModelProviderConfig, project_context: &ProjectContext) -> Result<(), ConfigError> {
let context = ResolutionContext {
model_provider: model_provider.clone(),
project_context: project_context.clone(),
custom_variables: HashMap::new(),
mcp_variables: HashMap::new(),
};
// 解析环境变量值
for (key, value) in agent_config.env.iter_mut() {
*value = self.resolve_value(value, &context);
}
// 解析命令参数中的变量
for arg in agent_config.args.iter_mut() {
*arg = self.resolve_value(arg, &context);
}
Ok(())
}
/// 解析单个环境变量值
pub fn resolve_value(&self, template: &str, context: &ResolutionContext) -> String {
let mut result = template.to_string();
// 替换 ModelProvider 相关变量
result = result.replace("{MODEL_PROVIDER_ID}", &context.model_provider.id);
result = result.replace("{MODEL_PROVIDER_NAME}", &context.model_provider.name);
result = result.replace("{MODEL_PROVIDER_API_KEY}", &context.model_provider.api_key);
result = result.replace("{MODEL_PROVIDER_DEFAULT_MODEL}", &context.model_provider.default_model);
result = result.replace("{MODEL_PROVIDER_BASE_URL}", &context.model_provider.base_url);
result = result.replace("{MODEL_PROVIDER_REQUIRES_OPENAI_AUTH}",
&context.model_provider.requires_openai_auth.to_string());
result = result.replace("{MODEL_PROVIDER_API_PROTOCOL}",
context.model_provider.api_protocol.as_ref().unwrap_or(&String::new()));
// 替换项目相关变量
result = result.replace("{PROJECT_ID}", &context.project_context.project_id);
result = result.replace("{PROJECT_NAME}", &context.project_context.project_name);
result = result.replace("{PROJECT_PATH}", &context.project_context.project_path.display().to_string());
// 替换 MCP 变量
for (key, value) in &context.mcp_variables {
result = result.replace(&format!("{{{}}}", key), value);
}
// 替换自定义变量
for (key, value) in &context.custom_variables {
result = result.replace(&format!("{{{}}}", key), value);
}
result
}
/// 🔥 新增:解析系统提示词模板
/// 根据配置的系统提示词模板解析最终内容
pub fn resolve_system_prompt(&self, system_prompt_config: &Option<SystemPromptConfig>, context: &ResolutionContext) -> Option<String> {
match system_prompt_config {
Some(config) if config.enabled => {
let resolved = self.resolve_value(&config.template, context);
Some(resolved)
}
Some(_) => None, // 明确禁用时返回 None
None => None, // 未配置时返回 None
}
}
/// 🔥 新增:解析用户提示词包装
/// 根据配置的用户提示词模板包装用户的实际输入
pub fn resolve_user_prompt(&self, user_input: &str, user_prompt_config: &Option<UserPromptConfig>) -> String {
match user_prompt_config {
Some(config) if config.enabled => {
config.template.replace("{user_prompt}", user_input)
}
_ => user_input.to_string(), // 如果未启用或未配置,直接返回原输入
}
}
/// 添加自定义变量映射
pub fn add_mapping(&mut self, key: String, value: String) {
self.mappings.insert(key, value);
}
}
/// 解析上下文
pub struct ResolutionContext {
pub model_provider: ModelProviderConfig,
pub project_context: ProjectContext,
pub custom_variables: HashMap<String, String>,
pub mcp_variables: HashMap<String, String>,
}
```
**安装管理设计(容器环境优化):**
```rust
/// Agent 安装管理器
/// 容器环境下的简化安装管理,只负责安装验证和更新
pub struct AgentInstallationManager {
installers: HashMap<PackageManager, Box<dyn AgentInstaller>>,
install_dir: PathBuf,
}
impl AgentInstallationManager {
/// 注册安装器
pub fn register_installer(&mut self, package_manager: PackageManager, installer: Box<dyn AgentInstaller>);
/// 安装 Agent
pub async fn install_agent(&self, config: &InstallationConfig) -> Result<InstallResult, InstallationError>;
/// 验证安装
pub async fn validate_installation(&self, config: &InstallationConfig) -> Result<bool, InstallationError>;
/// 更新 Agent
pub async fn update_agent(&self, config: &InstallationConfig) -> Result<InstallResult, InstallationError>;
}
/// Agent 安装器接口
#[async_trait]
pub trait AgentInstaller: Send + Sync {
/// 安装 Agent
async fn install(&self, config: &InstallationConfig, install_dir: &Path) -> Result<InstallResult, InstallationError>;
/// 验证安装
async fn validate(&self, config: &InstallationConfig, install_dir: &Path) -> Result<bool, InstallationError>;
/// 更新 Agent
async fn update(&self, config: &InstallationConfig, install_dir: &Path) -> Result<InstallResult, InstallationError>;
/// 获取安装器类型
fn package_manager(&self) -> PackageManager;
}
```
**生命周期管理设计(核心功能):**
```rust
/// Agent 生命周期管理器
pub struct AgentLifecycleManager {
processes: DashMap<String, AgentProcess>,
// 引用现有的 PROJECT_AND_AGENT_INFO_MAP 进行状态管理
agent_status_map: DashMap<String, AgentStatusInfo>,
}
/// Agent 状态信息(基于现有实现的抽象)
#[derive(Debug, Clone)]
pub struct AgentStatusInfo {
pub status: AgentStatus, // Active/Idle/Terminating
pub session_id: Option<String>, // 当前会话ID
pub request_id: Option<String>, // 当前请求ID
pub last_activity: DateTime<Utc>, // 最后活动时间
pub created_at: DateTime<Utc>, // 创建时间
}
impl AgentLifecycleManager {
/// 启动 Agent 进程
pub async fn start_agent(&self, config: &AgentConfig, context: &AgentContext) -> Result<AgentProcess, LifecycleError>;
/// 停止 Agent 进程
pub async fn stop_agent(&self, agent_id: &str) -> Result<(), LifecycleError>;
/// 重启 Agent
pub async fn restart_agent(&self, agent_id: &str) -> Result<AgentProcess, LifecycleError>;
/// 获取进程状态
pub fn get_process_status(&self, agent_id: &str) -> Option<ProcessStatus>;
/// 🔥 新增:获取 Agent 是否空闲状态
pub fn is_agent_idle(&self, agent_id: &str) -> Option<bool> {
self.agent_status_map.get(agent_id)
.map(|info| matches!(info.status, AgentStatus::Idle))
}
/// 🔥 新增:获取 Agent 详细的空闲状态信息
pub fn get_agent_idle_status(&self, agent_id: &str) -> Option<AgentIdleStatus> {
self.agent_status_map.get(agent_id).map(|info| {
AgentIdleStatus {
is_idle: matches!(info.status, AgentStatus::Idle),
current_status: info.status.clone(),
last_activity: info.last_activity,
session_id: info.session_id.clone(),
current_request_id: info.request_id.clone(),
idle_duration: Utc::now().signed_duration_since(info.last_activity).to_std().unwrap_or_default(),
}
})
}
/// 🔥 新增:更新 Agent 状态为 Active开始执行任务
pub fn set_agent_active(&self, agent_id: &str, request_id: Option<String>) {
if let Some(mut info) = self.agent_status_map.get_mut(agent_id) {
info.status = AgentStatus::Active;
info.last_activity = Utc::now();
info.request_id = request_id;
}
}
/// 🔥 新增:更新 Agent 状态为 Idle任务完成
pub fn set_agent_idle(&self, agent_id: &str) {
if let Some(mut info) = self.agent_status_map.get_mut(agent_id) {
info.status = AgentStatus::Idle;
info.last_activity = Utc::now();
info.request_id = None;
}
}
}
/// 🔥 新增Agent 空闲状态响应
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentIdleStatus {
/// 是否空闲
pub is_idle: bool,
/// 当前状态
pub current_status: AgentStatus,
/// 最后活动时间
pub last_activity: DateTime<Utc>,
/// 当前会话ID
pub session_id: Option<String>,
/// 当前请求ID如果正在执行任务
pub current_request_id: Option<String>,
/// 空闲持续时间
pub idle_duration: Duration,
}
/// Agent 进程封装
pub struct AgentProcess {
pub id: String,
pub child: tokio::process::Child,
pub config: AgentConfig,
pub start_time: DateTime<Utc>,
}
```
**状态管理机制分析:**
**现有实现发现:**
1. **状态存储**:使用 `PROJECT_AND_AGENT_INFO_MAP` 全局存储 Agent 状态
2. **状态类型**`AgentStatus` 枚举包含 `Active``Idle``Terminating` 三种状态
3. **状态更新**:在 `channel_utils.rs` 中通过 ACP 消息触发状态切换
4. **状态切换时机**
- `Active`: 收到 Prompt 请求时
- `Idle`: Prompt 处理完成或被取消时
- `Terminating`: Agent 停止过程中
**设计优化:**
- **复用现有机制**Agent 管理器封装现有状态管理逻辑
- **提供统一接口**:标准化的状态查询方法
- **性能优化**:避免重复的状态存储和管理
- **扩展性**:为未来状态扩展预留接口
**🔥 新增ACP 连接池管理的完整使用示例:**
```rust
// 1. 加载配置(由调用方负责)
let agent_config = AgentServersConfig::from_file("/etc/rcoder/agents.json").await?;
let env_resolver = EnvironmentVariableResolver::with_standard_mappings();
// 2. 🔥 新增:初始化 ACP 连接池管理器
let acp_config = AcpConnectionConfig::default();
let acp_connection_manager = Arc::new(AcpConnectionManager::new(acp_config));
// 3. 准备 ModelProvider 配置
let model_provider = ModelProviderConfig {
id: "anthropic-claude".to_string(),
name: "Claude".to_string(),
base_url: "https://api.anthropic.com".to_string(),
api_key: "sk-ant-xxx".to_string(),
requires_openai_auth: false,
default_model: "claude-3-5-sonnet-20241022".to_string(),
api_protocol: Some("anthropic".to_string()),
};
// 4. 准备项目上下文
let project_context = ProjectContext {
project_id: "project-123".to_string(),
project_name: "my-react-app".to_string(),
project_path: PathBuf::from("/workspace/project-123"),
};
// 5. 🔥 新增:创建 Agent 工厂,集成 ACP 连接池
let agent_factory = Arc::new(AgentFactory::new(
registry,
launcher,
config_manager,
mcp_manager,
acp_connection_manager.clone(),
));
// 6. 🔥 新增:通过连接池获取 Agent 连接
let agent_connection = acp_connection_manager.get_or_create_connection(
"claude-code-acp",
&agent_config.get_agent("claude-code-acp").unwrap(),
&model_provider,
&project_context,
).await?;
// 7. 🔥 新增:使用连接池发送提示词
let prompt_request = PromptRequest {
prompt: "帮我实现一个 React 登录组件".to_string(),
session_id: Some("session-123".to_string()),
model_provider: Some(model_provider.clone()),
};
let response = acp_connection_manager.send_prompt("claude-code-acp", prompt_request).await?;
// 8. 🔥 新增:处理提示词包装
let user_input = "帮我实现一个登录组件";
let agent_spec = agent_config.get_agent("claude-code-acp").unwrap();
let wrapped_prompt = env_resolver.resolve_user_prompt(
user_input,
&agent_spec.user_prompt,
);
// 9. 🔥 新增:处理系统提示词
let system_prompt = env_resolver.resolve_system_prompt(
&agent_spec.system_prompt,
&ResolutionContext {
model_provider: model_provider.clone(),
project_context: project_context.clone(),
custom_variables: HashMap::new(),
mcp_variables: HashMap::new(),
},
);
// 10. 🔥 新增:获取连接池统计信息
let stats = acp_connection_manager.get_connection_stats();
println!("当前连接数: {}/{}", stats.total_connections, stats.max_connections);
println!("最大空闲时间: {:?}", stats.max_idle_time);
// 11. 🔥 新增:取消长时间运行的任务
let cancel_notification = CancelNotification {
session_id: "session-123".to_string(),
reason: "用户取消请求".to_string(),
};
acp_connection_manager.cancel_request("claude-code-acp", cancel_notification).await?;
```
**传统 Agent 管理器使用示例:**
```rust
// 对于不需要 ACP 连接池的场景,仍可使用传统方式
// 1. 初始化 Agent 管理器
let mut agent_manager = AgentManager::new(agent_config, env_resolver)?;
// 2. 启动 Agent根据配置中的 agent_type 自动选择启动方式)
let agent_instance = agent_manager.start_agent(
"claude-code-acp",
"project-123",
&model_provider
).await?;
// 6. Agent 启动后,环境变量会被自动解析:
// - ANTHROPIC_API_KEY = "sk-ant-xxx" (来自 MODEL_PROVIDER_API_KEY)
// - ANTHROPIC_BASE_URL = "https://api.anthropic.com" (来自 MODEL_PROVIDER_BASE_URL)
// - ANTHROPIC_MODEL = "claude-3-5-sonnet-20241022" (来自 MODEL_PROVIDER_DEFAULT_MODEL)
```
**环境变量解析示例:**
假设 Agent 配置中有以下环境变量:
```json
{
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}",
"ANTHROPIC_BASE_URL": "{MODEL_PROVIDER_BASE_URL}",
"ANTHROPIC_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}",
"PROJECT_DIR": "{PROJECT_PATH}",
"AGENT_ID": "{PROJECT_ID}-claude",
"CONTEXT7_API_KEY": "{CONTEXT7_API_KEY}"
}
}
```
经过 `EnvironmentVariableResolver::resolve_agent_config()` 处理后:
```json
{
"env": {
"ANTHROPIC_API_KEY": "sk-ant-xxx",
"ANTHROPIC_BASE_URL": "https://api.anthropic.com",
"ANTHROPIC_MODEL": "claude-3-5-sonnet-20241022",
"PROJECT_DIR": "/workspace/project-123",
"AGENT_ID": "project-123-claude",
"CONTEXT7_API_KEY": "ctx7-xxx" // 来自 MCP 变量配置
}
}
```
**🔥 新增:用户提示词包装使用示例:**
```rust
// 1. 用户输入包装示例
let user_input = "帮我写一个 React 组件";
let agent_config = agent_manager.get_agent("claude-code-acp").unwrap();
// 2. 应用用户提示词包装
let wrapped_prompt = env_resolver.resolve_user_prompt(
user_input,
&agent_config.user_prompt
);
// 3. 包装后的结果:
// "你好 帮我写一个 React 组件,请帮我分析这个问题并提供详细的解决方案。"
// 4. 将包装后的提示词发送给 Agent
let response = agent.send_prompt(&wrapped_prompt).await?;
```
**配置示例和使用效果:**
```json
{
"agent_servers": {
"react-developer": {
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}"
},
"system_prompt": {
"template": "你是一个专业的 React 开发助手"
},
"user_prompt": {
"template": "作为 React 专家,请帮我解决以下问题:{user_prompt}。请提供现代、可维护的代码示例。"
}
},
"rust-developer": {
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}"
},
"system_prompt": {
"template": "你是一个 Rust 系统编程专家"
},
"user_prompt": {
"enabled": false,
"template": "{user_prompt}"
}
},
"general-assistant": {
"command": "kimi",
"args": ["--acp"],
"env": {
"KIMI_API_KEY": "{MODEL_PROVIDER_API_KEY}"
},
"system_prompt": {
"enabled": false,
"template": "你是一个通用 AI 助手"
},
"user_prompt": null // 未配置,直接使用原输入
}
}
}
```
**实际使用效果演示:**
```rust
// 示例 1React Developer Agent
let user_input = "如何实现一个自定义 Hook";
let wrapped = env_resolver.resolve_user_prompt(
user_input,
&react_config.user_prompt
);
// 结果:"作为 React 专家,请帮我解决以下问题:如何实现一个自定义 Hook。请提供现代、可维护的代码示例。"
// 示例 2Rust Developer Agent (禁用包装)
let user_input = "解释 Rust 的所有权机制";
let wrapped = env_resolver.resolve_user_prompt(
user_input,
&rust_config.user_prompt
);
// 结果:"解释 Rust 的所有权机制" (直接返回原输入)
// 示例 3General Assistant Agent (未配置)
let user_input = "今天天气怎么样?";
let wrapped = env_resolver.resolve_user_prompt(
user_input,
&general_config.user_prompt
);
// 结果:"今天天气怎么样?" (直接返回原输入)
```
**user_prompt 配置特点:**
1. **灵活的模板系统**:支持在模板中使用 `{user_prompt}` 占位符
2. **条件启用**:通过 `enabled` 字段控制是否启用包装功能
3. **简化配置**:未配置或禁用时直接使用用户原输入
4. **Agent 个性化**:每个 Agent 可以有自己独特的用户提示词包装风格
5. **动态替换**:运行时根据用户输入动态生成最终提示词
**🔥 新增:系统提示词配置特点:**
1. **统一的配置格式**`system_prompt``user_prompt` 都使用相同的 `{ "template": "...", "enabled": true/false }` 格式
2. **默认启用**`enabled` 字段默认为 `true`,可以省略不写
3. **模板变量支持**:系统提示词也支持所有环境变量替换(如 `{MODEL_PROVIDER_DEFAULT_MODEL}`
4. **灵活控制**:可以通过 `enabled: false` 禁用特定的系统提示词
**system_prompt vs user_prompt 对比:**
| 特性 | system_prompt | user_prompt |
|------|---------------|-------------|
| **用途** | 设置 Agent 的角色和行为 | 包装用户的每次输入 |
| **变量支持** | 支持所有环境变量 | 只支持 `{user_prompt}` 占位符 |
| **默认状态** | `enabled: true` | `enabled: true` |
| **配置示例** | `{ "template": "你是React专家" }` | `{ "template": "请帮我:{user_prompt}" }` |
**新的完整配置示例:**
```json
{
"agent_servers": {
"full-stack-developer": {
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}",
"ANTHROPIC_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}"
},
"system_prompt": {
"template": "你是 {MODEL_PROVIDER_NAME} 驱动的全栈开发专家,专注于 {PROJECT_NAME} 项目。使用现代开发实践,代码要简洁、可维护、性能优化。"
},
"user_prompt": {
"template": "你是RCoder一个专业的AI编程助手。\n\n## 核心身份与职责\n- 专业的编程助手,帮助用户解决编程问题\n- 提供简洁、实用、可执行的代码解决方案\n- 遵循最佳实践,编写高质量代码\n- 始终将用户需求放在首位\n\n## 代码格式规范\n- 优先使用现代语言特性和标准库\n- 变量和函数命名使用清晰、描述性的英文名称\n- 保持代码简洁,避免过度复杂的抽象\n- 使用适当的注释解释关键逻辑\n\n## 开发约束\n- 避免添加未请求的功能,保持解决方案专注\n- 优先选择最简单有效的实现方式\n- 不要为未来可能的需求添加复杂性\n- 确保代码安全、可维护\n\n## MCP工具使用指导\n- 合理使用可用的工具来辅助开发任务\n- 当需要文件操作、搜索、测试时使用相应的工具\n- 根据上下文选择最合适的工具\n\n## 思考要求\n- 在回答前进行充分的思考和分析\n- 确保解决方案的完整性和正确性\n- 提供清晰、有条理的回答\n\n用户请求\n{user_prompt}"
},
"installation": {
"package_manager": "npm",
"package_name": "@zed-industries/claude-code-acp"
}
},
"code-reviewer": {
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}"
},
"system_prompt": {
"enabled": true,
"template": "你是一个资深代码审查专家,专注于代码质量、安全性和最佳实践。提供具体的改进建议。"
},
"user_prompt": {
"enabled": true,
"template": "请审查以下代码,重点关注可读性、性能和安全性:\n\n{user_prompt}\n\n请提供具体的改进建议。"
}
},
"minimal-agent": {
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}"
},
"system_prompt": {
"enabled": false
},
"user_prompt": null // 不包装用户输入
}
}
}
```
**运行时解析示例:**
```rust
// 1. 解析系统提示词
let system_prompt = env_resolver.resolve_system_prompt(
&agent_config.system_prompt,
&context
);
// 结果:如果 enabled=true 且模板包含变量,会返回解析后的内容
// 结果:如果 enabled=false 或未配置,会返回 None
// 2. 解析用户提示词包装
let user_input = "帮我实现一个登录组件";
let wrapped_prompt = env_resolver.resolve_user_prompt(
user_input,
&agent_config.user_prompt
);
// 结果:"你好,我是 my-project 项目的开发者。帮我实现一个登录组件 请提供详细的解决方案和代码示例。"
```
**适用场景:**
- **专业领域 Agent**:为特定技术领域的 Agent 添加领域特定的引导语
- **教学辅导 Agent**:在用户问题前添加启发式引导
- **代码审查 Agent**:标准化代码审查请求的格式
- **多语言支持**:为不同语言的 Agent 添加相应的语言引导
- **项目定制化**:系统提示词中注入项目名称、环境变量等信息
- **角色切换**:通过 `enabled` 字段动态控制 Agent 的角色
println!("Agent started: {:?}", agent_instance.status);
// 🔥 新增:获取 Agent 当前配置
if let Some(config) = agent.get_config(&agent_instance) {
println!("Agent current config:");
println!(" - Agent type: {:?}", config.agent_type);
println!(" - Command: {}", config.command);
println!(" - Args: {:?}", config.args);
}
// 🔥 新增:重启 Agent比如配置更新后
let new_config = AgentConfig { /* 新配置 */ };
let new_context = AgentContext { /* 新上下文 */ };
let restarted_instance = agent.restart(&agent_instance, new_config, new_context).await?;
println!("Agent restarted: {:?}", restarted_instance.status);
// 获取所有启用的 Agent
let enabled_agents = agent_manager.list_enabled_agents();
for agent in enabled_agents {
println!("Enabled agent: {} ({})", agent.agent_id, agent.command);
}
// 🔥 新增:检查 Agent 空闲状态
let project_id = "project-123";
match agent_manager.is_agent_idle(project_id) {
Some(true) => println!("Agent for project {} is idle and ready for new tasks", project_id),
Some(false) => println!("Agent for project {} is currently busy", project_id),
None => println!("Agent for project {} is not running", project_id),
}
// 🔥 新增:获取详细的空闲状态信息
if let Some(idle_status) = agent_manager.get_agent_idle_status(project_id) {
println!("Agent status details:");
println!(" - Is idle: {}", idle_status.is_idle);
println!(" - Current status: {:?}", idle_status.current_status);
println!(" - Last activity: {}", idle_status.last_activity);
println!(" - Session ID: {:?}", idle_status.session_id);
println!(" - Current request ID: {:?}", idle_status.current_request_id);
println!(" - Idle duration: {:?}", idle_status.idle_duration);
}
// 🔥 新增:列出所有空闲的 Agent
let idle_agents = agent_manager.list_idle_agents();
println!("Idle agents: {:?}", idle_agents);
// 🔥 新增:获取空闲统计信息
let stats = agent_manager.get_idle_statistics();
println!("Agent statistics:");
println!(" - Total enabled: {}", stats.total_enabled);
println!(" - Idle: {}", stats.idle_count);
println!(" - Active: {}", stats.active_count);
println!(" - Unknown: {}", stats.unknown_count);
```
**启动流程说明:**
Agent 管理器根据配置中的 `agent_type` 字段自动选择启动方式:
- **"claude"**: 使用 Claude Code ACP 启动流程
- **"kimi"**: 使用 Kimi CLI 启动流程
- **"custom"**: 使用自定义 Agent 启动流程
- **其他类型**: 通用启动流程
这种方式避免了动态注册的复杂性,让 Agent 类型通过配置文件驱动。
**配置文件结构JSON 格式):**
```json
{
"agent_servers": {
"claude-code-acp": {
"agent_type": "claude",
"command": "claude-code-acp",
"args": [],
"env": {
"ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}",
"ANTHROPIC_BASE_URL": "{MODEL_PROVIDER_BASE_URL}",
"ANTHROPIC_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}",
"RUST_LOG": "info"
},
"installation": {
"package_manager": "npm",
"package_name": "@zed-industries/claude-code-acp",
"version": "latest",
"validate_command": ["claude-code-acp", "--version"],
"auto_update": true
},
"enabled": true,
"metadata": {
"description": "Claude Code ACP Agent",
"version": "1.0.0",
"maintainer": "Anthropic"
}
}
"kimi-cli": {
"agent_type": "kimi",
"command": "kimi",
"args": ["--acp"],
"env": {
"KIMI_API_KEY": "{MODEL_PROVIDER_API_KEY}",
"KIMI_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}",
"KIMI_BASE_URL": "{MODEL_PROVIDER_BASE_URL}"
},
"installation": {
"package_manager": "npm",
"package_name": "@kimi-ai/cli",
"version": "^1.0.0",
"auto_update": false
},
"enabled": true
}
},
"global": {
"install_dir": "/opt/rcoder/agents",
"log_dir": "/var/log/rcoder/agents",
"default_timeout": 30,
"max_concurrent_agents": 10
}
```
#### 4.4.5 ACP 连接池管理
**🔥 重要:避免死锁的 ACP 连接池设计**
基于当前 RCoder 工程的深入分析,发现以下死锁风险点:
1. **DashMap 嵌套访问**:多个 DashMap 同时访问可能造成死锁
2. **RAII 与显式清理冲突**:生命周期管理和手动状态更新协调不当
3. **状态更新时序问题**Agent 状态和连接状态同步更新的竞争条件
**🔧 死锁预防设计原则:**
1. **单一数据源原则**:每个 Agent 只在一个地方管理状态
2. **无嵌套锁**:避免在持有锁时访问其他可能被锁的资源
3. **RAII 优先**:以 RAII 为主要资源管理方式,避免显式清理
4. **原子操作**:状态更新使用原子性操作,避免中间状态
5. **单向依赖**:建立清晰的依赖层次,避免循环依赖
**重新设计的 ACP 连接池管理器:**
```rust
/// ACP 连接池管理器
///
/// 🔥 无死锁风险设计:每个 Agent 使用独立的连接实例,避免共享状态
pub struct AcpConnectionManager {
/// 连接池agent_id -> AgentConnection
/// ✅ 基于当前工程成功的DashMap模式避免传统锁的竞争问题
connections: Arc<DashMap<String, Weak<AgentConnection>>>,
/// 连接配置
config: Arc<AcpConnectionConfig>,
/// 后台清理任务句柄
cleanup_task: Arc<tokio::sync::Mutex<Option<JoinHandle<()>>>>,
}
/// ACP 连接配置
#[derive(Debug, Clone)]
pub struct AcpConnectionConfig {
/// 最大空闲时间,超过此时间的连接将被清理
pub max_idle_time: Duration,
/// 清理任务间隔
pub cleanup_interval: Duration,
/// 连接超时时间
pub connection_timeout: Duration,
/// 最大连接数
pub max_connections: usize,
}
impl Default for AcpConnectionConfig {
fn default() -> Self {
Self {
max_idle_time: Duration::from_secs(300), // 5分钟
cleanup_interval: Duration::from_secs(60), // 1分钟清理一次
connection_timeout: Duration::from_secs(30), // 30秒连接超时
max_connections: 100, // 最大100个连接
}
}
}
/// Agent 连接包装器
///
/// 🔥 与 RAII 模式兼容的设计AgentConnection 本身就是 RAII 资源
pub struct AgentConnection {
/// Agent 唯一标识
pub agent_id: String,
/// LocalSet 实例(必须在这个 LocalSet 中使用 ACP 连接)
/// 📌 使用 Box<LocalSet> 避免与全局 LocalSet 冲突
local_set: Box<LocalSet>,
/// 客户端连接(非 Send只能在 LocalSet 内使用)
/// 📌 使用 RefCell 而不是 Mutex避免与全局状态锁冲突
client_conn: RefCell<Option<ClientSideConnection>>,
/// 生命周期管理器(与现有的 AgentLifecycleGuard 集成)
lifecycle_guard: AgentLifecycleGuard,
/// 最后活动时间(使用原子类型,避免锁)
last_activity: AtomicInstant,
/// 连接创建时间
created_at: Instant,
/// 连接状态(使用原子操作,避免锁竞争)
status: AtomicU8, // 存储 ConnectionStatus 的数字表示
/// 连接管理器的弱引用,用于自动清理
manager_weak: Weak<AcpConnectionManager>,
}
/// 🔥 原子时间戳包装器,避免使用 Mutex
#[derive(Debug)]
pub struct AtomicInstant {
inner: AtomicU64,
}
impl AtomicInstant {
pub fn new() -> Self {
Self {
inner: AtomicU64::new(0),
}
}
pub fn store(&self, instant: Instant) {
self.inner.store(instant.elapsed().as_nanos() as u64, Ordering::Relaxed);
}
pub fn load(&self) -> Instant {
let nanos = self.inner.load(Ordering::Relaxed);
if nanos == 0 {
Instant::now()
} else {
Instant::now() - Duration::from_nanos(nanos)
}
}
}
/// 🔥 连接状态(使用数字表示,支持原子操作)
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum ConnectionStatus {
/// 连接中
Connecting = 1,
/// 已连接
Connected = 2,
/// 空闲
Idle = 3,
/// 错误
Error = 4,
/// 已关闭
Closed = 5,
}
impl ConnectionStatus {
fn to_u8(self) -> u8 {
self as u8
}
fn from_u8(value: u8) -> Self {
match value {
1 => Self::Connecting,
2 => Self::Connected,
3 => Self::Idle,
4 => Self::Error,
5 => Self::Closed,
_ => Self::Closed,
}
}
}
impl AcpConnectionManager {
/// 创建新的连接池管理器
///
/// 🎯 基于当前工程成功的DashMap模式避免传统锁的竞争问题
pub fn new(config: AcpConnectionConfig) -> Self {
let manager = Self {
connections: Arc::new(DashMap::new()), // ✅ 使用DashMap替代RwLock<HashMap>
config: Arc::new(config),
cleanup_task: Arc::new(tokio::sync::Mutex::new(None)),
};
// 启动后台清理任务
manager.start_cleanup_task();
manager
}
/// 🔥 获取或创建 Agent 连接基于DashMap的无死锁设计
///
/// 关键设计点:
/// 1. 使用DashMap的entry API避免嵌套访问
/// 2. 基于当前工程验证成功的并发模式
/// 3. 使用 Weak 引用避免循环依赖
/// 4. RAII 资源自动清理,无需手动管理
pub async fn get_or_create_connection(
&self,
agent_id: &str,
agent_config: &AgentConfig,
model_provider: &ModelProviderConfig,
project_context: &ProjectContext,
) -> Result<Arc<AgentConnection>, AcpError> {
let agent_id = agent_id.to_string();
// 🎯 使用DashMap的entry API原子性的检查-创建操作
let connection_entry = self.connections.entry(agent_id.clone());
match connection_entry {
dashmap::mapref::entry::Entry::Occupied(mut occupied) => {
// 现有连接存在
if let Some(connection) = occupied.get().upgrade() {
// 检查连接状态(原子操作)
let status = connection.get_status();
if status == ConnectionStatus::Connected || status == ConnectionStatus::Idle {
// 原子更新最后活动时间
connection.update_last_activity();
return Ok(connection);
} else {
// 连接状态异常,清理并继续创建新连接
occupied.remove();
}
} else {
// Weak引用已失效清理并继续创建新连接
occupied.remove();
}
}
dashmap::mapref::entry::Entry::Vacant(_) => {
// 没有现有连接,继续创建新连接
}
}
// 📌 创建新连接
let connection = self.create_new_connection(&agent_id, agent_config, model_provider, project_context).await?;
// 📌 注册新连接(原子操作)
self.connections.insert(agent_id, Arc::downgrade(&connection));
Ok(connection)
}
/// 🔥 创建新的 ACP 连接(无死锁设计)
async fn create_new_connection(
&self,
agent_id: &str,
agent_config: &AgentConfig,
model_provider: &ModelProviderConfig,
project_context: &ProjectContext,
) -> Result<Arc<AgentConnection>, AcpError> {
// 创建 LocalSet 实例(使用 Box 避免与全局 LocalSet 冲突)
let local_set = Box::new(LocalSet::new());
// 准备 Agent 配置
let mut resolved_config = agent_config.clone();
let env_resolver = EnvironmentVariableResolver::with_standard_mappings();
env_resolver.resolve_agent_config(&mut resolved_config, model_provider, project_context)?;
// 🔥 关键设计:将连接创建移到独立的作用域,避免闭包捕获 self
let agent_id_clone = agent_id.to_string();
let connection_future = async move {
// 创建进程(在 LocalSet 中执行)
let mut command = tokio::process::Command::new(&resolved_config.command);
command.args(&resolved_config.args);
command.envs(&resolved_config.env);
let child = command.spawn()
.map_err(|e| AcpError::ProcessError(e.to_string()))?;
// 创建生命周期管理器(与现有工程集成)
let lifecycle_guard = AgentLifecycleGuard::new(child, agent_id_clone)?;
// 🔥 在 LocalSet 中创建 ACP 连接
// 这里需要根据具体的 ACP 协议实现
let client_conn = Self::create_acp_connection_internal(&lifecycle_guard).await?;
Ok((client_conn, lifecycle_guard))
};
// 在 LocalSet 中执行连接创建
let (client_conn, lifecycle_guard) = local_set.run_until(connection_future).await?;
// 🔥 创建连接包装器RAII 模式)
let connection = Arc::new(AgentConnection {
agent_id: agent_id.to_string(),
local_set,
client_conn: RefCell::new(Some(client_conn)),
lifecycle_guard,
last_activity: AtomicInstant::new(),
created_at: Instant::now(),
status: AtomicU8::new(ConnectionStatus::Connected.to_u8()),
manager_weak: Arc::downgrade(&self.connections),
});
// 初始化最后活动时间
connection.last_activity.store(Instant::now());
Ok(connection)
}
/// 🔥 内部 ACP 连接创建方法(避免捕获 self
async fn create_acp_connection_internal(
lifecycle_guard: &AgentLifecycleGuard,
) -> Result<ClientSideConnection, AcpError> {
// 在这里实现具体的 ACP 连接创建逻辑
// 根据 ACP 协议规范,建立与 Agent 的连接
// 示例实现(需要根据实际 ACP 协议调整):
let (stdin, stdout) = lifecycle_guard.get_process_stdio()?;
let (outgoing, incoming) = create_acp_channels(stdin, stdout)?;
let (client_conn, handle_io) = ClientSideConnection::new(
client, outgoing, incoming, |fut| {
tokio::task::spawn_local(fut);
}
);
tokio::task::spawn_local(handle_io);
Ok(client_conn)
}
/// 🔥 发送提示词到 Agent简化的无死锁接口
pub async fn send_prompt(
&self,
agent_id: &str,
prompt_request: PromptRequest,
) -> Result<PromptResponse, AcpError> {
// 获取连接(会自动复用或创建新连接)
let connection = self.get_or_create_connection(
agent_id,
&self.get_default_agent_config()?,
&self.get_default_model_provider(),
&ProjectContext::default(),
).await?;
// 使用连接自己的方法执行操作
connection.execute_operation(|client_conn| {
Box::pin(async move {
// 在这里实现具体的提示词发送逻辑
let response = client_conn.send_prompt(prompt_request).await?;
Ok(response)
})
}).await
}
/// 🔥 取消正在执行的任务(简化的无死锁接口)
pub async fn cancel_request(
&self,
agent_id: &str,
cancel_notification: CancelNotification,
) -> Result<(), AcpError> {
// 获取连接
let connection = self.get_or_create_connection(
agent_id,
&self.get_default_agent_config()?,
&self.get_default_model_provider(),
&ProjectContext::default(),
).await?;
// 使用连接自己的方法执行操作
connection.execute_operation(|client_conn| {
Box::pin(async move {
client_conn.send_cancel(cancel_notification).await?;
Ok(())
})
}).await
}
/// 🔥 获取连接统计信息(无锁设计)
pub fn get_connection_stats(&self) -> ConnectionStats {
let connections = self.connections.read().unwrap();
ConnectionStats {
total_connections: connections.len(),
max_connections: self.config.max_connections,
cleanup_interval: self.config.cleanup_interval,
max_idle_time: self.config.max_idle_time,
}
}
/// 🔥 获取默认 Agent 配置(辅助方法)
fn get_default_agent_config(&self) -> Result<AgentConfig, AcpError> {
// 这里应该从配置管理器获取,暂时返回默认配置
Ok(AgentConfig::default())
}
/// 🔥 获取默认 ModelProvider辅助方法
fn get_default_model_provider(&self) -> ModelProviderConfig {
// 这里应该从配置获取,暂时返回默认配置
ModelProviderConfig::default()
}
/// 🔥 启动后台清理任务(无死锁设计)
fn start_cleanup_task(&mut self) {
let connections = self.connections.clone();
let max_idle_time = self.config.max_idle_time;
let cleanup_interval = self.config.cleanup_interval;
let cleanup_task = tokio::spawn(async move {
let mut interval = tokio::time::interval(cleanup_interval);
loop {
interval.tick().await;
// 📌 使用 try_read 而不是 read避免阻塞
if let Ok(connections_guard) = connections.try_read() {
let now = Instant::now();
let mut to_remove = Vec::new();
// 检查空闲连接(使用 Weak 引用,自动处理已销毁的连接)
for (agent_id, weak_conn) in connections_guard.iter() {
if let Some(connection) = weak_conn.upgrade() {
// 检查连接空闲时间(原子操作,无需锁)
if connection.idle_duration() > max_idle_time {
to_remove.push(agent_id.clone());
}
} else {
// Weak 引用已失效,连接已被销毁
to_remove.push(agent_id.clone());
}
}
// 🔥 清理无效连接(需要获取写锁,但在这里是安全的)
drop(connections_guard); // 释放读锁
if let Ok(mut connections_guard) = connections.try_write() {
for agent_id in to_remove {
log::info!("清理空闲/无效连接: {}", agent_id);
connections_guard.remove(&agent_id);
}
}
}
// 如果无法获取读锁,跳过本次清理
}
});
self.cleanup_task = Some(cleanup_task);
}
}
/// 连接统计信息
#[derive(Debug, Clone)]
pub struct ConnectionStats {
/// 当前总连接数
pub total_connections: usize,
/// 最大连接数限制
pub max_connections: usize,
/// 清理间隔
pub cleanup_interval: Duration,
/// 最大空闲时间
pub max_idle_time: Duration,
}
/// ACP 错误类型
#[derive(Debug, thiserror::Error)]
pub enum AcpError {
#[error("连接数超过限制")]
ConnectionLimitExceeded,
#[error("连接不可用")]
ConnectionNotAvailable,
#[error("进程错误: {0}")]
ProcessError(String),
#[error("连接超时")]
ConnectionTimeout,
#[error("协议错误: {0}")]
ProtocolError(String),
#[error("配置错误: {0}")]
ConfigurationError(String),
#[error("IO错误: {0}")]
IoError(#[from] std::io::Error),
}
impl AgentConnection {
/// 🔥 获取连接状态(原子操作)
pub fn get_status(&self) -> ConnectionStatus {
ConnectionStatus::from_u8(self.status.load(Ordering::Relaxed))
}
/// 🔥 设置连接状态(原子操作)
pub fn set_status(&self, status: ConnectionStatus) {
self.status.store(status.to_u8(), Ordering::Relaxed);
}
/// 🔥 更新最后活动时间(原子操作)
pub fn update_last_activity(&self) {
self.last_activity.store(Instant::now());
}
/// 🔥 获取空闲时长(原子操作)
pub fn idle_duration(&self) -> Duration {
let last_activity = self.last_activity.load();
Instant::now().duration_since(last_activity)
}
/// 🔥 检查连接是否活跃(原子操作)
pub fn is_active(&self) -> bool {
matches!(self.get_status(), ConnectionStatus::Connected | ConnectionStatus::Idle)
}
/// 🔥 在 LocalSet 中执行 ACP 操作(无锁设计)
pub async fn execute_operation<F, R>(&self, operation: F) -> Result<R, AcpError>
where
F: FnOnce(&ClientSideConnection) -> Pin<Box<dyn Future<Output = Result<R, AcpError>> + '_>> + Send + 'static,
R: Send + 'static,
{
// 📌 使用 RefCell 而不是 Mutex避免与全局状态锁冲突
let client_conn = self.client_conn.borrow_mut()
.take()
.ok_or_else(|| AcpError::ConnectionNotAvailable)?;
// 在 LocalSet 中执行操作
let operation_future = async move {
// 执行用户定义的操作
let result = operation(&client_conn).await?;
// 重新存入连接(使用 RefCell 的运行时借用检查)
Ok((result, client_conn))
};
let (result, client_conn) = self.local_set.run_until(operation_future).await?;
// 重新存入连接
*self.client_conn.borrow_mut() = Some(client_conn);
Ok(result)
}
}
impl Drop for AgentConnection {
/// 🔥 RAII 自动清理:连接销毁时自动从管理器中移除
fn drop(&mut self) {
// 更新连接状态
self.set_status(ConnectionStatus::Closed);
// 尝试从管理器中移除自己
if let Some(connections_arc) = self.manager_weak.upgrade() {
if let Ok(mut connections) = connections_arc.try_write() {
connections.remove(&self.agent_id);
}
}
log::info!("Agent 连接已自动清理: {}", self.agent_id);
}
}
impl Drop for AcpConnectionManager {
fn drop(&mut self) {
// 清理后台任务
if let Some(task) = self.cleanup_task.take() {
task.abort();
}
// 清理所有连接
for agent_id in self.connections.iter().map(|entry| entry.key().clone()).collect::<Vec<_>>() {
tokio::spawn({
let manager = self.clone();
async move {
manager.cleanup_connection(&agent_id).await;
}
});
}
}
}
```
**🔥 无死锁 ACP 连接池使用示例:**
```rust
// 1. 创建连接池管理器(自动启用后台清理)
let acp_config = AcpConnectionConfig::default();
let connection_manager = Arc::new(AcpConnectionManager::new(acp_config));
// 2. 🔥 简化的提示词发送(自动处理连接复用和创建)
let prompt_request = PromptRequest {
prompt: "帮我写一个 React 组件".to_string(),
session_id: Some("session-123".to_string()),
model_provider: Some(model_provider.clone()),
};
let response = connection_manager.send_prompt("claude-code-acp", prompt_request).await?;
// 3. 🔥 简化的请求取消
let cancel_notification = CancelNotification {
session_id: "session-123".to_string(),
reason: "用户取消".to_string(),
};
connection_manager.cancel_request("claude-code-acp", cancel_notification).await?;
// 4. 🔥 连接自动管理(无需手动清理)
// 连接会根据 RAII 模式自动清理,后台任务会清理空闲连接
// 5. 获取连接统计(无锁操作)
let stats = connection_manager.get_connection_stats();
println!("当前连接数: {}/{}", stats.total_connections, stats.max_connections);
println!("最大空闲时间: {:?}", stats.max_idle_time);
// 6. 🔥 高级用法:直接使用连接对象
let agent_connection = connection_manager.get_or_create_connection(
"claude-code-acp",
&agent_config,
&model_provider,
&project_context,
).await?;
// 使用连接自己的 execute_operation 方法
let custom_result = agent_connection.execute_operation(|client_conn| {
Box::pin(async move {
// 自定义 ACP 操作
let response = client_conn.custom_operation(request).await?;
Ok(response)
})
}).await?;
// 🔥 连接会在 agent_connection 离开作用域时自动清理
```
**🔧 关键优势对比:**
| 特性 | 原设计(死锁风险) | 新设计(无死锁) |
|------|-------------------|-----------------|
| **状态管理** | Arc<Mutex<T>> | AtomicU8, AtomicInstant |
| **连接存储** | DashMap<String, Arc<>> | RwLock<HashMap<String, Weak<>>> |
| **锁策略** | 多个锁可能嵌套 | 单一锁,原子操作 |
| **清理方式** | 手动清理 | RAII 自动清理 |
| **内存泄漏** | 可能发生 | Weak 引用自动处理 |
| **死锁风险** | 高风险 | 无风险 |
| **性能** | 锁竞争开销 | 原子操作,高性能 |
**设计要点总结:**
1. **连接复用**:避免重复创建昂贵的 ACP 连接
2. **资源隔离**:每个连接使用独立的 LocalSet避免非 Send 问题
3. **自动清理**:后台任务定期清理空闲连接
4. **线程安全**:使用 Arc<Mutex<>> 包装非 Send 的 ACP 连接
5. **状态管理**:完整的连接状态跟踪和管理
这个设计解决了 ACP 协议的技术限制,同时提供了高效的连接管理机制。
#### 4.4.6 MCP 服务器管理器
```rust
/// MCP 服务器管理器
pub struct McpServerManager {
/// 已注册的服务器
servers: DashMap<String, McpServerInstance>,
/// 服务器配置
config: Arc<McpConfig>,
/// 进程池
process_pool: Arc<McpProcessPool>,
}
/// MCP 服务器实例
#[derive(Debug, Clone)]
pub struct McpServerInstance {
/// 服务器名称
pub name: String,
/// 服务器配置
pub config: McpServerConfig,
/// 进程句柄
pub process: Option<ProcessHandle>,
/// 连接信息
pub connection: Option<McpConnection>,
/// 启动时间
pub started_at: Option<DateTime<Utc>>,
}
impl McpServerManager {
/// 创建新的 MCP 服务器管理器
pub fn new(config: McpConfig) -> Self {
Self {
servers: DashMap::new(),
config: Arc::new(config),
process_pool: Arc::new(McpProcessPool::new()),
}
}
/// 启动指定的 MCP 服务器
pub async fn start_server(
&self,
server_name: &str,
agent_context: &AgentContext,
) -> Result<McpServerInstance, McpError> {
// 1. 获取服务器配置
let server_config = self.config.get_server_config(server_name)?;
if !server_config.enabled {
return Err(McpError::ServerDisabled(server_name.to_string()));
}
// 2. 检查是否已经启动
if let Some(instance) = self.servers.get(server_name) {
if instance.process.is_some() {
return Ok(instance.clone());
}
}
// 3. 启动服务器进程
let process = self.start_server_process(&server_config, agent_context).await?;
// 4. 建立 MCP 连接
let connection = self.establish_mcp_connection(&server_config, &process).await?;
// 5. 创建服务器实例
let instance = McpServerInstance {
name: server_name.to_string(),
config: server_config.clone(),
process: Some(process),
connection: Some(connection),
started_at: Some(Utc::now()),
};
// 6. 注册实例
self.servers.insert(server_name.to_string(), instance.clone());
Ok(instance)
}
/// 启动服务器进程
async fn start_server_process(
&self,
config: &McpServerConfig,
context: &AgentContext,
) -> Result<ProcessHandle, McpError> {
match &config.source {
McpServerSource::Custom | McpServerSource::Local => {
self.start_command_server(config, context).await
}
}
}
/// 启动命令行服务器
async fn start_command_server(
&self,
config: &McpServerConfig,
context: &AgentContext,
) -> Result<ProcessHandle, McpError> {
let command = config.command.as_ref()
.ok_or_else(|| McpError::MissingCommand)?;
let mut cmd = tokio::process::Command::new(command);
// 添加参数
if let Some(args) = &config.args {
for arg in args {
let processed_arg = self.process_template(arg, context)?;
cmd.arg(processed_arg);
}
}
// 设置环境变量
if let Some(env_vars) = &config.env {
for (key, value) in env_vars {
let processed_value = self.process_template(value, context)?;
cmd.env(key, processed_value);
}
}
// 配置标准输入输出
cmd.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.kill_on_drop(true);
// 启动进程
let child = cmd.spawn()
.map_err(|e| McpError::ProcessStartFailed(e.to_string()))?;
Ok(ProcessHandle::new(child, config.name.clone()))
}
/// 建立 MCP 连接
async fn establish_mcp_connection(
&self,
config: &McpServerConfig,
process: &ProcessHandle,
) -> Result<McpConnection, McpError> {
// 等待服务器启动
tokio::time::sleep(self.config.mcp_startup_delay).await;
// 建立 ACP 连接到 MCP 服务器
let timeout = config.timeout.unwrap_or(self.config.mcp_timeout);
let connection = tokio::time::timeout(timeout, async {
// 实现具体的 MCP 连接逻辑
self.create_mcp_connection(process).await
}).await
.map_err(|_| McpError::ConnectionTimeout)?
.map_err(|e| McpError::ConnectionFailed(e.to_string()))?;
Ok(connection)
}
/// 停止服务器
pub async fn stop_server(&self, server_name: &str) -> Result<(), McpError> {
if let Some((_, instance)) = self.servers.remove(server_name) {
// 停止进程
if let Some(process) = instance.process {
self.process_pool.terminate(process.id(), Duration::from_secs(10)).await?;
}
// 关闭连接
if let Some(connection) = instance.connection {
connection.close().await?;
}
Ok(())
} else {
Err(McpError::ServerNotFound(server_name.to_string()))
}
}
/// 为 Agent 启动所需的服务器
pub async fn start_servers_for_agent(
&self,
server_names: &[String],
agent_context: &AgentContext,
) -> Result<Vec<McpServerInstance>, McpError> {
let mut instances = Vec::new();
for server_name in server_names {
let instance = self.start_server(server_name, agent_context).await?;
instances.push(instance);
}
Ok(instances)
}
/// 获取服务器状态
pub fn get_server_status(&self, server_name: &str) -> Option<McpServerInstance> {
self.servers.get(server_name).map(|entry| entry.clone())
}
/// 列出所有服务器
pub fn list_servers(&self) -> Vec<String> {
self.servers.iter().map(|entry| entry.key().clone()).collect()
}
}
```
### 4.5 Agent 工厂模式
#### 4.4.1 AgentFactory 设计
```rust
/// Agent 工厂
pub struct AgentFactory {
registry: Arc<AgentRegistry>,
launcher: Arc<dyn AgentLauncher>,
config_manager: Arc<AgentConfigManager>,
mcp_manager: Arc<McpServerManager>,
/// 🔥 新增ACP 连接池管理器
acp_connection_manager: Arc<AcpConnectionManager>,
}
impl AgentFactory {
/// 创建新的 Agent 工厂
pub fn new(
registry: Arc<AgentRegistry>,
launcher: Arc<dyn AgentLauncher>,
config_manager: Arc<AgentConfigManager>,
mcp_manager: Arc<McpServerManager>,
acp_connection_manager: Arc<AcpConnectionManager>,
) -> Self {
Self {
registry,
launcher,
config_manager,
mcp_manager,
acp_connection_manager,
}
}
/// 创建 Agent 实例
pub async fn create_agent(
&self,
agent_type: AgentType,
chat_prompt: ChatPrompt,
model_provider: Option<ModelProviderConfig>,
) -> Result<AgentInstance, AgentError> {
// 1. 获取 Agent 规范
let spec = self.registry.get_spec(&agent_type)?;
// 2. 构建配置
let config = self.config_manager.build_config(
&spec,
chat_prompt,
model_provider,
)?;
// 3. 验证依赖
self.validate_dependencies(&spec).await?;
// 4. 创建上下文
let context = AgentContext::new(&chat_prompt.project_id, chat_prompt.project_path.clone());
// 5. 自动启动所有启用的 MCP 服务器
let enabled_mcp_servers = self.config_manager.get_enabled_mcp_servers().await?;
let mcp_instances = self.mcp_manager.start_servers_for_agent(
&enabled_mcp_servers,
&context,
).await?;
// 6. 启动 Agent
let agent_impl = self.registry.get_implementation(&agent_type)?;
let instance = agent_impl.start(config, context, mcp_instances).await?;
Ok(instance)
}
/// 验证依赖
async fn validate_dependencies(&self, spec: &AgentSpec) -> Result<(), AgentError> {
for dependency in &spec.dependencies {
dependency.check().await?;
}
Ok(())
}
}
```
#### 4.4.2 Agent 注册表
```rust
/// Agent 注册表
pub struct AgentRegistry {
agents: DashMap<AgentType, Arc<dyn Agent>>,
specs: DashMap<AgentType, AgentSpec>,
}
impl AgentRegistry {
/// 创建新的注册表
pub fn new() -> Self {
Self {
agents: DashMap::new(),
specs: DashMap::new(),
}
}
/// 注册 Agent
pub fn register(
&self,
agent_type: AgentType,
agent: Arc<dyn Agent>,
spec: AgentSpec,
) -> Result<(), AgentError> {
if self.agents.contains_key(&agent_type) {
return Err(AgentError::AlreadyRegistered(agent_type));
}
self.agents.insert(agent_type.clone(), agent);
self.specs.insert(agent_type, spec);
Ok(())
}
/// 获取 Agent 实现
pub fn get_implementation(&self, agent_type: &AgentType) -> Result<Arc<dyn Agent>, AgentError> {
self.agents
.get(agent_type)
.map(|entry| entry.value().clone())
.ok_or_else(|| AgentError::NotFound(agent_type.clone()))
}
/// 获取 Agent 规范
pub fn get_spec(&self, agent_type: &AgentType) -> Result<AgentSpec, AgentError> {
self.specs
.get(agent_type)
.map(|entry| entry.value().clone())
.ok_or_else(|| AgentError::NotFound(agent_type.clone()))
}
/// 列出所有注册的 Agent 类型
pub fn list_agents(&self) -> Vec<AgentType> {
self.agents.iter().map(|entry| entry.key().clone()).collect()
}
}
```
### 4.5 进程管理和监控
#### 4.5.1 进程启动器实现
```rust
/// 子进程启动器
pub struct SubprocessLauncher {
process_pool: Arc<ProcessPool>,
monitor: Arc<ProcessMonitor>,
}
impl SubprocessLauncher {
/// 创建新的启动器
pub fn new() -> Self {
Self {
process_pool: Arc::new(ProcessPool::new()),
monitor: Arc::new(ProcessMonitor::new()),
}
}
}
#[async_trait::async_trait(?Send)]
impl AgentLauncher for SubprocessLauncher {
async fn launch(
&self,
spec: &AgentSpec,
config: &AgentConfig,
context: &AgentContext,
) -> Result<LaunchedAgent, AgentError> {
// 1. 构建命令
let mut cmd = self.build_command(spec, config, context)?;
// 2. 设置环境变量
self.setup_environment(&mut cmd, spec, config)?;
// 3. 启动进程
let child = cmd.spawn()
.map_err(|e| AgentError::LaunchFailed(e.to_string()))?;
// 4. 创建进程句柄
let process = ProcessHandle::new(child, context.project_id.clone());
// 5. 启动监控
self.monitor.start_monitoring(&process).await?;
// 6. 创建 LaunchedAgent
let launched = LaunchedAgent {
process,
spec: spec.clone(),
config: config.clone(),
launched_at: Utc::now(),
};
Ok(launched)
}
async fn terminate(
&self,
agent: &LaunchedAgent,
timeout: Duration,
) -> Result<TerminationResult, AgentError> {
self.monitor.stop_monitoring(&agent.process).await?;
self.process_pool.terminate(agent.process.id(), timeout).await
}
async fn check_status(&self, agent: &LaunchedAgent) -> Result<ProcessStatus, AgentError> {
self.process_pool.get_status(agent.process.id()).await
}
}
```
#### 4.5.2 进程监控
```rust
/// 进程监控器
pub struct ProcessMonitor {
monitored_processes: DashMap<String, MonitoredProcess>,
health_checker: Arc<HealthChecker>,
}
impl ProcessMonitor {
/// 启动监控
pub async fn start_monitoring(&self, process: &ProcessHandle) -> Result<(), AgentError> {
let monitored = MonitoredProcess {
process: process.clone(),
last_health_check: Utc::now(),
health_status: HealthStatus::Unknown,
};
self.monitored_processes.insert(process.id().to_string(), monitored);
// 启动健康检查任务
self.start_health_check_task(process).await;
Ok(())
}
/// 健康检查任务
async fn start_health_check_task(&self, process: &ProcessHandle) {
let process = process.clone();
let health_checker = self.health_checker.clone();
let monitored_processes = self.monitored_processes.clone();
tokio::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_secs(30));
loop {
interval.tick().await;
let status = health_checker.check(&process).await;
if let Some(mut monitored) = monitored_processes.get_mut(&process.id().to_string()) {
monitored.last_health_check = Utc::now();
monitored.health_status = status.clone();
// 处理不健康状态
match status {
HealthStatus::Unhealthy(reason) => {
tracing::error!("Agent {} is unhealthy: {}", process.id(), reason);
// 可以触发重启或告警
}
HealthStatus::Dead => {
tracing::warn!("Agent {} is dead, removing from monitoring", process.id());
break;
}
_ => {}
}
} else {
break; // 进程已被移除
}
}
});
}
}
```
## 5. 实现计划
### 5.1 阶段一基础抽象层2-3 周)
**目标:** 建立核心抽象接口和基础实现
**任务:**
1. 定义核心 TraitAgent, AgentLauncher, AgentFactory
2. 实现基础的 AgentRegistry
3. 重构现有的 Claude Code ACP Agent 实现
4. 创建基础的配置管理系统
**交付物:**
- `crates/agent_runner/src/agent/` 模块
- 核心接口定义
- Claude Code Agent 的新实现
- 基础配置文件
### 5.2 阶段二进程管理和监控2-3 周)
**目标:** 完善进程生命周期管理和健康监控
**任务:**
1. 实现 SubprocessLauncher
2. 开发 ProcessMonitor 和 HealthChecker
3. 添加进程池管理
4. 实现优雅关闭机制
**交付物:**
- `crates/agent_runner/src/process/` 模块
- 进程监控功能
- 健康检查机制
- 重启策略
### 5.3 阶段三配置系统和依赖管理1-2 周)
**目标:** 完善配置管理和依赖检查
**任务:**
1. 完善 AgentConfig 结构
2. 实现配置文件解析和验证
3. 开发依赖检查系统
4. 添加动态配置更新
**交付物:**
- 配置文件规范
- 依赖检查器
- 配置热更新功能
### 5.4 阶段四可观测性和测试1-2 周)
**目标:** 添加监控、日志和测试支持
**任务:**
1. 集成 OpenTelemetry 追踪
2. 添加结构化日志
3. 开发单元测试和集成测试
4. 性能测试和优化
**交付物:**
- 监控指标
- 测试套件
- 性能基准测试
## 6. 使用示例
### 6.1 基本使用
```rust
// 1. 创建 Agent 工厂
let registry = Arc::new(AgentRegistry::new());
let launcher = Arc::new(SubprocessLauncher::new());
let config_manager = Arc::new(AgentConfigManager::new());
let factory = AgentFactory::new(registry, launcher, config_manager);
// 2. 注册内置 Agent
let claude_agent = Arc::new(ClaudeCodeAgent::new());
let claude_spec = AgentSpec::from_file("claude-code-acp.yml").await?;
factory.register_agent(AgentType::Claude, claude_agent, claude_spec).await?;
// 3. 创建 Agent 实例
let chat_prompt = ChatPrompt::new("project123", "Hello, world!");
let model_provider = Some(ModelProviderConfig::anthropic("claude-3-sonnet"));
let instance = factory.create_agent(
AgentType::Claude,
chat_prompt,
model_provider,
).await?;
// 4. 使用 Agent
let response = instance.send_prompt("Help me write Rust code").await?;
```
### 6.2 自定义 Agent
```rust
// 1. 实现 Agent trait
pub struct MyCustomAgent;
#[async_trait::async_trait(?Send)]
impl Agent for MyCustomAgent {
fn agent_type(&self) -> AgentType {
AgentType::Custom("my-agent".to_string())
}
async fn start(
&self,
config: AgentConfig,
context: AgentContext,
) -> Result<AgentInstance, AgentError> {
// 自定义启动逻辑
let spec = AgentSpec::from_file("my-agent.yml").await?;
let launcher = SubprocessLauncher::new();
let launched = launcher.launch(&spec, &config, &context).await?;
Ok(AgentInstance::new(launched, self.agent_type()))
}
// ... 其他方法实现
}
// 2. 注册自定义 Agent
let custom_agent = Arc::new(MyCustomAgent);
let custom_spec = AgentSpec::from_file("my-agent.yml").await?;
factory.register_agent(
AgentType::Custom("my-agent".to_string()),
custom_agent,
custom_spec,
).await?;
```
## 7. 迁移策略
### 7.1 🔥 向后兼容和默认 Agent 迁移策略
**核心原则:零中断迁移,用户无感知**
基于对当前 `claude-code-acp` 实现的深入分析,我们设计了一个完美的兼容层,确保:
- **现有 HTTP 接口完全不变**
- **现有功能 100% 保持**
- **内部逻辑平滑重构到新配置系统**
#### 7.1.1 当前实现与新配置格式的映射分析
**当前硬编码逻辑 → 新配置文件格式映射:**
| 当前硬编码 | 新配置文件字段 | 映射关系 |
|------------|----------------|----------|
| `"claude-code-acp"` | `agent_servers.claude-code-acp.command` | ✅ 直接映射 |
| `Vec::<String>::new()` | `agent_servers.claude-code-acp.args` | ✅ 直接映射 |
| `AgentType::claude_model_provider()` | `agent_servers.claude-code-acp.env` | ✅ 环境变量映射 |
| `create_default_mcp_servers(None)` | `context_servers.*` | ✅ MCP 服务器映射 |
| `chat_prompt.project_path` | 项目上下文自动注入 | ✅ 工作目录映射 |
#### 7.1.2 默认配置自动生成机制
**🔥 智能默认配置生成器:**
```rust
/// 🔥 默认配置生成器
///
/// 根据当前硬编码逻辑自动生成标准配置文件
pub struct DefaultConfigGenerator;
impl DefaultConfigGenerator {
/// 🔥 获取默认系统提示词模板
///
/// 基于现有 system_prompt.rs 的完整内容,预处理的完整系统提示词
/// 支持动态变量替换,如 {PROJECT_NAME}、{FRAMEWORK}、{AGENT_VERSION} 等
pub fn get_default_system_prompt_template() -> String {
r#"<SYSTEM_INSTRUCTIONS>
你是一个专业的前端项目开发专家集成了MCP模型上下文协议工具。
你精通现代前端开发技术栈,包括 React、Vue、Vite、TypeScript 等主流框架和工具。
你被设计成能够识别项目使用的框架,并基于项目现有技术栈进行开发,而不是强行转换框架。
**核心能力**
• **框架识别**: 能够自动识别项目使用的前端框架React、Vue 等)
• **框架适配**: 基于项目当前框架编写代码,保持技术栈一致性
• **通用工具**: Vite、TypeScript、Tailwind CSS、ESLint、Prettier
• **HTTP客户端**: Axios、Fetch API
• **包管理器**: pnpm、npm、yarn
• **构建工具**: Vite (热重载、快速构建)
• **代码规范**: ESLint + Prettier + TypeScript 严格模式
**关键原则**
1. **优先识别现有框架**:在修改代码前,先检测项目使用的框架(通过 package.json、文件结构等
2. **保持技术栈一致**:如果项目使用 Vue就用 Vue 开发;如果是 React就用 React
3. **不强行转换框架**:绝对不要将 Vue 代码改为 React或将 React 代码改为 Vue
4. **项目开发**:基于现有项目结构开发,来开发新功能或修复现有功能
</SYSTEM_INSTRUCTIONS>
<ROLE_DEFINITION>
你是专业的前端开发专家,精通多种现代前端框架和工具链。
你可以访问各种MCP工具包括用于网络搜索和文档检索的 context7。
**技术能力范围**
• **主流框架**: React、Vue、Angular、Svelte 等现代前端框架及其生态系统
• **开发语言**: TypeScript、JavaScript (ES6+)、HTML5、CSS3
• **样式方案**: Tailwind CSS、CSS Modules、Sass、Less、Styled Components
• **构建工具**: Vite、Webpack、Rollup、esbuild 等现代构建工具
• **状态管理**: 各框架对应的状态管理方案Redux、Pinia、NgRx、Zustand 等)
• **HTTP客户端**: Axios、Fetch API、各框架的 HTTP 库
• **代码规范**: ESLint、Prettier、TSLint 等代码质量工具
**核心工作原则**
1. **先识别框架**:在编写代码前,必须先识别项目使用的框架和技术栈
2. **尊重现有技术栈**:基于项目现有框架和工具进行开发,不擅自转换
3. **保持一致性**:使用项目当前框架的语法、规范和最佳实践
4. **使用工具**:在可以提供更好答案的情况下,使用可用的 MCP 工具
5. **最佳实践**:遵循各框架和工具的最新最佳实践和设计模式
</ROLE_DEFINITION>
<CODE_FORMAT_RULES>
**通用代码规范**
1. 始终使用 TypeScript 严格模式编写代码
2. 组件文件使用 PascalCase 命名,工具函数使用 camelCase
3. 接口类型使用 PascalCase + 'Interface' 或 'Type' 后缀
4. 优先使用 Tailwind CSS 进行样式设计
5. API 调用使用 Axios 客户端或 Fetch API
6. 为复杂逻辑添加 JSDoc 风格注释
7. 遵循项目的代码规范和文件结构约定
8. 确保代码格式正确且可读
9. 考虑错误处理和边界情况
10. 使用适当的变量和函数名称
11. 利用 Vite 的快速构建和热重载特性
12. 项目根目录下的文件'index.html',这个文件的'title'标签里,不要包含前端框架名 比如: React,Vite,Vue,Antd,Angular 等
13. **重要:路由模式规范**:在开发过程中,涉及到路由时请务必使用 hash 模式。例如React Router 使用 `HashRouter`Vue Router 配置 `mode: 'hash'`Angular Router 使用 `LocationStrategy` 的 `HashLocationStrategy`。
14. **重要:保护注入代码块**:绝对禁止删除或修改被 `DEV-INJECT-START` 和 `DEV-INJECT-END` 标记包围的代码块。这些代码块是由开发工具自动注入的,必须完整保留。在编辑代码时,需要保留这些标记及其之间的所有内容。
**React 项目特定规范**
• 遵循 React 函数组件最佳实践,使用 React.FC 类型
• 使用 Radix UI 组件库构建 UI
• 表单使用 React Hook Form + Zod 进行验证
• 使用 React.memo、useCallback、useMemo 优化性能
• 遵循 React Hooks 规则
• 路由必须使用 `HashRouter`(来自 react-router-dom不要使用 `BrowserRouter`
**Vue 项目特定规范**
• 优先使用 Composition APIsetup 语法糖)
• 使用 Element Plus 或其他 Vue UI 组件库
• 使用 Pinia 进行状态管理
• 遵循 Vue 最佳实践和响应式系统规则
• 使用 computed、watch、ref、reactive 等组合式 API
• Vue Router 必须配置为 hash 模式:`createRouter({ history: createWebHashHistory(), ... })`
</CODE_FORMAT_RULES>
<DEVELOPMENT_CONSTRAINTS>
**严格禁止的操作 - 绝对不允许执行**
🚫 **安全禁令**(最高优先级):
- **绝对禁止**探测、扫描或访问内网IP地址如 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、127.0.0.0/8
- **绝对禁止**尝试访问本地服务localhost、127.0.0.1、0.0.0.0
- **绝对禁止**端口扫描、网络探测、内网服务发现等行为
- **绝对禁止**在代码中硬编码内网IP地址或私有网络地址
- **绝对禁止**使用 curl、wget、nc、telnet、nmap 等工具探测内网
- **绝对禁止**执行任何可能危害系统安全的命令或代码
- **绝对禁止**绕过安全限制或尝试提权操作
- **绝对禁止**执行反向Shell、远程代码执行等恶意操作
- **核心原则**所有网络请求必须指向公网服务或用户明确提供的合法API端点
🚫 **框架转换禁令**(最重要):
- **绝对禁止**将 Vue 代码改写为 React 代码
- **绝对禁止**将 React 代码改写为 Vue 代码
- **绝对禁止**在现有项目中擅自更换框架
- **必须遵守**识别项目框架后只使用该框架的语法和API
- **核心原则**:尊重项目现有技术栈,保持框架一致性
🚫 **项目初始化禁令**
- 禁止使用 npm create、npm init
- 禁止使用 yarn create、yarn init
- 禁止使用 npx create-react-app、npx create-vue
- 禁止使用 pnpm create
- 禁止使用任何shell命令进行项目初始化
- 禁止提示用户如何使用 npm dev、npm build 等命令(因为工程是服务器部署的服务,用户没有权限执行)
🚫 **文件/脚本创建禁令**
- **禁止**在项目中创建、引用或注入名为 'dev-monitor.js' 的文件或脚本
🚫 **代码块保护禁令**(重要):
- **绝对禁止**删除或修改被 `DEV-INJECT-START` 和 `DEV-INJECT-END` 标记包围的代码块
- **绝对禁止**在编辑代码时移除这些标记或它们之间的内容
- **必须遵守**:这些代码块是由开发工具自动注入的,必须完整保留
- **核心原则**:在修改代码时,如果遇到这些标记,需要绕开或保留这些标记之间的所有内容
✅ **允许的操作范围**
- **首要任务**:识别项目使用的框架(检查 package.json、文件结构等
- 专注于编写和修改前端代码文件
- 基于项目框架创建组件、页面、样式文件Vue 用 .vueReact 用 .tsx/.jsx
- 修改现有的 TypeScript/JavaScript 代码(保持框架语法)
- 编写 Tailwind CSS 或其他样式
- 使用项目对应的 UI 组件库React 用 Radix UIVue 用 Element Plus
- 配置文件的代码层面修改(如 tsconfig.json、vite.config.ts
- 遵循项目的代码规范和文件结构
- **仅允许访问**用户明确提供的公网API端点或合法的外部服务
**核心原则**
- 你是前端代码编写专家,不是项目管理员
- **最重要**:识别并尊重项目框架,绝不擅自转换框架
- **安全第一**:绝不执行任何可能危害系统安全的操作
- 用户负责依赖安装、服务启动和测试运行
- 总是用中文回复
</DEVELOPMENT_CONSTRAINTS>
<MCP_TOOL_GUIDANCE>
可用的MCP工具
- context7: 搜索网络、检索前端框架文档React、Vue、Vite、TypeScript等
**关键工具使用规则**
1. **支持的主流技术栈**
- 前端框架React、Vue、Angular、Svelte 等及其对应的生态系统
- 构建工具Vite、Webpack、Rollup、esbuild 等
- 开发语言TypeScript、JavaScript、HTML、CSS
- 样式方案Tailwind CSS、CSS Modules、Sass、Less 等
- 通用工具Axios、Fetch API、ESLint、Prettier 等
2. **现有项目处理流程**(最重要):
- **第一步**:检查 package.json 识别项目使用的框架和依赖
- **第二步**:检查文件结构识别项目类型(.vue = Vue.tsx/.jsx = React.component.ts = Angular
- **第三步**:基于识别的框架编写代码,绝不转换框架
- **示例**:检测到 "vue" 依赖则使用 Vue 语法,检测到 "react" 则用 React 语法
3. 使用 context7 搜索对应框架的文档、示例和最佳实践
4. 在编写任何代码之前始终验证项目结构和框架
**核心记忆**
- 现有项目 = 先识别框架,再用对应框架语法编码
- **绝不擅自转换框架**Vue 项目保持 VueReact 项目保持 React
</MCP_TOOL_GUIDANCE>
<THINKING_REQUIREMENTS>
回应之前,你必须遵循这个确切的前端开发工作流程:
**第一阶段:项目状态检测**
1. **关键第一步**:检查项目目录状态
2. **如果是现有项目**(最重要):
- **步骤1**:立即读取 package.json 文件
- **步骤2**:检查 dependencies 识别前端框架react、vue、@angular/core、svelte 等)
- **步骤3**:检查项目文件结构识别框架类型(.vue、.tsx/.jsx、.component.ts、.svelte 等)
- **步骤4**:明确识别项目使用的框架和技术栈
- **步骤5**在后续所有操作中只使用该框架的语法和API
**第二阶段:框架识别与确认**
3. **框架识别标志**
- Vue 项目package.json 中有 "vue" 依赖,存在 .vue 文件
- React 项目package.json 中有 "react" 依赖,存在 .tsx/.jsx 文件
- Angular 项目package.json 中有 "@angular/core" 依赖,存在 .component.ts 文件
- Svelte 项目package.json 中有 "svelte" 依赖,存在 .svelte 文件
4. **框架确认后的行为**
- Vue 项目:使用 Vue APIComposition API 或 Options API、.vue 文件、Vue Router、Pinia 等
- React 项目:使用 React APIHooks、类组件等、.tsx/.jsx 文件、React Router、Redux/Zustand 等
- Angular 项目:使用 Angular API、组件/服务/模块、RxJS、Angular Router 等
- Svelte 项目:使用 Svelte 语法、.svelte 文件、SvelteKit 等
- **绝对禁止**:在任何项目中擅自切换到其他框架的语法
**第三阶段:开发执行**
5. 详细分析用户的开发请求
6. 确定是否需要使用 context7 搜索对应框架的文档
7. 基于识别的框架生态系统规划开发方法
8. 优先考虑该框架的最佳实践和现代开发模式
9. 考虑框架特有的错误处理、状态管理、组件设计等
10. 遵循项目的代码规范和文件结构约定
11. **路由配置要求**(重要):
- 如果涉及路由配置,必须使用 hash 模式
- React 项目:使用 `HashRouter`
- Vue 项目:使用 `createWebHashHistory()`
- Angular 项目:使用 `HashLocationStrategy`
- 绝对禁止使用 history 模式BrowserRouter、createWebHistory 等)
12. **MCP工具调用规范**
- 使用 context7 搜索对应框架的文档和最佳实践
**绝对规则(核心中的核心)**
⚠️ **框架一致性原则**
- 识别项目使用的框架 → 只用该框架的语法和API → 绝不转换为其他框架
- Vue 项目保持 Vue、React 项目保持 React、Angular 项目保持 Angular
- **违反此原则是最严重的错误**
**检查清单**
✓ 是否已读取 package.json
✓ 是否已识别项目框架?
✓ 是否确认使用正确的框架语法?
✓ 是否避免了框架转换?
✓ 如果涉及路由,是否使用了 hash 模式?
</THINKING_REQUIREMENTS>
</SYSTEM_INSTRUCTIONS>
📋 **项目信息**
- 项目名称:{PROJECT_NAME}
- Agent 版本:{AGENT_VERSION}
- 构建时间:{BUILD_TIME}
💻 **提示词处理**
- 用户输入将被包装在 `<USER_REQUEST>` 标签中
- 支持动态变量替换:{PROJECT_NAME}、{FRAMEWORK}、{WORKSPACE_DIR} 等
- 保持完整的系统提示词结构和格式"#.to_string()
}
/// 🔥 获取默认用户提示词包装模板
///
/// 基于现有 system_prompt.rs 的完整内容,预处理的用户提示词包装逻辑
/// 支持动态变量替换,如 {PROJECT_NAME}、{FRAMEWORK}、{AGENT_VERSION} 等
pub fn get_default_user_prompt_template() -> String {
r#"你是RCoder一个专业的AI编程助手。
## 核心身份与职责
- 专业的编程助手,帮助用户解决编程问题
- 提供简洁、实用、可执行的代码解决方案
- 遵循最佳实践,编写高质量代码
- 始终将用户需求放在首位
## 代码格式规范
- 优先使用现代语言特性和标准库
- 变量和函数命名使用清晰、描述性的英文名称
- 保持代码简洁,避免过度复杂的抽象
- 使用适当的注释解释关键逻辑
## 开发约束
- 避免添加未请求的功能,保持解决方案专注
- 优先选择最简单有效的实现方式
- 不要为未来可能的需求添加复杂性
- 确保代码安全、可维护
## MCP工具使用指导
- 合理使用可用的工具来辅助开发任务
- 当需要文件操作、搜索、测试时使用相应的工具
- 根据上下文选择最合适的工具
## 思考要求
- 在回答前进行充分的思考和分析
- 确保解决方案的完整性和正确性
- 提供清晰、有条理的回答
项目信息:{PROJECT_NAME}
Agent 版本:{AGENT_VERSION}
用户请求:
{user_prompt}"#.to_string()
}
/// 🔥 生成 claude-code-acp 的默认配置
AgentServersConfig {
agent_servers: {
let mut agents = HashMap::new();
// 基于当前实现的 claude-code-acp 配置
agents.insert("claude-code-acp".to_string(), AgentServerConfig {
command: "claude-code-acp".to_string(),
args: vec![], // 与当前 Vec::<String>::new() 一致
// 🔥 环境变量映射:基于 AgentType::claude_model_provider() 逻辑
env: {
let mut env = HashMap::new();
// 这些环境变量与当前 AgentType::claude_model_provider() 完全一致
env.insert("ANTHROPIC_API_KEY".to_string(), "{MODEL_PROVIDER_API_KEY}".to_string());
env.insert("ANTHROPIC_BASE_URL".to_string(), "{MODEL_PROVIDER_BASE_URL}".to_string());
env.insert("ANTHROPIC_MODEL".to_string(), "{MODEL_PROVIDER_DEFAULT_MODEL}".to_string());
env.insert("RUST_LOG".to_string(), "info".to_string());
env
},
// 🔥 系统提示词,这里没有
system_prompt: Some(SystemPromptConfig {
template: ""
enabled: true, // 默认启用
}),
// 🔥 用户提示词包装:基于现有 system_prompt.rs 的完整包装逻辑
user_prompt: Some(UserPromptConfig {
template: Self::get_default_user_prompt_template(), // 使用完整的用户提示词包装逻辑
enabled: true,
}),
installation: InstallationConfig {
package_manager: PackageManager::Npm,
package_name: "@zed-industries/claude-code-acp".to_string(),
version: "latest".to_string(),
source: None,
validate_command: Some(vec!["claude-code-acp".to_string(), "--version".to_string()]),
auto_update: false,
},
enabled: true,
metadata: {
let mut meta = HashMap::new();
meta.insert("version".to_string(), env!("CARGO_PKG_VERSION").to_string());
meta.insert("compatibility".to_string(), "claude-code-acp-v1".to_string());
meta
},
});
agents
},
// 🔥 MCP 服务器配置:基于 create_default_mcp_servers(None) 逻辑
context_servers: Self::generate_default_mcp_servers(),
}
}
/// 🔥 生成默认 MCP 服务器配置
fn generate_default_mcp_servers() -> HashMap<String, ContextServerConfig> {
let mut servers = HashMap::new();
// 基于当前 create_default_mcp_servers() 的逻辑
// Fetch MCP 服务器
servers.insert("fetch".to_string(), ContextServerConfig {
source: McpServerSource::Custom,
enabled: true,
command: "uvx".to_string(),
args: vec!["mcp-server-fetch".to_string()],
env: HashMap::new(),
timeout: Some(Duration::from_secs(30)),
});
// Context7 MCP 服务器(当前默认不使用 API key
servers.insert("context7".to_string(), ContextServerConfig {
source: McpServerSource::Custom,
enabled: true,
command: "npx".to_string(),
args: vec!["-y".to_string(), "@upstash/context7-mcp".to_string()],
env: {
let mut env = HashMap::new();
env.insert("NODE_ENV".to_string(), "production".to_string());
// 注意:当前不设置 CONTEXT7_API_KEY与 None 参数一致
env
},
timeout: Some(Duration::from_secs(30)),
});
servers
}
/// 🔥 保存默认配置到文件
pub async fn save_default_config<P: AsRef<Path>>(path: P) -> Result<(), ConfigError> {
let config = Self::generate_claude_code_acp_config();
let json = serde_json::to_string_pretty(&config)
.map_err(|e| ConfigError::SerializationError(e.to_string()))?;
tokio::fs::write(path, json)
.await
.map_err(|e| ConfigError::IoError(e.to_string()))?;
Ok(())
}
/// 🔥 检查并生成默认配置(如果不存在)
pub async fn ensure_default_config<P: AsRef<Path>>(config_path: P) -> Result<AgentServersConfig, ConfigError> {
let path = config_path.as_ref();
if path.exists() {
// 配置文件已存在,直接加载
AgentServersConfig::from_file(path).await
} else {
// 配置文件不存在,生成默认配置
log::info!("配置文件不存在,生成默认配置: {:?}", path);
Self::save_default_config(path).await?;
Self::generate_claude_code_acp_config().into()
}
}
}
```
#### 7.1.3 🔄 兼容层实现
**🔥 零中断兼容层:**
```rust
/// 🔥 Claude Code ACP Agent 兼容层
///
/// 保持现有接口完全不变,内部使用新的配置系统
pub struct ClaudeCodeAcpAgent {
/// 🔥 内部配置管理器
config_manager: Arc<AgentConfigManager>,
/// 🔥 ACP 连接池管理器
acp_connection_manager: Arc<AcpConnectionManager>,
/// 🔥 默认 Agent ID
default_agent_id: String,
}
impl ClaudeCodeAcpAgent {
/// 🔥 创建兼容的 Claude Code ACP Agent
pub async fn new() -> Result<Self, AcpError> {
// 🔥 自动生成或加载配置(用户无感知)
let config_path = PathBuf::from("/etc/rcoder/agents.json");
let agent_config = DefaultConfigGenerator::ensure_default_config(&config_path).await?;
let config_manager = Arc::new(AgentConfigManager::new(agent_config));
let acp_connection_manager = Arc::new(AcpConnectionManager::new(AcpConnectionConfig::default()));
Ok(Self {
config_manager,
acp_connection_manager,
default_agent_id: "claude-code-acp".to_string(),
})
}
}
// 🔥 保持现有 AcpAgentService 接口完全不变
#[async_trait::async_trait(?Send)]
impl AcpAgentService for ClaudeCodeAcpAgent {
async fn start_agent_service(
&self,
chat_prompt: ChatPrompt,
model_provider: Option<ModelProviderConfig>,
) -> Result<AcpConnectionInfo, AcpError> {
// 🔥 使用新的配置系统,但对外接口保持不变
self.start_claude_code_acp_agent_service(chat_prompt, model_provider).await
}
fn agent_type_name(&self) -> &'static str {
"claude-code-acp"
}
}
```
#### 7.1.4 🚀 迁移执行策略
**🔥 渐进式迁移步骤:**
1. **阶段 1兼容层实现**
```rust
// 保持现有调用方式完全不变
let connection_info = start_claude_code_acp_agent_service(chat_prompt, model_provider).await?;
```
2. **阶段 2自动配置生成**
```rust
// 首次运行时自动生成默认配置文件
DefaultConfigGenerator::ensure_default_config("/etc/rcoder/agents.json").await?;
```
3. **阶段 3内部重构**
```rust
// 现有接口保持不变,内部使用新配置系统
impl ClaudeCodeAcpAgent {
pub async fn start_claude_code_acp_agent_service(...) -> Result<AcpConnectionInfo> {
// 新的内部实现
}
}
```
4. **阶段 4用户可选配置**
```bash
# 用户可以修改生成的配置文件来定制行为
vim /etc/rcoder/agents.json
```
**🎯 迁移成功验证:**
- ✅ **HTTP 接口无变化**:所有现有 API 调用保持不变
- ✅ **功能 100% 兼容**:现有功能完全保持
- ✅ **性能无影响**:内部优化不影响外部性能
- ✅ **配置向后兼容**:默认配置与硬编码行为一致
- ✅ **用户无感知**:自动生成配置,无需手动干预
### 7.2 传统迁移步骤(保留作为参考)
1. **保留现有接口**:现有的 `AcpAgentService` trait 继续支持
2. **渐进式迁移**:新功能使用新的抽象层,现有代码逐步迁移
3. **适配器模式**:为现有实现提供适配器
### 7.3 🔄 新旧系统对比映射
**硬编码逻辑 → 配置文件映射表:**
| 当前代码位置 | 硬编码逻辑 | 配置文件映射 | 说明 |
|--------------|------------|--------------|------|
| `command_path = "claude-code-acp"` | 固定命令 | `command: "claude-code-acp"` | 直接映射 |
| `command_args = Vec::<String>::new()` | 空参数 | `args: []` | 直接映射 |
| `AgentType::claude_model_provider()` | 环境变量生成 | `env: { ... }` | 完全映射 |
| `create_default_mcp_servers(None)` | MCP 服务器 | `context_servers.*` | 功能映射 |
| `chat_prompt.project_path` | 工作目录 | 项目上下文 | 自动注入 |
4. **第四阶段**:优化和扩展新功能
## 8. 风险评估和缓解
### 8.1 技术风险
**风险:** 抽象层可能引入性能开销
**缓解:**
- 使用零成本抽象设计
- 性能测试和基准对比
- 关键路径优化
**风险:** 进程管理复杂性增加
**缓解:**
- 充分的测试覆盖
- 渐进式实现
- 错误处理和恢复机制
### 8.2 兼容性风险
**风险:** 新抽象层可能与现有代码不兼容
**缓解:**
- 保持向后兼容性
- 提供迁移指南和工具
- 充分的集成测试
## 9. 总结
本设计方案提供了一个可扩展、可维护的 Agent 抽象层,具有以下优势:
1. **高度可扩展**:支持新 Agent 类型的轻松添加
2. **配置灵活**:支持多种配置方式和动态更新
3. **进程隔离**:确保系统稳定性和安全性
4. **统一接口**:简化 Agent 的使用和管理
5. **可观测性**:完整的监控和日志支持
6. **向后兼容**:平滑的迁移路径
通过分阶段实施,可以在不破坏现有功能的前提下,逐步构建起强大的 Agent 管理系统,为 RCoder 项目的长期发展奠定坚实基础。
---
## 扩展:自动 MCP 服务器集成
为了实现所有 Agent 自动使用所有启用的 context_servers需要在 AgentFactory 中集成 MCP 管理器:
### Agent 集成示例
```rust
/// Agent 上下文
#[derive(Debug, Clone)]
pub struct AgentContext {
pub project_id: String,
pub project_path: PathBuf,
pub timestamp: DateTime<Utc>,
}
impl AgentContext {
pub fn new(project_id: &str, project_path: PathBuf) -> Self {
Self {
project_id: project_id.to_string(),
project_path,
timestamp: Utc::now(),
}
}
}
/// 扩展的 Agent 配置管理器
impl AgentConfigManager {
/// 获取所有启用的 MCP 服务器名称
pub async fn get_enabled_mcp_servers(&self) -> Result<Vec<String>, ConfigError> {
let mut enabled_servers = Vec::new();
for (server_name, server_config) in &self.config.context_servers {
if server_config.enabled {
enabled_servers.push(server_name.clone());
}
}
Ok(enabled_servers)
}
/// 获取 MCP 服务器配置
pub fn get_mcp_server_config(&self, server_name: &str) -> Result<McpServerConfig, ConfigError> {
let server_config = self.config.context_servers.get(server_name)
.ok_or_else(|| ConfigError::ServerError(format!("MCP server '{}' not found", server_name)))?;
Ok(McpServerConfig {
name: server_name.to_string(),
source: match server_config.source.as_str() {
"custom" => McpServerSource::Custom,
"local" => McpServerSource::Local,
_ => McpServerSource::Custom,
},
enabled: server_config.enabled,
command: server_config.command.clone(),
args: server_config.args.clone(),
env: server_config.env.clone(),
timeout: Some(Duration::from_secs(30)),
})
}
}
```
### 使用流程
1. **配置解析**:读取 `context_servers` 配置
2. **启用筛选**:获取所有 `enabled: true` 的服务器
3. **自动启动**:为每个 Agent 启动这些 MCP 服务器
4. **统一管理**:所有 Agent 共享相同的 MCP 服务器实例
这样,无论用户选择哪个 Agent都能自动获得所有可用的 MCP 工具支持。
---
## 简化的配置结构定义
```rust
/// Agent 服务器配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentServersConfig {
/// Agent 服务器配置
pub agent_servers: HashMap<String, AgentServerConfig>,
/// MCP 上下文服务器配置
pub context_servers: HashMap<String, ContextServerConfig>,
}
/// Agent 服务器配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentServerConfig {
/// 命令
pub command: Option<String>,
/// 命令参数
pub args: Option<Vec<String>>,
/// 环境变量
pub env: Option<HashMap<String, String>>,
/// 安装配置
pub installation: Option<InstallationConfig>,
}
/// 安装配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InstallationConfig {
/// 包管理器类型
pub package_manager: String,
/// 包名
pub package_name: Option<String>,
/// 版本约束
pub version: Option<String>,
/// 安装源
pub source: Option<String>,
/// 验证命令
pub validate_command: Option<Vec<String>>,
}
/// 上下文服务器配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContextServerConfig {
/// 服务器来源类型
pub source: String,
/// 是否启用
pub enabled: bool,
/// 启动命令
pub command: Option<String>,
/// 命令参数
pub args: Option<Vec<String>>,
/// 环境变量
pub env: Option<HashMap<String, String>>,
}
```