[全双工Agent架构]:完成完整语音助手OpenSpec计划,包含WebRTC音频底座、长期记忆和Tool Router设计
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-06-18
|
||||
@@ -0,0 +1,312 @@
|
||||
# Design: 完整全双工 Agent 语音助手架构
|
||||
|
||||
## Context
|
||||
|
||||
当前 Owner 项目已经具备真实语音桌宠的基础能力:本地唤醒词、麦克风采集、VAD/端点、实时字幕、final STT、云端 LLM、本地 TTS、播报、连续追问和初步打断规划。现有实现仍以 turn-based 轮次为中心:用户唤醒后系统录一段、识别、生成、播放,再回到待机或短暂追问窗口。
|
||||
|
||||
完整 Agent 语音助手需要更强的架构边界:
|
||||
|
||||
1. 音频输入和输出必须同时运行,而不是录完再播。
|
||||
2. 播放音频必须回注给 AEC reference,避免助手自己的声音污染麦克风输入。
|
||||
3. VAD、STT、LLM、TTS、工具执行和播放都必须能被统一取消。
|
||||
4. 长期记忆和工具执行必须纳入安全策略,而不是让 LLM 随意执行文本命令。
|
||||
5. 终端、未来 GUI 桌宠和自动测试必须消费同一事件流。
|
||||
|
||||
本设计仅用于 OpenSpec 规划。本阶段不修改 `src/`、不安装依赖、不下载模型、不运行外部工具、不接入 Open Interpreter,也不提交本地未跟踪的 `openinterpreter/`。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
1. 定义全双工音频底座:麦克风 capture、扬声器 render reference、WebRTC APM AEC/NS/AGC、环形缓冲和时钟对齐。
|
||||
2. 定义状态机:`idle/listening/thinking/speaking/interrupted/tool_running/recovering`。
|
||||
3. 定义并发任务模型:音频输入、STT、LLM、TTS、播放、工具执行相互独立但可被统一取消。
|
||||
4. 定义低延迟打断:用户在 `speaking` 中说话时,VAD 快速触发 interruption,目标小于 200 ms。
|
||||
5. 定义 Streaming STT/TTS:partial/final transcript、LLM token stream、句子切分、TTS chunk 播放。
|
||||
6. 定义长期记忆:SQLite 保存文本和元数据,FAISS 保存向量索引,敏感内容默认不自动保存。
|
||||
7. 定义 Tool Router:结构化工具调用协议、安全分类、确认策略、执行预算、防循环、结果脱敏回注。
|
||||
8. 定义 Open Interpreter 外部 adapter:只作为 CLI/子进程后端候选,不复制外部仓库。
|
||||
9. 定义 Playwright browser adapter 和未来 `ComputerControlProvider` 预留边界。
|
||||
10. 定义测试策略:fake APM/VAD/STT/TTS/memory/tool、端到端模拟、性能指标和安全回归。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
1. 本阶段不实现运行代码。
|
||||
2. 本阶段不安装 WebRTC APM、Silero、Faster Whisper、SenseVoice、CosyVoice、FAISS、Playwright 或 Open Interpreter。
|
||||
3. 本阶段不下载模型。
|
||||
4. 本阶段不改变 `.env`、`pyproject.toml`、`src/`、`tests/`、`scripts/`。
|
||||
5. 第一版规划不做 GUI 点击、键盘、屏幕控制,只预留公共 provider。
|
||||
6. 第一版不做长期主人声纹注册和多人身份鉴权。
|
||||
7. 第一版不自动执行高风险电脑控制、上传、交易、删除、权限修改或账号操作。
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision 1: WebRTC APM 作为默认音频底座
|
||||
|
||||
采用 `WebRtcAudioProcessingStage` 作为全双工默认音频预处理层,启用 AEC、NS、AGC。
|
||||
|
||||
**理由:**
|
||||
|
||||
1. AEC 需要播放 reference 才能可靠消除助手自己的声音,音色门控只能做后验抑制。
|
||||
2. NS 能降低风扇、环境声和麦克风底噪对持续 VAD/STT 的影响。
|
||||
3. AGC 能减少用户远近变化导致的阈值不稳定。
|
||||
|
||||
**替代方案:**
|
||||
|
||||
1. 继续使用 GTCRN 降噪:能改善噪音,但不能处理扬声器回声。
|
||||
2. 继续使用音色门控:实现成本低,但对不同扬声器、房间回声和 TTS 音色变化不稳定。
|
||||
3. 只靠 VAD/STT 置信度:误触发风险高,不适合作为全双工底座。
|
||||
|
||||
### Decision 2: capture/render 双环形缓冲
|
||||
|
||||
设计 `CaptureRingBuffer` 和 `RenderReferenceRingBuffer`。麦克风帧和播放帧都按 monotonic timestamp 写入,APM 处理 capture frame 时读取相邻 render reference。
|
||||
|
||||
**理由:**
|
||||
|
||||
1. 全双工需要持续输入和持续输出,不能用同步读写阻塞。
|
||||
2. AEC 对 reference 时序敏感,必须保留时间戳和 drift 监控。
|
||||
3. Ring buffer 可为 STT、VAD、打断检测和测试提供一致帧来源。
|
||||
|
||||
**替代方案:**
|
||||
|
||||
1. 直接从 sounddevice callback 推到各 stage:耦合高,难测试,易阻塞。
|
||||
2. 文件式临时 wav:延迟高,不适合全双工。
|
||||
|
||||
### Decision 3: 统一状态机和事件总线
|
||||
|
||||
新增 `FullDuplexAgentStateMachine` 和 `PipelineEventBus`。状态机只负责合法转移,事件总线承载终端、GUI 和测试可观察行为。
|
||||
|
||||
**理由:**
|
||||
|
||||
1. 现有 turn-based 状态无法表达 `tool_running` 和 `interrupted`。
|
||||
2. 终端和未来 GUI 必须共享事件,不应各自读取内部字段。
|
||||
3. 测试可以断言事件顺序、耗时和错误恢复。
|
||||
|
||||
### Decision 4: Cancellation Graph 管理所有可中断任务
|
||||
|
||||
每个用户输入 turn 创建 root cancellation token,LLM、TTS、playback、tool 子任务挂在 root 下。用户打断时 root token 广播取消。
|
||||
|
||||
**理由:**
|
||||
|
||||
1. 播放停止但 LLM 继续生成会浪费资源并污染上下文。
|
||||
2. TTS 合成继续运行会造成卡顿和旧回复残留。
|
||||
3. 工具执行必须区分可取消和不可安全取消。
|
||||
|
||||
### Decision 5: Streaming STT 分层输出
|
||||
|
||||
`StreamingSttProvider` 输出 `partial`、`stable_partial` 和 `final`。终端可展示 stable partial;LLM 默认只接收 final。
|
||||
|
||||
**理由:**
|
||||
|
||||
1. 用户需要实时看到系统听到了什么。
|
||||
2. partial 抖动不能直接写入上下文。
|
||||
3. final 是唯一可靠的 LLM 用户输入。
|
||||
|
||||
**开发候选:**
|
||||
|
||||
1. `faster-whisper`:开发阶段优先,生态成熟。
|
||||
2. `SenseVoice`:产品候选,中文和情绪能力更强,需要评估部署成本。
|
||||
3. `sherpa-onnx`:保留当前兼容 adapter,降低迁移风险。
|
||||
|
||||
### Decision 6: LLM token stream 按句进入 Streaming TTS
|
||||
|
||||
LLM delta 进入 `SentenceSegmenter`。达到完整句子、语义停顿或最大等待阈值后,将净化后的文本交给 TTS。
|
||||
|
||||
**理由:**
|
||||
|
||||
1. 不等待完整回复能显著缩短首音延迟。
|
||||
2. 句子级 TTS 比 token 级 TTS 更自然。
|
||||
3. 现有 TTS sanitizer 可复用,避免表情包、emoji 被读出。
|
||||
|
||||
### Decision 7: 长期记忆使用 FAISS + SQLite
|
||||
|
||||
SQLite 保存记忆文本、类型、敏感度、来源、时间和 checksum;FAISS 保存 embedding 向量。
|
||||
|
||||
**理由:**
|
||||
|
||||
1. SQLite 适合可审计元数据和删除。
|
||||
2. FAISS 适合向量相似检索。
|
||||
3. 两者分离便于一致性检查和索引重建。
|
||||
|
||||
**替代方案:**
|
||||
|
||||
1. 只用 SQLite FTS:部署简单,但语义召回弱。
|
||||
2. 直接把历史对话全文塞进 prompt:隐私和成本都不可控。
|
||||
3. 使用外部向量数据库:当前单机桌宠不需要额外服务复杂度。
|
||||
|
||||
### Decision 8: Tool Router 先安全工具后电脑控制
|
||||
|
||||
第一版只规划低风险工具:`memory.search`、`memory.save`、`shell.readonly`、`openinterpreter.run`、`browser.playwright`。GUI 电脑控制只预留。
|
||||
|
||||
**理由:**
|
||||
|
||||
1. 语音助手执行工具的风险高于文本聊天,必须先定义确认策略。
|
||||
2. Open Interpreter 能节省电脑任务开发时间,但必须被当成外部受限后端。
|
||||
3. GUI 点击/键盘/屏幕控制需要 Accessibility 权限和更复杂安全策略,不适合第一阶段自动执行。
|
||||
|
||||
### Decision 9: Open Interpreter 作为外部 CLI adapter
|
||||
|
||||
本地 `openinterpreter/` 是未跟踪新 Rust 版 Open Interpreter。Owner 不复制、不 vendoring、不提交它,只在后续实现中通过命令路径调用外部 CLI。
|
||||
|
||||
**理由:**
|
||||
|
||||
1. 避免把外部大型仓库混入 Owner。
|
||||
2. 保持 Owner 的工具边界清晰。
|
||||
3. 可以对 CLI 调用做超时、目录限制、输出截断和确认策略。
|
||||
|
||||
### Decision 10: Codex Computer Use 只参考安全策略
|
||||
|
||||
Codex App 的 Computer Use 能力可作为“需要确认、限制高风险操作、避免私自执行 GUI 动作”的安全策略参考,但不复制私有实现。
|
||||
|
||||
**理由:**
|
||||
|
||||
1. 用户希望从 Codex 控制电脑技能中复刻思路,而不是复制私有实现。
|
||||
2. 公共落地路线应基于 macOS Accessibility、Playwright、trycua 等能力。
|
||||
3. 第一版先不做 GUI 控制可降低安全和实现风险。
|
||||
|
||||
## Concurrent Task Model
|
||||
|
||||
### Runtime task groups
|
||||
|
||||
1. `audio_capture_task`:从麦克风读取帧,写入 capture ring buffer。
|
||||
2. `audio_render_task`:从 playback queue 取 PCM,送扬声器并写入 render reference buffer。
|
||||
3. `apm_task`:处理 capture frames,输出 cleaned frames。
|
||||
4. `vad_interrupt_task`:对 cleaned frames 做 VAD 和打断检测。
|
||||
5. `stt_task`:消费 cleaned frames,输出 partial/stable/final transcript。
|
||||
6. `llm_task`:消费 final transcript、记忆和工具结果,输出 token stream 或 tool call。
|
||||
7. `tts_task`:消费句子片段,输出 PCM chunks。
|
||||
8. `tool_task`:执行已批准工具,输出脱敏结果。
|
||||
9. `event_task`:聚合事件、指标和 reporter 输出。
|
||||
|
||||
### Backpressure
|
||||
|
||||
1. Ring buffer 有固定容量,超出容量丢弃最旧非关键帧并发出 `audio_buffer_overrun`。
|
||||
2. TTS queue 超限时暂停 LLM sentence enqueue 或请求 LLM stream 暂停/取消。
|
||||
3. Tool output 超限时截断并返回 `truncated=true`。
|
||||
|
||||
### Cancellation
|
||||
|
||||
1. `interrupt_detected` 触发 root cancellation。
|
||||
2. LLM stream 立即关闭连接或停止读取。
|
||||
3. TTS session 停止合成并释放资源。
|
||||
4. Playback queue 清空未播放 chunks,保留已播放文本边界。
|
||||
5. 可取消工具收到 token 后停止;不可取消工具标记为 pending cleanup。
|
||||
|
||||
## Audio Ring Buffer Design
|
||||
|
||||
### Frame format
|
||||
|
||||
1. 默认 16 kHz 或 48 kHz 内部采样率需在实现前确认。
|
||||
2. 默认 mono capture;render reference 可 mono 或 stereo downmix。
|
||||
3. 默认 frame size 为 20 ms。
|
||||
4. 每帧包含 `frame_id`、`timestamp_monotonic_ms`、`sample_rate`、`channels`、`samples`。
|
||||
|
||||
### Reference alignment
|
||||
|
||||
1. render frame 写入 reference buffer 时记录实际播放排队时间和预计播放时间。
|
||||
2. capture frame 进入 APM 时按 timestamp 查找 reference window。
|
||||
3. drift 超过阈值时发 `audio_reference_drift`,并降低打断置信度。
|
||||
|
||||
### Fallback
|
||||
|
||||
1. APM 不可用时,若 `OWNER_AUDIO_APM_REQUIRED=1`,全双工模式启动失败。
|
||||
2. 若允许 fallback,则使用现有 GTCRN denoiser、assistant playback gate 和 conservative VAD,但必须标记 `apm_fallback=true`。
|
||||
|
||||
## Tool Router Protocol
|
||||
|
||||
### Tool call request
|
||||
|
||||
```text
|
||||
ToolCallRequest:
|
||||
id: str
|
||||
name: str
|
||||
arguments: dict
|
||||
requested_by_turn_id: str
|
||||
natural_language_intent: str
|
||||
timeout_ms: int
|
||||
```
|
||||
|
||||
### Tool decision
|
||||
|
||||
```text
|
||||
ToolDecision:
|
||||
action: execute | reject | require_confirmation
|
||||
risk_level: low | medium | high | forbidden
|
||||
reason: str
|
||||
sanitized_arguments: dict
|
||||
confirmation_prompt: str | null
|
||||
```
|
||||
|
||||
### Tool result
|
||||
|
||||
```text
|
||||
ToolResult:
|
||||
id: str
|
||||
status: success | failed | cancelled | rejected | confirmation_required
|
||||
output_text: str
|
||||
output_truncated: bool
|
||||
error_code: str | null
|
||||
duration_ms: int
|
||||
audit_summary: str
|
||||
```
|
||||
|
||||
### First-version tools
|
||||
|
||||
1. `memory.search`:只读,低风险。
|
||||
2. `memory.save`:低到中风险,敏感内容需要确认。
|
||||
3. `shell.readonly`:低到中风险,只允许 allowlist 只读命令。
|
||||
4. `openinterpreter.run`:默认中风险,第一版默认关闭;执行前必须经过目录、意图和风险校验。
|
||||
5. `browser.playwright`:默认中风险,第一版默认关闭;账号、支付、提交、购买流程必须确认或拒绝。
|
||||
|
||||
## Memory Retrieval Chain
|
||||
|
||||
1. 用户 final transcript 进入 `MemoryQueryBuilder`。
|
||||
2. Query builder 结合当前任务、会话摘要和用户文本生成检索 query。
|
||||
3. Embedding provider 生成 query vector。
|
||||
4. FAISS 返回候选 ids。
|
||||
5. SQLite 读取 metadata,过滤 disabled、sensitive、expired、low-confidence records。
|
||||
6. Re-ranker 按相似度、类型、最近使用、用户显式偏好排序。
|
||||
7. Top-K 以独立 `memory_context` 注入 LLM。
|
||||
8. LLM 回复完成后,`MemoryWriteCandidateExtractor` 生成候选记忆。
|
||||
9. Safety classifier 决定保存、丢弃或请求确认。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 保留现有 turn-based `run-live` 作为稳定路径。
|
||||
2. 后续实现新增 feature flag 或新入口启用全双工 Agent。
|
||||
3. 先落地 fake provider 和模拟端到端,再接真实 WebRTC APM。
|
||||
4. STT/TTS provider 先用兼容 adapter 接现有能力,再替换为 streaming provider。
|
||||
5. 长期记忆默认关闭或空库启动,完成删除/禁用/隐私文档后再默认开启。
|
||||
6. Tool Router 默认只启用 `memory.search`;其他工具按风险逐步开放。
|
||||
7. Open Interpreter 和 Playwright adapter 默认关闭,用户显式配置后才可用。
|
||||
8. GUI 电脑控制另开 OpenSpec 变更,不混入第一版全双工音频和安全工具验收。
|
||||
|
||||
## Rollback Strategy
|
||||
|
||||
1. 若全双工音频不稳定,可通过配置回退 turn-based `run-live`。
|
||||
2. 若 APM provider 失败,可禁用 full-duplex mode 或启用 fallback 标记的旧链路。
|
||||
3. 若长期记忆异常,可设置 `OWNER_MEMORY_ENABLED=0`,继续短期对话。
|
||||
4. 若 Tool Router 风险过高,可设置 `OWNER_TOOL_ROUTER_ENABLED=0`,保留纯聊天。
|
||||
5. 若 Open Interpreter 或 Playwright adapter 出错,只禁用对应工具,不影响语音主循环。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
1. WebRTC APM 依赖复杂 -> 通过 provider 抽象、fake APM 测试和 fallback 降低风险。
|
||||
2. 全双工并发复杂 -> 通过 bounded queue、cancellation graph、虚拟时钟测试和事件指标控制。
|
||||
3. 流式 STT/TTS 模型较重 -> 分阶段实现,先 provider interface 和 fake tests,再接真实模型。
|
||||
4. 长期记忆有隐私风险 -> 默认敏感不保存、可禁用、可删除、可审计。
|
||||
5. 工具执行有安全风险 -> 安全工具优先,高风险确认或拒绝,输出脱敏和审计日志。
|
||||
6. Open Interpreter 能力强但风险大 -> 默认关闭、低风险受限执行、外部 CLI adapter、禁止复制仓库。
|
||||
7. Playwright 登录态风险 -> 第一版不默认使用用户登录态,敏感流程确认或拒绝。
|
||||
8. 第一阶段 scope 大 -> 按音频、状态机、STT/TTS、记忆、工具拆分里程碑,每个里程碑独立提交。
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. 全双工入口是否命名为 `run-agent-live`,还是通过 `run-live --mode full-duplex` 启用。
|
||||
2. WebRTC APM 的具体 Python/macOS 绑定选择需要验证。
|
||||
3. 内部采样率统一用 16 kHz 还是 48 kHz,需要结合 APM、STT、TTS provider 决定。
|
||||
4. SenseVoice 和 CosyVoice 是否作为产品强依赖,还是只保留候选。
|
||||
5. 长期记忆是否默认开启,需要用户确认隐私预期。
|
||||
6. Open Interpreter 是否允许写操作;若允许,确认流程和 sandbox 需要单独设计。
|
||||
7. Playwright 是否允许使用现有 Chrome 登录态。
|
||||
8. 后续 ComputerControlProvider 是否采用 macOS Accessibility、trycua 或其他公共方案。
|
||||
@@ -0,0 +1,516 @@
|
||||
# OpenSpec:完整全双工 Agent 语音助手架构
|
||||
|
||||
## 功能目标
|
||||
|
||||
### 完整业务价值
|
||||
|
||||
当前 Owner 语音桌宠已经从最初的“唤醒词 -> VAD -> STT -> LLM -> TTS -> 播放”演进到可真实运行的 `run-live`,并具备本地唤醒、实时字幕、噪音过滤、连续追问、结束提示音和初步播报打断规划。但现有核心仍然是 turn-based 语音桌宠:用户先唤醒,系统听完一段话,识别完再思考,回复播放完再决定是否继续。这个模型能完成普通问答,但距离“小爱同学式持续对话”和完整 Agent 仍有明显差距。
|
||||
|
||||
本变更的业务目标是把现有语音桌宠规划升级为完整全双工 Agent 语音助手:麦克风持续输入、播放端持续输出、WebRTC APM 提供 AEC/NS/AGC 音频底座、Streaming STT 实时生成用户话语、LLM 流式回复按句进入 Streaming TTS、用户在 AI 讲话时可以自然打断,长期记忆和 Tool Router 让助手不只聊天,还能在安全边界内检索记忆、执行只读系统任务、调用 Open Interpreter 外部后端和 Playwright 浏览器自动化。
|
||||
|
||||
本阶段只产出 OpenSpec 审核材料,不改运行代码、不安装依赖、不下载模型、不接入工具执行、不把本地未跟踪的 `openinterpreter/` 复制进 Owner 代码,也不提交该目录。`openinterpreter/` 在本变更中只被定义为外部 CLI/子进程工具后端候选。
|
||||
|
||||
### 目标用户场景
|
||||
|
||||
1. 用户在 macOS 上启动语音助手后,不需要按住说话;麦克风常驻监听,系统通过本地唤醒或持续 VAD/STT 管理输入。
|
||||
2. 用户听 AI 回复时可以直接插话;系统在 200 ms 目标延迟内停止 TTS 播放、取消当前 LLM/TTS 任务,并把用户新话语作为下一轮输入。
|
||||
3. AI 自己的扬声器声音不会被误当成用户输入;WebRTC APM 的 AEC 使用播放 reference 音频消除回声,NS 降低环境噪声,AGC 统一麦克风音量。
|
||||
4. 用户可以连续追问,不必每轮都说“小杰小杰”;Conversation Manager 根据状态机和上下文判断当前是继续听、执行工具、播报结果还是恢复待机。
|
||||
5. 助手可长期记住非敏感偏好、事实、项目摘要和任务摘要;重启后仍可通过 FAISS+SQLite 召回相关记忆,但敏感信息默认不自动保存。
|
||||
6. 用户要求“整理下载目录”“查一下项目文件”“打开网页抓取内容”时,Tool Router 先做安全分类,低风险只读工具可执行,高风险写操作、删除、上传、交易、权限变更必须要求确认,第一版不自动做 GUI 点击/键盘控制。
|
||||
7. 后续桌宠 GUI 可订阅同一事件流展示听、想、说、工具执行、被打断、等待确认等状态,而不是重新实现 pipeline 逻辑。
|
||||
|
||||
### 量化成功指标 KPI
|
||||
|
||||
1. 打断延迟:在可控音频测试环境中,`speaking` 状态下检测到有效用户语音后,进入 `interrupted` 并停止播放的 P95 延迟目标小于 200 ms。
|
||||
2. 回声抑制:播放 reference 音频注入 AEC 后,纯助手回放不触发用户 VAD/STT,不产生有效 `barge_in_detected`。
|
||||
3. 实时识别:用户开始说话后,Streaming STT 首个稳定 partial transcript 的 P95 目标小于 800 ms。
|
||||
4. 端到端首音:LLM 首个可播报句子产生后,Streaming TTS 首个可播放 PCM chunk 的 P95 目标小于 1000 ms。
|
||||
5. 流式播报:LLM 不等待完整回复;中文回复按句切分进入 TTS,第一句可播放后立即播放。
|
||||
6. 取消可靠性:用户打断时,当前 LLM stream、TTS synthesis、playback、工具执行候选任务均收到 cancellation token;被取消内容不得继续写入上下文。
|
||||
7. 记忆召回准确性:保存的偏好/事实/项目摘要在相关查询中可被 Top-K 检索召回;关闭记忆时不得读写 SQLite/FAISS。
|
||||
8. 工具安全:未授权工具、越权路径、写操作、删除操作、账号/上传/交易类任务必须被拒绝或进入确认流程;自动化测试覆盖非法工具拒绝、防循环、超时、输出截断。
|
||||
9. 兼容性:现有 turn-based `run-live` 语义在迁移期不得被破坏;新全双工入口可分阶段实现,允许先以 feature flag 启用。
|
||||
10. OpenSpec 完整性:`openspec validate add-full-duplex-agent-voice-assistant --strict` 与 `openspec validate --all --strict` 必须通过。
|
||||
|
||||
### 预期影响
|
||||
|
||||
1. 主规范 `voice-pet-pipeline` 将从“Python 桌宠语音 pipeline”升级为“全双工 Agent 语音助手 pipeline”,覆盖音频底座、并发模型、记忆、工具和安全策略。
|
||||
2. 后续实现将新增 WebRTC APM provider、全双工音频环形缓冲、Streaming STT/TTS provider、Conversation Manager、MemoryManager、ToolRouter、Open Interpreter adapter、Playwright browser adapter。
|
||||
3. 现有 GTCRN 降噪、主说话人音色门控和本地 KWS 保留为 fallback 或局部能力,不再作为完整全双工回声消除的主方案。
|
||||
4. 当前进程内临时上下文保留,但长期记忆成为独立层;临时会话历史和长期记忆必须有清楚边界。
|
||||
5. 工具执行引入新的安全面,必须规划确认策略、权限边界、路径限制、超时、输出截断、审计日志和敏感信息脱敏。
|
||||
6. 第一版电脑控制不做 GUI 点击/键盘/屏幕控制;只预留 `ComputerControlProvider`。Codex Computer Use 只参考安全确认策略,不复制私有或捆绑实现。
|
||||
|
||||
### 对现有问题的系统性总结
|
||||
|
||||
1. 性能问题:现有 turn-based pipeline 在录音结束后才进入 final STT 和 LLM,用户感知延迟集中爆发;全双工架构要求持续识别和流式回复。
|
||||
2. 打断问题:当前打断规划仍围绕播放 chunk 检查或后台监听补丁,缺少全局 cancellation graph;用户插话无法统一取消 LLM、TTS、播放和工具任务。
|
||||
3. 回声问题:现有音色门控只能降低误触发,无法从音频底座消除扬声器回放;没有 AEC reference,后续 VAD/STT 容易被 AI 自己声音污染。
|
||||
4. 噪音问题:GTCRN 只覆盖正式问题采集阶段;全双工持续监听需要系统级 NS/AGC,避免背景噪声导致持续 STT 和打断误判。
|
||||
5. 架构问题:现有 pipeline 仍以“轮次”为主,状态机缺少 `tool_running`、`interrupted`、`recovering` 等 Agent 必需状态。
|
||||
6. 记忆问题:当前上下文只存在于本次进程内;无法记住长期偏好、项目背景和任务摘要,也没有隐私分类和删除策略。
|
||||
7. 工具问题:当前 LLM 只能生成自然语言;没有结构化工具协议、工具路由、安全策略、执行预算、防循环机制和工具结果回注。
|
||||
8. Open Interpreter 边界问题:本地 `openinterpreter/` 是未跟踪外部仓库,不能复制进 Owner;需要把它规划为可选外部 CLI 后端并限制风险。
|
||||
9. UI/UX 问题:后续桌宠如果直接绑定 runtime 方法,会继续重复逻辑;需要统一事件总线承载状态、字幕、音频、打断、工具和确认请求。
|
||||
10. 安全问题:长期记忆和工具执行都会扩大数据面与操作面;必须默认最小权限、敏感内容不自动保存、高风险操作确认、日志脱敏。
|
||||
|
||||
## 详细需求
|
||||
|
||||
### 功能需求
|
||||
|
||||
1. 系统 SHALL 新增完整全双工 Agent 语音助手架构规划,保留现有 turn-based 能力作为迁移期兼容路径。
|
||||
2. 系统 SHALL 规划 `ContinuousAudioRuntime`,负责麦克风持续输入、扬声器播放 reference、音频环形缓冲、状态机事件和任务取消。
|
||||
3. 系统 SHALL 规划 `WebRtcAudioProcessingStage`,默认 `OWNER_AUDIO_APM_PROVIDER=webrtc`,开启 AEC、NS、AGC。
|
||||
4. 播放链路 SHALL 把 TTS PCM/render audio 提供给 AEC reference,麦克风 capture 音频经过 APM 后再进入 VAD、STT 和打断检测。
|
||||
5. 系统 SHALL 规划全双工状态机:`idle`、`listening`、`thinking`、`speaking`、`interrupted`、`tool_running`、`recovering`。
|
||||
6. 任意状态下检测到有效用户说话 SHALL 能进入 `interrupted`,但 `tool_running` 的中断语义必须区分可取消工具和不可安全取消工具。
|
||||
7. 系统 SHALL 规划 Silero VAD 或等价本地 VAD 作为打断触发的主要人声检测层;打断检测先判断“有人开始说话”,不依赖已识别出完整文本。
|
||||
8. 打断目标 SHALL 是在 `OWNER_BARGE_IN_TARGET_LATENCY_MS=200` 内停止播放和取消当前回复。
|
||||
9. 系统 SHALL 规划 Streaming STT provider;开发默认候选为 `faster-whisper`,产品候选为 `SenseVoice`,保留现有 `sherpa-onnx` 兼容 adapter。
|
||||
10. Streaming STT SHALL 输出 partial transcript、stable partial transcript 和 final transcript;只有 final transcript 或明确提交的 stable transcript 可进入 LLM。
|
||||
11. 系统 SHALL 规划 Streaming TTS provider;目标候选为 `CosyVoice`,支持句子级和流式 PCM 输出。
|
||||
12. LLM SHALL 流式输出 token;Sentence Segmenter SHALL 在检测到完整中文/英文句子或安全停顿时,把文本片段送入 TTS,不等待整段回复完成。
|
||||
13. TTS 播放 SHALL 支持中途停止;停止后未完整播出的 assistant 文本不得写入短期上下文或长期记忆。
|
||||
14. 系统 SHALL 规划 `ConversationManager`,负责短期会话历史、长期记忆召回、工具调用闭环和状态推进。
|
||||
15. 系统 SHALL 规划 `MemoryManager`,默认 `OWNER_MEMORY_PROVIDER=faiss_sqlite`,SQLite 存文本和元数据,FAISS 存向量索引。
|
||||
16. 记忆类型 SHALL 至少包含 `preference`、`fact`、`project`、`task_summary`。
|
||||
17. 每轮用户输入进入 LLM 前 SHALL 根据当前用户文本、会话摘要和任务上下文检索 Top-K 长期记忆,并以明确的 memory context 注入 LLM。
|
||||
18. 敏感内容 SHALL 默认不自动保存;记忆写入必须经过分类器、安全策略或用户明确指令。
|
||||
19. 系统 SHALL 规划 `ToolRouter` 和结构化工具调用协议,工具请求包含 name、arguments、risk_level、requires_confirmation、timeout_ms、budget、cancellation_policy。
|
||||
20. 第一版工具 SHALL 以安全工具为主:`memory.search`、`memory.save`、`shell.readonly`、`openinterpreter.run`、`browser.playwright`。
|
||||
21. `shell.readonly` SHALL 限制为只读命令和允许目录,禁止删除、写文件、修改权限、网络上传、安装依赖等高风险行为。
|
||||
22. `openinterpreter.run` SHALL 作为外部 CLI/子进程 adapter,默认只允许低风险、受限目录、超时和输出截断任务。
|
||||
23. `browser.playwright` SHALL 作为浏览器自动化 adapter,默认只允许可审计、非支付、非账号敏感的浏览和提取流程。
|
||||
24. 第一版 SHALL NOT 实现 GUI 点击/键盘/屏幕控制;只在规范中预留 `ComputerControlProvider`,后续可基于 macOS Accessibility、Playwright、trycua 等公共能力实现。
|
||||
25. Codex Computer Use 能力 SHALL 仅作为安全确认策略参考,不复制私有实现、捆绑脚本或内部协议。
|
||||
26. 系统 SHALL 规划工具结果回注:工具输出进入 Tool Result Message,经过脱敏和长度限制后返回 LLM;工具失败进入可恢复错误路径。
|
||||
27. 系统 SHALL 规划防循环策略:单轮最大工具调用次数、最大总耗时、最大输出字节、重复工具调用检测。
|
||||
28. 系统 SHALL 规划安全确认策略:写文件、删除、上传、交易、账号、权限、联网提交、安装依赖、执行任意代码等高风险操作必须确认,第一版默认拒绝自动执行。
|
||||
29. 系统 SHALL 规划桌宠/终端共用事件总线,事件覆盖 audio、vad、stt、llm、tts、playback、memory、tool、confirmation、interruption、recovery。
|
||||
30. 本阶段 SHALL 只创建 OpenSpec 文档;不得创建或修改 `src/`、`tests/`、`scripts/`、`pyproject.toml`、`.env`、模型文件、音频资产或运行时代码。
|
||||
|
||||
### 非功能需求
|
||||
|
||||
1. 性能优化:全双工音频处理必须以固定帧长和环形缓冲为基础,避免 Python 线程阻塞导致播放卡顿或输入积压。
|
||||
2. 延迟目标:VAD frame interval 默认不超过 20 ms;播放停止 chunk 默认不超过 30 ms;整体打断目标小于 200 ms。
|
||||
3. 稳定性:所有 provider 必须支持超时、取消、关闭和资源释放;异常必须进入 `recovering`,不得让后台线程泄漏。
|
||||
4. 可扩展性:APM、VAD、STT、TTS、LLM、Memory、Tool adapter 都必须是可替换 provider,不能把具体模型硬编码进状态机。
|
||||
5. UI/UX:终端和未来 GUI 不直接调用 provider,只消费事件;显示文案、字幕、工具确认和桌宠动画均由事件驱动。
|
||||
6. 安全:API key、Authorization header、原始音频、声纹特征、工具敏感输出不得写入日志或长期记忆。
|
||||
7. 隐私:默认不保存原始麦克风音频;长期记忆只保存文本摘要和必要元数据;用户必须能关闭记忆。
|
||||
8. 兼容性:现有 `.env` 中 LLM 配置继续可用;新增配置必须有默认值和迁移说明。
|
||||
9. 可测试性:每个并发 stage 必须可用 fake provider 和虚拟时钟测试;端到端模拟不依赖真实麦克风、扬声器或外部工具。
|
||||
10. 可观测性:事件必须携带 turn/session id、stage、时间戳、latency、error code 和脱敏 payload,便于定位卡顿、误触发和工具风险。
|
||||
|
||||
### 边缘案例
|
||||
|
||||
1. APM 初始化失败:系统必须报告 `AUDIO_APM_UNAVAILABLE`,可按配置降级到现有 GTCRN/音色门控 fallback 或拒绝进入全双工模式。
|
||||
2. AEC reference 丢失:播放中没有 reference 音频时,系统必须降低打断置信度或临时禁用高风险 barge-in,避免 AI 自己声音触发。
|
||||
3. 麦克风权限缺失:启动失败并提示设备检查,不进入假监听状态。
|
||||
4. 用户在 AI 说第一个字前打断:取消 LLM/TTS stream,未播报文本不写入上下文。
|
||||
5. 用户在工具执行中打断:可取消工具立即取消;不可安全取消工具进入“正在收尾/等待结果”状态,并向用户播报或显示限制。
|
||||
6. LLM 已发起工具调用但用户打断:未执行工具调用应取消;已执行且低风险的只读工具结果可丢弃或标记为 stale。
|
||||
7. 记忆库损坏:FAISS 或 SQLite 不可用时,系统可禁用长期记忆并继续基本语音对话,但必须报告结构化错误。
|
||||
8. 记忆召回命中敏感内容:默认不注入 LLM,除非用户明确要求并通过安全策略。
|
||||
9. Open Interpreter 路径缺失:`openinterpreter.run` adapter 标记不可用,不影响其他工具。
|
||||
10. 工具输出过长:按配置截断并附 `truncated=true` 元数据,不把完整大输出塞进 LLM。
|
||||
11. Playwright 未安装或浏览器不可用:工具返回可恢复错误,不影响语音主循环。
|
||||
12. TTS 输出卡顿:播放队列应能反压 TTS 合成;卡顿事件必须可观测,不能阻塞麦克风监听线程。
|
||||
13. Streaming STT partial 抖动:只显示稳定 partial;final transcript 才进入对话。
|
||||
14. 网络 LLM 慢或断线:取消和超时必须生效;恢复后回到 listening 或 idle。
|
||||
15. 多人同时说话:第一版不承诺身份鉴权,只要求 AEC 后的人声触发和用户体验合理;多人区分列为需人工澄清。
|
||||
|
||||
### 输入输出规格
|
||||
|
||||
新增或规划配置:
|
||||
|
||||
1. `OWNER_ASSISTANT_MODE=full_duplex_agent`
|
||||
2. `OWNER_AUDIO_APM_PROVIDER=webrtc`
|
||||
3. `OWNER_AUDIO_AEC_ENABLED=1`
|
||||
4. `OWNER_AUDIO_NS_ENABLED=1`
|
||||
5. `OWNER_AUDIO_AGC_ENABLED=1`
|
||||
6. `OWNER_AUDIO_FRAME_MS=20`
|
||||
7. `OWNER_AUDIO_RING_BUFFER_MS=3000`
|
||||
8. `OWNER_VAD_PROVIDER=silero`
|
||||
9. `OWNER_INTERRUPT_ENABLED=1`
|
||||
10. `OWNER_INTERRUPT_TARGET_LATENCY_MS=200`
|
||||
11. `OWNER_STREAMING_STT_PROVIDER=faster_whisper`
|
||||
12. `OWNER_STREAMING_STT_PRODUCT_CANDIDATE=sensevoice`
|
||||
13. `OWNER_STREAMING_TTS_PROVIDER=cosyvoice`
|
||||
14. `OWNER_LLM_STREAMING_ENABLED=1`
|
||||
15. `OWNER_MEMORY_ENABLED=1`
|
||||
16. `OWNER_MEMORY_PROVIDER=faiss_sqlite`
|
||||
17. `OWNER_MEMORY_TOP_K=5`
|
||||
18. `OWNER_MEMORY_AUTO_SAVE_SENSITIVE=0`
|
||||
19. `OWNER_TOOL_ROUTER_ENABLED=1`
|
||||
20. `OWNER_TOOL_MAX_CALLS_PER_TURN=5`
|
||||
21. `OWNER_TOOL_TIMEOUT_MS=30000`
|
||||
22. `OWNER_OPENINTERPRETER_ENABLED=0`
|
||||
23. `OWNER_OPENINTERPRETER_COMMAND=openinterpreter`
|
||||
24. `OWNER_BROWSER_PLAYWRIGHT_ENABLED=0`
|
||||
25. `OWNER_COMPUTER_CONTROL_ENABLED=0`
|
||||
|
||||
核心事件输出:
|
||||
|
||||
1. `audio_capture_started`
|
||||
2. `audio_apm_started`
|
||||
3. `listening_started`
|
||||
4. `speech_started`
|
||||
5. `stt_partial`
|
||||
6. `stt_final`
|
||||
7. `llm_stream_started`
|
||||
8. `llm_sentence_ready`
|
||||
9. `tts_chunk_ready`
|
||||
10. `playback_started`
|
||||
11. `interrupt_detected`
|
||||
12. `playback_cancelled`
|
||||
13. `llm_cancelled`
|
||||
14. `memory_retrieved`
|
||||
15. `tool_call_requested`
|
||||
16. `tool_confirmation_required`
|
||||
17. `tool_call_started`
|
||||
18. `tool_call_finished`
|
||||
19. `tool_call_rejected`
|
||||
20. `session_recovered`
|
||||
|
||||
### 数据验证规则
|
||||
|
||||
1. Provider 配置必须在启动前校验,不允许未知 provider 静默回退。
|
||||
2. APM 输出帧采样率、声道数、帧长必须与 VAD/STT 输入一致;不一致必须显式 resample 或报错。
|
||||
3. Streaming STT partial 不得进入长期记忆;final transcript 必须经过空文本、重复文本、敏感内容和最小置信度检查。
|
||||
4. TTS 播报文本必须经过现有 TTS sanitizer;emoji、表情包和 Markdown 图片不得进入语音。
|
||||
5. 长期记忆写入必须包含 type、text、source_turn_id、created_at、sensitivity、embedding_model、checksum。
|
||||
6. FAISS index 和 SQLite metadata 必须可一致性检查;缺失或 checksum 不匹配时不得返回伪造记忆。
|
||||
7. Tool Router arguments 必须按工具 schema 校验;未知字段、路径越界、命令注入风险必须拒绝。
|
||||
8. 工具结果进入 LLM 前必须截断、脱敏,并标注工具名、耗时、退出码和是否截断。
|
||||
9. 所有 cancellation token 必须可幂等触发,多次取消不得抛出未处理异常。
|
||||
|
||||
### 需人工澄清
|
||||
|
||||
1. 全双工入口是替换 `run-live`,还是新增 `run-agent-live` 并保留 `run-live` 为稳定 turn-based 入口。
|
||||
2. WebRTC APM Python 绑定优先选择哪个包或本地封装,是否允许引入需要系统编译的依赖。
|
||||
3. 产品阶段是否确定采用 SenseVoice 和 CosyVoice,还是只在规范中保留候选。
|
||||
4. 长期记忆是否需要用户可视化管理、删除、导出和禁用命令。
|
||||
5. Open Interpreter CLI 的实际本机命令、工作目录、沙箱策略和是否允许写操作需要人工确认。
|
||||
6. Playwright 浏览器工具是否允许使用用户当前 Chrome 登录态,还是只允许独立 browser context。
|
||||
7. 多人说话场景是否需要主人声纹注册;本变更默认不做身份鉴权。
|
||||
8. 桌宠 GUI 和电脑控制是否必须同期开工;本变更建议第一版先做音频全双工、记忆和安全工具。
|
||||
|
||||
## 设计方案
|
||||
|
||||
### 文字版全新架构图
|
||||
|
||||
```text
|
||||
Microphone
|
||||
-> Capture Ring Buffer
|
||||
-> WebRtcAudioProcessingStage(AEC + NS + AGC, render reference from Speaker)
|
||||
-> SileroVadStage
|
||||
-> InterruptDetector
|
||||
-> StreamingSttStage(faster-whisper dev / SenseVoice candidate / sherpa fallback)
|
||||
-> ConversationManager
|
||||
-> ShortTermSessionContext
|
||||
-> MemoryManager(SQLite metadata + FAISS vectors)
|
||||
-> LlmStage(streaming OpenAI-compatible provider)
|
||||
-> ToolRouter(memory.search/save, shell.readonly, openinterpreter.run, browser.playwright)
|
||||
-> ResponseStream
|
||||
-> SentenceSegmenter
|
||||
-> StreamingTtsStage(CosyVoice candidate / local fallback)
|
||||
-> Playback Ring Buffer
|
||||
-> Speaker
|
||||
-> Render Reference back to WebRtcAudioProcessingStage
|
||||
```
|
||||
|
||||
### 数据流
|
||||
|
||||
1. `ContinuousAudioRuntime` 启动后初始化 capture device、playback device、APM、VAD、STT、TTS、LLM、Memory、ToolRouter。
|
||||
2. 麦克风音频以固定 20 ms 帧写入 capture ring buffer;播放 PCM 以相同时间轴写入 render reference buffer。
|
||||
3. `WebRtcAudioProcessingStage` 使用 render reference 对 capture frame 执行 AEC,再执行 NS/AGC。
|
||||
4. APM 后音频同时进入 VAD、Streaming STT 和 Interrupt Detector。
|
||||
5. `listening` 状态下,VAD/STT 产生用户输入;final transcript 进入 Conversation Manager。
|
||||
6. Conversation Manager 召回短期上下文和长期记忆,生成 LLM streaming request。
|
||||
7. LLM delta 进入 Sentence Segmenter;完整句子进入 Streaming TTS;TTS chunk 立即入 playback queue。
|
||||
8. 播放开始后,播放 PCM 仍持续进入 render reference,使 AEC 能抑制助手回声。
|
||||
9. 如果用户讲话,Interrupt Detector 发出 `interrupt_detected`,Cancellation Graph 同时取消 LLM stream、未完成 TTS、播放队列和可取消工具。
|
||||
10. Tool Router 在 LLM 请求工具时执行 schema 校验、安全分类、确认策略、执行、结果脱敏和回注。
|
||||
11. 任何 stage 失败进入 `recovering`,释放后台任务和音频资源后回到 `listening` 或 `idle`。
|
||||
|
||||
### 接口定义
|
||||
|
||||
```text
|
||||
AudioFrame:
|
||||
samples: float32 PCM
|
||||
sample_rate: int
|
||||
channels: int
|
||||
timestamp_monotonic_ms: int
|
||||
frame_id: str
|
||||
```
|
||||
|
||||
```text
|
||||
WebRtcAudioProcessingStage.process_capture(frame: AudioFrame) -> AudioFrame
|
||||
WebRtcAudioProcessingStage.process_render(frame: AudioFrame) -> None
|
||||
WebRtcAudioProcessingStage.reset_stream() -> None
|
||||
Errors:
|
||||
AUDIO_APM_UNAVAILABLE
|
||||
AUDIO_APM_FORMAT_MISMATCH
|
||||
AUDIO_APM_PROCESS_FAILED
|
||||
```
|
||||
|
||||
```text
|
||||
StreamingSttProvider.start_session(session_id: str) -> StreamingSttSession
|
||||
StreamingSttSession.accept_audio(frame: AudioFrame) -> list[TranscriptEvent]
|
||||
StreamingSttSession.finish() -> TranscriptFinal
|
||||
StreamingSttSession.cancel(reason: str) -> None
|
||||
```
|
||||
|
||||
```text
|
||||
StreamingTtsProvider.start_stream(voice: str, sample_rate: int) -> StreamingTtsSession
|
||||
StreamingTtsSession.accept_text(text: str) -> list[AudioFrame]
|
||||
StreamingTtsSession.flush() -> list[AudioFrame]
|
||||
StreamingTtsSession.cancel(reason: str) -> None
|
||||
```
|
||||
|
||||
```text
|
||||
MemoryManager.search(query: str, *, top_k: int, filters: dict) -> list[MemoryRecord]
|
||||
MemoryManager.save(record: MemoryRecordInput) -> MemoryRecord
|
||||
MemoryManager.delete(memory_id: str) -> None
|
||||
MemoryManager.health_check() -> MemoryHealth
|
||||
```
|
||||
|
||||
```text
|
||||
ToolRouter.route(call: ToolCallRequest, context: ToolContext) -> ToolDecision
|
||||
ToolRouter.execute(decision: ToolDecision, cancellation: CancellationToken) -> ToolResult
|
||||
ToolDecision:
|
||||
action: execute | reject | require_confirmation
|
||||
risk_level: low | medium | high | forbidden
|
||||
reason: str
|
||||
```
|
||||
|
||||
### 状态机
|
||||
|
||||
```text
|
||||
idle
|
||||
-> listening
|
||||
listening
|
||||
-> thinking on final user transcript
|
||||
-> interrupted on explicit cancel or new speech over assistant residue
|
||||
-> recovering on audio/STT failure
|
||||
thinking
|
||||
-> speaking on first playable TTS chunk
|
||||
-> tool_running on approved tool call
|
||||
-> interrupted on user speech
|
||||
-> recovering on LLM failure
|
||||
speaking
|
||||
-> listening on reply finished and no follow-up/tool pending
|
||||
-> interrupted on valid user speech
|
||||
-> recovering on TTS/playback failure
|
||||
tool_running
|
||||
-> thinking on tool result returned to LLM
|
||||
-> interrupted on cancellable tool interrupted
|
||||
-> recovering on tool failure
|
||||
interrupted
|
||||
-> listening after current tasks cancelled and buffered user audio retained
|
||||
recovering
|
||||
-> listening after cleanup when runtime can continue
|
||||
-> idle when required provider unavailable
|
||||
```
|
||||
|
||||
### 关键算法
|
||||
|
||||
1. AEC reference 对齐:播放 PCM 写入 render buffer 时记录 monotonic timestamp;capture frame 处理前取最近 reference window,丢帧或漂移超过阈值时发 `audio_reference_drift`。
|
||||
2. 打断检测:APM 后音频先经 VAD 判断人声起点;连续人声超过最小阈值后结合 STT stable partial 或能量/频谱置信度触发 interrupt;纯 render echo 在 AEC 后应低于阈值。
|
||||
3. 句子切分:LLM delta 累积到中文句号、问号、感叹号、英文终止标点或最大等待阈值时切句;代码块、URL、数字小数点不得误切。
|
||||
4. 取消传播:每轮创建 root cancellation token;LLM、TTS、playback、tool 子任务注册 child token;用户打断时 root token 广播,所有 stage 幂等收尾。
|
||||
5. 长期记忆召回:用户 final transcript 生成 embedding,FAISS 取 Top-N,SQLite 取 metadata,按类型、敏感度、最近使用、相似度重排后注入 LLM。
|
||||
6. 记忆写入:Conversation Manager 在回合结束后提取候选记忆,按敏感分类和用户意图决定是否保存;敏感或不确定默认不保存。
|
||||
7. 工具路由:LLM tool call 先过 schema,再做风险分类和权限判断;低风险可执行,高风险进入确认,禁止类直接拒绝。
|
||||
|
||||
### 数据库/状态管理变更
|
||||
|
||||
1. SQLite 表 `memories`:`id`、`type`、`text`、`summary`、`metadata_json`、`sensitivity`、`source_turn_id`、`created_at`、`updated_at`、`last_used_at`、`embedding_id`、`checksum`。
|
||||
2. SQLite 表 `tool_audit_logs`:记录工具名、风险、确认状态、耗时、退出码、截断标记和脱敏摘要,不保存密钥。
|
||||
3. FAISS index 文件保存 embedding vectors;SQLite 保存 index 版本和 embedding model,启动时做一致性检查。
|
||||
4. 短期会话上下文仍在内存中,进程退出丢弃;长期记忆独立存储,可按配置禁用。
|
||||
|
||||
### UI 组件重构方案
|
||||
|
||||
1. 终端 reporter 只订阅事件,不直接读取 pipeline 内部状态。
|
||||
2. 未来桌宠 GUI 使用同一事件流展示 `listening`、`thinking`、`speaking`、`interrupted`、`tool_running`、`recovering`。
|
||||
3. 工具确认必须作为事件暴露,终端可先实现文本确认,GUI 后续实现按钮确认。
|
||||
4. 实时字幕分为 partial、stable partial、final 三种显示层级,避免把抖动 partial 当作最终用户输入。
|
||||
|
||||
### 依赖影响分析
|
||||
|
||||
1. WebRTC APM:新增依赖风险最高,需确认 Python/macOS 可用绑定或自建 native wrapper。
|
||||
2. Silero VAD:新增本地模型依赖,需评估 ONNX Runtime 或 torch 路线。
|
||||
3. Faster Whisper:开发体验好,但模型体积和 Metal/CPU 性能需评估。
|
||||
4. SenseVoice:中文效果强,产品候选;需确认 license、模型大小、macOS 部署成本。
|
||||
5. CosyVoice:TTS 效果强,依赖较重;第一阶段可先保留现有本地 TTS fallback。
|
||||
6. FAISS:macOS 安装和 wheel 兼容性需评估;必要时提供 sqlite-only 或 numpy fallback。
|
||||
7. Playwright:浏览器自动化依赖和浏览器安装体积需评估;第一版默认关闭。
|
||||
8. Open Interpreter:作为外部 CLI 后端,不作为 Owner 包内依赖;路径缺失时 adapter 不可用。
|
||||
|
||||
## 风险与权衡
|
||||
|
||||
| 风险 | 概率 | 影响 | 缓解措施 |
|
||||
| --- | --- | --- | --- |
|
||||
| WebRTC APM Python/macOS 绑定不可用或编译复杂 | 高 | 高 | OpenSpec 中把 provider 抽象出来;先验证 fake APM 和最小 native 方案;保留 GTCRN/音色门控 fallback。 |
|
||||
| AEC reference 与 capture 时钟不同步 | 中 | 高 | 使用 monotonic timestamp、ring buffer drift 监控、reference gap 事件和回声测试 fixture。 |
|
||||
| 全双工并发导致线程泄漏或播放卡顿 | 中 | 高 | 所有 stage 必须支持 cancellation token、bounded queue、backpressure 和统一 shutdown。 |
|
||||
| Streaming TTS 依赖过重导致落地慢 | 中 | 中 | 第一阶段先按句分段合成,CosyVoice 作为目标 provider,保留现有 Mac TTS fallback。 |
|
||||
| Faster Whisper/SenseVoice 模型性能不足 | 中 | 中 | 规范要求 provider 可替换,测试记录 partial/final latency,产品候选不在第一阶段强绑定。 |
|
||||
| 长期记忆保存敏感信息 | 中 | 高 | 默认敏感不自动保存;记忆写入前分类;用户可关闭;日志和记忆脱敏。 |
|
||||
| Tool Router 执行危险操作 | 中 | 高 | 默认安全工具优先,高风险确认,禁止类拒绝,目录限制,超时,输出截断,审计日志。 |
|
||||
| Open Interpreter 外部后端越权 | 中 | 高 | 默认关闭;只允许受限目录、低风险任务;写操作必须确认或拒绝;不复制外部仓库进 Owner。 |
|
||||
| Playwright 使用登录态带来账号风险 | 中 | 高 | 第一版默认独立 context;涉及账号、支付、购买、提交必须确认或拒绝。 |
|
||||
| 用户期望立即实现完整 GUI 控制 | 中 | 中 | 本变更明确第一版不做 GUI 点击/键盘/屏幕控制,只预留公共 provider。 |
|
||||
| FAISS 与 SQLite 一致性损坏 | 低 | 中 | 启动 health check、checksum、index rebuild 任务和 sqlite-only 降级。 |
|
||||
| LLM 工具循环 | 中 | 中 | 单轮最大工具次数、重复调用检测、总耗时预算和可恢复拒绝。 |
|
||||
| 不确定是否继续对话造成体验不稳 | 中 | 中 | Conversation Manager 规则优先,LLM 分类兜底,不确定默认 listening/idle 策略需人工确认。 |
|
||||
| OpenSpec scope 过大导致实现周期过长 | 高 | 中 | 实施计划分阶段:先音频全双工,再流式 STT/TTS,再记忆和工具,再电脑控制。 |
|
||||
|
||||
## 任务分解
|
||||
|
||||
> 本节定义 proposal 里的主要功能组或里程碑阶段。后续 `tasks.md` 必须把每组拆成不超过 1 小时的原子任务,并在完成每个大模块后按 Git 提交规范立即提交。
|
||||
|
||||
### 1. OpenSpec 与边界冻结
|
||||
|
||||
目标:只产出 `add-full-duplex-agent-voice-assistant` 文档,不改代码、不装依赖、不下载模型、不提交 `openinterpreter/`。
|
||||
|
||||
验收:OpenSpec 变更目录包含 proposal、design、tasks、spec delta;严格校验通过。
|
||||
|
||||
### 2. WebRTC APM 与全双工音频底座规划
|
||||
|
||||
目标:定义 capture/render ring buffer、AEC reference、NS、AGC、音频格式、时钟对齐和 fallback 策略。
|
||||
|
||||
验收:spec 包含 APM SHALL 要求、fake reference 测试场景和回声不触发 VAD/STT 场景。
|
||||
|
||||
### 3. 全双工状态机、事件总线与取消机制规划
|
||||
|
||||
目标:定义 `idle/listening/thinking/speaking/interrupted/tool_running/recovering` 状态机、事件模型、cancellation graph 和 recovery。
|
||||
|
||||
验收:design 包含状态转移表和取消传播;tasks 包含状态机、事件顺序和错误恢复测试。
|
||||
|
||||
### 4. Streaming STT 与低延迟打断规划
|
||||
|
||||
目标:定义 Streaming STT provider、Silero VAD、partial/final transcript、打断检测和 200 ms 目标。
|
||||
|
||||
验收:spec 包含 partial/final 行为、speaking 中用户说话进入 interrupted、纯回声不打断。
|
||||
|
||||
### 5. Streaming TTS 与响应流规划
|
||||
|
||||
目标:定义 LLM token stream、句子切分、Streaming TTS、播放队列、可中断播放和上下文写入边界。
|
||||
|
||||
验收:spec 包含不等待完整回复、未播完文本不写上下文、TTS 卡顿可观测。
|
||||
|
||||
### 6. 长期记忆规划
|
||||
|
||||
目标:定义 MemoryManager、FAISS+SQLite、记忆类型、召回、写入安全、禁用和删除策略。
|
||||
|
||||
验收:spec 包含保存、检索、重启召回、关闭记忆不读写、敏感内容不自动保存。
|
||||
|
||||
### 7. Tool Router 与安全工具规划
|
||||
|
||||
目标:定义结构化工具协议、安全路由、工具预算、防循环、工具结果回注,以及 `memory.search/save`、`shell.readonly`、`openinterpreter.run`、`browser.playwright`。
|
||||
|
||||
验收:spec 包含合法工具执行、非法工具拒绝、确认策略、Open Interpreter 缺失处理和 Playwright 安全边界。
|
||||
|
||||
### 8. Open Interpreter 与电脑控制边界规划
|
||||
|
||||
目标:明确 `openinterpreter/` 是外部未跟踪后端候选,不复制进 Owner;第一版不做 GUI 控制,只预留 `ComputerControlProvider`。
|
||||
|
||||
验收:proposal/design/tasks 均写明边界;git 提交不包含 `openinterpreter/`。
|
||||
|
||||
### 9. 测试、性能、安全和验收规划
|
||||
|
||||
目标:定义 fake APM、VAD、STT、TTS、memory、tool、Open Interpreter、Playwright、端到端模拟、性能指标和安全验证。
|
||||
|
||||
验收:tasks 中每项有前置条件、优先级、验收标准和测试要点;validation 命令明确。
|
||||
|
||||
## Spec Deltas
|
||||
|
||||
### Capabilities
|
||||
|
||||
#### New Capabilities
|
||||
|
||||
本变更不创建独立新 capability 文件。原因:用户明确要求 delta 文件路径为 `specs/voice-pet-pipeline/spec.md`,且全双工音频、长期记忆和 Tool Router 都作为语音助手 pipeline 的能力升级纳入同一现有 capability。
|
||||
|
||||
#### Modified Capabilities
|
||||
|
||||
- `voice-pet-pipeline`:从 turn-based Python 桌宠语音 pipeline 扩展为完整全双工 Agent 语音助手 pipeline,新增 WebRTC APM、持续监听、Streaming STT/TTS、低延迟打断、长期记忆、Tool Router、Open Interpreter 外部后端适配和安全工具执行要求。
|
||||
|
||||
### 与现有 `openspec/specs/voice-pet-pipeline/spec.md` 的精确差异
|
||||
|
||||
1. 修改 `Local microphone and speaker transport`:从本机麦克风/扬声器 transport 扩展为 capture/render reference 双向音频流,播放音频必须提供给 AEC。
|
||||
2. 修改 `VAD speech endpoint detection`:从 turn-based 端点检测扩展为持续 VAD、打断检测和全双工 listening。
|
||||
3. 修改 `Local STT transcription`:从 captured segment final STT 扩展为 Streaming STT partial/stable/final。
|
||||
4. 修改 `Cloud LLM streaming reply`:从流式 LLM 输出扩展为 token-to-sentence-to-TTS response stream,并要求可取消。
|
||||
5. 修改 `Local TTS synthesis and playback`:从整段或分句播放扩展为 Streaming TTS、PCM chunk 播放和中途停止。
|
||||
6. 修改 `Pipeline state machine`:新增 `listening`、`tool_running`、`recovering` 等全双工 Agent 状态,明确 `speaking -> interrupted`。
|
||||
7. 修改 `Audio feedback suppression`:从播放期间抑制输入扩展为 AEC + VAD + interrupt,允许用户有效打断。
|
||||
8. 修改 `Conversation context management`:保留进程内上下文,同时新增长期记忆召回的边界。
|
||||
9. 修改 `Security and privacy`:新增长期记忆、工具执行、Open Interpreter 和浏览器自动化安全要求。
|
||||
10. 修改 `Performance targets`:新增打断延迟、Streaming STT 首字、TTS 首 chunk、APM 帧处理等指标。
|
||||
11. 新增 requirement:`WebRTC audio processing foundation`。
|
||||
12. 新增 requirement:`Full-duplex agent state machine`。
|
||||
13. 新增 requirement:`Streaming STT and realtime transcript`。
|
||||
14. 新增 requirement:`Low-latency interruption and cancellation`。
|
||||
15. 新增 requirement:`Streaming response and TTS playback`。
|
||||
16. 新增 requirement:`Long-term memory with FAISS and SQLite`。
|
||||
17. 新增 requirement:`Tool Router and structured tool execution`。
|
||||
18. 新增 requirement:`Open Interpreter external adapter`。
|
||||
19. 新增 requirement:`Browser automation tool boundary`。
|
||||
20. 新增 requirement:`Computer control reservation`。
|
||||
|
||||
### 推翻重做的理由
|
||||
|
||||
1. turn-based VAD/STT/TTS 无法自然支持“AI 讲话时用户插话”,只能不断添加补丁。
|
||||
2. 音色门控不能替代 AEC;没有 render reference 的系统无法稳定区分助手回放和真实用户。
|
||||
3. 只靠 final STT 会让用户等待过久;完整助手需要持续识别和实时字幕。
|
||||
4. 没有 Tool Router 和 MemoryManager 的语音助手只能聊天,不能完成 Agent 任务。
|
||||
5. 工具和记忆如果后补,会难以补齐安全边界;必须在 OpenSpec 阶段先定义。
|
||||
|
||||
## 实施计划
|
||||
|
||||
### 分阶段优先级顺序
|
||||
|
||||
1. 阶段 A:OpenSpec 文档和边界冻结。
|
||||
2. 阶段 B:全双工音频底座和 fake APM 测试。
|
||||
3. 阶段 C:状态机、事件总线、取消机制和模拟端到端。
|
||||
4. 阶段 D:Streaming STT、VAD 打断和回声抑制测试。
|
||||
5. 阶段 E:Streaming LLM/TTS、句子切分和可中断播放。
|
||||
6. 阶段 F:长期记忆 FAISS+SQLite、记忆召回和隐私策略。
|
||||
7. 阶段 G:Tool Router、安全工具、Open Interpreter adapter 和 Playwright adapter。
|
||||
8. 阶段 H:文档、性能验收、安全审计和迁移收尾。
|
||||
|
||||
### 里程碑估时
|
||||
|
||||
| 里程碑 | 乐观 | 最可能 | 悲观 |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| A OpenSpec 文档 | 0.5 天 | 1 天 | 1.5 天 |
|
||||
| B 音频底座 | 2 天 | 4 天 | 8 天 |
|
||||
| C 状态机与取消 | 2 天 | 3 天 | 6 天 |
|
||||
| D Streaming STT 与打断 | 3 天 | 5 天 | 10 天 |
|
||||
| E Streaming TTS | 3 天 | 5 天 | 10 天 |
|
||||
| F 长期记忆 | 2 天 | 4 天 | 8 天 |
|
||||
| G Tool Router | 3 天 | 6 天 | 12 天 |
|
||||
| H 验收与收尾 | 2 天 | 4 天 | 8 天 |
|
||||
|
||||
总耗时预估:乐观 17.5 天,最可能 32 天,悲观 63.5 天。
|
||||
|
||||
### 数据/状态迁移策略
|
||||
|
||||
1. 现有进程内上下文不迁移为长期记忆,避免未经确认的历史被自动保存。
|
||||
2. 新长期记忆库首次启动为空;用户明确要求保存或分类器确认低敏偏好后才写入。
|
||||
3. 现有 `.env` 继续可用,新增变量采用默认值;全双工模式可通过 feature flag 启用。
|
||||
4. 现有 turn-based `run-live` 在迁移期保留,直到全双工验收稳定后再决定是否替换默认入口。
|
||||
5. `openinterpreter/` 外部仓库不纳入 Owner 迁移;只记录 adapter 配置和安全策略。
|
||||
|
||||
## Git 提交规范
|
||||
|
||||
1. 每完成一个大模块,必须立即执行构建或相应验证,然后执行 git commit。
|
||||
2. 大模块定义为 proposal “任务分解”中的主要功能组或实施计划中的里程碑阶段。
|
||||
3. 提交信息必须使用中文,格式为:`[模块名]:完成[具体功能描述],包含[关键变更]`。
|
||||
4. 提交前必须保证本模块验证通过,避免任何未提交的中间状态。
|
||||
5. 本 OpenSpec-only 阶段完成后提交信息固定为:`[全双工Agent架构]:完成完整语音助手OpenSpec计划,包含WebRTC音频底座、长期记忆和Tool Router设计`。
|
||||
6. 本次提交只允许包含 `openspec/changes/add-full-duplex-agent-voice-assistant/` 下的规划文档,不得提交 `openinterpreter/`、模型文件、依赖锁文件、`.env` 或运行代码。
|
||||
+379
@@ -0,0 +1,379 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Full-duplex agent mode
|
||||
The system SHALL support a planned full-duplex agent voice assistant mode that runs continuous microphone listening, streaming recognition, streaming response generation, streaming speech playback, interruption handling, memory retrieval, and safe tool routing as one coordinated pipeline.
|
||||
|
||||
#### Scenario: Full-duplex mode starts
|
||||
- **WHEN** the future implementation starts with `OWNER_ASSISTANT_MODE=full_duplex_agent`
|
||||
- **THEN** the system SHALL initialize continuous audio capture, audio playback, WebRTC audio processing, VAD, streaming STT, streaming TTS, conversation management, memory, and tool routing before accepting user interaction
|
||||
|
||||
#### Scenario: Turn-based mode remains available during migration
|
||||
- **WHEN** the future implementation starts with the existing turn-based mode
|
||||
- **THEN** the system SHALL preserve the existing wake-to-capture-to-STT-to-LLM-to-TTS behavior unless full-duplex mode is explicitly enabled
|
||||
|
||||
#### Scenario: Full-duplex provider is unavailable
|
||||
- **WHEN** a required full-duplex provider cannot be initialized and no configured fallback is allowed
|
||||
- **THEN** the system SHALL fail startup with a structured provider error rather than entering a fake full-duplex loop
|
||||
|
||||
### Requirement: WebRTC audio processing foundation
|
||||
The system SHALL define a WebRTC audio processing stage for full-duplex mode that applies acoustic echo cancellation, noise suppression, and automatic gain control to microphone capture audio using speaker playback audio as render reference.
|
||||
|
||||
#### Scenario: AEC uses playback reference
|
||||
- **WHEN** TTS playback writes PCM frames to the speaker output path
|
||||
- **THEN** the same render audio SHALL be provided to the WebRTC audio processing stage as echo cancellation reference
|
||||
|
||||
#### Scenario: Capture audio is processed
|
||||
- **WHEN** microphone frames are captured during full-duplex mode
|
||||
- **THEN** the frames SHALL pass through AEC, noise suppression, and automatic gain control before VAD, interruption detection, and streaming STT consume them
|
||||
|
||||
#### Scenario: Pure assistant echo is present
|
||||
- **WHEN** the microphone receives only the assistant's own playback echo and no user speech
|
||||
- **THEN** the processed audio SHALL NOT produce a valid user interruption or valid user transcript
|
||||
|
||||
#### Scenario: APM format mismatch occurs
|
||||
- **WHEN** capture audio and render reference audio have incompatible sample rate, channel count, or frame size
|
||||
- **THEN** the system SHALL either explicitly resample to the configured internal format or fail with `AUDIO_APM_FORMAT_MISMATCH`
|
||||
|
||||
#### Scenario: WebRTC APM fails at runtime
|
||||
- **WHEN** the WebRTC audio processing stage raises a processing error
|
||||
- **THEN** the pipeline SHALL emit a structured audio processing error and transition through recovery without corrupting conversation history
|
||||
|
||||
### Requirement: Full-duplex audio ring buffers
|
||||
The system SHALL use bounded capture and render reference ring buffers with timestamps so full-duplex capture, playback, AEC, VAD, STT, and interruption detection can run concurrently without unbounded memory growth.
|
||||
|
||||
#### Scenario: Capture frame is received
|
||||
- **WHEN** the microphone callback receives a PCM frame
|
||||
- **THEN** the frame SHALL be written to the capture ring buffer with a monotonic timestamp, frame id, sample rate, channel count, and duration
|
||||
|
||||
#### Scenario: Render frame is queued
|
||||
- **WHEN** TTS or playback queues a PCM frame for speaker output
|
||||
- **THEN** the frame SHALL be written to the render reference ring buffer with timing metadata usable by AEC
|
||||
|
||||
#### Scenario: Ring buffer overflows
|
||||
- **WHEN** an audio ring buffer exceeds its configured capacity
|
||||
- **THEN** the system SHALL drop the oldest safe frames, emit an `audio_buffer_overrun` event, and continue without blocking the audio callback indefinitely
|
||||
|
||||
#### Scenario: Reference drift is detected
|
||||
- **WHEN** capture and render timestamps drift beyond the configured tolerance
|
||||
- **THEN** the system SHALL emit an `audio_reference_drift` event and reduce confidence in interruption decisions until alignment recovers
|
||||
|
||||
### Requirement: Full-duplex agent state machine
|
||||
The system SHALL define a deterministic full-duplex state machine with `idle`, `listening`, `thinking`, `speaking`, `interrupted`, `tool_running`, and `recovering` states.
|
||||
|
||||
#### Scenario: User input reaches the LLM
|
||||
- **WHEN** full-duplex listening produces a valid final user transcript
|
||||
- **THEN** the state machine SHALL transition from `listening` to `thinking`
|
||||
|
||||
#### Scenario: First playable response is ready
|
||||
- **WHEN** the LLM response stream and TTS pipeline produce the first playable audio chunk
|
||||
- **THEN** the state machine SHALL transition from `thinking` to `speaking`
|
||||
|
||||
#### Scenario: User interrupts playback
|
||||
- **WHEN** valid user speech is detected while the assistant is speaking
|
||||
- **THEN** the state machine SHALL transition from `speaking` to `interrupted`
|
||||
|
||||
#### Scenario: Tool call starts
|
||||
- **WHEN** the LLM requests an approved tool call
|
||||
- **THEN** the state machine SHALL transition to `tool_running` until the tool result is returned, rejected, cancelled, or fails
|
||||
|
||||
#### Scenario: Recoverable error occurs
|
||||
- **WHEN** a recoverable provider, memory, tool, STT, TTS, LLM, or playback error occurs
|
||||
- **THEN** the state machine SHALL transition to `recovering` and then to a safe `listening` or `idle` state after cleanup
|
||||
|
||||
### Requirement: Pipeline event bus for agent stages
|
||||
The system SHALL expose a stable pipeline event bus for full-duplex audio, recognition, generation, playback, interruption, memory, tools, confirmation, and recovery events.
|
||||
|
||||
#### Scenario: Terminal reporter displays state
|
||||
- **WHEN** the terminal displays full-duplex runtime status
|
||||
- **THEN** it SHALL derive its output from pipeline events rather than directly reading provider internals
|
||||
|
||||
#### Scenario: GUI subscribes to the same events
|
||||
- **WHEN** a future desktop pet GUI is implemented
|
||||
- **THEN** it SHALL be able to subscribe to the same event bus used by the terminal reporter and tests
|
||||
|
||||
#### Scenario: Event contains diagnostics
|
||||
- **WHEN** a stage emits an event
|
||||
- **THEN** the event SHALL include the session id or turn id when available, stage name, event type, timestamp, and sanitized payload
|
||||
|
||||
#### Scenario: Sensitive payload is present
|
||||
- **WHEN** an event involves credentials, raw audio, memory content, or tool output
|
||||
- **THEN** the event payload SHALL omit secrets and SHALL truncate or summarize sensitive content according to security policy
|
||||
|
||||
### Requirement: Low-latency interruption and cancellation
|
||||
The full-duplex mode SHALL detect valid user speech during assistant playback and cancel the active response pipeline with a target interruption latency under 200 ms.
|
||||
|
||||
#### Scenario: User speaks while assistant is speaking
|
||||
- **WHEN** the assistant is playing TTS audio and APM-processed microphone audio contains valid user speech
|
||||
- **THEN** the interruption detector SHALL emit `interrupt_detected`, stop remaining playback, and cancel active LLM and TTS work
|
||||
|
||||
#### Scenario: Interruption latency is measured
|
||||
- **WHEN** a test fixture injects user speech during `speaking`
|
||||
- **THEN** the system SHALL record the latency from VAD speech start to playback stop and SHALL target P95 under 200 ms
|
||||
|
||||
#### Scenario: Echo does not interrupt
|
||||
- **WHEN** microphone input during playback is explained by assistant render reference echo after AEC
|
||||
- **THEN** the system SHALL NOT emit `interrupt_detected`
|
||||
|
||||
#### Scenario: Cancellation is idempotent
|
||||
- **WHEN** interruption or recovery triggers cancellation more than once
|
||||
- **THEN** LLM, TTS, playback, STT, and cancellable tool tasks SHALL handle repeated cancellation without unhandled exceptions
|
||||
|
||||
#### Scenario: Interrupted assistant text is stored
|
||||
- **WHEN** assistant playback is interrupted before the full response is spoken
|
||||
- **THEN** only assistant text that was fully spoken before interruption SHALL be eligible for short-term context or long-term memory
|
||||
|
||||
### Requirement: Streaming STT and realtime transcript
|
||||
The full-duplex mode SHALL use a streaming speech-to-text provider that emits partial, stable partial, and final transcripts while the user is speaking.
|
||||
|
||||
#### Scenario: Partial transcript is produced
|
||||
- **WHEN** the user is speaking and streaming STT emits a changed partial transcript
|
||||
- **THEN** the event bus SHALL emit a realtime transcript event for user-visible feedback
|
||||
|
||||
#### Scenario: Stable partial is produced
|
||||
- **WHEN** a partial transcript remains stable according to the configured stability filter
|
||||
- **THEN** the system SHALL mark it as stable partial while still withholding it from the LLM unless finalization rules allow submission
|
||||
|
||||
#### Scenario: Final transcript is produced
|
||||
- **WHEN** the current user utterance ends
|
||||
- **THEN** streaming STT SHALL emit a final transcript that becomes the user message candidate for conversation processing
|
||||
|
||||
#### Scenario: Empty transcript is produced
|
||||
- **WHEN** final STT returns empty text, punctuation-only text, or text below confidence thresholds
|
||||
- **THEN** the system SHALL discard the utterance, avoid invoking the LLM, and recover to listening
|
||||
|
||||
#### Scenario: Streaming STT provider changes
|
||||
- **WHEN** the configured provider changes from `faster_whisper` to `sensevoice` or `sherpa_onnx`
|
||||
- **THEN** the state machine and Conversation Manager SHALL keep the same transcript event contract
|
||||
|
||||
### Requirement: Streaming response and TTS playback
|
||||
The full-duplex mode SHALL stream LLM output into sentence segmentation, TTS synthesis, and playback without waiting for the full assistant reply to complete.
|
||||
|
||||
#### Scenario: First sentence is ready
|
||||
- **WHEN** the LLM stream produces a complete sentence or configured safe speech segment
|
||||
- **THEN** the sentence segmenter SHALL send sanitized text to the streaming TTS provider immediately
|
||||
|
||||
#### Scenario: TTS chunk is ready
|
||||
- **WHEN** the TTS provider produces the first playable PCM chunk
|
||||
- **THEN** playback SHALL begin without waiting for all remaining assistant text
|
||||
|
||||
#### Scenario: TTS text contains emoji
|
||||
- **WHEN** LLM output contains emoji, sticker markers, Markdown image syntax, or other non-speech content
|
||||
- **THEN** the text sent to TTS SHALL be sanitized before synthesis
|
||||
|
||||
#### Scenario: Playback is cancelled
|
||||
- **WHEN** cancellation is requested during response playback
|
||||
- **THEN** playback SHALL stop at the next configured audio chunk boundary and SHALL clear unplayed audio chunks
|
||||
|
||||
#### Scenario: TTS provider fails
|
||||
- **WHEN** streaming TTS fails before or during playback
|
||||
- **THEN** the system SHALL emit a structured TTS error and enter recovery without appending unspoken text to context
|
||||
|
||||
### Requirement: Conversation manager for agent turns
|
||||
The system SHALL define a Conversation Manager that coordinates short-term context, long-term memory retrieval, LLM streaming, tool calls, response playback, interruption, and recovery.
|
||||
|
||||
#### Scenario: User final transcript is accepted
|
||||
- **WHEN** a valid final transcript is produced
|
||||
- **THEN** the Conversation Manager SHALL create a user message candidate and gather short-term context and relevant long-term memory before invoking the LLM
|
||||
|
||||
#### Scenario: Assistant response completes
|
||||
- **WHEN** the assistant response is fully spoken and no tool call or interruption is pending
|
||||
- **THEN** the Conversation Manager SHALL commit the spoken assistant text to short-term context
|
||||
|
||||
#### Scenario: Response is interrupted
|
||||
- **WHEN** user speech interrupts the assistant response
|
||||
- **THEN** the Conversation Manager SHALL cancel the current response, preserve only committed spoken text, and process buffered user speech as the next input
|
||||
|
||||
#### Scenario: Conversation manager recovers
|
||||
- **WHEN** a provider error occurs
|
||||
- **THEN** the Conversation Manager SHALL emit a recoverable error event and return the agent to a safe listening or idle state when possible
|
||||
|
||||
### Requirement: Long-term memory with FAISS and SQLite
|
||||
The system SHALL define a long-term memory layer where SQLite stores text records and metadata while FAISS stores vector indexes for semantic retrieval.
|
||||
|
||||
#### Scenario: Memory is saved
|
||||
- **WHEN** the user explicitly asks the assistant to remember a non-sensitive preference, fact, project detail, or task summary
|
||||
- **THEN** the Memory Manager SHALL save a typed memory record with metadata in SQLite and an embedding vector in FAISS
|
||||
|
||||
#### Scenario: Memory is retrieved
|
||||
- **WHEN** a later user input is semantically related to stored memories
|
||||
- **THEN** the Memory Manager SHALL retrieve Top-K relevant memories and provide them to the Conversation Manager as separate memory context
|
||||
|
||||
#### Scenario: Runtime restarts
|
||||
- **WHEN** the assistant process restarts and memory is enabled
|
||||
- **THEN** saved non-sensitive memories SHALL remain available through SQLite and FAISS
|
||||
|
||||
#### Scenario: Memory is disabled
|
||||
- **WHEN** `OWNER_MEMORY_ENABLED=0`
|
||||
- **THEN** the system SHALL NOT read from or write to SQLite or FAISS memory storage
|
||||
|
||||
#### Scenario: Sensitive content is detected
|
||||
- **WHEN** a memory candidate contains credentials, payment data, private identifiers, account secrets, or other sensitive content
|
||||
- **THEN** the system SHALL NOT automatically save it and SHALL require explicit user confirmation or reject the save
|
||||
|
||||
#### Scenario: Memory index is inconsistent
|
||||
- **WHEN** SQLite metadata and FAISS index records are missing, mismatched, or fail checksum validation
|
||||
- **THEN** the Memory Manager SHALL report a health error and SHALL NOT return unverified memory records
|
||||
|
||||
### Requirement: Tool Router and structured tool execution
|
||||
The system SHALL define a Tool Router that validates structured tool calls, applies security policy, routes approved tools, enforces execution limits, and returns sanitized tool results to the LLM.
|
||||
|
||||
#### Scenario: Allowed memory search runs
|
||||
- **WHEN** the LLM requests `memory.search` with valid arguments
|
||||
- **THEN** the Tool Router SHALL execute the memory search within configured limits and return sanitized results
|
||||
|
||||
#### Scenario: Tool schema is invalid
|
||||
- **WHEN** a tool call has an unknown name, missing required argument, invalid type, or unknown field
|
||||
- **THEN** the Tool Router SHALL reject it with a structured validation error
|
||||
|
||||
#### Scenario: Tool exceeds call budget
|
||||
- **WHEN** a turn exceeds the configured maximum number of tool calls or total tool runtime
|
||||
- **THEN** the Tool Router SHALL reject further tool calls for that turn and return a budget error
|
||||
|
||||
#### Scenario: Tool output is too long
|
||||
- **WHEN** a tool returns output larger than the configured limit
|
||||
- **THEN** the Tool Router SHALL truncate the output, mark it as truncated, and avoid sending full oversized content to the LLM
|
||||
|
||||
#### Scenario: Tool execution fails
|
||||
- **WHEN** an approved tool raises an error or times out
|
||||
- **THEN** the Tool Router SHALL return a structured tool error and the Conversation Manager SHALL recover or ask the user for next steps
|
||||
|
||||
### Requirement: Safe first-version tools
|
||||
The first full-duplex Agent tool set SHALL prioritize low-risk tools and SHALL include only `memory.search`, `memory.save`, `shell.readonly`, `openinterpreter.run`, and `browser.playwright` as planned first-version adapters.
|
||||
|
||||
#### Scenario: Read-only shell command is allowed
|
||||
- **WHEN** `shell.readonly` receives an allowlisted read-only command within allowed directories
|
||||
- **THEN** the tool SHALL execute with timeout and output truncation
|
||||
|
||||
#### Scenario: Write shell command is rejected
|
||||
- **WHEN** `shell.readonly` receives a command that writes, deletes, installs dependencies, changes permissions, uploads data, or mutates external state
|
||||
- **THEN** the Tool Router SHALL reject the command
|
||||
|
||||
#### Scenario: Memory save is requested
|
||||
- **WHEN** `memory.save` is requested for a non-sensitive user-approved memory
|
||||
- **THEN** the tool SHALL save through the Memory Manager and return the new memory id
|
||||
|
||||
#### Scenario: High-risk action is requested
|
||||
- **WHEN** any planned first-version tool request involves deletion, upload, payment, trading, account changes, permission changes, secret access, or arbitrary code execution
|
||||
- **THEN** the Tool Router SHALL reject it or require explicit confirmation according to policy
|
||||
|
||||
### Requirement: Open Interpreter external adapter
|
||||
The system SHALL treat Open Interpreter as an optional external CLI or subprocess backend and SHALL NOT copy the local `openinterpreter/` clone into the Owner source tree.
|
||||
|
||||
#### Scenario: Open Interpreter is disabled
|
||||
- **WHEN** `OWNER_OPENINTERPRETER_ENABLED=0`
|
||||
- **THEN** the Tool Router SHALL mark `openinterpreter.run` unavailable and SHALL NOT invoke any Open Interpreter command
|
||||
|
||||
#### Scenario: Open Interpreter path is missing
|
||||
- **WHEN** `OWNER_OPENINTERPRETER_ENABLED=1` but the configured command cannot be found
|
||||
- **THEN** the adapter SHALL return `OPENINTERPRETER_UNAVAILABLE` without affecting other tools
|
||||
|
||||
#### Scenario: Low-risk Open Interpreter task is approved
|
||||
- **WHEN** a low-risk Open Interpreter task passes directory, timeout, and argument validation
|
||||
- **THEN** the adapter SHALL run it as an external process with bounded runtime and sanitized output
|
||||
|
||||
#### Scenario: High-risk Open Interpreter task is requested
|
||||
- **WHEN** an Open Interpreter task would write files, delete data, change accounts, install dependencies, upload data, or execute broad arbitrary code
|
||||
- **THEN** the Tool Router SHALL require explicit confirmation or reject the task in first-version policy
|
||||
|
||||
### Requirement: Browser automation boundary
|
||||
The system SHALL define `browser.playwright` as a planned browser automation adapter with explicit safety boundaries.
|
||||
|
||||
#### Scenario: Safe browser read task is requested
|
||||
- **WHEN** the user asks for a low-risk browser read or extraction task and Playwright is enabled
|
||||
- **THEN** the adapter SHALL run in an approved browser context with timeout, navigation limits, and sanitized output
|
||||
|
||||
#### Scenario: Sensitive browser action is requested
|
||||
- **WHEN** a browser task involves login, payment, purchase, form submission, account changes, private messages, uploads, or irreversible actions
|
||||
- **THEN** the adapter SHALL require explicit confirmation or reject the task according to policy
|
||||
|
||||
#### Scenario: Playwright is unavailable
|
||||
- **WHEN** Playwright or its browser runtime is not installed
|
||||
- **THEN** `browser.playwright` SHALL report a structured unavailable error and SHALL NOT affect voice conversation
|
||||
|
||||
### Requirement: Computer control reservation
|
||||
The system SHALL reserve a future `ComputerControlProvider` boundary for GUI control while excluding GUI click, keyboard, screen, and Accessibility automation from the first full-duplex Agent implementation.
|
||||
|
||||
#### Scenario: GUI control is requested in first version
|
||||
- **WHEN** a tool call requests direct GUI click, keyboard input, screen control, or Accessibility automation
|
||||
- **THEN** the first-version Tool Router SHALL reject it as unsupported
|
||||
|
||||
#### Scenario: Future provider is designed
|
||||
- **WHEN** a future change implements computer control
|
||||
- **THEN** it SHALL use public capabilities such as macOS Accessibility, Playwright, or trycua-style providers and SHALL define separate confirmation and audit requirements
|
||||
|
||||
#### Scenario: Codex Computer Use is referenced
|
||||
- **WHEN** design work references Codex Computer Use behavior
|
||||
- **THEN** the system SHALL use it only as a safety policy reference and SHALL NOT copy private or bundled implementation details
|
||||
|
||||
### Requirement: Agent security and privacy
|
||||
The full-duplex Agent architecture SHALL protect credentials, raw audio, memory data, and tool execution boundaries by default.
|
||||
|
||||
#### Scenario: Credentials are configured
|
||||
- **WHEN** LLM, embedding, tool, or external adapter credentials are needed
|
||||
- **THEN** they SHALL be read from local uncommitted configuration and SHALL NOT be hard-coded or logged
|
||||
|
||||
#### Scenario: Raw audio is processed
|
||||
- **WHEN** microphone or render audio is processed for APM, VAD, STT, or interruption
|
||||
- **THEN** raw audio and derived voice features SHALL remain process-local unless the user explicitly enables a documented recording feature
|
||||
|
||||
#### Scenario: Long-term memory stores text
|
||||
- **WHEN** memory is saved
|
||||
- **THEN** the memory record SHALL include sensitivity metadata and SHALL NOT include raw audio or credentials
|
||||
|
||||
#### Scenario: Tool audit is recorded
|
||||
- **WHEN** a tool executes
|
||||
- **THEN** the audit record SHALL include tool name, risk level, confirmation status, duration, status, and sanitized summary without secrets
|
||||
|
||||
#### Scenario: User disables tools
|
||||
- **WHEN** `OWNER_TOOL_ROUTER_ENABLED=0`
|
||||
- **THEN** no tool calls SHALL execute and LLM tool requests SHALL be rejected or ignored with a structured message
|
||||
|
||||
### Requirement: Full-duplex performance targets
|
||||
The full-duplex Agent architecture SHALL define measurable latency and reliability targets for audio processing, interruption, streaming STT, LLM-to-TTS, and tool routing.
|
||||
|
||||
#### Scenario: Audio frame is processed
|
||||
- **WHEN** WebRTC APM receives a normal 20 ms frame
|
||||
- **THEN** processing SHALL target completion before the next frame interval in normal local runtime conditions
|
||||
|
||||
#### Scenario: User begins speaking during playback
|
||||
- **WHEN** valid user speech begins while assistant speech is playing
|
||||
- **THEN** playback stop SHALL target P95 latency under 200 ms from speech start
|
||||
|
||||
#### Scenario: User starts speaking in listening mode
|
||||
- **WHEN** the user begins speaking while the system is listening
|
||||
- **THEN** streaming STT SHALL target first stable user-visible transcript within 800 ms P95
|
||||
|
||||
#### Scenario: LLM produces first sentence
|
||||
- **WHEN** the LLM stream yields a complete sentence
|
||||
- **THEN** TTS SHALL target first playable audio chunk within 1000 ms P95
|
||||
|
||||
#### Scenario: Tool call runs
|
||||
- **WHEN** an approved low-risk tool runs
|
||||
- **THEN** it SHALL obey configured timeout, output limit, and maximum calls per turn
|
||||
|
||||
### Requirement: Full-duplex testability
|
||||
The full-duplex Agent architecture SHALL be testable with fake audio devices, fake WebRTC APM reference audio, fake VAD, fake streaming STT/TTS, fake memory stores, fake tools, and deterministic virtual time.
|
||||
|
||||
#### Scenario: Fake APM suppresses echo
|
||||
- **WHEN** a test injects playback reference audio and matching microphone echo
|
||||
- **THEN** the fake or real APM test SHALL verify that echo does not trigger user transcript or interruption
|
||||
|
||||
#### Scenario: Speaking interruption is tested
|
||||
- **WHEN** a test injects user speech during assistant playback
|
||||
- **THEN** the state sequence SHALL include `speaking -> interrupted -> listening` and active LLM/TTS/playback tasks SHALL be cancelled
|
||||
|
||||
#### Scenario: Streaming STT and TTS are tested
|
||||
- **WHEN** fake providers emit partial transcripts, final transcript, LLM deltas, sentence segments, and TTS chunks
|
||||
- **THEN** tests SHALL verify event order, context writes, and playback order
|
||||
|
||||
#### Scenario: Memory persists across restart
|
||||
- **WHEN** a memory is saved and a new runtime instance starts with memory enabled
|
||||
- **THEN** the memory SHALL be retrievable from SQLite and FAISS
|
||||
|
||||
#### Scenario: Tools are tested
|
||||
- **WHEN** fake tool calls cover allowed, rejected, confirmation-required, timeout, and oversized output paths
|
||||
- **THEN** Tool Router tests SHALL verify decisions, audit events, and sanitized tool results
|
||||
|
||||
#### Scenario: OpenSpec validation runs
|
||||
- **WHEN** this planning change is complete
|
||||
- **THEN** `openspec validate add-full-duplex-agent-voice-assistant --strict` and `openspec validate --all --strict` SHALL pass
|
||||
@@ -0,0 +1,102 @@
|
||||
## 1. OpenSpec 与项目边界
|
||||
|
||||
- [ ] 1.1 冻结 full-duplex Agent 实施入口命名;前置条件:人工确认 `run-agent-live` 或 `run-live --mode full-duplex`;优先级:P0;验收标准:README 和配置说明使用同一入口名;测试要点:CLI help 中能看到一致入口。
|
||||
- [ ] 1.2 增加全双工模式配置读取规划;前置条件:入口命名已确认;优先级:P0;验收标准:配置包含 `OWNER_ASSISTANT_MODE`、APM、VAD、STT、TTS、memory、tool router 开关;测试要点:无效 provider 触发配置错误。
|
||||
- [ ] 1.3 规划依赖分组;前置条件:provider 候选已确认;优先级:P0;验收标准:依赖按 audio、stt、tts、memory、tools 分组且默认不强制安装重依赖;测试要点:最小安装仍可跑现有 turn-based 测试。
|
||||
- [ ] 1.4 定义迁移兼容策略;前置条件:现有 `run-live` 行为梳理完成;优先级:P0;验收标准:turn-based 路径在全双工开发期保持可用;测试要点:旧 simulate-live 和 run-live 回归不破坏。
|
||||
- [ ] 1.5 建立模块提交门禁;前置条件:本变更 OpenSpec 已合并;优先级:P0;验收标准:每个主要任务组完成后验证并中文 commit;测试要点:`git status --short` 不包含未提交中间状态。
|
||||
|
||||
## 2. WebRTC APM 与音频环形缓冲
|
||||
|
||||
- [ ] 2.1 设计 `AudioFrame` 数据结构;前置条件:内部采样率和帧长方案已确认;优先级:P0;验收标准:包含 samples、sample_rate、channels、timestamp、frame_id;测试要点:frame serialization fake fixture 可稳定回放。
|
||||
- [ ] 2.2 实现 capture ring buffer;前置条件:`AudioFrame` 已定义;优先级:P0;验收标准:固定容量、线程安全、溢出事件可观测;测试要点:超过容量时丢弃旧帧并发 `audio_buffer_overrun`。
|
||||
- [ ] 2.3 实现 render reference ring buffer;前置条件:playback frame 格式已定义;优先级:P0;验收标准:播放 PCM 写入 reference,保留时间戳;测试要点:可按 capture timestamp 取 reference window。
|
||||
- [ ] 2.4 定义 `AudioProcessingProvider` 接口;前置条件:ring buffer 已完成;优先级:P0;验收标准:支持 process_capture、process_render、reset、health_check;测试要点:fake APM 可替换真实 provider。
|
||||
- [ ] 2.5 实现 fake WebRTC APM provider;前置条件:接口已定义;优先级:P0;验收标准:测试中可模拟 echo suppression、format mismatch、processing failure;测试要点:纯回声不触发 VAD/STT。
|
||||
- [ ] 2.6 接入真实 WebRTC APM 探针;前置条件:依赖选择已人工确认;优先级:P1;验收标准:macOS 本地能初始化 AEC/NS/AGC 或返回明确不可用;测试要点:`model-check` 或 `audio-check` 报告 provider 状态。
|
||||
- [ ] 2.7 增加 APM fallback 策略;前置条件:fake/真实 provider 接口完成;优先级:P1;验收标准:`OWNER_AUDIO_APM_REQUIRED` 控制失败即退或带标记降级;测试要点:APM 不可用时不进入假全双工。
|
||||
|
||||
## 3. 全双工状态机、事件总线与取消机制
|
||||
|
||||
- [ ] 3.1 定义 full-duplex 状态枚举;前置条件:spec 状态机确认;优先级:P0;验收标准:包含 idle、listening、thinking、speaking、interrupted、tool_running、recovering;测试要点:非法状态转移被拒绝。
|
||||
- [ ] 3.2 实现状态机转移表;前置条件:状态枚举完成;优先级:P0;验收标准:每个事件对应合法 next state;测试要点:覆盖正常、打断、工具、错误恢复路径。
|
||||
- [ ] 3.3 扩展 pipeline event bus;前置条件:现有 event bus 梳理完成;优先级:P0;验收标准:事件包含 session/turn id、stage、timestamp、sanitized payload;测试要点:终端 reporter 只消费事件。
|
||||
- [ ] 3.4 实现 cancellation token;前置条件:状态机完成;优先级:P0;验收标准:root token 和 child token 支持幂等 cancel;测试要点:多次 cancel 不抛异常。
|
||||
- [ ] 3.5 建立 cancellation graph;前置条件:LLM/TTS/playback/tool task 边界已定义;优先级:P0;验收标准:打断时同时取消 LLM、TTS、playback 和可取消工具;测试要点:取消后无后台线程泄漏。
|
||||
- [ ] 3.6 实现 recovery coordinator;前置条件:错误码清单已定义;优先级:P1;验收标准:可恢复错误进入 recovering 后回 listening 或 idle;测试要点:STT/TTS/LLM/tool 错误均能恢复。
|
||||
|
||||
## 4. VAD、Streaming STT 与低延迟打断
|
||||
|
||||
- [ ] 4.1 定义 `VadProvider` 接口;前置条件:APM 输出 frame 格式完成;优先级:P0;验收标准:支持 speech_start、speech_end、confidence;测试要点:fake VAD 可注入人声起止。
|
||||
- [ ] 4.2 规划 Silero VAD adapter;前置条件:依赖策略确认;优先级:P1;验收标准:本地模型路径、采样率和阈值可配置;测试要点:模型缺失返回结构化错误。
|
||||
- [ ] 4.3 定义 `StreamingSttProvider` 接口;前置条件:transcript event contract 确认;优先级:P0;验收标准:支持 start_session、accept_audio、finish、cancel;测试要点:partial/stable/final 事件顺序稳定。
|
||||
- [ ] 4.4 实现 fake Streaming STT;前置条件:接口完成;优先级:P0;验收标准:可模拟 partial 抖动、final 空文本、provider 失败;测试要点:partial 不进入 LLM。
|
||||
- [ ] 4.5 规划 faster-whisper adapter;前置条件:模型和依赖策略确认;优先级:P1;验收标准:开发 provider 可配置模型、设备、语言;测试要点:fixture 音频产生 final transcript。
|
||||
- [ ] 4.6 规划 SenseVoice adapter;前置条件:产品候选确认;优先级:P2;验收标准:接口兼容 Streaming STT contract;测试要点:中文 fixture 输出与 faster-whisper contract 一致。
|
||||
- [ ] 4.7 实现 interruption detector;前置条件:APM、VAD、event bus 完成;优先级:P0;验收标准:speaking 中有效用户声触发 `interrupt_detected`;测试要点:纯助手 echo 不触发。
|
||||
- [ ] 4.8 增加 200 ms 打断延迟指标;前置条件:interruption detector 完成;优先级:P0;验收标准:事件记录 speech_start 到 playback_stop latency;测试要点:虚拟时钟 fixture 断言 P95 目标。
|
||||
|
||||
## 5. LLM 流、句子切分、Streaming TTS 与播放
|
||||
|
||||
- [ ] 5.1 定义 LLM streaming adapter contract;前置条件:现有 LLM provider 梳理完成;优先级:P0;验收标准:支持 delta、tool_call、finish、cancel、error;测试要点:取消时连接关闭或停止消费。
|
||||
- [ ] 5.2 实现 sentence segmenter;前置条件:LLM delta contract 完成;优先级:P0;验收标准:中文标点、英文标点、最大等待阈值可切句;测试要点:URL、小数、代码块不误切。
|
||||
- [ ] 5.3 复用 TTS 文本净化;前置条件:现有 sanitizer 可调用;优先级:P0;验收标准:emoji、表情包、Markdown 图片不送 TTS;测试要点:纯表情回复不触发语音。
|
||||
- [ ] 5.4 定义 `StreamingTtsProvider` 接口;前置条件:播放 PCM 格式确认;优先级:P0;验收标准:支持 accept_text、flush、cancel、chunk events;测试要点:fake TTS 逐 chunk 输出。
|
||||
- [ ] 5.5 规划 CosyVoice adapter;前置条件:产品 TTS 方案确认;优先级:P1;验收标准:可配置 voice、sample_rate、chunk size;测试要点:provider 缺失结构化失败。
|
||||
- [ ] 5.6 实现可中断 playback queue;前置条件:render ring buffer 完成;优先级:P0;验收标准:chunk 播放同时写 reference,取消后清空未播 chunk;测试要点:播放停止边界小于配置 chunk。
|
||||
- [ ] 5.7 记录已播文本边界;前置条件:sentence/TTS/playback 完成;优先级:P0;验收标准:只提交完整播出的 assistant 文本;测试要点:中途打断未播文本不进上下文。
|
||||
|
||||
## 6. Conversation Manager 与长期记忆
|
||||
|
||||
- [ ] 6.1 定义 Conversation Manager 接口;前置条件:状态机和 LLM contract 完成;优先级:P0;验收标准:协调 transcript、context、memory、LLM、tool、TTS;测试要点:正常问答流事件顺序稳定。
|
||||
- [ ] 6.2 保留短期会话上下文;前置条件:现有 ConversationContext 梳理完成;优先级:P0;验收标准:进程内历史继续支持截断;测试要点:新 runtime 不读取旧短期历史。
|
||||
- [ ] 6.3 设计 SQLite memory schema;前置条件:记忆类型确认;优先级:P0;验收标准:包含 type、text、metadata、sensitivity、source_turn_id、checksum;测试要点:迁移创建表成功。
|
||||
- [ ] 6.4 设计 FAISS index 管理;前置条件:embedding provider 策略确认;优先级:P1;验收标准:index 版本、embedding model 和 record id 可一致性检查;测试要点:SQLite/FAISS 不一致时报 health error。
|
||||
- [ ] 6.5 实现 fake MemoryManager;前置条件:接口完成;优先级:P0;验收标准:支持 search/save/delete/health_check;测试要点:关闭 memory 时不读写。
|
||||
- [ ] 6.6 实现记忆召回链路;前置条件:fake MemoryManager 完成;优先级:P0;验收标准:final transcript 前检索 Top-K 并注入独立 memory context;测试要点:相关偏好可召回。
|
||||
- [ ] 6.7 实现记忆写入安全策略;前置条件:sensitivity 分类规则确认;优先级:P0;验收标准:敏感内容默认不自动保存;测试要点:API key、支付信息、账号信息被拒绝或确认。
|
||||
- [ ] 6.8 增加记忆管理命令规划;前置条件:schema 和安全策略完成;优先级:P2;验收标准:列出、删除、禁用、导出策略明确;测试要点:删除后检索不到。
|
||||
|
||||
## 7. Tool Router 与安全工具
|
||||
|
||||
- [ ] 7.1 定义 ToolCallRequest schema;前置条件:LLM tool call contract 完成;优先级:P0;验收标准:包含 name、arguments、timeout、turn id、intent;测试要点:未知字段拒绝。
|
||||
- [ ] 7.2 定义 ToolDecision 和 ToolResult;前置条件:ToolCallRequest 完成;优先级:P0;验收标准:支持 execute、reject、require_confirmation、cancelled;测试要点:结果脱敏和截断。
|
||||
- [ ] 7.3 实现 Tool Router fake core;前置条件:schema 完成;优先级:P0;验收标准:按工具名路由 fake adapters;测试要点:合法、非法、超时、超预算均覆盖。
|
||||
- [ ] 7.4 实现工具风险分类规则;前置条件:安全策略确认;优先级:P0;验收标准:低/中/高/禁止风险可解释;测试要点:删除、上传、账号、交易、安装依赖触发高风险或禁止。
|
||||
- [ ] 7.5 规划 `memory.search` 和 `memory.save`;前置条件:MemoryManager fake 完成;优先级:P0;验收标准:search 只读,save 走敏感策略;测试要点:敏感 save 需要确认或拒绝。
|
||||
- [ ] 7.6 规划 `shell.readonly` adapter;前置条件:allowlist 策略确认;优先级:P0;验收标准:只允许只读命令和受限目录;测试要点:写文件、删除、chmod、pip install 被拒绝。
|
||||
- [ ] 7.7 增加工具预算和防循环;前置条件:Tool Router core 完成;优先级:P0;验收标准:单轮最大调用数、总耗时、重复调用检测生效;测试要点:循环工具调用被截断。
|
||||
- [ ] 7.8 增加工具审计日志规划;前置条件:安全字段确认;优先级:P1;验收标准:记录工具名、风险、确认、耗时、状态、脱敏摘要;测试要点:日志不包含密钥和完整敏感输出。
|
||||
|
||||
## 8. Open Interpreter、Playwright 与电脑控制边界
|
||||
|
||||
- [ ] 8.1 规划 Open Interpreter adapter 配置;前置条件:本地 CLI 路径策略确认;优先级:P1;验收标准:`OWNER_OPENINTERPRETER_ENABLED` 默认关闭,命令路径可配置;测试要点:路径缺失返回 unavailable。
|
||||
- [ ] 8.2 实现 Open Interpreter 受限执行设计;前置条件:Tool Router 风险策略完成;优先级:P1;验收标准:受限目录、超时、输出截断、确认策略明确;测试要点:高风险任务拒绝或确认。
|
||||
- [ ] 8.3 明确 `openinterpreter/` 仓库边界;前置条件:git status 检查完成;优先级:P0;验收标准:Owner 不复制、不 vendoring、不提交该目录;测试要点:提交 diff 不包含 `openinterpreter/`。
|
||||
- [ ] 8.4 规划 Playwright adapter;前置条件:浏览器安全策略确认;优先级:P1;验收标准:默认关闭,低风险读取可用,敏感流程确认或拒绝;测试要点:登录、支付、提交表单触发确认策略。
|
||||
- [ ] 8.5 规划 browser context 隔离;前置条件:用户是否允许登录态待澄清;优先级:P2;验收标准:默认独立 context,不默认复用用户 Chrome 登录态;测试要点:配置关闭时工具不可用。
|
||||
- [ ] 8.6 预留 ComputerControlProvider;前置条件:GUI 控制方案未进入第一版;优先级:P2;验收标准:直接 GUI 点击、键盘、屏幕控制在第一版拒绝;测试要点:相关 tool call 返回 unsupported。
|
||||
- [ ] 8.7 编写 Codex Computer Use 安全参考说明;前置条件:公共实现边界确认;优先级:P2;验收标准:只参考确认策略,不复制私有实现;测试要点:文档无私有 API 或实现细节。
|
||||
|
||||
## 9. 端到端模拟、性能与安全验证
|
||||
|
||||
- [ ] 9.1 构建 fake full-duplex audio fixture;前置条件:AudioFrame 和 ring buffer 完成;优先级:P0;验收标准:可注入用户语音、助手回声、噪声、打断;测试要点:fixture 可重复回放。
|
||||
- [ ] 9.2 增加 fake APM echo 测试;前置条件:fake APM 和 fixture 完成;优先级:P0;验收标准:助手回声不触发 VAD/STT/interrupt;测试要点:无用户语音时无 transcript。
|
||||
- [ ] 9.3 增加 speaking interruption 测试;前置条件:状态机、playback、interruption 完成;优先级:P0;验收标准:`speaking -> interrupted -> listening`;测试要点:LLM/TTS/playback 均取消。
|
||||
- [ ] 9.4 增加 Streaming STT/TTS 顺序测试;前置条件:fake providers 完成;优先级:P0;验收标准:partial、final、LLM delta、sentence、TTS chunk、playback 顺序稳定;测试要点:partial 不写上下文。
|
||||
- [ ] 9.5 增加 memory restart 测试;前置条件:SQLite/FAISS fake 或真实实现完成;优先级:P1;验收标准:保存后新 runtime 可召回;测试要点:禁用 memory 时不读写。
|
||||
- [ ] 9.6 增加 Tool Router 安全测试;前置条件:Tool Router core 完成;优先级:P0;验收标准:允许、拒绝、确认、超时、截断、防循环均覆盖;测试要点:高风险操作不自动执行。
|
||||
- [ ] 9.7 增加性能指标采集;前置条件:event bus latency 字段完成;优先级:P1;验收标准:记录 APM frame、STT first partial、interrupt latency、TTS first chunk、tool runtime;测试要点:指标不含敏感数据。
|
||||
- [ ] 9.8 增加安全检查扩展;前置条件:memory/tool/audit 字段完成;优先级:P1;验收标准:检查 `.env`、key、raw audio、memory secrets、tool logs;测试要点:伪 secret 不出现在日志和事件。
|
||||
|
||||
## 10. 文档、验收与模块提交
|
||||
|
||||
- [ ] 10.1 更新 README 全双工架构说明;前置条件:入口和配置确认;优先级:P1;验收标准:说明 APM、Streaming STT/TTS、记忆、工具、限制;测试要点:命令示例和默认关闭项准确。
|
||||
- [ ] 10.2 更新 `.env.example` 规划变量;前置条件:配置清单冻结;优先级:P1;验收标准:新增全双工、APM、memory、tool、adapter 配置;测试要点:默认值不启用高风险工具。
|
||||
- [ ] 10.3 编写模型和依赖准备说明;前置条件:provider 候选确认;优先级:P1;验收标准:区分开发默认和产品候选;测试要点:不承诺未验证模型已可用。
|
||||
- [ ] 10.4 编写安全确认策略文档;前置条件:Tool Router 风险规则完成;优先级:P0;验收标准:列明自动允许、需要确认、默认拒绝类别;测试要点:与工具测试用例一致。
|
||||
- [ ] 10.5 执行 Python 编译验证;前置条件:实现代码变更完成;优先级:P0;验收标准:`.venv/bin/python -m compileall src tests scripts` 通过;测试要点:无语法错误。
|
||||
- [ ] 10.6 执行单元测试验证;前置条件:测试实现完成;优先级:P0;验收标准:`.venv/bin/python -m unittest discover -s tests` 通过;测试要点:覆盖 full-duplex、memory、tool、security。
|
||||
- [ ] 10.7 执行安全和模型检查;前置条件:相关命令实现完成;优先级:P0;验收标准:security-check、model-check、device-check 按阶段通过或给出明确跳过理由;测试要点:不泄露密钥。
|
||||
- [ ] 10.8 执行 OpenSpec 校验;前置条件:docs 和 spec 更新完成;优先级:P0;验收标准:`openspec validate add-full-duplex-agent-voice-assistant --strict` 与 `openspec validate --all --strict` 通过;测试要点:无 spec 格式错误。
|
||||
- [ ] 10.9 按模块提交;前置条件:对应模块验证通过;优先级:P0;验收标准:提交信息符合 `[模块名]:完成[具体功能描述],包含[关键变更]`;测试要点:`git status --short` 不含本模块未提交改动。
|
||||
Reference in New Issue
Block a user