Repository navigation
Closed
Labels
P2Medium priorityMedium priorityarea:agentAgent areaAgent areaarea:voiceVoice areaVoice areaenhancementNew feature or requestNew feature or requestneeds-designNeeds design discussionNeeds design discussion
Description
背景
OpenLess 当前已经支持热键录音、ASR、LLM 润色、文本插入、Selection Ask QA 面板。希望在此基础上新增一个“语音调用代码 Agent”的独立能力:
- 用户触发专用快捷键后,OpenLess 开始录音。
- 再次触发快捷键后结束录音,ASR 得到文本。
- 系统可按配置先用“语音润色大语言模型”整理语音转写内容。
- 后端把最终文本发送给 Claude Code 或开源 OpenCode Agent。
- Agent 输出结果流式返回前端面板展示。
当前 OpenLess README 中说明产品主要负责文本整理,不负责回答问题、执行任务或分析项目。本功能会扩展为独立的 coding-agent 模式,应保持和普通听写、翻译、Selection Ask QA 分离,避免改变现有默认听写行为。
目标
新增一个独立功能:Voice Coding Agent。
默认行为:
- 默认关闭,需要用户在设置页开启。
- 使用独立快捷键,默认建议:
- Windows/Linux:
Ctrl+Shift+Enter - macOS:
Cmd+Shift+Enter
- Windows/Linux:
- 第一次按下开始录音。
- 第二次按下停止录音并进入 ASR。
- ASR 结果可先经过语音润色模型整理。
- 整理后的指令发送给 configured coding agent。
- 前端显示:
- 原始 ASR 文本
- 润色后的指令
- Agent 当前状态
- 流式输出
- 错误、超时、取消状态
- 默认不自动插入文本到当前光标位置。
- 默认不允许 Agent 修改本地文件;权限模式默认为只读/计划模式。
- 用户可在高级设置中切换为更强权限模式。
非目标
- 不改变普通听写热键行为。
- 不改变 Selection Ask QA 的现有交互。
- 不把 Claude Code 输出默认插入到其他应用。
- 不默认启用
bypassPermissions。 - 不把 API key、access token、命令输出中的敏感字段写入前端事件、日志或历史记录。
调研结论
- OpenLess 当前主处理路径已经具备热键录音、ASR、LLM 润色、历史保存、QA 面板流式回答能力,可复用大部分基础设施。
- 现有 Selection Ask QA 功能最接近目标:
qa_hotkey负责打开面板,主听写热键在面板可见时开始/结束 QA 录音,后端用 ASR 得到文本,再调用当前 LLM provider,前端通过qa:state接收流式回答。 - 当前
UserPreferences已有active_llm_provider、llm_thinking_enabled、qa_hotkey等字段;凭据通过 OS vault 保存,LLM provider 支持 Ark、OpenAI-compatible、Gemini、Codex OAuth、custom 等。 - 官方 Claude Code 可通过 CLI 和 SDK 集成,关键参数包括
claude -p/--print、--output-format text|json|stream-json、--model、--fallback-model、--permission-mode、--allowedTools、--disallowedTools、--mcp-config。 - 官方 Claude Code 未定位为可 fork 的开源实现;开源优先方案应增加
opencode适配器。OpenCode 是开源终端 coding agent,适合做二次开发优先落点,同时保留官方claude-code-cli适配器满足 Claude Code 用户。 - 相关 Issue 不构成重复:[insertion] 新增送出前文字處理 Hook #575 是“送出前文字处理 Hook”,[area] 无法现在大模型,也不知道哪个处于启用状态 #578 是模型选择状态问题;本需求是独立的语音触发代码 Agent 功能,但需要兼容 [insertion] 新增送出前文字處理 Hook #575 的文本处理扩展思路。
参考资料:
- Claude Code overview
- Claude Code CLI reference
- Claude Code SDK
- Claude Code MCP
- Claude Code hooks
- OpenCode official site
- OpenCode GitHub
Claude Code / OpenCode 集成策略
Provider 抽象
新增后端 trait:
#[async_trait]
pub trait CodingAgentProvider: Send + Sync {
async fn run(
&self,
request: CodingAgentRequest,
sink: CodingAgentEventSink,
cancel: CancellationToken,
) -> Result<CodingAgentResult, CodingAgentError>;
}核心类型:
pub struct CodingAgentRequest {
pub session_id: String,
pub prompt: String,
pub raw_transcript: String,
pub polished_prompt: Option<String>,
pub cwd: PathBuf,
pub model: Option<String>,
pub fallback_model: Option<String>,
pub permission_mode: CodingAgentPermissionMode,
pub allowed_tools: Vec<String>,
pub disallowed_tools: Vec<String>,
pub timeout_secs: u64,
pub extra_system_prompt: Option<String>,
}
pub enum CodingAgentEvent {
Started { session_id: String },
TranscriptReady { text: String },
PromptReady { text: String },
Delta { text: String },
ToolEvent { name: String, status: String },
Completed { text: String },
Cancelled,
Error { message: String },
}Provider IDs:
claude-code-cliopencode-cli- 预留:
claude-code-sdk
Claude Code CLI 适配器
新增 ClaudeCodeCliProvider:
- 默认可执行文件:
claude - 支持用户配置可执行文件路径。
- 使用非交互 print 模式:
claude -p--output-format stream-json--model <model>--fallback-model <fallback_model>--permission-mode <mode>--add-dir <cwd>如用户配置了额外目录--mcp-config <path>如用户配置 MCP--append-system-prompt <prompt>如配置了额外系统提示词
- stdin 写入最终 prompt。
- stdout 按行解析 stream-json。
- stderr 独立收集,只在错误状态中返回摘要。
- timeout 到期后 kill 子进程并发送
agent:error。 - 用户取消时 kill 子进程并发送
agent:cancelled。 - 子进程退出码非 0 时返回
CodingAgentError::ProcessExit。
默认权限:
permission_mode = CodingAgentPermissionMode::Plan
timeout_secs = 300
allowed_tools = []
disallowed_tools = []高级权限选项:
plandefaultacceptEditsbypassPermissions
UI 中 bypassPermissions 必须放在高级区,附带明确风险文案,不能作为默认值。
OpenCode 适配器
新增 OpenCodeCliProvider:
- provider id:
opencode-cli - 作为开源优先落点。
- 默认可执行文件:
opencode - 先实现同一
CodingAgentProvidertrait。 - 命令参数由适配器内部封装,保持前端配置和 Claude Code 适配器一致:
cwdmodelpermission_modetimeout_secsextra_system_prompt
- 若当前 OpenCode CLI 版本缺少稳定的非交互 stream 输出协议,先以实验 provider 暴露,并在 UI 中显示“experimental”。
后端实现
Preferences
在 UserPreferences 增加字段:
pub coding_agent_enabled: bool,
pub coding_agent_hotkey: Option<ShortcutBinding>,
pub coding_agent_provider: CodingAgentProviderId,
pub coding_agent_workdir: Option<String>,
pub coding_agent_permission_mode: CodingAgentPermissionMode,
pub coding_agent_model: Option<String>,
pub coding_agent_fallback_model: Option<String>,
pub coding_agent_timeout_secs: u64,
pub coding_agent_show_panel_on_start: bool,
pub coding_agent_save_history: bool,
pub coding_agent_use_voice_polish: bool,
pub voice_polish_model_mode: VoicePolishModelMode,
pub voice_polish_provider_id: Option<String>,
pub voice_polish_thinking_enabled: bool,默认值:
coding_agent_enabled = false
coding_agent_hotkey = CtrlOrCmd + Shift + Enter
coding_agent_provider = "claude-code-cli"
coding_agent_workdir = None
coding_agent_permission_mode = Plan
coding_agent_timeout_secs = 300
coding_agent_show_panel_on_start = true
coding_agent_save_history = true
coding_agent_use_voice_polish = true
voice_polish_model_mode = SystemDefault
voice_polish_provider_id = None
voice_polish_thinking_enabled = false新增 enum:
pub enum VoicePolishModelMode {
SystemDefault,
CustomProvider,
}
pub enum CodingAgentPermissionMode {
Plan,
Default,
AcceptEdits,
BypassPermissions,
}同步更新:
- Rust defaults
- serde rename
- TypeScript
UserPreferences - IPC mock settings
- 设置页初始值
- 所有 i18n locale key
语音润色模型配置层
新增“语音润色大语言模型”配置,不直接复用全局 active LLM 的写入命令,避免改变普通听写配置。
配置模式:
SystemDefault- 读取现有 active LLM provider。
- 使用现有润色 prompt 和 style pack。
- 不新增凭据。
CustomProvider- 使用独立 provider id:
voice-polish-custom。 - 凭据仍写入 OS vault 的 LLM providers map。
- 保存字段:
displayNameapiKeybaseURLmodeltemperatureextraHeaders
- 前端只显示
hasApiKey,不回传明文 key。 - 提供校验按钮,调用后端真实发起轻量模型请求。
- 使用独立 provider id:
新增后端命令:
get_voice_polish_model_config() -> VoicePolishModelConfigWire
set_voice_polish_model_mode(mode: VoicePolishModelMode)
set_voice_polish_provider_config(config: VoicePolishProviderConfigWire)
validate_voice_polish_provider_config(config: VoicePolishProviderConfigWire) -> ProviderValidationResult
list_voice_polish_provider_models(config: VoicePolishProviderConfigWire) -> Vec<ModelInfo>新增 provider factory:
fn build_voice_polish_provider(
prefs: &UserPreferences,
vault: &CredentialsVault,
) -> Result<Box<dyn LLMProvider>, ProviderError>规则:
SystemDefault走现有ActiveLLMProvider。CustomProvider通过 provider id 精确读取 vault entry。- 不修改
active_llm_provider。 - 不使用
...storedSettings展开旧字段。 - 保存 preferences 时仅写白名单字段。
Hotkey
新增 hotkey watcher 字段:
coding_agent_hotkey: Arc<Mutex<Option<ShortcutBinding>>>新增命令:
get_coding_agent_hotkey_label()
set_coding_agent_hotkey(binding: Option<ShortcutBinding>)更新冲突检测:
- dictation hotkey
- translation hotkey
- selection ask hotkey
- switch style hotkey
- open app hotkey
- coding agent hotkey
冲突时返回当前已有的快捷键名称。
Coordinator 状态机
新增状态:
pub enum CodingAgentPhase {
Idle,
Recording,
Transcribing,
Polishing,
AgentRunning,
}新增 session state:
pub struct CodingAgentSessionState {
pub session_id: String,
pub phase: CodingAgentPhase,
pub started_at: Instant,
pub raw_transcript: Option<String>,
pub polished_prompt: Option<String>,
pub cancel_token: CancellationToken,
}快捷键处理:
Idle且 feature enabled:- 校验 workdir 已配置且存在。
- 校验 ASR provider 可用。
- 打开 Agent panel。
- 启动 recorder + ASR session。
- phase ->
Recording。
Recording:- stop recorder。
- send last frame。
- phase ->
Transcribing。 - 等待 ASR final。
- ASR final 为空:
- phase ->
Idle - 前端显示空转写错误。
- phase ->
coding_agent_use_voice_polish = true:- phase ->
Polishing - 调用 voice polish provider。
- 失败时按配置 fallback:
- 默认 fallback 到 raw transcript,并在 UI 显示 warning。
- phase ->
- 调用 coding agent:
- phase ->
AgentRunning - 将 stream event 转成 Tauri event。
- phase ->
- 完成:
- 保存历史。
- phase ->
Idle - 前端显示完成。
事件名建议:
coding-agent:statecoding-agent:levelcoding-agent:dismisscoding-agent:history
前端事件 payload:
type CodingAgentStateEvent =
| { kind: "phase"; phase: CodingAgentPhase; sessionId: string }
| { kind: "transcript"; text: string; sessionId: string }
| { kind: "prompt"; text: string; sessionId: string }
| { kind: "delta"; text: string; sessionId: string }
| { kind: "answer"; text: string; sessionId: string }
| { kind: "error"; message: string; sessionId: string }
| { kind: "cancelled"; sessionId: string };所有事件必须带 sessionId,前端丢弃旧 session 的延迟事件。
前端
新增页面/组件:
VoiceCodingAgentPanel.tsxVoiceCodingAgentSettings.tsx- 设置页新增分组:“语音调用代码 Agent”
- provider 设置页新增分组:“语音润色大语言模型”
面板展示:
- phase badge
- raw ASR transcript collapsible block
- polished prompt collapsible block
- streaming markdown answer
- stop button
- copy answer button
- copy prompt button
- open settings button
- error banner
设置项:
- 启用 Voice Coding Agent
- 快捷键录制器
- Agent provider:Claude Code CLI / OpenCode CLI
- Agent executable path
- 工作目录选择
- model
- fallback model
- permission mode
- timeout
- 是否先语音润色
- 语音润色模型模式:系统默认 / 自定义
- 自定义 base URL
- 自定义 model
- 自定义 API key
- 校验模型按钮
安全与错误处理
- 默认权限为
Plan。 - 未配置 workdir 时不启动 Agent,前端提示用户先选择项目目录。
- 未找到
claude或opencode时显示安装提示。 - API key 永不通过普通 state event 回传。
- 日志中屏蔽 bearer token、API key、account id。
- 子进程必须支持取消和 timeout。
- 快速连续按快捷键时只允许当前 session 生效。
- ASR、润色、Agent 任一阶段失败都要恢复 phase 到
Idle。 - 旧 session 的 late event 必须被丢弃。
- 历史记录只保存用户允许保存的 raw transcript、polished prompt、answer、provider id、model、时间戳,不保存 secret。
测试计划
Rust:
- preferences 默认值和 serde 兼容测试。
- hotkey collision 测试,覆盖所有已有快捷键。
- voice polish custom provider 精确读取 provider id,不修改 active LLM。
- Claude Code CLI args 构造测试。
- stream-json parser 测试。
- timeout kill 子进程测试。
- cancel kill 子进程测试。
- session id guard 测试。
- 空 ASR 文本测试。
- Agent process exit 非 0 测试。
Frontend:
UserPreferences类型同步测试。- settings 初始渲染测试。
- system default/custom voice polish 切换测试。
- API key redacted 显示测试。
- panel stream delta 合并测试。
- stale session event 丢弃测试。
- error banner 和 phase reset 测试。
手动验收:
- 普通听写热键仍可录音、润色、插入。
- Selection Ask QA 仍可打开、录音、返回回答。
- Voice Coding Agent 关闭时快捷键无动作。
- Voice Coding Agent 启用但未配置 workdir 时给出设置提示。
- 使用系统默认语音润色模型能完成一次完整流程。
- 使用自定义强模型能完成一次完整流程。
- Claude Code CLI 不存在时给出可理解错误。
- Claude Code 输出能流式显示。
- 取消运行能终止子进程。
- 超时能终止子进程。
- 权限模式默认为计划/只读,不默认修改文件。
- 切换到 OpenCode provider 后能走同一 UI 与事件协议。
验收标准
- 用户可以在前端配置“语音润色大语言模型”,支持系统默认和自定义强模型。
- 用户可以配置 Voice Coding Agent 的快捷键、provider、模型、工作目录、权限模式。
- 触发快捷键后,ASR 内容能发送给 Claude Code CLI。
- Claude Code 处理结果能返回前端并流式展示。
- OpenCode provider 作为开源优先方案接入同一 provider trait。
- 功能不破坏普通听写、翻译、Selection Ask QA。
- 所有 secret 仍由 OS vault 保存,不进入前端事件和历史。
- 默认权限不会修改用户项目文件。
Metadata
Metadata
Assignees
Labels
P2Medium priorityMedium priorityarea:agentAgent areaAgent areaarea:voiceVoice areaVoice areaenhancementNew feature or requestNew feature or requestneeds-designNeeds design discussionNeeds design discussion
Activity
feat(coding-agent): 快速 Agent 引擎 + Claude 控制台(无头 Claude Code)
feat(coding-agent): OpenCode CLI 适配器,语音 Agent 可选 OpenCode 后端 (issue #579
feat(coding-agent): OpenCode CLI 适配器,语音 Agent 可选 OpenCode 后端 (Refs #579…
集成 1.3.14 → beta(主窗 UI 大改 + 一批 fix/feat) (#761)