Files
quercus/docs/ai-agent-phased-plan.md
Mike-Solar e0db5ab2cf P1: host-agnostic quercus-core with agent loop, providers, and tool schemas
- Core types: Rational time, EntityId, ActionBatch, PngBytes (no Pillow dep)
- Config: ~/.quercus/config.toml with 0600 perms, env var override for CI
- LLMProvider: Claude (anthropic SDK) and OpenAI-compatible endpoint
  (covers custom gateways and llama.cpp server mode); graceful degradation
  without API keys
- Tool schemas: 26 curated tools with JSON Schema and read_only flags
- AgentLoop: sync dialogue loop with confirmation gate (read-only batches
  bypass, rejected mutations are reported back to the LLM), PNG frame
  feedback for multimodal providers
- Session log: JSONL recording with frame sha256 hashes, replayable
- HostAdapter ABC (signatures only, aligned with OPP/1 method families)
- Mock LLM provider (scripted/replay/record) for network-free CI

Tests: 69 passed via uv run pytest (no network access)
2026-08-25 02:06:10 +08:00

381 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Quercus AI 剪辑助手 — 分阶段实施计划
> 本文是 [`ai-agent-design.md`](ai-agent-design.md)(设计)的**施工计划**(怎么做、
> 分几步、每步验收什么)。设计决策以设计文档为准,本文不重复论证,只把
> "一份宿主无关 AI core + 各宿主薄适配层"的结构落成可执行的阶段计划。
>
> **范围调整(相对设计文档)**:
> - 设计文档的落地形态原是 Oak 插件(`oak-plugin-ai`,依赖 OPP/1 与插件系统
> P1–P4)。**Oak 插件系统仍在开发中**(见 `../../oak/docs/zh/plans/` 下的
> `external-plugin-system.md` / `external-plugin-protocol.md`),因此本计划
> **只做 DaVinci Resolve 与 Premiere Pro 两个宿主**;Oak 适配层**只预留接口
> (stub 包),不实现、不排期**,等 OPP/1 P1–P3 落地后按 §8 启动。
> - 设计文档中"工具面 = OPP/1 方法映射"的表述,在本计划中改为"工具面 =
> HostAdapter 接口映射"——接口形状**刻意对齐 OPP/1 方法族**,使未来的 Oak
> 适配层只是 oakxp SDK 的薄封装(§3.4)。
>
> 外部参考(实现时以官方最新文档为准):
> - Resolve 脚本 API:<https://extremraym.com/cloud/resolve-scripting-doc/>(X-Raym 整理,
> 源自 Resolve 安装目录 `Developer/Scripting/README.txt`)
> - Premiere UXP 示例:<https://github.com/AdobeDocs/uxp-premiere-pro-samples>
---
## 1. 目标与非目标
### 1.1 目标
1. **quercus-core**:宿主无关的 Python AI 核心——LLMProvider 抽象、Agent 编排
(对话 loop + 工具调用 + 视觉闭环)、约 20 个策展工具的 schema、会话状态与
回放日志、密钥管理。
2. **Resolve 适配层**(第一优先级):Python 母语直连 Resolve 脚本 API,支持
无头(`-nogui`)跑 CI,完整实现工具面与取帧闭环。
3. **Premiere 适配层**:UXP 面板(TypeScript)+ localhost 桥接 core 本地服务,
实现工具面的 Premiere 可用子集,能力缺口显式降级而非伪造。
4. **统一交互**:core 内建本地 Web 聊天面板(Resolve / 无头 / 调试通用);
Premiere 用 UXP 原生面板。两层确认(会话层"待确认清单"为主)。
5. **Oak 预留**:`quercus-oak` stub 包,实现 HostAdapter 接口签名 + OPP/1
映射注释 + manifest 草案,所有方法 `raise NotImplementedError`。
### 1.2 非目标(明确不做)
- **不**实现 Oak 适配层(等 OPP/1 P1–P3,见 §8)。
- **不**把 LLM 推理放进任何宿主进程;core 永远是独立进程。
- **不**做 MCP server 对外暴露(设计文档 §2.1 已定位:需要时由 core 自起,
本计划不排期)。
- **不**支持 Resolve 免费版的 UI 集成(v19.1 起免费版移除 UIManager;
免费版能否外部脚本调用在 P0 验证,若不可行则 Resolve 侧仅支持 Studio)。
- **不**为宿主伪造原子事务:Resolve / Premiere 无事务 API,用快照 + 补偿
实现"尽力回滚"(§3.3),对用户诚实标注。
- **不**在 Premiere 侧使用 ExtendScript / QE DOM 作为正式通路(EOL 风险;
仅允许 P0 spike 里做能力对照)。
## 2. 仓库结构与进程拓扑
### 2.1 仓库布局(monorepo)
```
quercus/
├── docs/ # 设计 + 本计划
├── core/ # quercus-core(PyPI 风格包,宿主零依赖)
│ ├── providers/ # claude / openai_compat / llamacpp
│ ├── tools/ # ~20 个工具 schema + 事务编排
│ ├── agent/ # 对话 loop、视觉闭环、待确认清单
│ ├── session/ # 会话状态、ActionBatch 记录、回放日志
│ ├── host/ # HostAdapter ABC + 类型(§3.1)
│ └── webui/ # 本地 Web 聊天面板(FastAPI + 静态页)
├── adapters/
│ ├── resolve/ # quercus-resolve(Python,直连脚本 API)
│ ├── premiere/
│ │ ├── bridge/ # core 侧:WebSocket server + 协议编解码
│ │ └── panel/ # UXP 面板(TS + Vite,结构对齐 Adobe 官方示例)
│ └── oak/ # quercus-oak(stub,仅接口 + 映射注释)
├── tests/
│ ├── mock_llm/ # 录制/回放 LLM server
│ ├── mock_host/ # HostAdapter 内存实现(行为对齐 OPP/1 语义)
│ └── e2e/ # Resolve -nogui 黄金帧测试;Premiere 手工清单
└── pyproject.toml # workspace(uv/pdm 均可,实现时定)
```
### 2.2 进程拓扑
```
┌─ DaVinci Resolve ─┐ ┌─ Premiere Pro ────────┐ ┌─ Oak(预留)─┐
│ 脚本 API(进程内) │ │ UXP 面板(Chromium) │ │ oak-plugin- │
└───────┬───────────┘ └──────────┬────────────┘ │ host (OPP/1) │
│ fusionscript │ WebSocket └──────┬───────┘
│ (同机直连) │ localhost+token │ stdio+shm
┌───────┴───────────┐ ┌──────────┴────────────┐ ┌──────┴───────┐
│ quercus-resolve │ │ quercus-premiere │ │ quercus-oak │
│ (core 的进程内 │ │ bridge(core 进程内 │ │ (stub) │
│ adapter 对象) │ │ WebSocket server) │ │ │
└───────┬───────────┘ └──────────┬────────────┘ └──────────────┘
└──────────► quercus-core ◄┘
(Agent / LLM / Web UI / 会话)
```
- **Resolve**:core 进程 import `DaVinciResolveScript`,adapter 是 core 进程内的
一个对象(Resolve 要求宿主在跑;core 直连,无中间进程)。也可反向:Resolve
脚本菜单拉起 core——安装形态在 P3 定,默认**core 为主动方**(便于无头与 CI)。
- **Premiere**:UXP 无法 import Python,core 在 localhost 起 WebSocket server
(随机端口 + 启动时写 token 文件到 `~/.quercus/bridge.json`,权限 0600;
面板连接须带 token)。面板只做 UI 与宿主 API 调用,Agent 逻辑全在 core。
- **Oak**:未来 core 进程内 import `oakxp`,同 Resolve 形态;本计划只留 stub。
### 2.3 关键决策(本计划新增,设计文档未覆盖的)
| # | 决策 | 理由 |
|---|---|---|
| D1 | 面板主形态 = core 内建本地 Web UI;Premiere 另有 UXP 原生面板 | Resolve 免费版无 UI 能力、无头场景无 UI;Web UI 一份代码三处复用 |
| D2 | Premiere 桥用 WebSocket localhost + token 文件鉴权 | UXP 网络能力需 manifest 声明域名,localhost 可用;token 防同机其他进程误连 |
| D3 | 事务语义统一为 `ActionBatch`:宿主有事务用事务,无事务用快照 + 补偿 | Resolve/Premiere 均无事务/撤销分组 API,诚实降级(§3.3) |
| D4 | 取帧通路每宿主一条主通路 + 一条备用,P0 先验证再定主备 | 三家取帧能力差异最大,是整个视觉闭环的生死点(§5 表) |
| D5 | 内部时间模型统一有理秒(对齐 OPP/1 `Rational`) | 避免 Resolve 帧号 / Premiere ticks 渗透进 core;换算全部在适配层 |
## 3. 统一抽象:HostAdapter 接口
### 3.1 接口形状(刻意对齐 OPP/1 §8 方法族)
```python
# core/host/adapter.py(示意,非最终实现)
class HostAdapter(ABC):
# 会话与能力
def capabilities(self) -> set[Capability]: ...
def limits(self) -> Limits: ... # 取帧速率/分辨率上限等,各宿主自报
# 工程 / 媒体 / 时间线 / 节点(方法族与 OPP/1 §8.2–8.5 一一对应)
def get_project_overview(self) -> ProjectOverview: ...
def probe_media(self, path: str) -> MediaInfo: ...
def import_footage(self, paths: list[str]) -> list[FootageId]: ...
def get_timeline_structure(self, seq: SeqId) -> Timeline: ...
# 取帧(视觉闭环生死通路)
def get_frame(self, target: Target, time: Rational, max_size: Size) -> PngBytes: ...
def get_thumbnails(self, target: Target, range: TimeRange, count: int) -> list[PngBytes]: ...
def get_audio_levels(self, seq: SeqId, range: TimeRange, resolution: int) -> Levels: ...
# 回放 / 导出
def play / pause / seek / get_state: ...
def export(self, seq: SeqId, output: str, preset: str) -> JobHandle: ... # 事件经回调
# 编辑(ActionBatch 语义,见 §3.3)
def execute(self, batch: ActionBatch) -> BatchResult: ...
def undo_last(self) -> None: ... # 仅用户明确要求时
```
- `EntityId` 为不透明字符串(对齐 OPP/1 §5),适配层内部维护
id ↔ 宿主对象 的映射,工程重载后全部作废并通知 core 重新拉取。
- 事件(结构变化 / 播放头 / 导出进度)以回调注入 core;宿主无事件源的
(Resolve 脚本 API 无事件)由适配层**轮询合成**,轮询频率进 `limits`。
### 3.2 工具面(core 对 LLM 暴露 ~20 个策展工具)
沿用设计文档 §3 的工具清单(`open_project` … `undo_last_action`),一处修改:
"OPP 方法"列改为"HostAdapter 方法"。事务编排职责不变——LLM 看不到事务/
快照细节,core 把一次 LLM 动作包成 `ActionBatch` 交给适配层。
### 3.3 ActionBatch:三档事务语义(诚实分级)
| 档位 | 宿主 | 实现 | 用户可见承诺 |
|---|---|---|---|
| 真事务 | Oak(未来) | OPP/1 `edit.begin/commit/abort` | 一次 Ctrl-Z 整段撤销,失败自动回滚 |
| 快照 + 补偿 | Resolve | 执行前 `Timeline.DuplicateTimeline("quercus-snapshot-*")`;失败/撤销时切回快照时间线 | "已为你保留编辑前快照时间线",非原子 |
| 快照 + 补偿 | Premiere | 复制当前序列(UXP 支持则快照,不支持则仅反向操作日志)+ 逐步反向操作 | 面板内"撤销本段会话"按钮回放补偿;非原子 |
约束(写进 core,不依赖适配层自觉):
- 破坏性批次(删除/波纹删除/批量移动)**必须**先快照;只读批次(打点、
标记)可免快照。
- 快照命名带时间戳与会话 id,面板提供"清理快照"入口;快照数量进 `limits`
上限(防时间线列表被刷爆)。
- 任一子操作失败:已执行的保持(与 OPP/1 §6 规则 3 语义对齐),错误回喂
LLM,由 Agent 决定补偿或中止。
### 3.4 Oak 预留形态
`adapters/oak/` 包含:`OakAdapter(HostAdapter)` 全部方法
`raise NotImplementedError("awaiting OPP/1 P1-P3")`;每个方法 docstring 标注
对应 OPP/1 方法(如 `# -> timeline.split_clip,协议 §8.4`);`plugin.toml`
草案(capabilities 用设计文档 §5.2 最小集)。**不写任何 oakxp 调用代码。**
## 4. 分阶段计划
> 工时为单人粗略估算,仅用于排序与预期管理。阶段间依赖见 §9 图。
### P0 技术验证(1–2 周,其余一切的闸门)
四个 spike,每个产出可运行脚本 + 一页结论,全部通过才进 P1:
| Spike | 验证内容 | 通过标准 |
|---|---|---|
| S1 Resolve 连接 | 外部 Python 经 `fusionscript` 连 Resolve;记录免费版/Studio 差异(外部调用、UIManager、`-nogui`) | 脚本拿到 `resolve` 对象并列出工程;明确版本门槛写进 README |
| S2 Resolve 取帧 | 三条通路对比:`Project.ExportCurrentFrameAsStill(path)`(主候选)、`Timeline.GetCurrentClipThumbnailImage()`(仅 Color 页)、Gallery `GrabAllStills` + 导出 | 能按给定时间点稳定拿到 PNG;测出单帧延迟与 `-nogui` 下可用性,定下主/备通路 |
| S3 Premiere UXP 基座 | UDT 加载 TS 面板(照官方 `premiere-api` 示例结构);面板 ↔ 本地 WebSocket server 通信(manifest network 权限、token 握手) | 面板按钮触发本地 server 往返 < 50 ms |
| S4 Premiere 取帧与编辑面 | UXP export API 导单帧(官方示例 `export.ts`);`sequenceEditor` 的 overwrite/insert/remove、markers、effects、transitions、keyframes 实际可用性;**split 与 ripple delete 是否存在原生 API** | 得到 Premiere 侧能力清单(✅/⚠️/❌),填进 §5 表;单帧导出延迟实测 |
Go/No-Go 规则:S2、S4 的取帧延迟若 > 2 s/帧,视觉闭环体验不成立,
回到设计层改交互(如纯 contact-sheet 低帧率模式)再开工。
### P1 quercus-core(约 3 周,不碰任何宿主)
1. **类型与配置**:`Rational`/`EntityId`/`FrameRef` 等核心类型;
`~/.quercus/config.toml`(权限 0600、gitignore;环境变量仅 CI 覆盖,
优先级:环境变量 > 配置文件;密钥绝不写任何宿主侧文件——继承设计铁律 4)。
2. **LLMProvider**:统一接口(消息 + 图片 → 文本 + tool_calls);
后端:Claude、OpenAI 兼容 endpoint(自定义网关/代理通用通路)、
llama.cpp 本地多模态(Qwen-VL/LLaVA 类)。无 key 优雅降级:
面板可浏览工具说明并手动执行,不做对话编排。
3. **Agent 编排**:对话 loop、tool_call 派发、视觉闭环(工具返回可携带
图片消息回喂)、待确认清单(整段动作先入清单,用户确认后才执行——
宿主无协议层弹窗,**确认只有这一层**,默认全开)。
4. **工具 schema 注册表**:约 20 个工具的 JSON Schema;参数 min/max/choices
由 `get_params` 类方法回填(同设计 §3 的约束思路)。
5. **会话状态与回放**:ActionBatch 顺序记录、帧哈希、tool_call 日志落盘,
可回放复现(测试夹具同格式)。
6. **Mock LLM server**:录制/回放固定 tool_call 序列。
验收:`pytest` 全绿;无网络无 key 环境下跑通
"mock LLM → 工具派发 → 回喂 → 第二轮对话"。
### P2 HostAdapter + Mock 宿主 + 工具适配层(约 2–3 周)
1. HostAdapter ABC 与 `Limits`/`Capability`(§3.1–3.2)。
2. **MockHostAdapter**:内存时间线模型,行为对齐 OPP/1 语义(事务档位、
id 作废、`RATE_LIMITED` 式退避、帧非全黑校验)——它就是未来 Oak 适配层
的验收替身,也是 P1 的测试底座。
3. **工具适配层**:tool schema → adapter 方法组合;ActionBatch 编排
(快照策略、失败补偿、补偿顺序);取帧流水线(并发取帧 + 立即释放,
对齐 OPP/1 §10.3 的教训:批量扫描绝不串行等帧);限流客户端
(按 `limits` 令牌桶,退避不重试轰炸)。
4. **本地 Web 面板**:聊天、待确认清单、进度、撤销会话按钮、快照管理。
验收:Mock 宿主上"导入 → 铺轨 → 切/重建 → 删除 → 加效果 → 取帧验证 →
整段会话撤销"全链路自动化通过;Web 面板手工走查。
### P3 Resolve 适配层(约 3–4 周,依赖 P0 S1/S2、P2)
1. **连接与生命周期**:`fusionscript` 连接(环境变量
`RESOLVE_SCRIPT_API/LIB` 探测 + 报错指引)、断线重连、`-nogui` 模式支持、
版本门槛检查(S1 结论)。
2. **方法映射**(详表见 §5):工程/媒体池/时间线/标记/导出全量实现;
时间模型换算(帧号 ↔ 有理秒,按时间线 fps);`EntityId` ↔ 对象映射
(优先 `GetUniqueId()`)。
3. **取帧通路**:按 S2 结论实现主/备两条;contact sheet 拼贴(Pillow)。
4. **ActionBatch 档位**:快照(`DuplicateTimeline`)+ 补偿操作表;面板
"撤销会话"回放到快照。
5. **安装形态**:安装脚本写 Scripts 目录菜单项(`Utility/`)+ core 独立
启动两种入口;文档写清 Studio/免费版差异。
验收:`-nogui` CI 端到端——真实工程"导入 → 建时间线 → 粗剪 → 打点 →
导出",黄金帧校验(取到的帧非全黑、编辑前后切口帧像素不同);快照撤销
恢复一致性断言;GUI 模式手工走查 Web 面板对话粗剪一段真实素材。
### P4 Premiere 适配层(约 4–5 周,依赖 P0 S3/S4、P2)
1. **bridge**:core 内 WebSocket server(随机端口 + token 文件 0600);
NDJSON/JSON 消息协议(复用 core 的 HostAdapter 调用语义,一份 schema
两用);断线重连与版本协商。
2. **UXP 面板**(TS + Vite,结构照官方示例):聊天 UI、待确认清单、
进度;`manifest.json` 只声明必要权限(localhost 网络)。
3. **方法映射**:按 S4 能力清单实现 ✅ 项;⚠️ 项做变通(split 用
出入点重建、ripple 用移动补偿等);❌ 项在 schema 层显式隐藏并给
LLM 一份"本宿主不支持"说明(防幻觉调用)。
4. **取帧**:S4 定下的通路实现;延迟进 `limits` 让扫描策略自适应。
5. **ActionBatch 档位**:序列快照(若 API 支持复制序列)+ 补偿日志。
6. **打包**:开发走 UDT;发布形态(独立分发 `.ccx`)与签名要求调研
并落地最简可用路径。
验收:Premiere 内面板对话完成"铺轨 → 打点 → 加转场/效果 → 导出",
待确认与撤销交互完整;bridge 断连/重连不丢会话;手工 E2E 清单全过
(Premiere 无无头模式,此阶段接受手工测试为主)。
### P5 内容感知能力(约 3–4 周,依赖 P3,P4 可并行)
1. **Contact sheet 扫描打点**:等间隔采样拼图回喂,LLM 输出时间点 →
`add_marker`(两宿主 markers API 都全)。
2. **自动粗剪策略**:LLM 判定废片段 → ActionBatch(Resolve 直删/补偿;
Premiere 按能力变通);人工抽检闭环。
3. **转录利用**(能力增强,可选):Premiere 有 transcript 导出、Resolve
Studio 有 `TranscribeAudio`——按 `capabilities` 探测启用"按台词剪辑"。
4. **本地模型 provider 打磨**:llama.cpp 多模态的提示词与分辨率预算。
验收:对 10 分钟素材自动出粗剪版,人工抽检切点可用(同设计 A5 标准);
CI 有 mock 回放的粗剪回归。
### P6 发布与硬化(约 2 周)
- 两宿主安装器/打包(Resolve 脚本目录 + core 单包;Premiere `.ccx`);
core 用 PyInstaller / python-build-standalone 嵌入式发行(用户不装 Python,
同设计 §2.3)。
- 崩溃与断线恢复矩阵测试;日志与诊断包;密钥配置引导;限流与大图内存
压测。
- 文档:安装、能力矩阵(§5 表面向用户版)、故障排查。
### P7 Oak 适配(**预留,不启动**)
启动前提:OPP/1 P1–P3 完成(传输生命周期、宿主 API 核心、取帧 shm 数据面)。
届时 `quercus-oak` = HostAdapter → oakxp 的薄封装:事务档位直接升到"真事务"
(`edit.begin/commit`),取帧走 shm `FrameRef` + `shm.release` 流水线,确认
双层(协议弹窗 + 会话清单)按设计文档 §5.2。预计工作量显著小于 P3/P4——
这正是接口对齐 OPP/1 的收益。**本计划不为其分配资源。**
## 5. 宿主能力映射表(工具 × 宿主)
> ✅ 原生支持;⚠️ 有变通(注明);❌ 缺失(schema 层隐藏)。
> Resolve 方法名见 X-Raym 文档;Premiere 为 UXP API 域(以 S4 实测为准修订)。
| core 工具 | Resolve | Premiere(UXP) | Oak(预留 → OPP/1) |
|---|---|---|---|
| `open/save_project` | ✅ `ProjectManager.LoadProject/SaveProject` | ✅ project open/save | `project.open/save` |
| `get_project_overview` | ✅ `GetCurrentTimeline` + `GetItemListInTrack` 遍历 | ✅ activeSequence 遍历 | `project.get_info` + `timeline.get_structure` |
| `probe_media` | ⚠️ `MediaPoolItem.GetClipProperty()`(无独立 probe) | ✅ projectItem 元数据 | `media.probe` |
| `import_footage` | ✅ `MediaPool.ImportMedia` | ✅ `importFiles` | `media.import_footage` |
| `add_track` | ✅ `Timeline.AddTrack` | ✅ sequence tracks | `timeline.add_track` |
| `place_clip` | ⚠️ `AppendToTimeline`(clipInfo 带 startFrame/endFrame/recordFrame/trackIndex) | ✅ `sequenceEditor` overwrite/insert | `timeline.place_clip` |
| `split_clip` | ⚠️ 无直接 API——按出入点重建相邻两段(S4 复核新版是否已加) | ⚠️ 视 S4 结论;否则同样重建 | `timeline.split_clip` |
| `trim_clip` | ⚠️ `SetProperty`/重建 | ✅ trackItem 出入点 | `timeline.trim_clip` |
| `move_clip` | ⚠️ 删除 + `AppendToTimeline` 重放 | ✅ move track item | `timeline.move_clip` |
| `ripple_delete` | ✅ `Timeline.DeleteClips(items, True)` | ⚠️ 视 S4;否则补偿移动 | `timeline.ripple_delete` |
| `add_transition` | ⚠️ `TimelineItem` 属性/新建(有限) | ✅ transition 模块 | `timeline.add_transition` |
| `add_marker` | ✅ `Timeline.AddMarker`(含 customData,可存 AI 元数据) | ✅ markers 模块 | `timeline.add_marker` |
| `add_effect/set_param/keyframe` | ⚠️ 效果面有限(Fusion comp / 属性),调色走节点图另议 | ✅ effects + keyframe 模块 | `node.*` |
| `get_frame` | ✅ S2 主通路(`ExportCurrentFrameAsStill`) | ⚠️ S4:export 单帧,延迟实测 | `render.get_frame`(shm) |
| `scan_timeline` | ✅ `GrabAllStills` / 逐点取帧拼图 | ⚠️ 批量导帧拼 contact sheet | `render.get_thumbnails` |
| `get_audio_levels` | ❌(v1 隐藏;Fairlight 侧另议) | ⚠️ 视 API;否则隐藏 | `render.get_audio_levels` |
| `play/pause/seek` | ⚠️ `SetCurrentTimecode` 可 seek;播放控制弱 | ✅ sourceMonitor play/pause/position | `playback.*` |
| `export_render` | ✅ `LoadRenderPreset` + `AddRenderJob` + `StartRendering` + `GetRenderJobStatus` 轮询 | ✅ encoderManager / export | `export.start` + 事件 |
| `undo_last_action` | ❌ 无 undo API → 快照恢复(§3.3) | ❌ 同左(补偿回放) | `edit.undo` |
| 事件(结构/进度) | ⚠️ 轮询合成 | ✅ eventManager(工程/编码事件) | OPP/1 §9 原生事件 |
## 6. 安全与密钥(继承设计铁律,按本计划重述)
1. core 只经 HostAdapter 操作宿主;Premiere 桥接受 token 鉴权、只绑
`127.0.0.1`。
2. 一切编辑走 ActionBatch,破坏性批次先快照;UI 默认"确认后执行"
(宿主无协议层确认,会话层清单是唯一确认点,不可默认关闭)。
3. API key 只存 `~/.quercus/config.toml`(0600);绝不写入 Resolve 工程/
Premiere 工程/未来 `.ove` 的任何位置。
4. 遵守各宿主实测限流:取帧并发与分辨率预算写进 `limits`,core 侧令牌桶
统一执行,退避不轰炸。
## 7. 测试策略
1. **Mock LLM**(P1):无 key 无网络 CI 跑通 Agent loop。
2. **MockHostAdapter**(P2):协议级行为夹具;未来 Oak 适配层先对它达标
再连真 Oak。
3. **Resolve 黄金帧 E2E**(P3):`-nogui` 起真实实例,导入测试素材 →
编辑 → 取帧,断言帧非全黑且切口前后像素变化——对齐设计 §6.3 的
"Agent 的编辑确实改变了画面"。
4. **Premiere 手工清单**(P4):无无头模式,维护一份逐步 checklist +
预期画面截图基线,发布前必跑。
5. **会话回放**:tool_call + 帧哈希日志可直接作回归夹具。
## 8. 风险登记册
| 风险 | 影响 | 对策 |
|---|---|---|
| Resolve 免费版外部脚本/UI 受限(v19.1 移除 UIManager) | Resolve 侧受众收窄 | S1 定门槛;必要时仅支持 Studio 并在文档明示 |
| Resolve/Premiere 均无 undo/事务 API | "撤销会话"非原子,可能残留 | 快照 + 补偿(§3.3);UI 文案不承诺原子性 |
| Premiere UXP 取帧慢或无直接 API | 视觉闭环降格 | S4 实测;降格方案 = 低帧率 contact-sheet 模式 |
| Premiere split/ripple 无原生 API | 粗剪动作变通复杂易错 | 重建法封装进适配层 + 黄金帧类断言兜底 |
| UXP 网络/面板权限政策变化 | 桥接失效 | manifest 最小权限;关注 Adobe 公告;bridge 协议版本协商 |
| LLM 成本与延迟 | 体验差 | 本地 provider、扫描降采样、contact sheet 合并请求 |
| 时间模型换算(帧号/ticks/fps 下拉) | 切点漂移 | 有理秒唯一内部模型 + 适配层换算单测(NTSC fps 用例) |
## 9. 里程碑总表与依赖
```
P0(spike) ──► P1(core) ──► P2(adapter+mock) ──┬──► P3(Resolve) ──► P5(内容感知) ──► P6(发布)
│ └──► P4(Premiere) ────────────────►──┘
└──(P7 Oak:等 OPP/1 P1–P3,不占本计划资源)
```
| 里程碑 | 出口标准(一句话) | 估算 |
|---|---|---|
| P0 | 四个 spike 通过,两宿主取帧通路定案 | 1–2 周 |
| P1 | Mock LLM 下 Agent loop CI 全绿 | ~3 周 |
| P2 | Mock 宿主全链路 + Web 面板可用 | ~2–3 周 |
| P3 | Resolve 无头 E2E 黄金帧通过,GUI 对话粗剪走通 | ~3–4 周 |
| P4 | Premiere 面板对话编辑 + 撤销会话走通 | ~4–5 周 |
| P5 | 10 分钟素材自动粗剪,抽检可用 | ~3–4 周 |
| P6 | 两宿主安装包 + 文档 + 硬化完成 | ~2 周 |
| P7 | (预留)Oak 适配 = oakxp 薄封装,等 OPP/1 P1–P3 | 未排期 |
P4 与 P3 可由两人并行;单人执行顺序建议 P3 先于 P4(Resolve API 面更全、
可无头,能在最硬的宿主上先把 HostAdapter 接口的真实形状磨出来)。