# Computer Agent Runner 详细实施计划 **文档版本**: v1.0 **创建日期**: 2025-12-10 **作者**: Claude (基于需求设计文档) **项目**: rcoder - AI 驱动开发平台 **基准文档**: `specs/computer-agent-runner/0001-spec-claude.md` --- ## 一、项目概述与目标 ### 1.1 功能简介 Computer Agent Runner 是 rcoder 项目的扩展功能模块,旨在为 AI Agent 提供完整的虚拟桌面环境,使其能够: - **操作浏览器**: 在虚拟桌面中打开 Chromium,自主搜索和访问网络资料 - **远程监控**: 用户可通过 VNC 远程查看 Agent 的操作过程 - **复杂任务处理**: Agent 在容器内完成复杂的多步骤任务(如网页抓取、数据处理等) - **资源共享**: 一个用户可以有多个项目,共享同一个桌面环境容器 ### 1.2 核心特点 | 特点 | 说明 | |------|------| | **用户级容器** | 一个 `user_id` 对应一个带桌面环境的容器 | | **多 Agent 实例** | 容器内可同时运行多个 `project_id` 对应的 AI Agent 实例 | | **统一架构** | 使用 `ContainerKey` 和 `UnifiedContainerInfo` 统一管理两种模式 | | **VNC 访问** | 提供 VNC 远程桌面访问,用户可实时查看 Agent 操作 | | **浏览器操作** | 集成 Chrome DevTools MCP,赋予 Agent 浏览器操作能力 | | **智能清理** | 只有当用户下所有项目都闲置时才销毁容器 | ### 1.3 与现有 RCoder 的对比 | 维度 | RCoder (现有) | Computer Agent Runner (新) | |------|--------------|------------------------------| | 容器标识 | `project_id` | `user_id` | | 容器命名 | `rcoder-agent-{project_id}` | `computer-agent-runner-{user_id}` | | Agent 实例数 | 1 个 | 多个(按 `project_id` 区分) | | 工作目录 | `/app/project_workspace/{project_id}` | `/app/computer-project-workspace/{user_id}` | | 桌面环境 | 无 | XFCE4 + noVNC | | 浏览器 | 无 | Chromium + CDP | | 闲置策略 | project_id 闲置即销毁 | user_id 下所有 project_id 都闲置才销毁 | --- ## 二、实施准备 ### 2.1 环境准备 #### 开发环境配置 - **Rust**: 1.75+ (2024 Edition) - **Docker**: 支持 BuildKit 和多架构构建 - **Docker Compose**: v2.0+ - **开发工具**: cargo, rustfmt, clippy #### Docker 镜像准备 - 确认 `docker/rcoder-agent-runner/Dockerfile` 包含: - XFCE4 桌面环境 - noVNC 服务(端口 6080) - Chromium 浏览器(CDP 端口 9222) - 所有必要的系统依赖 #### 依赖库版本确认 ```toml [dependencies] tokio = { version = "1.35", features = ["full"] } tonic = "0.14.2" agent-client-protocol = "0.6" dashmap = "5.5" chrono = { version = "0.4", features = ["serde"] } ``` ### 2.2 技术栈确认 | 技术 | 版本/组件 | 用途 | |------|----------|------| | Rust | 1.75+ | 核心开发语言 | | gRPC | Tonic 0.14.2 | 内部通信协议 | | ACP | 0.6 / 0.4 | Agent 客户端协议 | | Docker | 最新稳定版 | 容器化部署 | | VNC/noVNC | 标准协议 | 远程桌面访问 | | Chromium | Debian 12 stable | 浏览器环境 | | XFCE4 | Debian 12 stable | 桌面环境 | --- ## 三、详细实施步骤 ### 阶段 1:核心数据结构实现(1-2天,P0) #### 目标 实现统一架构的核心数据模型,使用 `ContainerKey` 枚举和 `UnifiedContainerInfo` 结构统一管理 RCoder 和 ComputerAgentRunner 两种模式的容器。 #### 步骤 1.1:创建 ContainerKey 枚举 **文件**: `crates/shared_types/src/model/computer_agent_model.rs` **任务清单**: - [ ] 定义 `ContainerKey` 枚举,包含 `Project(String)` 和 `User(String)` 两种变体 - [ ] 实现 `as_str()` 方法:获取容器标识符的字符串形式 - [ ] 实现 `service_type()` 方法:返回对应的 `ServiceType` - [ ] 实现 `from_project()` 和 `from_user()` 构造方法 - [ ] 实现 `Display` trait,格式为 `"project:{id}"` 或 `"user:{id}"` - [ ] 实现 `Hash`, `Eq`, `PartialEq` trait(用于 DashMap) - [ ] 实现 `Serialize`, `Deserialize` trait(用于持久化) **关键代码模式**: ```rust #[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] pub enum ContainerKey { /// RCoder 模式:一个 project_id 对应一个容器 Project(String), /// ComputerAgentRunner 模式:一个 user_id 对应一个容器 User(String), } impl ContainerKey { pub fn as_str(&self) -> &str { match self { ContainerKey::Project(id) => id, ContainerKey::User(id) => id, } } pub fn service_type(&self) -> ServiceType { match self { ContainerKey::Project(_) => ServiceType::RCoder, ContainerKey::User(_) => ServiceType::ComputerAgentRunner, } } } ``` #### 步骤 1.2:实现 UnifiedContainerInfo 结构 **任务清单**: - [ ] 定义 `UnifiedContainerInfo` 结构体,合并 RCoder 和 ComputerAgentRunner 两种模式 - [ ] 实现 `new_rcoder()` 构造方法(RCoder 模式) - [ ] 实现 `new_computer()` 构造方法(ComputerAgentRunner 模式) - [ ] 实现 `update_activity()` 方法:更新活动时间 - [ ] 实现 ComputerAgentRunner 专用方法: - [ ] `upsert_project()`: 添加或更新项目 - [ ] `get_project()`: 获取项目 - [ ] `remove_project()`: 移除项目 - [ ] `list_projects()`: 列出所有项目 ID - [ ] 实现 `is_fully_idle()` 方法:统一的闲置判断逻辑 - [ ] 实现 `container_ip()` 和 `container_id()` 便捷方法 **关键代码模式**: ```rust #[derive(Debug, Clone)] pub struct UnifiedContainerInfo { pub key: ContainerKey, pub container: ContainerBasicInfo, pub service_type: ServiceType, pub created_at: DateTime, pub last_activity: DateTime, // RCoder 模式字段 pub session_id: Option, pub status: Option, pub model_provider: Option, // ComputerAgentRunner 模式字段 pub projects: Option>>>, } impl UnifiedContainerInfo { pub fn is_fully_idle(&self, idle_timeout: Duration) -> bool { let now = Utc::now(); let idle_duration = now - self.last_activity; let is_timeout = idle_duration > chrono::Duration::from_std(idle_timeout).unwrap_or_default(); match self.service_type { ServiceType::RCoder => { let is_idle_status = matches!( self.status, Some(AgentStatus::Idle) | None ); is_idle_status && is_timeout } ServiceType::ComputerAgentRunner => { if let Some(projects) = &self.projects { if projects.is_empty() { return true; } projects.iter().all(|entry| { let project = entry.value(); let project_idle_duration = now - project.last_activity; let project_is_timeout = project_idle_duration > chrono::Duration::from_std(idle_timeout).unwrap_or_default(); let is_idle_status = matches!( project.status, Some(AgentStatus::Idle) | None ); is_idle_status && project_is_timeout }) } else { true } } } } } ``` #### 步骤 1.3:实现 ProjectInfo 结构 **任务清单**: - [ ] 定义 `ProjectInfo` 结构体(简化版项目元数据) - [ ] 实现 `new()` 构造方法 - [ ] 实现 `update_activity()` 方法 - [ ] 实现 `update_session()` 方法 - [ ] 实现 `update_status()` 方法 **结构定义**: ```rust #[derive(Debug, Clone)] pub struct ProjectInfo { pub project_id: String, pub session_id: Option, pub status: Option, pub model_provider: Option, pub created_at: DateTime, pub last_activity: DateTime, } ``` #### 步骤 1.4:实现 SessionInfo 结构 **任务清单**: - [ ] 定义 `SessionInfo` 结构体(统一会话信息) - [ ] 实现 `new()` 构造方法 - [ ] 关联 `ContainerKey` 和 `project_id` **结构定义**: ```rust #[derive(Debug, Clone)] pub struct SessionInfo { pub session_id: String, pub container_key: ContainerKey, pub project_id: String, pub created_at: DateTime, } ``` #### 步骤 1.5:更新模块导出 **文件**: `crates/shared_types/src/model/mod.rs` **任务清单**: - [ ] 添加 `mod computer_agent_model;` - [ ] 添加 `pub use computer_agent_model::*;` #### 验收标准 - [ ] 所有结构体编译通过,无警告 - [ ] `is_fully_idle()` 单元测试通过(RCoder 和 ComputerAgentRunner 两种模式) - [ ] `ContainerKey` 可以正确序列化和反序列化 - [ ] 所有方法都有完整的文档注释 - [ ] cargo clippy 无警告 --- ### 阶段 2:容器管理服务实现(1天,P0) #### 目标 实现 `ComputerContainerManager` 服务,负责根据 `user_id` 获取或创建容器。 #### 步骤 2.1:创建 ComputerContainerManager **文件**: `crates/rcoder/src/service/computer_container_manager.rs` **任务清单**: - [ ] 定义 `ComputerContainerManager` 结构体 - [ ] 实现 `get_or_create_container_for_user()` 公开方法 - 输入:`user_id: &str`, `resource_limits: Option` - 输出:`Result` - 逻辑:查询是否存在 → 存在则返回 → 不存在则创建 - [ ] 实现 `create_container_for_user()` 私有方法 - 准备用户级工作目录 - 解析宿主机路径 - 调用 `DockerManager::start_agent_container()` - [ ] 实现 `get_user_workspace()` 方法 - 返回 `/app/computer-project-workspace/{user_id}` - [ ] 实现 `create_user_workspace()` 方法 - 创建用户工作区目录 - 确保目录权限正确 **关键代码模式**: ```rust pub struct ComputerContainerManager; impl ComputerContainerManager { pub async fn get_or_create_container_for_user( user_id: &str, resource_limits: Option, ) -> Result { let docker_manager = docker_manager::global::get_global_docker_manager() .await .map_err(|e| AppError::internal_server_error(&format!("获取 DockerManager 失败: {}", e)))?; // 检查容器是否已存在 if let Ok(Some(info)) = docker_manager.get_agent_info(user_id).await { return Ok(info); } // 创建新容器 Self::create_container_for_user(user_id, &docker_manager, resource_limits).await } async fn create_container_for_user( user_id: &str, docker_manager: &Arc, resource_limits: Option, ) -> Result { // 准备工作目录 let user_workspace = Self::get_user_workspace(user_id).await?; Self::create_user_workspace(user_id).await?; // 解析宿主机路径 let host_path = resolve_container_path_to_host(&user_workspace).await?; // 调用 DockerManager 启动容器 let container_info = docker_manager .start_agent_container( user_id, &host_path.to_string_lossy(), ServiceType::ComputerAgentRunner, resource_limits, ) .await?; Ok(container_info) } } ``` #### 步骤 2.2:集成 DockerManager **任务清单**: - [ ] 调用 `docker_manager::global::get_global_docker_manager()` 获取全局实例 - [ ] 使用 `get_agent_info()` 查询现有容器 - [ ] 使用 `start_agent_container()` 创建新容器,传递: - `user_id` 作为容器标识 - `host_path` 宿主机路径 - `ServiceType::ComputerAgentRunner` 服务类型 - `resource_limits` 资源限额配置 #### 步骤 2.3:路径管理 **任务清单**: - [ ] 工作区路径:`/app/computer-project-workspace/{user_id}` - [ ] 使用 `tokio::fs::create_dir_all()` 创建目录 - [ ] 使用 `resolve_container_path_to_host()` 解析宿主机路径 - [ ] 确保目录权限为 777(容器内外都可访问) #### 步骤 2.4:更新服务模块导出 **文件**: `crates/rcoder/src/service/mod.rs` **任务清单**: - [ ] 添加 `pub mod computer_container_manager;` - [ ] 添加 `pub use computer_container_manager::*;` #### 验收标准 - [ ] 可以成功创建用户容器 - [ ] 容器命名规则正确:`computer-agent-runner-{user_id}` - [ ] 工作区目录创建成功:`/app/computer-project-workspace/{user_id}` - [ ] 容器 IP 地址可以正确获取 - [ ] 容器内外路径映射正确 - [ ] 集成测试通过(调用 API 创建容器) --- ### 阶段 3:HTTP 接口实现(1天,P0) #### 目标 实现 Computer Agent 的 HTTP 接口,包括聊天、停止 Agent 和进度流。 #### 步骤 3.1:实现 computer_chat_handler **文件**: `crates/rcoder/src/handler/computer_chat_handler.rs` **任务清单**: - [ ] 定义 `ComputerChatRequest` 结构体 - `user_id: String` (必填) - `project_id: Option` (可选,自动生成) - `prompt: String` - 其他字段与现有 `ChatRequest` 保持一致 - [ ] 实现 `handle_computer_chat()` 函数 - 生成或使用提供的 `project_id` - 调用 `ComputerContainerManager::get_or_create_container_for_user()` - 获取或创建 `UnifiedContainerInfo` (ContainerKey::User) - 创建或更新 `ProjectInfo` - 通过 gRPC 转发请求到 agent_runner - 更新会话映射 - 返回 `ChatResponse` - [ ] 实现 `forward_computer_request_to_container()` 函数 - 仅使用 gRPC 通信(不回退 HTTP) - 调用 `grpc_pool.get_or_create_channel()` - 调用 `Chat` RPC - [ ] 实现 `computer_session_notification()` SSE 处理器 - 通过 `sessions` 查找 `SessionInfo` - 建立 SSE 连接到容器 - 实时推送进度事件 **请求处理流程**: ``` POST /computer/chat ↓ 1. 验证 user_id 2. 生成 project_id(若未提供) 3. get_or_create_container_for_user(user_id) 4. 获取或创建 UnifiedContainerInfo (ContainerKey::User) 5. 创建/更新 ProjectInfo 6. gRPC Chat RPC → agent_runner (带 project_id) 7. 更新会话映射 (session_id → SessionInfo) 8. 返回 ChatResponse ``` #### 步骤 3.2:实现 computer_agent_stop_handler **文件**: `crates/rcoder/src/handler/computer_agent_stop_handler.rs` **任务清单**: - [ ] 定义 `ComputerAgentStopRequest` 结构体 - `user_id: String` (必填) - `project_id: String` (必填) - `session_id: Option` (可选) - [ ] 实现 `computer_agent_stop()` 函数 - 查找 `containers[ContainerKey::User(user_id)]` - 从 `container_info.projects` 移除 `project_id` - 通过 gRPC StopAgent RPC 停止 agent - 清理会话映射 - 返回成功响应 **注意**: 容器不会被销毁,继续运行其他 `project_id`。 #### 步骤 3.3:添加路由 **文件**: `crates/rcoder/src/router.rs` **任务清单**: - [ ] 添加 `/computer/chat` 路由:`post(handler::handle_computer_chat)` - [ ] 添加 `/computer/agent/stop` 路由:`post(handler::computer_agent_stop)` - [ ] 添加 `/computer/progress/{session_id}` 路由:`get(handler::computer_session_notification)` #### 步骤 3.4:重构 AppState 使用统一架构 **文件**: `crates/rcoder/src/router.rs` **任务清单**: - [ ] 重构 `AppState` 结构体,从 6 个 DashMap 精简到 3 个: ```rust pub struct AppState { pub config: AppConfig, // 核心映射(统一管理) pub containers: DashMap>, pub sessions: DashMap>, pub project_to_container: DashMap, pub pingora_service: Option>, pub grpc_pool: Arc, } ``` - [ ] 实现便捷方法: - `get_container(&self, key: &ContainerKey)`: 获取容器信息 - `get_container_by_project(&self, project_id: &str)`: 通过 project_id 获取容器 - `get_session(&self, session_id: &str)`: 获取会话信息 - `upsert_container(&self, key, info)`: 添加或更新容器 - `add_session(&self, session_id, info)`: 添加会话 - `remove_container(&self, key)`: 统一清理方法(清理所有相关映射) **关键代码模式**: ```rust impl AppState { pub fn remove_container(&self, key: &ContainerKey) -> Option> { // 移除容器 let container = self.containers.remove(key).map(|(_, v)| v)?; // 清理 project_to_container 索引 match key { ContainerKey::Project(project_id) => { self.project_to_container.remove(project_id); } ContainerKey::User(_) => { if let Some(projects) = &container.projects { for entry in projects.iter() { self.project_to_container.remove(entry.key()); } } } } // 清理相关会话 let sessions_to_remove: Vec = self.sessions .iter() .filter(|entry| &entry.value().container_key == key) .map(|entry| entry.key().clone()) .collect(); for session_id in sessions_to_remove { self.sessions.remove(&session_id); } Some(container) } } ``` #### 步骤 3.5:更新处理器模块导出 **文件**: `crates/rcoder/src/handler/mod.rs` **任务清单**: - [ ] 添加 `pub mod computer_chat_handler;` - [ ] 添加 `pub mod computer_agent_stop_handler;` - [ ] 添加 `pub use computer_chat_handler::*;` - [ ] 添加 `pub use computer_agent_stop_handler::*;` #### 验收标准 - [ ] `POST /computer/chat` 接口可用,返回正确的 `ChatResponse` - [ ] 自动创建 `user_id` 对应的容器(首次请求) - [ ] `project_id` 自动生成(若未提供) - [ ] SSE 进度流正常工作(`GET /computer/progress/{session_id}`) - [ ] 可以停止特定 `project_id` 的 agent(`POST /computer/agent/stop`) - [ ] AppState 重构后所有现有接口仍然正常工作 - [ ] 集成测试通过(发送聊天请求 → 接收进度 → 停止 agent) --- ### 阶段 4:agent_runner 集成 agent_abstraction(2-3天,P0) #### 目标 复用现有的 `agent_abstraction` 模块,避免重复代码,实现多 Agent 实例管理。 #### 步骤 4.1:扩展 gRPC Proto **文件**: `crates/shared_types/proto/agent.proto` **任务清单**: - [ ] 添加 `StopAgent` RPC 定义 ```protobuf service AgentService { // 现有方法 rpc Chat(GrpcChatRequest) returns (GrpcChatResponse); rpc SubscribeProgress(ProgressRequest) returns (stream ProgressEvent); rpc CancelSession(CancelRequest) returns (CancelResponse); rpc GetStatus(StatusRequest) returns (StatusResponse); // 新增:停止特定 project_id 的 agent rpc StopAgent(StopAgentRequest) returns (StopAgentResponse); } ``` - [ ] 添加 `StopAgentRequest` 消息定义 ```protobuf message StopAgentRequest { string project_id = 1; } ``` - [ ] 添加 `StopAgentResponse` 消息定义 ```protobuf message StopAgentResponse { bool success = 1; string message = 2; string project_id = 3; } ``` - [ ] 运行 `cargo build` 重新生成 Proto 代码 #### 步骤 4.2:修改 agent_runner 主程序 **文件**: `crates/agent_runner/src/main.rs` **任务清单**: - [ ] 引入 `agent_abstraction` 模块: ```rust use agent_abstraction::{ AcpSessionManager, AgentLifecycleManager, AcpAgentWorker, }; ``` - [ ] 创建 `AcpSessionManager` 实例(多会话管理) - [ ] 创建 `AgentLifecycleManager` 实例(生命周期管理) - [ ] 创建 `AcpAgentWorker` 实例(Worker 模式) - [ ] 在 `LocalSet` 中初始化所有组件 - [ ] 将实例传递给 gRPC 服务实现 **关键代码模式**: ```rust struct AgentRunnerState { session_manager: Arc>, lifecycle_manager: Arc, worker: Arc>, } impl AgentRunnerState { pub fn new( notifier: Arc, lifecycle_manager: Arc, ) -> Self { let session_manager = Arc::new(AcpSessionManager::new(notifier)); let worker = Arc::new(AcpAgentWorker::new(session_manager.clone())); Self { session_manager, lifecycle_manager, worker, } } } ``` #### 步骤 4.3:修改 gRPC 服务实现 **文件**: `crates/agent_runner/src/grpc/agent_service_impl.rs` **任务清单**: - [ ] 修改 `Chat` RPC 实现: - 调用 `worker.process_request()` 处理请求 - `project_id` 自动路由到对应的 agent 实例 - [ ] 实现 `StopAgent` RPC: - 从 `session_manager` 移除会话 - 调用 `lifecycle_manager.stop_agent(project_id)` - 清理 Agent 资源 - 返回 `StopAgentResponse` - [ ] 确保所有操作在 `LocalSet` 中执行(ACP 协议要求) **关键代码模式**: ```rust #[tonic::async_trait] impl AgentService for AgentServiceImpl { async fn chat( &self, request: Request, ) -> Result, Status> { let req = request.into_inner(); // 构建 WorkerRequest let worker_request = WorkerRequest { prompt_message: /* 转换 */, model_provider: req.model_provider, attachment_blocks: /* 转换 */, }; // 调用 worker 处理(自动路由到 project_id) let response = self.state.worker.process_request(worker_request) .await .map_err(|e| Status::internal(e.to_string()))?; Ok(Response::new(GrpcChatResponse { session_id: response.session_id, project_id: response.project_id, // ... })) } async fn stop_agent( &self, request: Request, ) -> Result, Status> { let req = request.into_inner(); // 从会话管理器移除 self.state.session_manager.remove_session(&req.project_id); // 停止 agent 进程 self.state.lifecycle_manager.stop_agent(&req.project_id) .await .map_err(|e| Status::internal(e.to_string()))?; Ok(Response::new(StopAgentResponse { success: true, message: format!("Agent {} stopped", req.project_id), project_id: req.project_id, })) } } ``` #### 步骤 4.4:测试多 Agent 实例 **任务清单**: - [ ] 在同一容器内启动多个 `project_id` 的 agent - [ ] 验证 Agent 之间互不干扰(独立的工作区和会话) - [ ] 验证可以独立停止单个 Agent(容器继续运行) - [ ] 验证内存和资源使用合理(无泄漏) #### 验收标准 - [ ] 同一容器内可以运行多个 `project_id` 的 agent - [ ] Agent 之间无上下文污染(独立的 `AcpSessionManager` 会话) - [ ] 可以按 `project_id` 停止单个 agent - [ ] 容器不会因停止单个 agent 而销毁 - [ ] `StopAgent` RPC 测试通过 - [ ] 集成测试通过(多 agent 并发) - [ ] 内存泄漏测试通过 --- ### 阶段 5:闲置检测和清理优化(1天,P1) #### 目标 实现统一的闲置检测和清理逻辑,自动处理 RCoder 和 ComputerAgentRunner 两种模式。 #### 步骤 5.1:修改清理任务 **文件**: `crates/rcoder/src/proxy_agent/cleanup_task.rs` **任务清单**: - [ ] 重构 `cleanup_idle_agents()` 方法,使用统一逻辑: ```rust async fn cleanup_idle_agents(&mut self) -> Result { let mut stats = CleanupStats::default(); let current_time = Utc::now(); let mut containers_to_clean = Vec::new(); for entry in self.state.containers.iter() { let container_key = entry.key(); let container_info = entry.value(); // 容器保护期(创建后 5 分钟内不清理) let protection_time = chrono::Duration::minutes(5); if current_time - container_info.created_at < protection_time { continue; } // 使用统一的闲置判断方法 if container_info.is_fully_idle(self.config.idle_timeout) { containers_to_clean.push(container_key.clone()); } } // 执行清理 for container_key in containers_to_clean { match self.cleanup_container(&container_key).await { Ok(_) => stats.cleaned_count += 1, Err(e) => { stats.failed_count += 1; warn!("清理失败: {} - {}", container_key, e); } } } Ok(stats) } ``` - [ ] 实现 `cleanup_container()` 统一清理方法: - 获取容器信息 - 销毁 Docker 容器 - 清理 gRPC 连接池 - 调用 `AppState::remove_container()` 清理所有映射 - [ ] 添加清理日志(记录闲置时长、项目数量等) #### 步骤 5.2:实现容器保护期 **任务清单**: - [ ] 容器创建后 5 分钟内不进行清理 - [ ] 检查 `container_info.created_at` 时间 - [ ] 记录保护期跳过的日志 #### 步骤 5.3:实现孤立容器检测 **任务清单**: - [ ] 列出所有 `rcoder-agent-*` 和 `computer-agent-runner-*` 容器 - [ ] 与 `AppState.containers` 对比,找出孤立容器 - [ ] 清理不在 AppState 中的容器 - [ ] 记录孤立容器清理日志 **关键代码模式**: ```rust async fn cleanup_orphaned_containers(&mut self) -> u64 { let mut cleaned_count = 0; let docker_manager = /* 获取 DockerManager */; // 收集所有应该存在的容器 ID let expected_containers: HashSet = self.state.containers .iter() .map(|entry| entry.value().container.container_id.clone()) .collect(); // 列出所有容器 let patterns = vec!["rcoder-agent-", "computer-agent-runner-"]; for pattern in patterns { if let Ok(containers) = docker_manager.list_containers_by_pattern(pattern).await { for container in containers { if !expected_containers.contains(&container.id) { // 清理孤立容器 if let Err(e) = docker_manager.stop_container_by_id(&container.id).await { warn!("清理孤立容器失败: {} - {}", container.id, e); } else { cleaned_count += 1; } } } } } cleaned_count } ``` #### 步骤 5.4:添加清理日志 **任务清单**: - [ ] 记录清理操作(容器 key、清理原因) - [ ] 记录闲置时长(`now - last_activity`) - [ ] ComputerAgentRunner 模式:记录项目数量和各项目状态 - [ ] 记录清理成功/失败统计 #### 验收标准 - [ ] RCoder 模式:`project_id` 闲置即清理 - [ ] ComputerAgentRunner 模式:所有 `project_id` 都闲置才清理 - [ ] 容器保护期生效(创建后 5 分钟内不清理) - [ ] 孤立容器被正确清理 - [ ] 清理日志完整且可读 - [ ] 清理统计准确(`CleanupStats`) - [ ] 单元测试覆盖 `is_fully_idle()` 各种场景 --- ### 阶段 6:VNC 代理实现(1-2天,P1) #### 目标 实现 VNC 桌面访问功能,提供 WebSocket 透明代理。 #### 步骤 6.1:创建 computer_desktop_handler **文件**: `crates/rcoder/src/handler/computer_desktop_handler.rs` **任务清单**: - [ ] 实现 `computer_desktop_vnc()` 函数: ```rust pub async fn computer_desktop_vnc( State(state): State>, Path((user_id, project_id)): Path<(String, String)>, ) -> Result { // 1. 查找 containers[ContainerKey::User(user_id)] // 2. 获取容器 IP // 3. 构建目标 URL: ws://{container_ip}:6080 // 4. 使用 Pingora/Nginx 代理 WebSocket 连接 } ``` - [ ] 查找 `user_id` 对应的容器 - [ ] 获取容器 IP 地址 - [ ] 构建 WebSocket 代理 URL #### 步骤 6.2:实现 WebSocket 代理(方案选择) **方案 A(推荐):Pingora WebSocket 中间件** **任务清单**: - [ ] 调研 Pingora WebSocket 支持情况 - [ ] 实现 HTTP Upgrade 处理 - [ ] 透明转发 WebSocket 帧到容器的 6080 端口 - [ ] 处理连接错误和超时 **方案 B(备用):Nginx 反向代理** **任务清单**: - [ ] 配置 Nginx location: ```nginx location ~ ^/computer/desktop/([^/]+)/([^/]+)$ { set $user_id $1; # 动态查询容器 IP(通过 Lua 脚本或 upstream 模块) proxy_pass http://$container_ip:6080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } ``` - [ ] 实现动态 upstream 配置 **方案 C(临时):直接返回容器 URL** **任务清单**: - [ ] 返回 `http://{container_ip}:6080/vnc.html` 给前端 - [ ] 仅用于开发测试 #### 步骤 6.3:添加 VNC 路由 **文件**: `crates/rcoder/src/router.rs` **任务清单**: - [ ] 添加 `/computer/desktop/:user_id/:project_id` 路由 - [ ] 使用 `get(handler::computer_desktop_vnc)` 处理器 #### 步骤 6.4:测试 VNC 访问 **任务清单**: - [ ] 创建测试 HTML 页面(`fixtures/vnc-test.html`): ```html VNC Desktop Test

Computer Agent VNC Desktop




``` - [ ] 验证 WebSocket 连接建立 - [ ] 验证桌面画面传输流畅 - [ ] 测试鼠标和键盘输入 #### 验收标准 - [ ] 可以通过浏览器访问 VNC 桌面 - [ ] WebSocket 连接稳定(不频繁断开) - [ ] 桌面画面流畅(延迟 < 500ms) - [ ] `user_id` 隔离生效(不同用户互不干扰) - [ ] 测试 HTML 页面可用 - [ ] 性能测试通过(多用户并发访问) --- ### 阶段 7:MCP 配置和优化(0.5天,P2) #### 目标 创建 ComputerAgentRunner 专用的 MCP 配置文件。 #### 步骤 7.1:创建配置文件 **文件**: `crates/agent_config/configs/computer_agent_default.json` **任务清单**: - [ ] 复制 `default_agents.json` 内容作为基础 - [ ] 添加 Chrome DevTools MCP 配置: ```json { "agent_servers": { "claude-code-acp": { "agent_id": "claude-code-acp", "agent_type": "claude", "command": "claude-code-acp", "args": [], "env": { "ANTHROPIC_API_KEY": "{MODEL_PROVIDER_API_KEY}", "ANTHROPIC_MODEL": "{MODEL_PROVIDER_DEFAULT_MODEL}", "ANTHROPIC_BASE_URL": "{MODEL_PROVIDER_BASE_URL}", "RUST_LOG": "info" }, "system_prompt": { "source": "embedded", "template": "", "enabled": true }, "user_prompt": { "template": "{user_prompt}", "enabled": false }, "installation": { "package_manager": "npm", "package_name": "@anthropics/claude-code-acp", "version": "latest" }, "enabled": true, "metadata": { "description": "Claude Code ACP Agent - Computer Agent Runner 配置", "version": "1.0.0" } } }, "context_servers": { "chrome-devtools": { "source": "custom", "enabled": true, "command": "npx", "args": ["-y", "chrome-devtools-mcp@latest"], "env": { "CHROME_REMOTE_DEBUGGING_PORT": "9222" }, "metadata": { "description": "Chrome DevTools MCP - 浏览器操作能力", "documentation": "https://github.com/ChromeDevTools/chrome-devtools-mcp" } }, "context7": { "source": "custom", "enabled": true, "command": "bunx", "args": ["-y", "@upstash/context7-mcp"], "env": {} }, "fetch": { "source": "custom", "enabled": true, "command": "uvx", "args": ["mcp-server-fetch"], "env": {} } } } ``` - [ ] 设置 `CHROME_REMOTE_DEBUGGING_PORT=9222` #### 步骤 7.2:配置加载逻辑 **任务清单**: - [ ] 修改配置加载代码,根据 `ServiceType` 选择配置文件: ```rust fn get_agent_config_path(service_type: ServiceType) -> PathBuf { match service_type { ServiceType::RCoder => PathBuf::from("configs/default_agents.json"), ServiceType::ComputerAgentRunner => PathBuf::from("configs/computer_agent_default.json"), } } ``` - [ ] 确保配置文件正确加载 #### 步骤 7.3:验证 MCP 工具 **任务清单**: - [ ] 启动 agent 后验证 MCP 工具加载日志 - [ ] 测试 Chrome DevTools MCP 功能: - 导航到网页 - 截图 - 元素操作 - [ ] 测试浏览器操作能力(agent 可以控制 Chromium) #### 验收标准 - [ ] 配置文件格式正确(JSON 验证通过) - [ ] Chrome DevTools MCP 加载成功(日志显示连接到 CDP) - [ ] Agent 可以操作 Chromium 浏览器 - [ ] 支持网页导航和元素操作 - [ ] 支持截图功能 - [ ] 配置文件文档完整(metadata 字段) --- ## 四、集成测试 ### 4.1 功能测试用例 #### 测试用例 1:基本聊天流程 **目标**: 验证 Computer Agent 的基本聊天功能 **步骤**: ```bash # 1. 发送聊天请求 curl -X POST http://localhost:8087/computer/chat \ -H "Content-Type: application/json" \ -d '{ "user_id": "test_user_1", "prompt": "Hello, help me create a simple React app" }' # 预期输出: # { # "success": true, # "data": { # "session_id": "sess_xxx", # "project_id": "proj_yyy", # "message": "Task started" # } # } # 2. 验证容器创建 docker ps | grep computer-agent-runner-test_user_1 # 预期输出:显示一个运行中的容器 # 3. 订阅进度流 curl http://localhost:8087/computer/progress/{session_id} # 预期输出:SSE 事件流,显示 agent 执行进度 ``` **验收标准**: - [ ] API 返回正确的响应(`session_id` 和 `project_id`) - [ ] 容器自动创建(命名正确) - [ ] SSE 进度流实时推送事件 #### 测试用例 2:多项目并发 **目标**: 验证同一用户下多个项目可以并发运行 **步骤**: ```bash # 在同一用户下创建多个项目 curl -X POST http://localhost:8087/computer/chat \ -H "Content-Type: application/json" \ -d '{"user_id": "test_user_1", "project_id": "proj_1", "prompt": "Task 1"}' curl -X POST http://localhost:8087/computer/chat \ -H "Content-Type: application/json" \ -d '{"user_id": "test_user_1", "project_id": "proj_2", "prompt": "Task 2"}' # 验证容器数量(应该只有 1 个) docker ps | grep computer-agent-runner-test_user_1 | wc -l # 预期输出:1 # 验证两个项目都在运行 # (通过查看日志或 agent 状态) ``` **验收标准**: - [ ] 只创建一个容器 - [ ] 两个项目的 agent 都在运行 - [ ] 项目之间互不干扰(独立的工作区) #### 测试用例 3:Agent 停止 **目标**: 验证可以停止单个项目的 agent,而不销毁容器 **步骤**: ```bash # 停止特定项目的 agent curl -X POST http://localhost:8087/computer/agent/stop \ -H "Content-Type: application/json" \ -d '{"user_id": "test_user_1", "project_id": "proj_1"}' # 预期输出: # { # "success": true, # "message": "Agent stopped" # } # 验证容器仍然运行(proj_2 还在) docker ps | grep computer-agent-runner-test_user_1 # 预期输出:容器仍在运行 ``` **验收标准**: - [ ] proj_1 的 agent 停止 - [ ] 容器仍然运行 - [ ] proj_2 的 agent 不受影响 #### 测试用例 4:VNC 访问 **目标**: 验证可以通过浏览器访问 VNC 桌面 **步骤**: ```bash # 访问 VNC 桌面 open http://localhost:8087/computer/desktop/test_user_1/proj_1 # 或使用测试 HTML 页面 open fixtures/vnc-test.html ``` **验收标准**: - [ ] 浏览器显示 VNC 桌面 - [ ] 可以看到 XFCE4 桌面环境 - [ ] 鼠标和键盘输入正常 - [ ] 画面流畅(无明显延迟) #### 测试用例 5:闲置清理 **目标**: 验证闲置清理逻辑正确 **步骤**: ```bash # 1. 启动两个项目 curl -X POST http://localhost:8087/computer/chat \ -d '{"user_id": "test_user_1", "project_id": "proj_1", "prompt": "Task 1"}' curl -X POST http://localhost:8087/computer/chat \ -d '{"user_id": "test_user_1", "project_id": "proj_2", "prompt": "Task 2"}' # 2. 停止所有 agent curl -X POST http://localhost:8087/computer/agent/stop \ -d '{"user_id": "test_user_1", "project_id": "proj_1"}' curl -X POST http://localhost:8087/computer/agent/stop \ -d '{"user_id": "test_user_1", "project_id": "proj_2"}' # 3. 等待闲置超时(默认 30 分钟,测试时可改为 1 分钟) sleep 70 # 4. 验证容器被销毁 docker ps | grep computer-agent-runner-test_user_1 # 预期输出:无容器运行 ``` **验收标准**: - [ ] 只有当所有项目都闲置时才清理容器 - [ ] 闲置超时时间准确 - [ ] 容器保护期生效(创建后 5 分钟内不清理) ### 4.2 性能测试 #### 测试场景 1:容器创建时间 **目标**: 验证容器创建时间 < 30 秒 **步骤**: ```bash time (curl -X POST http://localhost:8087/computer/chat \ -H "Content-Type: application/json" \ -d '{"user_id": "test_user_perf", "prompt": "Hello"}') ``` **验收标准**: - [ ] 容器创建时间 < 30 秒 - [ ] 记录实际耗时 #### 测试场景 2:多 Agent 并发 **目标**: 验证单个容器可以稳定运行 3+ 个 agent **步骤**: ```bash # 并发启动 3 个 agent for i in {1..3}; do curl -X POST http://localhost:8087/computer/chat \ -d "{\"user_id\": \"test_user_1\", \"project_id\": \"proj_$i\", \"prompt\": \"Task $i\"}" & done wait # 监控资源使用 docker stats computer-agent-runner-test_user_1 ``` **验收标准**: - [ ] 3 个 agent 都成功启动 - [ ] 响应时间合理(< 2 秒) - [ ] 内存占用 < 4GB - [ ] CPU 占用 < 2 核 #### 测试场景 3:VNC 延迟 **目标**: 验证 VNC 桌面访问延迟 < 500ms **步骤**: - 使用浏览器开发工具测量 WebSocket 帧传输延迟 - 记录平均延迟、最大延迟 **验收标准**: - [ ] 平均延迟 < 500ms - [ ] 画面流畅,无明显卡顿 #### 测试场景 4:资源占用 **目标**: 验证容器资源占用符合限额 **步骤**: ```bash # 查看容器资源使用 docker stats computer-agent-runner-test_user_1 --no-stream ``` **验收标准**: - [ ] 内存占用 < 4GB(可配置) - [ ] CPU 占用 < 2 核(可配置) - [ ] 磁盘 IO 合理 ### 4.3 安全测试 #### 测试场景 1:用户隔离 **目标**: 验证不同用户之间的隔离 **步骤**: ```bash # 用户 A 创建项目 curl -X POST http://localhost:8087/computer/chat \ -d '{"user_id": "user_a", "project_id": "proj_1", "prompt": "Task A"}' # 用户 B 尝试访问用户 A 的容器 curl -X POST http://localhost:8087/computer/agent/stop \ -d '{"user_id": "user_b", "project_id": "proj_1"}' # 预期:失败(找不到容器) # 用户 B 尝试访问用户 A 的 VNC curl http://localhost:8087/computer/desktop/user_a/proj_1 # 预期:失败(无权限或找不到) ``` **验收标准**: - [ ] user_a 无法访问 user_b 的容器 - [ ] user_a 无法访问 user_b 的 VNC - [ ] 错误消息清晰 #### 测试场景 2:项目隔离 **目标**: 验证项目之间无上下文污染 **步骤**: ```bash # 在两个项目中创建同名文件 # proj_1 创建 test.txt curl -X POST http://localhost:8087/computer/chat \ -d '{"user_id": "test_user_1", "project_id": "proj_1", "prompt": "echo proj1 > test.txt"}' # proj_2 创建 test.txt curl -X POST http://localhost:8087/computer/chat \ -d '{"user_id": "test_user_1", "project_id": "proj_2", "prompt": "echo proj2 > test.txt"}' # 验证文件内容不同 # (通过 agent 读取文件内容) ``` **验收标准**: - [ ] 两个项目的 test.txt 文件内容不同 - [ ] 工作区目录独立(`/app/computer-project-workspace/{user_id}/{project_id}`) #### 测试场景 3:资源限额 **目标**: 验证容器资源限额生效 **步骤**: ```bash # 创建容器时设置资源限额 curl -X POST http://localhost:8087/computer/chat \ -H "Content-Type: application/json" \ -d '{ "user_id": "test_user_1", "prompt": "Task", "agent_config": { "resource_limits": { "memory_limit": 2147483648, "cpu_limit": 1.0 } } }' # 验证限额生效 docker inspect computer-agent-runner-test_user_1 | jq '.[0].HostConfig.Memory' docker inspect computer-agent-runner-test_user_1 | jq '.[0].HostConfig.NanoCpus' ``` **验收标准**: - [ ] 内存限额生效(Docker inspect 显示正确值) - [ ] CPU 限额生效(Docker inspect 显示正确值) - [ ] agent 在限额内正常运行 --- ## 五、部署和上线 ### 5.1 Docker 镜像更新 **检查清单**: - [ ] `docker/rcoder-agent-runner/Dockerfile` 包含所有依赖 - [ ] XFCE4 桌面环境配置正确 - [ ] noVNC 服务启动脚本正确(端口 6080) - [ ] Chromium 浏览器配置正确(CDP 端口 9222) - [ ] 所有系统依赖已安装(Node.js, npm, bun, uv 等) - [ ] 镜像大小合理(< 5GB) ### 5.2 Docker Compose 配置 **文件**: `docker/docker-compose.yml` **检查清单**: - [ ] 挂载了 `computer-project-workspace` 目录: ```yaml volumes: - ./project_workspace:/app/project_workspace - ./computer-project-workspace:/app/computer-project-workspace - ./logs:/app/logs ``` - [ ] 端口映射正确(8087:8087) - [ ] 环境变量配置完整(ANTHROPIC_API_KEY, RUST_LOG 等) ### 5.3 环境变量配置 **必需环境变量**: ```bash # API 密钥 ANTHROPIC_API_KEY=sk-ant-xxx # 日志级别 RUST_LOG=info # Docker 配置 DOCKER_SOCKET_PATH=/var/run/docker.sock ``` **可选环境变量**: ```bash # 资源限额(默认值) DEFAULT_MEMORY_LIMIT=4294967296 # 4GB DEFAULT_CPU_LIMIT=2.0 # 2 核 # 闲置超时(默认值) IDLE_TIMEOUT=1800 # 30 分钟 ``` ### 5.4 监控和告警 **监控指标**: - [ ] 容器创建/销毁日志 - [ ] Agent 状态变更日志 - [ ] 资源使用情况监控(CPU、内存、磁盘) - [ ] gRPC 连接池状态 - [ ] SSE 连接数量 **告警配置**: - [ ] 容器创建失败告警 - [ ] 资源超限告警 - [ ] gRPC 连接失败告警 - [ ] 闲置清理失败告警 --- ## 六、验收标准总结 ### 功能验收 - [ ] 可以通过 `POST /computer/chat` 发送请求,自动创建 user_id 对应的容器 - [ ] 同一 user_id 的多个 project_id 可以在同一容器内运行 - [ ] 可以通过 `GET /computer/desktop/{user_id}/{project_id}` 访问 VNC 桌面 - [ ] Agent 可以通过 Chrome DevTools MCP 操作 Chromium 浏览器 - [ ] 可以通过 `POST /computer/agent/stop` 停止单个 project_id 的 agent(不销毁容器) - [ ] 只有当 user_id 下所有 project_id 都闲置时才销毁容器 ### 性能验收 - [ ] 单个容器可以稳定运行 3+ 个 project_id 的 agent - [ ] VNC 桌面访问延迟 < 500ms - [ ] 容器创建时间 < 30s ### 安全验收 - [ ] user_id 只能访问自己的容器和 VNC - [ ] project_id 之间没有上下文污染 - [ ] 容器资源限额生效 --- ## 七、文件清单 ### 新建文件(6个) 1. **`crates/shared_types/src/model/computer_agent_model.rs`** - ContainerKey 枚举 - UnifiedContainerInfo 结构 - ProjectInfo 结构 - SessionInfo 结构 2. **`crates/rcoder/src/service/computer_container_manager.rs`** - ComputerContainerManager 服务 - 容器创建和管理逻辑 3. **`crates/rcoder/src/handler/computer_chat_handler.rs`** - ComputerChatRequest 结构 - handle_computer_chat() 函数 - forward_computer_request_to_container() 函数 - computer_session_notification() SSE 处理器 4. **`crates/rcoder/src/handler/computer_agent_stop_handler.rs`** - ComputerAgentStopRequest 结构 - computer_agent_stop() 函数 5. **`crates/rcoder/src/handler/computer_desktop_handler.rs`** - computer_desktop_vnc() 函数 - VNC 代理逻辑 6. **`crates/agent_config/configs/computer_agent_default.json`** - ComputerAgentRunner 专用的 MCP 配置 - Chrome DevTools MCP 配置 ### 修改文件(8个) 1. **`crates/shared_types/src/model/mod.rs`** - 添加 computer_agent_model 模块导出 2. **`crates/rcoder/src/service/mod.rs`** - 添加 computer_container_manager 模块导出 3. **`crates/rcoder/src/handler/mod.rs`** - 添加 computer_chat_handler 模块导出 - 添加 computer_agent_stop_handler 模块导出 - 添加 computer_desktop_handler 模块导出 4. **`crates/rcoder/src/router.rs`** - 重构 AppState(从 6 个 DashMap 精简到 3 个) - 添加 Computer 相关路由 - 实现便捷方法 5. **`crates/rcoder/src/proxy_agent/cleanup_task.rs`** - 统一清理逻辑 - 容器保护期 - 孤立容器检测 6. **`crates/agent_runner/src/main.rs`** - 集成 agent_abstraction 模块 - 创建 AcpSessionManager 实例 - 创建 AgentLifecycleManager 实例 - 创建 AcpAgentWorker 实例 7. **`crates/agent_runner/src/grpc/agent_service_impl.rs`** - 修改 Chat RPC 实现 - 实现 StopAgent RPC 8. **`crates/shared_types/proto/agent.proto`** - 添加 StopAgent RPC 定义 - 添加 StopAgentRequest 消息 - 添加 StopAgentResponse 消息 --- ## 八、时间估算 | 阶段 | 工作量 | 依赖 | 关键风险 | |------|--------|------|----------| | 阶段 1:核心数据结构 | 1-2 天 | 无 | 低 | | 阶段 2:容器管理服务 | 1 天 | 阶段 1 | 低 | | 阶段 3:HTTP 接口 | 1 天 | 阶段 1, 2 | 低 | | 阶段 4:agent_runner 集成 | 2-3 天 | 阶段 1 | 中(LocalSet 并发) | | 阶段 5:闲置检测优化 | 1 天 | 阶段 1, 3 | 低 | | 阶段 6:VNC 代理 | 1-2 天 | 阶段 3 | 中(WebSocket 代理) | | 阶段 7:MCP 配置 | 0.5 天 | 阶段 4 | 低 | | 集成测试 | 1 天 | 所有阶段 | 中 | | **总计** | **8.5-11.5 天** | | | --- ## 九、风险和缓解措施 | 风险 | 影响 | 概率 | 缓解措施 | |------|------|------|----------| | agent_runner LocalSet 并发管理复杂 | 高 | 高 | 复用 agent_abstraction 模块,避免重复造轮 | | Pingora 不支持 WebSocket | 中 | 中 | 备用方案:使用 Nginx 作为 VNC 专用代理 | | 容器资源耗尽 | 高 | 中 | 实施严格的资源限额和监控 | | VNC 安全风险 | 高 | 低 | user_id 绑定和访问控制(后续:一次性 token) | | 多 agent 内存泄漏 | 中 | 中 | AgentLifecycleManager 管理,定期清理 | --- ## 十、后续优化(MVP 后) ### 第一阶段优化 1. **VNC 会话录制和回放** - 录制用户与桌面的交互 - 回放功能用于调试和复现问题 2. **剪贴板 API 支持** - 实现剪贴板读取和写入接口 - 支持跨容器的剪贴板共享 3. **增强 Agent 监控和日志** - 详细的性能指标(CPU、内存、网络) - Agent 操作日志(浏览器操作、文件操作等) ### 第二阶段扩展 4. **多用户协作(共享 VNC 桌面)** - 多个用户可以同时查看和操作同一个桌面 - 实现光标同步和权限控制 5. **集成更多 MCP 工具** - 文件操作 MCP - 数据库操作 MCP - API 测试 MCP 6. **Agent 性能分析和优化** - 性能分析工具 - 瓶颈识别 - 优化建议 ### 长期愿景 7. **Agent 市场** - 用户可以共享和复用 Agent 配置 - 预置模板库 - 社区贡献 8. **自定义桌面环境和应用** - 支持用户自定义桌面环境 - 预装常用应用 - 应用商店 9. **Agent 集群调度和负载均衡** - 多节点部署 - 自动负载均衡 - 高可用性保障 --- ## 附录 ### A. 术语表 | 术语 | 说明 | |------|------| | user_id | 用户唯一标识符 | | project_id | 项目唯一标识符 | | ContainerKey | 统一容器标识符枚举(Project/User) | | UnifiedContainerInfo | 统一容器信息结构 | | ProjectInfo | 项目信息结构 | | SessionInfo | 会话信息结构 | | ServiceType | 服务类型枚举(RCoder, ComputerAgentRunner) | | ACP | Agent Client Protocol,AI Agent 通信协议 | | MCP | Model Context Protocol,模型上下文协议 | | CDP | Chrome DevTools Protocol,浏览器调试协议 | | noVNC | 基于 HTML5 的 VNC 客户端 | | LocalSet | Tokio 的本地任务集,支持 !Send 任务 | | DashMap | 高性能的并发 HashMap | ### B. 参考资料 1. **rcoder 项目文档**: - `CLAUDE.md` - 项目概述 - `specs/computer-agent-runner/0001-spec-claude.md` - 需求与设计文档 2. **外部依赖文档**: - [ACP Protocol](https://github.com/anthropics/agent-client-protocol) - [Chrome DevTools MCP](https://github.com/ChromeDevTools/chrome-devtools-mcp) - [noVNC Documentation](https://github.com/novnc/noVNC) - [Tonic gRPC](https://github.com/hyperium/tonic) - [DashMap](https://github.com/xacrimon/dashmap) 3. **技术博客**: - Rust Tokio LocalSet 使用指南 - WebSocket 代理实现最佳实践 - Docker 容器资源限制和管理 --- **文档变更历史** | 版本 | 日期 | 作者 | 变更说明 | |------|------|------|----------| | v1.0 | 2025-12-10 | Claude | 初始版本,基于 0001-spec-claude.md 生成 | --- **审批记录** | 角色 | 姓名 | 审批意见 | 日期 | |------|------|----------|------| | 产品负责人 | | | | | 技术负责人 | | | | | 安全负责人 | | | | --- **下一步行动** 1. **立即开始**: 阶段 1 - 核心数据结构实现 2. **并行开发**: 阶段 2 和阶段 3(容器管理 + HTTP 接口) 3. **关键里程碑**: 阶段 4 - agent_runner 集成(最复杂) 4. **集成测试**: 完成所有阶段后进行完整测试 5. **部署上线**: 通过验收后部署到生产环境 **联系方式** - 技术支持: [技术团队邮箱] - 项目管理: [项目经理邮箱] - 文档反馈: [文档维护者邮箱]