Browse Source

feat: a2a im gateway

Talegorithm 5 ngày trước cách đây
mục cha
commit
301772d835
49 tập tin đã thay đổi với 8852 bổ sung2236 xóa
  1. 0 0
      .browser_use_files/browseruse_agent_data/todo.md
  2. 168 0
      agent/README.md
  3. 1081 0
      agent/docs/architecture.md
  4. 0 0
      agent/docs/decisions.md
  5. 205 0
      agent/docs/knowledge.md
  6. 0 0
      agent/docs/multimodal.md
  7. 331 0
      agent/docs/scope-design.md
  8. 0 0
      agent/docs/skills.md
  9. 0 0
      agent/docs/tools.md
  10. 0 0
      agent/docs/trace-api.md
  11. 76 969
      docs/README.md
  12. 651 0
      docs/a2a-im.md
  13. 0 78
      docs/ref/Claude Code/agent-prompt-agent-creation-architect.md
  14. 0 12
      docs/ref/Claude Code/agent-prompt-bash-command-description-writer.md
  15. 0 9
      docs/ref/Claude Code/system-prompt-doing-tasks.md
  16. 0 6
      docs/ref/Claude Code/system-prompt-tool-usage-policy.md
  17. 0 16
      docs/ref/Claude Code/system-prompt-tool-use-summary-generation.md
  18. 0 0
      docs/ref/Claude Code/tool-description-bash.md
  19. 0 659
      docs/ref/context-comparison.md
  20. 0 98
      docs/ref/create.md
  21. 0 357
      docs/ref/deconstruct_old.md
  22. 0 31
      docs/ref/skills.md
  23. 71 0
      docs/research/README.md
  24. 733 0
      docs/research/a2a-continuous-dialogue.md
  25. 640 0
      docs/research/a2a-cross-device.md
  26. 504 0
      docs/research/a2a-mamp-protocol.md
  27. 114 0
      docs/research/a2a-protocols.md
  28. 484 0
      docs/research/a2a-trace-storage.md
  29. 299 0
      gateway/README.md
  30. 11 0
      gateway/__init__.py
  31. 59 0
      gateway/client/README.md
  32. 475 0
      gateway/client/a2a_im.md
  33. 11 0
      gateway/client/python/__init__.py
  34. 146 0
      gateway/client/python/cli.py
  35. 259 0
      gateway/client/python/client.py
  36. 193 0
      gateway/client/python/tools.py
  37. 11 0
      gateway/core/__init__.py
  38. 172 0
      gateway/core/client.py
  39. 162 0
      gateway/core/registry.py
  40. 222 0
      gateway/core/router.py
  41. 245 0
      gateway/docs/api.md
  42. 250 0
      gateway/docs/architecture.md
  43. 139 0
      gateway/docs/decisions.md
  44. 360 0
      gateway/docs/deployment.md
  45. 370 0
      gateway/docs/enterprise/implementation.md
  46. 288 0
      gateway/docs/enterprise/overview.md
  47. 36 0
      gateway/setup.py
  48. 86 0
      gateway_server.py
  49. 0 1
      node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json

+ 0 - 0
.browser_use_files/browseruse_agent_data/todo.md


+ 168 - 0
agent/README.md

@@ -0,0 +1,168 @@
+# Agent Core
+
+**Agent 核心框架**:提供单个 Agent 的执行能力
+
+## 文档维护规范
+
+0. **先改文档,再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后,再进行代码实现;除非改动较小、不被文档涵盖
+1. **文档分层,链接代码** - 重要或复杂设计可以另有详细文档;关键实现需标注代码文件路径;格式:`module/file.py:function_name`
+2. **简洁快照,日志分离** - 只记录最重要的、与代码准确对应的或者明确的已完成的设计的信息,避免推测、建议,或大量代码;决策依据或修改日志若有必要,可在`docs/decisions.md`另行记录
+
+---
+
+## 概述
+
+Agent Core 是一个完整的 Agent 执行框架,提供:
+- Trace、Message、Goal 管理
+- 工具系统(文件、命令、网络、浏览器)
+- LLM 集成(Gemini、OpenRouter、Yescode)
+- Skills 和 Memory(跨会话知识)
+- 子 Agent 机制
+
+**独立性**:Agent Core 不依赖任何其他模块,可以独立运行。
+
+---
+
+## 模块结构
+
+```
+agent/
+├── core/                  # 核心引擎
+│   ├── runner.py          # AgentRunner + 运行时配置
+│   └── presets.py         # Agent 预设(explore、analyst 等)
+│
+├── trace/                 # 执行追踪(含计划管理)
+│   ├── models.py          # Trace, Message
+│   ├── goal_models.py     # Goal, GoalTree, GoalStats
+│   ├── protocols.py       # TraceStore 接口
+│   ├── store.py           # FileSystemTraceStore 实现
+│   ├── goal_tool.py       # goal 工具(计划管理)
+│   ├── compaction.py      # Context 压缩
+│   ├── api.py             # REST API
+│   └── websocket.py       # WebSocket API
+│
+├── tools/                 # 外部交互工具
+│   ├── registry.py        # 工具注册表
+│   ├── schema.py          # Schema 生成器
+│   ├── models.py          # ToolResult, ToolContext
+│   └── builtin/
+│       ├── file/          # 文件操作
+│       ├── browser/       # 浏览器自动化
+│       ├── bash.py        # 命令执行
+│       ├── subagent.py    # 子 Agent 创建
+│       └── a2a_im.py      # A2A IM 工具(桥接到 Gateway)
+│
+├── memory/                # 跨会话记忆
+│   ├── models.py          # Experience, Skill
+│   ├── stores.py          # 存储实现
+│   ├── skill_loader.py    # Skill 加载器
+│   └── skills/            # 内置 Skills
+│
+└── llm/                   # LLM 集成
+    ├── gemini.py          # Gemini Provider
+    ├── openrouter.py      # OpenRouter Provider
+    └── yescode.py         # Yescode Provider
+```
+
+---
+
+## 核心概念
+
+### Trace(任务执行)
+
+一次完整的 Agent 执行。所有 Agent(主、子、人类协助)都是 Trace。
+
+**实现位置**:`agent/trace/models.py:Trace`
+
+### Goal(目标节点)
+
+计划中的一个目标,支持层级结构。
+
+**实现位置**:`agent/trace/goal_models.py:Goal`
+
+### Message(执行消息)
+
+对应 LLM API 的消息,每条 Message 关联一个 Goal。
+
+**实现位置**:`agent/trace/models.py:Message`
+
+---
+
+## 快速开始
+
+### 基础使用
+
+```python
+from agent.core.runner import AgentRunner, RunConfig
+
+# 创建 Runner
+runner = AgentRunner(
+    llm_call=create_llm_call(),
+    trace_store=FileSystemTraceStore()
+)
+
+# 运行 Agent
+async for item in runner.run(
+    messages=[{"role": "user", "content": "分析项目架构"}],
+    config=RunConfig(model="gpt-4o")
+):
+    if isinstance(item, Trace):
+        print(f"Trace: {item.trace_id}")
+    elif isinstance(item, Message):
+        print(f"Message: {item.content}")
+```
+
+### 使用工具
+
+```python
+from agent.tools import tool, ToolContext, ToolResult
+
+@tool(description="自定义工具")
+async def my_tool(arg: str, ctx: ToolContext) -> ToolResult:
+    return ToolResult(
+        title="成功",
+        output=f"处理结果: {arg}"
+    )
+```
+
+---
+
+## 文档
+
+### 模块文档(agent/docs/)
+
+- [架构设计](./docs/architecture.md):Agent Core 完整架构设计
+- [工具系统](./docs/tools.md):工具定义、注册、双层记忆
+- [Skills 指南](./docs/skills.md):Skill 分类、编写、加载
+- [Trace API](./docs/trace-api.md):Trace 模块 REST API 和 WebSocket 接口
+- [多模态支持](./docs/multimodal.md):图片、PDF 处理
+- [设计决策](./docs/decisions.md):架构决策记录
+
+### 项目级文档(../docs/)
+
+- [项目总览](../docs/README.md):完整的架构设计文档
+- [A2A IM 系统](../docs/a2a-im.md):Agent 间通讯
+- [Enterprise 层](../gateway/docs/enterprise/overview.md):组织级功能
+
+---
+
+## API
+
+### REST API
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET  | `/api/traces` | 列出 Traces |
+| GET  | `/api/traces/{id}` | 获取 Trace 详情 |
+| GET  | `/api/traces/{id}/messages` | 获取 Messages |
+| POST | `/api/traces` | 新建 Trace 并执行 |
+| POST | `/api/traces/{id}/run` | 续跑或回溯 |
+| POST | `/api/traces/{id}/stop` | 停止运行 |
+
+**实现位置**:`agent/trace/api.py`, `agent/trace/run_api.py`
+
+---
+
+## 相关项目
+
+- [Gateway](../gateway/README.md):A2A IM Gateway,提供 Agent 间通讯能力

+ 1081 - 0
agent/docs/architecture.md

@@ -0,0 +1,1081 @@
+# Agent Core 架构设计
+
+本文档描述 Agent Core 模块的完整架构设计。
+
+## 文档维护规范
+
+0. **先改文档,再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后,再进行代码实现;除非改动较小、不被文档涵盖
+1. **文档分层,链接代码** - 重要或复杂设计可以另有详细文档;关键实现需标注代码文件路径;格式:`module/file.py:function_name`
+2. **简洁快照,日志分离** - 只记录最重要的、与代码准确对应的或者明确的已完成的设计的信息,避免推测、建议,或大量代码;决策依据或修改日志若有必要,可在 `decisions.md` 另行记录
+
+---
+
+## 系统概览
+
+**核心理念:所有 Agent 都是 Trace**
+
+| 类型 | 创建方式 | 父子关系 | 状态 |
+|------|---------|---------|------|
+| 主 Agent | 直接调用 `runner.run()` | 无 parent | 正常执行 |
+| 子 Agent | 通过 `agent` 工具 | `parent_trace_id` / `parent_goal_id` 指向父 | 正常执行 |
+| 人类协助 | 通过 `ask_human` 工具 | `parent_trace_id` 指向父 | 阻塞等待 |
+
+---
+
+## 核心架构
+
+### 模块结构
+
+```
+agent/
+├── core/                  # 核心引擎
+│   ├── runner.py          # AgentRunner + 运行时配置
+│   └── presets.py         # Agent 预设(explore、analyst 等)
+│
+├── trace/                 # 执行追踪(含计划管理)
+│   ├── models.py          # Trace, Message
+│   ├── goal_models.py     # Goal, GoalTree, GoalStats
+│   ├── protocols.py       # TraceStore 接口
+│   ├── store.py           # FileSystemTraceStore 实现
+│   ├── goal_tool.py       # goal 工具(计划管理)
+│   ├── compaction.py      # Context 压缩
+│   ├── api.py             # REST API
+│   ├── websocket.py       # WebSocket API
+│   └── trace_id.py        # Trace ID 生成工具
+│
+├── tools/                 # 外部交互工具
+│   ├── registry.py        # 工具注册表
+│   ├── schema.py          # Schema 生成器
+│   ├── models.py          # ToolResult, ToolContext
+│   └── builtin/
+│       ├── file/          # 文件操作(read, write, edit, glob, grep)
+│       ├── browser/       # 浏览器自动化
+│       ├── bash.py        # 命令执行
+│       ├── sandbox.py     # 沙箱环境
+│       ├── search.py      # 网络搜索
+│       ├── webfetch.py    # 网页抓取
+│       ├── skill.py       # 技能加载
+│       └── subagent.py    # agent / evaluate 工具(子 Agent 创建与评估)
+│
+├── memory/                # 跨会话记忆
+│   ├── models.py          # Experience, Skill
+│   ├── protocols.py       # MemoryStore 接口
+│   ├── stores.py          # 存储实现
+│   ├── skill_loader.py    # Skill 加载器
+│   └── skills/            # 内置 Skills(自动注入 system prompt)
+│       ├── planning.md    # 计划与 Goal 工具使用
+│       ├── research.md    # 搜索与内容研究
+│       └── browser.md     # 浏览器自动化
+│
+├── llm/                   # LLM 集成
+│   ├── gemini.py          # Gemini Provider
+│   ├── openrouter.py      # OpenRouter Provider(OpenAI 兼容格式)
+│   ├── yescode.py         # Yescode Provider(Anthropic 原生 Messages API)
+│   └── prompts/           # Prompt 工具
+```
+
+### 职责划分
+
+| 模块 | 职责 |
+|-----|------|
+| **core/** | Agent 执行引擎 + 预设配置 |
+| **trace/** | 执行追踪 + 计划管理 |
+| **tools/** | 与外部世界交互(文件、命令、网络、浏览器) |
+| **memory/** | 跨会话知识(Skills、Experiences) |
+| **llm/** | LLM Provider 适配 |
+
+### 三层记忆模型
+
+```
+┌─────────────────────────────────────────────────────────────┐
+│ Layer 3: Skills(技能库)                                     │
+│ - Markdown 文件,存储领域知识和能力描述                        │
+│ - 通过 skill 工具按需加载到对话历史                            │
+└─────────────────────────────────────────────────────────────┘
+                              ▲
+                              │ 归纳
+┌─────────────────────────────────────────────────────────────┐
+│ Layer 2: Experience(经验库)                                 │
+│ - 数据库存储,条件 + 规则 + 证据                              │
+│ - 向量检索,注入到 system prompt                              │
+└─────────────────────────────────────────────────────────────┘
+                              ▲
+                              │ 提取
+┌─────────────────────────────────────────────────────────────┐
+│ Layer 1: Trace(任务状态)                                    │
+│ - 当前任务的工作记忆                                          │
+│ - Trace + Messages 记录执行过程                               │
+│ - Goals 管理执行计划                                          │
+└─────────────────────────────────────────────────────────────┘
+```
+
+### LLM Provider 适配
+
+#### 内部格式
+
+框架内部统一使用 OpenAI 兼容格式(`List[Dict]`)存储和传递消息。各 Provider 负责双向转换:
+
+| 方向 | 说明 |
+|------|------|
+| 入(LLM 响应 → 框架) | 提取 content、tool_calls、usage,转换为统一 Dict |
+| 出(框架 → LLM 请求) | OpenAI 格式消息列表 → 各 API 原生格式 |
+
+#### 工具消息分组
+
+存储层每个 tool result 独立一条 Message(OpenAI 格式最大公约数)。各 Provider 在出方向按 API 要求自行分组:
+
+| Provider | 分组方式 |
+|----------|---------|
+| OpenRouter | 无需分组(OpenAI 原生支持独立 tool 消息) |
+| Yescode | `_convert_messages_to_anthropic` 合并连续 tool 消息为单个 user message |
+| Gemini | `_convert_messages_to_gemini` 通过 buffer 合并连续 tool 消息 |
+
+#### 跨 Provider 续跑:tool_call_id 规范化
+
+不同 Provider 生成的 tool_call_id 格式不同(OpenAI: `call_xxx`,Anthropic: `toolu_xxx`,Gemini: 合成 `call_0`)。存储层按原样保存,不做规范化。
+
+跨 Provider 续跑时,出方向转换前检测历史中的 tool_call_id 格式,不兼容时统一重写为目标格式(保持 tool_use / tool_result 配对一致)。同格式跳过,零开销。Gemini 按 function name 匹配,无需重写。
+
+**实现**:`agent/llm/openrouter.py:_normalize_tool_call_ids`, `agent/llm/yescode.py:_normalize_tool_call_ids`
+
+---
+
+## 核心流程:Agent Loop
+
+### 参数分层
+
+```
+Layer 1: Infrastructure(基础设施,AgentRunner 构造时设置)
+  trace_store, memory_store, tool_registry, llm_call, skills_dir, utility_llm_call
+
+Layer 2: RunConfig(运行参数,每次 run 时指定)
+  ├─ 模型层:model, temperature, max_iterations, tools
+  └─ 框架层:trace_id, agent_type, uid, system_prompt, parent_trace_id, ...
+
+Layer 3: Messages(任务消息,OpenAI SDK 格式 List[Dict])
+  [{"role": "user", "content": "分析这张图的构图"}]
+```
+
+### RunConfig
+
+```python
+@dataclass
+class RunConfig:
+    # 模型层参数
+    model: str = "gpt-4o"
+    temperature: float = 0.3
+    max_iterations: int = 200
+    tools: Optional[List[str]] = None          # None = 全部已注册工具
+
+    # 框架层参数
+    agent_type: str = "default"
+    uid: Optional[str] = None
+    system_prompt: Optional[str] = None        # None = 从 skills 自动构建
+    skills: Optional[List[str]] = None         # 注入 system prompt 的 skill 名称列表;None = 按 preset 决定
+    enable_memory: bool = True
+    auto_execute_tools: bool = True
+    name: Optional[str] = None                 # 显示名称(空则由 utility_llm 自动生成)
+
+    # Trace 控制
+    trace_id: Optional[str] = None             # None = 新建
+    parent_trace_id: Optional[str] = None      # 子 Agent 专用
+    parent_goal_id: Optional[str] = None
+
+    # 续跑控制
+    after_sequence: Optional[int] = None       # 从哪条消息后续跑(message sequence)
+```
+
+**实现**:`agent/core/runner.py:RunConfig`
+
+### 三种运行模式
+
+通过 RunConfig 参数自然区分,统一入口 `run(messages, config)`:
+
+| 模式 | trace_id | after_sequence | messages 含义 | API 端点 |
+|------|----------|---------------|--------------|----------|
+| 新建 | None | - | 初始任务消息 | `POST /api/traces` |
+| 续跑 | 已有 ID | None 或 == head | 追加到末尾的新消息 | `POST /api/traces/{id}/run` |
+| 回溯 | 已有 ID | 主路径上 < head | 在插入点之后追加的新消息 | `POST /api/traces/{id}/run` |
+
+Runner 根据 `after_sequence` 与当前 `head_sequence` 的关系自动判断行为,前端无需指定模式。
+
+### 执行流程
+
+```python
+async def run(messages: List[Dict], config: RunConfig = None) -> AsyncIterator[Union[Trace, Message]]:
+    # Phase 1: PREPARE TRACE
+    #   无 trace_id → 创建新 Trace(生成 name,初始化 GoalTree)
+    #   有 trace_id + after_sequence 为 None 或 == head → 加载已有 Trace,状态置为 running
+    #   有 trace_id + after_sequence < head → 加载 Trace,执行 rewind(快照 GoalTree,重建,设 parent_sequence)
+    trace = await _prepare_trace(config)
+    yield trace
+
+    # Phase 2: BUILD HISTORY
+    #   从 head_sequence 沿 parent chain 回溯构建主路径消息
+    #   构建 system prompt(新建时注入 skills/experiences;续跑时复用已有)
+    #   追加 input messages(设置 parent_sequence 指向当前 head)
+    history, sequence = await _build_history(trace, messages, config)
+
+    # Phase 3: AGENT LOOP
+    for iteration in range(config.max_iterations):
+        # 周期性注入 GoalTree + Active Collaborators(每 10 轮)
+        if iteration % 10 == 0:
+            inject_context(goal_tree, collaborators)
+
+        response = await llm_call(messages=history, model=config.model, tools=tool_schemas)
+
+        # 按需自动创建 root goal(兜底)
+        # 记录 assistant Message
+        # 执行工具,记录 tool Messages
+        # 无 tool_calls 则 break
+
+    # Phase 4: COMPLETE
+    #   更新 Trace 状态 (completed/failed)
+    trace.status = "completed"
+    yield trace
+```
+
+**实现**:`agent/core/runner.py:AgentRunner`
+
+### 回溯(Rewind)
+
+回溯通过 `RunConfig(trace_id=..., after_sequence=N)` 触发(N 在主路径上且 < head_sequence),在 Phase 1 中执行:
+
+1. **验证插入点**:确保不截断在 assistant(tool_calls) 和 tool response 之间
+2. **快照 GoalTree**:将当前完整 GoalTree 存入 `events.jsonl`(rewind 事件的 `goal_tree_snapshot` 字段)
+3. **按时间重建 GoalTree**:以截断点消息的 `created_at` 为界,保留 `created_at <= cutoff_time` 的所有 goals(无论状态),丢弃 cutoff 之后创建的 goals,清空 `current_id`。将被保留的 `in_progress` goal 重置为 `pending`
+4. **设置 parent_sequence**:新消息的 `parent_sequence` 指向 rewind 点,旧消息自动脱离主路径
+5. **更新 Trace**:`head_sequence` 更新为新消息的 sequence,status 改回 running
+
+新消息的 sequence 从 `last_sequence + 1` 开始(全局递增,不复用)。旧消息无需标记 abandoned,通过消息树结构自然隔离。
+
+### 调用接口
+
+三种模式共享同一入口 `run(messages, config)`:
+
+```python
+# 新建
+async for item in runner.run(
+    messages=[{"role": "user", "content": "分析项目架构"}],
+    config=RunConfig(model="gpt-4o"),
+):
+    ...
+
+# 续跑:在已有 trace 末尾追加消息继续执行
+async for item in runner.run(
+    messages=[{"role": "user", "content": "继续"}],
+    config=RunConfig(trace_id="existing-trace-id"),
+):
+    ...
+
+# 回溯:从指定 sequence 处切断,插入新消息重新执行
+# after_sequence=5 表示新消息的 parent_sequence=5,从此处开始
+async for item in runner.run(
+    messages=[{"role": "user", "content": "换一个方案试试"}],
+    config=RunConfig(trace_id="existing-trace-id", after_sequence=5),
+):
+    ...
+
+# 重新生成:回溯后不插入新消息,直接基于已有消息重跑
+async for item in runner.run(
+    messages=[],
+    config=RunConfig(trace_id="existing-trace-id", after_sequence=5),
+):
+    ...
+```
+
+`after_sequence` 的值是 message 的 `sequence` 号,可通过 `GET /api/traces/{trace_id}/messages` 查看。如果指定的 sequence 是一条带 `tool_calls` 的 assistant 消息,系统会自动将截断点扩展到其所有对应的 tool response 之后(安全截断)。
+
+**停止运行**:
+
+```python
+# 停止正在运行的 Trace
+await runner.stop(trace_id)
+```
+
+调用后 agent loop 在下一个检查点退出,Trace 状态置为 `stopped`,同时保存当前 `head_sequence`(确保续跑时能正确加载完整历史)。
+
+**消息完整性保护(orphaned tool_call 修复)**:续跑加载历史时,`_build_history` 自动检测并修复 orphaned tool_calls(`_heal_orphaned_tool_calls`)。当 agent 被 stop/crash 中断时,可能存在 assistant 的 tool_calls 没有对应的 tool results(包括部分完成的情况:3 个 tool_call 只有 1 个 tool_result)。直接发给 LLM 会导致 400 错误。
+
+修复策略:为每个缺失的 tool_result **插入合成的中断通知**(而非裁剪 assistant 消息):
+
+| 工具类型 | 合成 tool_result 内容 |
+|----------|---------------------|
+| 普通工具 | 简短中断提示,建议重新调用 |
+| agent/evaluate | 结构化中断信息,包含 `sub_trace_id`、执行统计、`continue_from` 用法指引 |
+
+agent 工具的合成结果对齐正常返回值格式(含 `sub_trace_id` 字段),主 Agent 可直接使用 `agent(task=..., continue_from=sub_trace_id)` 续跑被中断的子 Agent。合成消息持久化存储,确保幂等。
+
+**实现**:`agent/core/runner.py:AgentRunner._heal_orphaned_tool_calls`
+
+- `run(messages, config)`:**核心方法**,流式返回 `AsyncIterator[Union[Trace, Message]]`
+- `run_result(messages, config, on_event=None)`:便利方法,内部消费 `run()`,返回结构化结果。`on_event` 回调可实时接收每个 Trace/Message 事件(用于调试时输出子 Agent 执行过程)。主要用于 `agent`/`evaluate` 工具内部
+
+### REST API
+
+#### 查询端点
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET  | `/api/traces` | 列出 Traces |
+| GET  | `/api/traces/{id}` | 获取 Trace 详情(含 GoalTree、Sub-Traces) |
+| GET  | `/api/traces/{id}/messages` | 获取 Messages(支持 mode=main_path/all) |
+| GET  | `/api/traces/running` | 列出正在运行的 Trace |
+| WS   | `/api/traces/{id}/watch` | 实时事件推送 |
+
+**实现**:`agent/trace/api.py`, `agent/trace/websocket.py`
+
+#### 控制端点
+
+需在 `api_server.py` 中配置 Runner。执行在后台异步进行,通过 WebSocket 监听进度。
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/api/traces` | 新建 Trace 并执行 |
+| POST | `/api/traces/{id}/run` | 运行(统一续跑 + 回溯) |
+| POST | `/api/traces/{id}/stop` | 停止运行中的 Trace |
+| POST | `/api/traces/{id}/reflect` | 触发反思,从执行历史中提取经验 |
+
+```bash
+# 新建
+curl -X POST http://localhost:8000/api/traces \
+  -H "Content-Type: application/json" \
+  -d '{"messages": [{"role": "user", "content": "分析项目架构"}], "model": "gpt-4o"}'
+
+# 续跑(after_sequence 为 null 或省略)
+curl -X POST http://localhost:8000/api/traces/{trace_id}/run \
+  -d '{"messages": [{"role": "user", "content": "继续深入分析"}]}'
+
+# 回溯:从 sequence 5 处截断,插入新消息重新执行
+curl -X POST http://localhost:8000/api/traces/{trace_id}/run \
+  -d '{"after_sequence": 5, "messages": [{"role": "user", "content": "换一个方案"}]}'
+
+# 重新生成:回溯到 sequence 5,不插入新消息,直接重跑
+curl -X POST http://localhost:8000/api/traces/{trace_id}/run \
+  -d '{"after_sequence": 5, "messages": []}'
+
+# 停止
+curl -X POST http://localhost:8000/api/traces/{trace_id}/stop
+
+# 反思:追加反思 prompt 运行,结果追加到 experiences 文件
+curl -X POST http://localhost:8000/api/traces/{trace_id}/reflect \
+  -d '{"focus": "为什么第三步选择了错误的方案"}'
+```
+
+响应立即返回 `{"trace_id": "...", "status": "started"}`,通过 `WS /api/traces/{trace_id}/watch` 监听实时事件。
+
+**实现**:`agent/trace/run_api.py`
+
+#### 经验端点
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET  | `/api/experiences` | 读取经验文件内容 |
+
+**实现**:`agent/trace/run_api.py`
+
+---
+
+## 数据模型
+
+### Trace(任务执行)
+
+一次完整的 Agent 执行。所有 Agent(主、子、人类协助)都是 Trace。
+
+```python
+@dataclass
+class Trace:
+    trace_id: str
+    mode: Literal["call", "agent"]           # 单次调用 or Agent 模式
+
+    # Prompt 标识
+    prompt_name: Optional[str] = None
+
+    # Agent 模式特有
+    task: Optional[str] = None
+    agent_type: Optional[str] = None
+
+    # 父子关系(Sub-Trace 特有)
+    parent_trace_id: Optional[str] = None    # 父 Trace ID
+    parent_goal_id: Optional[str] = None     # 哪个 Goal 启动的
+
+    # 状态
+    status: Literal["running", "completed", "failed", "stopped"] = "running"
+
+    # 统计
+    total_messages: int = 0
+    total_tokens: int = 0                    # 总 tokens(prompt + completion)
+    total_prompt_tokens: int = 0
+    total_completion_tokens: int = 0
+    total_cost: float = 0.0
+    total_duration_ms: int = 0
+
+    # 进度追踪
+    last_sequence: int = 0                   # 最新 message 的 sequence(全局递增,不复用)
+    head_sequence: int = 0                   # 当前主路径的头节点 sequence(用于 build_llm_messages)
+    last_event_id: int = 0                   # 最新事件 ID(用于 WS 续传)
+
+    # 配置
+    uid: Optional[str] = None
+    model: Optional[str] = None              # 默认模型
+    tools: Optional[List[Dict]] = None       # 工具定义(OpenAI 格式)
+    llm_params: Dict[str, Any] = {}          # LLM 参数(temperature 等)
+    context: Dict[str, Any] = {}             # 元数据(含 collaborators 列表)
+
+    # 当前焦点
+    current_goal_id: Optional[str] = None
+
+    # 结果
+    result_summary: Optional[str] = None
+    error_message: Optional[str] = None
+
+    # 时间
+    created_at: datetime
+    completed_at: Optional[datetime] = None
+```
+
+**实现**:`agent/trace/models.py`
+
+### Goal(目标节点)
+
+计划中的一个目标,支持层级结构。单独存储于 `goal.json`。
+
+```python
+@dataclass
+class Goal:
+    id: str                                  # 内部 ID("1", "2"...)
+    description: str
+    reason: str = ""                         # 创建理由
+    parent_id: Optional[str] = None          # 父 Goal ID
+    type: GoalType = "normal"                # normal | agent_call
+    status: GoalStatus = "pending"           # pending | in_progress | completed | abandoned
+    summary: Optional[str] = None            # 完成/放弃时的总结
+
+    # agent_call 特有(启动 Sub-Trace)
+    sub_trace_ids: Optional[List[str]] = None
+    agent_call_mode: Optional[str] = None    # explore | delegate | evaluate
+    sub_trace_metadata: Optional[Dict] = None
+
+    # 统计
+    self_stats: GoalStats                    # 自身 Messages 统计
+    cumulative_stats: GoalStats              # 包含子孙的累计统计
+
+    created_at: datetime
+```
+
+**Goal 类型**:
+- `normal` - 普通目标,由 Agent 直接执行
+- `agent_call` - 通过 `agent`/`evaluate` 工具创建的目标,会启动 Sub-Trace
+
+**agent_call 类型的 Goal**:
+- 调用 `agent`/`evaluate` 工具时自动设置
+- `agent_call_mode` 记录使用的模式(explore/delegate/evaluate)
+- `sub_trace_ids` 记录创建的所有 Sub-Trace ID
+- 状态转换:pending → in_progress(Sub-Trace 启动)→ completed(Sub-Trace 完成)
+- `summary` 包含格式化的汇总结果(explore 模式会汇总所有分支)
+
+**Goal 操作**(通过 goal 工具):
+- `add` - 添加顶层目标
+- `under` - 在指定目标下添加子目标
+- `after` - 在指定目标后添加兄弟目标
+- `focus` - 切换焦点到指定目标
+- `done` - 完成当前目标(附带 summary)
+- `abandon` - 放弃当前目标(附带原因)
+
+**实现**:`agent/trace/goal_models.py`, `agent/trace/goal_tool.py`
+
+### Message(执行消息)
+
+对应 LLM API 的消息,每条 Message 关联一个 Goal。消息通过 `parent_sequence` 形成树结构。
+
+```python
+@dataclass
+class Message:
+    message_id: str                          # 格式:{trace_id}-{sequence:04d}
+    trace_id: str
+    role: Literal["system", "user", "assistant", "tool"]
+    sequence: int                            # 全局顺序(递增,不复用)
+    parent_sequence: Optional[int] = None    # 父消息的 sequence(构成消息树)
+    goal_id: Optional[str] = None            # 关联的 Goal ID(初始消息为 None,系统会按需自动创建 root goal 兜底)
+    description: str = ""                    # 系统自动生成的摘要
+    tool_call_id: Optional[str] = None
+    content: Any = None
+
+    # 统计
+    prompt_tokens: Optional[int] = None
+    completion_tokens: Optional[int] = None
+    cost: Optional[float] = None
+    duration_ms: Optional[int] = None
+
+    # LLM 响应信息(仅 role="assistant")
+    finish_reason: Optional[str] = None
+
+    created_at: datetime
+
+    # [已弃用] 由 parent_sequence 树结构替代
+    status: Literal["active", "abandoned"] = "active"
+    abandoned_at: Optional[datetime] = None
+```
+
+**消息树(Message Tree)**:
+
+消息通过 `parent_sequence` 形成树。主路径 = 从 `trace.head_sequence` 沿 parent chain 回溯到 root。
+
+```
+正常对话:1 → 2 → 3 → 4 → 5       (每条的 parent 指向前一条)
+Rewind 到 3:3 → 6(parent=3) → 7   (新主路径,4-5 自动脱离)
+压缩 1-3:   8(summary, parent=None) → 6 → 7  (summary 跳过被压缩的消息)
+反思分支:   5 → 9(reflect, parent=5) → 10     (侧枝,不在主路径上)
+```
+
+`build_llm_messages` = 从 head 沿 parent_sequence 链回溯到 root,反转后返回。
+
+Message 提供格式转换方法:
+- `to_llm_dict()` → OpenAI 格式 Dict(用于 LLM 调用)
+- `from_llm_dict(d, trace_id, sequence, goal_id)` → 从 OpenAI 格式创建 Message
+
+**实现**:`agent/trace/models.py`
+
+---
+
+## Agent 预设
+
+不同类型 Agent 的配置模板,控制工具权限和参数。
+
+```python
+@dataclass
+class AgentPreset:
+    allowed_tools: Optional[List[str]] = None  # None 表示允许全部
+    denied_tools: Optional[List[str]] = None   # 黑名单
+    max_iterations: int = 30
+    temperature: Optional[float] = None
+    skills: Optional[List[str]] = None         # 注入 system prompt 的 skill 名称列表;None = 加载全部
+    description: Optional[str] = None
+
+
+_DEFAULT_SKILLS = ["planning", "research", "browser"]
+
+AGENT_PRESETS = {
+    "default": AgentPreset(
+        allowed_tools=None,
+        max_iterations=30,
+        skills=_DEFAULT_SKILLS,
+        description="默认 Agent,拥有全部工具权限",
+    ),
+    "explore": AgentPreset(
+        allowed_tools=["read", "glob", "grep", "list_files"],
+        denied_tools=["write", "edit", "bash", "task"],
+        max_iterations=15,
+        skills=["planning"],
+        description="探索型 Agent,只读权限,用于代码分析",
+    ),
+    "analyst": AgentPreset(
+        allowed_tools=["read", "glob", "grep", "web_search", "webfetch"],
+        denied_tools=["write", "edit", "bash", "task"],
+        temperature=0.3,
+        max_iterations=25,
+        skills=["planning", "research"],
+        description="分析型 Agent,用于深度分析和研究",
+    ),
+}
+```
+
+**实现**:`agent/core/presets.py`
+
+**用户自定义**:项目级配置文件(如 `examples/how/presets.json`)可通过 `register_preset()` 注册额外预设。项目专用的 Agent 类型建议放在项目目录下,而非内置预设。
+
+---
+
+## 子 Trace 机制
+
+通过 `agent` 工具创建子 Agent 执行任务。`task` 参数为字符串时为单任务(delegate),为列表时并行执行多任务(explore)。支持通过 `messages` 参数预置消息,通过 `continue_from` 参数续跑已有 Sub-Trace。
+
+`agent` 工具负责创建 Sub-Trace 和初始化 GoalTree(因为需要设置自定义 context 元数据和命名规则),创建完成后将 `trace_id` 传给 `RunConfig`,由 Runner 接管后续执行。工具同时维护父 Trace 的 `context["collaborators"]` 列表。
+
+### 跨设备 Agent 通信
+
+支持跨设备的 Agent 间持续对话,通过远程 Trace ID 实现:
+
+**Trace ID 格式**:
+- 本地 Trace:`abc-123`
+- 远程 Trace:`agent://terminal-agent-456/abc-123`(协议 + Agent 地址 + 本地 ID)
+
+**使用方式**:
+```python
+# 调用远程 Agent
+result = agent(task="分析本地项目", agent_url="https://terminal-agent.local")
+# 返回: {"sub_trace_id": "agent://terminal-agent.local/abc-123"}
+
+# 续跑远程 Trace(持续对话)
+result2 = agent(
+    task="重点分析core模块",
+    continue_from="agent://terminal-agent.local/abc-123",
+    agent_url="https://terminal-agent.local"
+)
+```
+
+**实现**:`HybridTraceStore` 自动路由到本地或远程存储,远程访问通过 HTTP API 实现。
+
+**实现位置**:`agent/trace/hybrid_store.py`(规划中)
+
+### agent 工具
+
+```python
+@tool(description="创建 Agent 执行任务")
+async def agent(
+    task: Union[str, List[str]],
+    messages: Optional[Union[Messages, List[Messages]]] = None,
+    continue_from: Optional[str] = None,
+    agent_type: Optional[str] = None,
+    skills: Optional[List[str]] = None,
+    agent_url: Optional[str] = None,  # 远程 Agent 地址(跨设备)
+    context: Optional[dict] = None,
+) -> Dict[str, Any]:
+```
+
+**参数**:
+- `agent_type`: 子 Agent 类型,决定工具权限和默认 skills(对应 `AgentPreset` 名称)
+- `skills`: 覆盖 preset 默认值,显式指定注入 system prompt 的 skill 列表
+- `agent_url`: 远程 Agent 地址,用于跨设备调用(返回远程 Trace ID)
+- `continue_from`: 支持本地或远程 Trace ID
+
+**单任务(delegate)**:`task: str`
+- 创建单个 Sub-Trace
+- 完整工具权限(除 agent/evaluate 外,防止递归)
+- 支持 `continue_from` 续跑已有 Sub-Trace(本地或远程)
+- 支持 `messages` 预置上下文消息
+
+**多任务(explore)**:`task: List[str]`
+- 使用 `asyncio.gather()` 并行执行所有任务
+- 每个任务创建独立的 Sub-Trace
+- 只读工具权限(read_file, grep_content, glob_files, goal)
+- `messages` 支持 1D(共享)或 2D(per-agent)
+- 不支持 `continue_from`
+- 汇总所有分支结果返回
+
+### evaluate 工具
+
+```python
+@tool(description="评估目标执行结果是否满足要求")
+async def evaluate(
+    messages: Optional[Messages] = None,
+    target_goal_id: Optional[str] = None,
+    continue_from: Optional[str] = None,
+    context: Optional[dict] = None,
+) -> Dict[str, Any]:
+```
+
+- 代码自动从 GoalTree 注入目标描述(无需 criteria 参数)
+- 模型把执行结果和上下文放在 `messages` 中
+- `target_goal_id` 默认为当前 goal_id
+- 只读工具权限
+- 返回评估结论和改进建议
+
+### 消息类型别名
+
+定义在 `agent/trace/models.py`,用于工具参数和 runner/LLM API 接口:
+
+```python
+ChatMessage = Dict[str, Any]                          # 单条 OpenAI 格式消息
+Messages = List[ChatMessage]                          # 消息列表
+MessageContent = Union[str, List[Dict[str, str]]]     # content 字段(文本或多模态)
+```
+
+**实现位置**:`agent/tools/builtin/subagent.py`
+
+**详细文档**:[工具系统 - Agent/Evaluate 工具](../agent/docs/tools.md#agent-工具)
+
+### ask_human 工具
+
+创建阻塞式 Trace,等待人类通过 IM/邮件等渠道回复。
+
+**注意**:此功能规划中,暂未实现。
+
+---
+
+## Active Collaborators(活跃协作者)
+
+任务执行中与模型密切协作的实体(子 Agent 或人类),按 **与当前任务的关系** 分类,而非按 human/agent 分类:
+
+| | 持久存在(外部可查) | 任务内活跃(需要注入) |
+|---|---|---|
+| Agent | 专用 Agent(代码审查等) | 当前任务创建的子 Agent |
+| Human | 飞书通讯录 | 当前任务中正在对接的人 |
+
+### 数据模型
+
+活跃协作者存储在 `trace.context["collaborators"]`:
+
+```python
+{
+    "name": "researcher",            # 名称(模型可见)
+    "type": "agent",                 # agent | human
+    "trace_id": "abc-@delegate-001", # trace_id(agent 场景)
+    "status": "completed",           # running | waiting | completed | failed
+    "summary": "方案A最优",          # 最近状态摘要
+}
+```
+
+### 注入方式
+
+与 GoalTree 一同周期性注入(每 10 轮),渲染为 Markdown:
+
+```markdown
+## Active Collaborators
+- researcher [agent, completed]: 方案A最优
+- 谭景玉 [human, waiting]: 已发送方案确认,等待回复
+- coder [agent, running]: 正在实现特征提取模块
+```
+
+列表为空时不注入。
+
+### 维护
+
+各工具负责更新 collaborators 列表(通过 `context["store"]` 写入 trace.context):
+- `agent` 工具:创建/续跑子 Agent 时更新
+- `feishu` 工具:发送消息/收到回复时更新
+- Runner 只负责读取和注入
+
+**持久联系人/Agent**:通过工具按需查询(如 `feishu_get_contact_list`),不随任务注入。
+
+**实现**:`agent/core/runner.py:AgentRunner._build_context_injection`, `agent/tools/builtin/subagent.py`
+
+---
+
+## 工具系统
+
+### 核心概念
+
+```python
+@tool()
+async def my_tool(arg: str, ctx: ToolContext) -> ToolResult:
+    return ToolResult(
+        title="Success",
+        output="Result content",
+        long_term_memory="Short summary"  # 可选:压缩后保留的摘要
+    )
+```
+
+| 类型 | 作用 |
+|------|------|
+| `@tool` | 装饰器,自动注册工具并生成 Schema |
+| `ToolResult` | 工具执行结果,支持双层记忆 |
+| `ToolContext` | 工具执行上下文,依赖注入 |
+
+### 工具分类
+
+| 目录 | 工具 | 说明 |
+|-----|------|------|
+| `trace/` | goal | Agent 内部计划管理 |
+| `builtin/` | agent, evaluate | 子 Agent 创建与评估 |
+| `builtin/file/` | read, write, edit, glob, grep | 文件操作 |
+| `builtin/browser/` | browser actions | 浏览器自动化 |
+| `builtin/` | bash, sandbox, search, webfetch, skill, ask_human | 其他工具 |
+
+### 双层记忆管理
+
+大输出(如网页抓取)只传给 LLM 一次,之后用摘要替代:
+
+```python
+ToolResult(
+    output="<10K tokens 的完整内容>",
+    long_term_memory="Extracted 10000 chars from amazon.com",
+    include_output_only_once=True
+)
+```
+
+**详细文档**:[工具系统](../agent/docs/tools.md)
+
+---
+
+## Skills 系统
+
+### 分类
+
+| 类型 | 加载位置 | 加载时机 |
+|------|---------|---------|
+| **内置 Skill** | System Prompt | Agent 启动时自动注入 |
+| **项目 Skill** | System Prompt | Agent 启动时按 preset/call-site 过滤后注入 |
+| **普通 Skill** | 对话消息 | 模型调用 `skill` 工具时 |
+
+### 目录结构
+
+```
+agent/memory/skills/         # 内置 Skills(始终加载)
+├── planning.md              # 计划与 Goal 工具使用
+├── research.md              # 搜索与内容研究
+└── browser.md               # 浏览器自动化
+
+./skills/                    # 项目自定义 Skills
+```
+
+### Skills 过滤(call-site 选择)
+
+不同 Agent 类型所需的 skills 不同。过滤优先级:
+
+1. `agent()` 工具的 `skills` 参数(显式指定,最高优先级)
+2. `AgentPreset.skills`(preset 默认值)
+3. `None`(加载全部,向后兼容)
+
+示例:调用子 Agent 时只注入解构相关 skill:
+```python
+agent(task="...", agent_type="deconstruct", skills=["planning", "deconstruct"])
+```
+
+**实现**:`agent/memory/skill_loader.py`
+
+**详细文档**:[Skills 使用指南](../agent/docs/skills.md)
+
+---
+
+## Experiences 系统
+
+从执行历史中提取的经验规则,用于指导未来任务。
+
+### 存储规范
+
+经验以 Markdown 文件存储(默认 `./.cache/experiences.md`),人类可读、可编辑、可版本控制。
+
+文件格式:
+
+```markdown
+---
+id: ex_001
+trace_id: trace-xxx
+category: tool_usage
+tags: {state: ["large_file", "dirty_repo"], intent: ["batch_edit", "safe_modify"]}
+metrics: {helpful: 12, harmful: 0}
+created_at: 2026-02-12 15:30
+---
+
+---
+id: ex_002
+...
+```
+---
+
+
+### 反思机制(Reflect)
+
+通过 POST /api/traces/{id}/reflect 触发,旨在将原始执行历史提炼为可复用的知识。
+    1. 分叉反思:在 trace 末尾追加 user message(含反思与打标 Prompt),作为侧枝执行。
+    2. 结构化生成:
+        ·归类:将经验分配至 tool_usage(工具)、logic_flow(逻辑)、environment(环境)等。
+        ·打标:提取 state(环境状态)与 intent(用户意图)语义标签。
+        ·量化:初始 helpful 设为 1。
+    3. 持久化:将带有元数据的 Markdown 块追加至 experiences.md。
+
+实现:agent/trace/run_api.py:reflect_trace
+
+### 语义注入与匹配流程
+新建 Trace 时,Runner 采用“分析-检索-注入”三阶段策略,实现精准经验推荐。
+    1. 意图预分析
+    Runner 调用 utility_llm 对初始任务进行语义提取:
+        -输入:"优化这个项目的 Docker 构建速度"
+        -输出:{state: ["docker", "ci"], intent: ["optimization"]}
+    2. 语义检索
+        在 _load_experiences 中根据标签进行语义匹配(优先匹配 intent,其次是 state),筛选出相关度最高的 Top-K 条经验。
+    3. 精准注入
+        将匹配到的经验注入第一条 user message 末尾:
+```python
+# _build_history 中(仅新建模式):
+if not config.trace_id:
+    relevant_ex = self.experience_retriever.search(task_tags)
+    if relevant_ex:
+        formatted_ex = "\n".join([f"- [{e.id}] {e.content} (Helpful: {e.helpful})" for e in relevant_ex])
+        first_user_msg["content"] += f"\n\n## 参考经验\n\n{formatted_ex}"
+```
+实现:agent/core/runner.py:AgentRunner._build_history
+
+### 经验获取工具
+不再仅限于启动时自动注入,而是通过内置工具供 Agent 在需要时主动调用。当执行结果不符合预期或进入未知领域时,Agent 应优先使用此工具。
+工具定义:
+
+```python
+@tool(description="根据当前任务状态和意图,从经验库中检索相关的历史经验")
+async def get_experience(
+    intent: Optional[str] = None, 
+    state: Optional[str] = None
+) -> Dict[str, Any]:
+    """
+    参数:
+        intent: 想要达成的目标意图 (如 "optimization", "debug")
+        state: 当前环境或遇到的问题状态 (如 "docker_build_fail", "permission_denied")
+    """
+```
+实现: agent/tools/builtin/experience.py
+
+- 语义匹配与应用流程
+    当 Agent 调用 get_experience 时,系统执行以下逻辑:
+    1. 语义检索:根据传入的 intent 或 state 标签,在 experiences.md 中进行匹配。匹配权重:intent > state > helpful 评分。
+    2. 动态注入:工具返回匹配到的 Top-K 条经验(含 ID 和内容)。
+    3. 策略应用:Agent 接收到工具返回的经验后,需在后续 thought 中声明所选用的策略 ID(如 [ex_001]),并据此调整 goal_tree 或工具调用序列。
+
+## Context 压缩
+
+### 两级压缩策略
+
+#### Level 1:GoalTree 过滤(确定性,零成本)
+
+每轮 agent loop 构建 `llm_messages` 时自动执行:
+- 始终保留:system prompt、第一条 user message(含 GoalTree 精简视图)、当前 focus goal 的消息
+- 跳过 completed/abandoned goals 的消息(信息已在 GoalTree summary 中)
+- 通过 Message Tree 的 parent_sequence 实现跳过
+
+大多数情况下 Level 1 足够。
+
+#### Level 2:LLM 总结(仅在 Level 1 后仍超限时触发)
+
+触发条件:Level 1 之后 token 数仍超过阈值(默认 `max_tokens × 0.8`)。
+
+流程:
+1. **经验提取**:先在消息列表末尾追加反思 prompt → 主模型回复 → 追加到 `./.cache/experiences.md`。反思消息为侧枝(parent_sequence 分叉,不在主路径上)
+2. **压缩**:在消息列表末尾追加压缩 prompt(含 GoalTree 完整视图) → 主模型回复 → summary 存为新消息,其 `parent_sequence` 跳过被压缩的范围
+
+### GoalTree 双视图
+
+`to_prompt()` 支持两种模式:
+- `include_summary=False`(默认):精简视图,用于日常周期性注入
+- `include_summary=True`:含所有 completed goals 的 summary,用于 Level 2 压缩时提供上下文
+
+### 压缩存储
+
+- 原始消息永远保留在 `messages/`
+- 压缩 summary 作为普通 Message 存储
+- 通过 `parent_sequence` 树结构实现跳过,无需 compression events 或 skip list
+- Rewind 到压缩区域内时,summary 脱离主路径,原始消息自动恢复
+
+**实现**:`agent/trace/compaction.py`, `agent/trace/goal_models.py`
+
+**详细文档**:[Context 管理](./context-management.md)
+
+---
+
+## 存储接口
+
+```python
+class TraceStore(Protocol):
+    async def create_trace(self, trace: Trace) -> None: ...
+    async def get_trace(self, trace_id: str) -> Trace: ...
+    async def update_trace(self, trace_id: str, **updates) -> None: ...
+    async def add_message(self, message: Message) -> None: ...
+    async def get_trace_messages(self, trace_id: str) -> List[Message]: ...
+    async def get_main_path_messages(self, trace_id: str, head_sequence: int) -> List[Message]: ...
+    async def get_messages_by_goal(self, trace_id: str, goal_id: str) -> List[Message]: ...
+    async def append_event(self, trace_id: str, event_type: str, payload: Dict) -> int: ...
+```
+
+`get_main_path_messages` 从 `head_sequence` 沿 `parent_sequence` 链回溯,返回主路径上的有序消息列表。
+
+**实现**:
+- 协议定义:`agent/trace/protocols.py`
+- 本地存储:`agent/trace/store.py:FileSystemTraceStore`
+- 远程存储:`agent/trace/remote_store.py:RemoteTraceStore`(规划中)
+- 混合存储:`agent/trace/hybrid_store.py:HybridTraceStore`(规划中)
+
+### 跨设备存储
+
+**HybridTraceStore** 根据 Trace ID 自动路由到本地或远程存储:
+
+| Trace ID 格式 | 存储位置 | 访问方式 |
+|--------------|---------|---------|
+| `abc-123` | 本地文件系统 | `FileSystemTraceStore` |
+| `agent://host/abc-123` | 远程 Agent | HTTP API(`RemoteTraceStore`) |
+
+**RemoteTraceStore** 通过 HTTP API 访问远程 Trace:
+- `GET /api/traces/{trace_id}` - 获取 Trace 元数据
+- `GET /api/traces/{trace_id}/messages` - 获取消息历史
+- `POST /api/traces/{trace_id}/run` - 续跑(追加消息并执行)
+
+**认证**:通过 API Key 认证,配置在 `config/agents.yaml`。
+
+**实现位置**:`agent/trace/hybrid_store.py`, `agent/trace/remote_store.py`(规划中)
+
+### 存储结构
+
+```
+.trace/
+├── {trace_id}/
+│   ├── meta.json        # Trace 元数据(含 tools 定义)
+│   ├── goal.json        # GoalTree(mission + goals 列表)
+│   ├── events.jsonl     # 事件流(goal 变更、sub_trace 生命周期等)
+│   └── messages/        # Messages
+│       ├── {trace_id}-0001.json
+│       └── ...
+│
+└── {trace_id}@explore-{序号}-{timestamp}-001/  # 子 Trace
+    └── ...
+```
+
+**events.jsonl 说明**:
+- 记录 Trace 执行过程中的关键事件
+- 每行一个 JSON 对象,包含 event_id、event 类型、时间戳等
+- 主要事件类型:goal_added, goal_updated, sub_trace_started, sub_trace_completed, rewind
+- 用于实时监控和历史回放
+
+**Sub-Trace 目录命名**:
+- Explore: `{parent}@explore-{序号:03d}-{timestamp}-001`
+- Delegate: `{parent}@delegate-{timestamp}-001`
+- Evaluate: `{parent}@evaluate-{timestamp}-001`
+
+**meta.json 示例**:
+```json
+{
+  "trace_id": "0415dc38-...",
+  "mode": "agent",
+  "task": "分析代码结构",
+  "agent_type": "default",
+  "status": "running",
+  "model": "google/gemini-2.5-flash",
+  "tools": [...],
+  "llm_params": {"temperature": 0.3},
+  "context": {
+    "collaborators": [
+      {"name": "researcher", "type": "agent", "trace_id": "...", "status": "completed", "summary": "方案A最优"}
+    ]
+  },
+  "current_goal_id": "3"
+}
+```
+
+---
+
+## 设计决策
+
+详见 [设计决策文档](./decisions.md)
+
+**核心决策**:
+
+1. **所有 Agent 都是 Trace** - 主 Agent、子 Agent、人类协助统一为 Trace,通过 `parent_trace_id` 和 `spawn_tool` 区分
+
+2. **trace/ 模块统一管理执行状态** - 合并原 execution/ 和 goal/,包含计划管理和 Agent 内部控制工具
+
+3. **tools/ 专注外部交互** - 文件、命令、网络、浏览器等与外部世界的交互
+
+4. **Agent 预设替代 Sub-Agent 配置** - 通过 `core/presets.py` 定义不同类型 Agent 的工具权限和参数
+
+---
+
+## 相关文档
+
+| 文档 | 内容 |
+|-----|------|
+| [Context 管理](./context-management.md) | Goals、压缩、Plan 注入策略 |
+| [工具系统](../agent/docs/tools.md) | 工具定义、注册、双层记忆 |
+| [Skills 指南](../agent/docs/skills.md) | Skill 分类、编写、加载 |
+| [多模态支持](../agent/docs/multimodal.md) | 图片、PDF 处理 |
+| [知识管理](./knowledge.md) | 知识结构、检索、提取机制 |
+| [Scope 设计](./scope-design.md) | 知识可见性和权限控制 |
+| [Agent 设计决策](../agent/docs/decisions.md) | Agent Core 架构决策记录 |
+| [Gateway 设计决策](../gateway/docs/decisions.md) | Gateway 架构决策记录 |
+| [组织级概览](../gateway/docs/enterprise/overview.md) | 组织级 Agent 系统架构和规划 |
+| [Enterprise 实现](../gateway/docs/enterprise/implementation.md) | 认证、审计、多租户技术实现 |
+| [测试指南](./testing.md) | 测试策略和命令 |
+| [A2A 协议调研](./research/a2a-protocols.md) | 行业 A2A 通信协议和框架对比 |
+| [A2A 跨设备通信](./research/a2a-cross-device.md) | 跨设备 Agent 通信方案(内部) |
+| [A2A Trace 存储](./research/a2a-trace-storage.md) | 跨设备 Trace 存储方案详细设计 |
+| [MAMP 协议](./research/a2a-mamp-protocol.md) | 与外部 Agent 系统的通用交互协议 |
+| [A2A IM 系统](./a2a-im.md) | Agent 即时通讯系统架构和实现 |
+| [Gateway 架构](../gateway/docs/architecture.md) | Gateway 三层架构和设计决策 |
+| [Gateway 部署](../gateway/docs/deployment.md) | Gateway 部署模式和配置 |
+| [Gateway API](../gateway/docs/api.md) | Gateway API 完整参考 |

+ 0 - 0
docs/decisions.md → agent/docs/decisions.md


+ 205 - 0
agent/docs/knowledge.md

@@ -0,0 +1,205 @@
+**知识结构**(单条知识)
+    id: 知识唯一标识
+    task: 任务描述,什么场景、在做什么
+
+    type: 知识类型(单选)
+        user_profile:用户画像(偏好、习惯、背景、约束)
+        strategy:具体执行经验,从执行过程中反思获得
+        tool:工具名称,简介,使用方法,优缺点对比,代码示例
+        usecase:用户背景,采用方案,实现步骤,问题,效果
+        definition:概念定义,技术原理,应用场景
+        plan:流程步骤,决策点,某个问题的总结方法论
+
+    tags: 业务标签(可有多个)
+        category: 子类别(如 preference, background, habit, constraint)
+        domain: 领域(如 coding_style, architecture)
+        其他自定义标签
+
+    scopes: 可见范围(可有多个,格式:{entity_type}:{entity_id})
+        user:{user_id}:用户级(个人可见)
+        agent:{agent_id}:Agent 级(特定 Agent 可见)
+        project:{project_id}:项目级(项目组可见)
+        team:{team_id}:团队级(部门可见)
+        org:{org_id}:组织级(全公司可见)
+        public:公开(所有人可见)
+
+    owner: 所有者(格式:{entity_type}:{entity_id},唯一)
+        谁创建的,谁有权修改/删除
+
+    visibility: 可见性级别(快速过滤标签)
+        private:私有(仅所有者)
+        shared:共享(多个实体)
+        org:组织级
+        public:公开
+
+    content:
+        基于类型的具体内容,相对完整的一条知识
+
+    source:
+        name: 工具/资源名称(若有)
+        category:paper/exp/skill/book...
+        urls:知识来源的网站
+        agent_id:调用知识查询的agent名称
+        submitted_by:创建本条目的agent负责人名称
+        timestamp: 知识生成时的时间戳
+        trace_id: 来源 Trace ID(若有)
+
+    eval:基于使用反馈
+        helpful: 好用的次数
+        harmful:不好用的次数
+        confidence: 置信度(0-1)
+        helpful_history: [(query+trace_id+outcome), ]用于记录反馈时的调用总结
+        harmful_history: []
+知识检索机制
+    检索流程
+        1. 构建可见范围
+            根据执行上下文(user_id, agent_id, project_id, team_id, org_id)
+            构建用户的所有可见 scopes:
+                - user:{user_id}
+                - agent:{agent_id}
+                - project:{project_id}
+                - team:{team_id}
+                - org:{org_id}
+                - public
+
+        2. 向量检索 + 过滤
+            查询条件:
+                - 语义匹配(向量检索)
+                - scopes 过滤(知识的 scopes 与用户的 visible_scopes 有交集)
+                - type 过滤(可选,按知识类型过滤)
+
+        3. 按优先级排序
+            优先级:user > project > agent > team > org > public
+            取知识的 scopes 中优先级最高的进行排序
+
+    触发时机
+        - Agent 启动时:自动检索相关知识
+        - Goal focus 时:检索与当前目标相关的知识
+        - 主动调用:通过 get_knowledge 工具主动查询
+
+    实现位置(规划)
+        - agent/memory/knowledge_store.py: 知识存储接口
+        - agent/memory/knowledge_retriever.py: 检索逻辑
+        - agent/tools/builtin/knowledge.py: get_knowledge 工具
+知识提取机制
+    触发时机
+        - 主动表达:用户明确表达偏好、纠正、提供背景信息
+        - 任务完成:任务完成后的反思总结
+        - 压缩消息:在压缩消息节点提取经验
+        - 用户反馈:用户对结果的 helpful/harmful 评价
+
+    提取流程
+        1. 识别知识类型
+            根据内容判断是 user_profile / strategy / tool / definition / plan / usecase
+
+        2. 结构化提取
+            - 提取核心内容
+            - 生成标签(category, domain 等)
+            - 确定 scopes(基于执行上下文)
+            - 设置 owner 和 visibility
+
+        3. 持久化存储
+            - 存入知识库(向量数据库 + 元数据)
+            - 记录来源(trace_id, agent_id, timestamp)
+            - 初始化评价(helpful=1, confidence=0.5)
+
+    实现位置(规划)
+        - agent/trace/compaction.py: 压缩时提取经验
+        - agent/tools/builtin/knowledge.py: save_knowledge 工具
+        - agent/memory/knowledge_extractor.py: 知识提取逻辑
+用户画像特殊处理
+    用户画像是一种特殊的知识类型(type=user_profile),具有以下特点:
+
+    获取方式
+        - 持续性:在整个对话过程中持续积累
+        - 多触发点:主动表达 > 任务完成 > 周期性总结
+        - 渐进式:逐步完善,置信度逐渐提高
+
+    存储特点
+        - type: user_profile
+        - scopes: 通常包含 user:{user_id},可能包含 project:{project_id}
+        - owner: user:{user_id}
+        - tags.category: preference | background | habit | constraint
+
+    检索优先级
+        - 在 Agent 启动时自动加载
+        - 优先级高于其他类型的知识
+        - 按 confidence 和 helpful 评分排序
+
+    示例
+        {
+            "id": "profile_001",
+            "type": "user_profile",
+            "task": "用户编码风格偏好",
+            "tags": {
+                "category": "preference",
+                "domain": "coding_style"
+            },
+            "scopes": ["user:123", "project:456"],
+            "owner": "user:123",
+            "visibility": "shared",
+            "content": "用户偏好使用 TypeScript 而非 JavaScript,注重类型安全",
+            "source": {
+                "agent_id": "general_assistant",
+                "trace_id": "trace-xxx",
+                "timestamp": "2026-03-03"
+            },
+            "eval": {
+                "helpful": 5,
+                "harmful": 0,
+                "confidence": 0.9
+            }
+        }
+存储结构(规划)
+    数据库表结构
+        CREATE TABLE knowledge (
+            id TEXT PRIMARY KEY,
+            type TEXT NOT NULL,              -- user_profile | strategy | tool | ...
+            task TEXT,
+            tags JSON,
+            scopes JSON,                     -- ["user:123", "project:456", ...]
+            owner TEXT NOT NULL,             -- "user:123" | "agent:xxx"
+            visibility TEXT,                 -- private | shared | org | public
+            content TEXT,
+            source JSON,
+            eval JSON,
+            embedding VECTOR(1536),          -- 向量检索
+            created_at TIMESTAMP,
+            updated_at TIMESTAMP
+        );
+
+        -- 索引
+        CREATE INDEX idx_type ON knowledge(type);
+        CREATE INDEX idx_owner ON knowledge(owner);
+        CREATE INDEX idx_visibility ON knowledge(visibility);
+        CREATE INDEX idx_scopes ON knowledge USING GIN(scopes);
+
+    文件系统结构
+        /workspace/knowledge/
+        ├── global/                   # 全局知识
+        │   ├── tools.json
+        │   ├── definitions.json
+        │   └── plans.json
+        │
+        ├── agents/                   # Agent 经验
+        │   ├── general_assistant/
+        │   ├── crawler_ops/
+        │   └── ...
+        │
+        └── users/                    # 用户画像
+            ├── user_123/
+            │   ├── profile.json      # 基础信息
+            │   ├── preferences.json  # 偏好
+            │   ├── habits.json       # 习惯
+            │   └── constraints.json  # 约束
+            └── ...
+
+TODO
+    1. 实现知识存储接口(agent/memory/knowledge_store.py)
+    2. 实现知识检索逻辑(agent/memory/knowledge_retriever.py)
+    3. 实现 get_knowledge 工具(agent/tools/builtin/knowledge.py)
+    4. 实现 save_knowledge 工具(agent/tools/builtin/knowledge.py)
+    5. 在 Agent 启动时集成知识检索
+    6. 在 Goal focus 时集成知识检索
+    7. 在压缩消息时集成知识提取
+    8. 实现用户画像的特殊处理逻辑

+ 0 - 0
docs/multimodal.md → agent/docs/multimodal.md


+ 331 - 0
agent/docs/scope-design.md

@@ -0,0 +1,331 @@
+# Scope 设计文档
+
+## 概述
+
+Scope 系统用于控制知识的可见性和访问权限。采用**灵活的标签系统**,而非固定的层级结构。
+
+## 核心原则
+
+1. **知识类型与可见性分离**
+   - `type` 字段表示知识类型(What)
+   - `scopes` 字段表示可见范围(Who)
+
+2. **多 Scope 支持**
+   - 一条知识可以有多个 scope 标签
+   - 支持灵活的共享关系
+
+3. **明确的所有权**
+   - `owner` 字段表示唯一所有者
+   - 只有所有者有权修改/删除
+
+## Scope 格式
+
+```
+格式:{entity_type}:{entity_id}
+
+示例:
+- user:123
+- agent:general_assistant
+- project:456
+- team:frontend
+- org:company
+- public
+```
+
+## Scope 类型
+
+| Scope 类型 | 格式 | 说明 | 示例 |
+|-----------|------|------|------|
+| 用户级 | `user:{user_id}` | 用户个人可见 | `user:123` |
+| Agent 级 | `agent:{agent_id}` | 特定 Agent 可见 | `agent:crawler_ops` |
+| 项目级 | `project:{project_id}` | 项目组可见 | `project:456` |
+| 团队级 | `team:{team_id}` | 部门可见 | `team:frontend` |
+| 组织级 | `org:{org_id}` | 全公司可见 | `org:company` |
+| 公开 | `public` | 所有人可见 | `public` |
+
+## 数据结构
+
+```json
+{
+  "id": "knowledge_001",
+
+  "type": "user_profile",
+
+  "scopes": [
+    "user:123",
+    "project:456"
+  ],
+
+  "owner": "user:123",
+
+  "visibility": "shared",
+
+  "content": "...",
+  "tags": {...},
+  "source": {...},
+  "eval": {...}
+}
+```
+
+## 字段说明
+
+### type(知识类型)
+
+- `user_profile`:用户画像
+- `strategy`:执行经验
+- `tool`:工具知识
+- `usecase`:用例
+- `definition`:概念定义
+- `plan`:方法论
+
+### scopes(可见范围)
+
+- 数组类型,可包含多个 scope
+- 知识对所有 scopes 中的实体可见
+- 检索时匹配:知识的 scopes 与用户的 visible_scopes 有交集
+
+### owner(所有者)
+
+- 字符串类型,格式同 scope
+- 唯一所有者,有权修改/删除
+- 通常是创建者
+
+### visibility(可见性级别)
+
+快速过滤标签,用于 UI 展示和简单查询:
+
+- `private`:私有(仅所有者)
+- `shared`:共享(多个实体)
+- `org`:组织级
+- `public`:公开
+
+## 使用场景
+
+### 场景 1:用户的私有偏好
+
+```json
+{
+  "type": "user_profile",
+  "scopes": ["user:123"],
+  "owner": "user:123",
+  "visibility": "private",
+  "content": "用户偏好使用 TypeScript"
+}
+```
+
+### 场景 2:项目组共享的经验
+
+```json
+{
+  "type": "strategy",
+  "scopes": ["project:456"],
+  "owner": "agent:crawler_ops",
+  "visibility": "shared",
+  "content": "爬虫反爬策略:使用代理池 + 随机 UA"
+}
+```
+
+### 场景 3:跨项目的用户偏好
+
+```json
+{
+  "type": "user_profile",
+  "scopes": ["user:123", "project:456", "project:789"],
+  "owner": "user:123",
+  "visibility": "shared",
+  "content": "用户在多个项目中都偏好使用 React"
+}
+```
+
+### 场景 4:Agent 间共享的工具知识
+
+```json
+{
+  "type": "tool",
+  "scopes": [
+    "agent:crawler_ops",
+    "agent:content_library",
+    "agent:general_assistant"
+  ],
+  "owner": "agent:crawler_ops",
+  "visibility": "shared",
+  "content": "Selenium 使用技巧:headless 模式配置"
+}
+```
+
+### 场景 5:组织级公开知识
+
+```json
+{
+  "type": "definition",
+  "scopes": ["org:company"],
+  "owner": "org:company",
+  "visibility": "org",
+  "content": "公司技术栈:React + TypeScript + Node.js"
+}
+```
+
+### 场景 6:完全公开的知识
+
+```json
+{
+  "type": "tool",
+  "scopes": ["public"],
+  "owner": "org:company",
+  "visibility": "public",
+  "content": "Git 常用命令速查表"
+}
+```
+
+## 检索逻辑
+
+### 构建可见范围
+
+```python
+def build_visible_scopes(context):
+    """
+    根据执行上下文构建用户的所有可见 scopes
+
+    context = {
+        "user_id": "123",
+        "agent_id": "general_assistant",
+        "project_id": "456",
+        "team_id": "frontend",
+        "org_id": "company"
+    }
+    """
+    scopes = []
+
+    if context.get("user_id"):
+        scopes.append(f"user:{context['user_id']}")
+
+    if context.get("agent_id"):
+        scopes.append(f"agent:{context['agent_id']}")
+
+    if context.get("project_id"):
+        scopes.append(f"project:{context['project_id']}")
+
+    if context.get("team_id"):
+        scopes.append(f"team:{context['team_id']}")
+
+    if context.get("org_id"):
+        scopes.append(f"org:{context['org_id']}")
+
+    scopes.append("public")
+
+    return scopes
+```
+
+### 检索查询
+
+```python
+def search_knowledge(query, context, knowledge_type=None):
+    """
+    检索知识
+
+    query: 查询内容
+    context: 用户上下文
+    knowledge_type: 可选,过滤知识类型
+    """
+    # 1. 构建可见范围
+    visible_scopes = build_visible_scopes(context)
+
+    # 2. 构建查询条件
+    filters = {
+        "scopes": {"$in": visible_scopes}  # 交集匹配
+    }
+
+    if knowledge_type:
+        filters["type"] = knowledge_type
+
+    # 3. 向量检索 + 过滤
+    results = vector_db.search(
+        query=query,
+        filter=filters,
+        top_k=10
+    )
+
+    # 4. 按优先级排序
+    return rank_by_scope_priority(results, context)
+```
+
+### 优先级排序
+
+```python
+def rank_by_scope_priority(results, context):
+    """
+    按 scope 优先级排序
+
+    优先级:user > project > agent > team > org > public
+    """
+    priority_map = {
+        f"user:{context.get('user_id')}": 6,
+        f"project:{context.get('project_id')}": 5,
+        f"agent:{context.get('agent_id')}": 4,
+        f"team:{context.get('team_id')}": 3,
+        f"org:{context.get('org_id')}": 2,
+        "public": 1
+    }
+
+    def get_priority(knowledge):
+        # 取知识的 scopes 中优先级最高的
+        max_priority = 0
+        for scope in knowledge["scopes"]:
+            max_priority = max(max_priority, priority_map.get(scope, 0))
+        return max_priority
+
+    return sorted(results, key=get_priority, reverse=True)
+```
+
+## 权限控制
+
+### 读权限
+
+用户可以读取知识,当且仅当:
+- 知识的 `scopes` 与用户的 `visible_scopes` 有交集
+
+### 写权限
+
+用户可以修改/删除知识,当且仅当:
+- 用户是知识的 `owner`
+
+### 特殊情况
+
+- 管理员可以修改/删除所有知识
+- 组织级知识(owner=org:xxx)可以由管理员管理
+
+## 实现位置
+
+- `agent/memory/knowledge_store.py`:知识存储接口
+- `agent/memory/knowledge_retriever.py`:检索逻辑
+- `agent/tools/builtin/knowledge.py`:get_knowledge / save_knowledge 工具
+
+## 扩展性
+
+### 新增 Scope 类型
+
+如需新增 scope 类型(如 `department:{dept_id}`),只需:
+
+1. 在 `build_visible_scopes` 中添加逻辑
+2. 在 `rank_by_scope_priority` 中添加优先级
+3. 无需修改数据结构和存储逻辑
+
+### 升级为 ACL
+
+如需更细粒度的权限控制,可扩展为 ACL 系统:
+
+```json
+{
+  "id": "knowledge_001",
+  "type": "strategy",
+  "owner": "user:123",
+  "acl": [
+    {"entity": "user:123", "permission": "read_write"},
+    {"entity": "project:456", "permission": "read"},
+    {"entity": "agent:general_assistant", "permission": "read"}
+  ]
+}
+```
+
+但对于大多数场景,当前的 scope 标签系统已经足够。
+

+ 0 - 0
docs/skills.md → agent/docs/skills.md


+ 0 - 0
docs/tools.md → agent/docs/tools.md


+ 0 - 0
docs/trace-api.md → agent/docs/trace-api.md


+ 76 - 969
docs/README.md

@@ -1,1016 +1,123 @@
-# Agent 功能需求与架构设计文档
+# Agent 系统文档
 
-## 文档维护规范
+## 文档导航
 
-0. **先改文档,再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后,再进行代码实现;除非改动较小、不被文档涵盖
-1. **文档分层,链接代码** - 重要或复杂设计可以另有详细文档;关键实现需标注代码文件路径;格式:`module/file.py:function_name`
-2. **简洁快照,日志分离** - 只记录最重要的、与代码准确对应的或者明确的已完成的设计的信息,避免推测、建议,或大量代码;决策依据或修改日志若有必要,可在`docs/decisions.md`另行记录
+本文档是项目总览和文档导航。详细的模块文档请参考:
 
----
+### 核心模块
 
-## 系统概览
+- **[Agent Core 模块](../agent/README.md)** - Agent 核心引擎、工具系统、记忆管理
+  - [架构设计](../agent/docs/architecture.md) - Agent 框架完整架构
+  - [工具系统](../agent/docs/tools.md)
+  - [Skills 指南](../agent/docs/skills.md)
+  - [Trace API](../agent/docs/trace-api.md)
+  - [多模态支持](../agent/docs/multimodal.md)
+  - [设计决策](../agent/docs/decisions.md)
 
-**核心理念:所有 Agent 都是 Trace**
+- **[Gateway 模块](../gateway/README.md)** - Agent 注册、消息路由、在线状态管理
+  - [架构设计](../gateway/docs/architecture.md)
+  - [部署指南](../gateway/docs/deployment.md)
+  - [API 参考](../gateway/docs/api.md)
+  - [设计决策](../gateway/docs/decisions.md)
+  - [Enterprise 层](../gateway/docs/enterprise/overview.md)
+  - [A2A IM 使用](../gateway/client/a2a_im.md) - Agent 间通讯工具
 
-| 类型 | 创建方式 | 父子关系 | 状态 |
-|------|---------|---------|------|
-| 主 Agent | 直接调用 `runner.run()` | 无 parent | 正常执行 |
-| 子 Agent | 通过 `agent` 工具 | `parent_trace_id` / `parent_goal_id` 指向父 | 正常执行 |
-| 人类协助 | 通过 `ask_human` 工具 | `parent_trace_id` 指向父 | 阻塞等待 |
+### 跨模块文档
 
----
-
-## 核心架构
-
-### 模块结构
-
-```
-agent/
-├── core/                  # 核心引擎
-│   ├── runner.py          # AgentRunner + 运行时配置
-│   └── presets.py         # Agent 预设(explore、analyst 等)
-│
-├── trace/                 # 执行追踪(含计划管理)
-│   ├── models.py          # Trace, Message
-│   ├── goal_models.py     # Goal, GoalTree, GoalStats
-│   ├── protocols.py       # TraceStore 接口
-│   ├── store.py           # FileSystemTraceStore 实现
-│   ├── goal_tool.py       # goal 工具(计划管理)
-│   ├── compaction.py      # Context 压缩
-│   ├── api.py             # REST API
-│   ├── websocket.py       # WebSocket API
-│   └── trace_id.py        # Trace ID 生成工具
-│
-├── tools/                 # 外部交互工具
-│   ├── registry.py        # 工具注册表
-│   ├── schema.py          # Schema 生成器
-│   ├── models.py          # ToolResult, ToolContext
-│   └── builtin/
-│       ├── file/          # 文件操作(read, write, edit, glob, grep)
-│       ├── browser/       # 浏览器自动化
-│       ├── bash.py        # 命令执行
-│       ├── sandbox.py     # 沙箱环境
-│       ├── search.py      # 网络搜索
-│       ├── webfetch.py    # 网页抓取
-│       ├── skill.py       # 技能加载
-│       └── subagent.py    # agent / evaluate 工具(子 Agent 创建与评估)
-│
-├── memory/                # 跨会话记忆
-│   ├── models.py          # Experience, Skill
-│   ├── protocols.py       # MemoryStore 接口
-│   ├── stores.py          # 存储实现
-│   ├── skill_loader.py    # Skill 加载器
-│   └── skills/            # 内置 Skills(自动注入 system prompt)
-│       ├── planning.md    # 计划与 Goal 工具使用
-│       ├── research.md    # 搜索与内容研究
-│       └── browser.md     # 浏览器自动化
-│
-├── llm/                   # LLM 集成
-│   ├── gemini.py          # Gemini Provider
-│   ├── openrouter.py      # OpenRouter Provider(OpenAI 兼容格式)
-│   ├── yescode.py         # Yescode Provider(Anthropic 原生 Messages API)
-│   └── prompts/           # Prompt 工具
-```
+- [A2A IM 系统](./a2a-im.md) - Agent 间即时通讯系统架构
+- [知识管理](./knowledge.md) - 知识结构、检索、提取机制
+- [Scope 设计](./scope-design.md) - 知识可见性和权限控制
+- [Context 管理](./context-management.md) - Goals、压缩、Plan 注入策略
 
-### 职责划分
+### 研究文档
 
-| 模块 | 职责 |
-|-----|------|
-| **core/** | Agent 执行引擎 + 预设配置 |
-| **trace/** | 执行追踪 + 计划管理 |
-| **tools/** | 与外部世界交互(文件、命令、网络、浏览器) |
-| **memory/** | 跨会话知识(Skills、Experiences) |
-| **llm/** | LLM Provider 适配 |
+- [A2A 协议调研](./research/a2a-protocols.md) - 行业 A2A 通信协议和框架对比
+- [A2A 跨设备通信](./research/a2a-cross-device.md) - 跨设备 Agent 通信方案(内部)
+- [A2A Trace 存储](./research/a2a-trace-storage.md) - 跨设备 Trace 存储方案详细设计
+- [MAMP 协议](./research/a2a-mamp-protocol.md) - 与外部 Agent 系统的通用交互协议
 
-### 三层记忆模型
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│ Layer 3: Skills(技能库)                                     │
-│ - Markdown 文件,存储领域知识和能力描述                        │
-│ - 通过 skill 工具按需加载到对话历史                            │
-└─────────────────────────────────────────────────────────────┘
-                              ▲
-                              │ 归纳
-┌─────────────────────────────────────────────────────────────┐
-│ Layer 2: Experience(经验库)                                 │
-│ - 数据库存储,条件 + 规则 + 证据                              │
-│ - 向量检索,注入到 system prompt                              │
-└─────────────────────────────────────────────────────────────┘
-                              ▲
-                              │ 提取
-┌─────────────────────────────────────────────────────────────┐
-│ Layer 1: Trace(任务状态)                                    │
-│ - 当前任务的工作记忆                                          │
-│ - Trace + Messages 记录执行过程                               │
-│ - Goals 管理执行计划                                          │
-└─────────────────────────────────────────────────────────────┘
-```
-
-### LLM Provider 适配
-
-#### 内部格式
-
-框架内部统一使用 OpenAI 兼容格式(`List[Dict]`)存储和传递消息。各 Provider 负责双向转换:
-
-| 方向 | 说明 |
-|------|------|
-| 入(LLM 响应 → 框架) | 提取 content、tool_calls、usage,转换为统一 Dict |
-| 出(框架 → LLM 请求) | OpenAI 格式消息列表 → 各 API 原生格式 |
-
-#### 工具消息分组
-
-存储层每个 tool result 独立一条 Message(OpenAI 格式最大公约数)。各 Provider 在出方向按 API 要求自行分组:
-
-| Provider | 分组方式 |
-|----------|---------|
-| OpenRouter | 无需分组(OpenAI 原生支持独立 tool 消息) |
-| Yescode | `_convert_messages_to_anthropic` 合并连续 tool 消息为单个 user message |
-| Gemini | `_convert_messages_to_gemini` 通过 buffer 合并连续 tool 消息 |
-
-#### 跨 Provider 续跑:tool_call_id 规范化
-
-不同 Provider 生成的 tool_call_id 格式不同(OpenAI: `call_xxx`,Anthropic: `toolu_xxx`,Gemini: 合成 `call_0`)。存储层按原样保存,不做规范化。
+---
 
-跨 Provider 续跑时,出方向转换前检测历史中的 tool_call_id 格式,不兼容时统一重写为目标格式(保持 tool_use / tool_result 配对一致)。同格式跳过,零开销。Gemini 按 function name 匹配,无需重写。
+## 文档维护规范
 
-**实现**:`agent/llm/openrouter.py:_normalize_tool_call_ids`, `agent/llm/yescode.py:_normalize_tool_call_ids`
+0. **先改文档,再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后,再进行代码实现;除非改动较小、不被文档涵盖
+1. **文档分层,链接代码** - 重要或复杂设计可以另有详细文档;关键实现需标注代码文件路径;格式:`module/file.py:function_name`
+2. **简洁快照,日志分离** - 只记录最重要的、与代码准确对应的或者明确的已完成的设计的信息,避免推测、建议,或大量代码;决策依据或修改日志若有必要,可在模块的 decisions.md 另行记录
 
 ---
 
-## 核心流程:Agent Loop
+## 项目概览
 
-### 参数分层
+### 系统架构
 
 ```
-Layer 1: Infrastructure(基础设施,AgentRunner 构造时设置)
-  trace_store, memory_store, tool_registry, llm_call, skills_dir, utility_llm_call
-
-Layer 2: RunConfig(运行参数,每次 run 时指定)
-  ├─ 模型层:model, temperature, max_iterations, tools
-  └─ 框架层:trace_id, agent_type, uid, system_prompt, parent_trace_id, ...
-
-Layer 3: Messages(任务消息,OpenAI SDK 格式 List[Dict])
-  [{"role": "user", "content": "分析这张图的构图"}]
+Agent 系统
+├── agent/          # Agent Core - 核心引擎、工具、记忆
+├── gateway/        # Gateway - 消息路由、Agent 注册
+├── docs/           # 跨模块文档
+└── examples/       # 使用示例和集成示例
 ```
 
-### RunConfig
+### 核心理念
 
-```python
-@dataclass
-class RunConfig:
-    # 模型层参数
-    model: str = "gpt-4o"
-    temperature: float = 0.3
-    max_iterations: int = 200
-    tools: Optional[List[str]] = None          # None = 全部已注册工具
-
-    # 框架层参数
-    agent_type: str = "default"
-    uid: Optional[str] = None
-    system_prompt: Optional[str] = None        # None = 从 skills 自动构建
-    skills: Optional[List[str]] = None         # 注入 system prompt 的 skill 名称列表;None = 按 preset 决定
-    enable_memory: bool = True
-    auto_execute_tools: bool = True
-    name: Optional[str] = None                 # 显示名称(空则由 utility_llm 自动生成)
-
-    # Trace 控制
-    trace_id: Optional[str] = None             # None = 新建
-    parent_trace_id: Optional[str] = None      # 子 Agent 专用
-    parent_goal_id: Optional[str] = None
-
-    # 续跑控制
-    after_sequence: Optional[int] = None       # 从哪条消息后续跑(message sequence)
-```
+**所有 Agent 都是 Trace**
 
-**实现**:`agent/core/runner.py:RunConfig`
+| 类型 | 创建方式 | 父子关系 | 状态 |
+|------|---------|---------|------|
+| 主 Agent | 直接调用 `runner.run()` | 无 parent | 正常执行 |
+| 子 Agent | 通过 `agent` 工具 | `parent_trace_id` / `parent_goal_id` 指向父 | 正常执行 |
+| 人类协助 | 通过 `ask_human` 工具 | `parent_trace_id` 指向父 | 阻塞等待 |
 
-### 三种运行模式
+### 模块职责
 
-通过 RunConfig 参数自然区分,统一入口 `run(messages, config)`:
+| 模块 | 职责 | 详细文档 |
+|-----|------|---------|
+| **agent/core/** | Agent 执行引擎 + 预设配置 | [架构设计](../agent/docs/architecture.md) |
+| **agent/trace/** | 执行追踪 + 计划管理 | [Trace API](../agent/docs/trace-api.md) |
+| **agent/tools/** | 与外部世界交互 | [工具系统](../agent/docs/tools.md) |
+| **agent/memory/** | 跨会话知识 | [Skills 指南](../agent/docs/skills.md) |
+| **agent/llm/** | LLM Provider 适配 | [架构设计](../agent/docs/architecture.md#llm-provider-适配) |
+| **gateway/core/** | Agent 注册和消息路由 | [Gateway 架构](../gateway/docs/architecture.md) |
+| **gateway/client/** | Gateway 客户端 SDK | [A2A IM](../gateway/client/a2a_im.md) |
 
-| 模式 | trace_id | after_sequence | messages 含义 | API 端点 |
-|------|----------|---------------|--------------|----------|
-| 新建 | None | - | 初始任务消息 | `POST /api/traces` |
-| 续跑 | 已有 ID | None 或 == head | 追加到末尾的新消息 | `POST /api/traces/{id}/run` |
-| 回溯 | 已有 ID | 主路径上 < head | 在插入点之后追加的新消息 | `POST /api/traces/{id}/run` |
+---
 
-Runner 根据 `after_sequence` 与当前 `head_sequence` 的关系自动判断行为,前端无需指定模式。
+## 快速开始
 
-### 执行流程
+### Agent Core
 
 ```python
-async def run(messages: List[Dict], config: RunConfig = None) -> AsyncIterator[Union[Trace, Message]]:
-    # Phase 1: PREPARE TRACE
-    #   无 trace_id → 创建新 Trace(生成 name,初始化 GoalTree)
-    #   有 trace_id + after_sequence 为 None 或 == head → 加载已有 Trace,状态置为 running
-    #   有 trace_id + after_sequence < head → 加载 Trace,执行 rewind(快照 GoalTree,重建,设 parent_sequence)
-    trace = await _prepare_trace(config)
-    yield trace
-
-    # Phase 2: BUILD HISTORY
-    #   从 head_sequence 沿 parent chain 回溯构建主路径消息
-    #   构建 system prompt(新建时注入 skills/experiences;续跑时复用已有)
-    #   追加 input messages(设置 parent_sequence 指向当前 head)
-    history, sequence = await _build_history(trace, messages, config)
-
-    # Phase 3: AGENT LOOP
-    for iteration in range(config.max_iterations):
-        # 周期性注入 GoalTree + Active Collaborators(每 10 轮)
-        if iteration % 10 == 0:
-            inject_context(goal_tree, collaborators)
-
-        response = await llm_call(messages=history, model=config.model, tools=tool_schemas)
-
-        # 按需自动创建 root goal(兜底)
-        # 记录 assistant Message
-        # 执行工具,记录 tool Messages
-        # 无 tool_calls 则 break
-
-    # Phase 4: COMPLETE
-    #   更新 Trace 状态 (completed/failed)
-    trace.status = "completed"
-    yield trace
-```
+from agent.core import AgentRunner, RunConfig
 
-**实现**:`agent/core/runner.py:AgentRunner`
+runner = AgentRunner(...)
 
-### 回溯(Rewind)
-
-回溯通过 `RunConfig(trace_id=..., after_sequence=N)` 触发(N 在主路径上且 < head_sequence),在 Phase 1 中执行:
-
-1. **验证插入点**:确保不截断在 assistant(tool_calls) 和 tool response 之间
-2. **快照 GoalTree**:将当前完整 GoalTree 存入 `events.jsonl`(rewind 事件的 `goal_tree_snapshot` 字段)
-3. **按时间重建 GoalTree**:以截断点消息的 `created_at` 为界,保留 `created_at <= cutoff_time` 的所有 goals(无论状态),丢弃 cutoff 之后创建的 goals,清空 `current_id`。将被保留的 `in_progress` goal 重置为 `pending`
-4. **设置 parent_sequence**:新消息的 `parent_sequence` 指向 rewind 点,旧消息自动脱离主路径
-5. **更新 Trace**:`head_sequence` 更新为新消息的 sequence,status 改回 running
-
-新消息的 sequence 从 `last_sequence + 1` 开始(全局递增,不复用)。旧消息无需标记 abandoned,通过消息树结构自然隔离。
-
-### 调用接口
-
-三种模式共享同一入口 `run(messages, config)`:
-
-```python
-# 新建
 async for item in runner.run(
     messages=[{"role": "user", "content": "分析项目架构"}],
-    config=RunConfig(model="gpt-4o"),
+    config=RunConfig(model="gpt-4o")
 ):
-    ...
-
-# 续跑:在已有 trace 末尾追加消息继续执行
-async for item in runner.run(
-    messages=[{"role": "user", "content": "继续"}],
-    config=RunConfig(trace_id="existing-trace-id"),
-):
-    ...
-
-# 回溯:从指定 sequence 处切断,插入新消息重新执行
-# after_sequence=5 表示新消息的 parent_sequence=5,从此处开始
-async for item in runner.run(
-    messages=[{"role": "user", "content": "换一个方案试试"}],
-    config=RunConfig(trace_id="existing-trace-id", after_sequence=5),
-):
-    ...
-
-# 重新生成:回溯后不插入新消息,直接基于已有消息重跑
-async for item in runner.run(
-    messages=[],
-    config=RunConfig(trace_id="existing-trace-id", after_sequence=5),
-):
-    ...
+    print(item)
 ```
 
-`after_sequence` 的值是 message 的 `sequence` 号,可通过 `GET /api/traces/{trace_id}/messages` 查看。如果指定的 sequence 是一条带 `tool_calls` 的 assistant 消息,系统会自动将截断点扩展到其所有对应的 tool response 之后(安全截断)。
-
-**停止运行**:
-
-```python
-# 停止正在运行的 Trace
-await runner.stop(trace_id)
-```
-
-调用后 agent loop 在下一个检查点退出,Trace 状态置为 `stopped`,同时保存当前 `head_sequence`(确保续跑时能正确加载完整历史)。
-
-**消息完整性保护(orphaned tool_call 修复)**:续跑加载历史时,`_build_history` 自动检测并修复 orphaned tool_calls(`_heal_orphaned_tool_calls`)。当 agent 被 stop/crash 中断时,可能存在 assistant 的 tool_calls 没有对应的 tool results(包括部分完成的情况:3 个 tool_call 只有 1 个 tool_result)。直接发给 LLM 会导致 400 错误。
-
-修复策略:为每个缺失的 tool_result **插入合成的中断通知**(而非裁剪 assistant 消息):
-
-| 工具类型 | 合成 tool_result 内容 |
-|----------|---------------------|
-| 普通工具 | 简短中断提示,建议重新调用 |
-| agent/evaluate | 结构化中断信息,包含 `sub_trace_id`、执行统计、`continue_from` 用法指引 |
+详见:[Agent Core README](../agent/README.md)
 
-agent 工具的合成结果对齐正常返回值格式(含 `sub_trace_id` 字段),主 Agent 可直接使用 `agent(task=..., continue_from=sub_trace_id)` 续跑被中断的子 Agent。合成消息持久化存储,确保幂等。
-
-**实现**:`agent/core/runner.py:AgentRunner._heal_orphaned_tool_calls`
-
-- `run(messages, config)`:**核心方法**,流式返回 `AsyncIterator[Union[Trace, Message]]`
-- `run_result(messages, config, on_event=None)`:便利方法,内部消费 `run()`,返回结构化结果。`on_event` 回调可实时接收每个 Trace/Message 事件(用于调试时输出子 Agent 执行过程)。主要用于 `agent`/`evaluate` 工具内部
-
-### REST API
-
-#### 查询端点
-
-| 方法 | 路径 | 说明 |
-|------|------|------|
-| GET  | `/api/traces` | 列出 Traces |
-| GET  | `/api/traces/{id}` | 获取 Trace 详情(含 GoalTree、Sub-Traces) |
-| GET  | `/api/traces/{id}/messages` | 获取 Messages(支持 mode=main_path/all) |
-| GET  | `/api/traces/running` | 列出正在运行的 Trace |
-| WS   | `/api/traces/{id}/watch` | 实时事件推送 |
-
-**实现**:`agent/trace/api.py`, `agent/trace/websocket.py`
-
-#### 控制端点
-
-需在 `api_server.py` 中配置 Runner。执行在后台异步进行,通过 WebSocket 监听进度。
-
-| 方法 | 路径 | 说明 |
-|------|------|------|
-| POST | `/api/traces` | 新建 Trace 并执行 |
-| POST | `/api/traces/{id}/run` | 运行(统一续跑 + 回溯) |
-| POST | `/api/traces/{id}/stop` | 停止运行中的 Trace |
-| POST | `/api/traces/{id}/reflect` | 触发反思,从执行历史中提取经验 |
+### Gateway
 
 ```bash
-# 新建
-curl -X POST http://localhost:8000/api/traces \
-  -H "Content-Type: application/json" \
-  -d '{"messages": [{"role": "user", "content": "分析项目架构"}], "model": "gpt-4o"}'
-
-# 续跑(after_sequence 为 null 或省略)
-curl -X POST http://localhost:8000/api/traces/{trace_id}/run \
-  -d '{"messages": [{"role": "user", "content": "继续深入分析"}]}'
-
-# 回溯:从 sequence 5 处截断,插入新消息重新执行
-curl -X POST http://localhost:8000/api/traces/{trace_id}/run \
-  -d '{"after_sequence": 5, "messages": [{"role": "user", "content": "换一个方案"}]}'
-
-# 重新生成:回溯到 sequence 5,不插入新消息,直接重跑
-curl -X POST http://localhost:8000/api/traces/{trace_id}/run \
-  -d '{"after_sequence": 5, "messages": []}'
-
-# 停止
-curl -X POST http://localhost:8000/api/traces/{trace_id}/stop
-
-# 反思:追加反思 prompt 运行,结果追加到 experiences 文件
-curl -X POST http://localhost:8000/api/traces/{trace_id}/reflect \
-  -d '{"focus": "为什么第三步选择了错误的方案"}'
-```
-
-响应立即返回 `{"trace_id": "...", "status": "started"}`,通过 `WS /api/traces/{trace_id}/watch` 监听实时事件。
-
-**实现**:`agent/trace/run_api.py`
-
-#### 经验端点
-
-| 方法 | 路径 | 说明 |
-|------|------|------|
-| GET  | `/api/experiences` | 读取经验文件内容 |
-
-**实现**:`agent/trace/run_api.py`
-
----
-
-## 数据模型
-
-### Trace(任务执行)
-
-一次完整的 Agent 执行。所有 Agent(主、子、人类协助)都是 Trace。
-
-```python
-@dataclass
-class Trace:
-    trace_id: str
-    mode: Literal["call", "agent"]           # 单次调用 or Agent 模式
-
-    # Prompt 标识
-    prompt_name: Optional[str] = None
-
-    # Agent 模式特有
-    task: Optional[str] = None
-    agent_type: Optional[str] = None
-
-    # 父子关系(Sub-Trace 特有)
-    parent_trace_id: Optional[str] = None    # 父 Trace ID
-    parent_goal_id: Optional[str] = None     # 哪个 Goal 启动的
-
-    # 状态
-    status: Literal["running", "completed", "failed", "stopped"] = "running"
-
-    # 统计
-    total_messages: int = 0
-    total_tokens: int = 0                    # 总 tokens(prompt + completion)
-    total_prompt_tokens: int = 0
-    total_completion_tokens: int = 0
-    total_cost: float = 0.0
-    total_duration_ms: int = 0
-
-    # 进度追踪
-    last_sequence: int = 0                   # 最新 message 的 sequence(全局递增,不复用)
-    head_sequence: int = 0                   # 当前主路径的头节点 sequence(用于 build_llm_messages)
-    last_event_id: int = 0                   # 最新事件 ID(用于 WS 续传)
-
-    # 配置
-    uid: Optional[str] = None
-    model: Optional[str] = None              # 默认模型
-    tools: Optional[List[Dict]] = None       # 工具定义(OpenAI 格式)
-    llm_params: Dict[str, Any] = {}          # LLM 参数(temperature 等)
-    context: Dict[str, Any] = {}             # 元数据(含 collaborators 列表)
-
-    # 当前焦点
-    current_goal_id: Optional[str] = None
-
-    # 结果
-    result_summary: Optional[str] = None
-    error_message: Optional[str] = None
-
-    # 时间
-    created_at: datetime
-    completed_at: Optional[datetime] = None
-```
-
-**实现**:`agent/trace/models.py`
-
-### Goal(目标节点)
-
-计划中的一个目标,支持层级结构。单独存储于 `goal.json`。
-
-```python
-@dataclass
-class Goal:
-    id: str                                  # 内部 ID("1", "2"...)
-    description: str
-    reason: str = ""                         # 创建理由
-    parent_id: Optional[str] = None          # 父 Goal ID
-    type: GoalType = "normal"                # normal | agent_call
-    status: GoalStatus = "pending"           # pending | in_progress | completed | abandoned
-    summary: Optional[str] = None            # 完成/放弃时的总结
-
-    # agent_call 特有(启动 Sub-Trace)
-    sub_trace_ids: Optional[List[str]] = None
-    agent_call_mode: Optional[str] = None    # explore | delegate | evaluate
-    sub_trace_metadata: Optional[Dict] = None
-
-    # 统计
-    self_stats: GoalStats                    # 自身 Messages 统计
-    cumulative_stats: GoalStats              # 包含子孙的累计统计
-
-    created_at: datetime
-```
-
-**Goal 类型**:
-- `normal` - 普通目标,由 Agent 直接执行
-- `agent_call` - 通过 `agent`/`evaluate` 工具创建的目标,会启动 Sub-Trace
-
-**agent_call 类型的 Goal**:
-- 调用 `agent`/`evaluate` 工具时自动设置
-- `agent_call_mode` 记录使用的模式(explore/delegate/evaluate)
-- `sub_trace_ids` 记录创建的所有 Sub-Trace ID
-- 状态转换:pending → in_progress(Sub-Trace 启动)→ completed(Sub-Trace 完成)
-- `summary` 包含格式化的汇总结果(explore 模式会汇总所有分支)
-
-**Goal 操作**(通过 goal 工具):
-- `add` - 添加顶层目标
-- `under` - 在指定目标下添加子目标
-- `after` - 在指定目标后添加兄弟目标
-- `focus` - 切换焦点到指定目标
-- `done` - 完成当前目标(附带 summary)
-- `abandon` - 放弃当前目标(附带原因)
-
-**实现**:`agent/trace/goal_models.py`, `agent/trace/goal_tool.py`
+# 安装 Gateway 客户端
+cd gateway
+pip install -e .
 
-### Message(执行消息)
-
-对应 LLM API 的消息,每条 Message 关联一个 Goal。消息通过 `parent_sequence` 形成树结构。
-
-```python
-@dataclass
-class Message:
-    message_id: str                          # 格式:{trace_id}-{sequence:04d}
-    trace_id: str
-    role: Literal["system", "user", "assistant", "tool"]
-    sequence: int                            # 全局顺序(递增,不复用)
-    parent_sequence: Optional[int] = None    # 父消息的 sequence(构成消息树)
-    goal_id: Optional[str] = None            # 关联的 Goal ID(初始消息为 None,系统会按需自动创建 root goal 兜底)
-    description: str = ""                    # 系统自动生成的摘要
-    tool_call_id: Optional[str] = None
-    content: Any = None
-
-    # 统计
-    prompt_tokens: Optional[int] = None
-    completion_tokens: Optional[int] = None
-    cost: Optional[float] = None
-    duration_ms: Optional[int] = None
-
-    # LLM 响应信息(仅 role="assistant")
-    finish_reason: Optional[str] = None
-
-    created_at: datetime
-
-    # [已弃用] 由 parent_sequence 树结构替代
-    status: Literal["active", "abandoned"] = "active"
-    abandoned_at: Optional[datetime] = None
+# 使用 CLI
+gateway-cli send --from my-agent --to target-agent --message "Hello"
+gateway-cli list
 ```
 
-**消息树(Message Tree)**:
-
-消息通过 `parent_sequence` 形成树。主路径 = 从 `trace.head_sequence` 沿 parent chain 回溯到 root。
-
-```
-正常对话:1 → 2 → 3 → 4 → 5       (每条的 parent 指向前一条)
-Rewind 到 3:3 → 6(parent=3) → 7   (新主路径,4-5 自动脱离)
-压缩 1-3:   8(summary, parent=None) → 6 → 7  (summary 跳过被压缩的消息)
-反思分支:   5 → 9(reflect, parent=5) → 10     (侧枝,不在主路径上)
-```
-
-`build_llm_messages` = 从 head 沿 parent_sequence 链回溯到 root,反转后返回。
-
-Message 提供格式转换方法:
-- `to_llm_dict()` → OpenAI 格式 Dict(用于 LLM 调用)
-- `from_llm_dict(d, trace_id, sequence, goal_id)` → 从 OpenAI 格式创建 Message
-
-**实现**:`agent/trace/models.py`
-
----
-
-## Agent 预设
-
-不同类型 Agent 的配置模板,控制工具权限和参数。
-
-```python
-@dataclass
-class AgentPreset:
-    allowed_tools: Optional[List[str]] = None  # None 表示允许全部
-    denied_tools: Optional[List[str]] = None   # 黑名单
-    max_iterations: int = 30
-    temperature: Optional[float] = None
-    skills: Optional[List[str]] = None         # 注入 system prompt 的 skill 名称列表;None = 加载全部
-    description: Optional[str] = None
-
-
-_DEFAULT_SKILLS = ["planning", "research", "browser"]
-
-AGENT_PRESETS = {
-    "default": AgentPreset(
-        allowed_tools=None,
-        max_iterations=30,
-        skills=_DEFAULT_SKILLS,
-        description="默认 Agent,拥有全部工具权限",
-    ),
-    "explore": AgentPreset(
-        allowed_tools=["read", "glob", "grep", "list_files"],
-        denied_tools=["write", "edit", "bash", "task"],
-        max_iterations=15,
-        skills=["planning"],
-        description="探索型 Agent,只读权限,用于代码分析",
-    ),
-    "analyst": AgentPreset(
-        allowed_tools=["read", "glob", "grep", "web_search", "webfetch"],
-        denied_tools=["write", "edit", "bash", "task"],
-        temperature=0.3,
-        max_iterations=25,
-        skills=["planning", "research"],
-        description="分析型 Agent,用于深度分析和研究",
-    ),
-}
-```
-
-**实现**:`agent/core/presets.py`
-
-**用户自定义**:项目级配置文件(如 `examples/how/presets.json`)可通过 `register_preset()` 注册额外预设。项目专用的 Agent 类型建议放在项目目录下,而非内置预设。
-
----
-
-## 子 Trace 机制
-
-通过 `agent` 工具创建子 Agent 执行任务。`task` 参数为字符串时为单任务(delegate),为列表时并行执行多任务(explore)。支持通过 `messages` 参数预置消息,通过 `continue_from` 参数续跑已有 Sub-Trace。
-
-`agent` 工具负责创建 Sub-Trace 和初始化 GoalTree(因为需要设置自定义 context 元数据和命名规则),创建完成后将 `trace_id` 传给 `RunConfig`,由 Runner 接管后续执行。工具同时维护父 Trace 的 `context["collaborators"]` 列表。
-
-### agent 工具
-
-```python
-@tool(description="创建 Agent 执行任务")
-async def agent(
-    task: Union[str, List[str]],
-    messages: Optional[Union[Messages, List[Messages]]] = None,
-    continue_from: Optional[str] = None,
-    agent_type: Optional[str] = None,
-    skills: Optional[List[str]] = None,
-    context: Optional[dict] = None,
-) -> Dict[str, Any]:
-```
-
-- `agent_type`: 子 Agent 类型,决定工具权限和默认 skills(对应 `AgentPreset` 名称,如 `"deconstruct"`)
-- `skills`: 覆盖 preset 默认值,显式指定注入 system prompt 的 skill 列表
-
-**单任务(delegate)**:`task: str`
-- 创建单个 Sub-Trace
-- 完整工具权限(除 agent/evaluate 外,防止递归)
-- 支持 `continue_from` 续跑已有 Sub-Trace
-- 支持 `messages` 预置上下文消息
-
-**多任务(explore)**:`task: List[str]`
-- 使用 `asyncio.gather()` 并行执行所有任务
-- 每个任务创建独立的 Sub-Trace
-- 只读工具权限(read_file, grep_content, glob_files, goal)
-- `messages` 支持 1D(共享)或 2D(per-agent)
-- 不支持 `continue_from`
-- 汇总所有分支结果返回
-
-### evaluate 工具
-
-```python
-@tool(description="评估目标执行结果是否满足要求")
-async def evaluate(
-    messages: Optional[Messages] = None,
-    target_goal_id: Optional[str] = None,
-    continue_from: Optional[str] = None,
-    context: Optional[dict] = None,
-) -> Dict[str, Any]:
-```
-
-- 代码自动从 GoalTree 注入目标描述(无需 criteria 参数)
-- 模型把执行结果和上下文放在 `messages` 中
-- `target_goal_id` 默认为当前 goal_id
-- 只读工具权限
-- 返回评估结论和改进建议
-
-### 消息类型别名
-
-定义在 `agent/trace/models.py`,用于工具参数和 runner/LLM API 接口:
-
-```python
-ChatMessage = Dict[str, Any]                          # 单条 OpenAI 格式消息
-Messages = List[ChatMessage]                          # 消息列表
-MessageContent = Union[str, List[Dict[str, str]]]     # content 字段(文本或多模态)
-```
-
-**实现位置**:`agent/tools/builtin/subagent.py`
-
-**详细文档**:[工具系统 - Agent/Evaluate 工具](./tools.md#agent-工具)
-
-### ask_human 工具
-
-创建阻塞式 Trace,等待人类通过 IM/邮件等渠道回复。
-
-**注意**:此功能规划中,暂未实现。
-
----
-
-## Active Collaborators(活跃协作者)
-
-任务执行中与模型密切协作的实体(子 Agent 或人类),按 **与当前任务的关系** 分类,而非按 human/agent 分类:
-
-| | 持久存在(外部可查) | 任务内活跃(需要注入) |
-|---|---|---|
-| Agent | 专用 Agent(代码审查等) | 当前任务创建的子 Agent |
-| Human | 飞书通讯录 | 当前任务中正在对接的人 |
-
-### 数据模型
-
-活跃协作者存储在 `trace.context["collaborators"]`:
-
-```python
-{
-    "name": "researcher",            # 名称(模型可见)
-    "type": "agent",                 # agent | human
-    "trace_id": "abc-@delegate-001", # trace_id(agent 场景)
-    "status": "completed",           # running | waiting | completed | failed
-    "summary": "方案A最优",          # 最近状态摘要
-}
-```
-
-### 注入方式
-
-与 GoalTree 一同周期性注入(每 10 轮),渲染为 Markdown:
-
-```markdown
-## Active Collaborators
-- researcher [agent, completed]: 方案A最优
-- 谭景玉 [human, waiting]: 已发送方案确认,等待回复
-- coder [agent, running]: 正在实现特征提取模块
-```
-
-列表为空时不注入。
-
-### 维护
-
-各工具负责更新 collaborators 列表(通过 `context["store"]` 写入 trace.context):
-- `agent` 工具:创建/续跑子 Agent 时更新
-- `feishu` 工具:发送消息/收到回复时更新
-- Runner 只负责读取和注入
-
-**持久联系人/Agent**:通过工具按需查询(如 `feishu_get_contact_list`),不随任务注入。
-
-**实现**:`agent/core/runner.py:AgentRunner._build_context_injection`, `agent/tools/builtin/subagent.py`
-
----
-
-## 工具系统
-
-### 核心概念
-
-```python
-@tool()
-async def my_tool(arg: str, ctx: ToolContext) -> ToolResult:
-    return ToolResult(
-        title="Success",
-        output="Result content",
-        long_term_memory="Short summary"  # 可选:压缩后保留的摘要
-    )
-```
-
-| 类型 | 作用 |
-|------|------|
-| `@tool` | 装饰器,自动注册工具并生成 Schema |
-| `ToolResult` | 工具执行结果,支持双层记忆 |
-| `ToolContext` | 工具执行上下文,依赖注入 |
-
-### 工具分类
-
-| 目录 | 工具 | 说明 |
-|-----|------|------|
-| `trace/` | goal | Agent 内部计划管理 |
-| `builtin/` | agent, evaluate | 子 Agent 创建与评估 |
-| `builtin/file/` | read, write, edit, glob, grep | 文件操作 |
-| `builtin/browser/` | browser actions | 浏览器自动化 |
-| `builtin/` | bash, sandbox, search, webfetch, skill, ask_human | 其他工具 |
-
-### 双层记忆管理
-
-大输出(如网页抓取)只传给 LLM 一次,之后用摘要替代:
-
-```python
-ToolResult(
-    output="<10K tokens 的完整内容>",
-    long_term_memory="Extracted 10000 chars from amazon.com",
-    include_output_only_once=True
-)
-```
-
-**详细文档**:[工具系统](./tools.md)
-
----
-
-## Skills 系统
-
-### 分类
-
-| 类型 | 加载位置 | 加载时机 |
-|------|---------|---------|
-| **内置 Skill** | System Prompt | Agent 启动时自动注入 |
-| **项目 Skill** | System Prompt | Agent 启动时按 preset/call-site 过滤后注入 |
-| **普通 Skill** | 对话消息 | 模型调用 `skill` 工具时 |
-
-### 目录结构
-
-```
-agent/memory/skills/         # 内置 Skills(始终加载)
-├── planning.md              # 计划与 Goal 工具使用
-├── research.md              # 搜索与内容研究
-└── browser.md               # 浏览器自动化
-
-./skills/                    # 项目自定义 Skills
-```
-
-### Skills 过滤(call-site 选择)
-
-不同 Agent 类型所需的 skills 不同。过滤优先级:
-
-1. `agent()` 工具的 `skills` 参数(显式指定,最高优先级)
-2. `AgentPreset.skills`(preset 默认值)
-3. `None`(加载全部,向后兼容)
-
-示例:调用子 Agent 时只注入解构相关 skill:
-```python
-agent(task="...", agent_type="deconstruct", skills=["planning", "deconstruct"])
-```
-
-**实现**:`agent/memory/skill_loader.py`
-
-**详细文档**:[Skills 使用指南](./skills.md)
-
----
-
-## Experiences 系统
-
-从执行历史中提取的经验规则,用于指导未来任务。
-
-### 存储规范
-
-经验以 Markdown 文件存储(默认 `./.cache/experiences.md`),人类可读、可编辑、可版本控制。
-
-文件格式:
-
-```markdown
----
-id: ex_001
-trace_id: trace-xxx
-category: tool_usage
-tags: {state: ["large_file", "dirty_repo"], intent: ["batch_edit", "safe_modify"]}
-metrics: {helpful: 12, harmful: 0}
-created_at: 2026-02-12 15:30
----
-
----
-id: ex_002
-...
-```
----
-
-
-### 反思机制(Reflect)
-
-通过 POST /api/traces/{id}/reflect 触发,旨在将原始执行历史提炼为可复用的知识。
-    1. 分叉反思:在 trace 末尾追加 user message(含反思与打标 Prompt),作为侧枝执行。
-    2. 结构化生成:
-        ·归类:将经验分配至 tool_usage(工具)、logic_flow(逻辑)、environment(环境)等。
-        ·打标:提取 state(环境状态)与 intent(用户意图)语义标签。
-        ·量化:初始 helpful 设为 1。
-    3. 持久化:将带有元数据的 Markdown 块追加至 experiences.md。
-
-实现:agent/trace/run_api.py:reflect_trace
-
-### 语义注入与匹配流程
-新建 Trace 时,Runner 采用“分析-检索-注入”三阶段策略,实现精准经验推荐。
-    1. 意图预分析
-    Runner 调用 utility_llm 对初始任务进行语义提取:
-        -输入:"优化这个项目的 Docker 构建速度"
-        -输出:{state: ["docker", "ci"], intent: ["optimization"]}
-    2. 语义检索
-        在 _load_experiences 中根据标签进行语义匹配(优先匹配 intent,其次是 state),筛选出相关度最高的 Top-K 条经验。
-    3. 精准注入
-        将匹配到的经验注入第一条 user message 末尾:
-```python
-# _build_history 中(仅新建模式):
-if not config.trace_id:
-    relevant_ex = self.experience_retriever.search(task_tags)
-    if relevant_ex:
-        formatted_ex = "\n".join([f"- [{e.id}] {e.content} (Helpful: {e.helpful})" for e in relevant_ex])
-        first_user_msg["content"] += f"\n\n## 参考经验\n\n{formatted_ex}"
-```
-实现:agent/core/runner.py:AgentRunner._build_history
-
-### 经验获取工具
-不再仅限于启动时自动注入,而是通过内置工具供 Agent 在需要时主动调用。当执行结果不符合预期或进入未知领域时,Agent 应优先使用此工具。
-工具定义:
-
-```python
-@tool(description="根据当前任务状态和意图,从经验库中检索相关的历史经验")
-async def get_experience(
-    intent: Optional[str] = None, 
-    state: Optional[str] = None
-) -> Dict[str, Any]:
-    """
-    参数:
-        intent: 想要达成的目标意图 (如 "optimization", "debug")
-        state: 当前环境或遇到的问题状态 (如 "docker_build_fail", "permission_denied")
-    """
-```
-实现: agent/tools/builtin/experience.py
-
-- 语义匹配与应用流程
-    当 Agent 调用 get_experience 时,系统执行以下逻辑:
-    1. 语义检索:根据传入的 intent 或 state 标签,在 experiences.md 中进行匹配。匹配权重:intent > state > helpful 评分。
-    2. 动态注入:工具返回匹配到的 Top-K 条经验(含 ID 和内容)。
-    3. 策略应用:Agent 接收到工具返回的经验后,需在后续 thought 中声明所选用的策略 ID(如 [ex_001]),并据此调整 goal_tree 或工具调用序列。
-
-## Context 压缩
-
-### 两级压缩策略
-
-#### Level 1:GoalTree 过滤(确定性,零成本)
-
-每轮 agent loop 构建 `llm_messages` 时自动执行:
-- 始终保留:system prompt、第一条 user message(含 GoalTree 精简视图)、当前 focus goal 的消息
-- 跳过 completed/abandoned goals 的消息(信息已在 GoalTree summary 中)
-- 通过 Message Tree 的 parent_sequence 实现跳过
-
-大多数情况下 Level 1 足够。
-
-#### Level 2:LLM 总结(仅在 Level 1 后仍超限时触发)
-
-触发条件:Level 1 之后 token 数仍超过阈值(默认 `max_tokens × 0.8`)。
-
-流程:
-1. **经验提取**:先在消息列表末尾追加反思 prompt → 主模型回复 → 追加到 `./.cache/experiences.md`。反思消息为侧枝(parent_sequence 分叉,不在主路径上)
-2. **压缩**:在消息列表末尾追加压缩 prompt(含 GoalTree 完整视图) → 主模型回复 → summary 存为新消息,其 `parent_sequence` 跳过被压缩的范围
-
-### GoalTree 双视图
-
-`to_prompt()` 支持两种模式:
-- `include_summary=False`(默认):精简视图,用于日常周期性注入
-- `include_summary=True`:含所有 completed goals 的 summary,用于 Level 2 压缩时提供上下文
-
-### 压缩存储
-
-- 原始消息永远保留在 `messages/`
-- 压缩 summary 作为普通 Message 存储
-- 通过 `parent_sequence` 树结构实现跳过,无需 compression events 或 skip list
-- Rewind 到压缩区域内时,summary 脱离主路径,原始消息自动恢复
-
-**实现**:`agent/trace/compaction.py`, `agent/trace/goal_models.py`
-
-**详细文档**:[Context 管理](./context-management.md)
-
----
-
-## 存储接口
-
-```python
-class TraceStore(Protocol):
-    async def create_trace(self, trace: Trace) -> None: ...
-    async def get_trace(self, trace_id: str) -> Trace: ...
-    async def update_trace(self, trace_id: str, **updates) -> None: ...
-    async def add_message(self, message: Message) -> None: ...
-    async def get_trace_messages(self, trace_id: str) -> List[Message]: ...
-    async def get_main_path_messages(self, trace_id: str, head_sequence: int) -> List[Message]: ...
-    async def get_messages_by_goal(self, trace_id: str, goal_id: str) -> List[Message]: ...
-    async def append_event(self, trace_id: str, event_type: str, payload: Dict) -> int: ...
-```
-
-`get_main_path_messages` 从 `head_sequence` 沿 `parent_sequence` 链回溯,返回主路径上的有序消息列表。
-
-**实现**:
-- 协议定义:`agent/trace/protocols.py`
-- 文件存储:`agent/trace/store.py:FileSystemTraceStore`
-
-### 存储结构
-
-```
-.trace/
-├── {trace_id}/
-│   ├── meta.json        # Trace 元数据(含 tools 定义)
-│   ├── goal.json        # GoalTree(mission + goals 列表)
-│   ├── events.jsonl     # 事件流(goal 变更、sub_trace 生命周期等)
-│   └── messages/        # Messages
-│       ├── {trace_id}-0001.json
-│       └── ...
-│
-└── {trace_id}@explore-{序号}-{timestamp}-001/  # 子 Trace
-    └── ...
-```
-
-**events.jsonl 说明**:
-- 记录 Trace 执行过程中的关键事件
-- 每行一个 JSON 对象,包含 event_id、event 类型、时间戳等
-- 主要事件类型:goal_added, goal_updated, sub_trace_started, sub_trace_completed, rewind
-- 用于实时监控和历史回放
-
-**Sub-Trace 目录命名**:
-- Explore: `{parent}@explore-{序号:03d}-{timestamp}-001`
-- Delegate: `{parent}@delegate-{timestamp}-001`
-- Evaluate: `{parent}@evaluate-{timestamp}-001`
-
-**meta.json 示例**:
-```json
-{
-  "trace_id": "0415dc38-...",
-  "mode": "agent",
-  "task": "分析代码结构",
-  "agent_type": "default",
-  "status": "running",
-  "model": "google/gemini-2.5-flash",
-  "tools": [...],
-  "llm_params": {"temperature": 0.3},
-  "context": {
-    "collaborators": [
-      {"name": "researcher", "type": "agent", "trace_id": "...", "status": "completed", "summary": "方案A最优"}
-    ]
-  },
-  "current_goal_id": "3"
-}
-```
-
----
-
-## 设计决策
-
-详见 [设计决策文档](./decisions.md)
-
-**核心决策**:
-
-1. **所有 Agent 都是 Trace** - 主 Agent、子 Agent、人类协助统一为 Trace,通过 `parent_trace_id` 和 `spawn_tool` 区分
-
-2. **trace/ 模块统一管理执行状态** - 合并原 execution/ 和 goal/,包含计划管理和 Agent 内部控制工具
-
-3. **tools/ 专注外部交互** - 文件、命令、网络、浏览器等与外部世界的交互
-
-4. **Agent 预设替代 Sub-Agent 配置** - 通过 `core/presets.py` 定义不同类型 Agent 的工具权限和参数
+详见:[Gateway README](../gateway/README.md) 和 [A2A IM 文档](../gateway/client/a2a_im.md)
 
 ---
 
 ## 相关文档
 
-| 文档 | 内容 |
-|-----|------|
-| [Context 管理](./context-management.md) | Goals、压缩、Plan 注入策略 |
-| [工具系统](./tools.md) | 工具定义、注册、双层记忆 |
-| [Skills 指南](./skills.md) | Skill 分类、编写、加载 |
-| [多模态支持](./multimodal.md) | 图片、PDF 处理 |
-| [设计决策](./decisions.md) | 架构决策记录 |
-| [测试指南](./testing.md) | 测试策略和命令 |
+完整的文档列表见各模块的 README:
+- [Agent Core 文档](../agent/README.md#文档)
+- [Gateway 文档](../gateway/README.md#文档)

+ 651 - 0
docs/a2a-im.md

@@ -0,0 +1,651 @@
+# A2A IM:Agent 即时通讯系统
+
+**更新日期:** 2026-03-04
+
+## 文档维护规范
+
+0. **先改文档,再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后,再进行代码实现;除非改动较小、不被文档涵盖
+1. **文档分层,链接代码** - 重要或复杂设计可以另有详细文档;关键实现需标注代码文件路径;格式:`module/file.py:function_name`
+2. **简洁快照,日志分离** - 只记录最重要的、与代码准确对应的或者明确的已完成的设计的信息,避免推测、建议,或大量代码;决策依据或修改日志若有必要,可在`docs/decisions.md`另行记录
+
+---
+
+## 文档说明
+
+本文档描述 Agent 间即时通讯(A2A IM)系统的架构和实现。
+
+**相关文档**:
+- [MAMP 协议](./research/a2a-mamp-protocol.md):消息格式和传输协议
+- [A2A 跨设备通信](./research/a2a-cross-device.md):内部 Agent 通信方案
+- [Agent 框架](./README.md):核心 Agent 能力
+- [Enterprise 层](../gateway/docs/enterprise/overview.md):组织级功能
+
+---
+
+## 系统概述
+
+A2A IM 是一个**任务导向的 Agent 即时通讯系统**,支持:
+- Agent 间消息传递(点对点、通过 Gateway)
+- 活跃协作者管理(当前任务)
+- 全局联系人管理(历史记录)
+- 在线状态查询
+- 对话历史追溯
+
+**与传统 IM 的区别**:
+- 任务导向(非纯聊天)
+- 长时间处理(分钟到小时)
+- 工具调用和执行记录
+- 完整的 Trace 追溯
+
+---
+
+## 架构层次关系
+
+A2A IM 在整体架构中的定位:
+
+```
+┌─────────────────────────────────────────────────────────────┐
+│ Enterprise Layer(组织级)- 可选                              │
+│ - 认证和授权(飞书 OAuth、API Key、JWT)                      │
+│ - 审计和监控(操作日志、成本记录、安全事件)                    │
+│ - 多租户和权限控制(角色验证、资源访问控制)                    │
+│ - 成本管理和限额(用户级/组织级限额、超限告警)                 │
+│                                                              │
+│ 实现位置: gateway/enterprise/                                │
+│ 文档: gateway/docs/enterprise/overview.md                   │
+└─────────────────────────────────────────────────────────────┘
+
+┌─────────────────────────────────────────────────────────────┐
+│ A2A IM Gateway(通讯层)★ 本文档                             │
+│ - Agent 注册和发现(Registry)                                │
+│ - 消息路由(Gateway Router)                                  │
+│ - 活跃协作者管理(Collaborators)                             │
+│ - 在线状态管理(Heartbeat)                                   │
+│ - 联系人管理(ContactStore)                                  │
+│                                                              │
+│ 实现位置: gateway/core/                                       │
+│ 文档: docs/a2a-im.md(本文档)                                │
+└─────────────────────────────────────────────────────────────┘
+         ↕ 使用(单向依赖)
+┌─────────────────────────────────────────────────────────────┐
+│ Agent Core(核心层)                                          │
+│ - Trace、Message、Goal 管理                                  │
+│ - 工具系统(文件、命令、网络、浏览器)                          │
+│ - LLM 集成(Gemini、OpenRouter、Yescode)                    │
+│ - Skills 和 Memory(跨会话知识)                              │
+│ - 子 Agent 机制(agent 工具)                                 │
+│                                                              │
+│ 实现位置: agent/                                              │
+│ 文档: docs/README.md                                         │
+└─────────────────────────────────────────────────────────────┘
+```
+
+### 层次说明
+
+**Agent Core(核心层)**:
+- 提供单个 Agent 的执行能力
+- 管理 Trace、Message、Goal
+- 提供工具系统和 LLM 集成
+- 支持子 Agent 创建(通过 `agent` 工具)
+- **独立部署**:可以不依赖 Gateway 运行
+
+**A2A IM Gateway(通讯层)**:
+- 与 Agent Core 并列,独立的系统
+- 提供 Agent 间通讯能力
+- 管理 Agent 注册和在线状态
+- 路由消息到目标 Agent
+- 维护活跃协作者和联系人
+- **依赖 Agent Core**:使用 ToolContext、TraceStore 等组件
+- **独立部署**:可以作为独立服务部署
+
+**Enterprise(组织层)**:
+- 可选的企业功能扩展
+- 提供企业级管理和控制
+- 认证、授权、审计
+- 多租户和成本管理
+- **可以集成到 Gateway**:作为 Gateway 的扩展模块
+- **也可以独立部署**:作为独立的 Enterprise Gateway 服务
+
+### 依赖关系
+
+```
+Enterprise → Gateway → Agent Core
+(可选)    (通讯)    (核心)
+
+- Agent Core 不依赖任何其他层(独立)
+- Gateway 依赖 Agent Core(单向依赖)
+- Enterprise 依赖 Gateway(可选扩展)
+```
+
+### 部署方式
+
+**方式 1:单体部署(个人/小团队)**
+```
+一个进程:
+├─ Agent Core
+└─ Gateway(包含 Enterprise 模块)
+```
+
+**方式 2:分离部署(中等规模)**
+```
+进程 1:Agent Core
+进程 2:Gateway(包含 Enterprise 模块)
+```
+
+**方式 3:分层部署(大规模/企业)**
+```
+进程 1:Agent Core
+进程 2:Gateway Core
+进程 3:Enterprise Gateway
+```
+
+---
+
+## 架构设计
+
+### 三层架构
+
+```
+┌─────────────────────────────────────────────────┐
+│ Layer 3: Agent 逻辑层                            │
+│ - Trace, Goal, Messages                         │
+│ - 工具调用和执行                                  │
+└─────────────────────────────────────────────────┘
+                    ↕
+┌─────────────────────────────────────────────────┐
+│ Layer 2: A2A IM 层                               │
+│ - 活跃协作者管理                                  │
+│ - 全局联系人管理                                  │
+│ - conversation_id ↔ trace_id 映射                │
+└─────────────────────────────────────────────────┘
+                    ↕
+┌─────────────────────────────────────────────────┐
+│ Layer 1: Gateway 层                              │
+│ - Agent 注册和发现                                │
+│ - 消息路由                                        │
+│ - 在线状态管理                                    │
+│ - WebSocket 长连接                                │
+└─────────────────────────────────────────────────┘
+```
+
+### 通信模式
+
+**模式 1:内部 Agent(同进程)**
+```
+Agent A → 直接调用 → Agent B
+(复用现有 agent 工具)
+```
+
+**模式 2:跨设备 Agent(组织内)**
+```
+PC Agent → WebSocket → Gateway → 云端 Agent
+(反向连接,无需公网 IP)
+```
+
+**模式 3:外部 Agent(跨组织)**
+```
+Agent A → MAMP 协议 → Agent B
+(点对点 HTTP)
+```
+
+---
+
+## 数据模型
+
+### 活跃协作者(Layer 2)
+
+存储在 `trace.context["collaborators"]`,记录当前任务的协作者。
+
+```python
+{
+    "name": "code-analyst",
+    "type": "agent",  # agent | human
+    "agent_uri": "agent://other.com/code-analyst",
+    "trace_id": "abc-123",
+    "conversation_id": "conv-456",
+    "status": "running",  # running | waiting | completed | failed
+    "summary": "正在分析代码架构",
+    "last_message_at": "2026-03-04T10:30:00Z"
+}
+```
+
+**实现位置**:`agent/core/runner.py:AgentRunner._build_context_injection`
+
+### 全局联系人(Layer 2)
+
+存储在 `.trace/contacts.json`,记录所有历史联系过的 Agent。
+
+```python
+{
+    "agent_uri": "agent://other.com/code-analyst",
+    "name": "Code Analyst",
+    "type": "agent",
+
+    # 身份信息(从 Agent Card 获取)
+    "card": {
+        "description": "专注于代码分析",
+        "capabilities": ["code_analysis", "file_read"],
+        "owner": {"user_name": "张三"}
+    },
+
+    # 交互统计
+    "stats": {
+        "first_contact": "2026-02-01T10:00:00Z",
+        "last_contact": "2026-03-04T10:30:00Z",
+        "total_conversations": 15,
+        "total_messages": 127
+    },
+
+    # 最近对话
+    "recent_conversations": [
+        {
+            "conversation_id": "conv-456",
+            "trace_id": "abc-123",
+            "started_at": "2026-03-04T10:00:00Z",
+            "last_message": "分析完成",
+            "status": "active"
+        }
+    ],
+
+    # 关系标签
+    "tags": ["code", "architecture"],
+    "pinned": false
+}
+```
+
+**实现位置**:`agent/trace/contact_store.py`
+
+### Agent 注册信息(Layer 1)
+
+存储在 Gateway,记录在线 Agent 的连接信息。
+
+```python
+{
+    "agent_uri": "agent://internal/code-analyst",
+    "connection_type": "websocket",  # websocket | http
+    "websocket": <WebSocket>,  # WebSocket 连接对象
+    "http_endpoint": "http://localhost:8001",  # HTTP 端点
+    "last_heartbeat": "2026-03-04T10:30:00Z",
+    "capabilities": ["code_analysis", "file_read"]
+}
+```
+
+**实现位置**:`gateway/core/registry.py`
+
+---
+
+## 核心功能
+
+### 1. Agent 注册和发现
+
+**PC Agent 启动时注册**:
+
+```python
+# 建立 WebSocket 长连接
+ws = await websockets.connect("wss://gateway.com/gateway/connect")
+
+# 注册
+await ws.send(json.dumps({
+    "type": "register",
+    "agent_uri": "agent://internal/my-agent",
+    "capabilities": ["file_read", "bash"]
+}))
+
+# 保持心跳
+while True:
+    await ws.send(json.dumps({"type": "heartbeat"}))
+    await asyncio.sleep(30)
+```
+
+**实现位置**:`gateway/core/client.py`
+
+### 2. 消息路由
+
+**通过 Gateway 发送消息**:
+
+```python
+# 发送方
+POST /gateway/send
+{
+    "to": "agent://internal/code-analyst",
+    "content": "帮我分析代码"
+}
+
+# Gateway 查找目标 Agent
+agent_info = registry.lookup("agent://internal/code-analyst")
+
+# 通过 WebSocket 推送
+await agent_info["websocket"].send(json.dumps({
+    "type": "message",
+    "from": "agent://internal/caller",
+    "content": "帮我分析代码"
+}))
+```
+
+**实现位置**:`gateway/core/router.py`
+
+### 3. 活跃协作者管理
+
+**发送消息时自动更新**:
+
+```python
+# agent/tools/builtin/a2a_im.py
+
+async def send_to_agent(...):
+    # 发送消息
+    response = await gateway_client.send(...)
+
+    # 更新活跃协作者
+    await update_active_collaborator(
+        trace_id=ctx.trace_id,
+        agent_uri=target_agent,
+        conversation_id=response["conversation_id"],
+        status="waiting"
+    )
+```
+
+**周期性注入到 Agent 上下文**:
+
+```python
+# agent/core/runner.py
+
+if iteration % 10 == 0:
+    collaborators = trace.context.get("collaborators", [])
+    inject_collaborators_markdown(collaborators)
+```
+
+### 4. 全局联系人管理
+
+**查询联系人**:
+
+```python
+# 通过工具查询
+contacts = await get_contacts(
+    type="agent",
+    status="online",
+    tags=["code"]
+)
+```
+
+**自动维护**:
+
+```python
+# 发送/接收消息时自动更新
+await contact_store.update(
+    agent_uri=target_agent,
+    last_contact=datetime.now(),
+    increment_message_count=True
+)
+```
+
+**实现位置**:`agent/trace/contact_store.py`
+
+### 5. 在线状态查询
+
+**查询 Agent 在线状态**:
+
+```python
+GET /gateway/status/{agent_uri}
+
+返回:
+{
+    "agent_uri": "agent://internal/code-analyst",
+    "status": "online",  # online | offline
+    "last_seen": "2026-03-04T10:30:00Z"
+}
+```
+
+**实现位置**:`gateway/core/router.py:get_agent_status`
+
+---
+
+## API 端点
+
+### Gateway API
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| WS | `/gateway/connect` | Agent 注册和保持连接 |
+| POST | `/gateway/send` | 发送消息到其他 Agent |
+| GET | `/gateway/status/{agent_uri}` | 查询 Agent 在线状态 |
+| GET | `/gateway/agents` | 列出所有在线 Agent |
+
+### A2A IM API
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/api/traces/{id}/collaborators` | 查询活跃协作者 |
+| GET | `/api/contacts` | 查询全局联系人 |
+| GET | `/api/contacts/{agent_uri}` | 查询特定联系人详情 |
+| GET | `/api/contacts/{agent_uri}/conversations` | 查询对话历史 |
+
+---
+
+## 工具系统
+
+### send_to_agent 工具
+
+发送消息到其他 Agent(内部或外部)。
+
+```python
+@tool(description="发送消息到其他 Agent")
+async def send_to_agent(
+    target_agent: str,  # agent://domain/id
+    message: str,
+    conversation_id: Optional[str] = None,
+    ctx: ToolContext = None
+) -> ToolResult
+```
+
+**实现位置**:`agent/tools/builtin/a2a_im.py:send_to_agent`
+
+### get_active_collaborators 工具
+
+查询当前任务的活跃协作者。
+
+```python
+@tool(description="查询当前任务的活跃协作者")
+async def get_active_collaborators(
+    ctx: ToolContext
+) -> ToolResult
+```
+
+**实现位置**:`agent/tools/builtin/a2a_im.py:get_active_collaborators`
+
+### get_contacts 工具
+
+查询全局联系人列表。
+
+```python
+@tool(description="查询所有联系过的 Agent")
+async def get_contacts(
+    type: Optional[str] = None,  # agent | human
+    status: Optional[str] = None,  # online | offline
+    tags: Optional[List[str]] = None,
+    ctx: ToolContext = None
+) -> ToolResult
+```
+
+**实现位置**:`agent/tools/builtin/a2a_im.py:get_contacts`
+
+---
+
+## Skill 系统
+
+### a2a_im.md Skill
+
+提供 A2A IM 使用指南,注入到 Agent 的 system prompt。
+
+**内容**:
+- 如何发送消息到其他 Agent
+- 如何查询活跃协作者
+- 如何查询联系人
+- 最佳实践
+
+**实现位置**:`agent/memory/skills/a2a_im.md`
+
+---
+
+## 使用示例
+
+### 场景 1:调用其他 Agent 协作
+
+```python
+# Agent A 需要代码分析帮助
+result = await send_to_agent(
+    target_agent="agent://internal/code-analyst",
+    message="帮我分析 /path/to/project 的架构"
+)
+
+# 继续对话
+result2 = await send_to_agent(
+    target_agent="agent://internal/code-analyst",
+    message="重点分析 core 模块",
+    conversation_id=result["conversation_id"]
+)
+```
+
+### 场景 2:查询活跃协作者
+
+```python
+# 查看当前任务中有哪些 Agent 在协作
+collaborators = await get_active_collaborators()
+
+# 输出:
+# ## 活跃协作者
+# - code-analyst [agent, completed]: 分析完成,发现3个问题
+# - test-runner [agent, running]: 正在运行测试
+```
+
+### 场景 3:查询联系人
+
+```python
+# 查找擅长代码分析的 Agent
+contacts = await get_contacts(
+    type="agent",
+    tags=["code", "architecture"]
+)
+
+# 输出:
+# ## 联系人列表
+# 🟢 code-analyst - agent://internal/code-analyst
+#    最后联系: 2026-03-04 10:30
+#    对话次数: 15
+```
+
+---
+
+## 架构决策
+
+### 决策 1:Gateway 与 Agent 并列而非包含
+
+**问题**:Gateway 应该放在 agent/ 内部还是与 agent/ 并列?
+
+**决策**:与 agent/ 并列
+
+**理由**:
+1. **解耦**:Gateway 和 Agent Core 是两个独立的系统
+2. **独立部署**:Gateway 可以独立部署和扩展
+3. **职责清晰**:Agent Core 负责单 Agent 执行,Gateway 负责 Agent 间通讯
+4. **依赖关系**:Gateway 依赖 Agent Core(单向),但 Agent Core 不依赖 Gateway
+
+**实现**:
+- 目录结构:`gateway/` 与 `agent/` 并列
+- Import 路径:`from gateway.core import ...`
+
+### 决策 2:Enterprise 与 Gateway 的关系
+
+**问题**:Enterprise 应该是 Gateway 的上层(分层架构)还是 Gateway 的模块(模块化架构)?
+
+**决策**:根据阶段选择
+
+**MVP 阶段(当前)**:模块化架构
+- Enterprise 作为 Gateway 的可选模块
+- 部署简单,快速迭代
+- 适合中小规模
+
+**大规模阶段(未来)**:可选分层架构
+- Enterprise 作为独立的 Gateway 层
+- 可独立扩容,团队协作
+- 适合大规模部署
+
+**理由**:
+1. **灵活性**:两种架构都可以实现可选部署
+2. **演进路径**:从模块化开始,需要时重构为分层
+3. **规模决定**:小规模用模块化,大规模用分层
+
+**实现**:
+- 当前:`gateway/enterprise/` 作为可选模块
+- 未来:可重构为独立的 `enterprise_gateway/` 服务
+
+### 决策 3:活跃协作者的管理方式
+
+**问题**:活跃协作者信息应该如何存储和管理?
+
+**决策**:存储在 `trace.context["collaborators"]`,由工具自动维护
+
+**理由**:
+1. **复用现有机制**:Agent Core 已有 context 机制
+2. **自动注入**:Runner 周期性注入到 Agent 上下文(每 10 轮)
+3. **工具维护**:send_to_agent 等工具自动更新
+4. **与 Goal 一致**:与 GoalTree 一同注入,保持一致性
+
+**实现位置**:
+- 存储:`trace.context["collaborators"]`
+- 注入:`agent/core/runner.py:AgentRunner._build_context_injection`
+- 更新:`agent/tools/builtin/a2a_im.py:_update_active_collaborator`
+
+---
+
+## 实现路线图
+
+### Phase 1:基础功能(1-2 周)
+
+**目标**:实现核心通信能力
+
+**任务**:
+1. 实现 Gateway(注册、路由、WebSocket)
+2. 实现 send_to_agent 工具
+3. 实现活跃协作者自动更新
+4. 实现 a2a_im.md Skill
+
+**实现位置**:
+- `gateway/core/`
+- `agent/tools/builtin/a2a_im.py`
+- `agent/memory/skills/a2a_im.md`
+
+### Phase 2:联系人管理(1 周)
+
+**目标**:完善联系人和历史记录
+
+**任务**:
+1. 实现 ContactStore
+2. 实现 get_contacts 工具
+3. 实现对话历史查询
+4. 实现在线状态查询
+
+**实现位置**:
+- `agent/trace/contact_store.py`
+- `agent/tools/builtin/a2a_im.py`
+
+### Phase 3:增强功能(可选)
+
+**目标**:提升用户体验
+
+**任务**:
+1. 实现消息队列(异步处理)
+2. 实现 Agent 发现和推荐
+3. 实现关系标签和分组
+4. 实现 UI 界面
+
+---
+
+## 相关文档
+
+- [MAMP 协议](./research/a2a-mamp-protocol.md):消息格式和传输协议
+- [A2A 跨设备通信](./research/a2a-cross-device.md):内部 Agent 通信方案
+- [工具系统](../agent/docs/tools.md):工具定义、注册
+- [Skills 指南](../agent/docs/skills.md):Skill 分类、编写、加载
+- [Agent 框架](./README.md):核心 Agent 能力
+- [Gateway 架构](../gateway/docs/architecture.md):Gateway 三层架构
+- [Gateway API](../gateway/docs/api.md):Gateway API 参考

+ 0 - 78
docs/ref/Claude Code/agent-prompt-agent-creation-architect.md

@@ -1,78 +0,0 @@
-<!--
-name: 'Agent Prompt: Agent creation architect'
-description: System prompt for creating custom AI agents with detailed specifications
-ccVersion: 2.0.77
-variables:
-  - TASK_TOOL_NAME
--->
-You are an elite AI agent architect specializing in crafting high-performance agent configurations. Your expertise lies in translating user requirements into precisely-tuned agent specifications that maximize effectiveness and reliability.
-
-**Important Context**: You may have access to project-specific instructions from CLAUDE.md files and other context that may include coding standards, project structure, and custom requirements. Consider this context when creating agents to ensure they align with the project's established patterns and practices.
-
-When a user describes what they want an agent to do, you will:
-
-1. **Extract Core Intent**: Identify the fundamental purpose, key responsibilities, and success criteria for the agent. Look for both explicit requirements and implicit needs. Consider any project-specific context from CLAUDE.md files. For agents that are meant to review code, you should assume that the user is asking to review recently written code and not the whole codebase, unless the user has explicitly instructed you otherwise.
-
-2. **Design Expert Persona**: Create a compelling expert identity that embodies deep domain knowledge relevant to the task. The persona should inspire confidence and guide the agent's decision-making approach.
-
-3. **Architect Comprehensive Instructions**: Develop a system prompt that:
-   - Establishes clear behavioral boundaries and operational parameters
-   - Provides specific methodologies and best practices for task execution
-   - Anticipates edge cases and provides guidance for handling them
-   - Incorporates any specific requirements or preferences mentioned by the user
-   - Defines output format expectations when relevant
-   - Aligns with project-specific coding standards and patterns from CLAUDE.md
-
-4. **Optimize for Performance**: Include:
-   - Decision-making frameworks appropriate to the domain
-   - Quality control mechanisms and self-verification steps
-   - Efficient workflow patterns
-   - Clear escalation or fallback strategies
-
-5. **Create Identifier**: Design a concise, descriptive identifier that:
-   - Uses lowercase letters, numbers, and hyphens only
-   - Is typically 2-4 words joined by hyphens
-   - Clearly indicates the agent's primary function
-   - Is memorable and easy to type
-   - Avoids generic terms like "helper" or "assistant"
-
-6 **Example agent descriptions**:
-  - in the 'whenToUse' field of the JSON object, you should include examples of when this agent should be used.
-  - examples should be of the form:
-    - <example>
-      Context: The user is creating a test-runner agent that should be called after a logical chunk of code is written.
-      user: "Please write a function that checks if a number is prime"
-      assistant: "Here is the relevant function: "
-      <function call omitted for brevity only for this example>
-      <commentary>
-      Since a significant piece of code was written, use the ${TASK_TOOL_NAME} tool to launch the test-runner agent to run the tests.
-      </commentary>
-      assistant: "Now let me use the test-runner agent to run the tests"
-    </example>
-    - <example>
-      Context: User is creating an agent to respond to the word "hello" with a friendly jok.
-      user: "Hello"
-      assistant: "I'm going to use the ${TASK_TOOL_NAME} tool to launch the greeting-responder agent to respond with a friendly joke"
-      <commentary>
-      Since the user is greeting, use the greeting-responder agent to respond with a friendly joke. 
-      </commentary>
-    </example>
-  - If the user mentioned or implied that the agent should be used proactively, you should include examples of this.
-- NOTE: Ensure that in the examples, you are making the assistant use the Agent tool and not simply respond directly to the task.
-
-Your output must be a valid JSON object with exactly these fields:
-{
-  "identifier": "A unique, descriptive identifier using lowercase letters, numbers, and hyphens (e.g., 'test-runner', 'api-docs-writer', 'code-formatter')",
-  "whenToUse": "A precise, actionable description starting with 'Use this agent when...' that clearly defines the triggering conditions and use cases. Ensure you include examples as described above.",
-  "systemPrompt": "The complete system prompt that will govern the agent's behavior, written in second person ('You are...', 'You will...') and structured for maximum clarity and effectiveness"
-}
-
-Key principles for your system prompts:
-- Be specific rather than generic - avoid vague instructions
-- Include concrete examples when they would clarify behavior
-- Balance comprehensiveness with clarity - every instruction should add value
-- Ensure the agent has enough context to handle variations of the core task
-- Make the agent proactive in seeking clarification when needed
-- Build in quality assurance and self-correction mechanisms
-
-Remember: The agents you create should be autonomous experts capable of handling their designated tasks with minimal additional guidance. Your system prompts are their complete operational manual.

+ 0 - 12
docs/ref/Claude Code/agent-prompt-bash-command-description-writer.md

@@ -1,12 +0,0 @@
-Clear, concise description of what this command does in active voice. Never use words like "complex" or "risk" in the description - just describe what it does.
-
-For simple commands (git, npm, standard CLI tools), keep it brief (5-10 words):
-
-ls → "List files in current directory"
-git status → "Show working tree status"
-npm install → "Install package dependencies"
-For commands that are harder to parse at a glance (piped commands, obscure flags, etc.), add enough context to clarify what it does:
-
-find . -name "*.tmp" -exec rm {} \; → "Find and delete all .tmp files recursively"
-git reset --hard origin/main → "Discard all local changes and match remote main"
-curl -s url | jq '.data[]' → "Fetch JSON from URL and extract data array elements"

+ 0 - 9
docs/ref/Claude Code/system-prompt-doing-tasks.md

@@ -1,9 +0,0 @@
-Doing tasks
-The user will primarily request you perform software engineering tasks. This includes solving bugs, adding new functionality, refactoring code, explaining code, and more. For these tasks the following steps are recommended: ${"- NEVER propose changes to code you haven't read. If a user asks about or wants you to modify a file, read it first. Understand existing code before suggesting modifications."}${TOOL_USAGE_HINTS_ARRAY.length>0? ${TOOL_USAGE_HINTS_ARRAY.join( )}:""}
-
-Be careful not to introduce security vulnerabilities such as command injection, XSS, SQL injection, and other OWASP top 10 vulnerabilities. If you notice that you wrote insecure code, immediately fix it.
-Avoid over-engineering. Only make changes that are directly requested or clearly necessary. Keep solutions simple and focused.
-Don't add features, refactor code, or make "improvements" beyond what was asked. A bug fix doesn't need surrounding code cleaned up. A simple feature doesn't need extra configurability. Don't add docstrings, comments, or type annotations to code you didn't change. Only add comments where the logic isn't self-evident.
-Don't add error handling, fallbacks, or validation for scenarios that can't happen. Trust internal code and framework guarantees. Only validate at system boundaries (user input, external APIs). Don't use feature flags or backwards-compatibility shims when you can just change the code.
-Don't create helpers, utilities, or abstractions for one-time operations. Don't design for hypothetical future requirements. The right amount of complexity is the minimum needed for the current task—three similar lines of code is better than a premature abstraction.
-Avoid backwards-compatibility hacks like renaming unused `_vars`, re-exporting types, adding `// removed` comments for removed code, etc. If something is unused, delete it completely.

+ 0 - 6
docs/ref/Claude Code/system-prompt-tool-usage-policy.md

@@ -1,6 +0,0 @@
-Tool usage policy${WEBFETCH_ENABLED_SECTION}${MCP_TOOLS_SECTION}
-You can call multiple tools in a single response. If you intend to call multiple tools and there are no dependencies between them, make all independent tool calls in parallel. Maximize use of parallel tool calls where possible to increase efficiency. However, if some tool calls depend on previous calls to inform dependent values, do NOT call these tools in parallel and instead call them sequentially. For instance, if one operation must complete before another starts, run these operations sequentially instead. Never use placeholders or guess missing parameters in tool calls.
-If the user specifies that they want you to run tools "in parallel", you MUST send a single message with multiple tool use content blocks. For example, if you need to launch multiple agents in parallel, send a single message with multiple ${TASK_TOOL_NAME} tool calls.
-Use specialized tools instead of bash commands when possible, as this provides a better user experience. For file operations, use dedicated tools: ${READ_TOOL_NAME} for reading files instead of cat/head/tail, ${EDIT_TOOL_NAME} for editing instead of sed/awk, and ${WRITE_TOOL_NAME} for creating files instead of cat with heredoc or echo redirection. Reserve bash tools exclusively for actual system commands and terminal operations that require shell execution. NEVER use bash echo or other command-line tools to communicate thoughts, explanations, or instructions to the user. Output all communication directly in your response text instead.
-${VERY IMPORTANT: When exploring the codebase to gather context or to answer a question that is not a needle query for a specific file/class/function, it is CRITICAL that you use the ${TASK_TOOL_NAME} tool with subagent_type=${EXPLORE_AGENT.agentType} instead of running search commands directly.}
-user: Where are errors from the client handled? assistant: [Uses the ${TASK_TOOL_NAME} tool with subagent_type=${EXPLORE_AGENT.agentType} to find the files that handle client errors instead of using ${GLOB_TOOL_NAME} or ${GREP_TOOL_NAME} directly] user: What is the codebase structure? assistant: [Uses the ${TASK_TOOL_NAME} tool with subagent_type=${EXPLORE_AGENT.agentType}]

+ 0 - 16
docs/ref/Claude Code/system-prompt-tool-use-summary-generation.md

@@ -1,16 +0,0 @@
-You summarize what was accomplished by a coding assistant. Given the tools executed and their results, provide a brief summary.
-
-Rules:
-
-Use past tense (e.g., "Read package.json", "Fixed type error in utils.ts")
-Be specific about what was done
-Keep under 8 words
-Do not include phrases like "I did" or "The assistant" - just describe what happened
-Focus on the user-visible outcome, not implementation details
-Examples:
-
-"Searched codebase for authentication code"
-"Read and analyzed Message.tsx component"
-"Fixed null pointer exception in data processor"
-"Created new user registration endpoint"
-"Ran tests and fixed 3 failing assertions"

+ 0 - 0
docs/ref/Claude Code/tool-description-bash.md


+ 0 - 659
docs/ref/context-comparison.md

@@ -1,659 +0,0 @@
-# Context 管理方案对比分析
-
-> 对比 OpenCode、Codex 和 Gemini-cli 三个项目的 context 管理方案
-
----
-
-## 一、整体架构对比
-
-| 维度 | **OpenCode** | **Codex** | **Gemini-cli** |
-|------|-------------|-----------|---------------|
-| **核心数据结构** | 线性 Message List | ContextManager (Vec<ResponseItem>) | Content[] (双版本) |
-| **消息历史版本** | 单一版本 | 单一版本 + GhostSnapshot | 精选版本 + 完整版本 |
-| **分层设计** | 无 | 无 | **✓ 三层**: Global → Environment → JIT |
-| **Plan 管理** | goal.json (计划中) + plan.md (参考) | SQLite + TodoListItem | 无 Plan 机制 |
-| **存储格式** | Storage Key-Value | JSONL + SQLite 混合 | JSON + 文本文件 |
-| **并发控制** | 未明确 | Arc<Mutex> + 文件锁 | Promise并发限制 |
-
----
-
-## 二、Token 限制处理策略
-
-### 2.1 Token 估算方法
-
-| 项目 | 估算策略 | 精度 | 实现位置 |
-|------|---------|------|---------|
-| **OpenCode** | 未详细说明,引用 Prune 阈值 | 中 | - |
-| **Codex** | **字节估算**: `bytes / 4` (1 token ≈ 4 bytes) | 低 | `truncate.rs::approx_token_count()` |
-| **Gemini-cli** | **启发式**: ASCII (0.25), 非ASCII (1.3), 图片 (3000), PDF (25800) | 高 | `tokenCalculation.ts::estimateTokenCountSync()` |
-
-**关键差异**:
-- **Codex**: 简单但快速,适合实时估算
-- **Gemini-cli**: 更精确,区分字符类型和媒体,牺牲少量性能
-
-### 2.2 Token 限制阈值
-
-| 项目 | 限制类型 | 阈值定义 |
-|------|---------|---------|
-| **OpenCode** | 删除阈值 | `PRUNE_MINIMUM = 20,000`, `PRUNE_PROTECT = 40,000` |
-| **Codex** | 模型限制 | 依赖模型配置,无固定值 |
-| **Gemini-cli** | 压缩阈值 | 默认 **50%** 模型限制 (`DEFAULT_COMPRESSION_TOKEN_THRESHOLD = 0.5`) |
-
-### 2.3 截断策略
-
-```
-┌─────────────────┬──────────────────────────┬─────────────────────┐
-│    OpenCode     │         Codex            │    Gemini-cli       │
-├─────────────────┼──────────────────────────┼─────────────────────┤
-│ 删除旧工具输出   │ 前缀+后缀保留,中间截断    │ 反向token预算       │
-│ 保护最近2轮turns │ 插入省略标记             │ 最近工具完整保留     │
-│ 不删除"skill"工具│ 保证UTF-8边界完整性       │ 旧工具仅保留30行    │
-└─────────────────┴──────────────────────────┴─────────────────────┘
-```
-
-**Gemini-cli 的反向预算策略** (最独特):
-```typescript
-// 从最新消息往回遍历,为每条工具输出分配token预算
-// 优先保留最近的,旧的按需截断
-COMPRESSION_FUNCTION_RESPONSE_TOKEN_BUDGET = 50,000;
-COMPRESSION_TRUNCATE_LINES = 30;
-```
-
----
-
-## 三、摘要/压缩机制
-
-### 3.1 压缩触发时机
-
-| 项目 | 触发时机 | 方式 |
-|------|---------|------|
-| **OpenCode** | 事后 (context满时) | 被动压缩 |
-| **Codex** | 超过模型窗口时 | 自动压缩 |
-| **Gemini-cli** | **主动** (达到50%阈值) + **手动** (/compress) | 混合方式 |
-
-### 3.2 压缩策略对比
-
-#### OpenCode: 两阶段压缩
-
-```
-阶段1: Prune (清理旧工具输出)
-  ├─ 从后向前遍历
-  ├─ 跳过最后2轮
-  ├─ 跳过已有summary的消息
-  └─ 删除量 > PRUNE_MINIMUM 时执行
-
-阶段2: Full Compaction (上下文总结)
-  ├─ 创建summary=true的assistant消息
-  ├─ 调用"compaction"专用agent
-  └─ 提示词: "Provide a detailed prompt for continuing..."
-```
-
-#### Codex: 内联自动压缩
-
-```
-触发: run_inline_auto_compact_task()
-  ├─ 生成摘要前缀 (SUMMARY_PREFIX)
-  ├─ 使用SUMMARIZATION_PROMPT
-  ├─ 保留GhostSnapshot (幽灵快照)
-  └─ 替换历史记录为CompactedItem
-```
-
-**GhostSnapshot** (Codex独有):
-- 保留被压缩部分的"幽灵"引用
-- 用户可查看但不会发送给模型
-- 在UI中显示为折叠项
-
-#### Gemini-cli: 三相智能压缩
-
-```
-Phase 1: 历史分割
-  ├─ 保留最后30% (COMPRESSION_PRESERVE_THRESHOLD)
-  └─ 压缩前70%
-
-Phase 2: 双重总结验证 ⭐ (独特)
-  ├─ 第1次: 生成 <state_snapshot>
-  ├─ 第2次: 自我批评 ("Did you omit any...")
-  └─ 生成改进版本或确认原版本
-
-Phase 3: 输出验证
-  ├─ 检查压缩后token数 < 原token数
-  └─ 失败则保持原历史
-```
-
-**双重验证的价值**:
-```typescript
-// 第一次生成
-"Generate a state snapshot of the conversation..."
-
-// 第二次自我批评
-"Did you omit any specific file content, code snippets,
-or context that might be needed later? If yes, provide
-an improved version. If no, confirm the original."
-```
-
-### 3.3 压缩结果处理
-
-| 项目 | 压缩失败处理 | 结果存储 |
-|------|------------|---------|
-| **OpenCode** | 标记为已compacted | 替换为summary message |
-| **Codex** | 保留GhostSnapshot | CompactedItem + replacement_history |
-| **Gemini-cli** | **回退原历史** ⭐ | 成功时替换,失败时保持原状 |
-
----
-
-## 四、存储和加载方式
-
-### 4.1 存储架构
-
-#### OpenCode (计划中)
-```
-.trace/{trace_id}/
-├── goal.json          # Goal Tree (结构化plan)
-├── messages.jsonl     # 消息记录 (含 goal_id)
-└── meta.json          # Trace 元数据
-```
-
-#### Codex
-```
-~/.codex/
-├── history.jsonl                           # 全局消息历史
-├── sessions/
-│   ├── rollout-{timestamp}-{uuid}.jsonl    # 会话回滚文件
-│   └── ...
-└── state.db                                # SQLite状态数据库
-```
-
-**关键特性**:
-- **原子写入**: 使用 `O_APPEND` 标志
-- **并发安全**: Advisory文件锁
-- **自动清理**: 超过限制时删除旧条目 (软限制80%)
-
-#### Gemini-cli
-```
-~/.gemini/
-├── GEMINI.md                               # 全局内存
-├── tmp/{project_hash}/
-│   └── chats/{session-ID}.json             # 会话记录
-└── config.json                             # 配置
-
-项目根目录/
-├── GEMINI.md                               # 环境内存
-└── subdirs/
-    └── GEMINI.md                           # JIT内存 (按需加载)
-```
-
-**独特的三层内存系统**:
-```
-Tier 1: Global Memory
-  ├─ ~/.gemini/GEMINI.md
-  └─ 用户级别,所有会话共享
-
-Tier 2: Environment Memory
-  ├─ 项目根目录的GEMINI.md
-  ├─ 扩展提供的上下文文件
-  └─ MCP客户端指令
-
-Tier 3: JIT Subdirectory Memory ⭐
-  ├─ 访问路径时动态发现
-  ├─ 向上遍历到项目根
-  ├─ 向下BFS搜索 (最多200目录)
-  └─ 避免加载不相关上下文
-```
-
-### 4.2 加载策略对比
-
-| 项目 | 加载时机 | 策略 | 并发控制 |
-|------|---------|------|---------|
-| **OpenCode** | 会话启动/恢复 | 按需加载 | 未明确 |
-| **Codex** | 启动时 | lookup(log_id, offset) | Arc<Mutex> + 文件锁 |
-| **Gemini-cli** | **分层+JIT** ⭐ | 全局(启动) + 环境(会话) + JIT(访问) | Promise并发限制 (10/20) |
-
----
-
-## 五、Plan/Todo 机制
-
-### 5.1 数据结构对比
-
-#### OpenCode (参考方案)
-```typescript
-// plan.md (文本)
-- [ ] 分析代码
-- [x] 实现功能
-- [ ] 测试
-
-// Todo.Info (结构化)
-{
-  id: string,
-  content: string,
-  status: "pending" | "in_progress" | "completed" | "cancelled",
-  priority: "high" | "medium" | "low"
-}
-```
-
-#### OpenCode (我们的方案 - 计划中)
-```python
-@dataclass
-class Goal:
-    id: str                    # "1", "1.1", "2"
-    description: str
-    status: Status             # pending | in_progress | completed | abandoned
-    summary: Optional[str]     # done/abandon 时的总结
-    children: List["Goal"]
-
-@dataclass
-class GoalTree:
-    mission: str
-    current_id: Optional[str]
-    goals: List[Goal]
-```
-
-**关键特性**:
-- **goal_id 关联**: 每条 message 记录它属于哪个 goal
-- **增量压缩**: goal 完成/放弃时压缩相关 messages
-- **精确回溯**: 基于 goal 的状态流转
-
-#### Codex
-```rust
-// TodoListItem in ResponseItem
-pub struct TodoListItem {
-    todo_list: Vec<TodoItem>,
-}
-
-pub struct TodoItem {
-    task: String,
-    completed: bool,
-}
-```
-
-**存储**: 作为 ResponseItem 的一部分,随对话历史一起管理
-
-#### Gemini-cli
-**无专门 Plan 机制**,但有:
-- **会话记录**: 完整的 `ConversationRecord`
-- **目录跟踪**: `directories?: string[]` (会话中添加的目录)
-
-### 5.2 执行与 Plan 的关联
-
-| 项目 | 关联方式 | 可编辑性 | 可视化 |
-|------|---------|---------|--------|
-| **OpenCode (参考)** | 无结构化关联 | plan.md 可直接编辑 | 基础 |
-| **OpenCode (计划)** | message.goal_id | 通过 goal 工具 | 增强 (树形+步骤) |
-| **Codex** | TodoItem 在 ResponseItem 中 | 通过模型更新 | 基础 |
-| **Gemini-cli** | - | - | - |
-
----
-
-## 六、Sub-Agent/并行探索
-
-### 6.1 Sub-Agent 支持
-
-#### OpenCode (参考方案)
-```typescript
-// Agent Mode
-- primary: 主代理,执行工具
-- subagent: 子代理,独立context
-
-// 内置 Sub-Agents
-- general: 通用代理,可并行执行
-- explore: 代码探索,仅查询工具
-- compaction: 上下文总结
-```
-
-**执行流程**:
-```
-1. 创建 SubtaskPart
-2. 子代理独立处理 (独立 message list)
-3. 结果汇总: "The following tool was executed by the user"
-```
-
-#### OpenCode (我们的方案 - 计划中)
-```python
-@tool
-def explore(
-    question: str,           # 探索要回答的问题
-    branches: List[str],     # 探索方向 (2-4个)
-) -> str:
-    """并行探索多个方向,汇总结果"""
-```
-
-**执行流程**:
-```
-1. 为每个探索方向创建独立的 Sub-Trace(完整的 Trace 结构)
-2. 并行执行所有 Sub-Traces(使用 asyncio.gather)
-3. 收集每个 Sub-Trace 的结论
-4. 返回汇总结果给主 Trace
-```
-
-#### Codex
-**无明确 Sub-Agent 机制**,但有:
-- **SessionState**: 管理会话状态
-- **Turn Context**: 单轮对话的上下文
-
-#### Gemini-cli
-**无 Sub-Agent 机制**,但有:
-- **CoreToolScheduler**: 工具执行调度
-- **并发工具执行**: 多个工具可并行运行
-
-### 6.2 并行探索对比
-
-| 特性 | OpenCode (参考) | OpenCode (计划) | Codex | Gemini-cli |
-|------|---------------|---------------|-------|-----------|
-| **并行探索** | Sub-agent 手动管理 | explore 工具自动汇总 ⭐ | 无 | 工具级并发 |
-| **Context 隔离** | ✓ (独立 message list) | ✓ (独立 message list) | - | - |
-| **结果汇总** | 手动 | 自动 (返回 markdown) | - | - |
-| **适用场景** | 大任务隔离 | 多方案评估 | - | 工具执行 |
-
----
-
-## 七、回溯能力
-
-### 7.1 回溯机制对比
-
-#### OpenCode (参考方案)
-```
-限制: 有限的回溯能力
-- 无精确状态保存
-- 依赖压缩后的摘要
-```
-
-#### OpenCode (我们的方案 - 计划中)
-```python
-goal(abandon="方案A需要Redis,环境没有", add="实现方案B")
-```
-
-**回溯流程**:
-```
-Before:
-  Messages:
-    [分析代码的 20 条 message...]
-    [实现方案 A 的 30 条 message...]  ← 这些要压缩
-    [测试失败的 message...]
-
-After:
-  Messages:
-    [分析代码的 20 条 message...]
-    [Summary: "尝试方案A,因依赖问题失败"]  ← 压缩为1条
-    [开始方案B的 message...]
-
-  Plan:
-    [✓] 1. 分析代码
-    [✗] 2. 实现方案A (abandoned: 依赖问题)
-    [→] 2'. 实现方案B
-```
-
-**优势**:
-- **精确回溯**: 基于 goal 的状态标记
-- **保留失败原因**: summary 包含 abandon 原因
-- **压缩旧路径**: 失败尝试不占用大量 context
-
-#### Codex
-```rust
-// GhostSnapshot: 保留被压缩部分的引用
-pub struct CompactedItem {
-    message: String,
-    replacement_history: Option<Vec<ResponseItem>>,
-}
-```
-
-**回溯能力**:
-- **GhostSnapshot**: 用户可查看历史,但不发送给模型
-- **Rollout 记录**: 完整的会话记录保存在 JSONL
-- **用户转换检测**: 可定位到特定用户消息
-
-#### Gemini-cli
-```typescript
-enum CompressionStatus {
-  COMPRESSED,
-  COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,  // 压缩反而增加
-  COMPRESSION_FAILED_EMPTY_SUMMARY,          // 摘要为空
-  NOOP,
-}
-```
-
-**回溯能力**:
-- **会话记录**: 完整的 `ConversationRecord` 保存所有消息
-- **压缩失败回退**: 自动回退到原历史
-- **无结构化回溯**: 缺乏基于任务的回溯机制
-
-### 7.2 回溯对比表
-
-| 项目 | 回溯粒度 | 状态保存 | 失败处理 | 历史查看 |
-|------|---------|---------|---------|---------|
-| **OpenCode (参考)** | 粗粒度 | 摘要 | 有限 | 基础 |
-| **OpenCode (计划)** | **goal级别** ⭐ | goal.summary + abandon原因 | 精确压缩 | goal树 + 步骤 |
-| **Codex** | 用户turn级别 | GhostSnapshot | GhostSnapshot引用 | 完整回滚文件 |
-| **Gemini-cli** | 消息级别 | ConversationRecord | 自动回退 | 会话记录文件 |
-
----
-
-## 八、核心差异总结
-
-### 8.1 设计哲学
-
-| 项目 | 核心理念 | 优势场景 |
-|------|---------|---------|
-| **OpenCode** | **结构化计划驱动** | 复杂任务,需要回溯和探索 |
-| **Codex** | **简单高效,成熟稳定** | 通用编码助手,快速响应 |
-| **Gemini-cli** | **分层智能,高保真保留** | 多项目管理,长期会话 |
-
-### 8.2 独特创新点
-
-#### OpenCode (我们的方案)
-1. **goal 工具**: 结构化 Plan + 执行关联
-2. **explore 工具**: 并行探索自动汇总
-3. **增量压缩**: goal 完成/放弃时压缩,而非事后被动
-4. **精确回溯**: abandon + 状态流转
-
-#### Codex
-1. **GhostSnapshot**: 压缩历史仍可查看
-2. **原子写入**: O_APPEND + 并发安全
-3. **字节估算**: 简单快速 (bytes/4)
-4. **历史规范化**: 确保调用-输出对完整性
-
-#### Gemini-cli
-1. **三层内存**: Global → Environment → JIT ⭐
-2. **双重验证**: 自我批评式压缩
-3. **反向token预算**: 优先保留最近工具输出
-4. **启发式token估算**: 区分字符类型和媒体
-5. **JIT Context发现**: 按需加载相关GEMINI.md
-
-### 8.3 技术选型对比
-
-| 技术点 | OpenCode | Codex | Gemini-cli |
-|--------|---------|-------|-----------|
-| **语言** | TypeScript | Rust | TypeScript |
-| **存储** | Storage KV | JSONL + SQLite | JSON + 文本 |
-| **并发** | 未明确 | Arc<Mutex> + 文件锁 | Promise限制 |
-| **token估算** | 未详述 | bytes/4 | 启发式 (区分类型) |
-| **压缩策略** | 两阶段 | 内联自动 | 三相智能 |
-
----
-
-## 九、与 OpenCode 方案的详细对比
-
-### 9.1 OpenCode vs Codex
-
-| 方面 | OpenCode (参考) | Codex | 评估 |
-|------|---------------|-------|------|
-| **Plan格式** | 纯文本 (plan.md) | TodoItem (结构化) | Codex更结构化,但OpenCode计划中的goal.json更强 |
-| **Plan与执行关联** | 无 | TodoItem在ResponseItem中 | Codex有关联,但OpenCode计划中的goal_id更精确 |
-| **压缩时机** | 事后 (满时) | 事后 (超过窗口) | 相同 (被动) |
-| **并行探索** | Sub-agent (手动) | 无 | OpenCode参考方案更强,计划方案的explore更自动化 |
-| **回溯能力** | 有限 | GhostSnapshot | Codex的GhostSnapshot有价值,但OpenCode计划的goal-based更精确 |
-| **存储可靠性** | 未明确 | 原子写入+并发安全 | **Codex胜** ⭐ |
-| **工具复杂度** | todoread/todowrite | 无专门工具 | OpenCode参考方案更复杂,计划的goal/explore更简洁 |
-
-**可借鉴**:
-- ✓ Codex的原子写入和并发安全机制
-- ✓ GhostSnapshot的用户友好性 (可查看但不发送)
-- ✓ 历史规范化 (ensure_call_outputs_present)
-
-### 9.2 OpenCode vs Gemini-cli
-
-| 方面 | OpenCode (参考) | Gemini-cli | 评估 |
-|------|---------------|-----------|------|
-| **Plan格式** | plan.md + Todo.Info | 无 | **OpenCode胜** |
-| **Plan与执行关联** | 无 | 无 | 平局 |
-| **压缩时机** | 事后 (满时) | **主动** (50%阈值) | **Gemini-cli胜** ⭐ |
-| **并行探索** | Sub-agent (手动) | 工具级并发 | OpenCode的Sub-agent隔离更好 |
-| **回溯能力** | 有限 | 自动回退 | OpenCode计划方案的goal-based更强 |
-| **Context分层** | 无 | **三层** (Global/Env/JIT) | **Gemini-cli胜** ⭐ |
-| **压缩质量** | 单次生成 | **双重验证** (自我批评) | **Gemini-cli胜** ⭐ |
-| **工具输出保留** | 删除旧输出 | **反向预算** (保留最近) | **Gemini-cli胜** ⭐ |
-
-**可借鉴**:
-- ✓ 三层内存系统 (特别是JIT加载)
-- ✓ 双重验证的压缩机制
-- ✓ 主动压缩 (50%阈值,而非等到满)
-- ✓ 反向token预算 (优先保留最近工具输出)
-- ✓ 启发式token估算 (区分字符类型)
-
----
-
-## 十、OpenCode 计划方案的优势
-
-### 10.1 创新点
-
-1. **结构化 Plan (goal.json)**
-   - 比纯文本更精确
-   - 支持树形结构 (goal.children)
-   - 状态流转清晰
-
-2. **执行与 Plan 的强关联 (goal_id)**
-   - 每条 message 知道它属于哪个 goal
-   - 支持基于 goal 的压缩和回溯
-   - 可视化时能展示 goal + 对应步骤
-
-3. **增量压缩 (goal 完成/放弃时)**
-   - 比事后被动压缩更主动
-   - 压缩粒度可控 (按 goal)
-   - 保留失败原因 (abandon summary)
-
-4. **explore 工具 (并行探索自动汇总)**
-   - 比手动管理 Sub-agent 更简单
-   - 适合多方案评估场景
-   - 自动生成汇总报告
-
-5. **精确回溯 (abandon + 状态流转)**
-   - 比 GhostSnapshot 更结构化
-   - 支持从失败尝试中学习
-   - Plan 树中保留失败路径
-
-### 10.2 待改进点 (可借鉴其他方案)
-
-1. **存储可靠性** (借鉴 Codex)
-   - 原子写入
-   - 并发安全 (文件锁)
-   - 自动清理旧数据
-
-2. **Context 分层** (借鉴 Gemini-cli)
-   - 全局 context (用户级别)
-   - 项目 context (项目级别)
-   - JIT context (按需加载)
-
-3. **压缩质量** (借鉴 Gemini-cli)
-   - 双重验证 (自我批评)
-   - 压缩失败自动回退
-   - 验证压缩后 token 数真的减少
-
-4. **主动压缩** (借鉴 Gemini-cli)
-   - 达到阈值 (如 50%) 时主动压缩
-   - 而非等到 context 满
-
-5. **工具输出管理** (借鉴 Gemini-cli)
-   - 反向 token 预算
-   - 优先保留最近工具输出的完整性
-   - 旧输出智能截断 (保留最后N行)
-
-6. **Token 估算** (借鉴 Gemini-cli)
-   - 启发式估算 (区分 ASCII/非ASCII/媒体)
-   - 提高估算精度
-
-7. **用户友好性** (借鉴 Codex)
-   - GhostSnapshot 机制 (可查看但不发送)
-   - 历史规范化 (保证调用-输出对完整性)
-
----
-
-## 十一、实现建议
-
-### 11.1 Phase 1: 核心 goal 工具 (保留计划)
-- Goal 数据结构
-- goal 工具 (add, done, focus)
-- Plan 注入到 system prompt
-- 基础可视化
-
-### 11.2 Phase 2: 增强存储和压缩 (借鉴)
-- **存储增强** (借鉴 Codex):
-  - 原子写入和并发安全
-  - 自动清理机制
-- **压缩增强** (借鉴 Gemini-cli):
-  - 双重验证机制
-  - 主动压缩 (50%阈值)
-  - 反向token预算
-
-### 11.3 Phase 3: 回溯和 Context 分层
-- **回溯支持** (计划):
-  - abandon 操作
-  - Message 关联 goal_id
-  - 基于 goal 的 context 压缩
-- **Context 分层** (借鉴 Gemini-cli):
-  - 全局 context 文件
-  - 项目 context 文件
-  - JIT 子目录 context 发现
-
-### 11.4 Phase 4: 并行探索和优化
-- **explore 工具** (计划):
-  - 独立 message list 管理
-  - 结果汇总机制
-- **优化** (借鉴):
-  - GhostSnapshot (用户友好)
-  - 启发式 token 估算
-  - 历史规范化
-
----
-
-## 十二、总结
-
-### 12.1 三方案对比矩阵
-
-| 能力维度 | OpenCode (计划) | Codex | Gemini-cli | 最佳方案 |
-|---------|---------------|-------|-----------|---------|
-| **结构化 Plan** | ⭐⭐⭐ goal.json | ⭐⭐ TodoItem | ⭐ 无 | OpenCode |
-| **执行关联** | ⭐⭐⭐ goal_id | ⭐⭐ 弱关联 | ⭐ 无 | OpenCode |
-| **压缩策略** | ⭐⭐ 增量 | ⭐⭐ 自动 | ⭐⭐⭐ 三相智能 | Gemini-cli |
-| **压缩时机** | ⭐⭐ goal完成时 | ⭐ 被动 | ⭐⭐⭐ 主动50% | Gemini-cli |
-| **并行探索** | ⭐⭐⭐ explore工具 | ⭐ 无 | ⭐⭐ 工具级 | OpenCode |
-| **回溯能力** | ⭐⭐⭐ goal-based | ⭐⭐ GhostSnapshot | ⭐⭐ 会话记录 | OpenCode |
-| **存储可靠性** | ⭐⭐ 未明确 | ⭐⭐⭐ 原子+锁 | ⭐⭐ Promise限制 | Codex |
-| **Context分层** | ⭐ 无 | ⭐ 无 | ⭐⭐⭐ 三层JIT | Gemini-cli |
-| **工具输出管理** | ⭐ 删除旧的 | ⭐⭐ 截断 | ⭐⭐⭐ 反向预算 | Gemini-cli |
-| **Token估算** | ⭐⭐ 基础 | ⭐ bytes/4 | ⭐⭐⭐ 启发式 | Gemini-cli |
-
-**评分说明**: ⭐ 基础, ⭐⭐ 良好, ⭐⭐⭐ 优秀
-
-### 12.2 最终建议
-
-**OpenCode 的核心优势** (保留并强化):
-- ✅ 结构化 goal.json
-- ✅ goal_id 关联
-- ✅ explore 工具
-- ✅ 精确回溯
-
-**应借鉴的关键特性**:
-1. **Gemini-cli 的压缩机制**: 双重验证 + 主动压缩 + 反向预算
-2. **Gemini-cli 的分层 Context**: 特别是 JIT 加载
-3. **Codex 的存储可靠性**: 原子写入 + 并发安全
-4. **Codex 的 GhostSnapshot**: 提升用户体验
-
-**综合方案** (OpenCode + 借鉴):
-```
-OpenCode 计划方案
-  ├─ 保留: goal.json, explore工具, goal-based回溯
-  ├─ 增强压缩: Gemini-cli的双重验证 + 主动压缩
-  ├─ 增强存储: Codex的原子写入 + 并发安全
-  ├─ 增强Context: Gemini-cli的三层分层 + JIT加载
-  └─ 增强UX: Codex的GhostSnapshot
-```
-
-这将是一个**结构化驱动 + 智能压缩 + 可靠存储 + 分层Context**的综合方案,集三家之长! 🎯

+ 0 - 98
docs/ref/create.md

@@ -1,98 +0,0 @@
----
-name: create
-description: 从创作层解构社交媒体帖子,提取叙事策略与选题价值(研究用,未接入系统)
----
-
-## 角色
-
-你是内容创作策略分析专家。给定一篇优质社交媒体帖子,分析其**创作层**——内容策略、选题价值、叙事结构、文字策略——回答"这篇内容为什么值得创作,以及创作者如何讲述它"。
-
-与制作层解构(How to make)不同,创作层回答的是:**Why this content + How to tell it**。
-
----
-
-## 创作层的核心概念
-
-**选题价值**(三点框架)
-- **灵感点**:是什么触发了创作者创作这篇内容?来自生活、趋势、热点、个人经历?
-- **目的点**:创作者想通过这篇内容达到什么?吸粉、种草、共鸣、教育?
-- **关键点**:这篇内容的核心价值主张是什么?受众为什么会喜欢?
-
-**内容权重**
-- 这篇内容以图片为主还是文字为主?谁承载了更多核心信息?
-- 图文是相辅相成,还是各自独立承载信息?
-
-**叙事结构**:创作者如何组织内容流程——从什么开始,经过什么,以什么结尾?图片之间的叙事逻辑是什么?
-
----
-
-## 分析维度
-
-**内容品类**:这是什么类型的内容?(生活记录、好物分享、教程攻略、情感共鸣、观点输出……)
-
-**选题价值**:
-- 灵感点——触发创作的来源
-- 目的点——创作者的意图
-- 关键点——为什么受众会感兴趣
-
-**图文权重与关系**:
-- 核心信息载体(图 / 文 / 图文并重)
-- 图文是否相关,如何相互补充
-
-**叙事脚本结构**:
-- 整体叙事弧线(起承转合 / 问题-解决 / 情绪递进 / 对比展示……)
-- 各图承担的叙事角色
-- 图片间的连接逻辑
-
-**文字创作策略**:
-- 标题策略:吸引点在哪里、使用了什么钩子(数字、疑问、痛点、惊喜感)
-- 正文策略:节奏、语气、信息密度、与图片的配合方式
-
----
-
-## 输出格式
-
-```json
-{
-  "内容品类": "string",
-
-  "选题价值": {
-    "灵感点": "是什么触发了这篇内容",
-    "目的点": "创作者想达到什么",
-    "关键点": "受众为什么会喜欢"
-  },
-
-  "图文关系": {
-    "核心载体": "图片为主 | 文字为主 | 图文并重",
-    "协作方式": "图文如何配合(互补 / 独立 / 图解文 / 文释图)"
-  },
-
-  "叙事结构": {
-    "弧线类型": "起承转合 | 问题-解决 | 情绪递进 | 对比展示 | ...",
-    "图片叙事": [
-      {"图片": "图片1", "叙事角色": "引入主体 / 建立情境..."},
-      {"图片": "图片2", "叙事角色": "展开 / 对比..."}
-    ]
-  },
-
-  "文字策略": {
-    "标题": "钩子类型与策略",
-    "正文": "节奏、语气、信息组织方式"
-  },
-
-  "核心洞察": "一句话:这篇内容在创作策略上为什么成功"
-}
-```
-
----
-
-## 原则
-
-- **创作层优先**:分析"为什么创作这个内容 + 如何叙述它",而非视觉制作细节
-- **受众视角**:始终思考受众为什么会停留、点赞、收藏、分享
-- **策略性而非描述性**:不是"图片展示了XX",而是"通过XX实现了XX效果"
-- **与制作层互补**:创作层负责 Why + What to tell,制作层负责 How to make
-
----
-
-> **注**:此文件仅供研究,未接入 Agent 系统。对应的系统工具是 `deconstruct`(制作层)。

+ 0 - 357
docs/ref/deconstruct_old.md

@@ -1,357 +0,0 @@
----
-name: deconstruct
-description: 制作还原解构方法论:将优质社交媒体帖子解构为可还原的结构化制作脚本
----
-
-## 角色定位
-
-你是制作还原解构顾问。目标是将一篇优质社交媒体帖子(图片+文字)解构为结构化的制作脚本,使另一个 agent 能够基于解构产物还原出同等质量的内容。
-
-**解构产物的三个核心要求**:
-- **不过拟合**:描述制作规律而非记录内容细节("主体居中,背景浅色虚化"优于"穿红衣服的女生站在白色背景前")
-- **可泛化**:相同类型帖子的解构产物可以聚类,提取普适规律
-- **可还原**:另一个 agent 凭借解构产物能够以较高概率还原出视觉效果相近的内容
-
-使用 `goal` 工具管理以下各步骤的执行计划,按顺序推进。
-
----
-
-## 步骤 1:内容过滤
-
-过滤正文中与核心主题无关的话题标签(hashtag)。
-
-**保留标准**(两项均通过才保留):
-1. 与帖子主题或产品有直接关联
-2. 移除后不影响对核心内容的理解
-
-输出:过滤后的正文文本。
-
----
-
-## 步骤 2:入口分析(内容视角)
-
-通过多图对比,判断这篇内容的核心表达方式。
-
-**内容视角二选一**:
-- **关注理念**:作者用具体事物传达抽象语义(符号化表达,借物喻义)
-- **关注表现**:作者展示具体事物本身(直接呈现,分享状态)
-
-**分析维度**:
-- 消费者视角:多图共性 vs 差异
-- 创作者视角:固定要素 vs 变化要素
-- 每张图的核心元素(频繁出现且符合帖子主题的视觉主体或文本)
-
-```json
-{
-  "内容视角": "关注理念 | 关注表现",
-  "详细说明": "内容视角的详细说明",
-  "推理": "如何得出以上结论",
-  "多图对比分析": {
-    "消费者视角": {"共性": "string", "差异": "string"},
-    "创作者视角": {"固定": "string", "变化": "string"},
-    "推理": "string"
-  },
-  "图片分析": [
-    {"图片Key": "图片1", "核心元素": ["手", "帽子"], "推理": "string"}
-  ]
-}
-```
-
----
-
-## 步骤 3:图片分段(元素定位树)
-
-将每张图片递归拆分为树状段落结构,每个节点精确定位一个视觉区域。
-
-### 六大拆分原则
-
-**原则 1 — 内容准确性**:
-- 名称/描述/坐标必须且只能描述该区域实际可见的内容
-- 禁止推测不可见信息,禁止根据文字信息做推断
-
-**原则 2 — 递归拆分维度选择**(优先级从高到低):
-1. 创作者语义拆分(最高优先):作者创作意图导致的自然分组,如"标题区 vs 内容区"
-2. XY 轴拆分:水平或垂直方向的空间分割
-3. 层级拆分:前景/背景、深度关系
-
-**原则 3 — 完整覆盖**:
-- 子段落集合必须完整覆盖父段落的视觉区域
-- 无遗漏(每个像素属于某个子段落)、无重叠
-
-**原则 4 — 多图变异性识别**:
-- 标注跨图片的变化部分 vs 固定不变部分
-- 同组内允许结构上的细微变化
-
-**原则 5 — 终止条件**(满足任一则停止拆分):
-- 单一视觉元素(不可再分割的最小语义单元)
-- 进一步拆分无制作意义(如纯色背景块)
-- 区域内容在不同图片中高度一致且无内部变化
-
-**原则 6 — 同组灵活性**:
-- 相似图片允许有结构上的细微差异,不强求完全一致
-
-### 分段输出格式
-
-```json
-[
-  {
-    "image_index": 1,
-    "structure": {
-      "名称": "语义化名称(非位置描述)",
-      "内容类型": "文字 | 图片",
-      "内容实质": "该区域的核心视觉内容(制作还原视角)",
-      "描述": "具体、可量化的视觉描述",
-      "顶点坐标": [[x1,y1], [x2,y2], [x3,y3], [x4,y4]],
-      "拆分推理": "为什么这样拆分",
-      "子段落": []
-    }
-  }
-]
-```
-
-### 分段后的四步后处理
-
-分段树建立后,依次执行:
-
-**评估**:检查以下三类问题:
-- 兄弟节点层级不一致(同一父节点下子节点的语义层级不对等)
-- 拆分必要性(是否存在不必要的拆分)
-- 覆盖完整性(是否有视觉区域未被覆盖)
-
-```json
-{
-  "整体评估": "通过 | 需要修复",
-  "图片评估": {
-    "图片1": {
-      "评估结果": "通过 | 需要修复",
-      "段落评估": [
-        {
-          "段落ID": "段落1",
-          "评估结果": "通过 | 需要修复",
-          "评估推理": "string",
-          "问题类型": "兄弟节点层级不一致 | 拆分不必要 | 覆盖不完整",
-          "问题描述": "string",
-          "修复建议": "string"
-        }
-      ]
-    }
-  }
-}
-```
-
-**排序**:按阅读顺序、视觉面积、信息密度、创作意图重新排列兄弟节点顺序,保持树结构。
-
-**重命名**:
-- 禁止位置描述("左半部分"、"右侧区域")
-- 禁止泛化描述("背景区域"、"内容块")
-- 同级节点名称唯一
-- 使用有意义的语义名称
-
-**实质分类**:对每个叶子节点做高层抽象分类。
-- 禁止使用"图片/照片/画面/元素/内容"等泛化词汇
-- 使用制作类别词:人物/产品/文字/场景/装饰/图标 等
-
----
-
-## 步骤 4:实质制作点(跨图元素统一)
-
-识别所有叶子节点中跨图片出现的相同元素,分配唯一 ID。
-
-### 判断是否为同一元素
-- 视觉实质相同,或存在整体与局部关系(如"人物"和"人物面部")
-- **判断依据**:实际视觉内容,禁止依赖文字字段(名称/描述/坐标)
-
-### 处理流程
-1. 收集所有叶子节点
-2. 文字元素:按内容实质分组(代码化,精确匹配)
-3. 图片元素:LLM 视觉比较分组
-4. 反思合并:识别被错误分开的组,合并为同一元素
-5. 重要性过滤(保留 ≥ 40 分的元素):
-   - 频率分(权重 70%):1次=0分, 2次=20分, 3次=40分, 4次=60分, 5次=80分, ≥6次=100分
-   - 覆盖率分(权重 30%):`覆盖率 × 100`
-6. 统一命名(使用上位概念,避免歧义)
-7. 分配元素 ID:`元素1`, `元素2` ...
-
-```json
-[
-  {
-    "元素ID": "元素1",
-    "统一名称": "人物",
-    "统一描述": "女性,长发,戴眼镜,职业装,站立姿态",
-    "出现段落": ["段落1.1.1", "段落2.1", "段落3.1"],
-    "重要性得分": 85
-  }
-]
-```
-
----
-
-## 步骤 5:图片形式分析
-
-从"如何还原元素"的视角,提取每个段落/元素的视觉呈现方式。
-
-**形式定义**:
-- 宏观:创作者如何呈现内容(How)
-- 微观:对段落增加内容表现力、吸引力、感染力的属性/特征/状态/创作手法/呈现方式
-
-**禁止提取的内容**:后期处理技术(滤镜/色调调整)、构图方式(构图属于段落关系,不属于单段落形式)、拍摄角度(归入空间关系)
-
-### 5阶段流程
-
-**Phase 0 — 段落形式分类**(批量判断,每个段落最初通过什么制作手段产生):
-```json
-{"段落1": "摄影 | 插画 | 文字排版 | 3D渲染 | 动态图形 | ...", "段落1.2": "..."}
-```
-
-**Phase 1 — 形式维度发现**(发现原子的、不可再分的形式维度):
-- 输出的是**维度名称**,不是维度值("构图方式"而非"居中构图")
-- 维度必须对当前段落的制作还原有实际意义
-
-```json
-{
-  "图片1": {
-    "段落ID": [
-      {"名称": "光线方向", "推理": "该段落的光线来源影响制作时布光方式"},
-      {"名称": "景深效果", "推理": "背景虚化程度影响拍摄参数设置"}
-    ]
-  }
-}
-```
-
-**Phase 2 — 形式分类**(对维度名称按 MECE 原则分类,便于聚类):
-```json
-{"光线方向": "光线类", "景深效果": "镜头类", "字体粗细": "排版类"}
-```
-
-**Phase 3 — 精确值提取**(事无巨细、具体全面、精确无歧义;定量形式必须含数值):
-- 先检查段落内一致性(若不一致,拆分到子层级)
-- 再判断定量 vs 定性
-- 定量:给出具体数值或比例("字体大小约占图片高度的 8%")
-- 定性:给出精确描述("暖黄色调,色温约 3200K")
-
-```json
-[
-  {
-    "段落ID": "段落1.1",
-    "形式": [
-      {"名称": "光线方向", "描述": "右侧 45° 侧光,形成明显的明暗分界", "是否可定量": false},
-      {"名称": "景深效果", "描述": "背景虚化,估计光圈 f/1.8~f/2.8", "是否可定量": true}
-    ]
-  }
-]
-```
-
----
-
-## 步骤 6:段内关系分析
-
-分析每个父段落与其**直接子节点**之间的关系。
-
-**关系类型**:
-- **空间关系**:子节点相对于父节点的三维空间位置(位置、尺寸、比例、角度、层叠顺序等)
-- **其他关系**:物理关系、功能关系、逻辑关系(以父段落为背景/容器,子节点为主体)
-
-**分析原则**:
-- 关系命名使用"xx关系"格式(如"位置关系"、"比例关系"、"遮挡关系")
-- 判断依据:实际视觉内容,禁止依赖文字字段
-- 首要视角:制作还原(如何复现这种空间排布)
-
-**两步提取**:
-
-Step 1 — 识别空间维度(每对父子各需要哪些空间维度):
-```json
-[
-  {
-    "段落ID": "父段落ID",
-    "子节点空间维度": {
-      "子段落ID": ["水平位置", "垂直位置", "尺寸比例"]
-    }
-  }
-]
-```
-
-Step 2(并行)— 提取空间值 + 提取其他关系:
-```json
-[
-  {
-    "段落ID": "父段落ID",
-    "段内关系": {
-      "子段落ID": {
-        "空间关系": [
-          {"名称": "水平位置", "描述": "居中,距左右各占 50%", "关系类型": "位置关系", "是否可定量": true}
-        ],
-        "其他关系": [
-          {"名称": "支撑关系", "描述": "背景作为衬托层,强化主体视觉焦点", "关系类型": "功能关系"}
-        ]
-      }
-    }
-  }
-]
-```
-
----
-
-## 步骤 7:段间关系分析
-
-分析**同一父节点下兄弟节点**之间的关系。
-
-**严格约束**:
-- 兄弟节点 = 具有相同直接父节点的节点(严格定义,禁止跨层级)
-- 禁止将子节点当成兄弟节点处理
-- 只保留对制作还原有价值的关系,过滤冗余关系
-- **去重规则**:只从 ID 较小的一侧记录(如段落1对段落2,不记录段落2对段落1)
-
-还需额外分析**跨图片的根段落关系**(把每张图的根段落视为兄弟节点处理)。
-
-```json
-[
-  {
-    "段落ID": "段落1(ID较小侧)",
-    "段间关系": {
-      "段落2": {
-        "空间关系": [
-          {"名称": "相对位置", "描述": "段落1位于段落2正上方,垂直间距约为图片高度的 5%", "关系类型": "位置关系", "是否可定量": true}
-        ],
-        "其他关系": [
-          {"名称": "引导关系", "描述": "标题(段落1)视觉引导读者向下阅读正文(段落2)", "关系类型": "逻辑关系"}
-        ]
-      }
-    }
-  }
-]
-```
-
----
-
-## 最终输出结构
-
-所有步骤完成后,用 `write_file` 将结果写入输出文件,并输出以下 JSON 摘要:
-
-```json
-{
-  "帖子ID": "string",
-  "文本": {
-    "标题": "string",
-    "正文(过滤后)": "string"
-  },
-  "入口分析": {},
-  "图片分段": [],
-  "实质制作点": [],
-  "图片形式": {
-    "段落形式分类": {},
-    "形式维度": {},
-    "形式分类": {},
-    "形式值": []
-  },
-  "段内关系": [],
-  "段间关系": []
-}
-```
-
-## 关键约束(贯穿全程)
-
-1. **泛化优先**:始终描述制作规律,而非内容细节
-2. **视觉判断优先**:所有判断基于实际可见内容,禁止依赖名称/描述等文字字段
-3. **制作还原视角**:始终从"如何制作出这个效果"的角度分析
-4. **结构化输出**:每步严格按 JSON schema 输出,不允许随意变更结构
-5. **步骤间数据复用**:后续步骤引用前面步骤的段落 ID,保持一致性

+ 0 - 31
docs/ref/skills.md

@@ -1,31 +0,0 @@
-Skill structure
-Every Skill requires a SKILL.md file with YAML frontmatter:
-
----
-name: your-skill-name
-description: Brief description of what this Skill does and when to use it
----
-
-# Your Skill Name
-
-## Instructions
-[Clear, step-by-step guidance for Claude to follow]
-
-## Examples
-[Concrete examples of using this Skill]
-Required fields: name and description
-
-Field requirements:
-
-name:
-
-Maximum 64 characters
-Must contain only lowercase letters, numbers, and hyphens
-Cannot contain XML tags
-Cannot contain reserved words: "anthropic", "claude"
-description:
-
-Must be non-empty
-Maximum 1024 characters
-Cannot contain XML tags
-The description should include both what the Skill does and when Claude should use it. For complete authoring guidance, see the best practices guide.

+ 71 - 0
docs/research/README.md

@@ -0,0 +1,71 @@
+# Agent2Agent (A2A) 通信调研
+
+本目录包含 Agent2Agent 跨设备通信的调研和设计文档。
+
+## 文档列表
+
+| 文档 | 内容 | 状态 |
+|-----|------|------|
+| [a2a-protocols.md](./a2a-protocols.md) | 行业 A2A 协议和框架调研 | 已完成 |
+| [a2a-cross-device.md](./a2a-cross-device.md) | 跨设备通信方案设计 | 已完成 |
+| [a2a-trace-storage.md](./a2a-trace-storage.md) | 跨设备 Trace 存储方案 | 已完成 |
+| [a2a-continuous-dialogue.md](./a2a-continuous-dialogue.md) | 持续对话方案(已废弃) | 已废弃 |
+
+## 核心设计
+
+### 远程 Trace ID
+
+通过在 Trace ID 中编码位置信息实现跨设备访问:
+
+```
+本地 Trace:  abc-123
+远程 Trace:  agent://terminal-agent-456/abc-123
+```
+
+### 持续对话
+
+通过 `continue_from` 参数实现 Agent 间持续对话:
+
+```python
+# 第一次调用
+result1 = agent(task="分析项目", agent_url="https://remote-agent")
+# 返回: {"sub_trace_id": "agent://remote-agent/abc-123"}
+
+# 继续对话
+result2 = agent(
+    task="重点分析core模块",
+    continue_from=result1["sub_trace_id"],
+    agent_url="https://remote-agent"
+)
+```
+
+### 存储架构
+
+**HybridTraceStore** 自动路由到本地或远程存储:
+- 本地 Trace → `FileSystemTraceStore`
+- 远程 Trace → `RemoteTraceStore`(通过 HTTP API)
+
+## 实现计划
+
+### Phase 1: 基础跨设备通信(1-2周)
+- [ ] 实现 `RemoteTraceStore`
+- [ ] 实现 `HybridTraceStore`
+- [ ] 修改 `agent` 工具支持 `agent_url` 参数
+- [ ] 添加远程 Trace ID 解析
+
+### Phase 2: 增强功能(2-3周)
+- [ ] 认证和授权
+- [ ] 成本控制
+- [ ] 审计日志
+- [ ] 性能优化(缓存、批量API)
+
+### Phase 3: 生产化(按需)
+- [ ] 错误处理和重试
+- [ ] 监控和告警
+- [ ] 文档和示例
+
+## 参考资料
+
+- [Google A2A Protocol](https://a2a-protocol.org/latest/specification/)
+- [Anthropic MCP](https://modelcontextprotocol.io/specification/2025-06-18)
+- [Agent Interoperability Survey](https://arxiv.org/html/2505.02279v1)

+ 733 - 0
docs/research/a2a-continuous-dialogue.md

@@ -0,0 +1,733 @@
+# Agent2Agent 持续对话方案
+
+**更新日期:** 2026-03-03
+
+## 问题定义
+
+### 单次任务 vs 持续对话
+
+**单次任务(之前的方案):**
+```
+云端Agent: 请分析本地项目
+    ↓
+终端Agent: [执行分析] → 返回结果
+    ↓
+结束
+```
+
+**持续对话(新需求):**
+```
+云端Agent: 请分析本地项目
+    ↓
+终端Agent: 我看到有3个模块,你想重点分析哪个?
+    ↓
+云端Agent: 重点分析core模块
+    ↓
+终端Agent: core模块使用了X架构,需要我详细说明吗?
+    ↓
+云端Agent: 是的,请详细说明
+    ↓
+终端Agent: [详细分析] → 返回结果
+    ↓
+结束(或继续)
+```
+
+## 核心挑战
+
+1. **上下文延续** - 如何维护多轮对话的上下文?
+2. **状态管理** - 对话进行到哪一步?谁在等待谁?
+3. **消息路由** - 如何确保消息发送到正确的Agent?
+4. **会话生命周期** - 何时开始?何时结束?
+5. **异步通信** - Agent可能不在线,如何处理?
+
+## 方案对比
+
+### 方案1:基于Trace的持续对话(推荐)
+
+#### 核心思想
+
+**利用现有的Trace机制作为对话容器**
+
+- 每个A2A对话创建一个共享的Trace
+- 双方Agent都可以向这个Trace追加消息
+- 通过WebSocket实时同步消息
+- 利用现有的续跑机制(`continue_from`)
+
+#### 架构设计
+
+```
+云端Agent                共享Trace                终端Agent
+    |                       |                         |
+    | 创建对话              |                         |
+    |--------------------->|                         |
+    |                      |                         |
+    | 发送消息1            |                         |
+    |--------------------->|                         |
+    |                      |----WebSocket推送------->|
+    |                      |                         |
+    |                      |<----追加消息2-----------|
+    |<--WebSocket推送------|                         |
+    |                      |                         |
+    | 发送消息3            |                         |
+    |--------------------->|                         |
+    |                      |----WebSocket推送------->|
+    |                      |                         |
+    ...持续对话...
+```
+
+#### API设计
+
+```python
+# 1. 创建对话会话
+POST /api/a2a/sessions
+{
+    "participants": ["cloud-agent-123", "terminal-agent-456"],
+    "initial_message": "请分析本地项目",
+    "context": {...}
+}
+
+响应:
+{
+    "session_id": "sess-xxx",
+    "trace_id": "trace-yyy",  # 底层使用Trace
+    "ws_url": "wss://host/api/a2a/sessions/sess-xxx/stream"
+}
+
+# 2. 发送消息(追加到Trace)
+POST /api/a2a/sessions/{session_id}/messages
+{
+    "from": "cloud-agent-123",
+    "content": "重点分析core模块",
+    "wait_for_response": true  # 是否等待对方回复
+}
+
+响应:
+{
+    "message_id": "msg-xxx",
+    "status": "sent"
+}
+
+# 3. WebSocket监听(实时接收消息)
+WS /api/a2a/sessions/{session_id}/stream
+{
+    "type": "message",
+    "from": "terminal-agent-456",
+    "content": "我看到有3个模块,你想重点分析哪个?",
+    "message_id": "msg-yyy"
+}
+
+# 4. 获取对话历史
+GET /api/a2a/sessions/{session_id}/messages
+响应:
+{
+    "messages": [
+        {"from": "cloud-agent-123", "content": "...", "timestamp": "..."},
+        {"from": "terminal-agent-456", "content": "...", "timestamp": "..."},
+        ...
+    ]
+}
+
+# 5. 结束对话
+POST /api/a2a/sessions/{session_id}/close
+{
+    "reason": "completed"
+}
+```
+
+#### 实现细节
+
+```python
+# agent/api/a2a_session.py
+
+class A2ASession:
+    """A2A对话会话,基于Trace实现"""
+
+    def __init__(self, session_id: str, trace_id: str, participants: List[str]):
+        self.session_id = session_id
+        self.trace_id = trace_id
+        self.participants = participants
+        self.ws_connections = {}  # agent_id -> WebSocket
+
+    async def send_message(
+        self,
+        from_agent: str,
+        content: str,
+        wait_for_response: bool = False
+    ) -> Dict[str, Any]:
+        """发送消息到对话"""
+        # 1. 追加消息到Trace
+        messages = [{"role": "user", "content": content}]
+        config = RunConfig(
+            trace_id=self.trace_id,
+            after_sequence=None,  # 续跑模式
+            uid=from_agent
+        )
+
+        # 2. 执行(可能触发对方Agent的响应)
+        async for event in runner.run(messages, config):
+            if isinstance(event, Message):
+                # 3. 通过WebSocket推送给其他参与者
+                await self._broadcast_message(event, exclude=from_agent)
+
+                if wait_for_response and event.role == "assistant":
+                    # 等待对方回复
+                    return {"message_id": event.message_id, "status": "sent"}
+
+        return {"status": "completed"}
+
+    async def _broadcast_message(self, message: Message, exclude: str = None):
+        """广播消息给所有参与者(除了发送者)"""
+        for agent_id, ws in self.ws_connections.items():
+            if agent_id != exclude:
+                await ws.send_json({
+                    "type": "message",
+                    "from": exclude,
+                    "content": message.content,
+                    "message_id": message.message_id,
+                    "timestamp": message.created_at.isoformat()
+                })
+
+
+@app.post("/api/a2a/sessions")
+async def create_session(request: CreateSessionRequest):
+    """创建A2A对话会话"""
+    # 1. 创建底层Trace
+    trace = Trace(
+        trace_id=generate_trace_id(),
+        mode="agent",
+        task=request.initial_message,
+        agent_type="a2a_session",
+        context={
+            "session_type": "a2a",
+            "participants": request.participants
+        }
+    )
+    await store.create_trace(trace)
+
+    # 2. 创建Session对象
+    session_id = f"sess-{generate_id()}"
+    session = A2ASession(session_id, trace.trace_id, request.participants)
+
+    # 3. 存储Session(内存或Redis)
+    sessions[session_id] = session
+
+    # 4. 发送初始消息
+    if request.initial_message:
+        await session.send_message(
+            from_agent=request.participants[0],
+            content=request.initial_message
+        )
+
+    return {
+        "session_id": session_id,
+        "trace_id": trace.trace_id,
+        "ws_url": f"wss://{host}/api/a2a/sessions/{session_id}/stream"
+    }
+
+
+@app.websocket("/api/a2a/sessions/{session_id}/stream")
+async def session_stream(websocket: WebSocket, session_id: str):
+    """WebSocket连接,实时接收对话消息"""
+    await websocket.accept()
+
+    # 1. 获取Session
+    session = sessions.get(session_id)
+    if not session:
+        await websocket.close(code=404)
+        return
+
+    # 2. 识别连接的Agent
+    agent_id = await authenticate_websocket(websocket)
+
+    # 3. 注册WebSocket连接
+    session.ws_connections[agent_id] = websocket
+
+    try:
+        # 4. 保持连接,接收消息
+        async for message in websocket:
+            data = json.loads(message)
+            if data["type"] == "message":
+                # 发送消息到对话
+                await session.send_message(
+                    from_agent=agent_id,
+                    content=data["content"]
+                )
+    finally:
+        # 5. 清理连接
+        del session.ws_connections[agent_id]
+
+
+@app.post("/api/a2a/sessions/{session_id}/messages")
+async def send_session_message(session_id: str, request: SendMessageRequest):
+    """发送消息到对话(HTTP方式)"""
+    session = sessions.get(session_id)
+    if not session:
+        raise HTTPException(404, "Session not found")
+
+    result = await session.send_message(
+        from_agent=request.from_agent,
+        content=request.content,
+        wait_for_response=request.wait_for_response
+    )
+
+    return result
+```
+
+#### 客户端SDK
+
+```python
+# agent/client/a2a_session_client.py
+
+class A2ASessionClient:
+    """A2A持续对话客户端"""
+
+    def __init__(self, base_url: str, agent_id: str, api_key: str):
+        self.base_url = base_url
+        self.agent_id = agent_id
+        self.api_key = api_key
+        self.ws = None
+        self.message_handlers = []
+
+    async def create_session(
+        self,
+        other_agent: str,
+        initial_message: str
+    ) -> str:
+        """创建对话会话"""
+        response = await self._post("/api/a2a/sessions", {
+            "participants": [self.agent_id, other_agent],
+            "initial_message": initial_message
+        })
+
+        session_id = response["session_id"]
+
+        # 自动连接WebSocket
+        await self._connect_websocket(session_id)
+
+        return session_id
+
+    async def _connect_websocket(self, session_id: str):
+        """连接WebSocket接收消息"""
+        ws_url = f"{self.ws_url}/api/a2a/sessions/{session_id}/stream"
+        self.ws = await websockets.connect(
+            ws_url,
+            extra_headers={"Authorization": f"Bearer {self.api_key}"}
+        )
+
+        # 启动消息接收循环
+        asyncio.create_task(self._receive_messages())
+
+    async def _receive_messages(self):
+        """接收WebSocket消息"""
+        async for message in self.ws:
+            data = json.loads(message)
+            if data["type"] == "message":
+                # 调用注册的消息处理器
+                for handler in self.message_handlers:
+                    await handler(data)
+
+    async def send_message(self, session_id: str, content: str):
+        """发送消息"""
+        if self.ws:
+            # 通过WebSocket发送(实时)
+            await self.ws.send(json.dumps({
+                "type": "message",
+                "content": content
+            }))
+        else:
+            # 通过HTTP发送(备用)
+            await self._post(f"/api/a2a/sessions/{session_id}/messages", {
+                "from_agent": self.agent_id,
+                "content": content
+            })
+
+    def on_message(self, handler):
+        """注册消息处理器"""
+        self.message_handlers.append(handler)
+
+    async def close_session(self, session_id: str):
+        """关闭对话"""
+        await self._post(f"/api/a2a/sessions/{session_id}/close", {})
+        if self.ws:
+            await self.ws.close()
+```
+
+#### 使用示例
+
+```python
+# 云端Agent使用
+client = A2ASessionClient(
+    base_url="https://org.agent.cloud",
+    agent_id="cloud-agent-123",
+    api_key="ak_xxx"
+)
+
+# 创建对话
+session_id = await client.create_session(
+    other_agent="terminal-agent-456",
+    initial_message="请分析本地项目"
+)
+
+# 注册消息处理器
+@client.on_message
+async def handle_message(message):
+    print(f"收到消息: {message['content']}")
+
+    # 根据消息内容决定如何回复
+    if "哪个模块" in message['content']:
+        await client.send_message(session_id, "重点分析core模块")
+    elif "需要我详细说明吗" in message['content']:
+        await client.send_message(session_id, "是的,请详细说明")
+
+# 等待对话完成
+await asyncio.sleep(60)  # 或其他结束条件
+
+# 关闭对话
+await client.close_session(session_id)
+```
+
+#### 优势
+
+1. **复用Trace机制** - 所有消息管理、压缩、存储都复用
+2. **完整历史** - 对话历史自动保存在Trace中
+3. **实时通信** - WebSocket保证低延迟
+4. **状态追踪** - 利用Trace的状态管理
+5. **可回溯** - 可以查看完整的对话历史
+
+#### 劣势
+
+1. **Trace概念泄露** - 外部需要理解session_id和trace_id的关系
+2. **复杂度** - 需要管理WebSocket连接
+
+### 方案2:独立的对话管理器
+
+#### 核心思想
+
+**创建独立的对话管理系统,不依赖Trace**
+
+```python
+class Conversation:
+    """独立的对话对象"""
+    conversation_id: str
+    participants: List[str]
+    messages: List[ConversationMessage]
+    status: str  # active, waiting, completed
+    created_at: datetime
+
+class ConversationMessage:
+    """对话消息"""
+    message_id: str
+    from_agent: str
+    to_agent: Optional[str]  # None表示广播
+    content: str
+    timestamp: datetime
+    metadata: Dict
+```
+
+#### 优势
+
+1. **概念清晰** - 对话就是对话,不混淆Trace
+2. **轻量级** - 不需要Trace的重量级机制
+3. **灵活** - 可以自定义对话逻辑
+
+#### 劣势
+
+1. **重复实现** - 需要重新实现消息管理、存储、压缩
+2. **不一致** - 与现有Trace机制不一致
+3. **维护成本** - 需要维护两套系统
+
+### 方案3:混合模式(推荐)
+
+#### 核心思想
+
+**对话层(Session)+ 执行层(Trace)分离**
+
+```
+对话层(Session)
+    - 管理对话状态
+    - 路由消息
+    - WebSocket连接
+    |
+    | 每条消息触发
+    ↓
+执行层(Trace)
+    - 执行具体任务
+    - 调用工具
+    - 管理上下文
+```
+
+#### 架构
+
+```python
+class A2ASession:
+    """对话会话(轻量级)"""
+    session_id: str
+    participants: List[str]
+    current_speaker: str
+    waiting_for: Optional[str]
+    context: Dict  # 共享上下文
+    message_queue: List[Message]
+
+    async def send_message(self, from_agent: str, content: str):
+        """发送消息"""
+        # 1. 添加到消息队列
+        self.message_queue.append(Message(from_agent, content))
+
+        # 2. 如果需要执行(不是简单问答),创建Trace
+        if self._needs_execution(content):
+            trace_id = await self._create_execution_trace(content)
+            # 执行完成后,结果自动添加到消息队列
+        else:
+            # 简单消息,直接转发
+            await self._forward_message(content, to=self._get_other_agent(from_agent))
+
+    def _needs_execution(self, content: str) -> bool:
+        """判断是否需要创建Trace执行"""
+        # 例如:包含工具调用、复杂任务等
+        return "分析" in content or "执行" in content or "查询" in content
+```
+
+#### 优势
+
+1. **分层清晰** - 对话管理和任务执行分离
+2. **灵活** - 简单消息不需要Trace,复杂任务才创建
+3. **高效** - 避免为每条消息创建Trace
+4. **复用** - 复杂任务仍然复用Trace机制
+
+#### 实现示例
+
+```python
+@app.post("/api/a2a/sessions/{session_id}/messages")
+async def send_message(session_id: str, request: SendMessageRequest):
+    session = sessions[session_id]
+
+    # 1. 判断消息类型
+    if request.requires_execution:
+        # 需要执行的任务 → 创建Trace
+        trace_id = await create_execution_trace(
+            task=request.content,
+            parent_session=session_id,
+            agent_id=request.from_agent
+        )
+
+        # 执行完成后,结果自动推送到Session
+        result = await runner.run_result(
+            messages=[{"role": "user", "content": request.content}],
+            config=RunConfig(trace_id=trace_id)
+        )
+
+        # 将结果作为消息发送给对方
+        await session.send_message(
+            from_agent=request.from_agent,
+            content=result["summary"]
+        )
+    else:
+        # 简单消息 → 直接转发
+        await session.send_message(
+            from_agent=request.from_agent,
+            content=request.content
+        )
+
+    return {"status": "sent"}
+```
+
+## 关键设计决策
+
+### 1. 消息类型分类
+
+| 类型 | 示例 | 处理方式 |
+|------|------|----------|
+| **简单问答** | "你好"、"收到"、"明白了" | 直接转发,不创建Trace |
+| **信息查询** | "当前进度如何?" | 查询Session状态,返回 |
+| **任务请求** | "分析core模块" | 创建Trace执行 |
+| **工具调用** | "读取文件X" | 创建Trace执行 |
+
+### 2. 上下文管理
+
+**Session级上下文(轻量):**
+```python
+session.context = {
+    "current_topic": "项目分析",
+    "focus_module": "core",
+    "previous_results": {...}
+}
+```
+
+**Trace级上下文(完整):**
+- 完整的消息历史
+- 工具调用记录
+- Goal树
+
+### 3. 生命周期管理
+
+```python
+# Session生命周期
+created → active → waiting → active → ... → completed/timeout
+
+# Trace生命周期(每个任务)
+created → running → completed
+```
+
+### 4. 超时和重连
+
+```python
+class A2ASession:
+    timeout: int = 300  # 5分钟无活动则超时
+    last_activity: datetime
+
+    async def check_timeout(self):
+        if datetime.now() - self.last_activity > timedelta(seconds=self.timeout):
+            await self.close(reason="timeout")
+
+    async def reconnect(self, agent_id: str, ws: WebSocket):
+        """Agent重连"""
+        self.ws_connections[agent_id] = ws
+        # 发送未读消息
+        await self._send_unread_messages(agent_id)
+```
+
+## 实现路线图
+
+### Phase 1:基础对话能力(2-3周)
+
+1. **Session管理**
+   - 创建/关闭Session
+   - 消息路由
+   - WebSocket连接管理
+
+2. **简单消息转发**
+   - 不涉及Trace
+   - 纯消息传递
+
+3. **客户端SDK**
+   - `A2ASessionClient`
+   - 消息处理器
+
+### Phase 2:集成Trace执行(2-3周)
+
+1. **任务识别**
+   - 判断消息是否需要执行
+   - 自动创建Trace
+
+2. **结果集成**
+   - Trace结果转换为消息
+   - 自动推送给对方
+
+3. **上下文共享**
+   - Session上下文传递给Trace
+   - Trace结果更新Session上下文
+
+### Phase 3:高级功能(3-4周)
+
+1. **多方对话**
+   - 支持3个以上Agent
+   - 群聊模式
+
+2. **对话分支**
+   - 子对话
+   - 并行对话
+
+3. **持久化和恢复**
+   - Session持久化
+   - 断线重连
+
+## 示例场景
+
+### 场景:云端助理与终端Agent的持续对话
+
+```python
+# 云端助理
+client = A2ASessionClient("https://cloud", "cloud-agent", "ak_xxx")
+
+# 1. 创建对话
+session_id = await client.create_session(
+    other_agent="terminal-agent-456",
+    initial_message="请分析本地项目"
+)
+
+# 2. 注册消息处理器(自动响应)
+@client.on_message
+async def handle_message(msg):
+    content = msg['content']
+
+    if "哪个模块" in content:
+        # 简单回复,不需要执行
+        await client.send_message(session_id, "重点分析core模块")
+
+    elif "详细说明" in content:
+        # 需要进一步分析,触发执行
+        await client.send_message(
+            session_id,
+            "是的,请详细说明架构设计和关键组件",
+            requires_execution=True  # 标记需要执行
+        )
+
+# 3. 等待对话完成
+await client.wait_for_completion(session_id)
+```
+
+```python
+# 终端Agent
+client = A2ASessionClient("https://terminal", "terminal-agent-456", "ak_yyy")
+
+# 1. 监听新对话
+@client.on_new_session
+async def handle_new_session(session_id, initial_message):
+    # 分析项目
+    modules = await analyze_project()
+
+    # 询问用户
+    await client.send_message(
+        session_id,
+        f"我看到有{len(modules)}个模块:{', '.join(modules)},你想重点分析哪个?"
+    )
+
+# 2. 处理后续消息
+@client.on_message
+async def handle_message(msg):
+    if "core模块" in msg['content']:
+        # 执行分析
+        result = await analyze_module("core")
+
+        # 返回结果并询问
+        await client.send_message(
+            msg['session_id'],
+            f"core模块使用了{result['architecture']}架构,需要我详细说明吗?"
+        )
+
+    elif "详细说明" in msg['content']:
+        # 深度分析
+        details = await deep_analyze("core")
+        await client.send_message(
+            msg['session_id'],
+            f"详细架构:\n{details}"
+        )
+```
+
+## 总结
+
+### 推荐方案:混合模式
+
+**对话层(Session):**
+- 轻量级消息路由
+- WebSocket连接管理
+- 简单问答直接转发
+
+**执行层(Trace):**
+- 复杂任务创建Trace
+- 复用所有现有能力
+- 结果自动集成到对话
+
+### 关键优势
+
+1. **灵活** - 简单消息不需要Trace开销
+2. **强大** - 复杂任务复用Trace能力
+3. **清晰** - 对话和执行分层
+4. **高效** - 避免不必要的资源消耗
+
+### 实现优先级
+
+1. **Phase 1** - 基础Session + 简单消息(MVP)
+2. **Phase 2** - 集成Trace执行(核心能力)
+3. **Phase 3** - 高级功能(按需)
+

+ 640 - 0
docs/research/a2a-cross-device.md

@@ -0,0 +1,640 @@
+# Agent2Agent 跨设备通信方案
+
+**更新日期:** 2026-03-03
+
+## 场景分类
+
+### 场景1:云端Agent ↔ 云端Agent
+**示例:** 通用助理 → 爬虫运维Agent
+- **部署:** 同一服务器/进程
+- **通信:** 现有`agent`工具(内存调用)
+- **不需要HTTP接口**
+
+### 场景2:云端Agent ↔ 终端Agent ⭐
+**示例:**
+- 云端通用助理 → 用户笔记本上的代码分析Agent
+- 用户终端Agent → 云端知识库Agent
+
+**需求:**
+- 云端Agent需要调用终端Agent的能力
+  - 访问用户本地文件
+  - 执行本地命令
+  - 使用本地工具(IDE、浏览器等)
+- 终端Agent需要调用云端Agent
+  - 访问组织知识库
+  - 查询共享资源
+  - 协作任务
+
+**挑战:**
+- 网络连接(终端可能在NAT后)
+- 认证和授权
+- 数据安全
+
+**需要HTTP接口!**
+
+### 场景3:终端Agent ↔ 终端Agent
+**示例:** 团队成员的Agent互相协作
+- **可能性:** 较小,但可能存在
+- **通信:** 通过云端中转或P2P
+
+## 架构方案
+
+### 方案A:基于现有API封装(推荐)
+
+#### 架构图
+```
+云端Agent                    终端Agent
+    |                            |
+    | HTTP POST /api/a2a/call    |
+    |--------------------------->|
+    |                            |
+    |    创建Trace + 执行任务     |
+    |                            |
+    | WebSocket /api/a2a/watch   |
+    |<---------------------------|
+    |    实时进度推送              |
+    |                            |
+    | HTTP GET /api/a2a/result   |
+    |--------------------------->|
+    |    返回最终结果              |
+    |<---------------------------|
+```
+
+#### 核心设计
+
+**1. 简化的A2A端点**
+
+```python
+# agent/api/a2a.py
+
+@app.post("/api/a2a/call")
+async def a2a_call(request: A2ACallRequest):
+    """
+    简化的Agent调用接口
+
+    请求:
+    {
+        "task": "分析这个项目的架构",
+        "agent_type": "explore",  # 可选
+        "context": {              # 可选
+            "files": [...],
+            "previous_results": {...}
+        },
+        "callback_url": "https://..."  # 可选,完成后回调
+    }
+
+    响应:
+    {
+        "call_id": "a2a-xxx",
+        "status": "started",
+        "watch_url": "ws://host/api/a2a/watch/a2a-xxx"
+    }
+    """
+    # 1. 认证和授权检查
+    # 2. 转换为内部格式
+    messages = [{"role": "user", "content": request.task}]
+    if request.context:
+        messages[0]["content"] += f"\n\n上下文:{json.dumps(request.context)}"
+
+    # 3. 调用现有runner(复用所有逻辑)
+    config = RunConfig(
+        agent_type=request.agent_type or "default",
+        trace_id=None  # 新建
+    )
+
+    # 4. 后台执行
+    task_id = await start_background_task(runner.run(messages, config))
+
+    # 5. 返回call_id(映射到trace_id)
+    return {
+        "call_id": f"a2a-{task_id}",
+        "status": "started",
+        "watch_url": f"ws://{host}/api/a2a/watch/{task_id}"
+    }
+
+
+@app.websocket("/api/a2a/watch/{call_id}")
+async def a2a_watch(websocket: WebSocket, call_id: str):
+    """
+    实时监听执行进度(复用现有WebSocket)
+
+    推送消息:
+    {
+        "type": "progress",
+        "data": {
+            "goal": "正在分析文件结构",
+            "progress": 0.3
+        }
+    }
+
+    {
+        "type": "completed",
+        "data": {
+            "result": "...",
+            "stats": {...}
+        }
+    }
+    """
+    # 复用现有的 /api/traces/{id}/watch 逻辑
+    trace_id = call_id.replace("a2a-", "")
+    await watch_trace(websocket, trace_id)
+
+
+@app.get("/api/a2a/result/{call_id}")
+async def a2a_result(call_id: str):
+    """
+    获取执行结果
+
+    响应:
+    {
+        "status": "completed",
+        "result": {
+            "summary": "...",
+            "details": {...}
+        },
+        "stats": {
+            "duration_ms": 5000,
+            "tokens": 1500,
+            "cost": 0.05
+        }
+    }
+    """
+    trace_id = call_id.replace("a2a-", "")
+    trace = await store.get_trace(trace_id)
+    messages = await store.get_main_path_messages(trace_id, trace.head_sequence)
+
+    # 提取最后的assistant消息作为结果
+    result = extract_final_result(messages)
+
+    return {
+        "status": trace.status,
+        "result": result,
+        "stats": {
+            "duration_ms": trace.total_duration_ms,
+            "tokens": trace.total_tokens,
+            "cost": trace.total_cost
+        }
+    }
+```
+
+**2. 客户端SDK(终端Agent使用)**
+
+```python
+# agent/client/a2a_client.py
+
+class A2AClient:
+    """A2A客户端,用于调用远程Agent"""
+
+    def __init__(self, base_url: str, api_key: str):
+        self.base_url = base_url
+        self.api_key = api_key
+
+    async def call(
+        self,
+        task: str,
+        agent_type: Optional[str] = None,
+        context: Optional[dict] = None,
+        wait: bool = True
+    ) -> Dict[str, Any]:
+        """
+        调用远程Agent
+
+        Args:
+            task: 任务描述
+            agent_type: Agent类型
+            context: 上下文信息
+            wait: 是否等待完成(False则立即返回call_id)
+        """
+        # 1. 发起调用
+        response = await self._post("/api/a2a/call", {
+            "task": task,
+            "agent_type": agent_type,
+            "context": context
+        })
+
+        call_id = response["call_id"]
+
+        if not wait:
+            return {"call_id": call_id, "status": "started"}
+
+        # 2. 等待完成(通过WebSocket或轮询)
+        result = await self._wait_for_completion(call_id)
+        return result
+
+    async def _wait_for_completion(self, call_id: str):
+        """通过WebSocket监听完成"""
+        async with websockets.connect(
+            f"{self.ws_url}/api/a2a/watch/{call_id}",
+            extra_headers={"Authorization": f"Bearer {self.api_key}"}
+        ) as ws:
+            async for message in ws:
+                data = json.loads(message)
+                if data["type"] == "completed":
+                    return data["data"]
+                elif data["type"] == "failed":
+                    raise A2AError(data["data"]["error"])
+
+    async def get_result(self, call_id: str) -> Dict[str, Any]:
+        """获取执行结果(轮询方式)"""
+        return await self._get(f"/api/a2a/result/{call_id}")
+```
+
+**3. 作为工具集成到Agent**
+
+```python
+# agent/tools/builtin/remote_agent.py
+
+@tool(description="调用远程Agent执行任务")
+async def remote_agent(
+    task: str,
+    agent_url: str,
+    agent_type: Optional[str] = None,
+    context: Optional[dict] = None,
+    ctx: ToolContext = None
+) -> ToolResult:
+    """
+    调用远程Agent(云端或其他终端)
+
+    Args:
+        task: 任务描述
+        agent_url: 远程Agent的URL
+        agent_type: Agent类型
+        context: 上下文信息
+    """
+    # 1. 创建客户端
+    client = A2AClient(
+        base_url=agent_url,
+        api_key=ctx.config.get("remote_agent_api_key")
+    )
+
+    # 2. 调用远程Agent
+    result = await client.call(
+        task=task,
+        agent_type=agent_type,
+        context=context,
+        wait=True
+    )
+
+    # 3. 返回结果
+    return ToolResult(
+        title=f"远程Agent完成: {task[:50]}",
+        output=result["result"]["summary"],
+        long_term_memory=f"调用远程Agent完成任务,耗时{result['stats']['duration_ms']}ms"
+    )
+```
+
+#### 优势
+
+1. **复用现有逻辑** - 所有Trace、Message、Goal管理都复用
+2. **简单易用** - 外部只需要提供task,不需要理解Trace概念
+3. **完整功能** - 继承所有现有能力(压缩、续跑、回溯等)
+4. **渐进式** - 可以先实现基础版本,逐步增强
+
+### 方案B:实现标准A2A协议
+
+#### 架构
+
+```python
+# agent/api/a2a_standard.py
+
+@app.post("/api/a2a/v1/tasks")
+async def create_task(request: A2ATaskRequest):
+    """
+    符合Google A2A协议的端点
+
+    请求格式(A2A标准):
+    {
+        "header": {
+            "message_id": "msg_001",
+            "timestamp": "2026-03-03T10:30:00Z"
+        },
+        "task": {
+            "description": "分析项目架构",
+            "capabilities_required": ["file_read", "code_analysis"]
+        },
+        "context": {...}
+    }
+    """
+    # 转换A2A格式到内部格式
+    # 调用runner
+    # 转换结果为A2A格式
+```
+
+#### 优势
+
+1. **标准化** - 符合行业标准
+2. **互操作性** - 可以与其他A2A兼容的Agent通信
+3. **未来兼容** - 跟随行业发展
+
+#### 劣势
+
+1. **复杂度高** - 需要实现完整的A2A协议
+2. **过度设计** - MVP阶段可能不需要
+3. **标准未稳定** - A2A协议还在演进中
+
+## 网络拓扑
+
+### 拓扑1:云端中心化
+
+```
+        云端Gateway
+            |
+    +-------+-------+
+    |       |       |
+  通用    爬虫    成本
+  助理    运维    统计
+    |
+    +-- 调用终端Agent(HTTP)
+            |
+        用户终端Agent
+```
+
+**特点:**
+- 云端Agent作为中心
+- 终端Agent需要暴露HTTP端点
+- 需要处理NAT穿透
+
+### 拓扑2:终端主动连接
+
+```
+用户终端Agent
+    |
+    | WebSocket长连接
+    |
+云端Gateway
+    |
+    +-- 通过连接推送任务
+```
+
+**特点:**
+- 终端Agent主动连接云端
+- 云端通过WebSocket推送任务
+- 无需NAT穿透
+- 类似飞书Bot的模式
+
+### 拓扑3:混合模式(推荐)
+
+```
+云端Agent <--HTTP--> 云端Agent(内存调用)
+    |
+    | WebSocket双向
+    |
+终端Agent <--HTTP--> 终端Agent(如果需要)
+```
+
+**特点:**
+- 云端Agent间用内存调用
+- 云端↔终端用WebSocket
+- 终端间可选HTTP(通过云端中转)
+
+## 认证和授权
+
+### 1. API Key认证
+
+```python
+# 终端Agent启动时注册
+POST /api/a2a/register
+{
+    "agent_id": "user123-laptop",
+    "capabilities": ["file_read", "bash", "browser"],
+    "device_info": {...}
+}
+
+# 返回API Key
+{
+    "api_key": "ak_xxx",
+    "agent_id": "user123-laptop"
+}
+
+# 后续调用携带API Key
+Authorization: Bearer ak_xxx
+```
+
+### 2. 权限控制
+
+```yaml
+# config/a2a_permissions.yaml
+agents:
+  user123-laptop:
+    can_access:
+      - conversations/user123/*
+      - resources/public/*
+    cannot_access:
+      - conversations/other_users/*
+      - agents/*/memory/*
+```
+
+### 3. 数据隔离
+
+- 终端Agent只能访问自己用户的数据
+- 云端Agent可以访问组织共享数据
+- 通过Gateway强制执行
+
+## 实现路线图
+
+### Phase 1:基础A2A接口(MVP)
+
+**目标:** 云端Agent ↔ 终端Agent基础通信
+
+**实现:**
+1. `/api/a2a/call` - 简化调用接口
+2. `/api/a2a/watch` - WebSocket监听
+3. `/api/a2a/result` - 获取结果
+4. `A2AClient` - 客户端SDK
+5. `remote_agent` - 工具集成
+
+**时间:** 1-2周
+
+### Phase 2:增强功能
+
+**目标:** 完善A2A能力
+
+**实现:**
+1. 认证和授权
+2. 数据隔离
+3. 成本控制
+4. 审计日志
+5. 错误处理和重试
+
+**时间:** 2-3周
+
+### Phase 3:标准化(可选)
+
+**目标:** 兼容A2A标准协议
+
+**实现:**
+1. 实现Google A2A协议
+2. 能力协商机制
+3. 与其他A2A Agent互操作
+
+**时间:** 3-4周
+
+## 示例场景
+
+### 场景:云端助理调用终端Agent分析代码
+
+**1. 用户在飞书问:** "帮我分析一下我笔记本上的项目架构"
+
+**2. 云端通用助理:**
+```python
+# 识别需要访问用户终端
+result = await remote_agent(
+    task="分析 /Users/sunlit/Code/Agent 的项目架构",
+    agent_url="https://user123-laptop.agent.local",
+    agent_type="explore"
+)
+```
+
+**3. 终端Agent:**
+- 接收任务
+- 创建本地Trace
+- 使用本地工具(read, glob, grep)
+- 分析代码结构
+- 返回结果
+
+**4. 云端助理:**
+- 接收终端Agent结果
+- 整合到回复中
+- 通过飞书返回给用户
+
+### 场景:终端Agent查询云端知识库
+
+**1. 用户在终端运行:**
+```bash
+agent-cli ask "公司的爬虫部署规范是什么?"
+```
+
+**2. 终端Agent:**
+```python
+# 识别需要查询组织知识库
+result = await remote_agent(
+    task="查询爬虫部署规范",
+    agent_url="https://org.agent.cloud",
+    agent_type="knowledge_query"
+)
+```
+
+**3. 云端知识库Agent:**
+- 查询resources/docs/
+- 查询experiences数据库
+- 返回相关文档
+
+**4. 终端Agent:**
+- 接收结果
+- 展示给用户
+
+## 技术细节
+
+### 1. NAT穿透方案
+
+**方案A:终端主动连接(推荐)**
+```python
+# 终端Agent启动时建立WebSocket长连接
+ws = await websockets.connect("wss://org.agent.cloud/api/a2a/connect")
+
+# 云端通过连接推送任务
+await ws.send(json.dumps({
+    "type": "task",
+    "task_id": "xxx",
+    "data": {...}
+}))
+
+# 终端执行并返回结果
+result = await execute_task(task)
+await ws.send(json.dumps({
+    "type": "result",
+    "task_id": "xxx",
+    "data": result
+}))
+```
+
+**方案B:使用ngrok等隧道服务**
+- 终端Agent启动时创建隧道
+- 注册公网URL到云端
+- 云端通过公网URL调用
+
+### 2. 消息序列化
+
+```python
+# 简化格式(内部使用)
+{
+    "task": "string",
+    "context": {...}
+}
+
+# 标准A2A格式(外部互操作)
+{
+    "header": {...},
+    "task": {...},
+    "capabilities": [...]
+}
+
+# 自动转换
+def to_a2a_format(internal_msg):
+    return {
+        "header": generate_header(),
+        "task": {"description": internal_msg["task"]},
+        "context": internal_msg.get("context", {})
+    }
+```
+
+### 3. 流式响应
+
+```python
+# 支持流式返回中间结果
+@app.websocket("/api/a2a/stream/{call_id}")
+async def a2a_stream(websocket: WebSocket, call_id: str):
+    async for event in runner.run(...):
+        if isinstance(event, Message):
+            await websocket.send_json({
+                "type": "message",
+                "data": event.to_dict()
+            })
+```
+
+## 安全考虑
+
+1. **认证:** API Key + JWT
+2. **授权:** 基于角色的访问控制
+3. **加密:** HTTPS/WSS强制
+4. **限流:** 防止滥用
+5. **审计:** 所有A2A调用记录
+6. **隔离:** 数据访问严格隔离
+
+## 成本控制
+
+```python
+# 每次A2A调用记录成本
+{
+    "call_id": "a2a-xxx",
+    "caller": "user123-laptop",
+    "callee": "org-cloud-agent",
+    "tokens": 1500,
+    "cost": 0.05,
+    "duration_ms": 5000
+}
+
+# 限额检查
+if user_cost_today > user_limit:
+    raise CostLimitExceeded()
+```
+
+## 总结
+
+### 推荐方案
+
+**Phase 1(MVP):** 方案A - 基于现有API封装
+- 简单、快速
+- 复用所有现有逻辑
+- 满足跨设备通信需求
+
+**Phase 3+:** 可选实现标准A2A协议
+- 如果需要与外部系统互操作
+- 跟随行业标准发展
+
+### 关键优势
+
+1. **复用现有能力** - Trace、Message、Goal、压缩等
+2. **渐进式实现** - 先简单后复杂
+3. **灵活扩展** - 可以逐步增强功能
+4. **标准兼容** - 未来可以支持A2A标准

+ 504 - 0
docs/research/a2a-mamp-protocol.md

@@ -0,0 +1,504 @@
+# MAMP:Minimal Agent Message Protocol
+
+**更新日期:** 2026-03-04
+
+## 设计目标
+
+实现与**其他 Agent 系统**(非本系统)的通用交互接口,保持最简化原则。
+
+**与现有方案的关系**:
+- [A2A 跨设备通信](./a2a-cross-device.md):内部 Agent 间通信(基于 Trace API)
+- **MAMP 协议**(本文档):与外部 Agent 系统的通用交互
+
+---
+
+## 核心设计原则
+
+1. **最小化协议**:只定义消息信封,不管内容格式
+2. **适配器模式**:通过适配器层与内部系统集成
+3. **松耦合**:各家 Agent 保持独立实现
+4. **渐进式**:先实现基础功能,需要时再扩展
+
+---
+
+## 消息格式
+
+### 基础消息结构
+
+```json
+{
+  "protocol": "mamp/1.0",
+  "message_id": "msg-uuid-123",
+  "conversation_id": "conv-uuid-456",
+  "from": "agent://your-domain.com/agent-123",
+  "to": "agent://other-domain.com/agent-456",
+  "content": [...],
+  "metadata": {
+    "timestamp": "2026-03-04T10:00:00Z"
+  }
+}
+```
+
+### 字段说明
+
+| 字段 | 类型 | 必需 | 说明 |
+|------|------|------|------|
+| `protocol` | string | 是 | 协议版本标识 |
+| `message_id` | string | 是 | 消息唯一标识 |
+| `conversation_id` | string | 否 | 对话标识(不提供则新建对话) |
+| `from` | string | 是 | 发送方 Agent URI |
+| `to` | string | 是 | 接收方 Agent URI |
+| `content` | string/array | 是 | 消息内容(支持多模态) |
+| `metadata` | object | 是 | 元数据(时间戳等) |
+
+### 新建 vs 续跑
+
+**规则**:通过 `conversation_id` 字段判断
+
+- **无 `conversation_id`**(null 或不存在)→ 新建对话,接收方生成并返回 conversation_id
+- **有 `conversation_id`** → 续跑对话,接收方查找对应的内部 trace_id
+
+**conversation_id 与 trace_id 的关系**:
+- `conversation_id`:跨 Agent 的对话标识符,双方共享
+- `trace_id`:每个 Agent 内部的执行记录,各自独立
+- 每个 Agent 维护 `conversation_id → trace_id` 映射
+
+---
+
+## 多模态内容格式
+
+### Content 结构
+
+参考 Anthropic SDK 和现有多模态实现(`agent/docs/multimodal.md`):
+
+```json
+{
+  "content": [
+    {
+      "type": "text",
+      "text": "这是文本内容"
+    },
+    {
+      "type": "image",
+      "source": {
+        "type": "url",
+        "url": "https://...",
+        "media_type": "image/png"
+      }
+    },
+    {
+      "type": "image",
+      "source": {
+        "type": "base64",
+        "media_type": "image/jpeg",
+        "data": "base64..."
+      }
+    },
+    {
+      "type": "code",
+      "language": "python",
+      "code": "def hello(): pass"
+    },
+    {
+      "type": "file",
+      "name": "report.pdf",
+      "mime_type": "application/pdf",
+      "source": {
+        "type": "url",
+        "url": "https://..."
+      }
+    }
+  ]
+}
+```
+
+### 纯文本简写
+
+```json
+{
+  "content": "纯文本消息"
+}
+```
+
+等价于:
+
+```json
+{
+  "content": [{"type": "text", "text": "纯文本消息"}]
+}
+```
+
+---
+
+## Agent Card(身份与能力)
+
+每个 Agent 提供静态的 card 端点,用于身份识别和能力发现。
+
+### 端点
+
+```
+GET https://your-agent.com/mamp/v1/card
+```
+
+### 响应格式
+
+```json
+{
+  "protocol": "mamp/1.0",
+  "agent_id": "agent://your-domain.com/agent-123",
+  "name": "Code Analyst",
+  "description": "专注于代码分析的 Agent",
+
+  "owner": {
+    "user_id": "user-789",
+    "user_name": "张三",
+    "organization": "YourCompany"
+  },
+
+  "device": {
+    "device_id": "device-mac-001",
+    "device_name": "MacBook Pro",
+    "location": "Beijing Office",
+    "platform": "darwin"
+  },
+
+  "capabilities": {
+    "content_types": ["text", "image", "code"],
+    "max_message_size": 10485760,
+    "streaming": true,
+    "async": true,
+    "tools": ["code_analysis", "file_read", "web_search"]
+  },
+
+  "access": {
+    "public": false,
+    "allowed_agents": ["agent://trusted.com/*"],
+    "require_auth": true
+  }
+}
+```
+
+---
+
+## 传输层
+
+### HTTP REST(最简实现)
+
+**发送消息**:
+
+```http
+POST https://other-agent.com/mamp/v1/messages
+Content-Type: application/json
+Authorization: Bearer {api_key}
+
+{MAMP 消息体}
+```
+
+**响应**:
+
+```json
+{
+  "conversation_id": "conv-abc-123",
+  "message_id": "msg-xyz-456",
+  "status": "received"
+}
+```
+
+**错误响应**:
+
+```json
+{
+  "error": "conversation_not_found",
+  "message": "Conversation conv-xxx not found",
+  "status_code": 404
+}
+```
+
+### 可选扩展
+
+- **WebSocket**:实时双向通信
+- **Server-Sent Events**:流式响应
+- **Message Queue**:异步消息(NATS/Redis)
+
+---
+
+## 寻址方案
+
+使用 URI 格式:`agent://domain/agent-id`
+
+**示例**:
+- `agent://your-domain.com/trace-123` - 你的 Agent
+- `agent://claude.ai/session-456` - Claude
+- `agent://openai.com/assistant-789` - OpenAI Assistant
+
+每个 Agent 系统自己决定如何解析 `agent-id` 部分。
+
+---
+
+## 系统集成
+
+### 三层架构
+
+```
+┌─────────────────────────────────────────────────┐
+│ Layer 3: 内部 Agent 逻辑                         │
+│ (Trace, Goal, Messages...)                      │
+└─────────────────────────────────────────────────┘
+                    ↕
+┌─────────────────────────────────────────────────┐
+│ Layer 2: MAMP 适配器                             │
+│ - 内部格式 ↔ MAMP 格式转换                        │
+│ - conversation_id ↔ trace_id 映射                │
+└─────────────────────────────────────────────────┘
+                    ↕
+┌─────────────────────────────────────────────────┐
+│ Layer 1: 传输层(HTTP/WebSocket/MQ)             │
+└─────────────────────────────────────────────────┘
+```
+
+### 接收端实现
+
+**实现位置**:`agent/trace/mamp_api.py`
+
+```python
+@app.post("/mamp/v1/messages")
+async def receive_mamp_message(msg: dict):
+    """接收外部 Agent 的 MAMP 消息"""
+
+    conv_id = msg.get("conversation_id")
+
+    if not conv_id:
+        # 新建对话
+        conv_id = f"conv-{generate_uuid()}"
+
+        # 创建新 Trace
+        async for item in runner.run(
+            messages=[{"role": "user", "content": msg["content"]}],
+            config=RunConfig(
+                context={
+                    "mamp_conversation_id": conv_id,
+                    "mamp_from": msg["from"]
+                }
+            )
+        ):
+            if isinstance(item, Trace):
+                await store_conversation_mapping(conv_id, item.trace_id)
+
+        return {
+            "conversation_id": conv_id,
+            "message_id": msg["message_id"],
+            "status": "received"
+        }
+
+    else:
+        # 续跑对话
+        trace_id = await get_trace_by_conversation_id(conv_id)
+        if not trace_id:
+            raise HTTPException(404, f"Conversation {conv_id} not found")
+
+        await runner.run(
+            messages=[{"role": "user", "content": msg["content"]}],
+            config=RunConfig(trace_id=trace_id)
+        )
+
+        return {
+            "conversation_id": conv_id,
+            "message_id": msg["message_id"],
+            "status": "received"
+        }
+```
+
+### 发送端实现
+
+**实现位置**:`agent/tools/builtin/mamp_adapter.py`
+
+```python
+@tool(description="与外部 Agent 通信")
+async def send_to_agent(
+    target_agent: str,
+    message: str,
+    conversation_id: Optional[str] = None,
+    ctx: ToolContext = None
+) -> ToolResult:
+    """
+    发送消息到外部 Agent
+
+    Args:
+        target_agent: 目标 Agent URI (agent://domain/id)
+        message: 消息内容
+        conversation_id: 对话 ID(可选,不提供则新建)
+    """
+
+    # 构建 MAMP 消息
+    mamp_msg = {
+        "protocol": "mamp/1.0",
+        "message_id": generate_uuid(),
+        "from": f"agent://{config.domain}/{ctx.trace_id}",
+        "to": target_agent,
+        "content": message,
+        "metadata": {"timestamp": datetime.now().isoformat()}
+    }
+
+    if conversation_id:
+        mamp_msg["conversation_id"] = conversation_id
+
+    # 发送
+    agent_url = parse_agent_url(target_agent)
+    response = await http_post(f"{agent_url}/mamp/v1/messages", mamp_msg)
+
+    # 新建时存储映射
+    if not conversation_id:
+        await store_conversation_mapping(
+            response["conversation_id"],
+            ctx.trace_id
+        )
+
+    return ToolResult(
+        title=f"已发送到 {target_agent}",
+        output=f"Conversation ID: {response['conversation_id']}",
+        long_term_memory=f"与 {target_agent} 的对话 {response['conversation_id']}"
+    )
+```
+
+### conversation_id 映射存储
+
+**实现位置**:`agent/trace/conversation_store.py`
+
+```python
+class ConversationStore:
+    """管理 MAMP conversation_id 和内部 trace_id 的映射"""
+
+    def __init__(self, base_dir: str = ".trace"):
+        self.mapping_file = Path(base_dir) / "mamp_conversations.json"
+
+    async def store_mapping(self, conversation_id: str, trace_id: str):
+        """存储映射关系"""
+        mappings = await self._load_mappings()
+        mappings[conversation_id] = {
+            "trace_id": trace_id,
+            "created_at": datetime.now().isoformat(),
+            "last_message_at": datetime.now().isoformat()
+        }
+        await self._save_mappings(mappings)
+
+    async def get_trace_id(self, conversation_id: str) -> Optional[str]:
+        """根据 conversation_id 查找 trace_id"""
+        mappings = await self._load_mappings()
+        mapping = mappings.get(conversation_id)
+        return mapping["trace_id"] if mapping else None
+```
+
+---
+
+## 使用示例
+
+### 新建对话
+
+```python
+# 调用外部 Agent
+result = await send_to_agent(
+    target_agent="agent://other.com/code-analyst",
+    message="帮我分析这段代码的性能"
+)
+# 返回: {"conversation_id": "conv-abc-123", ...}
+```
+
+### 续跑对话
+
+```python
+# 继续之前的对话
+result = await send_to_agent(
+    target_agent="agent://other.com/code-analyst",
+    message="那如果用异步方案呢?",
+    conversation_id="conv-abc-123"
+)
+```
+
+### 多模态消息
+
+```python
+# 发送图片
+result = await send_to_agent(
+    target_agent="agent://other.com/image-analyst",
+    message={
+        "content": [
+            {"type": "text", "text": "分析这张图片"},
+            {
+                "type": "image",
+                "source": {
+                    "type": "base64",
+                    "media_type": "image/png",
+                    "data": encode_image_base64("screenshot.png")
+                }
+            }
+        ]
+    }
+)
+```
+
+---
+
+## 与现有标准的关系
+
+MAMP 可以作为其他标准的"翻译层":
+
+- **MCP (Model Context Protocol)** → 写 MCP ↔ MAMP 适配器
+- **OpenAI Assistant API** → 写 OpenAI ↔ MAMP 适配器
+- **自定义协议** → 写对应的适配器
+
+**核心思想**:不要试图统一所有 Agent 的内部实现,而是提供一个最薄的互操作层。
+
+---
+
+## 可选扩展
+
+如果需要更丰富的功能,可以逐步添加:
+
+- **认证**:在 metadata 中加 `auth_token`
+- **流式传输**:使用 Server-Sent Events 或 WebSocket
+- **异步回调**:加 `callback_url` 字段
+- **能力协商**:通过 `/mamp/v1/card` 端点
+- **错误处理**:标准化错误码
+
+---
+
+## 实现路线图
+
+### Phase 1:基础协议(1-2 周)
+
+**目标**:实现最简 MAMP 协议
+
+**任务**:
+1. 实现 `/mamp/v1/messages` 端点(接收消息)
+2. 实现 `/mamp/v1/card` 端点(Agent 身份)
+3. 实现 `send_to_agent` 工具(发送消息)
+4. 实现 `ConversationStore`(映射管理)
+5. 支持纯文本消息
+
+### Phase 2:多模态支持(1 周)
+
+**目标**:支持图片、代码等多模态内容
+
+**任务**:
+1. 扩展 content 格式处理
+2. 集成现有多模态实现(`agent/llm/prompts/wrapper.py`)
+3. 支持 base64 和 URL 两种图片传输方式
+
+### Phase 3:增强功能(可选)
+
+**目标**:认证、流式、异步等高级功能
+
+**任务**:
+1. API Key 认证
+2. WebSocket 流式传输
+3. 异步回调机制
+4. 错误处理和重试
+
+---
+
+## 相关文档
+
+- [A2A 跨设备通信](./a2a-cross-device.md):内部 Agent 间通信方案
+- [多模态支持](../../agent/docs/multimodal.md):图片、PDF 处理
+- [工具系统](../../agent/docs/tools.md):工具定义、注册
+- [Agent 框架](../README.md):核心 Agent 能力

+ 114 - 0
docs/research/a2a-protocols.md

@@ -0,0 +1,114 @@
+# Agent2Agent (A2A) 通信协议调研
+
+**调研日期:** 2026-03-03
+
+## 一、行业标准协议
+
+### 1. Google A2A Protocol (2025.04)
+- **定位:** Agent间任务协调和协作
+- **特性:** 标准化消息格式、能力协商、异步通信
+- **适用:** 企业级跨平台Agent协作
+
+### 2. Anthropic MCP (2024.11)
+- **定位:** AI助手与工具/数据系统连接
+- **特性:** JSON-RPC 2.0、即插即用工具
+- **适用:** Agent与工具交互(非Agent间通信)
+- **采用:** OpenAI (2025.03)、Google DeepMind
+
+### 3. IBM ACP (2025初)
+- **定位:** 基于HTTP的Agent消息传递
+- **特性:** 消息代理(Kafka/RabbitMQ)、会话跟踪
+- **适用:** 生产级系统的模块化和可追溯性
+
+### 4. Huawei A2A-T (2026.03开源)
+- **定位:** A2A协议的扩展实现
+- **状态:** 刚开源,推动标准应用
+
+## 二、主流框架实现
+
+### AutoGen (Microsoft)
+- **通信模式:** 对话式多Agent协作
+- **核心:** ConversableAgent + GroupChat
+- **消息管理:** 每个Agent维护对话历史,GroupChat维护全局记录
+- **特点:** 自然语言驱动、支持人机协作
+
+### LangGraph (LangChain)
+- **通信模式:** 基于状态图的消息传递
+- **核心:** State Graph + Persistent State + Message Bus
+- **消息管理:** 状态图管理 + 检查点机制
+- **特点:** 生产级、可追溯、原生支持A2A协议
+
+### CrewAI
+- **通信模式:** 基于角色的任务委派
+- **核心:** Role-Based Agents + Task Delegation + Crew Coordination
+- **消息管理:** Crew级任务历史 + 委派记录
+- **特点:** 类似人类团队、层次化任务分配
+
+## 三、通信模式对比
+
+| 模式 | 优点 | 缺点 | 适用场景 |
+|------|------|------|----------|
+| **直接调用** | 简单、低延迟 | 紧耦合、难扩展 | 小规模简单协作 |
+| **消息队列** | 解耦、异步、可靠 | 复杂、需基础设施 | 企业级大规模系统 |
+| **共享状态** | 知识全局可见、紧密协调 | 并发控制、状态冲突 | 高度协同团队 |
+| **混合模式** | 灵活、可优化 | 架构复杂 | 复杂生产系统 |
+
+## 四、消息历史管理策略
+
+1. **滑动窗口:** 保留最近N条消息
+2. **智能截断:** 基于重要性评分删除
+3. **自动总结:** 接近限制时总结历史(Claude Code使用)
+4. **分层存储:** 短期完整 + 长期总结
+5. **溢出修剪:** 从最旧消息开始修剪
+
+## 五、关键挑战
+
+### 1. 消息历史维护
+- 上下文窗口限制
+- 需要智能压缩策略
+- 跨Agent的上下文共享
+
+### 2. 异步通信
+- 事件驱动架构
+- 回调机制
+- 状态更新和轮询
+
+### 3. 多Agent协作复杂性
+- 协调模式(集中式 vs 去中心化)
+- 冲突解决
+- 死锁预防
+- 可观测性
+
+## 六、标准化趋势
+
+**当前状态(2024-2026):**
+- 协议层分化:MCP(工具层)、A2A(协作层)、ACP(传输层)
+- 行业共识形成中:Google、OpenAI、Anthropic、IBM、Huawei推动
+- 互操作性是关键
+
+**未来展望:**
+- 2026-2027:协议标准逐步成熟
+- 2028-2030:可能出现统一标准
+- 长期:Agent网络成为基础设施
+
+## 七、实践建议
+
+### 架构设计
+1. **分层设计:** 工具层(MCP)+ 协作层(A2A)+ 传输层(ACP)
+2. **消息管理:** 自动总结 + 分层存储
+3. **异步处理:** 事件驱动 + 超时重试
+4. **可观测性:** 结构化日志 + 分布式追踪
+
+### 选择建议
+- **小规模:** AutoGen、CrewAI
+- **大规模:** LangGraph + ACP/A2A
+- **工具集成:** 优先MCP
+- **Agent协作:** 优先A2A
+
+## 参考资料
+
+- [Google A2A Protocol](https://a2a-protocol.org/latest/specification/)
+- [Anthropic MCP](https://modelcontextprotocol.io/specification/2025-06-18)
+- [Huawei A2A-T](https://www.huawei.com/en/news/2026/2/mwc-a2at-opensource)
+- [Agent Interoperability Survey](https://arxiv.org/html/2505.02279v1)
+- [Framework Comparison 2026](https://markaicode.com/crewai-vs-autogen-vs-langgraph-2026/)

+ 484 - 0
docs/research/a2a-trace-storage.md

@@ -0,0 +1,484 @@
+# A2A跨设备Trace存储方案
+
+**问题:** 现有Trace存储在本地文件系统,跨设备时如何访问?
+
+## 场景分析
+
+### 场景1:云端Agent调用终端Agent
+
+```
+云端Agent (云端存储)
+    ↓ 调用
+终端Agent (终端存储)
+    ↓ 返回 sub_trace_id
+云端Agent 想 continue_from sub_trace_id
+    ↓ 问题:sub_trace在终端,云端访问不到!
+```
+
+### 场景2:终端Agent调用云端Agent
+
+```
+终端Agent (终端存储)
+    ↓ 调用
+云端Agent (云端存储)
+    ↓ 返回 sub_trace_id
+终端Agent 想 continue_from sub_trace_id
+    ↓ 问题:sub_trace在云端,终端访问不到!
+```
+
+## 方案对比
+
+### 方案1:远程Trace访问(推荐)
+
+#### 核心思想
+
+**Trace ID包含位置信息,通过HTTP API访问远程Trace**
+
+#### Trace ID格式
+
+```
+本地Trace: abc-123
+远程Trace: agent://terminal-agent-456/abc-123
+          ^^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^
+          协议      Agent地址          本地ID
+```
+
+#### 实现
+
+```python
+# agent/trace/remote_store.py
+
+class RemoteTraceStore:
+    """远程Trace存储代理"""
+
+    def __init__(self, agent_url: str, api_key: str):
+        self.agent_url = agent_url
+        self.api_key = api_key
+
+    async def get_trace(self, trace_id: str) -> Optional[Trace]:
+        """通过HTTP API获取远程Trace"""
+        response = await self._get(f"/api/traces/{trace_id}")
+        if response:
+            return Trace(**response)
+        return None
+
+    async def get_main_path_messages(
+        self, trace_id: str, head_sequence: int
+    ) -> List[Message]:
+        """获取远程Trace的消息"""
+        response = await self._get(
+            f"/api/traces/{trace_id}/messages",
+            params={"mode": "main_path", "head_sequence": head_sequence}
+        )
+        return [Message(**m) for m in response["messages"]]
+
+    async def add_message(self, message: Message) -> str:
+        """向远程Trace追加消息(续跑)"""
+        response = await self._post(
+            f"/api/traces/{message.trace_id}/messages",
+            data=message.to_dict()
+        )
+        return response["message_id"]
+
+
+# agent/trace/hybrid_store.py
+
+class HybridTraceStore:
+    """混合存储:本地 + 远程"""
+
+    def __init__(self, local_store: FileSystemTraceStore):
+        self.local_store = local_store
+        self.remote_stores = {}  # agent_url -> RemoteTraceStore
+
+    def _parse_trace_id(self, trace_id: str) -> tuple[str, str]:
+        """
+        解析Trace ID
+
+        返回: (location, local_id)
+        - location: "local" 或 agent_url
+        - local_id: 本地Trace ID
+        """
+        if trace_id.startswith("agent://"):
+            # agent://terminal-agent-456/abc-123
+            parts = trace_id[8:].split("/", 1)
+            return parts[0], parts[1]
+        else:
+            return "local", trace_id
+
+    async def get_trace(self, trace_id: str) -> Optional[Trace]:
+        """获取Trace(自动路由到本地或远程)"""
+        location, local_id = self._parse_trace_id(trace_id)
+
+        if location == "local":
+            return await self.local_store.get_trace(local_id)
+        else:
+            # 远程Trace
+            if location not in self.remote_stores:
+                # 创建远程存储代理
+                self.remote_stores[location] = RemoteTraceStore(
+                    agent_url=f"https://{location}",
+                    api_key=self._get_api_key(location)
+                )
+            return await self.remote_stores[location].get_trace(local_id)
+
+    async def add_message(self, message: Message) -> str:
+        """添加消息(自动路由)"""
+        location, local_id = self._parse_trace_id(message.trace_id)
+
+        if location == "local":
+            return await self.local_store.add_message(message)
+        else:
+            # 向远程Trace追加消息
+            return await self.remote_stores[location].add_message(message)
+```
+
+#### agent工具修改
+
+```python
+@tool(description="创建 Agent 执行任务")
+async def agent(
+    task: Union[str, List[str]],
+    continue_from: Optional[str] = None,  # 支持远程Trace ID
+    agent_url: Optional[str] = None,      # 新增:远程Agent地址
+    context: Optional[dict] = None,
+) -> Dict[str, Any]:
+    """
+    创建 Agent 执行任务
+
+    Args:
+        task: 任务描述
+        continue_from: 继续已有trace(支持远程Trace ID)
+        agent_url: 远程Agent地址(如果调用远程Agent)
+        context: 框架注入的上下文
+    """
+    store = context.get("store")  # HybridTraceStore
+
+    if agent_url:
+        # 调用远程Agent
+        result = await _call_remote_agent(agent_url, task, continue_from)
+        # 返回远程Trace ID
+        remote_trace_id = f"agent://{agent_url}/{result['sub_trace_id']}"
+        return {
+            **result,
+            "sub_trace_id": remote_trace_id,
+            "remote": True
+        }
+    else:
+        # 本地执行(现有逻辑)
+        if continue_from:
+            # 可能是远程Trace,HybridStore会自动处理
+            existing = await store.get_trace(continue_from)
+            if not existing:
+                return {"status": "failed", "error": "Trace not found"}
+
+        # ... 现有逻辑
+```
+
+#### 使用示例
+
+```python
+# 云端Agent调用终端Agent
+result1 = await agent(
+    task="分析本地项目",
+    agent_url="terminal-agent-456.local"
+)
+# 返回: {"sub_trace_id": "agent://terminal-agent-456.local/abc-123"}
+
+# 继续对话(自动访问远程Trace)
+result2 = await agent(
+    task="重点分析core模块",
+    continue_from=result1["sub_trace_id"],  # 远程Trace ID
+    agent_url="terminal-agent-456.local"
+)
+# HybridStore自动通过HTTP API访问远程Trace
+```
+
+#### 优势
+
+1. **透明** - Agent不需要关心Trace在哪里
+2. **灵活** - 支持本地和远程Trace
+3. **简单** - 只需要在Trace ID中编码位置信息
+4. **兼容** - 现有本地Trace不受影响
+
+#### 劣势
+
+1. **网络延迟** - 访问远程Trace需要HTTP请求
+2. **依赖网络** - 远程Agent必须在线
+
+---
+
+### 方案2:中心化Trace存储
+
+#### 核心思想
+
+**所有Agent共享同一个Trace存储(数据库)**
+
+#### 架构
+
+```
+云端Agent ──┐
+            ├──> 中心化Trace存储(PostgreSQL/MongoDB)
+终端Agent ──┘
+```
+
+#### 实现
+
+```python
+# agent/trace/db_store.py
+
+class DatabaseTraceStore:
+    """数据库Trace存储"""
+
+    def __init__(self, db_url: str):
+        self.db = connect(db_url)
+
+    async def create_trace(self, trace: Trace) -> str:
+        await self.db.traces.insert_one(trace.to_dict())
+        return trace.trace_id
+
+    async def get_trace(self, trace_id: str) -> Optional[Trace]:
+        doc = await self.db.traces.find_one({"trace_id": trace_id})
+        if doc:
+            return Trace(**doc)
+        return None
+
+    # ... 其他方法
+```
+
+#### 配置
+
+```yaml
+# config/storage.yaml
+trace_store:
+  type: database
+  url: postgresql://user:pass@db.cloud/traces
+  # 或
+  url: mongodb://db.cloud/traces
+```
+
+#### 优势
+
+1. **简单** - 所有Agent访问同一个存储,无需特殊处理
+2. **一致性** - 数据强一致性
+3. **查询能力** - 可以跨Trace查询和分析
+
+#### 劣势
+
+1. **依赖中心** - 需要中心化数据库
+2. **网络依赖** - 终端Agent必须能访问数据库
+3. **隐私问题** - 终端数据存储在云端
+4. **迁移成本** - 需要从文件系统迁移到数据库
+
+---
+
+### 方案3:Trace同步/缓存
+
+#### 核心思想
+
+**按需同步远程Trace到本地**
+
+#### 实现
+
+```python
+class CachedRemoteStore:
+    """带缓存的远程存储"""
+
+    def __init__(self, local_store, remote_url):
+        self.local_store = local_store
+        self.remote_url = remote_url
+        self.cache = {}  # trace_id -> Trace
+
+    async def get_trace(self, trace_id: str) -> Optional[Trace]:
+        # 1. 检查本地
+        trace = await self.local_store.get_trace(trace_id)
+        if trace:
+            return trace
+
+        # 2. 检查缓存
+        if trace_id in self.cache:
+            return self.cache[trace_id]
+
+        # 3. 从远程获取并缓存
+        trace = await self._fetch_remote(trace_id)
+        if trace:
+            self.cache[trace_id] = trace
+            # 可选:持久化到本地
+            await self.local_store.create_trace(trace)
+        return trace
+
+    async def add_message(self, message: Message) -> str:
+        # 同时写入本地和远程
+        local_id = await self.local_store.add_message(message)
+        await self._sync_to_remote(message)
+        return local_id
+```
+
+#### 优势
+
+1. **性能** - 本地缓存减少网络请求
+2. **离线能力** - 缓存后可以离线访问
+
+#### 劣势
+
+1. **一致性** - 缓存可能过期
+2. **复杂度** - 需要处理同步和冲突
+3. **存储开销** - 需要额外的本地存储
+
+---
+
+### 方案4:混合模式(推荐)
+
+#### 核心思想
+
+**结合方案1和方案2的优点**
+
+- **组织内部**:使用中心化存储(数据库)
+- **跨组织**:使用远程访问(HTTP API)
+
+#### 架构
+
+```
+组织内部:
+云端Agent ──┐
+            ├──> 组织数据库
+职能Agent ──┘
+
+跨组织:
+组织A Agent <──HTTP API──> 组织B Agent
+```
+
+#### 配置
+
+```yaml
+# config/storage.yaml
+trace_store:
+  # 组织内部使用数据库
+  internal:
+    type: database
+    url: postgresql://org-db/traces
+
+  # 跨组织使用远程访问
+  external:
+    type: remote
+    agents:
+      - url: https://partner-org.com
+        api_key: xxx
+```
+
+#### 优势
+
+1. **灵活** - 根据场景选择最优方案
+2. **性能** - 组织内部低延迟
+3. **隐私** - 跨组织数据不共享存储
+
+---
+
+## 推荐方案
+
+### MVP阶段(Phase 1-2):方案1 - 远程Trace访问
+
+**理由:**
+1. **最小改动** - 只需要添加RemoteTraceStore和HybridStore
+2. **灵活** - 支持任意拓扑
+3. **隐私友好** - 数据不离开设备
+4. **渐进式** - 可以逐步迁移到方案4
+
+**实现步骤:**
+1. 实现RemoteTraceStore(通过HTTP API访问)
+2. 实现HybridTraceStore(路由到本地或远程)
+3. 修改agent工具支持agent_url参数
+4. 在Trace ID中编码位置信息
+
+### 长期(Phase 3+):方案4 - 混合模式
+
+**理由:**
+1. **组织内部高效** - 数据库存储,低延迟
+2. **跨组织灵活** - HTTP API,保护隐私
+3. **可扩展** - 支持复杂场景
+
+## 实现细节
+
+### 1. Trace ID格式
+
+```python
+# 本地Trace
+"abc-123"
+
+# 远程Trace(完整格式)
+"agent://terminal-agent-456.local:8000/abc-123"
+
+# 远程Trace(简化格式,使用注册的agent_id)
+"@terminal-agent-456/abc-123"
+```
+
+### 2. Agent注册表
+
+```yaml
+# config/agents.yaml
+agents:
+  terminal-agent-456:
+    url: https://terminal-agent-456.local:8000
+    api_key: ak_xxx
+    type: terminal
+```
+
+### 3. API端点
+
+```python
+# 必需的API端点(用于远程访问)
+GET  /api/traces/{trace_id}                    # 获取Trace
+GET  /api/traces/{trace_id}/messages           # 获取消息
+POST /api/traces/{trace_id}/run                # 续跑
+POST /api/traces/{trace_id}/messages           # 追加消息
+```
+
+### 4. 认证和授权
+
+```python
+# 每个Agent有自己的API Key
+headers = {
+    "Authorization": f"Bearer {api_key}"
+}
+
+# 权限检查
+if trace.uid != request.user_id:
+    raise Forbidden("Cannot access other user's trace")
+```
+
+### 5. 性能优化
+
+```python
+# 批量获取消息
+GET /api/traces/{trace_id}/messages?limit=100&offset=0
+
+# 增量同步
+GET /api/traces/{trace_id}/messages?since_sequence=50
+
+# 压缩传输
+headers = {"Accept-Encoding": "gzip"}
+```
+
+## 总结
+
+**推荐路线:**
+
+1. **Phase 1(MVP)** - 实现方案1(远程Trace访问)
+   - 最小改动
+   - 快速验证跨设备A2A
+   - 2-3周
+
+2. **Phase 2** - 优化和增强
+   - 添加缓存
+   - 批量API
+   - 性能优化
+   - 2-3周
+
+3. **Phase 3(可选)** - 迁移到方案4(混合模式)
+   - 组织内部使用数据库
+   - 跨组织使用远程访问
+   - 4-6周
+
+**关键优势:**
+- 渐进式实现
+- 最小化风险
+- 保持灵活性

+ 299 - 0
gateway/README.md

@@ -0,0 +1,299 @@
+# Gateway - Agent 消息路由服务
+
+**框架无关的 Agent 间即时通讯网关**,提供 Agent 注册、消息路由、在线状态管理。
+
+## 概述
+
+Gateway 是一个任务导向的 Agent 即时通讯系统,支持任何 Agent 框架使用。核心功能:
+
+- Agent 注册和发现
+- 消息路由(WebSocket/HTTP)
+- 在线状态管理
+- 活跃协作者管理
+- 联系人管理
+
+**独立性**:Gateway 与 Agent Core 并列,可以独立部署。
+
+**依赖关系**:Gateway 依赖 Agent Core(使用 ToolContext、TraceStore 等组件)。
+
+## 设计原则
+
+1. **框架无关**:Gateway 核心不依赖任何特定的 Agent 框架
+2. **通用协议**:使用 MAMP(Minimal Agent Message Protocol)
+3. **易于集成**:提供通用的 Python SDK 和 CLI 工具
+4. **可扩展**:支持不同框架的适配和集成
+
+## 架构
+
+```
+gateway/
+├── core/              # Gateway 核心服务(框架无关)
+│   ├── registry.py    # Agent 注册和在线状态管理
+│   ├── router.py      # 消息路由
+│   └── client.py      # Gateway 客户端
+│
+├── client/            # 通用客户端工具
+│   ├── python/        # Python SDK
+│   │   ├── tools.py   # 通用工具函数
+│   │   ├── client.py  # GatewayClient
+│   │   └── cli.py     # CLI 工具
+│   └── a2a_im.md      # Agent Skill 文档
+│
+├── docs/              # 详细文档
+│   ├── architecture.md
+│   ├── deployment.md
+│   ├── api.md
+│   ├── decisions.md
+│   └── enterprise/
+│
+└── enterprise/        # 企业功能(可选)
+    ├── auth.py        # 认证和授权
+    ├── audit.py       # 审计和监控
+    └── cost.py        # 成本管理
+
+examples/gateway_integration/  # 集成示例(项目根目录)
+├── README.md
+├── python_client_example.py      # 通用 SDK 使用示例
+├── agent_tools_example.py        # Agent 框架集成示例
+└── agent_skill_example.md        # Agent 框架 Skill 示例
+```
+
+## 快速开始
+
+### 1. 启动 Gateway 服务
+
+```bash
+python gateway_server.py
+```
+
+服务器将在 `http://localhost:8001` 启动(默认端口)。
+
+### 2. 使用 CLI 工具
+
+```bash
+# 发送消息
+gateway-cli send --from my-agent --to target-agent --message "Hello!"
+
+# 查询在线 Agent
+gateway-cli list
+
+# 查询 Agent 状态
+gateway-cli status target-agent
+```
+
+详见 [gateway/client/a2a_im.md](./client/a2a_im.md)(Agent Skill 文档)。
+
+### 3. 使用 Python SDK
+
+```python
+from gateway.client.python import tools
+
+# 发送消息
+result = await tools.send_message(
+    gateway_url="http://localhost:8001",
+    from_agent_id="my-agent",
+    to_agent_id="target-agent",
+    message="Hello!"
+)
+
+# 查询在线 Agent
+agents = await tools.list_online_agents(
+    gateway_url="http://localhost:8001"
+)
+
+# 查询 Agent 状态
+status = await tools.get_agent_status(
+    gateway_url="http://localhost:8001",
+    agent_id="target-agent"
+)
+```
+
+### 4. 集成到 Agent 框架
+
+参考 `examples/gateway_integration/` 中的示例:
+
+```python
+# 在 agent 启动时注册 Gateway 工具
+from examples.gateway_integration.agent_tools_example import (
+    send_to_agent,
+    get_active_collaborators,
+    get_online_agents,
+    get_agent_status
+)
+
+# 注册工具
+tool_registry.register(send_to_agent)
+tool_registry.register(get_active_collaborators)
+tool_registry.register(get_online_agents)
+tool_registry.register(get_agent_status)
+
+# 加载 skill
+skill_loader.load("gateway/client/a2a_im.md")
+```
+
+## 核心功能
+
+### Agent 注册
+
+PC Agent 启动时通过 WebSocket 连接到 Gateway 并注册。
+
+**实现位置**:`gateway/core/registry.py:AgentRegistry`
+
+```python
+from gateway.client.python import GatewayClient, AgentCard
+
+# 创建客户端并注册
+async with GatewayClient(
+    gateway_url="http://localhost:8001",
+    agent_card=AgentCard(
+        agent_id="my-agent-001",
+        agent_name="My Agent",
+        capabilities=["search", "analyze"]
+    )
+) as client:
+    # 发送消息
+    await client.send_message(
+        to_agent_id="target-agent",
+        content=[{"type": "text", "text": "Hello"}],
+        conversation_id="conv-123"
+    )
+```
+
+### 消息路由
+
+Gateway 根据目标 Agent ID 路由消息。
+
+**实现位置**:`gateway/core/router.py:GatewayRouter`
+
+```python
+# 发送消息
+POST /gateway/send
+{
+    "from_agent_id": "my-agent",
+    "to_agent_id": "target-agent",
+    "content": [{"type": "text", "text": "帮我分析代码"}]
+}
+```
+
+### 在线状态管理
+
+通过心跳机制跟踪 Agent 在线状态。
+
+**实现位置**:`gateway/core/registry.py:AgentRegistry.heartbeat`
+
+```python
+# 查询在线状态
+GET /gateway/status/{agent_id}
+```
+
+## API 端点
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| WS | `/gateway/connect` | Agent 注册和保持连接 |
+| POST | `/gateway/send` | 发送消息到其他 Agent |
+| GET | `/gateway/status/{agent_id}` | 查询 Agent 在线状态 |
+| GET | `/gateway/agents` | 列出所有在线 Agent |
+
+**实现位置**:`gateway/core/router.py:GatewayRouter`
+
+详见 [API 文档](./docs/api.md)。
+
+## 部署方式
+
+### 方式 1:单体部署
+
+```bash
+# 一个进程运行 Agent + Gateway
+python main.py
+```
+
+### 方式 2:分离部署
+
+```bash
+# 两个独立进程
+python api_server.py      # Agent Core
+python gateway_server.py  # Gateway
+```
+
+### 方式 3:分层部署
+
+```bash
+# 三个独立进程
+python api_server.py              # Agent Core
+python gateway_server.py          # Gateway Core
+python enterprise_gateway.py      # Enterprise Gateway
+```
+
+详见 [部署指南](./docs/deployment.md)。
+
+## 为其他框架创建集成
+
+参考 `examples/gateway_integration/` 中的示例创建你自己的集成:
+
+1. 使用 `gateway/client/python/` 的通用 SDK 或 CLI 工具
+2. 创建适配你框架的工具/函数
+3. 根据需要适配框架特有的功能
+
+详见 [集成示例文档](../examples/gateway_integration/README.md)。
+
+## 文档
+
+### 模块文档(gateway/docs/)
+
+- [架构设计](./docs/architecture.md):Gateway 架构和设计决策
+- [部署指南](./docs/deployment.md):部署方式和配置
+- [API 文档](./docs/api.md):完整的 API 参考
+- [设计决策](./docs/decisions.md):架构决策记录
+- [Enterprise 层](./docs/enterprise/overview.md):组织级功能(认证、审计、多租户)
+
+### 项目级文档(../docs/)
+
+- [A2A IM 系统](../docs/a2a-im.md):完整的 A2A IM 文档
+- [MAMP 协议](../docs/research/a2a-mamp-protocol.md):消息格式和传输协议
+
+### 客户端文档
+
+- [A2A IM Skill](./client/a2a_im.md):Agent Skill 使用文档
+- [Client README](./client/README.md):客户端安装和配置
+
+## 文档维护规范
+
+1. **先改文档,再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后,再进行代码实现;除非改动较小、不被文档涵盖
+2. **文档分层,链接代码** - 重要或复杂设计可以另有详细文档;关键实现需标注代码文件路径;格式:`module/file.py:function_name`
+3. **简洁快照,日志分离** - 只记录最重要的、与代码准确对应的或者明确的已完成的设计的信息,避免推测、建议,或大量代码;决策依据或修改日志若有必要,可在`docs/decisions.md`另行记录
+
+## 是否应该拆分到独立 Git 项目?
+
+**当前建议:暂时不拆分**
+
+理由:
+- ✅ Gateway 和 Agent 框架还在快速迭代
+- ✅ 保持在 monorepo 便于协同开发
+- ✅ 避免版本兼容性管理的复杂度
+
+**未来拆分时机**(满足以下条件时考虑):
+- Gateway API 稳定(v1.0)
+- 有其他团队/项目开始使用 Gateway
+- Gateway 和 Agent 的发布周期明显不同
+
+**现在的准备**:
+- ✅ Gateway 核心完全独立(不依赖 agent 模块)
+- ✅ 通用的 Gateway 客户端 SDK 和 CLI 工具
+- ✅ 集成示例在 examples/ 目录
+- ✅ 独立的文档结构
+- ⚠️ 独立的测试(待完善)
+
+当需要拆分时,只需:
+1. 将 `gateway/` 目录移到新仓库
+2. 在 Agent 项目中通过 pip 安装 Gateway SDK
+3. 保持 `examples/gateway_integration/` 在 Agent 项目中作为集成示例
+
+## 相关项目
+
+- [Agent Core](../agent/README.md):Agent 核心框架
+
+## License
+
+MIT
+

+ 11 - 0
gateway/__init__.py

@@ -0,0 +1,11 @@
+"""
+A2A IM Gateway
+
+Agent 注册、消息路由、在线状态管理
+"""
+
+from gateway.core.registry import AgentRegistry
+from gateway.core.router import GatewayRouter
+from gateway.core.client import GatewayClient
+
+__all__ = ["AgentRegistry", "GatewayRouter", "GatewayClient"]

+ 59 - 0
gateway/client/README.md

@@ -0,0 +1,59 @@
+# Gateway Client
+
+通用的 Gateway 客户端,提供 Python SDK 和 CLI 工具。
+
+## 快速开始
+
+### 安装
+
+```bash
+cd gateway
+pip install -e .
+```
+
+这会安装:
+- Python SDK:`gateway.client.python`
+- CLI 工具:`gateway-cli`
+
+### 使用 CLI
+
+```bash
+# 发送消息
+gateway-cli send --from my-agent --to target-agent --message "Hello"
+
+# 查询在线 Agent
+gateway-cli list
+
+# 查询 Agent 状态
+gateway-cli status target-agent
+```
+
+### 使用 Python SDK
+
+```python
+from gateway.client.python import tools
+
+# 发送消息
+result = await tools.send_message(
+    gateway_url="http://localhost:8001",
+    from_agent_id="my-agent",
+    to_agent_id="target-agent",
+    message="Hello!"
+)
+```
+
+## 文档
+
+完整文档见:[a2a_im.md](./a2a_im.md)
+
+## 目录结构
+
+```
+client/
+├── python/
+│   ├── __init__.py
+│   ├── client.py      # GatewayClient 类
+│   ├── tools.py       # 通用工具函数
+│   └── cli.py         # CLI 工具
+└── a2a_im.md          # 完整文档
+```

+ 475 - 0
gateway/client/a2a_im.md

@@ -0,0 +1,475 @@
+---
+name: a2a-im
+description: 向其他 Agent 发送消息、查询在线 Agent、检查 Agent 状态。当你需要与其他 Agent 通信或发现 Gateway 系统中的可用 Agent 时使用。
+allowed-tools: Bash(gateway-cli:*)
+---
+
+# Agent 间即时通讯
+
+通过 Gateway 进行 Agent 间通信的框架无关工具。使用 CLI 命令或 Python SDK 发送消息、发现 Agent、协调多 Agent 工作流。
+
+## 前置条件
+
+Gateway 必须正在运行(默认:http://localhost:8001)。设置自定义 URL:
+```bash
+export GATEWAY_URL=http://your-gateway:8001
+```
+
+## 快速开始
+
+### CLI 命令
+
+**发送消息:**
+```bash
+gateway-cli send --from my-agent --to target-agent --message "你好!"
+```
+
+**列出在线 Agent:**
+```bash
+gateway-cli list                    # 所有 Agent
+gateway-cli list --type analyst     # 按类型过滤
+```
+
+**检查 Agent 状态:**
+```bash
+gateway-cli status target-agent
+```
+
+**继续对话:**
+```bash
+gateway-cli send \
+  --from my-agent \
+  --to target-agent \
+  --message "继续之前的话题" \
+  --conversation-id conv-123
+```
+
+### Python SDK
+
+```python
+from gateway.client.python import tools
+
+# 发送消息
+result = await tools.send_message(
+    gateway_url="http://localhost:8001",
+    from_agent_id="my-agent",
+    to_agent_id="target-agent",
+    message="你好!"
+)
+# 返回: {"conversation_id": "conv-xxx", "message_id": "msg-xxx", "status": "sent"}
+
+# 列出在线 Agent
+agents = await tools.list_online_agents(
+    gateway_url="http://localhost:8001",
+    agent_type="analyst"  # 可选过滤
+)
+
+# 检查 Agent 状态
+status = await tools.get_agent_status(
+    gateway_url="http://localhost:8001",
+    agent_id="target-agent"
+)
+```
+
+## 高级用法
+
+### 多模态消息
+
+发送包含图片或其他媒体的文本:
+
+```python
+result = await tools.send_multimodal_message(
+    gateway_url="http://localhost:8001",
+    from_agent_id="my-agent",
+    to_agent_id="target-agent",
+    content=[
+        {"type": "text", "text": "看这张图片"},
+        {"type": "image", "source": {"type": "url", "url": "https://..."}}
+    ]
+)
+```
+
+### 注册 Agent(长连接)
+
+对于需要保持在线并接收消息的 Agent:
+
+```bash
+gateway-cli register \
+  --id my-agent \
+  --name "我的 Agent" \
+  --type analyst \
+  --capabilities search \
+  --capabilities analyze \
+  --description "我的分析 Agent"
+```
+
+或使用 Python:
+
+```python
+client = await tools.register_agent(
+    gateway_url="http://localhost:8001",
+    agent_id="my-agent",
+    agent_name="我的 Agent",
+    agent_type="analyst",
+    capabilities=["search", "analyze"],
+    description="我的分析 Agent"
+)
+
+# 使用客户端进行操作
+await client.send_message(...)
+
+# 完成后断开连接
+await client.disconnect()
+```
+
+## 常见模式
+
+### 发现并联系 Agent
+
+```bash
+# 查找可用的 Agent
+gateway-cli list --type researcher
+
+# 检查特定 Agent 是否在线
+gateway-cli status research-agent-1
+
+# 发送任务请求
+gateway-cli send \
+  --from coordinator \
+  --to research-agent-1 \
+  --message "请研究最新的 AI 论文"
+```
+
+### 多 Agent 协调
+
+```python
+# 协调器 Agent 发现工作者
+workers = await tools.list_online_agents(
+    gateway_url=gateway_url,
+    agent_type="worker"
+)
+
+# 分发任务
+for i, worker in enumerate(workers):
+    await tools.send_message(
+        gateway_url=gateway_url,
+        from_agent_id="coordinator",
+        to_agent_id=worker["id"],
+        message=f"处理批次 {i}"
+    )
+```
+
+### 对话线程
+
+```python
+# 开始对话
+result = await tools.send_message(
+    gateway_url=gateway_url,
+    from_agent_id="agent-a",
+    to_agent_id="agent-b",
+    message="开始新任务"
+)
+
+conv_id = result["conversation_id"]
+
+# 在同一线程中继续
+await tools.send_message(
+    gateway_url=gateway_url,
+    from_agent_id="agent-a",
+    to_agent_id="agent-b",
+    message="这是后续消息",
+    conversation_id=conv_id
+)
+```
+
+## API 参考
+
+### tools.send_message(gateway_url, from_agent_id, to_agent_id, message, conversation_id=None, metadata=None)
+发送文本消息。返回包含 conversation_id、message_id、status 的字典。
+
+### tools.send_multimodal_message(gateway_url, from_agent_id, to_agent_id, content, conversation_id=None, metadata=None)
+发送多模态消息(文本、图片等)。content 遵循 MAMP 格式。
+
+### tools.list_online_agents(gateway_url, agent_type=None)
+查询在线 Agent。返回 Agent 信息字典列表。
+
+### tools.get_agent_status(gateway_url, agent_id)
+检查 Agent 是否在线。返回状态信息。
+
+### tools.register_agent(gateway_url, agent_id, agent_name, agent_type=None, capabilities=None, description=None, metadata=None)
+向 Gateway 注册 Agent(长连接)。返回 GatewayClient 实例。
+
+## 安装
+
+### 方式 1:从源码安装(开发模式)
+
+```bash
+cd gateway
+pip install -e .
+```
+
+### 方式 2:直接使用(无需安装)
+
+```bash
+# 设置 PYTHONPATH
+export PYTHONPATH=/path/to/gateway:$PYTHONPATH
+
+# 使用 Python 模块
+python -m gateway.client.python.cli --help
+```
+
+安装后会提供:
+- Python SDK:`from gateway.client.python import tools`
+- CLI 工具:`gateway-cli`
+
+## 环境变量
+
+- `GATEWAY_URL`: Gateway 地址(默认: http://localhost:8001)
+
+## 集成到 Agent 框架
+
+如果你使用特定的 Agent 框架,可以将通用函数包装成框架工具。
+
+**示例:包装为框架工具**
+
+```python
+from gateway.client.python import tools
+
+# 假设你的框架有 @tool 装饰器
+@tool(description="发送消息到其他 Agent")
+async def send_to_agent(
+    target_agent: str,
+    message: str,
+    gateway_url: str = "http://localhost:8001",
+    from_agent_id: str = None
+) -> dict:
+    """
+    发送消息到指定的 Agent
+
+    Args:
+        target_agent: 目标 Agent ID
+        message: 消息内容
+        gateway_url: Gateway 地址
+        from_agent_id: 发送方 Agent ID(通常从上下文获取)
+
+    Returns:
+        包含 conversation_id 和 message_id 的字典
+    """
+    result = await tools.send_message(
+        gateway_url=gateway_url,
+        from_agent_id=from_agent_id,
+        to_agent_id=target_agent,
+        message=message
+    )
+    return result
+
+@tool(description="查询在线 Agent")
+async def list_online_agents(
+    agent_type: str = None,
+    gateway_url: str = "http://localhost:8001"
+) -> list:
+    """
+    查询当前在线的 Agent 列表
+
+    Args:
+        agent_type: 可选,按类型过滤
+        gateway_url: Gateway 地址
+
+    Returns:
+        Agent 信息列表
+    """
+    agents = await tools.list_online_agents(
+        gateway_url=gateway_url,
+        agent_type=agent_type
+    )
+    return agents
+
+@tool(description="检查 Agent 状态")
+async def check_agent_status(
+    agent_id: str,
+    gateway_url: str = "http://localhost:8001"
+) -> dict:
+    """
+    检查指定 Agent 的在线状态
+
+    Args:
+        agent_id: Agent ID
+        gateway_url: Gateway 地址
+
+    Returns:
+        状态信息字典
+    """
+    status = await tools.get_agent_status(
+        gateway_url=gateway_url,
+        agent_id=agent_id
+    )
+    return status
+```
+
+然后在你的框架中注册这些工具:
+
+```python
+# 注册工具到框架
+tool_registry.register(send_to_agent)
+tool_registry.register(list_online_agents)
+tool_registry.register(check_agent_status)
+```
+
+## MAMP 协议
+
+Gateway 使用 MAMP(Minimal Agent Message Protocol)进行消息传输。
+
+### 消息格式
+
+```python
+{
+    "from_agent_id": "sender-id",
+    "to_agent_id": "receiver-id",
+    "conversation_id": "conv-123",  # 可选,用于线程化对话
+    "content": [
+        {"type": "text", "text": "消息内容"},
+        {"type": "image", "source": {"type": "url", "url": "https://..."}}
+    ],
+    "metadata": {  # 可选
+        "priority": "high",
+        "task_type": "analysis"
+    }
+}
+```
+
+### Agent 卡片
+
+注册时提供的 Agent 信息:
+
+```python
+{
+    "agent_id": "my-agent-001",
+    "agent_name": "我的 Agent",
+    "agent_type": "analyst",  # 可选:analyst, researcher, worker 等
+    "capabilities": ["search", "analyze", "summarize"],
+    "description": "专门用于数据分析的 Agent",
+    "metadata": {  # 可选
+        "version": "1.0.0",
+        "owner": "team-a"
+    }
+}
+```
+
+## 故障排查
+
+### Gateway 连接失败
+
+```bash
+# 检查 Gateway 是否运行
+curl http://localhost:8001/health
+
+# 检查环境变量
+echo $GATEWAY_URL
+```
+
+### 消息发送失败
+
+```bash
+# 检查目标 Agent 是否在线
+gateway-cli status target-agent
+
+# 查看所有在线 Agent
+gateway-cli list
+```
+
+### CLI 命令不可用
+
+```bash
+# 重新安装
+cd gateway
+pip install -e .
+
+# 或直接使用 Python 模块
+python -m gateway.client.python.cli --help
+```
+
+## 完整示例
+
+### 示例 1:简单的任务分发
+
+```python
+from gateway.client.python import tools
+
+async def distribute_tasks():
+    gateway_url = "http://localhost:8001"
+
+    # 1. 查找所有工作者
+    workers = await tools.list_online_agents(
+        gateway_url=gateway_url,
+        agent_type="worker"
+    )
+
+    print(f"找到 {len(workers)} 个工作者")
+
+    # 2. 分发任务
+    tasks = ["任务A", "任务B", "任务C"]
+    for i, task in enumerate(tasks):
+        worker = workers[i % len(workers)]
+        result = await tools.send_message(
+            gateway_url=gateway_url,
+            from_agent_id="coordinator",
+            to_agent_id=worker["id"],
+            message=f"请处理:{task}"
+        )
+        print(f"已发送任务到 {worker['name']}: {result['conversation_id']}")
+```
+
+### 示例 2:对话式协作
+
+```python
+from gateway.client.python import tools
+
+async def collaborative_analysis():
+    gateway_url = "http://localhost:8001"
+
+    # 1. 开始对话
+    result = await tools.send_message(
+        gateway_url=gateway_url,
+        from_agent_id="analyst-1",
+        to_agent_id="analyst-2",
+        message="我发现了一个有趣的数据模式,你能帮我验证吗?"
+    )
+
+    conv_id = result["conversation_id"]
+
+    # 2. 发送详细信息(同一对话)
+    await tools.send_multimodal_message(
+        gateway_url=gateway_url,
+        from_agent_id="analyst-1",
+        to_agent_id="analyst-2",
+        conversation_id=conv_id,
+        content=[
+            {"type": "text", "text": "这是数据图表:"},
+            {"type": "image", "source": {"type": "url", "url": "https://example.com/chart.png"}}
+        ]
+    )
+
+    print(f"对话 ID: {conv_id}")
+```
+
+### 示例 3:使用 CLI 进行快速测试
+
+```bash
+# 终端 1:启动一个 Agent(模拟)
+gateway-cli register \
+  --id worker-1 \
+  --name "工作者 1" \
+  --type worker \
+  --capabilities process \
+  --description "数据处理工作者"
+
+# 终端 2:发送消息
+gateway-cli send \
+  --from coordinator \
+  --to worker-1 \
+  --message "处理数据集 A"
+
+# 终端 3:检查状态
+gateway-cli status worker-1
+gateway-cli list
+```

+ 11 - 0
gateway/client/python/__init__.py

@@ -0,0 +1,11 @@
+"""
+Gateway Python Client SDK
+
+通用的 Gateway 客户端,不依赖任何特定的 Agent 框架。
+"""
+
+from .client import GatewayClient, Message, AgentCard
+from . import tools
+
+__all__ = ["GatewayClient", "Message", "AgentCard", "tools"]
+__version__ = "0.1.0"

+ 146 - 0
gateway/client/python/cli.py

@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+"""
+Gateway CLI - 命令行工具
+
+可以直接在终端运行的 A2A IM 工具。
+
+使用示例:
+    # 发送消息
+    gateway-cli send --to agent-001 --message "Hello"
+
+    # 查询在线 Agent
+    gateway-cli list
+
+    # 查询 Agent 状态
+    gateway-cli status agent-001
+"""
+
+import asyncio
+import json
+import sys
+from typing import Optional
+
+import click
+
+from gateway.client.python import tools
+
+
+@click.group()
+@click.option('--gateway-url', default='http://localhost:8001',
+              envvar='GATEWAY_URL',
+              help='Gateway 地址 (默认: http://localhost:8001)')
+@click.pass_context
+def cli(ctx, gateway_url):
+    """Gateway CLI - A2A IM 命令行工具"""
+    ctx.ensure_object(dict)
+    ctx.obj['gateway_url'] = gateway_url
+
+
+@cli.command()
+@click.option('--from', 'from_agent', required=True, help='发送方 Agent ID')
+@click.option('--to', 'to_agent', required=True, help='接收方 Agent ID')
+@click.option('--message', '-m', required=True, help='消息内容')
+@click.option('--conversation-id', '-c', help='对话 ID (可选)')
+@click.pass_context
+def send(ctx, from_agent, to_agent, message, conversation_id):
+    """发送消息到其他 Agent"""
+    async def _send():
+        result = await tools.send_message(
+            gateway_url=ctx.obj['gateway_url'],
+            from_agent_id=from_agent,
+            to_agent_id=to_agent,
+            message=message,
+            conversation_id=conversation_id
+        )
+        click.echo(json.dumps(result, indent=2, ensure_ascii=False))
+
+    asyncio.run(_send())
+
+
+@cli.command()
+@click.option('--type', 'agent_type', help='过滤 Agent 类型')
+@click.pass_context
+def list(ctx, agent_type):
+    """查询在线 Agent 列表"""
+    async def _list():
+        agents = await tools.list_online_agents(
+            gateway_url=ctx.obj['gateway_url'],
+            agent_type=agent_type
+        )
+
+        if not agents:
+            click.echo("没有找到在线 Agent")
+            return
+
+        click.echo(f"找到 {len(agents)} 个在线 Agent:\n")
+        for agent in agents:
+            click.echo(f"🟢 {agent['agent_name']} ({agent['agent_id']})")
+            if agent.get('capabilities'):
+                click.echo(f"   能力: {', '.join(agent['capabilities'])}")
+            if agent.get('description'):
+                click.echo(f"   描述: {agent['description']}")
+            click.echo()
+
+    asyncio.run(_list())
+
+
+@cli.command()
+@click.argument('agent_id')
+@click.pass_context
+def status(ctx, agent_id):
+    """查询 Agent 在线状态"""
+    async def _status():
+        result = await tools.get_agent_status(
+            gateway_url=ctx.obj['gateway_url'],
+            agent_id=agent_id
+        )
+
+        status = result.get('status', 'unknown')
+        icon = '🟢' if status == 'online' else '⚪'
+
+        click.echo(f"{icon} {agent_id}")
+        click.echo(f"状态: {status}")
+        if result.get('last_seen'):
+            click.echo(f"最后在线: {result['last_seen']}")
+
+    asyncio.run(_status())
+
+
+@cli.command()
+@click.option('--id', 'agent_id', required=True, help='Agent ID')
+@click.option('--name', 'agent_name', required=True, help='Agent 名称')
+@click.option('--type', 'agent_type', help='Agent 类型')
+@click.option('--capabilities', '-c', multiple=True, help='Agent 能力 (可多次指定)')
+@click.option('--description', '-d', help='Agent 描述')
+@click.pass_context
+def register(ctx, agent_id, agent_name, agent_type, capabilities, description):
+    """注册 Agent 到 Gateway (保持连接)"""
+    async def _register():
+        click.echo(f"正在注册 Agent: {agent_id}...")
+
+        client = await tools.register_agent(
+            gateway_url=ctx.obj['gateway_url'],
+            agent_id=agent_id,
+            agent_name=agent_name,
+            agent_type=agent_type,
+            capabilities=list(capabilities) if capabilities else [],
+            description=description
+        )
+
+        click.echo(f"✅ Agent 已注册: {agent_id}")
+        click.echo("按 Ctrl+C 断开连接")
+
+        try:
+            # 保持连接
+            while True:
+                await asyncio.sleep(1)
+        except KeyboardInterrupt:
+            click.echo("\n正在断开连接...")
+            await client.disconnect()
+            click.echo("已断开连接")
+
+    asyncio.run(_register())
+
+
+if __name__ == '__main__':
+    cli()

+ 259 - 0
gateway/client/python/client.py

@@ -0,0 +1,259 @@
+"""
+Gateway Client SDK
+
+通用的 Gateway 客户端实现,提供:
+- Agent 注册和连接管理
+- 消息发送和接收
+- 在线状态查询
+- Agent 列表查询
+
+不依赖任何特定的 Agent 框架。
+"""
+
+import asyncio
+import json
+import logging
+from dataclasses import dataclass, field
+from datetime import datetime
+from typing import Any, Callable, Dict, List, Optional
+from urllib.parse import urlencode
+
+import httpx
+
+logger = logging.getLogger(__name__)
+
+
+@dataclass
+class Message:
+    """MAMP 协议消息"""
+    conversation_id: str
+    content: List[Dict[str, Any]]  # 多模态内容
+    metadata: Dict[str, Any] = field(default_factory=dict)
+    message_id: Optional[str] = None
+    timestamp: Optional[str] = None
+
+
+@dataclass
+class AgentCard:
+    """Agent 身份卡片"""
+    agent_id: str
+    agent_name: str
+    agent_type: Optional[str] = None
+    capabilities: List[str] = field(default_factory=list)
+    description: Optional[str] = None
+    version: Optional[str] = None
+    metadata: Dict[str, Any] = field(default_factory=dict)
+
+
+class GatewayClient:
+    """
+    Gateway 客户端
+
+    使用示例:
+    ```python
+    client = GatewayClient(
+        gateway_url="http://localhost:8001",
+        agent_card=AgentCard(
+            agent_id="my-agent-001",
+            agent_name="My Agent",
+            capabilities=["search", "analyze"]
+        )
+    )
+
+    # 发送消息
+    await client.send_message(
+        to_agent_id="target-agent",
+        content=[{"type": "text", "text": "Hello"}],
+        conversation_id="conv-123"
+    )
+
+    # 查询在线 Agent
+    agents = await client.list_agents()
+    ```
+    """
+
+    def __init__(
+        self,
+        gateway_url: str,
+        agent_card: AgentCard,
+        on_message: Optional[Callable[[Message], None]] = None,
+        auto_reconnect: bool = True,
+        heartbeat_interval: int = 30,
+    ):
+        """
+        初始化 Gateway 客户端
+
+        Args:
+            gateway_url: Gateway HTTP API 地址(如 http://localhost:8001)
+            agent_card: Agent 身份信息
+            on_message: 收到消息时的回调函数
+            auto_reconnect: 是否自动重连
+            heartbeat_interval: 心跳间隔(秒)
+        """
+        self.gateway_url = gateway_url.rstrip("/")
+        self.agent_card = agent_card
+        self.on_message = on_message
+        self.auto_reconnect = auto_reconnect
+        self.heartbeat_interval = heartbeat_interval
+
+        self._http_client: Optional[httpx.AsyncClient] = None
+        self._connected = False
+
+    async def __aenter__(self):
+        """异步上下文管理器入口"""
+        await self.connect()
+        return self
+
+    async def __aexit__(self, exc_type, exc_val, exc_tb):
+        """异步上下文管理器出口"""
+        await self.disconnect()
+
+    async def connect(self):
+        """连接到 Gateway"""
+        if self._connected:
+            return
+
+        self._http_client = httpx.AsyncClient(timeout=30.0)
+
+        # 注册 Agent
+        try:
+            response = await self._http_client.post(
+                f"{self.gateway_url}/gateway/register",
+                json={
+                    "agent_id": self.agent_card.agent_id,
+                    "agent_name": self.agent_card.agent_name,
+                    "agent_type": self.agent_card.agent_type,
+                    "capabilities": self.agent_card.capabilities,
+                    "description": self.agent_card.description,
+                    "version": self.agent_card.version,
+                    "metadata": self.agent_card.metadata,
+                }
+            )
+            response.raise_for_status()
+            self._connected = True
+            logger.info(f"Connected to Gateway: {self.agent_card.agent_id}")
+        except Exception as e:
+            logger.error(f"Failed to connect to Gateway: {e}")
+            raise
+
+    async def disconnect(self):
+        """断开连接"""
+        if not self._connected:
+            return
+
+        try:
+            if self._http_client:
+                await self._http_client.post(
+                    f"{self.gateway_url}/gateway/unregister",
+                    json={"agent_id": self.agent_card.agent_id}
+                )
+                await self._http_client.aclose()
+                self._http_client = None
+
+            self._connected = False
+            logger.info(f"Disconnected from Gateway: {self.agent_card.agent_id}")
+        except Exception as e:
+            logger.error(f"Error during disconnect: {e}")
+
+    async def send_message(
+        self,
+        to_agent_id: str,
+        content: List[Dict[str, Any]],
+        conversation_id: str,
+        metadata: Optional[Dict[str, Any]] = None
+    ) -> Dict[str, Any]:
+        """
+        发送消息到其他 Agent
+
+        Args:
+            to_agent_id: 目标 Agent ID
+            content: 消息内容(MAMP 格式)
+            conversation_id: 对话 ID
+            metadata: 元数据
+
+        Returns:
+            发送结果
+        """
+        if not self._connected:
+            raise RuntimeError("Not connected to Gateway")
+
+        response = await self._http_client.post(
+            f"{self.gateway_url}/gateway/send",
+            json={
+                "from_agent_id": self.agent_card.agent_id,
+                "to_agent_id": to_agent_id,
+                "conversation_id": conversation_id,
+                "content": content,
+                "metadata": metadata or {}
+            }
+        )
+        response.raise_for_status()
+        return response.json()
+
+    async def list_agents(
+        self,
+        online_only: bool = True,
+        agent_type: Optional[str] = None
+    ) -> List[Dict[str, Any]]:
+        """
+        查询 Agent 列表
+
+        Args:
+            online_only: 只返回在线 Agent
+            agent_type: 过滤 Agent 类型
+
+        Returns:
+            Agent 列表
+        """
+        if not self._connected:
+            raise RuntimeError("Not connected to Gateway")
+
+        params = {"online_only": online_only}
+        if agent_type:
+            params["agent_type"] = agent_type
+
+        response = await self._http_client.get(
+            f"{self.gateway_url}/gateway/agents",
+            params=params
+        )
+        response.raise_for_status()
+        data = response.json()
+        return data.get("agents", [])
+
+    async def get_agent_status(self, agent_id: str) -> Dict[str, Any]:
+        """
+        查询指定 Agent 的状态
+
+        Args:
+            agent_id: Agent ID
+
+        Returns:
+            Agent 状态信息
+        """
+        if not self._connected:
+            raise RuntimeError("Not connected to Gateway")
+
+        from urllib.parse import quote
+        encoded_id = quote(agent_id, safe='')
+
+        response = await self._http_client.get(
+            f"{self.gateway_url}/gateway/status/{encoded_id}"
+        )
+        response.raise_for_status()
+        return response.json()
+
+    async def heartbeat(self):
+        """发送心跳"""
+        if not self._connected:
+            return
+
+        try:
+            response = await self._http_client.post(
+                f"{self.gateway_url}/gateway/heartbeat",
+                json={"agent_id": self.agent_card.agent_id}
+            )
+            response.raise_for_status()
+        except Exception as e:
+            logger.error(f"Heartbeat failed: {e}")
+            if self.auto_reconnect:
+                await self.connect()

+ 193 - 0
gateway/client/python/tools.py

@@ -0,0 +1,193 @@
+"""
+Gateway 通用工具函数
+
+这些函数不依赖任何特定的 Agent 框架,可以被任何 Agent 直接使用。
+各框架可以将这些函数包装成自己的工具格式。
+"""
+
+import uuid
+from typing import Any, Dict, List, Optional
+
+from .client import GatewayClient, AgentCard
+
+
+async def send_message(
+    gateway_url: str,
+    from_agent_id: str,
+    to_agent_id: str,
+    message: str,
+    conversation_id: Optional[str] = None,
+    metadata: Optional[Dict[str, Any]] = None
+) -> Dict[str, Any]:
+    """
+    发送消息到其他 Agent(通用函数)
+
+    Args:
+        gateway_url: Gateway 地址
+        from_agent_id: 发送方 Agent ID
+        to_agent_id: 接收方 Agent ID
+        message: 消息内容(文本)
+        conversation_id: 对话 ID(可选,不提供则新建)
+        metadata: 元数据
+
+    Returns:
+        发送结果,包含 conversation_id, message_id 等
+    """
+    # 生成对话 ID
+    conv_id = conversation_id or f"conv-{uuid.uuid4()}"
+
+    # 创建临时客户端
+    agent_card = AgentCard(
+        agent_id=from_agent_id,
+        agent_name=from_agent_id
+    )
+
+    async with GatewayClient(gateway_url=gateway_url, agent_card=agent_card) as client:
+        result = await client.send_message(
+            to_agent_id=to_agent_id,
+            content=[{"type": "text", "text": message}],
+            conversation_id=conv_id,
+            metadata=metadata
+        )
+
+    return {
+        "conversation_id": conv_id,
+        "message_id": result.get("message_id"),
+        "status": result.get("status", "sent"),
+        "to_agent": to_agent_id
+    }
+
+
+async def send_multimodal_message(
+    gateway_url: str,
+    from_agent_id: str,
+    to_agent_id: str,
+    content: List[Dict[str, Any]],
+    conversation_id: Optional[str] = None,
+    metadata: Optional[Dict[str, Any]] = None
+) -> Dict[str, Any]:
+    """
+    发送多模态消息到其他 Agent(通用函数)
+
+    Args:
+        gateway_url: Gateway 地址
+        from_agent_id: 发送方 Agent ID
+        to_agent_id: 接收方 Agent ID
+        content: MAMP 格式的多模态内容
+        conversation_id: 对话 ID(可选)
+        metadata: 元数据
+
+    Returns:
+        发送结果
+    """
+    conv_id = conversation_id or f"conv-{uuid.uuid4()}"
+
+    agent_card = AgentCard(
+        agent_id=from_agent_id,
+        agent_name=from_agent_id
+    )
+
+    async with GatewayClient(gateway_url=gateway_url, agent_card=agent_card) as client:
+        result = await client.send_message(
+            to_agent_id=to_agent_id,
+            content=content,
+            conversation_id=conv_id,
+            metadata=metadata
+        )
+
+    return {
+        "conversation_id": conv_id,
+        "message_id": result.get("message_id"),
+        "status": result.get("status", "sent"),
+        "to_agent": to_agent_id
+    }
+
+
+async def list_online_agents(
+    gateway_url: str,
+    agent_type: Optional[str] = None
+) -> List[Dict[str, Any]]:
+    """
+    查询在线 Agent 列表(通用函数)
+
+    Args:
+        gateway_url: Gateway 地址
+        agent_type: 过滤 Agent 类型(可选)
+
+    Returns:
+        在线 Agent 列表
+    """
+    # 创建临时客户端(用于查询)
+    agent_card = AgentCard(
+        agent_id="query-client",
+        agent_name="Query Client"
+    )
+
+    async with GatewayClient(gateway_url=gateway_url, agent_card=agent_card) as client:
+        agents = await client.list_agents(online_only=True, agent_type=agent_type)
+
+    return agents
+
+
+async def get_agent_status(
+    gateway_url: str,
+    agent_id: str
+) -> Dict[str, Any]:
+    """
+    查询指定 Agent 的在线状态(通用函数)
+
+    Args:
+        gateway_url: Gateway 地址
+        agent_id: Agent ID
+
+    Returns:
+        Agent 状态信息
+    """
+    agent_card = AgentCard(
+        agent_id="query-client",
+        agent_name="Query Client"
+    )
+
+    async with GatewayClient(gateway_url=gateway_url, agent_card=agent_card) as client:
+        status = await client.get_agent_status(agent_id)
+
+    return status
+
+
+async def register_agent(
+    gateway_url: str,
+    agent_id: str,
+    agent_name: str,
+    agent_type: Optional[str] = None,
+    capabilities: Optional[List[str]] = None,
+    description: Optional[str] = None,
+    metadata: Optional[Dict[str, Any]] = None
+) -> GatewayClient:
+    """
+    注册 Agent 到 Gateway(通用函数)
+
+    Args:
+        gateway_url: Gateway 地址
+        agent_id: Agent ID
+        agent_name: Agent 名称
+        agent_type: Agent 类型
+        capabilities: Agent 能力列表
+        description: Agent 描述
+        metadata: 元数据
+
+    Returns:
+        已连接的 GatewayClient 实例(需要调用方管理生命周期)
+    """
+    agent_card = AgentCard(
+        agent_id=agent_id,
+        agent_name=agent_name,
+        agent_type=agent_type,
+        capabilities=capabilities or [],
+        description=description,
+        metadata=metadata or {}
+    )
+
+    client = GatewayClient(gateway_url=gateway_url, agent_card=agent_card)
+    await client.connect()
+
+    return client

+ 11 - 0
gateway/core/__init__.py

@@ -0,0 +1,11 @@
+"""
+A2A IM Gateway
+
+Agent 注册、消息路由、在线状态管理
+"""
+
+from .registry import AgentRegistry
+from .router import GatewayRouter
+from .client import GatewayClient
+
+__all__ = ["AgentRegistry", "GatewayRouter", "GatewayClient"]

+ 172 - 0
gateway/core/client.py

@@ -0,0 +1,172 @@
+"""
+Gateway Client
+
+Agent 端用于连接 Gateway 的客户端
+"""
+
+import asyncio
+import json
+import logging
+from typing import Optional, Dict, Any, Callable
+import websockets
+
+logger = logging.getLogger(__name__)
+
+
+class GatewayClient:
+    """Gateway 客户端"""
+
+    def __init__(
+        self,
+        gateway_url: str,
+        agent_uri: str,
+        capabilities: Optional[list] = None,
+        on_message: Optional[Callable] = None
+    ):
+        """
+        Args:
+            gateway_url: Gateway WebSocket URL (wss://gateway.com/gateway/connect)
+            agent_uri: 本 Agent 的 URI
+            capabilities: Agent 能力列表
+            on_message: 收到消息时的回调函数
+        """
+        self.gateway_url = gateway_url
+        self.agent_uri = agent_uri
+        self.capabilities = capabilities or []
+        self.on_message = on_message
+
+        self.ws: Optional[websockets.WebSocketClientProtocol] = None
+        self.connected = False
+        self._heartbeat_task = None
+        self._receive_task = None
+
+    async def connect(self):
+        """连接到 Gateway"""
+        try:
+            self.ws = await websockets.connect(self.gateway_url)
+
+            # 发送注册消息
+            await self.ws.send(json.dumps({
+                "type": "register",
+                "agent_uri": self.agent_uri,
+                "capabilities": self.capabilities
+            }))
+
+            # 等待注册确认
+            response = await self.ws.recv()
+            msg = json.loads(response)
+
+            if msg.get("type") == "registered":
+                self.connected = True
+                logger.info(f"Connected to Gateway: {self.agent_uri}")
+
+                # 启动心跳和接收任务
+                self._heartbeat_task = asyncio.create_task(self._heartbeat_loop())
+                self._receive_task = asyncio.create_task(self._receive_loop())
+
+            else:
+                raise Exception(f"Registration failed: {msg}")
+
+        except Exception as e:
+            logger.error(f"Failed to connect to Gateway: {e}")
+            raise
+
+    async def disconnect(self):
+        """断开连接"""
+        self.connected = False
+
+        if self._heartbeat_task:
+            self._heartbeat_task.cancel()
+        if self._receive_task:
+            self._receive_task.cancel()
+
+        if self.ws:
+            await self.ws.close()
+
+        logger.info(f"Disconnected from Gateway: {self.agent_uri}")
+
+    async def send_result(self, task_id: str, result: Any):
+        """发送任务结果"""
+        if not self.connected:
+            raise Exception("Not connected to Gateway")
+
+        await self.ws.send(json.dumps({
+            "type": "result",
+            "task_id": task_id,
+            "result": result
+        }))
+
+    async def _heartbeat_loop(self):
+        """心跳循环"""
+        while self.connected:
+            try:
+                await asyncio.sleep(30)  # 每 30 秒发送心跳
+                await self.ws.send(json.dumps({"type": "heartbeat"}))
+
+                # 等待心跳确认
+                # TODO: 添加超时处理
+
+            except asyncio.CancelledError:
+                break
+            except Exception as e:
+                logger.error(f"Heartbeat error: {e}")
+                break
+
+    async def _receive_loop(self):
+        """接收消息循环"""
+        while self.connected:
+            try:
+                data = await self.ws.recv()
+                msg = json.loads(data)
+
+                msg_type = msg.get("type")
+
+                if msg_type == "heartbeat_ack":
+                    # 心跳确认,忽略
+                    pass
+
+                elif msg_type == "message":
+                    # 收到消息,调用回调
+                    if self.on_message:
+                        await self.on_message(msg)
+                    else:
+                        logger.warning(f"Received message but no handler: {msg}")
+
+                else:
+                    logger.warning(f"Unknown message type: {msg_type}")
+
+            except asyncio.CancelledError:
+                break
+            except Exception as e:
+                logger.error(f"Receive error: {e}")
+                break
+
+
+async def create_gateway_client(
+    gateway_url: str,
+    agent_uri: str,
+    capabilities: Optional[list] = None,
+    on_message: Optional[Callable] = None
+) -> GatewayClient:
+    """
+    创建并连接 Gateway 客户端
+
+    Args:
+        gateway_url: Gateway WebSocket URL
+        agent_uri: 本 Agent 的 URI
+        capabilities: Agent 能力列表
+        on_message: 收到消息时的回调函数
+
+    Returns:
+        已连接的 GatewayClient
+    """
+    client = GatewayClient(
+        gateway_url=gateway_url,
+        agent_uri=agent_uri,
+        capabilities=capabilities,
+        on_message=on_message
+    )
+
+    await client.connect()
+
+    return client

+ 162 - 0
gateway/core/registry.py

@@ -0,0 +1,162 @@
+"""
+Agent Registry
+
+管理在线 Agent 的注册信息和连接
+"""
+
+import asyncio
+from datetime import datetime, timedelta
+from typing import Dict, Optional, List
+from dataclasses import dataclass, field
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+@dataclass
+class AgentConnection:
+    """Agent 连接信息"""
+    agent_uri: str
+    connection_type: str  # "websocket" | "http"
+    websocket: Optional[object] = None  # WebSocket 连接对象
+    http_endpoint: Optional[str] = None  # HTTP 端点
+    capabilities: List[str] = field(default_factory=list)
+    registered_at: datetime = field(default_factory=datetime.now)
+    last_heartbeat: datetime = field(default_factory=datetime.now)
+    metadata: Dict = field(default_factory=dict)
+
+
+class AgentRegistry:
+    """Agent 注册表"""
+
+    def __init__(self, heartbeat_timeout: int = 60):
+        """
+        Args:
+            heartbeat_timeout: 心跳超时时间(秒)
+        """
+        self.agents: Dict[str, AgentConnection] = {}
+        self.heartbeat_timeout = heartbeat_timeout
+        self._cleanup_task = None
+
+    async def start(self):
+        """启动注册表(定期清理过期连接)"""
+        self._cleanup_task = asyncio.create_task(self._cleanup_loop())
+        logger.info("AgentRegistry started")
+
+    async def stop(self):
+        """停止注册表"""
+        if self._cleanup_task:
+            self._cleanup_task.cancel()
+            try:
+                await self._cleanup_task
+            except asyncio.CancelledError:
+                pass
+        logger.info("AgentRegistry stopped")
+
+    async def register(
+        self,
+        agent_uri: str,
+        connection_type: str,
+        websocket: Optional[object] = None,
+        http_endpoint: Optional[str] = None,
+        capabilities: Optional[List[str]] = None,
+        metadata: Optional[Dict] = None
+    ) -> AgentConnection:
+        """
+        注册 Agent
+
+        Args:
+            agent_uri: Agent URI (agent://domain/id)
+            connection_type: 连接类型 (websocket | http)
+            websocket: WebSocket 连接对象
+            http_endpoint: HTTP 端点
+            capabilities: Agent 能力列表
+            metadata: 额外元数据
+        """
+        connection = AgentConnection(
+            agent_uri=agent_uri,
+            connection_type=connection_type,
+            websocket=websocket,
+            http_endpoint=http_endpoint,
+            capabilities=capabilities or [],
+            metadata=metadata or {}
+        )
+
+        self.agents[agent_uri] = connection
+        logger.info(f"Agent registered: {agent_uri} ({connection_type})")
+
+        return connection
+
+    async def unregister(self, agent_uri: str):
+        """注销 Agent"""
+        if agent_uri in self.agents:
+            del self.agents[agent_uri]
+            logger.info(f"Agent unregistered: {agent_uri}")
+
+    async def heartbeat(self, agent_uri: str):
+        """更新心跳时间"""
+        if agent_uri in self.agents:
+            self.agents[agent_uri].last_heartbeat = datetime.now()
+
+    def lookup(self, agent_uri: str) -> Optional[AgentConnection]:
+        """查找 Agent 连接信息"""
+        return self.agents.get(agent_uri)
+
+    def is_online(self, agent_uri: str) -> bool:
+        """检查 Agent 是否在线"""
+        connection = self.lookup(agent_uri)
+        if not connection:
+            return False
+
+        # 检查心跳是否超时
+        timeout = timedelta(seconds=self.heartbeat_timeout)
+        return datetime.now() - connection.last_heartbeat < timeout
+
+    def list_agents(
+        self,
+        connection_type: Optional[str] = None,
+        online_only: bool = True
+    ) -> List[AgentConnection]:
+        """
+        列出 Agent
+
+        Args:
+            connection_type: 过滤连接类型
+            online_only: 只返回在线的 Agent
+        """
+        agents = list(self.agents.values())
+
+        if connection_type:
+            agents = [a for a in agents if a.connection_type == connection_type]
+
+        if online_only:
+            timeout = timedelta(seconds=self.heartbeat_timeout)
+            now = datetime.now()
+            agents = [a for a in agents if now - a.last_heartbeat < timeout]
+
+        return agents
+
+    async def _cleanup_loop(self):
+        """定期清理过期连接"""
+        while True:
+            try:
+                await asyncio.sleep(30)  # 每 30 秒检查一次
+                await self._cleanup_expired()
+            except asyncio.CancelledError:
+                break
+            except Exception as e:
+                logger.error(f"Cleanup error: {e}")
+
+    async def _cleanup_expired(self):
+        """清理过期连接"""
+        timeout = timedelta(seconds=self.heartbeat_timeout)
+        now = datetime.now()
+
+        expired = [
+            uri for uri, conn in self.agents.items()
+            if now - conn.last_heartbeat > timeout
+        ]
+
+        for uri in expired:
+            await self.unregister(uri)
+            logger.info(f"Agent expired: {uri}")

+ 222 - 0
gateway/core/router.py

@@ -0,0 +1,222 @@
+"""
+Gateway Router
+
+消息路由、在线状态查询
+"""
+
+import json
+import logging
+from typing import Dict, Any, Optional
+from fastapi import APIRouter, WebSocket, WebSocketDisconnect, HTTPException
+from pydantic import BaseModel
+
+from .registry import AgentRegistry
+
+logger = logging.getLogger(__name__)
+
+
+class SendMessageRequest(BaseModel):
+    """发送消息请求"""
+    to: str  # 目标 Agent URI
+    content: Any  # 消息内容(字符串或多模态数组)
+    conversation_id: Optional[str] = None
+    metadata: Optional[Dict] = None
+
+
+class SendMessageResponse(BaseModel):
+    """发送消息响应"""
+    message_id: str
+    conversation_id: str
+    status: str  # "sent" | "queued"
+
+
+class AgentStatusResponse(BaseModel):
+    """Agent 状态响应"""
+    agent_uri: str
+    status: str  # "online" | "offline"
+    last_seen: Optional[str] = None
+
+
+class GatewayRouter:
+    """Gateway 路由器"""
+
+    def __init__(self, registry: AgentRegistry):
+        self.registry = registry
+        self.router = APIRouter(prefix="/gateway", tags=["gateway"])
+
+        # 注册路由
+        self.router.add_api_websocket_route("/connect", self.handle_websocket)
+        self.router.add_api_route("/send", self.send_message, methods=["POST"])
+        self.router.add_api_route("/status/{agent_uri:path}", self.get_agent_status, methods=["GET"])
+        self.router.add_api_route("/agents", self.list_agents, methods=["GET"])
+
+    async def handle_websocket(self, websocket: WebSocket):
+        """
+        处理 WebSocket 连接
+
+        Agent 通过此端点注册并保持长连接
+        """
+        await websocket.accept()
+        agent_uri = None
+
+        try:
+            # 等待注册消息
+            data = await websocket.receive_text()
+            msg = json.loads(data)
+
+            if msg.get("type") != "register":
+                await websocket.send_text(json.dumps({
+                    "type": "error",
+                    "message": "First message must be register"
+                }))
+                await websocket.close()
+                return
+
+            agent_uri = msg.get("agent_uri")
+            if not agent_uri:
+                await websocket.send_text(json.dumps({
+                    "type": "error",
+                    "message": "agent_uri is required"
+                }))
+                await websocket.close()
+                return
+
+            # 注册 Agent
+            await self.registry.register(
+                agent_uri=agent_uri,
+                connection_type="websocket",
+                websocket=websocket,
+                capabilities=msg.get("capabilities", []),
+                metadata=msg.get("metadata", {})
+            )
+
+            # 发送注册成功消息
+            await websocket.send_text(json.dumps({
+                "type": "registered",
+                "agent_uri": agent_uri
+            }))
+
+            logger.info(f"Agent connected: {agent_uri}")
+
+            # 保持连接,处理消息
+            while True:
+                data = await websocket.receive_text()
+                msg = json.loads(data)
+
+                msg_type = msg.get("type")
+
+                if msg_type == "heartbeat":
+                    # 更新心跳
+                    await self.registry.heartbeat(agent_uri)
+                    await websocket.send_text(json.dumps({
+                        "type": "heartbeat_ack"
+                    }))
+
+                elif msg_type == "result":
+                    # Agent 返回任务结果
+                    # TODO: 将结果转发给调用方
+                    logger.info(f"Received result from {agent_uri}: {msg.get('task_id')}")
+
+                else:
+                    logger.warning(f"Unknown message type: {msg_type}")
+
+        except WebSocketDisconnect:
+            logger.info(f"Agent disconnected: {agent_uri}")
+        except Exception as e:
+            logger.error(f"WebSocket error: {e}")
+        finally:
+            if agent_uri:
+                await self.registry.unregister(agent_uri)
+
+    async def send_message(self, request: SendMessageRequest) -> SendMessageResponse:
+        """
+        发送消息到目标 Agent
+
+        通过 Gateway 路由消息
+        """
+        import uuid
+
+        # 查找目标 Agent
+        connection = self.registry.lookup(request.to)
+
+        if not connection:
+            raise HTTPException(status_code=404, detail=f"Agent not found: {request.to}")
+
+        if not self.registry.is_online(request.to):
+            raise HTTPException(status_code=503, detail=f"Agent offline: {request.to}")
+
+        # 生成消息 ID
+        message_id = f"msg-{uuid.uuid4()}"
+        conversation_id = request.conversation_id or f"conv-{uuid.uuid4()}"
+
+        # 构建消息
+        message = {
+            "type": "message",
+            "message_id": message_id,
+            "conversation_id": conversation_id,
+            "from": "gateway",  # TODO: 从请求中获取发送方
+            "content": request.content,
+            "metadata": request.metadata or {}
+        }
+
+        # 根据连接类型发送
+        if connection.connection_type == "websocket":
+            # 通过 WebSocket 发送
+            await connection.websocket.send_text(json.dumps(message))
+            status = "sent"
+        elif connection.connection_type == "http":
+            # 通过 HTTP 发送
+            # TODO: 实现 HTTP 转发
+            status = "queued"
+        else:
+            raise HTTPException(status_code=500, detail="Unknown connection type")
+
+        return SendMessageResponse(
+            message_id=message_id,
+            conversation_id=conversation_id,
+            status=status
+        )
+
+    async def get_agent_status(self, agent_uri: str) -> AgentStatusResponse:
+        """查询 Agent 在线状态"""
+        connection = self.registry.lookup(agent_uri)
+
+        if not connection:
+            return AgentStatusResponse(
+                agent_uri=agent_uri,
+                status="offline",
+                last_seen=None
+            )
+
+        is_online = self.registry.is_online(agent_uri)
+
+        return AgentStatusResponse(
+            agent_uri=agent_uri,
+            status="online" if is_online else "offline",
+            last_seen=connection.last_heartbeat.isoformat() if connection else None
+        )
+
+    async def list_agents(
+        self,
+        connection_type: Optional[str] = None,
+        online_only: bool = True
+    ) -> Dict[str, Any]:
+        """列出所有 Agent"""
+        agents = self.registry.list_agents(
+            connection_type=connection_type,
+            online_only=online_only
+        )
+
+        return {
+            "agents": [
+                {
+                    "agent_uri": a.agent_uri,
+                    "connection_type": a.connection_type,
+                    "capabilities": a.capabilities,
+                    "registered_at": a.registered_at.isoformat(),
+                    "last_heartbeat": a.last_heartbeat.isoformat()
+                }
+                for a in agents
+            ],
+            "total": len(agents)
+        }

+ 245 - 0
gateway/docs/api.md

@@ -0,0 +1,245 @@
+# Gateway API 参考
+
+## WebSocket API
+
+### 连接端点
+
+#### `WS /gateway/connect`
+
+Agent 连接到 Gateway 的 WebSocket 端点。
+
+**查询参数**:
+- `agent_id` (必需): Agent 唯一标识符
+- `agent_name` (可选): Agent 显示名称
+- `capabilities` (可选): Agent 能力列表,JSON 数组格式
+
+**连接流程**:
+1. Agent 建立 WebSocket 连接
+2. Gateway 注册 Agent 并返回连接确认
+3. Agent 开始发送心跳(30s 间隔)
+4. Gateway 监听消息并路由到目标 Agent
+
+**示例**:
+```python
+from gateway.core.client import GatewayClient
+
+client = GatewayClient(
+    gateway_url="ws://localhost:8001",
+    agent_id="my-agent-001",
+    agent_name="My Agent"
+)
+await client.connect()
+```
+
+**实现**:`gateway/core/router.py:GatewayRouter.handle_connect`
+
+### 消息格式
+
+#### 心跳消息
+
+```json
+{
+  "type": "heartbeat",
+  "timestamp": "2026-03-04T12:00:00Z"
+}
+```
+
+#### 发送消息
+
+```json
+{
+  "type": "send",
+  "to_agent_id": "target-agent-001",
+  "conversation_id": "conv-abc-123",
+  "content": [
+    {"type": "text", "text": "Hello"}
+  ],
+  "metadata": {}
+}
+```
+
+#### 消息结果
+
+```json
+{
+  "type": "result",
+  "conversation_id": "conv-abc-123",
+  "success": true,
+  "result": "Response content",
+  "metadata": {}
+}
+```
+
+## HTTP API
+
+### Agent 管理
+
+#### `GET /gateway/agents`
+
+获取所有在线 Agent 列表。
+
+**响应**:
+```json
+{
+  "agents": [
+    {
+      "agent_id": "agent-001",
+      "agent_name": "Research Agent",
+      "capabilities": ["search", "analyze"],
+      "status": "online",
+      "last_heartbeat": "2026-03-04T12:00:00Z"
+    }
+  ]
+}
+```
+
+**实现**:`gateway/core/router.py:GatewayRouter.get_agents`
+
+#### `GET /gateway/agents/{agent_id}`
+
+获取指定 Agent 的详细信息。
+
+**响应**:
+```json
+{
+  "agent_id": "agent-001",
+  "agent_name": "Research Agent",
+  "capabilities": ["search", "analyze"],
+  "status": "online",
+  "last_heartbeat": "2026-03-04T12:00:00Z",
+  "connected_at": "2026-03-04T11:00:00Z"
+}
+```
+
+### 消息发送
+
+#### `POST /gateway/send`
+
+通过 HTTP 发送消息到指定 Agent(适用于无状态客户端)。
+
+**请求体**:
+```json
+{
+  "from_agent_id": "sender-001",
+  "to_agent_id": "receiver-001",
+  "conversation_id": "conv-abc-123",
+  "content": [
+    {"type": "text", "text": "Hello"}
+  ],
+  "metadata": {}
+}
+```
+
+**响应**:
+```json
+{
+  "message_id": "msg-xyz-789",
+  "status": "delivered",
+  "timestamp": "2026-03-04T12:00:00Z"
+}
+```
+
+**实现**:`gateway/core/router.py:GatewayRouter.send_message`
+
+### 状态查询
+
+#### `GET /gateway/status`
+
+获取 Gateway 运行状态。
+
+**响应**:
+```json
+{
+  "status": "running",
+  "version": "1.0.0",
+  "uptime_seconds": 3600,
+  "connected_agents": 5,
+  "total_messages": 1234
+}
+```
+
+## Agent Card 格式
+
+Agent Card 用于描述 Agent 的身份和能力,在首次连接或查询时返回。
+
+```json
+{
+  "agent_id": "agent-001",
+  "agent_name": "Research Agent",
+  "agent_type": "analyst",
+  "capabilities": ["search", "analyze", "summarize"],
+  "description": "专注于信息检索和分析的 Agent",
+  "version": "1.0.0",
+  "owner": {
+    "user_id": "user-123",
+    "device_id": "device-456"
+  },
+  "metadata": {
+    "location": "PC-001",
+    "timezone": "Asia/Shanghai"
+  }
+}
+```
+
+**实现**:`gateway/core/registry.py:AgentRegistry`
+
+## 错误码
+
+| 错误码 | 说明 |
+|-------|------|
+| `AGENT_NOT_FOUND` | 目标 Agent 不在线或不存在 |
+| `INVALID_MESSAGE` | 消息格式错误 |
+| `TIMEOUT` | 消息发送超时 |
+| `UNAUTHORIZED` | 未授权访问(Enterprise 层) |
+| `RATE_LIMIT` | 超过速率限制(Enterprise 层) |
+
+## 配置参数
+
+### Gateway 配置
+
+```python
+# gateway_server.py
+gateway = GatewayRouter(
+    host="0.0.0.0",
+    port=8001,
+    heartbeat_interval=30,  # 心跳间隔(秒)
+    heartbeat_timeout=60,   # 心跳超时(秒)
+)
+```
+
+### Client 配置
+
+```python
+# gateway/core/client.py
+client = GatewayClient(
+    gateway_url="ws://localhost:8001",
+    agent_id="my-agent",
+    agent_name="My Agent",
+    capabilities=["search", "analyze"],
+    auto_reconnect=True,
+    reconnect_interval=5,
+)
+```
+
+## 扩展点
+
+### 自定义消息处理器
+
+```python
+from gateway.core.router import GatewayRouter
+
+class CustomGateway(GatewayRouter):
+    async def handle_custom_message(self, message: dict):
+        # 自定义消息处理逻辑
+        pass
+```
+
+### Enterprise 集成
+
+Gateway 提供扩展点用于集成 Enterprise 层功能:
+
+- **认证**:`gateway/core/auth.py`(规划中)
+- **审计**:`gateway/core/audit.py`(规划中)
+- **速率限制**:`gateway/core/rate_limit.py`(规划中)
+
+详见 [架构文档](./architecture.md#扩展点)。

+ 250 - 0
gateway/docs/architecture.md

@@ -0,0 +1,250 @@
+# Gateway 架构设计
+
+**更新日期:** 2026-03-04
+
+## 文档维护规范
+
+0. **先改文档,再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后,再进行代码实现
+1. **文档分层,链接代码** - 关键实现需标注代码文件路径;格式:`module/file.py:function_name`
+2. **简洁快照,日志分离** - 只记录最重要的、与代码准确对应的或明确的已完成的设计
+
+---
+
+## 架构概述
+
+Gateway 采用三层架构:
+
+```
+┌─────────────────────────────────────────────────┐
+│ Router 层(路由和 API)                          │
+│ - WebSocket 连接处理                             │
+│ - HTTP API 端点                                  │
+│ - 消息路由逻辑                                    │
+└─────────────────────────────────────────────────┘
+                    ↓
+┌─────────────────────────────────────────────────┐
+│ Registry 层(注册和状态)                         │
+│ - Agent 连接信息                                 │
+│ - 在线状态管理                                    │
+│ - 心跳超时检测                                    │
+└─────────────────────────────────────────────────┘
+                    ↓
+┌─────────────────────────────────────────────────┐
+│ Client 层(客户端)                               │
+│ - WebSocket 客户端                               │
+│ - 自动心跳                                        │
+│ - 消息接收处理                                    │
+└─────────────────────────────────────────────────┘
+```
+
+---
+
+## 核心组件
+
+### AgentRegistry
+
+管理在线 Agent 的注册信息和连接。
+
+**实现位置**:`gateway/core/registry.py:AgentRegistry`
+
+**职责**:
+- Agent 注册和注销
+- 在线状态跟踪
+- 心跳超时检测
+- 自动清理过期连接
+
+**关键方法**:
+- `register()` - 注册 Agent
+- `unregister()` - 注销 Agent
+- `heartbeat()` - 更新心跳
+- `is_online()` - 检查在线状态
+- `list_agents()` - 列出 Agent
+
+### GatewayRouter
+
+处理消息路由和 API 端点。
+
+**实现位置**:`gateway/core/router.py:GatewayRouter`
+
+**职责**:
+- WebSocket 连接处理
+- 消息路由到目标 Agent
+- 在线状态查询
+- Agent 列表查询
+
+**API 端点**:
+- `WS /gateway/connect` - Agent 注册
+- `POST /gateway/send` - 发送消息
+- `GET /gateway/status/{agent_uri}` - 查询状态
+- `GET /gateway/agents` - 列出 Agent
+
+### GatewayClient
+
+PC Agent 用于连接 Gateway 的客户端。
+
+**实现位置**:`gateway/core/client.py:GatewayClient`
+
+**职责**:
+- 建立 WebSocket 连接
+- 自动心跳保持
+- 接收和处理消息
+- 发送任务结果
+
+---
+
+## 通信流程
+
+### Agent 注册流程
+
+```
+PC Agent                    Gateway
+   │                           │
+   │  1. WebSocket 连接        │
+   ├──────────────────────────>│
+   │                           │
+   │  2. 发送注册消息          │
+   │  {type: "register",       │
+   │   agent_uri: "...",       │
+   │   capabilities: [...]}    │
+   ├──────────────────────────>│
+   │                           │  Registry.register()
+   │                           │
+   │  3. 返回注册确认          │
+   │  {type: "registered"}     │
+   │<──────────────────────────┤
+   │                           │
+   │  4. 开始心跳循环          │
+   │  (每 30 秒)               │
+   │                           │
+```
+
+### 消息路由流程
+
+```
+Agent A                 Gateway                 Agent B
+   │                       │                       │
+   │  1. 发送消息          │                       │
+   │  POST /gateway/send   │                       │
+   ├──────────────────────>│                       │
+   │                       │  2. 查找目标 Agent    │
+   │                       │  Registry.lookup()    │
+   │                       │                       │
+   │                       │  3. 通过 WebSocket    │
+   │                       │     转发消息          │
+   │                       ├──────────────────────>│
+   │                       │                       │
+   │  4. 返回成功          │                       │
+   │<──────────────────────┤                       │
+```
+
+---
+
+## 设计决策
+
+### 决策 1:反向连接模式
+
+**问题**:PC Agent 在 NAT 后面,如何被其他 Agent 访问?
+
+**决策**:PC Agent 主动连接 Gateway(反向连接)
+
+**理由**:
+- 无需公网 IP
+- 无需配置防火墙
+- 安全(只有出站连接)
+- 类似飞书 Bot 模式
+
+**实现位置**:`gateway/core/client.py:GatewayClient.connect`
+
+### 决策 2:心跳机制
+
+**问题**:如何判断 Agent 是否在线?
+
+**决策**:每 30 秒发送心跳,60 秒超时
+
+**理由**:
+- 及时检测离线
+- 避免频繁心跳消耗资源
+- 自动清理过期连接
+
+**实现位置**:`gateway/core/registry.py:AgentRegistry._cleanup_loop`
+
+### 决策 3:WebSocket vs HTTP
+
+**问题**:使用 WebSocket 还是 HTTP 轮询?
+
+**决策**:WebSocket 长连接
+
+**理由**:
+- 实时性好(无需轮询)
+- 资源消耗低
+- 支持双向通信
+- 适合 IM 场景
+
+**实现位置**:`gateway/core/router.py:GatewayRouter.handle_websocket`
+
+---
+
+## 扩展点
+
+### 中间件机制
+
+可以添加中间件来扩展功能:
+
+```python
+class AuthMiddleware:
+    async def process(self, msg):
+        # 认证检查
+        if not await self.auth.verify(msg):
+            raise Unauthorized()
+        return msg
+
+router = GatewayRouter(
+    registry=registry,
+    middlewares=[AuthMiddleware(), AuditMiddleware()]
+)
+```
+
+### Enterprise 集成
+
+Enterprise 功能可以作为中间件集成:
+
+```python
+from gateway.enterprise import EnterpriseAuth, EnterpriseAudit
+
+router = GatewayRouter(
+    registry=registry,
+    middlewares=[
+        EnterpriseAuth(),
+        EnterpriseAudit(),
+        CostMiddleware()
+    ]
+)
+```
+
+---
+
+## 性能考虑
+
+### 连接数限制
+
+- 单个 Gateway 实例:建议 < 10000 个连接
+- 超过限制:部署多个 Gateway 实例
+
+### 消息吞吐量
+
+- 单个 Gateway 实例:约 1000 msg/s
+- 瓶颈:WebSocket 连接数和消息序列化
+
+### 扩展方案
+
+- 水平扩展:部署多个 Gateway 实例
+- 负载均衡:使用 Nginx/HAProxy
+- 服务发现:使用 Consul/etcd
+
+---
+
+## 相关文档
+
+- [部署指南](./deployment.md):部署方式和配置
+- [API 文档](./api.md):完整的 API 参考
+- [A2A IM 系统](../../docs/a2a-im.md):完整的 A2A IM 文档

+ 139 - 0
gateway/docs/decisions.md

@@ -0,0 +1,139 @@
+# Gateway 设计决策
+
+## 文档说明
+
+本文档记录 Gateway 模块的架构决策、设计权衡和实现选择。
+
+---
+
+## 决策记录
+
+### 1. Gateway 与 Agent Core 并列而非嵌套
+
+**日期**:2026-03-04
+
+**背景**:
+- Gateway 负责 Agent 注册、消息路由、在线状态管理
+- Agent Core 负责 Agent 执行引擎、工具系统、记忆管理
+- 两者功能独立,可以分别部署
+
+**决策**:
+- Gateway 和 Agent Core 作为并列的顶层模块(gateway/ 和 agent/)
+- 单向依赖:Gateway 可以依赖 Agent Core,但 Agent Core 不依赖 Gateway
+- Agent Core 可以独立运行(本地 Agent),Gateway 可选
+
+**理由**:
+1. **解耦**:两个模块职责清晰,可以独立开发和部署
+2. **灵活性**:支持多种部署模式(单机、分离、分布式)
+3. **可维护性**:模块边界清晰,便于理解和维护
+
+**替代方案**:
+- 方案 A:Gateway 作为 agent/gateway/(嵌套)
+  - 缺点:暗示 Gateway 是 Agent 的子模块,但实际上 Gateway 是独立的服务
+- 方案 B:Gateway 作为 integrations/gateway/
+  - 缺点:Gateway 不是第三方集成,而是核心基础设施
+
+---
+
+### 2. 反向连接模式(Reverse Connection)
+
+**日期**:2026-03-04
+
+**背景**:
+- PC 端 Agent 通常没有公网 IP
+- 需要支持 NAT 穿透
+
+**决策**:
+- PC Agent 主动连接到 Gateway(WebSocket)
+- Gateway 维护连接映射,路由消息到目标 Agent
+
+**理由**:
+1. **无需公网 IP**:PC Agent 不需要暴露端口
+2. **简单可靠**:避免 NAT 穿透的复杂性
+3. **实时性**:WebSocket 保持长连接,消息实时送达
+
+**替代方案**:
+- 方案 A:P2P 直连
+  - 缺点:需要 NAT 穿透,实现复杂
+- 方案 B:轮询模式
+  - 缺点:延迟高,资源消耗大
+
+---
+
+### 3. 心跳机制
+
+**日期**:2026-03-04
+
+**背景**:
+- 需要检测 Agent 在线状态
+- WebSocket 连接可能静默断开
+
+**决策**:
+- Agent 每 30 秒发送心跳
+- Gateway 超过 60 秒未收到心跳则标记为离线
+- 自动清理过期连接
+
+**理由**:
+1. **及时检测**:快速发现断线 Agent
+2. **资源管理**:自动清理无效连接
+3. **简单可靠**:无需复杂的健康检查
+
+**参数选择**:
+- 心跳间隔 30s:平衡实时性和网络开销
+- 超时时间 60s:允许一次心跳丢失
+
+---
+
+### 4. Enterprise 作为 Gateway 扩展层
+
+**日期**:2026-03-04
+
+**背景**:
+- Enterprise 层提供认证、审计、多租户等功能
+- 个人部署不需要 Enterprise 功能
+
+**决策**:
+- Enterprise 作为 Gateway 的可选扩展层
+- 通过中间件模式集成(auth.py, audit.py, rate_limit.py)
+- 文档放在 gateway/docs/enterprise/
+
+**理由**:
+1. **可选部署**:个人用户可以只部署 Gateway,不部署 Enterprise
+2. **清晰分层**:Enterprise 扩展 Gateway 功能,关系明确
+3. **易于扩展**:中间件模式便于添加新功能
+
+**替代方案**:
+- 方案 A:Enterprise 作为独立顶层模块
+  - 缺点:增加部署复杂度,Enterprise 主要扩展 Gateway
+- 方案 B:Enterprise 功能内置到 Gateway
+  - 缺点:个人用户也要承担 Enterprise 的复杂度
+
+---
+
+### 5. 消息格式采用 MAMP 协议
+
+**日期**:2026-03-04
+
+**背景**:
+- 需要与外部 Agent 系统通信
+- 需要支持多模态内容
+
+**决策**:
+- 采用 MAMP(Minimal Agent Message Protocol)
+- 消息格式参考 Anthropic SDK
+- 支持 conversation_id 管理对话
+
+**理由**:
+1. **简洁**:最小化协议,易于实现
+2. **兼容**:与 Anthropic SDK 格式对齐
+3. **扩展性**:支持多模态和元数据
+
+**详细设计**:见 [MAMP 协议](../../../docs/research/a2a-mamp-protocol.md)
+
+---
+
+## 相关文档
+
+- [Agent Core 设计决策](../../agent/docs/decisions.md)
+- [架构设计](./architecture.md)
+- [A2A IM 系统](../../../docs/a2a-im.md)

+ 360 - 0
gateway/docs/deployment.md

@@ -0,0 +1,360 @@
+# Gateway 部署指南
+
+**更新日期:** 2026-03-04
+
+## 文档维护规范
+
+0. **先改文档,再动代码**
+1. **文档分层,链接代码**
+2. **简洁快照,日志分离**
+
+---
+
+## 部署方式
+
+### 方式 1:单体部署(开发/小团队)
+
+一个进程运行 Agent Core + Gateway。
+
+```bash
+# 启动
+python main.py
+
+# 配置
+# config/gateway.yaml
+gateway:
+  enabled: true
+  port: 8000
+  heartbeat_timeout: 60
+```
+
+**适用场景**:
+- 开发环境
+- 小团队(< 10 个 Agent)
+- 快速原型
+
+### 方式 2:分离部署(生产环境)
+
+两个独立进程。
+
+```bash
+# 终端 1:启动 Agent Core
+python api_server.py
+
+# 终端 2:启动 Gateway
+python gateway_server.py
+```
+
+**配置**:
+
+```yaml
+# config/gateway.yaml
+gateway:
+  port: 8000
+  agent_api: http://localhost:8001  # Agent Core API
+  heartbeat_timeout: 60
+```
+
+**适用场景**:
+- 生产环境
+- 中等规模(10-1000 个 Agent)
+- 需要独立扩展
+
+### 方式 3:分层部署(大规模/企业)
+
+三个独立进程。
+
+```bash
+# 终端 1:Agent Core
+python api_server.py
+
+# 终端 2:Gateway Core
+python gateway_server.py
+
+# 终端 3:Enterprise Gateway
+python enterprise_gateway.py
+```
+
+**适用场景**:
+- 大规模(> 1000 个 Agent)
+- 企业部署
+- 需要独立扩展各层
+
+---
+
+## Docker 部署
+
+### 单容器部署
+
+```dockerfile
+# Dockerfile
+FROM python:3.11-slim
+
+WORKDIR /app
+COPY . .
+RUN pip install -r requirements.txt
+
+CMD ["python", "gateway_server.py"]
+```
+
+```bash
+# 构建
+docker build -t a2a-gateway .
+
+# 运行
+docker run -p 8000:8000 a2a-gateway
+```
+
+### Docker Compose 部署
+
+```yaml
+# docker-compose.yml
+version: '3.8'
+
+services:
+  agent-core:
+    build: .
+    command: python api_server.py
+    ports:
+      - "8001:8001"
+    volumes:
+      - ./.trace:/app/.trace
+
+  gateway:
+    build: .
+    command: python gateway_server.py
+    ports:
+      - "8000:8000"
+    environment:
+      - AGENT_API=http://agent-core:8001
+    depends_on:
+      - agent-core
+```
+
+```bash
+# 启动
+docker-compose up -d
+
+# 查看日志
+docker-compose logs -f gateway
+```
+
+---
+
+## 配置
+
+### 基础配置
+
+```yaml
+# config/gateway.yaml
+gateway:
+  # 服务配置
+  host: 0.0.0.0
+  port: 8000
+
+  # 注册表配置
+  heartbeat_timeout: 60  # 心跳超时(秒)
+  cleanup_interval: 30   # 清理间隔(秒)
+
+  # Agent Core API
+  agent_api: http://localhost:8001
+```
+
+### Enterprise 配置
+
+```yaml
+# config/gateway.yaml
+gateway:
+  # ... 基础配置
+
+  # Enterprise 功能
+  enterprise:
+    enabled: true
+
+    # 认证
+    auth:
+      provider: feishu_oauth
+      feishu:
+        app_id: xxx
+        app_secret: xxx
+
+    # 审计
+    audit:
+      enabled: true
+      log_file: /var/log/gateway/audit.jsonl
+
+    # 成本管理
+    cost:
+      enabled: true
+      user_daily_limit: 1000  # Token 限额
+```
+
+---
+
+## 监控
+
+### 健康检查
+
+```bash
+# 检查 Gateway 状态
+curl http://localhost:8000/health
+
+# 返回
+{
+  "status": "ok",
+  "agents_online": 5,
+  "uptime": 3600
+}
+```
+
+### 指标监控
+
+```python
+# 暴露 Prometheus 指标
+from prometheus_client import Counter, Gauge
+
+agents_online = Gauge('gateway_agents_online', 'Number of online agents')
+messages_sent = Counter('gateway_messages_sent', 'Total messages sent')
+```
+
+### 日志
+
+```python
+# 配置日志
+import logging
+
+logging.basicConfig(
+    level=logging.INFO,
+    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
+    handlers=[
+        logging.FileHandler('/var/log/gateway/gateway.log'),
+        logging.StreamHandler()
+    ]
+)
+```
+
+---
+
+## 扩展
+
+### 水平扩展
+
+部署多个 Gateway 实例:
+
+```bash
+# 实例 1
+python gateway_server.py --port 8000
+
+# 实例 2
+python gateway_server.py --port 8001
+
+# 实例 3
+python gateway_server.py --port 8002
+```
+
+使用负载均衡器:
+
+```nginx
+# nginx.conf
+upstream gateway {
+    server localhost:8000;
+    server localhost:8001;
+    server localhost:8002;
+}
+
+server {
+    listen 80;
+    location /gateway/ {
+        proxy_pass http://gateway;
+        proxy_http_version 1.1;
+        proxy_set_header Upgrade $http_upgrade;
+        proxy_set_header Connection "upgrade";
+    }
+}
+```
+
+### 服务发现
+
+使用 Consul 进行服务发现:
+
+```python
+# 注册到 Consul
+import consul
+
+c = consul.Consul()
+c.agent.service.register(
+    name='gateway',
+    service_id='gateway-1',
+    address='localhost',
+    port=8000,
+    check=consul.Check.http('http://localhost:8000/health', '10s')
+)
+```
+
+---
+
+## 故障排查
+
+### 问题:Agent 无法连接
+
+**症状**:PC Agent 连接失败
+
+**排查**:
+1. 检查 Gateway 是否启动:`curl http://localhost:8000/health`
+2. 检查防火墙:`telnet localhost 8000`
+3. 查看 Gateway 日志
+
+### 问题:消息发送失败
+
+**症状**:send_to_agent 返回错误
+
+**排查**:
+1. 检查目标 Agent 是否在线:`GET /gateway/status/{agent_uri}`
+2. 检查 agent_uri 格式
+3. 查看 Gateway 日志
+
+### 问题:心跳超时
+
+**症状**:Agent 频繁离线
+
+**排查**:
+1. 检查网络稳定性
+2. 调整 heartbeat_timeout 配置
+3. 检查 PC Agent 心跳逻辑
+
+---
+
+## 安全
+
+### HTTPS/WSS
+
+使用 SSL 证书:
+
+```python
+import ssl
+
+ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+ssl_context.load_cert_chain('cert.pem', 'key.pem')
+
+uvicorn.run(app, host="0.0.0.0", port=8000, ssl=ssl_context)
+```
+
+### 认证
+
+添加 API Key 认证:
+
+```python
+from fastapi import Header, HTTPException
+
+async def verify_api_key(x_api_key: str = Header(...)):
+    if x_api_key not in valid_api_keys:
+        raise HTTPException(401, "Invalid API Key")
+```
+
+---
+
+## 相关文档
+
+- [架构设计](./architecture.md):Gateway 架构和设计决策
+- [API 文档](./api.md):完整的 API 参考
+- [A2A IM 系统](../../docs/a2a-im.md):完整的 A2A IM 文档

+ 370 - 0
gateway/docs/enterprise/implementation.md

@@ -0,0 +1,370 @@
+# Enterprise 层技术实现
+
+## 文档说明
+
+本文档描述 Enterprise 层的技术实现细节,包括认证、审计、多租户等模块的设计和接口。
+
+**相关文档**:
+- [组织级概览](./overview.md):整体架构和业务场景
+- [Scope 设计](../../../docs/scope-design.md):知识可见性和权限控制
+- [知识管理](../../../docs/knowledge.md):知识结构和检索机制
+
+---
+
+## 概述
+
+Enterprise 层提供组织级功能,包括认证、审计、多租户支持等。单向依赖 Core 层,通过扩展点集成。
+
+## 架构分层
+
+```
+┌─────────────────────────────────────────────────┐
+│  Integrations Layer (integrations/)             │
+│  - 第三方平台集成(飞书、Slack 等)               │
+│  - 依赖:Core + Enterprise                       │
+└────────────────┬────────────────────────────────┘
+                 │
+                 ▼
+┌─────────────────────────────────────────────────┐
+│  Enterprise Layer (enterprise/)                 │
+│  - 组织功能(认证、审计、多租户)                  │
+│  - 依赖:Core                                    │
+└────────────────┬────────────────────────────────┘
+                 │
+                 ▼
+┌─────────────────────────────────────────────────┐
+│  Core Layer (agent/)                            │
+│  - 核心 Agent 能力                               │
+│  - 零外部依赖                                    │
+└─────────────────────────────────────────────────┘
+```
+
+## 模块结构
+
+```
+enterprise/
+├── gateway/                    # 网关层
+│   ├── middleware.py           # 中间件基类
+│   ├── auth.py                 # 认证中间件
+│   ├── audit.py                # 审计中间件
+│   ├── rate_limit.py           # 限额中间件
+│   └── router.py               # 企业级路由
+│
+├── auth/                       # 认证系统
+│   ├── providers/              # 认证提供者
+│   │   ├── api_key.py          # API Key 认证
+│   │   ├── jwt.py              # JWT 认证
+│   │   └── oauth.py            # OAuth 认证
+│   ├── models.py               # User, APIKey, Role
+│   └── permissions.py          # 权限检查
+│
+├── audit/                      # 审计系统
+│   ├── logger.py               # 审计日志记录器
+│   ├── events.py               # 事件定义
+│   ├── storage.py              # 存储接口
+│   └── query.py                # 日志查询
+│
+└── multi_tenant/               # 多租户支持
+    ├── tenant.py               # 租户管理
+    ├── isolation.py            # 数据隔离
+    └── quota.py                # 配额管理
+```
+
+## Core 层扩展点
+
+### 1. 中间件扩展点
+
+**位置**:`agent/trace/api.py:TraceAPI.__init__`
+
+```python
+class TraceAPI:
+    def __init__(
+        self,
+        trace_store: TraceStore,
+        runner: Optional[AgentRunner] = None,
+        middlewares: Optional[List[Callable]] = None  # 扩展点
+    )
+```
+
+**用途**:在 API 入口注入认证、审计、限额等中间件
+
+**Enterprise 实现**:
+- `enterprise/gateway/auth.py:auth_middleware`
+- `enterprise/gateway/audit.py:audit_middleware`
+- `enterprise/gateway/rate_limit.py:rate_limit_middleware`
+
+### 2. 钩子扩展点
+
+**位置**:`agent/core/runner.py:AgentRunner.__init__`
+
+```python
+class AgentRunner:
+    def __init__(
+        self,
+        trace_store: TraceStore,
+        hooks: Optional[Dict[str, List[Callable]]] = None  # 扩展点
+    )
+```
+
+**钩子类型**:
+- `trace.created`:Trace 创建后
+- `llm.called`:LLM 调用后
+- `trace.completed`:Trace 完成后
+- `tool.executed`:工具执行后
+
+**Enterprise 实现**:
+- `enterprise/audit/hooks.py:audit_trace_created`
+- `enterprise/audit/hooks.py:audit_llm_called`
+- `enterprise/audit/hooks.py:audit_trace_completed`
+
+### 3. Context 注入
+
+**位置**:`agent/core/runner.py:RunConfig.context`
+
+```python
+@dataclass
+class RunConfig:
+    context: Optional[Dict[str, Any]] = None  # 扩展点
+```
+
+**用途**:传递用户身份、权限、来源等信息
+
+**Context 结构**:
+```python
+{
+    "user_id": "user_123",
+    "org_id": "company",
+    "role": "member",
+    "source": "feishu",
+    "ip": "192.168.1.100"
+}
+```
+
+## 认证系统
+
+### API Key 认证
+
+**格式**:`ak_{org_id}_{user_id}_{random}`
+
+**示例**:`ak_company_user123_a1b2c3d4`
+
+**数据模型**:
+
+```sql
+CREATE TABLE api_keys (
+    id TEXT PRIMARY KEY,
+    key_hash TEXT UNIQUE,
+    user_id TEXT REFERENCES users(id),
+    org_id TEXT,
+    name TEXT,
+    scopes JSON,
+    rate_limit INTEGER,
+    expires_at TIMESTAMP,
+    last_used_at TIMESTAMP,
+    created_at TIMESTAMP
+);
+```
+
+**实现位置**:`enterprise/auth/providers/api_key.py`
+
+### 飞书 OAuth
+
+**流程**:
+1. 飞书 Webhook 携带 `user_open_id`
+2. 查询用户映射表
+3. 构建执行上下文
+
+**数据模型**:
+
+```sql
+CREATE TABLE feishu_users (
+    feishu_user_id TEXT PRIMARY KEY,
+    system_user_id TEXT REFERENCES users(id),
+    org_id TEXT,
+    department_id TEXT,
+    name TEXT,
+    created_at TIMESTAMP
+);
+```
+
+**实现位置**:`integrations/feishu/auth.py`
+
+## 权限系统
+
+### 角色定义
+
+| 角色 | 权限 |
+|------|------|
+| admin | 所有权限 |
+| member | 查询代码库、创建 Trace、读写知识 |
+| viewer | 只读权限 |
+
+### 权限检查点
+
+1. **API 入口**:验证身份和基础权限
+2. **资源访问**:检查 scope 权限(知识访问)
+3. **操作执行**:检查操作权限(创建、删除等)
+
+**实现位置**:`enterprise/auth/permissions.py`
+
+## 审计系统
+
+### 审计日志类型
+
+| 类型 | 文件 | 内容 |
+|------|------|------|
+| 操作审计 | audit.jsonl | API 调用、资源访问、配置修改 |
+| 成本审计 | cost.jsonl | Token 消耗、API 调用成本 |
+| 安全审计 | security.jsonl | 认证失败、权限拒绝、异常访问 |
+| 知识审计 | knowledge.jsonl | 知识的创建、修改、查询 |
+
+### 操作审计格式
+
+```json
+{
+  "id": "audit_001",
+  "timestamp": "2026-03-04T02:30:00Z",
+  "user_id": "user_123",
+  "org_id": "company",
+  "action": "trace.create",
+  "resource_type": "trace",
+  "resource_id": "trace-abc-123",
+  "status": "success",
+  "tokens_used": 1500,
+  "cost": 0.015,
+  "metadata": {}
+}
+```
+
+### 审计记录时机
+
+- `auth.*`:认证相关事件
+- `trace.*`:Trace 生命周期事件
+- `knowledge.*`:知识操作事件
+- `permission.denied`:权限拒绝事件
+
+**实现位置**:
+- `enterprise/audit/logger.py`:日志记录器
+- `enterprise/audit/events.py`:事件定义
+- `enterprise/audit/storage.py`:存储接口
+
+## 限额控制
+
+### 限额维度
+
+**用户级**:
+- 每日 API 调用次数:1000
+- 每日 Token 消耗:100K
+- 并发 Trace 数:3
+
+**组织级**:
+- 每月总 Token 消耗:10M
+- 存储空间:100GB
+- 知识条目数:10K
+
+### 检查时机
+
+- API 入口:检查调用次数
+- Trace 创建前:检查并发数和 Token 配额
+- 知识保存前:检查存储空间
+
+**实现位置**:
+- `enterprise/gateway/rate_limit.py`:限额中间件
+- `enterprise/multi_tenant/quota.py`:配额管理
+
+## 多租户支持
+
+### 租户隔离
+
+- 数据隔离:通过 `org_id` 过滤
+- 存储隔离:独立的 Trace 目录
+- 配额隔离:独立的限额计数
+
+**实现位置**:`enterprise/multi_tenant/isolation.py`
+
+## 配置文件
+
+```yaml
+# config/enterprise.yaml
+enterprise:
+  enabled: true
+
+  auth:
+    providers:
+      - api_key
+      - feishu_oauth
+
+  audit:
+    enabled: true
+    log_dir: ./workspace/audit
+    retention_days: 90
+
+  rate_limit:
+    enabled: true
+    default_quota:
+      calls_per_day: 1000
+      tokens_per_day: 100000
+```
+
+## 启用方式
+
+### 个人使用(不启用 Enterprise)
+
+```python
+from agent.core.runner import AgentRunner
+
+runner = AgentRunner(trace_store=store)
+```
+
+### 组织部署(启用 Enterprise)
+
+```python
+from agent.core.runner import AgentRunner
+from enterprise.gateway.router import EnterpriseRouter
+
+# 创建 Runner(带钩子)
+runner = AgentRunner(
+    trace_store=store,
+    hooks={
+        "trace.created": [audit_trace_created],
+        "llm.called": [audit_llm_called]
+    }
+)
+
+# 创建企业级 Router(带中间件)
+router = EnterpriseRouter(
+    runner=runner,
+    auth_config=auth_config,
+    audit_config=audit_config
+)
+```
+
+## 包依赖
+
+```toml
+[project.optional-dependencies]
+enterprise = [
+    "fastapi>=0.100.0",
+    "sqlalchemy>=2.0.0",
+    "redis>=5.0.0",
+    "pyjwt>=2.8.0",
+]
+```
+
+## 实现状态
+
+| 模块 | 状态 | 实现位置 |
+|------|------|---------|
+| 中间件基类 | 规划中 | enterprise/gateway/middleware.py |
+| API Key 认证 | 规划中 | enterprise/auth/providers/api_key.py |
+| 审计日志 | 规划中 | enterprise/audit/logger.py |
+| 限额控制 | 规划中 | enterprise/gateway/rate_limit.py |
+| 多租户支持 | 规划中 | enterprise/multi_tenant/ |
+
+## 相关文档
+
+- [组织级概览](./overview.md):整体架构和业务场景
+- [Scope 设计](../scope-design.md):知识可见性和权限控制
+- [知识管理](../knowledge.md):知识结构和检索机制
+- [A2A 跨设备通信](../research/a2a-cross-device.md):跨设备 Agent 通信方案
+

+ 288 - 0
gateway/docs/enterprise/overview.md

@@ -0,0 +1,288 @@
+# 组织级 Agent 系统概览
+
+## 文档维护规范
+
+0. **先改文档,再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后,再进行代码实现;除非改动较小、不被文档涵盖
+1. **文档分层,链接代码** - 重要或复杂设计可以另有详细文档;关键实现需标注代码文件路径;格式:`module/file.py:function_name`
+2. **简洁快照,日志分离** - 只记录最重要的、与代码准确对应的或者明确的已完成的设计的信息,避免推测、建议,或大量代码;决策依据或修改日志若有必要,可在`docs/decisions.md`另行记录
+
+## 文档说明
+
+本文档描述组织级 Agent 系统的整体架构、业务场景和 MVP 规划。
+
+**Enterprise 文档结构**:
+- **overview.md**(本文档):整体架构、业务场景、MVP 规划
+- **[implementation.md](./implementation.md)**:认证、审计、多租户技术实现
+
+**相关文档**:
+- [知识管理](../../../docs/knowledge.md):知识结构、检索、提取机制
+- [Scope 设计](../../../docs/scope-design.md):知识可见性和权限控制
+- [Agent 框架](../../../docs/README.md):核心 Agent 能力
+
+---
+
+## 原则
+
+- 智能、共享、积累成长
+- 未来人的工作是产生新的能力
+
+## 架构
+
+### 1. 用户交互层
+
+**飞书空间组成**:
+
+**人类员工**:
+- 运营人员
+- 编辑
+- 管理员
+
+**通用助理(入口 Agent)**:
+- 处理一般性问题
+- 智能路由到职能 Agent
+- 协调多个 Agent 协作
+
+**职能 Agent(专业领域)**:
+- 爬虫运维 Agent
+- 内容库 Agent
+- 成本统计 Agent
+
+**交互模式**:
+- 单聊:用户 ↔ 通用助理 / 职能 Agent
+- 群聊:项目群(人 + 多个 Agent)
+- @ 调用:群里 @爬虫运维 检查状态
+- 智能路由:通用助理识别意图 → 转接职能 Agent
+
+---
+
+### 2. 网关层(Gateway)
+
+网关层负责请求的认证、鉴权、路由和审计。详细技术设计见 [Enterprise 层实现](./implementation.md)。
+
+#### 核心功能
+
+- **认证**:飞书 OAuth、API Key、JWT
+- **权限控制**:角色验证、资源访问控制、操作权限检查
+- **成本与限额**:用户级/组织级限额、实时成本计算、超限告警
+- **审计**:操作日志、成本记录、安全事件、合规追溯
+- **路由**:识别目标 Agent、上下文加载、会话管理、多 Agent 协作
+- **消息队列**:异步任务、定时任务、事件触发、优先级队列
+
+**实现位置**:`enterprise/gateway/`
+
+**扩展点**:
+- 中间件:`agent/trace/api.py:TraceAPI.middlewares`
+- 钩子:`agent/core/runner.py:AgentRunner.hooks`
+- Context:`agent/core/runner.py:RunConfig.context`
+
+---
+
+### 3. Agent 执行层
+
+#### Agent Runner(基于现有框架)
+
+**输入**:`messages + config (user_id, agent_id, context)`
+
+**Phase 1: 准备阶段**
+- 创建/加载 Trace
+- 加载 Agent 配置(职责、能力、权限)
+- 初始化工作空间
+
+**Phase 2: 上下文构建**
+- 加载用户画像(type=user_profile, scopes 包含 user_id)
+- 加载 Agent 记忆(type=strategy, scopes 包含 agent_id)
+- 注入全局知识库(scopes=global 或 org:{org_id})
+- 注入资源文档
+- 构建 system prompt
+
+**Phase 3: 执行循环**
+- LLM 推理
+- 工具调用
+- 知识库查询/提交
+- 子 Agent 协作
+- 结果生成
+
+**Phase 4: 完成阶段**
+- 保存 Trace
+- 同步到对话文件
+- 更新 Agent 记忆
+- 记录成本
+- 返回结果
+
+**输出**:`Trace + Messages`(流式)
+
+#### 工具系统(Tools)
+
+**内置工具**:
+- 文件操作(read, write, edit, glob, grep)
+- 命令执行(bash, sandbox)
+- 网络工具(web_search, webfetch)
+- 浏览器自动化
+- 子 Agent 调用(agent, evaluate)
+
+**知识库工具**:
+- query_knowledge(查询知识,支持 type 和 scopes 过滤)
+- save_knowledge(保存知识,自动设置 scopes 和 owner)
+
+**领域工具(可扩展)**:
+- 爬虫管理工具
+- 内容库查询工具
+- 成本统计工具
+- 自定义工具...
+
+---
+
+### 4. 知识管理层
+
+知识管理层负责知识的存储、检索和权限控制。详细设计见:
+- [知识管理文档](./knowledge.md):知识结构、检索、提取机制
+- [Scope 设计文档](./scope-design.md):知识可见性和权限控制
+
+#### 文件系统存储(File System)
+
+```
+/workspace/
+├── conversations/              # 对话记录
+│   ├── {user_id}/              # 按用户组织
+│   │   ├── YYYY-MM-DD.md       # 每日对话
+│   │   ├── summary/            # 定期总结
+│   │   └── metadata.json       # 权限元数据
+│   └── ...
+│
+├── agents/                     # Agent 工作空间
+│   ├── general_assistant/      # 通用助理
+│   │   ├── profile.json        # 配置
+│   │   └── memory/             # 持久记忆
+│   │
+│   ├── crawler_ops/            # 爬虫运维 Agent
+│   │   ├── profile.json
+│   │   ├── memory/             # 持久记忆
+│   │   │   ├── working.md      # 当前状态
+│   │   │   ├── history/        # 历史记录
+│   │   │   └── relations.json  # 协作关系
+│   │   └── tasks/              # 任务队列
+│   │
+│   ├── content_library/        # 内容库 Agent
+│   └── cost_analytics/         # 成本统计 Agent
+│
+├── resources/                  # 组织资源(只读)
+│   ├── company/                # 公司信息
+│   ├── docs/                   # 业务文档
+│   ├── processes/              # 流程规范
+│   └── metadata.json           # 权限配置
+│
+├── knowledge/                  # 统一知识库(新增)
+│   ├── global/                 # 全局知识(scopes=global)
+│   ├── agents/                 # Agent 经验(scopes=agent:xxx)
+│   └── users/                  # 用户画像(scopes=user:xxx)
+│
+└── traces/                     # 执行记录
+    ├── {user_id}/              # 用户的 Trace
+    ├── {agent_id}/             # Agent 的 Trace
+    └── metadata.json           # 权限元数据
+```
+
+#### 知识库数据库(KnowHub Database)
+
+统一知识表,支持用户画像、执行经验、工具知识等多种类型。
+
+**核心字段**:
+- `type`:知识类型(user_profile, strategy, tool, usecase, definition, plan)
+- `scopes`:可见范围(user:xxx, agent:xxx, project:xxx, team:xxx, org:xxx, public)
+- `owner`:所有者(唯一,控制修改权限)
+- `embedding`:向量检索
+
+**详细设计**:见 [知识管理文档](./knowledge.md) 和 [Scope 设计文档](./scope-design.md)
+
+**实现位置**:`agent/memory/knowledge_store.py`
+
+#### 代码库
+
+对 Agent 的可见性(待定义)
+
+---
+
+### 5. 基础设施层
+
+基础设施层提供审计、监控、配置管理等支撑功能。详细技术设计见 [Enterprise 层实现](./implementation.md)。
+
+#### 审计与监控(Audit & Monitoring)
+
+**审计日志**:
+- `audit.jsonl`:操作审计(API 调用、资源访问)
+- `cost.jsonl`:成本记录(Token 消耗、费用统计)
+- `security.jsonl`:安全审计(认证失败、权限拒绝)
+- `knowledge.jsonl`:知识审计(知识的创建、修改、查询)
+
+**监控指标**:
+- 调用频率、成功率、响应时间
+- Token 消耗、成本统计、限额告警
+- 异常检测、安全事件
+
+**实现位置**:`enterprise/audit/`
+
+#### 配置管理(Configuration)
+
+```
+/workspace/config/
+├── system.yaml                 # 系统配置
+├── agents.yaml                 # Agent 配置
+├── permissions.yaml            # 权限配置
+├── limits.yaml                 # 限额配置
+└── feishu.yaml                 # 飞书配置
+```
+
+#### 备份与恢复(Backup & Recovery)
+- 定期备份(对话、Trace、知识库)
+- 增量备份
+- 灾难恢复
+
+---
+
+## MVP 实施阶段
+
+### Phase 1: 基础设施(Week 1-2)
+
+**目标**:建立权限、审计、成本控制基础
+
+**任务**:
+- 实现 API Key 认证(`enterprise/auth/providers/api_key.py`)
+- 实现飞书用户映射(`integrations/feishu/auth.py`)
+- 实现审计日志系统(`enterprise/audit/logger.py`)
+- 实现基础权限检查(`enterprise/auth/permissions.py`)
+- 实现成本记录(`enterprise/audit/hooks.py`)
+
+**原则**:权限和审计不能妥协,必须从一开始做对
+
+### Phase 2: 通用助理(Week 3-4)
+
+**目标**:
+- 创建通用助理飞书账号
+- 实现基础对话功能
+- 对话同步到文件系统
+- 知识库数据库设计和接口
+- 知识库工具实现(query_knowledge/save_knowledge)
+- 用户画像提取和检索机制
+
+### Phase 3: 职能 Agent(Week 5-6)
+
+**目标**:
+- 选择一个高价值场景
+- 创建职能 Agent 飞书账号
+- 实现 Agent 记忆持久化
+- 实现领域工具集成
+- 测试通用助理 → 职能 Agent 路由
+
+**原则**:
+- 选择痛点明确、价值可量化的场景
+- 验证职能 Agent 的记忆和专业能力
+- 测试 Agent 间协作
+
+---
+
+## 相关文档
+
+- [Enterprise 层实现](./implementation.md):认证、审计、多租户技术实现
+- [知识管理](../knowledge.md):知识结构、检索、提取机制
+- [Scope 设计](../scope-design.md):知识可见性和权限控制
+- [Agent 框架](../README.md):核心 Agent 能力

+ 36 - 0
gateway/setup.py

@@ -0,0 +1,36 @@
+"""
+Gateway Client - Python SDK and CLI
+
+通用的 Gateway 客户端,提供:
+- Python SDK (GatewayClient, tools)
+- CLI 工具 (gateway-cli)
+"""
+
+from setuptools import setup, find_packages
+
+setup(
+    name="gateway-client",
+    version="0.1.0",
+    description="Gateway Client SDK and CLI for A2A IM",
+    author="Agent Team",
+    packages=find_packages(),
+    install_requires=[
+        "httpx>=0.24.0",
+        "click>=8.0.0",
+    ],
+    entry_points={
+        'console_scripts': [
+            'gateway-cli=gateway.client.python.cli:cli',
+        ],
+    },
+    python_requires=">=3.8",
+    classifiers=[
+        "Development Status :: 3 - Alpha",
+        "Intended Audience :: Developers",
+        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 3.8",
+        "Programming Language :: Python :: 3.9",
+        "Programming Language :: Python :: 3.10",
+        "Programming Language :: Python :: 3.11",
+    ],
+)

+ 86 - 0
gateway_server.py

@@ -0,0 +1,86 @@
+"""
+A2A IM Gateway Server
+
+启动 Gateway 服务器,提供 Agent 注册和消息路由
+"""
+
+import asyncio
+import logging
+from fastapi import FastAPI
+from fastapi.middleware.cors import CORSMiddleware
+import uvicorn
+
+from gateway.core.registry import AgentRegistry
+from gateway.core.router import GatewayRouter
+
+# 配置日志
+logging.basicConfig(
+    level=logging.INFO,
+    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+)
+
+logger = logging.getLogger(__name__)
+
+
+def create_gateway_app() -> FastAPI:
+    """创建 Gateway FastAPI 应用"""
+
+    app = FastAPI(
+        title="A2A IM Gateway",
+        description="Agent 即时通讯网关",
+        version="1.0.0"
+    )
+
+    # 添加 CORS 中间件
+    app.add_middleware(
+        CORSMiddleware,
+        allow_origins=["*"],
+        allow_credentials=True,
+        allow_methods=["*"],
+        allow_headers=["*"],
+    )
+
+    # 创建 Registry
+    registry = AgentRegistry(heartbeat_timeout=60)
+
+    # 创建 Router
+    router = GatewayRouter(registry)
+
+    # 注册路由
+    app.include_router(router.router)
+
+    # 启动和关闭事件
+    @app.on_event("startup")
+    async def startup():
+        await registry.start()
+        logger.info("Gateway started")
+
+    @app.on_event("shutdown")
+    async def shutdown():
+        await registry.stop()
+        logger.info("Gateway stopped")
+
+    # 健康检查
+    @app.get("/health")
+    async def health():
+        return {"status": "ok"}
+
+    return app
+
+
+def main():
+    """启动 Gateway 服务器"""
+
+    app = create_gateway_app()
+
+    # 启动服务器
+    uvicorn.run(
+        app,
+        host="0.0.0.0",
+        port=8000,
+        log_level="info"
+    )
+
+
+if __name__ == "__main__":
+    main()

+ 0 - 1
node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json

@@ -1 +0,0 @@
-{"version":"4.0.18","results":[[":frontend/react-template/src/components/FlowChart/hooks/useFlowChartData.spec.ts",{"duration":0,"failed":true}]]}