Explorar el Código

更新了gateway/docs/core文档

kevin.yang hace 1 día
padre
commit
7d7a073870
Se han modificado 3 ficheros con 214 adiciones y 210 borrados
  1. 57 80
      gateway/docs/core/channels.md
  2. 55 91
      gateway/docs/core/executor.md
  3. 102 39
      gateway/docs/core/lifecycle.md

+ 57 - 80
gateway/docs/core/channels.md

@@ -50,15 +50,24 @@
 
 
 ```
 ```
 gateway/core/channels/
 gateway/core/channels/
-├── feishu/                    # 飞书集成
-│   ├── connector.py           # 飞书连接器
-│   ├── webhook.py             # Webhook 处理
-│   └── api.py                 # 飞书 API 调用
+├── manager.py                 # ChannelRegistry(通用注册/启停/状态)
+├── router.py                  # ChannelTraceRouter(与 IM 无关的 trace 解析)
+├── loader.py                  # 渠道加载入口
+├── types.py                   # RouteResult 等
+├── protocols.py               # TraceBackend 等协议
-├── router.py                  # 消息路由
-└── channel_manager.py         # 渠道管理
+└── feishu/                    # 飞书渠道
+    ├── manager.py             # FeishuChannelManager、FeishuChannelConfig
+    ├── connector.py           # FeishuConnector(HTTP 入站解析等)
+    ├── router.py              # FeishuMessageRouter
+    ├── bridge.py              # FeishuHttpRunApiExecutor(调 Gateway Executor / Agent)
+    ├── api.py                 # FastAPI 路由装配(Webhook 等)
+    ├── identity.py            # 用户身份解析
+    └── types.py               # 飞书侧类型
 ```
 ```
 
 
+飞书侧还包含 `openclaw-lark` 等子项目(Node/TS IM 逻辑),Compose 中可由独立 `feishu` 服务承载 HTTP;Gateway 通过 `FEISHU_HTTP_BASE_URL` 等与其通信。
+
 ---
 ---
 
 
 ## 关键功能
 ## 关键功能
@@ -93,88 +102,57 @@ class FeishuConnector:
         pass
         pass
 ```
 ```
 
 
-### MessageRouter
+### ChannelTraceRouter
 
 
 **实现位置:** `gateway/core/channels/router.py`
 **实现位置:** `gateway/core/channels/router.py`
 
 
-**职责:**
-- 根据飞书用户 ID 查找对应的 Trace
-- 如果 Trace 不存在,自动创建
-- 将消息转换为任务提交给 Executor
-
-**核心接口:**
+**职责:** 与具体 IM 无关;按 `workspace_prefix` 生成 `workspace_id`,并委托 `TraceBackend` 解析已绑定的 Agent `trace_id`(**不**在 Gateway 内预分配 UUID)。
 
 
 ```python
 ```python
-class MessageRouter:
-    def route_message(self, channel: str, user_id: str, message: dict) -> str:
-        """路由消息,返回 task_id"""
-        pass
+class ChannelTraceRouter:
+    async def get_trace_id(
+        self, channel: str, user_id: str, *, create_if_missing: bool = True
+    ) -> str: ...
 
 
-    def get_trace_id(self, channel: str, user_id: str) -> str:
-        """获取或创建 Trace ID"""
-        pass
-
-    def create_trace_for_user(self, channel: str, user_id: str) -> str:
-        """为用户创建 Trace"""
-        pass
+    async def create_trace_for_user(self, channel: str, user_id: str) -> str: ...
 ```
 ```
 
 
-### ChannelManager
+### FeishuMessageRouter
 
 
-**实现位置:** `gateway/core/channels/channel_manager.py`
+**实现位置:** `gateway/core/channels/feishu/router.py`
 
 
-**职责:**
-- 管理所有渠道的配置
-- 启动和停止渠道
-- 监控渠道状态
+**职责:** 飞书消息 → `workspace_id` / 路由决策;与 `FeishuChannelManager`、`bridge` 协同。
 
 
-**核心接口:**
+### FeishuChannelManager 与 Bridge
 
 
-```python
-class ChannelManager:
-    def register_channel(self, channel_id: str, config: dict):
-        """注册渠道"""
-        pass
+**实现位置:** `gateway/core/channels/feishu/manager.py`、`feishu/bridge.py`
 
 
-    def start_channel(self, channel_id: str):
-        """启动渠道"""
-        pass
+- **FeishuChannelManager**:组装配置(`FeishuChannelConfig`)、依赖(Trace/Workspace/Executor)、Webhook 处理与跟单策略。
+- **FeishuHttpRunApiExecutor**:在渠道流程中调用 Gateway **Executor**(或等价 HTTP)提交 `submit_task`,并在 Agent 返回后 `TraceManager.bind_agent_trace`。
+- 配置项含 `workspace_prefix`、`auto_create_trace`、`dispatch_card_actions`、`stop_container_on_trace_terminal` 等(见 `FeishuChannelConfig` 字段注释)。
 
 
-    def stop_channel(self, channel_id: str):
-        """停止渠道"""
-        pass
+### ChannelRegistry
 
 
-    def get_channel_status(self, channel_id: str) -> dict:
-        """获取渠道状态"""
-        pass
-```
+**实现位置:** `gateway/core/channels/manager.py`
+
+**职责:** 通用渠道注册表、启停与状态查询(`register_channel`、`start_channel`、`stop_channel`、`get_channel_status`)。
 
 
 ---
 ---
 
 
 ## 典型流程
 ## 典型流程
 
 
-### 用户首次通过飞书发送消息
-
-1. 飞书用户发送消息
-2. 飞书 Webhook 触发,调用 `FeishuConnector.handle_webhook()`
-3. FeishuConnector 提取用户 ID 和消息内容
-4. 调用 `MessageRouter.route_message()`
-5. MessageRouter 查询是否有对应的 Trace
-6. 无 Trace → 调用 `Lifecycle.TraceManager.create_trace()`
-7. 创建 Trace(workspace_id=feishu_user_id, agent_type="personal_assistant")
-8. 调用 `Executor.TaskManager.submit_task()`
-9. Executor 调度 Agent 执行
-10. Agent 执行完成,返回结果
-11. Executor 调用 `FeishuConnector.send_message()` 发送回复
-12. 用户在飞书收到回复
+### 用户首次通过飞书发送消息(与当前实现一致)
+
+1. 飞书 Webhook → `FeishuConnector` / `api` 解析事件与用户标识。
+2. 解析 `workspace_id`(如 `feishu:<open_id>`);`TraceManager.prepare_workspace_session(workspace_id)` → **Workspace 目录 + 沙箱**(`ensure_session`)。
+3. 通过 **Bridge** 调用 Executor:`TaskManager.submit_task`;内部 HTTP 调 Agent `POST .../run` 创建/续跑 Trace。
+4. Agent 返回 `trace_id` 后,`TraceManager.bind_agent_trace(workspace_id, trace_id, ...)`。
+5. 渠道侧跟单(WebSocket/HTTP)将 Assistant 内容回写飞书;Typing、卡片回调等由 `FeishuChannelConfig` 开关控制。
 
 
 ### 用户再次发送消息
 ### 用户再次发送消息
 
 
-1. 飞书用户发送消息
-2. FeishuConnector 处理 Webhook
-3. MessageRouter 查询到已有 Trace
-4. 直接提交任务给 Executor
-5. Agent 执行并回复
+1. 已绑定 `trace_id` 时,可直接 `submit_task(trace_id, ...)` 续跑。
+2. Workspace/沙箱通常 **跨多轮复用**(默认不在单次 Trace 终态停容器,见 `stop_container_on_trace_terminal`)。
 
 
 ---
 ---
 
 
@@ -183,27 +161,25 @@ class ChannelManager:
 ### 与 Lifecycle 模块
 ### 与 Lifecycle 模块
 
 
 ```python
 ```python
-# 创建 Trace
-from gateway.core.lifecycle import TraceManager
-
-trace_mgr = TraceManager()
-trace_id = trace_mgr.create_trace(
-    workspace_id=f"feishu:{user_id}",
-    agent_type="personal_assistant"
+# 准备会话目录与沙箱;Agent 返回 trace_id 后再绑定
+await trace_mgr.prepare_workspace_session(f"feishu:{user_id}")
+# ... Agent run 得到 trace_id 后:
+await trace_mgr.bind_agent_trace(
+    f"feishu:{user_id}",
+    agent_trace_id=trace_id,
+    agent_type="personal_assistant",
 )
 )
 ```
 ```
 
 
+详见 [Lifecycle 模块](./lifecycle.md)(目录布局、命名卷、`volume_subpath`)。
+
 ### 与 Executor 模块
 ### 与 Executor 模块
 
 
 ```python
 ```python
-# 提交任务
-from gateway.core.executor import TaskManager
-
-task_mgr = TaskManager()
-task_id = task_mgr.submit_task(
+task_id = await task_mgr.submit_task(
     trace_id=trace_id,
     trace_id=trace_id,
     task_description=message_text,
     task_description=message_text,
-    mode="async"
+    mode="async",
 )
 )
 ```
 ```
 
 
@@ -274,5 +250,6 @@ channels:
 
 
 - [需求规划](../requirements.md):外部渠道接入需求
 - [需求规划](../requirements.md):外部渠道接入需求
 - [架构设计](../architecture.md):模块在整体架构中的位置
 - [架构设计](../architecture.md):模块在整体架构中的位置
-- [Lifecycle 模块](./lifecycle.md):生命周期管理模块
-- [Executor 模块](./executor.md):任务执行调度模块
+- [Lifecycle 模块](./lifecycle.md):Workspace、沙箱卷、Trace 绑定
+- [Executor 模块](./executor.md):任务提交、`gateway_exec`、Agent HTTP
+- 仓库根目录 `docker-compose.yml`:`gateway` / `feishu` / `api` 服务与环境变量

+ 55 - 91
gateway/docs/core/executor.md

@@ -51,11 +51,15 @@
 
 
 ```
 ```
 gateway/core/executor/
 gateway/core/executor/
-├── task_manager.py        # 任务管理
-├── scheduler.py           # 调度器
-└── execution_context.py   # 执行上下文
+├── __init__.py            # 导出 TaskManager、ExecutionContext、build_executor_router 等
+├── task_manager.py        # TaskManager、ExecutionContext、AgentTraceHttpClient、执行管道
+├── models.py              # TaskRecord、TaskStatus、RunMode
+├── api.py                 # FastAPI 路由 build_executor_router
+└── errors.py              # ExecutorError、TaskNotFoundError
 ```
 ```
 
 
+**说明:** 无独立 `scheduler.py`;按 **trace_id 互斥** 的串行由 `task_manager.py` 内 `_TraceSerialLocks` + `asyncio` 任务完成。
+
 ---
 ---
 
 
 ## 关键功能
 ## 关键功能
@@ -65,22 +69,30 @@ gateway/core/executor/
 **实现位置:** `gateway/core/executor/task_manager.py`
 **实现位置:** `gateway/core/executor/task_manager.py`
 
 
 **职责:**
 **职责:**
-- 接收用户任务
-- 存储任务信息
-- 查询任务状态和结果
+- 校验 Trace 存在(`TraceManager.get_trace`)
+- **内存任务表**(`_InMemoryTaskStore`);同一 `trace_id` 下任务 **串行**(`_TraceSerialLocks`)
+- 通过 `AgentTraceHttpClient` 调用 Agent:`POST /api/traces/{trace_id}/run`,轮询 `GET /api/traces/{trace_id}` 直至终态
+- 若 `WorkspaceManager.get_workspace_container_id` 有值,在请求体中附带 **`gateway_exec`**(`docker_container`、`container_workdir=/home/agent/workspace` 等),使 Agent 在沙箱内执行
 
 
 **核心接口:**
 **核心接口:**
 
 
 ```python
 ```python
 class TaskManager:
 class TaskManager:
-    def submit_task(
+    @classmethod
+    def from_env(
+        cls,
+        workspace_manager: WorkspaceManager,
+        trace_manager: TraceManager,
+    ) -> TaskManager: ...
+
+    async def submit_task(
         self,
         self,
         trace_id: str,
         trace_id: str,
         task_description: str,
         task_description: str,
-        mode: str = "async",  # "sync" | "async"
-        metadata: dict = None
+        mode: RunMode = "async",  # "sync" | "async"
+        metadata: dict | None = None,
     ) -> str:
     ) -> str:
-        """提交任务,返回 task_id"""
+        """提交任务,返回 task_id;sync 模式下会阻塞至任务结束"""
         pass
         pass
 
 
     def get_task(self, task_id: str) -> dict:
     def get_task(self, task_id: str) -> dict:
@@ -89,68 +101,31 @@ class TaskManager:
 
 
     def list_tasks(
     def list_tasks(
         self,
         self,
-        trace_id: str = None,
-        status: str = None
+        trace_id: str | None = None,
+        status: str | None = None,
     ) -> list[dict]:
     ) -> list[dict]:
         """查询任务列表"""
         """查询任务列表"""
         pass
         pass
 
 
-    def cancel_task(self, task_id: str):
-        """取消任务"""
-        pass
-```
-
-### Scheduler
-
-**实现位置:** `gateway/core/executor/scheduler.py`
-
-**职责:**
-- 调度 Agent 框架执行任务
-- 管理执行队列
-- 处理并发和串行逻辑
-
-**核心接口:**
-
-```python
-class Scheduler:
-    def schedule(self, task_id: str):
-        """调度任务执行"""
+    async def cancel_task(self, task_id: str) -> None:
+        """取消任务;运行中会 POST Agent /stop"""
         pass
         pass
 
 
-    def execute(self, task_id: str) -> dict:
-        """执行任务(调用 Agent 框架)"""
-        pass
-
-    def get_queue_status(self, trace_id: str) -> dict:
-        """获取队列状态"""
+    def get_execution_logs(self, task_id: str) -> list[dict]:
+        """内存执行日志"""
         pass
         pass
 ```
 ```
 
 
-### ExecutionContext
+### ExecutionContext 与 AgentTraceHttpClient
 
 
-**实现位置:** `gateway/core/executor/execution_context.py`
+**实现位置:** 同 `task_manager.py`
 
 
-**职责:**
-- 管理任务执行上下文
-- 提供 Agent 执行所需的环境信息
-- 记录执行日志
+- **ExecutionContext**:按 `trace_id` 解析 `workspace_id` 与 **Workspace 路径**(`WorkspaceManager.get_workspace_path`);内存记录每任务的执行日志。
+- **AgentTraceHttpClient**:对 Agent 基址(`GATEWAY_AGENT_API_BASE_URL`)的 HTTP 封装(`post_run`、`get_trace_status`、`post_stop`)。
 
 
-**核心接口:**
+### HTTP 路由
 
 
-```python
-class ExecutionContext:
-    def create_context(self, task_id: str, trace_id: str) -> dict:
-        """创建执行上下文"""
-        pass
-
-    def get_workspace_path(self, trace_id: str) -> str:
-        """获取 Workspace 路径"""
-        pass
-
-    def log_execution(self, task_id: str, log_entry: dict):
-        """记录执行日志"""
-        pass
-```
+**实现位置:** `gateway/core/executor/api.py` 的 `build_executor_router`,挂载 Gateway 应用的 Executor API。
 
 
 ---
 ---
 
 
@@ -196,23 +171,18 @@ queue_key = f"task_queue:digital_employee:{agent_id}"
 
 
 ### 同步任务执行
 ### 同步任务执行
 
 
-1. 用户通过 API 提交任务
-2. TaskManager 创建任务记录(状态:pending)
-3. Scheduler 立即调度执行
-4. 调用 Agent 框架执行任务
-5. 等待执行完成
-6. 更新任务状态(completed/failed)
-7. 返回结果给用户
+1. 调用 `await submit_task(..., mode="sync")`
+2. 内存写入 `TaskRecord`(pending)并启动后台 pipeline
+3. **当前协程**在 `done_ev.wait()` 上阻塞直至任务结束
+4. Pipeline 持 `trace_id` 锁 → `POST .../run` → 轮询 Trace 终态
+5. 返回的 `task_id` 在返回时任务已处于终态
 
 
 ### 异步任务执行
 ### 异步任务执行
 
 
-1. 用户通过 API 提交任务
-2. TaskManager 创建任务记录(状态:pending)
-3. 立即返回 task_id 给用户
-4. Scheduler 异步调度执行
-5. 调用 Agent 框架执行任务
-6. 更新任务状态(running → completed/failed)
-7. 用户通过 task_id 查询结果
+1. 调用 `await submit_task(..., mode="async")`
+2. 立即返回 `task_id`;pipeline 在后台运行
+3. 通过 `get_task` / `list_tasks` 查询状态;`get_execution_logs` 查看内存日志
+4. 终态:`completed` / `failed` / `cancelled`
 
 
 ### 任务取消
 ### 任务取消
 
 
@@ -226,28 +196,22 @@ queue_key = f"task_queue:digital_employee:{agent_id}"
 
 
 ## 与 Lifecycle 模块的集成
 ## 与 Lifecycle 模块的集成
 
 
-Executor 依赖 Lifecycle 模块:
-
-1. **获取 Trace 信息**:
-   ```python
-   from gateway.core.lifecycle import TraceManager
+Executor 构造时注入 `WorkspaceManager` 与 `TraceManager`(见 `TaskManager.from_env`)。
 
 
-   trace_info = await trace_manager.get_trace(trace_id)
-   ```
+1. **提交前校验**:`submit_task` 内 `await trace_manager.get_trace(trace_id)`。
+2. **Workspace 路径**:`ExecutionContext` 通过 `trace_manager.get_workspace_id(trace_id)` → `workspace_manager.get_workspace_path(workspace_id)`。
+3. **沙箱执行**:`_GatewayExecResolver.resolve(trace_id)` 读取 `workspace_manager.get_workspace_container_id(workspace_id)`,非空则写入 `gateway_exec` 传给 Agent。
 
 
-2. **获取 Workspace 路径**:
-   ```python
-   from gateway.core.lifecycle import WorkspaceManager
+**Workspace 目录、meta、Docker 卷与 Compose 配置** 见 [Lifecycle 模块](./lifecycle.md)(`ensure_session`、`volume_subpath`、命名卷名等)。
 
 
-   workspace_path = await workspace_manager.get_workspace_path(workspace_id)
-   ```
+### 环境变量(Executor / Agent HTTP)
 
 
-3. **检查 Trace 状态**:
-   ```python
-   # 确保 Trace 存在且可用
-   if not trace_info:
-       raise TraceNotFoundError(trace_id)
-   ```
+| 变量 | 说明 |
+|------|------|
+| `GATEWAY_AGENT_API_BASE_URL` | Agent API 基址(Compose 中常为 `http://api:8000`) |
+| `GATEWAY_AGENT_API_TIMEOUT` | HTTP 超时(秒) |
+| `GATEWAY_EXECUTOR_POLL_INTERVAL` | 轮询 Trace 状态间隔(秒) |
+| `GATEWAY_EXECUTOR_POLL_MAX_SECONDS` | 最长轮询时间(秒) |
 
 
 ---
 ---
 
 

+ 102 - 39
gateway/docs/core/lifecycle.md

@@ -37,7 +37,7 @@ Agent 生命周期管理,包括:
 
 
 - 多个 Trace 可以共享一个 Workspace(主 Agent 和子 Agent)
 - 多个 Trace 可以共享一个 Workspace(主 Agent 和子 Agent)
 - 包含 Agent 的配置、记忆、技能等
 - 包含 Agent 的配置、记忆、技能等
-- 路径格式:`~/.gateway/workspaces/{workspace_id}/`
+- Gateway 进程内目录:``{GATEWAY_WORKSPACES_ROOT}/{sha256(workspace_id)}/``(默认 ``/root/.gateway/workspaces/<64位hex>/``),**不是**用明文 ``workspace_id`` 作目录名;详见下文「目录与 meta」。
 - 需要引用计数机制,确保清理时无活跃 Trace
 - 需要引用计数机制,确保清理时无活跃 Trace
 
 
 ---
 ---
@@ -72,31 +72,44 @@ gateway/core/lifecycle/
 
 
 **核心接口:**
 **核心接口:**
 
 
+**说明:** Trace 的创建由 **Agent API**(HTTP)完成;Gateway 在拿到 `trace_id` 后通过 `bind_agent_trace` 与 `WorkspaceManager` 建立关联。详见 `gateway/core/lifecycle/trace/manager.py`。
+
 ```python
 ```python
 class TraceManager:
 class TraceManager:
-    def create_trace(
+    async def prepare_workspace_session(self, workspace_id: str) -> None:
+        """调用 WorkspaceManager.ensure_session(目录 + 沙箱)"""
+        pass
+
+    async def bind_agent_trace(
         self,
         self,
         workspace_id: str,
         workspace_id: str,
-        agent_type: str,  # "personal_assistant" | "digital_employee"
-        metadata: dict = None
-    ) -> str:
-        """创建新 Trace,返回 trace_id"""
+        agent_trace_id: str,
+        agent_type: str,
+        metadata: dict | None = None,
+    ) -> None:
+        """Agent 返回 trace_id 后登记本地 meta 与 workspace 引用"""
         pass
         pass
 
 
-    def get_trace(self, trace_id: str) -> dict:
-        """查询 Trace 信息(调用 Agent 框架)"""
+    async def release_agent_trace(self, workspace_id: str, agent_trace_id: str) -> None:
+        """解除绑定"""
         pass
         pass
 
 
-    def list_traces(
+    async def get_trace(self, trace_id: str) -> dict:
+        """优先请求 Agent API,失败时返回 Gateway 本地登记"""
+        pass
+
+    async def list_traces(
         self,
         self,
-        workspace_id: str = None,
-        agent_type: str = None
+        workspace_id: str | None = None,
+        agent_type: str | None = None,
+        *,
+        limit: int = 50,
     ) -> list[dict]:
     ) -> list[dict]:
-        """查询 Trace 列表"""
+        """查询 Trace 列表(带 Agent API 查询参数约定)"""
         pass
         pass
 
 
     def get_workspace_id(self, trace_id: str) -> str:
     def get_workspace_id(self, trace_id: str) -> str:
-        """获取 Trace 对应的 workspace_id"""
+        """同步:解析 workspace_id(Executor、gateway_exec 使用)"""
         pass
         pass
 ```
 ```
 
 
@@ -104,6 +117,51 @@ class TraceManager:
 
 
 **实现位置:** `gateway/core/lifecycle/workspace/manager.py`(Docker 编排见同目录 `docker_runner.py`)
 **实现位置:** `gateway/core/lifecycle/workspace/manager.py`(Docker 编排见同目录 `docker_runner.py`)
 
 
+#### 目录与 meta
+
+磁盘布局与 `manager.py` 文档字符串一致:
+
+| 根路径(环境变量) | 默认(容器内) | 用途 |
+|-------------------|----------------|------|
+| `GATEWAY_WORKSPACES_ROOT` | `/root/.gateway/workspaces` | 每个 workspace 一个子目录(名为 `sha256(workspace_id)`),其下含 `.gateway/meta.json` |
+| `GATEWAY_SHARED_ROOT` | `/root/.gateway/shared` | 多会话/多 workspace 共享文件;沙箱内挂载为 `/home/agent/shared` |
+
+**meta.json** 路径:`{GATEWAY_WORKSPACES_ROOT}/<hex>/.gateway/meta.json`。由 `WorkspaceManager._save_meta` 写入,字段包含 `workspace_id`、`trace_refs`、`workspace_container_id`(沙箱容器 ID)等。在 **`volume_subpath` 模式**下,该目录与沙箱内 `/home/agent/workspace` 为同一块存储(命名卷 + Subpath),故 Agent 在沙箱里也能看到 `workspace/.gateway/meta.json`。
+
+#### Docker 沙箱(WorkspaceDockerRunner)
+
+**实现位置:** `gateway/core/lifecycle/workspace/docker_runner.py`
+
+- 为每个 workspace 保证一个运行中的沙箱容器(镜像默认 `agent/workspace:latest`,容器名前缀 `gws-`)。
+- **挂载模式** `GATEWAY_WORKSPACE_MOUNT_MODE`:
+  - **`bind`(默认)**:`workspace_host_path`、`shared_host_path` 解析后的路径直接 bind 到沙箱(适合 Gateway 与本机 Docker 守护进程同环境、路径对 Docker 可见)。
+  - **`volume_subpath`**:使用命名卷 + `VolumeOptions.Subpath`,将 **workspace 卷** 的子目录 `<hex>` 挂到 `/home/agent/workspace`,**shared 卷** 整卷挂到 `/home/agent/shared`。要求同时设置 `GATEWAY_WORKSPACE_DOCKER_VOLUME` 与 `GATEWAY_SHARED_DOCKER_VOLUME`,且 Gateway 通过 **宿主机 `docker.sock`** 创建的容器与 Compose 使用同一 Docker(卷名一致)。
+- 镜像与网络:`GATEWAY_WORKSPACE_IMAGE`(默认 `agent/workspace:latest`);`GATEWAY_WORKSPACE_DOCKER_NETWORK` 指定沙箱加入的网络名(如 `agent`)。
+- 关闭沙箱编排:`GATEWAY_WORKSPACE_DOCKER_ENABLED=false`;若失败需中断会话则设 `GATEWAY_WORKSPACE_DOCKER_REQUIRED=true`。
+
+#### Gateway 环境变量(Workspace / Docker)
+
+| 变量 | 说明 |
+|------|------|
+| `GATEWAY_WORKSPACES_ROOT` | Workspace 根目录(容器内常为 `/root/.gateway/workspaces`) |
+| `GATEWAY_SHARED_ROOT` | 共享目录(容器内常为 `/root/.gateway/shared`) |
+| `GATEWAY_WORKSPACE_MOUNT_MODE` | `bind` 或 `volume_subpath` |
+| `GATEWAY_WORKSPACE_DOCKER_VOLUME` | `volume_subpath` 时:workspace 数据 **Docker 卷名**(与 Compose 中 `name:` 一致,如 `agent_workspace_root`) |
+| `GATEWAY_SHARED_DOCKER_VOLUME` | `volume_subpath` 时:shared 数据 **Docker 卷名**(如 `agent_workspace_shared`) |
+| `GATEWAY_WORKSPACE_DOCKER_NETWORK` | 沙箱容器加入的网络名 |
+| `GATEWAY_WORKSPACE_IMAGE` | 沙箱镜像,默认 `agent/workspace:latest` |
+| `GATEWAY_WORKSPACE_DOCKER_ENABLED` | 是否启用沙箱容器 |
+| `GATEWAY_WORKSPACE_DOCKER_REQUIRED` | Docker 失败时是否视为致命错误 |
+
+**TraceManager(HTTP)**:`GATEWAY_AGENT_API_BASE_URL`、`GATEWAY_AGENT_API_TIMEOUT`(与 Executor 共用 Agent 基址)。
+
+#### 仓库 `docker-compose.yml`(Gateway 服务)
+
+- 命名卷 **`workspace_root`**(固定名 **`agent_workspace_root`**)→ `/root/.gateway/workspaces`。
+- 命名卷 **`workspace_shared`**(固定名 **`agent_workspace_shared`**)→ `/root/.gateway/shared`;使用 **`driver: local` + bind**,将卷绑定到宿主机目录,便于直接查看文件。
+- **`GATEWAY_SHARED_HOST_BIND`**:**仅用于 Compose 解析**,写在项目根 `.env` 或 shell 环境中;作为 `driver_opts.device` 的宿主机路径。未设置时默认 `${PWD}/.gateway/shared`(请在项目根执行 `docker compose`,并保证目录存在)。**Gateway 进程不读取该变量。**
+- 与上述卷名对应的环境变量:`GATEWAY_WORKSPACE_DOCKER_VOLUME=agent_workspace_root`、`GATEWAY_SHARED_DOCKER_VOLUME=agent_workspace_shared`,并通常配合 `GATEWAY_WORKSPACE_MOUNT_MODE=volume_subpath`。
+
 **职责:**
 **职责:**
 - 创建和初始化 Workspace 目录
 - 创建和初始化 Workspace 目录
 - 管理 Workspace 引用计数
 - 管理 Workspace 引用计数
@@ -113,28 +171,36 @@ class TraceManager:
 
 
 ```python
 ```python
 class WorkspaceManager:
 class WorkspaceManager:
-    def create_workspace(self, workspace_id: str) -> str:
-        """创建 Workspace 目录,返回路径"""
+    async def create_workspace(self, workspace_id: str) -> str:
+        """创建 Workspace 目录(含 meta),返回绝对路径"""
+        pass
+
+    async def ensure_session(self, workspace_id: str) -> str:
+        """会话启动:目录 + 共享目录 + 按需启动沙箱;返回 Workspace 绝对路径"""
+        pass
+
+    async def get_workspace_path(self, workspace_id: str) -> str:
+        """获取 Workspace 路径(不存在则抛错)"""
         pass
         pass
 
 
-    def get_workspace_path(self, workspace_id: str) -> str:
-        """获取 Workspace 路径"""
+    def get_workspace_container_id(self, workspace_id: str) -> str | None:
+        """读 meta 中沙箱容器 ID(供 Executor 注入 gateway_exec)"""
         pass
         pass
 
 
-    def add_trace_ref(self, workspace_id: str, trace_id: str):
+    async def add_trace_ref(self, workspace_id: str, trace_id: str) -> None:
         """增加 Trace 引用"""
         """增加 Trace 引用"""
         pass
         pass
 
 
-    def remove_trace_ref(self, workspace_id: str, trace_id: str):
+    async def remove_trace_ref(self, workspace_id: str, trace_id: str) -> None:
         """移除 Trace 引用"""
         """移除 Trace 引用"""
         pass
         pass
 
 
-    def cleanup_workspace(self, workspace_id: str, force: bool = False):
+    async def cleanup_workspace(self, workspace_id: str, force: bool = False) -> None:
         """清理 Workspace(检查引用计数,force=True 强制清理)"""
         """清理 Workspace(检查引用计数,force=True 强制清理)"""
         pass
         pass
 
 
-    def list_workspaces(self) -> list[dict]:
-        """列出所有 Workspace 及其引用计数"""
+    async def list_workspaces(self) -> list[dict]:
+        """列出所有 Workspace 及其引用计数、容器 ID 等"""
         pass
         pass
 ```
 ```
 
 
@@ -164,31 +230,27 @@ class ConfigWatcher:
 
 
 ## 典型流程
 ## 典型流程
 
 
-### 个人助理型 Agent 首次对话
+### 个人助理型 Agent 首次对话(与当前实现一致)
 
 
-1. 用户通过飞书发送消息
-2. Routing 模块收到消息,查询是否有对应 Trace
-3. 无 Trace → 调用 `TraceManager.create_trace(workspace_id=user_id, agent_type="personal_assistant")`
-4. TraceManager 调用 Agent 框架创建 Trace,返回 trace_id
-5. 调用 `WorkspaceManager.create_workspace(workspace_id=user_id)`(如果不存在)
-6. 调用 `WorkspaceManager.add_trace_ref(workspace_id=user_id, trace_id=trace_id)`
-7. 开始对话
+1. 用户通过飞书发送消息;渠道层解析 `workspace_id`(如 `feishu:<user_id>`)。
+2. `TraceManager.prepare_workspace_session(workspace_id)` → 内部 `WorkspaceManager.ensure_session`(目录、shared、沙箱容器)。
+3. 调用 **Agent HTTP API** 创建/续跑 Trace,得到 `trace_id`。
+4. `TraceManager.bind_agent_trace(workspace_id, trace_id, agent_type, ...)` 登记引用与本地 meta。
+5. **Executor** 侧通过 `TaskManager.submit_task(trace_id, ...)` 驱动 `POST /api/traces/{id}/run`(可带 `gateway_exec` 指向沙箱)。
 
 
 ### 数字员工型 Agent 串行处理
 ### 数字员工型 Agent 串行处理
 
 
 1. 用户 A 发送消息
 1. 用户 A 发送消息
 2. Routing 模块查询数字员工的 Trace(共享 workspace_id)
 2. Routing 模块查询数字员工的 Trace(共享 workspace_id)
-3. 如果无 Trace → 创建(同上)
+3. 如果无 Trace → 仍由 Agent API 创建 trace,再 `bind_agent_trace`(同上)
 4. 如果有 Trace 且正在处理 → 消息进入队列
 4. 如果有 Trace 且正在处理 → 消息进入队列
 5. 当前对话结束 → 从队列取下一条消息
 5. 当前对话结束 → 从队列取下一条消息
 
 
 ### 主 Agent 调用子 Agent
 ### 主 Agent 调用子 Agent
 
 
-1. 主 Agent 执行过程中需要调用子 Agent
-2. 调用 `TraceManager.create_trace(workspace_id=主Agent的workspace_id, agent_type=...)`
-3. 子 Trace 共享主 Trace 的 Workspace
-4. 调用 `WorkspaceManager.add_trace_ref(workspace_id, 子trace_id)`
-5. 子 Agent 执行完成 → `WorkspaceManager.remove_trace_ref(...)`
+1. 主 Agent 执行过程中需要子 Trace 时,由 Agent 侧创建子 trace(HTTP)
+2. Gateway 对子 trace 调用 `bind_agent_trace(同一 workspace_id, 子 trace_id, ...)`
+3. `WorkspaceManager.add_trace_ref` 维护引用;子 Agent 结束后 `remove_trace_ref`(或由渠道策略 `release_agent_trace`)
 
 
 ### Workspace 清理
 ### Workspace 清理
 
 
@@ -201,10 +263,10 @@ class ConfigWatcher:
 
 
 ## 错误处理
 ## 错误处理
 
 
-### Trace 创建失败
+### Trace 创建 / 绑定失败
 
 
-- Agent 框架返回错误 → 向用户返回友好错误信息
-- Workspace 创建失败 → 清理已创建的 Trace,返回错误
+- Agent HTTP 创建或续跑失败 → 渠道/Executor 向用户返回友好错误;**勿**在未拿到 `trace_id` 时调用 `bind_agent_trace`
+- `ensure_session`(Docker 卷、沙箱)失败 → 若 `GATEWAY_WORKSPACE_DOCKER_REQUIRED=true` 则中断;否则可降级为无沙箱(见日志)
 
 
 ### Workspace 引用计数不一致
 ### Workspace 引用计数不一致
 
 
@@ -228,3 +290,4 @@ class ConfigWatcher:
 - [需求规划](../requirements.md):生命周期管理需求
 - [需求规划](../requirements.md):生命周期管理需求
 - [架构设计](../architecture.md):模块在整体架构中的位置
 - [架构设计](../architecture.md):模块在整体架构中的位置
 - [Agent Core 架构](../../../agent/docs/architecture.md):Trace 数据结构定义
 - [Agent Core 架构](../../../agent/docs/architecture.md):Trace 数据结构定义
+- 仓库根目录 `docker-compose.yml`:`gateway` 服务的卷与环境变量与上文「Compose」小节一致,部署时以此为准。