# 自动化记忆任务设计方案（v2）

## 1. 背景与目标

本方案用于重构自动化记忆能力，目标是：

- 保持单一运行时框架，不并行维护第二套执行系统；
- 在运行时中新增一层抽象，使 `router` 与 `executor` 的启用策略可配置；
- 将记忆处理职责从通用 worker 中剥离为独立 `memory agent` 角色；
- 保留审计能力与用户可见性隔离（自动输入可审计、默认对用户隐藏）；
- 维持与现有 `/api/v1/agent`、SSE、history 协议的兼容演进路径。

该版本是架构重构设计文档，重点解决职责边界与扩展性问题。

## 2. 设计原则

1. **单框架，多角色**
   - 仍复用同一套 runtime、队列、持久化、SSE 通道；
   - 不再让 worker 承担所有领域职责。

2. **配置驱动执行拓扑**
   - 运行路径由配置决定：是否经过 router、最终由哪个 executor 执行；
   - 执行拓扑可被审计并可回放。

3. **记忆职责显式化**
   - 记忆提取、写入、遗忘由 `memory agent` 执行；
   - worker 继续承担通用对话/工具编排场景。

4. **默认安全最小权限**
   - 工具集必须是 `declared_tools ∩ allowlist`；
   - memory executor 默认仅开放记忆域工具。

5. **协议先行**
   - 任何对运行协议和数据结构的变更，先更新 `docs/protocols/` 再落地代码。

## 3. 范围与非目标

### 3.1 范围

- `automation_jobs` 引入执行拓扑配置，支持是否启用 router 与 executor 选择；
- 运行时新增抽象层：`Execution Profile`；
- 支持 executor 类型：`worker`、`memory`；
- 自动任务默认使用 memory executor；
- 消息可见性和审计策略保持增强。

### 3.2 非目标

- 不引入复杂 DSL 编排语言；
- 不开放无限制策略字段；
- 不新增独立部署形态的第二运行时；
- 不在本阶段改造前端交互形态（仅保证协议兼容）。

## 4. 核心决策

1. **新增抽象层：Execution Profile（关键）**
   - 在 scheduler/orchestrator 与具体 agent 之间新增执行配置层；
   - 该层决定是否调用 router、调用哪个 executor、可用工具策略。

2. **executor 职责分离**
   - `worker executor`：通用任务、复杂工具编排、常规聊天；
   - `memory executor`：记忆提取、记忆写入、记忆遗忘、记忆总结。

3. **router 可配置启用**
   - 自动记忆任务默认 `enable_router=false`，减少不必要决策成本；
   - 普通 chat 默认 `enable_router=true`。

4. **拓扑合法性约束**
   - 必须保证至少有一个 executor；
   - 禁止出现 `enable_router=false` 且 `executor` 为空；
   - executor 仅允许枚举值：`worker | memory`。

5. **保持事件/审计统一出口**
   - 无论 executor 类型，SSE 与消息持久化走同一通道；
   - 仅扩展阶段字段枚举，不拆协议体系。

## 5. 目标架构

## 5.1 运行链路（重构后）

```text
scheduler/api trigger
  -> execution profile resolver
  -> (optional) router step
  -> executor step (worker | memory)
  -> persistence + redis stream
  -> history/sse consumers
```

与旧链路相比，变化点是新增 `execution profile resolver` 和 `memory executor`。

## 5.2 Execution Profile 抽象

建议抽象（运行时内部模型）：

```json
{
  "name": "automation_memory_default",
  "enable_router": false,
  "executor": "memory",
  "tool_policy": {
    "mode": "intersection",
    "allowlist": ["memory_write", "memory_forget"]
  },
  "history_policy": {
    "window": "today_yesterday"
  }
}
```

说明：

- `enable_router`：是否执行 router 决策步骤；
- `executor`：最终执行角色；
- `tool_policy`：工具授权策略，默认交集模式；
- `history_policy`：上下文窗口策略（保持最小化，不扩展过多字段）。

## 5.3 默认 Profile 建议

- `chat_default`
  - `enable_router=true`
  - `executor=worker`

- `automation_memory_default`
  - `enable_router=false`
  - `executor=memory`

## 6. 数据模型设计

## 6.1 `automation_jobs` 调整

保留现有调度相关字段：

- `id`, `owner_id`, `title`, `schedule_type`, `run_at`, `next_run_at`, `timezone`, `last_run_at`, `status`

新增/调整字段：

- `config JSONB NOT NULL`：任务输入与工具声明；
- `execution_profile JSONB NOT NULL`：运行拓扑配置（MVP 可先内联，后续可抽到 profile registry）。

建议结构：

```json
{
  "config": {
    "prompt": "提取最近对话中的稳定记忆并写入",
    "tools": ["memory_write", "memory_forget"]
  },
  "execution_profile": {
    "enable_router": false,
    "executor": "memory"
  }
}
```

## 6.2 Schema 约束

- `config.prompt`：必填非空，建议长度 `<= 2000`；
- `config.tools`：必填数组，元素为已注册工具名；
- `execution_profile.enable_router`：必填布尔；
- `execution_profile.executor`：必填枚举 `worker|memory`；
- `extra=forbid`，拒绝未知字段；
- 执行前二次校验：`declared_tools ∩ runtime_allowlist`。

## 6.3 `messages.metadata` 扩展

建议标准化字段：

- `hidden_from_user: bool`
- `origin: "chat" | "automation"`
- `executor: "worker" | "memory"`
- `execution_profile_name: string`

用途：

- 用户视图过滤自动输入；
- 审计可按 executor/profile 追踪行为；
- 支持后续灰度比较（同任务不同 profile）。

## 7. 运行时行为约束

## 7.1 自动任务

- 会话类型：`session_type=automation`；
- 自动输入消息：`role=user` + `hidden_from_user=true`；
- 默认 profile：`automation_memory_default`；
- executor：`memory`。

## 7.2 普通对话

- 会话类型：`session_type=chat`；
- 默认 profile：`chat_default`；
- executor：`worker`。

## 7.3 工具授权

- 输入工具集合来自 `config.tools`；
- 实际可调用集合来自 `config.tools ∩ profile_allowlist ∩ system_allowlist`；
- 对被拒绝工具记录审计日志与拒绝原因。

## 8. 调度器设计

## 8.1 扫描与触发

- 扫描条件：
  - `status='active'`
  - `next_run_at <= now_utc`
- 命中后投递执行命令，命令中携带 `execution_profile` 快照。

## 8.2 幂等与并发

- 幂等键：`job_id + scheduled_slot`；
- 通过原子更新或行级锁抢占，防止重复执行；
- 失败重试并保留错误上下文。

## 8.3 时区策略

- 调度语义按用户本地时区（例如每日 10:00）；
- 存储执行点统一使用 UTC `next_run_at`；
- 调度器仅按 UTC 扫描，避免多时区计算分散。

## 9. 协议影响与兼容策略

本阶段是设计重构，协议建议如下：

1. `docs/protocols/agent/sse-events.md`
   - `STEP_STARTED/STEP_FINISHED.stepName` 从 `router|worker` 扩展为 `router|worker|memory`；
   - 当 `enable_router=false` 时，不产出 router step 事件。

2. `docs/protocols/agent/run-agent-input.md`
   - 增补运行上下文说明：内部执行可由 profile 决定 executor；
   - 对外 API 入参保持兼容，不强制前端传 executor。

3. `docs/protocols/agent/api-endpoints.md`
   - 增补说明：`/runs` 的运行阶段由后端 profile 决定，历史与 SSE 保持统一消费方式。

兼容要求：

- 老客户端仍可消费现有事件；
- 仅新增枚举值，不删除既有字段；
- 如客户端未识别 `memory`，按未知阶段容错处理。

## 10. 默认任务创建

用户创建后自动创建 daily 记忆任务：

- `schedule_type='daily'`
- 本地时区目标时间 `10:00`
- `timezone` 优先用户设置，缺省 `Asia/Shanghai`
- `config.prompt` 使用内置记忆提取模板
- `config.tools=["memory_write","memory_forget"]`
- `execution_profile={"enable_router":false,"executor":"memory"}`

## 11. 安全与审计

安全约束：

- 禁止越权工具调用；
- memory 读写必须强制 owner 作用域；
- 日志不输出敏感内容与完整私密上下文。

审计能力：

- 自动输入、工具调用、输出全链路可追踪；
- 可按 `origin/executor/execution_profile_name` 回放。

## 12. 迁移与发布步骤

1. 更新 `docs/protocols`（先协议）；
2. 新增 `execution_profile` schema 与运行时模型；
3. 数据迁移：历史任务写入默认 profile；
4. 运行时接入 profile resolver；
5. 引入 `memory executor` 并接管自动记忆任务；
6. 灰度：先新建任务使用 memory executor，再迁移存量任务；
7. 稳定后收敛旧逻辑分支。

## 13. 测试与验收

## 13.1 单元测试

- profile schema 校验（非法枚举、空 executor、未知字段）；
- 工具授权交集逻辑；
- `next_run_at` 跨时区计算；
- 隐藏消息过滤与审计字段落库。

## 13.2 集成测试

- 自动任务触发后进入 memory executor；
- `enable_router=false` 时无 router step 事件；
- SSE `stepName=memory` 可被稳定消费；
- 自动输入审计可见、用户历史不可见。

## 13.3 验收标准

- 每日 10:00（用户本地时区）稳定执行；
- memory 任务不经过 router 亦可稳定完成；
- 工具权限边界有效；
- 审计链路完整；
- 对现有 chat 流程零回归。

## 14. 实施顺序建议

1. 协议文档更新（`docs/protocols/agent/*`）；
2. `automation_jobs` 数据结构改造与迁移；
3. profile resolver 与 executor 抽象接入；
4. memory executor 接入与工具边界验证；
5. 调度器联调与默认任务创建；
6. 端到端压测与灰度发布。

---

本版（v2）将“抽象 Agent 运行”落到可执行的配置模型，核心是：

- 新增一层 `Execution Profile`；
- 将 `router` 和 `executor` 拓扑配置化；
- 使用独立 `memory executor` 承载记忆职责；
- 在不引入第二运行时的前提下完成大规模重构演进。
