A
AI TraderAI 原生期货客户端
不要操作软件,直接告诉 AI 你要什么。
v1.6.11 · macOS 13+ Apple Silicon · Windows 10/11 x64
更新日志
v1.6.112026-09-24
- 修复:新闻面板按钮完整遵循明暗主题;媒体缺失时以来源域名显示,引用编号不作媒体名,网站首页标注“查看来源网站”而非“阅读原文”,缺少发布时间不补造。
- 功能:游客、测试与会员共用正式工作区,删除独立游客页及样式;功能入口保留,游客受限时提示登录,会员未开通时说明权限。游客行情服务端默认限制最近3个交易日内,后台可选1/3/5;HTTP/SSE共用受限投影,不补下载历史,语音遵守档位及全局技能开关。
- 修复:新闻文章保持完整高度并在面板内滚动。
- 功能:普通用户与游客共用指定快期账号的页面行情源,合约目录、报价、图表及纯行情 AI/CLI 查询合并取数;普通图表按更新通知独立推送,同一版本仅校验/编码一次,慢连接保留最新图表,不等待账户轮询;真实冷启动的合约目录保持加载状态并自动重试。资金、持仓、模拟委托与下单前报价核验仍走本人账号,策略执行和规则回测深历史保留原链路。
- 性能:游客公共行情与个人模拟交易会话分离;陌生品种异步加载,热行情按更新唤醒共享推送,同合约/周期只取数、编码一次,慢连接直接恢复最新快照。无人浏览的订阅通过闲置关闭或预热替换真正回收,冷加载和总订阅均有界;保存按规模扩展、行情延迟与验收口径的研究。
- 修复:游客行情显式选择已有快期成员账号,复用其认证与池进程并支持无人登录时恢复;不再隐式使用默认主账号,失败不切换来源,游客不会启动私人策略或下单循环。
- 功能:新闻成为与策略并列的阅读面板,保留图表;新闻 / 研究数据页签支持跟随或固定阅读品种,研究数据从策略详情移入。新闻展示来源、时间、摘要和原文,按正式合约目录的中文品种名搜索、按品种共享缓存与在途请求,失败共享缓存60秒并保留真实错误及旧值日期;正式 API、UI 命令、快照和帮助同步;错误显示简短中文,技术原因保留在正式API及日志。
- 功能:首次进入可免密浏览公共行情、指标和独立新闻;游客身份只读取公开数据,不请求私人账户、订单、策略或回放数据。需要模拟交易时再登录,保留合约、周期和主题;按住说话仅支持简单界面操作,未知指令不进入普通 Agent。保留旧服务端登录入口,并提供游客界面命令与脱敏观察;桌面游客凭据只留内存,行情尾K与界面命令共用推送,观察仅随界面/新闻变化回报,已确认的界面命令自动消费,避免后续操作重新打开用户已关闭的新闻。
- 功能:新增独立短期游客身份、只读共享行情与新闻接口、本人窗口控制和有限按住说话;游客不能进入交易账户、私人数据或通用 Agent。生产默认关闭,游客档位不能扩大身份权限。桌面使用独立内存令牌;共享流仅发变化K线,界面命令按版本推送;报价和K线取自同一次公开行情快照,避免最新/最高/最低价格缺失。
- 修复:AI 用 update_preferences 改了账号偏好(如「把复盘与日结放到快捷栏」)后界面不跟随——偏好文档只在连接时读一次。客户端每收到一轮完成的 AI 回答重读一次偏好,快捷技能栏等随即更新。
- 修复:后台「技能」矩阵同一分类的组头重复出现(注册表按 id 列出、同分类不相邻,而分组只合并相邻行),重复的组 key 还让切回「档位」分区时技能行残留在档位矩阵里、模型/token/语音行不显示。改为每个分类只出一段组头、按固定产品顺序排列;测试夹具改为与生产一致的 id 顺序并断言切回档位无残留。
- 功能:技能注册表第二期——后台「技能」矩阵、客户端技能可用性视图、快捷技能栏。① 后台管理新增「技能」分区(UI 命令 adminSection: skills,ADMIN_SECTIONS 两端同步):技能按 category 分组的矩阵(行头名称+说明可换行不截断),列=「全局」启停开关 + 每档位一列勾选(tierGated=false 或 owner-only 的技能为「—」);开关即时保存(保存中禁用该控件、失败回滚并在该行旁显示错误;全局走 PUT /api/admin/skills/{id},档位走 PUT /api/admin/plans/{name} {"skills": {id: bool}} 合并语义);停用 admin-console 弹二次确认(写明停用后后台管理的其他写操作将被拒绝、技能分区仍可重新启用);「档位」分区矩阵删除原 7 项功能开关行,改为一行提示 + 「前往「技能」分区」跳转按钮(旧客户端写 features 仍兼容)。② 客户端新增 useSkills()(读 GET /api/agent/skills,登录/runtime.status 变化/后台保存后刷新;接口不可达回退状态载荷 features,老 Runtime 不崩):顶栏回放、图表回测、工具栏策略、设置里 AI 自主执行与简讯开关的置灰与原因行改读技能注册表,文案与服务端 unavailable_line 同源(「「X」已停用」「当前档位未开通「X」」「「X」仅主账号可用」)。③ 快捷技能栏:对话面板输入框上方一行可换行 chip,只列有 quickAction 的技能;偏好键 ui.quickSkills(Runtime 校验:只接受有 quickAction 的技能 id、去重、≤8;未设置默认 strategy-signals + strategy-guided-design),设置 → 界面「快捷技能」勾选列表;点击以用户身份把 prompt 文本发进当前会话(复用发送入口),技能不可用置灰显示原因不发送;AI 经既有 preference 命令与观察快照可读写。文档同 PR:能力覆盖表加后台·技能分区/快捷技能栏/设置·快捷技能三行,app_help、SKILL.md 同步。
- 功能:内置 AI 技能注册表(第一期)。① services/trader-runtime/src/trader_runtime/agent_skills/<name>/SKILL.md 成为唯一事实源:23 个技能文件按 Agent Skills 开放规范(frontmatter + 正文 何时用/何时不用/步骤/安全边界 + ≥3 典型说法 + ≥2 反例,细节放 references/),产品扩展(tools/routes/tier-gated/owner-only/ui-entries)放 metadata 的 ai-trader- 键;启动扫描注册,Dockerfile.cloud 与 PyInstaller 打包随包携带。② 执行点全部注册表派生:删除 FEATURE_TOOL_NAMES 硬编码,工具隐藏、能力目录 tools()/routes() 过滤、HTTP 写接口门禁统一读注册表——门是一个 app 级 FastAPI dependency(write_skill_gate 按请求匹配路由查 METHOD path → skill 归属表,有归属且写方法即 403;与门重复的逐路由 require_skill 调用点删除,语义不同的保留:GET 接口、回放 control 的 close 与停止类动作一样永远放行、引导设计会话入口;三条写路由带书面理由留给各自 handler——回放 control 的 close、邀请码生成(其门是认证层 owner 会话判定,遗留库同名 cloud_users 行会让 owner_only 误判真主账号)、简讯刷新(1.6.8 客户端契约:档位未开回温和 status: disabled,仅全局停用才 403);技能管理接口 GET/PUT /api/admin/skills 刻意不归属任何技能——恢复入口,停用 admin-console 不得让主账号无法再启用技能),旧错误码 feature_not_in_plan 保留一版;plan_tiers.config.features 幂等迁移为 skills,plans.FEATURES 旧 7 键保留为兼容视图。③ 全局启停:skill_settings 表,disabled 压过档位与 owner_only、对主账号同样生效;状态载荷继续输出 features/strategyTools,新增 skills。④ 渐进披露三层:instructions 技能目录行(仅 name+description,只列该用户可用技能)→ activate_skill 加载完整手册(enum 不含不可用技能,会话内去重,历史压缩后保留)→ read_skill_resource 读 references/(拒绝 .. 与绝对路径)。⑤ 对外接口:GET /api/agent/skills(含单技能详情与资源)、MCP 与打包 CLI 各新增三个技能工具、GET/PUT /api/admin/skills、档位编辑的技能勾选,全部进能力目录。⑥ 文档同 PR:app_help 技能主题由注册表生成,skills/ai-trader/SKILL.md 与 docs/FUTURES_AGENT_CAPABILITY_V1.md 技能表同步;fuzzy 评测语料由 SKILL.md 派生(每技能 ≥3 正例 + ≥2 反例,共 142 例)。⑦ 实现中修复三个缺陷:typed 确定性命中的统一提示行只写历史不发布(用户看不到“当前档位未开通/已停用”提示);有被隐藏技能的用户在 general 回合丢失 activate_skill/read_skill_resource 两个披露工具;评测发现裸“帮我写/做/搞个策略”没有说不清的信号却被引导设计开场词劫持(收紧为仅“设计”,创建草稿归 strategy-management,新增测试钉住)。待确认下单卡片的确认/取消优先级不变(测试钉死)。
- 修复:图表周期只影响当前账户的跟随策略;同一库策略在不同账户验证时生成各自执行副本并读取本账户行情,已有副本继续沿用;历史行情会话持续接收更新,缓存到期可读到新 K 线;实例租约在部分启动或停止失败时守住旧循环停止后才接管;分段止盈超过 255 根仍按真实持仓根数判断;收盘前平仓回测对无法精确撮合的周期或缺失数据报错;已启动的回测取消后等工作真正结束才释放名额。
v1.6.102026-09-24
- 修复:Runtime 蓝绿换槽后进行中的回放丢失(回放随旧槽退出被关闭)。旧槽 lifespan 退出现在只把回放「分离」——停推进循环并 join、不向 sidecar 发 close;创建回放时把属主/合约/交易日/初始资金/默认周期/费率方案/创建时间等元数据(不含凭据)写进 {state_root}/replays/<id>/replay.json。新槽惰性接管:GET /api/replays 先以 loading 占位列出本人可接管的回放,对该回放的第一个请求(详情、控制、runtime 子路径、内置 AI 工具)在锁内探测 sidecar 后复用原回放子数据库、以暂停状态恢复(元数据属主校验与成员隔离不变;sidecar 已无此回放则清理元数据并 404);replay_already_active 按「已挂载或可接管」计算;两槽并存窗口内旧槽退出前已停并 join 推进任务、新槽仅在被请求触发后推进,不会两边同时推进;用户显式退出回放仍真正关闭 sidecar 会话并删除记录。部署手册蓝绿一节、app_help、SKILL.md 同 PR 更新。新增 Runtime 测试:换槽分离+新槽暂停接管(含列表占位与行情可读)、非本人 404、sidecar 已无则清理、可接管回放仍阻止二次创建、显式 close 照旧关闭。
- 修复:回放「先开后补」偶发未生效。生产日志(first_quote 9738ms、kline_ready_86400 13910ms、ready 14736ms)说明该次 ready 门等的是 86400——创建请求带的就是启动时图表所在的日线周期,门控按设计工作,真正缺陷是:①客户端把 chartTimeframe 原样透传,而 sidecar 对无效值(0、非白名单数、字符串、布尔)直接 invalid_replay_duration 拒绝整单创建;②回放中未就绪周期的 503 market_series_not_ready 在客户端显示为错误而非加载中;③日志没有一行能回答「本次 ready 在等哪个周期」。改动:sidecar 对无效 defaultDurationSeconds 回落 60(不再拒单)并在构造时先记 replay_timing stage=default_duration value=<秒>(早于任何可能卡住的阶段);客户端创建回放传 chartTimeframe || 60,回放中该 503 显示「该周期历史数据加载中…」并沿用 250ms 轮询自动刷新,不当错误提示。sidecar 全量 74 通过(含新增日志与回落合同测试)。
- 修复:StrategyGuideCard.test.tsx 偶发失败(CI 一次 expected [] to have a length of 2)。被动 useEffect 在 DOM commit 后经调度器异步把图上标注落盘,findByText 通过时标注可能尚未写入;改为对断言目标本身 waitFor(等标注数组就位再断言内容),本地连跑 20 次全过。伴随的 jsdom "Not implemented: navigation" 报错定位为 src/externalLinks.test.ts 锚点跳转的良性 stderr,与本失败无因果,未改。
- 修复:GET /api/auth/owner/status 等每小时约 1 次的偶发 500(ExceptionGroup: unhandled errors in a TaskGroup,栈里只有 starlette/middleware 帧、无本项目帧)。根因:main.py 两个 @app.middleware("http")(BaseHTTPMiddleware)把每个请求跑进 anyio 任务组/内存流,客户端中途断开时传输异常以异常组形态逃逸、被 ServerErrorMiddleware 记成 500;uvicorn 自身对断开的 send 静默丢弃、从不向应用抛错(ASGI 级复现已验证)。改为纯 ASGI 中间件,请求路径不再有任务组/内存流:DisconnectGuard 最外层把断开(ConnectionReset/BrokenPipe/anyio 流关闭)当已处理结局静默完成——不记 500、不打堆栈;OriginAndClientCompat 合并原 origin 门控与客户端兼容应答,行为逐项保持(origin 403 短路及该 403 的 compat 头、X-AI-Trader-* 头、client_build_seen 有界集合与日志格式、/api/ 与 /healthz 路径过滤),CORS 仍在最内层。新增模拟客户端中途断开的测试(断开点×异常类参数化,断言无异常逃逸、无 500 重建)与 origin 门控回归测试。
- 修复:蓝绿部署后成员按需连接失效(页面持续「当前行情不可用」、positions/activity/workbench 503)。根因是 Runtime 优雅退出对所有池账户执行 release(reason="shutdown"),把 tqkq-pool 里按账户 id 唯一的子连接停掉——换槽窗口内新旧槽共享该子连接,旧槽退出即断掉新槽正在服务的成员。① 退出只分离:进程退出改为 detach(停本进程循环/订阅/provider 装配,不调池 stop),只有空闲回收、解绑、禁用用户才 stop 子连接;② 接管幂等:池 start 对已运行账户返回现有子连接(端口/pid 不变、不重启),Runtime ensure 据此接管;③ 自愈:账户解析时发现池子未报告该账户运行,摘除死装配并当场重新装配,一次外部停子连接不再变成持续 503;④ 孤儿回收:新进程启动读 GET /pool/accounts 收养旧槽留下的运行中子连接(不强制装配),无人在线超过 idle_seconds 即 stop,用户到来则由 ensure 正常接管;解绑未装配的孤儿同样停子连接。成员隔离、容量上限、排队、凭据加密存储不变。docs/THREE_PLATFORM_AND_WEB_DEPLOYMENT.md 蓝绿一节补「成员按需连接跨槽保持」。
- 后台管理「账户与授权」的类型列改为「快期模拟 · 常驻连接 / 按需连接」(原「快期模拟 / 快期接入池」让成员账户看起来不像模拟账户;两者都是快期模拟账户,只是连接方式不同)。
v1.6.92026-09-24
- 修复:后台管理「账户与授权」把成员对自己账户的 owner 角色显示成「主账号」,改为「所有者 / 操作员 / 只读」;顶栏复盘/回放按钮在收起文字后读屏无名称,补 aria-label。
- 功能:AI 语音提问引导设计策略(用户需求:“AI 通过问问题的方式引导我设计自己的策略,有时候我不是不知道策略而是不会表达”)。① 入口两个:策略面板顶部「语音引导设计」折叠卡(disclosure: strategy-guide,可打字作答),通话里说“帮我设计一个策略 / 我想做个策略但说不清楚”(route_utterance 新增 guide_start/answer/stop 路由;引导进行中“算了/下次再说”暂停、界面命令与寒暄照旧、口头“确认”落到当前问题,其余话都当作回答)。② 四阶段状态机(Runtime 持久会话 {state_root}/guided-design/{user}.json,暂停与重启后继续):访谈(固定四问:品种、周期、方向、出入场想法)→ 澄清(设计器 plan.clarifications 优先、否则 questions 前三条;选项支持口头序号“第二个”映射成设计器自己的表达)→ 图上举例校准(按 strategy_rules 同一语义只扫描已收盘K线,最近 3 个命中位置以 buy/sell 标注画到 AI 标注层并聚焦,“是/不像+差别”确认含义,不改参数;举不出例的组说明后跳过)→ 复述确认(大白话复述 + 已确认条件清单,明确确认才落草稿;含糊回答或“要改”回到澄清重新生成)。③ 边界:全程只设计策略——无提案、无委托、无监控状态;图上举例只确认意思不调参;档位未开通 strategies 时六个端点全部 403 feature_not_in_plan;会话按账号隔离。④ 顺带修两个实现过程发现的缺陷:_calibrate_next 确认某组后从队头重扫导致同一组无限重问(改为从 index+1 续扫);voice 调用点投机传 guide_active=True 使两字“确认”落进闲聊、破坏卡片确认流(改为传真实 guide_active)。⑤ PR 审查修正(2026-09-24):有待确认的下单卡时“确认/取消”永远先于引导判定(语音与打字同序);“进行中”加 10 分钟时效——最后一次引导交互超过 10 分钟自动转为暂停(进度保留,说“继续设计/帮我设计策略”或点面板恢复),之后的话按普通路由处理;引导进行中不再吞掉行情/持仓/账户快查、界面指令与带手数的下单/平仓/目标持仓说法(复用 turn_router 现有识别,出卡不直接下单;“上穿均线就开多”这类不带手数的描述仍是设计回答)。接口入能力目录:POST/GET /api/strategy-plans/guide、POST …/guide/answer|confirm|pause;app_help(策略、ui-commands、实时语音主题)、SKILL.md、能力覆盖表同 PR 更新。新增 Runtime 测试 test_strategy_guided_design.py 六项与客户端 StrategyGuideCard.test.tsx 两项。
- 修复:回放打开后图表一直空白、提示 Runtime 请求失败。① 回放子 Runtime 继承主账号口令认证后被当成多用户部署,账户角色为空,客户端丢弃全部状态事件——回放子 Runtime 按构造就是单用户,改为单用户兜底(数据库层标记、请求路径与实时推送三处统一读同一个部署级判定,推送不再误报 connecting;事件流改为先补发历史再推当前快照,重连后最后看到的是最新状态);② nginx 按来源 IP 限 20 个并发(HTTP/2 下每个请求/事件流都算),同一代理出口的桌面+网页+回放窗口很快超限并返回不带 CORS 的 503——/api/ 并发上限改 200、突发 200,超限返回 429。
- 策略信号解读与主动提醒:让 AI 按当前策略讲“现在该怎么做”并在图上画出来。① 只读能力 explain_strategy_signal(HTTP GET /api/strategies/signal,query strategyId?/symbol?/chartTimeframeSeconds?;内置 AI 工具与外部 tool:explain_strategy_signal 同一实现;受档位“策略管理与监控”开关约束):用 evaluate_plan 在当前数据源(实时行情或回放子 Runtime 的回放时钟)评估一张策略,返回结论(开多/开空/平多/平空/观望)、每条条件的满足情况与当前值/阈值差距、参考入场价与策略止损/止盈价、数据时间与 validated,以及与 annotate_chart 同构的编号标注 annotations;省略 strategyId 时取当前合约上监控中的策略(多张返回 requiresSelection 候选、一张没有 409 strategy_signal_no_candidate);只读、不下单、不出方案卡,未验证草稿可解读但标注未验证。② 图上标注复用 annotate_chart 同一数据结构与客户端渲染(编号 ①②③ + ≤8 字短标签,不新造图层)。③ 三种触发:打字/语音“按我的策略现在该怎么做”“策略怎么看”“现在能开多吗”走确定性路由(strategy_signal 档:固定工具集 explain_strategy_signal+annotate_chart、单轮、温度 0,ASR 热词已加策略问法;语音通话中口播结论);图表工具栏新增「策略信号」按钮(等价 chat:send 固定问句,窄窗图标化);监控循环对“监控中”策略在信号从观望变为开多/开空/平仓时每策略每根已完成K线至多一次推 feed.strategy-signal 事件——客户端画标注并弹 12 秒轻提示(strategy-signal-notice),语音通话中播一句,回放按回放时钟同样生效。④ 新增账号偏好 notify.strategySignalAlerts(默认开,设置 → 通知一个开关;关闭只停主动提醒不影响主动询问)。app_help(策略/语音/偏好主题)、SKILL.md、能力覆盖表与 uiCoverage 同 PR 更新。
- 性能:回放“先开后补”+客户端重连 3 秒静默+Runtime 蓝绿无缝部署。① 回放创建请求新增可选 defaultDurationSeconds(客户端传启动时显示的周期;不传默认 60s):Sidecar 在报价与该周期 K 线就绪时即置 ready 并返回快照,其余周期在 export 里标 loading: true 占位(不阻塞整份快照、不泄漏未来 bar),actor 空闲时后台继续预热(180 秒预算),已暂停回放的轮询也会带上补齐后的周期;未就绪周期的 workbench 返回 503 market_series_not_ready(客户端沿用“正在订阅”文案与自动重试);新增单行 replay_timing stage=… ms=… 阶段日志(TqApi 构造、首个报价、各周期就绪、ready)。② 客户端事件流/行情断开 3 秒内重连成功不再显示断开提示、不清空图表与持仓(连接回调挂 3 秒定时器,超时才置 disconnected)。③ Runtime 双槽蓝绿(blue 127.0.0.1:18000 / green 127.0.0.1:18001,同镜像同卷同环境,共享 sidecar netns;两槽均 --timeout-graceful-shutdown 5 使优雅退出能释放实例租约、≤10 秒接管):deploy-release.sh 序列改为 启动空闲槽→healthz commit 门(超时删新槽、旧槽不动)→nginx upstream include 切换(nginx -t 通过才 reload,失败还原)→等 10 秒→停旧槽;首次迁移为一次性幂等步骤(删旧单槽容器、--force-recreate 重建 sidecar 及其 netns 内容器、安装含 upstream include 的 nginx 模板,属全栈重启),此后发布无缝;回滚(含手动切回单槽命令)见 docs/THREE_PLATFORM_AND_WEB_DEPLOYMENT.md。app_help、SKILL.md、部署手册同 PR 更新。
- 回放语音与 AI 控制回放:① 回放窗口的用户级接口转发主 Runtime——/api/replays/<id>/runtime 命名空间里与回放无关的账号级表面(语音状态/音色/播报、模型列表与偏好、账号偏好、owner 状态、账户目录只读 GET)由主 Runtime 以当前登录用户应答,客户端 URL 方案不变,五类 403 消失;账户写入(bind-tqkq 等)不转发(403),未知/已关闭回放一律 404 不回落实盘;WebSocket 握手按语音通话自己的鉴权子协议认证(scope 无 method 的 starlette 断言与 ws 关闭码 4401/4403/4404 一并处理)。② 语音通话绑定回放(硬约束,有测试钉住)——socket 经回放命名空间打开即绑定该回放:行情、持仓、账户、下单卡与口头确认都作用于回放子账户,实盘模拟网关零提交、权益不变;回放关闭后按 replay_not_found 失败关闭;通用 AI(delegate)在回放中拒绝(防未来信息)。③ 播放控制进能力目录——新工具 control_replay(tool:control_replay,HTTP 等价 POST /api/replays/{identifier}/control,与回放窗口按钮同一接口,仅引擎已有动作 play/pause/step/speed 1-2-5-10/pause_entries/resume_entries/finish/close,不能按时间跳);回放通话里 暂停/继续播放/单步/快一点/慢一点/调到 N 倍速 由 Runtime 确定性映射到同一组动作(voice_intents.match_replay_control),"快进到下午3点"如实拒绝;档位未开通 replays 时工具从目录隐藏。新增 test_replay_voice.py 六项测试(转发、隔离硬约束、目录与子 Runtime 工具路径、档位隐藏、说法映射、socket 绑定),Runtime 全量 931 通过。app_help(replay/agent/voice 主题)、SKILL.md、能力覆盖表(回放控制条一行)同 PR 更新。
- 主账号「后台管理」从设置抽屉改为整页控制台(仅主账号可见:顶栏用户图标 + 设置 → 用户管理里只剩“打开后台管理”按钮,非主账号不渲染入口,UI 命令 rejected)。五个分区:概览(成员总数、今日活跃、今日 token/语音合计、估算成本、档位人数分布、待处理数)、用户(完整表格:档位与状态是下拉、绑定交易账户、今日用量、估算成本、最后在线、注册来源,表头排序 + 用户名搜索,改动即时保存行内回显)、档位(对比矩阵:行=设置项、列=档位,显示名/默认档/使用人数/逐模型开关/每日 token 与语音(下拉 不限/常用预设/自定义…)/七项功能开关;列头删除(占用或默认禁用并写原因)+ 复制新建)、邀请码(有效期与落位档位下拉,生成后大号显示 + 复制;列表按状态筛选)、账户与授权(只读核对隔离)。新增主账号只读接口 GET /api/admin/accounts(非主账号 404,进能力目录);UI 命令 view: admin 与 adminSection: overview|users|plans|invites|accounts 进观察快照;app_help 新增“后台管理”主题,SKILL.md、能力覆盖表、部署手册、uiCoverage 同 PR 更新。
- CI:4090D 的 Windows runner 改用独立 Windows 账户 aitrader-ci(冒烟安装/卸载不再触碰用户日常账户里的 AI Trader),Rust 工具链按 CARGO_HOME(共享 D:\ci-tools)查找。
- 安全修复:多用户数据隔离——成员不再获得主账号(默认)交易账户的任何权限。① 删除自动授权机制:启动对账不再把 cloud_users 其余用户授成默认账户 operator,注册新用户不再同事务自动授 operator(auto_operator_for_cloud_users 参数与调用、grant_default_account、default_account_grants_declared 一并移除);accounts 文件显式声明的 grants 照常生效。② 一次性幂等启动迁移:默认账户未声明 grants 时,删除历史自动授权写入的 role != 'owner' 行(granted_by 为执行负责人/system/invite-code 签名);已声明 grants 的账户不迁移。③ 无授权账户的成员在所有账户表面得到 403 tqkq_account_required,不再回落主账号账户;owner 与本机 token 用户行为不变。④ 修掉审计发现的成员回落默认账户路径:内置 AI 工具会话与能力目录 app_call(桥现在按调用方身份解析账户、拒绝失权会话)、GET /api/app/activity 与策略解释证据读取、策略草稿/验证/复盘成交读写、确定性止损重建会话、SSE 失权会话续推(feed 报 account_not_granted 不推数据)。行情数据公共,未改。新增 test_member_isolation.py 五项隔离测试;docs/ARCHITECTURE.md、app_help、SKILL.md 同 PR 更正。同日修正该改动引入的 cloud-jwt 回归:无 grant 行的单租户用户在 SSE runtime.status 的 account.role 变 null,客户端事件校验拒收整条事件(云端 AI 隔离提示不再出现、账户目录为空);状态载荷与目录的角色统一走与 resolve_account 同口径的 effective_account_role(create_app 按认证模式在 store 记录 idp_fallback,owner-password 部署保持 False,成员隔离不变),新增 cloud-jwt 浏览器链路回归测试。
- 撤回 1.6.8 里的「Windows 冒烟自动清理自身残留登记」(#285):4090D 的 runner 与日常桌面使用同一 Windows 账户,冒烟安装会改写同一份 HKCU…\Uninstall\AI Trader 登记,客户端自动更新随后按登记装进 runner 临时目录并被清空——指向临时目录的登记可能正是用户的真实安装,自动清理会删掉它。恢复为任何已有登记都拒绝运行;根治是 runner 改用独立 Windows 账户。
v1.6.82026-09-23
- CI:Windows 安装包冒烟测试遇到自己上次被取消/中断时留下的卸载登记(安装位置在 runner 临时目录 ai-trader-nsis-smoke-*)会自动卸载并清理后继续;指向其他位置的真实安装仍然拒绝运行、不覆盖不卸载。起因:09-23 main 的 windows-desktop 被一次旧运行的残留登记挡住。
- 修复:顶栏按实际可用空间逐级收起,不再按视口宽度断点提前隐藏——Windows 客户端窗口调窄(约 750px)时明明还有大半空间,权益却被隐藏、复盘/回放只剩图标;上线后实测两处缺陷一并修正:约 760px 处合约标签互相压叠但等级停在 0(检测漏了深层容器)、跨宽度跳变时等级卡死不重判。useHeaderFit 最终行为:溢出判定为“内容是否放得下”——header、brand、nav、合约标签、合约下拉、status 各自 scrollWidth 超限、header/nav 等各容器相邻盒子重叠(prev.right > next.left + 1)或有可见内容的子元素被挤成 0 宽都算溢出,警告文字省略号截断、被等级隐藏的容器与被收空(如等级 5 后的 status)不算;每轮触发(ResizeObserver 经 requestAnimationFrame 合帧 + 内容变化)在单次同步测量里把等级类名直接写到 DOM 逐级试放,首个放得下的等级一次 setState 生效,无逐渲染爬升状态机可竞态;等级 3 起 tabs/下拉两个子树常驻 DOM、由等级类名切 display(aria-hidden 镜像最终等级),测量不依赖 React 重渲染。等级表不变(1 藏复盘/回放文字、2 藏品牌副标「模拟盘」、3 合约标签收成单个下拉、4 藏权益、5 藏网页版「下载客户端」),连接/排队警告与恢复入口永不隐藏(放不下时省略号截断),重判触发继续只用权益位数不随权益跳动;已删除按视口隐藏顶栏内容的媒体查询(960/980/760/640/480/1180),nav 列改 minmax(0, 1fr) 可收缩。Playwright 实测 1440→1100→800→760→600→430→390→760→1440 逐步与 800 直跳 430 两个序列:每步各容器无溢出、无重叠、无 0 宽,等级单调收放。能力覆盖表与工作区设计文档同步更新。
- 修复:窄窗口下行情栏品种名只剩一个字(如「中证2612」显示成「中.」)——合约代码在窄布局隐藏后,品种按钮收缩到最小内容宽度而不是撑满所在格子;改为按钮占满格子,名称按可用宽度显示、放不下才省略。
- 桌面版发现新版本时自动弹出更新窗口(原来只在设置里显示):useDesktopUpdater 在启动检查后每 6 小时后台静默再查一次(仅在 current/available/error 时发起,下载/安装中不打断,失败不改变已展示的更新状态);新组件 DesktopUpdateDialog 在出现可用新版本时弹出,显示新版本号、当前版本、发布日期与更新说明(纯文本保留换行、超长窗内滚动),「立即更新」窗内复用进度条与暂停,「稍后」或 Esc 后本次运行内该版本不再弹(更高版本或下次启动再弹);下载中关窗只是最小化,下载继续、进度仍在设置 → 账户与模型 → 更新状态可见。设置里的原更新入口不变。AI 可操作性:dialog: {name: "update-dialog"} 只能开关该窗(无可更新版本或网页版 rejected;下载安装仍属受保护核心),快照新增 context.update(open/version/phase);workbench.generated.ts 重生成,帮助主题(ui-commands、设置)、SKILL.md 与能力覆盖表同 PR 更新。
- 修复:桌面客户端外部链接(登录页快期「去注册」、AI 回复与资讯原文链接)改为用系统浏览器打开,修复 Mac/Windows 点击无反应——Tauri WebView 不处理 target="_blank" 与 window.open,纯锚点在桌面端无效。原三个打开命令(open_news_source 的交易所域名白名单、前端无调用方的 open_tqkq_registration/open_deepseek_api_keys)合并为 open_external_url(只放行无内嵌凭据的 http/https),前端新增全局捕获阶段链接处理器统一拦截,资讯原文链接回归普通锚点,网页版行为不变。
- 多人档位改存数据库并全量后台可调:① 档位存库——新表 plan_tiers,首次启动空表时播种一次 基础档/高级档/测试档 三档(此后主账号的编辑、新建、删除不被重启复原);删除 AI_TRADER_PLANS_JSON 环境变量与 PLANS/PLAN_NAMES/PLAN_LABELS 常量(种子保留为 SEED_TIERS),旧库已有成员的档位值不变。② 功能注册表——FEATURES 七项:AI 自主执行、联网研究、行情简讯、策略管理与监控、回测、行情回放、语音通话;档位另限定可用模型集合、每日 token、每日语音分钟(各自可设不限)。③ 统一检查 require_feature——回测全部 POST、语音 socket(4431 拒绝、status reason feature_not_in_plan)、行情简讯(读取返回空列表 + status: "disabled",不调模型)、策略与回放读写入口分键拦截,403 feature_not_in_plan;读取类接口与停止/回放退出等收尾动作永远可用;档位缺失回退默认档,owner 与 local-token 不限;内置 AI 工具集与能力目录同步隐藏未开通工具(CLI 同一检查)。④ 状态载荷兼容——features 在既有 aiExecution/webResearch/strategyTools 之外补全七个 camel 键,strategyTools = strategies && backtests && replays,plan/planLabel 保留,1.6.7 客户端无需升级。⑤ 管理接口(仅主账号,其他人 404,入能力目录)——GET/POST/PUT/DELETE /api/admin/plans(新建带 copyFrom;PUT 部分更新,显式 null = 不限;model_unknown/feature_unknown 400;删除 409 plan_in_use/plan_is_default)、PUT /api/admin/users/{username} 改档位(400 plan_unknown);邀请码带 plan(invite_codes 补列),首次登录直接落在该档;改动每请求读库、立即生效。⑥ 后台页面(设置 → 用户管理)——档位区一次编辑一个档位(「编辑档位」下拉选择,选项显示「显示名(N 人|默认)」,新建后自动选中新档位、删除后回到默认档),可改显示名、默认档、逐模型开关、每日 token 与语音分钟(步进 + 不限)、七个功能开关,显示使用人数,删除按钮按原因禁用,支持复制新建;用户档位下拉列出全部现存档位;邀请码可选落位档位;客户端按 ownerStatus.features 灰显未开通入口(回放、回测、策略、简讯、语音,提示「当前档位未开通,联系管理员」),不新增灰显组件。app_help、SKILL.md、能力覆盖表、部署手册与 uiCoverage 同 PR 更新。
v1.6.72026-09-22
- CI 自动重跑不再把所有作业跳过:各作业的执行者门禁原来同时要求 github.actor 与 github.triggering_actor 都是仓库属主,而 rerun-checkout-failures 工作流用 github.token 发起重跑,触发者是 github-actions[bot]——于是 Windows runner 那条偶发 TLS 握手失败被自动重跑后,整轮作业全部 skip,还白白用掉一次尝试次数。门禁改为actor 仍须是属主、triggering_actor 允许属主或 github-actions[bot](跨仓 PR 仍被 head.repo.full_name 挡住)。
- 云端页面加载不再报 404 控制台错误:GET /api/auth/owner/status 在没有管理员口令认证的 Runtime(本机 token、云端 JWT)不再回 404,而是照实回 {authenticated: false, ownerAuth: false}。客户端 M2 起每次打开云端页面都会问一次当前档位(useOwnerPlan),拿 404 只是「这台 Runtime 没有管理员认证」,却在浏览器控制台留下一条无从修起的资源加载错误,也让生产镜像的七视口验收红。前端与档位展示行为不变。
- 下单台「目标持仓」模式(差额出卡 + 两段接力 + 语音):① 客户端下单台第三模式——开仓/平仓/目标持仓三段切换(ticketMode 增 target),目标净持仓带符号步进(多正空负、0=清零)+ 价格方式复用,本地按持仓即时预览差额(“目标 X,当前 Y → 买开 Z 手”),「生成方案卡」直接调新能力;已是目标持仓时按钮禁用。② Runtime 差额出卡——新纯函数模块 rt/target_position.py 按净持仓(多−空轧差)计算计划:不变不出卡、加仓出开仓卡、减仓出定向平仓卡、清零出全平卡、反手(如 +2→−2)拆两段跨零;新工具 create_target_position_proposal(symbol/targetNet/priceIntent?)与 HTTP POST /api/simulation/target-position/proposals,复用既有 create_trade_proposal / create_close_batch 出第一段卡,卡上多一行“目标持仓:…”与“第 n 步/共 N 步”;不变时直接中文说明“当前已经是目标持仓,不用下单”。③ 两段接力(新表 target_position_plans + rt/order_watch.py 扫描)——第一段委托全部已成交才自动出第二段的卡并提醒/播报,等用户确认,绝不自动连发;同 (用户,合约) 新计划顶替旧计划,30 分钟无进展自动放弃并说明;UNKNOWN 家族(结果未知/身份异常/回报异常)不推进。④ 语音与打字共用确定性路由——message_context 识别目标持仓句式(调到/调整到/变成/保持/持有…手多空、目标持仓清零/归零;开平仓动词句与持仓问答不误入)注入一轮指令,turn_router 新 target_position 路由只带目标持仓卡工具+search_instruments(temperature 0、minimal 推理、一轮),评测集补 6 句;说话如“把螺纹调到三手多单”与 AI 工具同一出卡路径。不引入 TqSdk TargetPosTask,不新增下单/撤单调用点,确认仍走既有 exactly-once 发单链路。app_help、SKILL.md、能力覆盖表、uiCoverage 同 PR 更新。
- 五档盘口与语音/对话小修:① 价格阶梯五档——sidecar 透传 TqSdk bid/ask_price2..5、bid/ask_volume2..5(缺档归一 None,空快照占位同样带 2–5 档字段),get_market_snapshot 与 workbench 一并透出;客户端阶梯渲染 11 行(卖五→卖一→最新→买一→买五),价格与挂量同行显示,缺档灰显不可点,有两档以上数据时右上提示「五档行情」、仅一档时保留「仅一档行情」。② 续句合并去噪——合并半句时服务端取消其 agent run 并补发 message.superseded 事件(payload {turnId, supersededBy}),客户端把该半句 user 消息与其后的「已停止/未完成」收尾一起隐藏(数据保留不删),模型历史本就去掉未作答用户轮。③ 看护口令放宽——挂单看护中「撤单/追单」从整句精确匹配改为短句关键词:≤16 字含「撤/取消」或「追/改对手价」,排除否定(别/不要/不用)、其它动作词(买/卖/开/平/加/减/改价)与复合句(再/然后/顺便);无看护挂单时仍由 AI 处理。app_help、AI_AUTONOMY_AND_VOICE_V1 同 PR 更新。
- TqSdk 未用能力 A 档(M3,七项接入):① 官方 TqSdk Skills 包 vendored 到 services/tqkq-sidecar/skills/tqsdk-trading-and-data/(2026-09-22 自官方 zip 下载,内容不改、仅去掉 agents/,改 TqSdk 调用前先读其 SKILL.md)。② 每日结算价:sidecar GET /v1/settlements?symbols=&days=(官方 query_symbol_settlement,days≤30)→ Runtime provider → AI 工具 get_settlement_prices(当日结算价约 19:00 后产生,asOf 标最新已产生交易日;主连不支持)。③ 合约交易状态:get_trading_status 汇入行情快照与 workbench(tradingStatus 原始值 + tradingStatusLabel 中文),客户端顶栏交易状态标签在集合竞价(AUCTIONORDERING)显示「集合竞价」(优先于「开盘前」);集合竞价时段 create_trade_proposal 照常出卡,就绪摘要注明「集合竞价中,开盘撮合后才有成交」。④ 日内开仓限额:目录/快照带 openLimit(0/缺失=无限制,来自 open_limit),openedToday 按账户当日 OPEN 成交求和,get_market_snapshot 另带 openRemaining;开仓超过剩余额度不出卡,拒绝码 open_limit_exceeded 并说明「今日还能开 N 手(日内开仓限额 X 手,已开 Y 手)」。⑤ 主连历史:sidecar GET /v1/cont-history?symbols=KQ.m@…&days=(≤200,query_his_cont_quotes)→ 工具 get_main_contract_history(品种/交易所.品种/主连代码均可,返回每日主力合约与换月日期)。⑥ 龙虎榜:sidecar GET /v1/rankings?symbol=&type=VOLUME|LONG|SHORT&days=(≤5,query_symbol_ranking)→ 工具 get_symbol_ranking(每日前 20 席位,官方数据非爬虫;默认简报不调用)。⑦ 更多指标:indicators.py 纯 Python 实现 BOLL(20,2)/ATR(14)/RSI(14)/CCI(14)(与 tqsdk.ta 对拍容差 1e-6,由测试钉住),get_market_analysis 输出四项最新值与一句话读法;语音口播不念数字细节,图表不加新副图。三个 sidecar 新端点走既有 actor 命令模式(10s 超时),FakeReadOnlyDataProvider 同步合成;app_help、SKILL.md、能力文档同 PR 更新。
- 多人接入 M2(用户档位):每个云端用户按档位运行,主账号不限。① 档位定义(新模块 rt/plans.py,PLANS + Plan.unlimited(),env AI_TRADER_PLANS_JSON 只能覆盖两档数值与开关、不能新增档位名,格式错误忽略;数字与服务端兜底 AI_TRADER_DAILY_TOKEN_LIMIT 取更紧):基础档(快期直登默认)只有 deepseek-flash、每日 30 万 token、每日语音 30 分钟、无 AI 自主执行与联网研究;高级档全部已配置模型、每日 200 万 token、120 分钟语音、全功能;策略设计/回测/复盘所有档位开放。存储:cloud_users 补 plan(默认 basic)与 disabled 列(旧库启动自动迁移、已有成员按基础档)、新表 user_voice_usage(user_id, day, seconds)。② 模型与 token:GET /api/models 按档位过滤 selectable(原有会员规则叠加)并带 quota{plan,planLabel,dailyTokenLimit,usedTokensToday,voiceSecondsToday,voiceSecondsPerDay};PUT /api/models/preference 越界 403 model_not_in_plan,send_message 同样过滤、偏好当前值不在档位内时回退首个可用模型但不改写偏好;token 超额当日 429(原码不变)。③ 语音分钟:通话结束记秒(跨零点记到结束日)、发起前额度用完 GET /api/voice/realtime/status reason voice_daily_limit、socket 4430 拒绝,通话中用完由看门狗播“今天的语音时长用完了。”后挂断。④ 功能开关:基础档 /api/ai-execution/start|limits 403 feature_not_in_plan(stop 永远可用);内置 agent 工具集按档位去掉 web_search/get_research_brief 并在指令中声明未开通联网研究;策略工具本期所有档位开放。⑤ 管理面(仅主账号,其他人 404):GET /api/admin/users(用户名/角色/档位/邀请来源/最近在线/今日与本月的 token、语音秒/今日成本估算/停用/快期绑定)、PUT /api/admin/users/{username} {plan,disabled}——改档位立即生效,停用立即结束该用户会话、其后登录 401 account_disabled 并释放其池装配;POST /api/auth/owner/invite-codes 增 daysValid 1–90 天(默认 14,旧调用不变);GET /api/auth/owner/status 认证后带 plan/planLabel/features。⑥ 客户端:档位外模型不进下拉、被关功能灰显并提示“当前档位未开通,联系管理员”;设置 → 账户与模型新增 档位/今日 token/今日语音 三行;新设 settingsPage=admin「用户管理」(仅主账号渲染):邀请码生成(1–90 天、只显示一次)、用户表(档位下拉、停用开关、用量与成本估算),UI 命令与快照覆盖入表。文档(app_help、SKILL、部署手册、能力覆盖表)同 PR 更新。
- 多人接入 M1b(登录页快期直登、解绑与主账号防重绑):① POST /api/auth/tqkq(body {username, password, inviteCode?})——池 verify 口令后首次登录凭邀请码建 role=user 用户(consume_invite_code,口令验证通过才消费,错密码不烧码;AI_TRADER_TQKQ_LOGIN_INVITE=0 可关),复用 bind_tqkq_account 绑定装配并发会话 cookie;再次登录重新密封最新口令;与管理员主账号同名 403 use_owner_login(compose 已把 tqkq_username secret 挂到 trader-runtime,env AI_TRADER_STATIC_TQKQ_USERNAME_FILE,fail closed)、与 Runtime owner 同名 409 username_taken、口令错 401 tqkq_login_failed(reason auth_failed/timeout/capacity_full)、按 IP+用户名双键限频(429)、池不可用 503;接入池 fixture 模式的 verify 改为直接收受任意账号口令(不起真实 TqApi 子进程,供本地端到端演练登录链路,真实模式子进程协议不变)。② 解绑即退出:POST /api/accounts/unbind-tqkq 吊销会话并清 cookie;未绑定的 role=user 业务请求 403 tqkq_account_required,不回落管理员默认账户(resolve_account 的 IdP 回落仅 owner 与 local-token 模式保留);装配中/排队中 GET /api/runtime/status 保持 200 可读(降级载荷带 account.poolStatus)。③ 客户端:登录页首选「快期账号登录」(邀请码按需显示、「去注册」开快期官网、「管理员登录」切回原表单),登录后顶栏显示「正在连接模拟盘…/在线人数已满排队中」并每 5 s 轮询目录直至连通;设置 → 账户与模型新增「快期账号」区(绑定用户名、连接状态、「解绑并删除密码」二次确认后回登录页,owner 不显示);错误文案覆盖 use_owner_login/邀请码/账号密码/连接超时/在线人数已满。
- 多人接入 M1a(后台基础设施,HTTP/CLI 验收;登录页在 M1b):用户绑定自己的快期模拟账号,后台按需起停连接进程,主账号常驻不变。① 接入池(sc/pool.py,python -m tqkq_readonly_sidecar.pool --serve):控制面端口 19010(鉴权沿用 sidecar token 文件),子接入进程 = 现有 main.py 以 --config-stdin 起子进程(凭据仅经 stdin 一次性传入,不落盘/不进命令行/不进环境变量),端口从 19100 起分配复用,上限 AI_TRADER_TQKQ_POOL_MAX(默认 8,满则 503 capacity_full);POST /pool/verify 临时 TqApi 只验登录(≤60 s),auth_failed 结果缓存 10 分钟防重启风暴。② Runtime 动态装配(rt/account_pool.py):ensure 凭据解密 → 调池 start → build_services 装入 registry(装配中 runtime.status.account.status="connecting",池满 503 runtime_capacity_full 且 status="queued");POST /api/accounts/bind-tqkq 池 verify 口令 → 建 tqkq-pool 账户行(owner=该用户,新会话默认账户切到它)→ 密码 AES-256-GCM 密封存库(新表 tqkq_credentials,主密钥 AI_TRADER_CREDENTIAL_KEY_FILE 32 字节 base64 secret,AAD=user_id);POST /api/accounts/unbind-tqkq 停子进程、删凭据与授权、账户置 disabled(历史委托/成交行保留)。③ 在线判定与闲置回收(rt/presence.py):ui/pulse、SSE 订阅、chat:send、语音通话开始四处 touch;后台每 60 s 扫描,账户全部授权用户超 AI_TRADER_ACCOUNT_IDLE_SECONDS(默认 1800)无心跳即 release(日志 account_pool start/stop account=… reason=login|idle|unbind),主账号与 always_on 不回收;下一次请求自动重装配,离线成交由账本 run_once 全量补账。④ 部署:可选覆盖层 deploy/vps/docker-compose.pool.yml(同镜像、read_only+tmpfs,只在 .env.production 有 AI_TRADER_TQKQ_POOL=1 时由 deploy-release.sh 追加并写 images.yml,回滚同条件),Runtime 侧 AI_TRADER_TQKQ_POOL_URL 默认空 = 池不可用,单账户行为逐字节不变;启用手册(密钥生成、回滚、凭据安全边界)见部署文档新节。
- 语音下单闭环修复(09-21 夜盘实测四问题的收口):① 口头确认失败不丢卡——_confirm 不再先清本地待确认记录,只有服务端终态码(approval_already_used/approval_expired/invalid_state_transition/stale_proposal_version/proposal_not_found)才清卡并作废;其余失败(行情停更/不在交易时段/后台没回应)中文口播原因、确认窗口重新起算、卡上倒计时复原,报价恢复(quoteDatetime 变新且 ≤15 s)时播一次"有新报价了,说确认就下";本地记录丢失时按 store.pending_proposals 重建,服务端待确认卡是唯一事实;确认窗口从最后一句念完起算,抢话同样顺延(deadline 变化 ≥1 s 才重发卡)。② 打断可取消进行中的命令——记录 delegate 回合的 runId(task.started),说"停"或(无待确认卡时)"算了/不要了/取消/别查了/不用了"取消本地回合 + POST /api/runs/{run_id}/cancel 并播"已停止"(时间线 turnCancelled);处理中改说新的业务句则取消旧回合按新句路由(turnSuperseded,不多播一句);寒暄不取消。③ 挂单未成交看护(新模块 rt/order_watch.py,来源无关:确认路由登记)——已受理/部分成交的限价单每 2 s 查询,15 s 与 60 s 各提醒一次(会话文本卡 orderwatch- 前缀 + 语音播报带当时买一卖一,受 voice.announceFills),成交/撤销/结果未知即停(UNKNOWN 只查不重发,遵守 TQKQ_SIM_THIN_V1);口头"追单"= 等撤单回报确认已撤销后以对手价同方向同手数走 delegate 出卡、"撤单"= 撤掉并播报;确认成功即时口播"已挂单 xx,还没成交,15 秒没成交我会提醒你"。④ 行情标签分清两种坏——交易时段标签只在整体 dataStatus !== "normal" 时显示"行情待更新";数据正常但该合约报价 >15 s 时按秒显示"X 秒无新报价"(普通样式、本地每秒刷新,marketSession.quoteAgeSeconds 与下单台可下单提示同源,15 s 阈值不变)。
- 语音通话体验修复:① 判停交给豆包动态判停——Runtime 看门狗降为安全网,账号偏好 voice.endpointStallSeconds 改 2.0–5.0 s(默认 3.0,旧值自动抬到下限),说话中间停一拍不再被判成说完;自定义判停窗键(enable_custom_vad + end_smooth_window_ms,env AI_TRADER_VOICE_END_SMOOTH_MS)实测被豆包接受但会卡死下一句识别(静音上幽灵 transcription.started、强制 commit 也无 completed),默认不发,仅 env 留口;② 续句合并——句中停顿拆出的两个 final 在 3 s 内(env AI_TRADER_VOICE_CONTINUATION_SECONDS;实测豆包对前半句的判停延迟约 1.2 s,窗口须覆盖停顿时长+判停延迟)且上一轮还没开口作答(被静音的豆包填充语不算已作答)时,取消上一轮、两句合成一句重新路由(时间线 utteranceMerged,链式合并上限 60 字);③ 打断改服务端首字确认——本地音量突增只把播报增益压到 0.15 等 700 ms,服务端 interrupt(ASR 识别出人声首字)才清播放队列,杂音不再误打断,客户端不再代发 cancel;④ 口播去掉合约代码括号("螺纹钢(SHFE.rb2610)"念作"螺纹钢",其它括号照念内容);⑤ 输出响度均衡 dialog.extra.enable_loudness_norm(env AI_TRADER_VOICE_LOUDNESS_NORM,默认开)。
v1.6.62026-09-21
- 模糊指令(第一期):打字回合接入确定性快路径、按句式收窄工具集。新增 rt/turn_router.py:界面意图表命中的口语不经过模型直接执行(与语音 fast 意图共用 run_window_intent,窗口不在线回落模型);开仓/平单个持仓只带 {create_trade_proposal, search_instruments}、整仓平掉只带 {create_close_batch_proposal}(temperature 0、minimal 推理、最多两工具回合一轮出卡);纯行情问句只带读数与标注工具(无 web_search);有方案卡等确认时下一句不收窄。助手回复发布前剥句首“好的/收到”套话。voice_intents 补“边上的/旁边的/侧边”收侧栏句式;ASR 热词扩到 72、近音纠错对 63(asr_context 格式不变,与目录品种去重)。评测集入仓 services/trader-runtime/eval/fuzzy/(116 句带期望路由,运行方法见 fuzzy_eval.py 文件头);tests/test_turn_router.py 无模型钉死全集路由。第二轮(同日):上期所/能源中心平仓缺省平今/平昨时按持仓自动判定(跨今昨出一张 close_batch 卡、超仓中文拒绝不建卡);一轮路由里卡片工具拒绝时把其 userFacing 中文直接作为回合答案(不再出现“未完成。”);意图表补字号/历史对话/持仓页句式与整仓平掉的说法,目录匹配接受品种代码且不区分大小写,语音 fast 词不再压制一轮路由;评测集期望按真模型结果修正。
- 修复:复盘「今日/手续费/当日盈亏」不再被结算清零——快期模拟账户 15:15 结算后 close_profit/position_profit/commission 归零,记账循环每 30 s 整行覆盖 account_daily,保存的永远是清零后的值(历史行已丢的当日数无法还原);现在 upsert_account_daily 对这四列改为「新值为 0/NULL 时保留已存值、非 0 新值照常覆盖」,权益/静态权益/时间照常覆盖。sidecar /v1/account 摘要与 Runtime 只读 provider 摘要补 staticBalance(static_balance 列不再恒为 NULL);复盘接口在实时 todayNetPnl 被结算清零时回退用同日日结行,days[] 新增 equityDelta(当日权益 − 上一交易日权益)作为日结行也丢失时的当日净盈亏回退(客户端复盘日展开不显示当日净盈亏,故仅加字段未改客户端)。(执行:GLM-5.3 via Claude Code headless,2026-09-20)
- 修复:云端镜像在生产机本机构建时 uv sync --frozen 直连 files.pythonhosted.org 挂死(uv.lock 钉的是下载地址,镜像源只影响解析)——两个 Dockerfile.cloud 改为 uv export --frozen 导出锁定清单后经配置的 PyPI 索引 uv pip install(版本与哈希不变),生产机实测 Runtime 28 s / Sidecar 36 s。
- 部署:Runtime/Sidecar 镜像改在生产机(腾讯云)本机构建,zgo-la 构建角色退役——deploy/vps/deploy-release.sh 的 BUILD_HOST 默认改为生产机自身(本机构建走 sudo docker build、archive 只做一次、跳过 save|gzip|load 跨机传输),构建命令以 --build-arg PIP_INDEX_URL/UV_DEFAULT_INDEX 注入 PyPI 镜像源(默认 https://mirrors.tencentyun.com/pypi/simple,--pypi-index <url> 或 PYPI_INDEX 环境变量可覆盖);两个 Dockerfile.cloud 去掉对 ghcr.io 的 uv 拷贝,改为 pip install "uv==0.11.28"(空 build-arg 时用默认源,不传 build-arg 的本地构建行为等价,仅 uv 来源从 ghcr 变为 PyPI);--build-host <别名> 保留旧两段式远程构建+传输回退路径(逻辑不变)。部署文档与迁移手册同步。(执行:GLM-5.3 via Claude Code headless,2026-09-20)
- 新增:网页版顶栏右上角「下载客户端」链接(新标签打开官网下载页,桌面版不显示);修复:手机窄屏下单台委托价输入框被截断(两个字段改单列)。
- 新增:客户端交易账户切换器与多 sidecar 部署(任务 4.4 下半)——被授权 ≥2 个账户时,顶栏与设置 → 账户与模型出现“交易账户”下拉(选项“显示名(角色)”),切换即 PUT /api/sessions/{id}/account,当前账户唯一来源是 SSE runtime.status.account(packages/ui-events 补齐该块),客户端所有 Runtime 请求补 X-AI-Trader-Account 头指向会话账户、会话重置即清空;只有一个账户时顶栏无切换器、设置行只读显示账户名,单账户用户零可见变化。界面命令 tradingAccount: <账户id>(UiChanges/UiState 同名字段,id 不在目录 rejected,applied 回执等切换发布的 runtime.status;旧客户端上报 tradingAccount=null 时回执照常成立),观察快照可见当前账户与顶栏 select 控件(顶栏新入 regions);覆盖表、app_help.py(settings/ui-commands 主题)与 SKILL.md 同 PR 更新。部署新增可选覆盖层 deploy/vps/docker-compose.accounts.yml(第二个 sidecar 复用同一镜像与主 sidecar 网络命名空间、独立数据卷、端口 19002,runtime 挂 accounts 文件 secret):仅当服务器 .env.production 有 AI_TRADER_ACCOUNTS_OVERLAY=1 时 deploy-release.sh 追加该文件并多写一行 sidecar-2 镜像(回滚按恢复的 env 决定是否带覆盖层),缺省部署命令与单账户逐字节一致,基础 compose 不变;启用手册见部署文档「启用第二个模拟账户」(含 accounts.json、secrets、回滚与 renameFrom 不回滚的说明),.env.production.example 带同名注释块。本 PR 不含 REST 路由或 OpenAPI 基线变化(新增字段均为可选,符合 R2/R3)。本机双账户验收方法见 PR 正文。(执行:GLM-5.3 via Claude Code headless,2026-09-20)
- 修复:手机网页版「新对话 / 历史对话」不再被历史回合锁死——chatBlocked 收窄为“正在切换对话或正在发送”(useWorkspaceChat.ts),去掉“最后一条 assistant 回合未 completed”与“任一 running 任务卡”两个启发式(后台标签页丢失 message.completed 或旧任务卡停在 running 时会把按钮整场锁死,8bc211b 不够);界面命令的同名拒绝改为“正在切换对话,请稍等”,app_help.py 两处描述同步。语音通话“滋啦卡拉”杂音——voiceRealtime.ts 捕获与播放改共用一个不指定采样率的 AudioContext(原 16k/24k 两个上下文在 iOS/Android WebKit 引起重采样失真与爆音),输出帧保持 24 kHz 标注由 WebAudio 在播放时重采样;回复起播先缓冲 ≥120 ms(或 6 帧)再从 currentTime+0.05 连续调度,帧晚到时欠载重对齐 currentTime+0.1 并对前 2 ms 线性淡入(每回复最多记一次 underrun 日志),不再每帧各自从 currentTime+0.02 起播留下缝隙;打断仍清空缓冲并把 playhead 归零。手机端两项均需真机复验。(执行:GLM-5.3 via Claude Code headless,2026-09-20)
- 新增:账户目录与会话切换账户、状态快照带账户、默认账户指纹改名与 grants 声明(任务 4.4 上半)——GET /api/accounts 列出当前用户被授权的全部账户(默认在前;每项 id/显示名/角色/环境/执行负责人标记/providerKind/isDefault/status)与本次请求实际账户 current(随 X-AI-Trader-Account 头变化)。PUT /api/sessions/{session_id}/account(body {"accountId"})把会话换到另一个有 grant 且本次已装配的账户:会话行、feed 会话状态(该会话全部事件缓存失效)与后续 AI 回合工具集跟随新账户,切换即向该会话发布一条带新账户块的 runtime.status,重复切同一账户幂等,未授权/未装配 403 account_not_granted 不回落默认。状态快照统一带 account{id, displayName, role, environment, executionOwner}:GET /api/runtime/status 按请求账户组块,SSE runtime.status(含 native agent 的 bootstrap/refresh_session)按会话账户组块。默认账户改用指纹 id:accounts 文件条目 renameFrom 声明旧 id,启动装配前一个事务内全表改名(PRAGMA defer_foreign_keys 迁移唯一外键;proposals_terminal_immutable 触发器事务内先 DROP 后原样重建;覆盖 trading_accounts + account_grants + 12 张账户列表),旧 id 不存在则无操作(幂等可重启),新旧 id 并存或 renameFrom 与条目 id 冲突启动即失败;无 accounts 文件的部署零变化(仍 tqkq-sim:default)。条目 grants: {"operator": [...], "viewer": [...]}(用户名映射 scoped id,拒绝跨角色重复与执行负责人出现在声明里)时启动把该账户对账为恰好 owner + 声明集合;默认账户声明 grants 后注册新用户不再自动授 operator。能力目录新增两条操作;OpenAPI 基线再生成(顺带收入 main 上的 preferences 契约漂移);app_help.py、SKILL.md、能力文档与架构文档同 PR 更新。(执行:GLM-5.3 via Claude Code headless,2026-09-20)
- 新增:执行归属与角色权限(任务 4.3)——一账户一执行负责人,角色判定唯一来源是 store.account_role / store.is_execution_owner(trading_accounts.execution_owner_user_id)。AI 自主动作(ai_initiated=True 的下单/恢复/挂止损、显式建租约 activate、策略监控下单与 POST /api/strategies/{id}/monitor/start)只属于执行负责人,其他授权用户的 AI 一律 403 not_execution_owner、只能生成方案卡;策略监控对非负责人策略"只监控不消耗 K 线"。角色差异:owner(=执行负责人)与 operator 可手工确认自己的方案卡、撤改自己的委托、挂撤自己的止损,并可普通停止/只停新开仓/急停;viewer 一切账户写操作 403 account_read_only(读不受影响)。resolve_account 新增显式 account_id 目标(提案确认/改风险按提案行账户、monitor/start·pause 按策略行账户解析),/api/trade-review 按请求账户取 provider;AI 工具对上述错误码返回中文 userFacing(引导出卡);保护单授权读取补上 trading_account_id 过滤,跨账户急停行不再互相覆盖。客户端 strategyApi 对 403 裸错误码给对应中文文案(其余 401/403 提示不变)。单账户部署所有者即执行负责人,owner 路径无任何新增拒绝。(执行:GLM-5.3 via Claude Code headless,2026-09-20)
- 新增:多账户服务装配第二期(任务 4.2,无 accounts 文件时行为不变)——Runtime 按交易账户装配服务。新模块 wiring/accounts.py:账户声明文件 AI_TRADER_ACCOUNTS_FILE(accounts[]:id/displayName/dataMode/symbols/sidecarUrl/sidecarTokenFile/executionOwnerUsername),结构或内容不合法启动即失败(accounts_file_invalid/empty/duplicate_id/requires_sidecar),文件里消失的账户标记 disabled 不再装配;每个账户一套 AccountServices(provider、模拟订单、自主执行、策略监控、账本),由 AccountRegistry 统一暴露,app.state 旧单例视图即默认账户实例。请求按 X-AI-Trader-Account 头 → 会话 trading_account_id → 用户 grants(默认账户优先、否则最小 id,无 grant 行用户沿用 4.1 落默认账户)解析 AccountContext,头部指向未授权账户返回 403 account_not_granted;会话型写入(建会话、交易/平仓卡、策略草稿)落会话账户,策略评估/监控按策略行账户,提案确认/改风险按提案行账户。leader 每账户各跑监控与账本循环,feed 通道按 (账户, 用户) 区分,native agent 每回合绑定会话账户的只读工具集;角色权限差异与多 sidecar 留到 4.3/4.4。审查返工(4.2b):未授权/未装配账户一律拒绝——会话绑定的账户无 grant 或本启动未装配时 403 account_not_granted(不再静默回退默认账户),提案确认/策略监控 409 account_not_assembled,agent 回合发布错误事件后停止,feed 通道只报该会话不可用;无 grant 行用户在默认账户上角色为 operator。(执行:GLM-5.3 via Claude Code headless,2026-09-20)
- 新增:多账户数据层第一期(任务 4.1,行为不变)——Runtime 状态库每行业务数据记 trading_account_id。新增 trading_accounts / account_grants(角色 owner/operator/viewer)两表;12 张业务表加账户列,account_trades / account_daily / ai_execution_controls 改复合主键,ACTIVE 部分唯一索引改 (user_id, trading_account_id);旧库启动自动迁移(九张表补列、三张改键表重建回填,foreign_key_check 必须为空)。启动时生成默认模拟账户 tqkq-sim:default:执行负责人按认证模式解析(owner-password → owner scoped id;cloud-jwt 有配置用户名 → 其 scoped id,否则 local-user;local-token → local-user),持 owner;cloud_users 全部用户与后续注册用户自动持 operator,保持"注册即可下单"现状。单账户部署下接口、循环、下单、记账、复盘结果与之前完全一致;Runtime 不读 TqKq 凭据,tqkq-sim:<指纹> 账户 id 留到 4.4 声明账户时引入。(执行:GLM-5.3 via Claude Code headless,指挥:Claude Code Fable 5.1,2026-09-20)
- 修正:网页版 设置 → 账户与模型 → 软件版本 行不再一直显示"正在读取",回退到客户端自身构建版本,显示 1.6.5(短 SHA)(1db86f4 网页验收时发现)。(执行:Claude Code,Claude Fable 5.1,2026-09-20)
- 新增:客户端能力版本上报与兼容提示(任务 3b)。客户端每个 Runtime 请求带 X-AI-Trader-Client: <platform>/<semver>[+<构建 sha>](platform ∈ web/desktop,构建 sha 由 AI_TRADER_BUILD_SHA 构建变量注入、本地 dev 为 dev 不带 sha;SSE 不变);Runtime(新模块 client_compat.py)在每个 /api/ 与 /healthz 响应回 X-AI-Trader-Client-Compat(ok / outdated 低于 MIN_CLIENT_VERSION=1.6.5 / unknown 未上报——Runtime 只判定客户端是否过旧,不比较网页构建:Runtime 与网页分开发布,它不知道网页当前部署的构建)、X-AI-Trader-Runtime(版本+短 sha),outdated 时另回 X-AI-Trader-Min-Client;CORS 允许该请求头并暴露三个响应头;首次见到的构建组合记一条 client_build_seen 日志(有界 ≤200)。/healthz 新增 minClientVersion。"网页有新版本,刷新页面即可更新"由网页客户端自己判定:加载时与回到前台(两次拉取至少间隔 5 分钟)拉页面旁 version.json(new URL("version.json", document.baseURI)),已部署构建与本页构建互不为前缀 → refresh;桌面版与 dev 构建不做该判定,拉取/解析失败静默忽略。窗口心跳 device 补 build(旧客户端不带上报仍通过),快照 connection 段补 build/compat;设置 → 账户与模型 → 软件版本行显示 版本(构建号),Runtime 判 outdated(提示更新客户端)或网页构建落后(提示刷新页面)时旁边一行提示,不弹窗、不拦截。外部 Agent 请求可带 agent/<版本>。能力覆盖表、app_help.py、SKILL.md、部署文档(MIN_CLIENT_VERSION 提高时机:只在契约基线确认必须破坏、且随版本准备 PR)同 PR 更新。(执行:GLM-5.3 via Claude Code headless,指挥:Claude Code Fable 5.1,2026-09-20)
- 新增:旧客户端兼容验收——全量 REST 契约基线 services/trader-runtime/contracts/openapi-baseline.json(scripts/export_runtime_openapi.py 以 fake 模式构造真实 app 导出;基线取自最新桌面 Release 1.6.5 @ 697a5cb:94 路径/103 操作),release:prepare 在 15 文件版本集之后自动重生成,CI 每次 pytest 跑 tests/test_client_compat.py 四条规则(不删路径+方法、请求不新增必填字段且不拒基线属性、响应不删字段且类型不变、枚举不删值),细则与盲区见 contracts/README.md。对 1.6.5 基线首跑抓到真实契约变化:UiState.highlights/chartAnnotations 在 05d996a(2026-09-18 生产事故修复)由类型化数组放宽为自由对象,4 个 UI 状态接口的响应 schema 不再承诺 12 个字段——首跑曾判红并标 [compat-red],2026-09-20 复审裁定该放宽为 schema 变松而非客户端破坏(字段由客户端在 pulse 上报、Runtime 原样回传,运行时载荷未变),R3 对类型化对象变自由对象记盲区不判红。(执行:GLM-5.3 via Claude Code headless,指挥:Claude Code Fable 5.1,2026-09-20)
- 新增:实例租约——同一 SQLite 状态库只允许一个 Runtime 实例跑会下单/写账的后台循环(止损监控、策略监控、后台记账)。租约为状态库单行 runtime_lease,BEGIN IMMEDIATE 事务内原子抢占:抢到者为 leader 并启动三个循环,第二个实例 standby——照常提供接口、跑只读推送 feed,不跑三类循环;leader 每 10 秒心跳,30 秒无心跳可被接管,失去租约时先停会下单的循环再停记账;心跳异常不致死也不失去租约(心跳任务逐轮兜住异常,循环启动失败按轮重试),只有心跳被拒(别的实例已持有)才降为 standby;正常关闭先停循环再释放租约。桌面重复拉起、测试版与正式版同状态目录、部署换容器时新旧实例短暂并存均只有一个实例在执行。/healthz 保持 status:"ok",新增 instance 字段(instanceId/role/leaderId/leaderSince,回放子应用 role:"replay" 不建租约)。(执行:GLM-5.3 via Claude Code headless,指挥:Claude Code Fable 5.1,2026-09-20)
- 新增:设置 → 交易 → 执行限制 新增"只停新开仓"按钮——可逆轻操作,点按直接生效、不弹确认框(stopAiExecution 请求体 {emergency, scope},opens 档 toast "已只停新开仓,AI 不再开新仓;平仓与保护单照常");"全局急停"仍走确认框,HALT_OPENS 状态下设置页并排保留"全局急停"(围栏只能加强)。stopStatus 联合类型补 "HALT_OPENS",顶栏与设置页恢复按钮三档文案(AI 已急停 / 已只停新开仓 / AI 已停止 · 恢复);策略监控启动只在 STOPPED/EMERGENCY_STOP 时拦(HALT_OPENS 允许启动、只监控不开仓),策略状态表补错误码 ai_new_opens_halted 中文文案。能力表覆盖行、app_help.py 设置说明同步。(执行:GLM-5.3 via Claude Code headless,指挥:Claude Code Fable 5.1,2026-09-20)
- 新增:AI 模拟执行停止分三档——急停撤 AI 委托并作废已挂止损止盈(行为不变);新增"只停新开仓"(POST /api/ai-execution/stop 与 AI 工具 stop_simulation_execution 传 scope: "opens":拒 AI 与策略新开仓,平仓、已挂保护单、策略平仓与执行租约照常,不暂停策略监控;急停 + opens 返回 invalid_stop_scope);普通停止拦 AI 一切主动动作,但已挂保护性止损止盈仍执行。保护性退出改为独立规则:触发时不检查也不消耗剩余委托次数、不受单笔手数上限、不要求租约 ACTIVE(过期或被普通停止也执行),挂保护单不再套手数上限,唯一拦截是急停(新增错误码 ai_new_opens_halted)。客户端"只停新开仓"入口、stopStatus 类型与错误码文案在下一 PR。停止围栏只能加强:已停止或急停后不能改成只停新开仓,需先恢复(返回 ai_execution_stopped);普通停止不会降级急停。(执行:GLM-5.3 via Claude Code headless,指挥:Claude Code Fable 5.1,2026-09-20)
- 修正:成交与日结记账改由 Runtime 后台记账循环负责(每 30 秒或 Sidecar 新快照时),不再依赖有客户端在线;此前零客户端在线时策略成交只留在 Sidecar 当日数据里、隔日丢失。(执行:GLM-5.3 via Claude Code headless,指挥:Claude Code Fable 5.1,2026-09-20)
- 修正:批量确认/急停撤单的事务原子性——委托变更通知改为提交后触发,store 事务内禁止嵌套提交(Runtime)。SimulationOrderService.prepare/request_cancel 在 proposals.confirm、autonomy 急停的 store.transaction() 内被调用时,末尾的 _notify_change() 会同步触发 wiring/feed.py 装配的委托回填(backfill_order_fills),后者 with lock, connection: 退出时把外层 BEGIN IMMEDIATE 事务提交掉;此后批量确认里第二张 prepare 失败时 rollback 只能回滚提交点之后的部分——第一张的 tqkq_sim_order_links 行与子 proposal 已落库,"nothing is half-sent" 的原子性失效(触发条件:tqkq_sim_order_links 里存在 submit_phase='CONFIRMED' AND last_remote_status='FINISHED' 且 account_trades 无同 client_order_id 行的链路;无待回填链路时不写库,故既有测试未抓到)。修复:store/base.py 新增 GuardedConnection——transaction() 持有期间,任何其他提交路径(with connection: 块退出、显式 commit()/rollback())都抛 commit_inside_owned_transaction(with connection: 的 C 层 __exit__ 不走 Python 重写的 commit(),故守卫同时覆写三处),嵌套 transaction() 抛 nested_transaction;新增 StoreBase.after_commit:事务所有者线程登记的回调在提交成功、释放锁之后执行(回滚即丢弃,回调失败只记日志、不向业务调用抛,通知失败不能让已提交的业务操作报错),非所有者线程调用则立即执行;_notify_change 改为 store.after_commit(self._fire_change),on_change 属性、签名与 wiring/feed.py 装配不变。新增回归测试(先红后绿:红在第一张子委托的链路行回滚后残留)与 tests/test_store_transaction.py(守卫拒绝 + 整体回滚、after_commit 提交/回滚/事务外/跨线程语义、回调失败不影响已提交操作);全量 pytest 714 项绿,守卫未发现其他事务内嵌套提交。(执行:GLM-5.3 via Claude Code headless,指挥:Claude Code Fable 5.1,2026-09-20)
- 外审修复第一批(用户 09-19 拍板;Runtime + 设置一行开关)。A1 数据库备份不可靠:store/base.py 开着 WAL,而 deploy/vps/deploy-release.sh 用 cp -p 直接拷主库文件,已提交但还在 -wal 里的事务不会进备份(外审用临时库复现:源库 1 条、cp 备份 0 条,且备份的 integrity_check 仍返回 ok)。改为 sqlite3.Connection.backup 取一致性快照,并在备份目录里回读 integrity_check 与 sessions / events / proposals / proposal_audit / 模拟委托链接 / 执行租约 / 止损 / 成交 / 策略草稿 / 偏好十张业务表的行数(备份行数必须落在备份前后两次源库计数之间,并发写不会误判、丢行一定失败),对不上就在换 .env 和动容器之前中止发布。脚本注释与部署文档同步写明:回滚只恢复环境与上一版容器,数据库不回滚,旧备份不得覆盖新交易记录。新增 test_deploy_backup.py 把外审复现固化,并直接运行脚本里内嵌的那段备份校验程序。A3 出卡工具没有限价参数:create_trade_proposal 只有 priceIntent,用户说“820挂一手多”会被按盘口重定价成 823/824(09-19 评测 order-04 实证)。工具新增 limitPrice(与 priceIntent 二选一,给了就原样下单;超出涨跌停或不在最小变动价位上时不出卡,返回中文原因,绝不静默改价。两者必须有一个:都不传时不出卡并用中文说明该补哪个字段,不会静默按对手价成卡;两个都传以 limitPrice 为准),返回值补 symbol / side / volume / limitPrice,与卡上是同一组数;指令、工具描述、帮助与 SKILL 同步。A5 AI 自主执行开关(用户拍板:设置 → 交易 一行开关,默认开):账号偏好新增 trade.aiAutonomy,关闭时 Runtime 拒绝 execute_simulation_trade、拒绝为 AI 建执行租约(含 AI 替用户挂止损 set_simulation_stop_loss,帮助与设置说明里已写明;用户自己挂的止损不受影响)、策略监控只监控不下单(不消耗该根 K 线,打开即继续),错误码 ai_autonomy_disabled、中文提示“AI 自主执行已关闭,只能生成待确认方案”;改为关闭时把 ACTIVE 租约置 STOPPED 并记一条 Runtime 日志。用户确认的方案卡、回放结束平仓和客户端自己的委托不受影响,用户的用法完全不变(说“买一手”→ 出卡 → 确认 → 发出),不新增任何授权话术。A6 “调过工具”≠“已核验”:原来任何业务工具(包括读操作手册、包括失败的读取,且在调用前就打标)都会清掉“本轮未读取实时数据”的脚注;改成证据记录——只有成功返回的实时事实类工具(行情快照/图表指标/摘要/K线/决策上下文/账户/持仓/委托成交/web_search)才计入,每条记 {tool, ok, scope, capturedAt/ageSeconds} 并打进回合日志。A7 历史压缩拆散工具调用:压缩从头逐条 pop(0),会留下 function_call_output 而删掉对应的 function_call(外审桩复现);改成按完整回合组裁剪、摘要成功后才替换(摘要失败不再丢历史),并在发模型请求前校验每组 call/output 成对,不成对的整组丢弃并 log,当前回合永不丢弃。(执行:Claude Code,Claude Opus 5,2026-09-19)
- 外审修复第二批:批量平仓的“已确认”不再等于“已发送”,推送改成按通道判定陈旧(Runtime + 客户端;用户 09-19 拍板)。①批量平仓卡的状态来自子委托事实:proposals.confirm 在事务里把父批次与子单落成 candidate_recorded 之后才逐笔 dispatch,而 candidate_recorded 原来被模型状态行写成“已确认并发送”、卡面写成“已发送”——确认后、发完前重启会留下仍是 PREPARED 的子单,某笔发送前校验失败又被概括成“结果未知”。现在父批次对外状态由持久化子单聚合(simulation_orders.close_batch_execution:已发送 / 未发送 / 结果未知 / 已成交),卡面写一句“已确认,2 笔已发送、1 笔未发送、1 笔结果未知”并逐笔列出状态,_proposal_status_line 给模型的系统说明同样由子单事实生成(PROPOSAL_STATUS_LABELS 的 candidate_recorded 改为中性的“已确认”);同 idempotencyKey 重试改为回读当前子单事实后返回,与单笔路径一致,不再只报本次附加的结果;发送前被拒的子单保持 PREPARED 并持久化原因(note_dispatch_error 写 last_read_error,一份回报即清除),标“未发送 + 原因”而不是“结果未知”;中断恢复只走既有单笔 continue / abandon(卡上直接给按钮),不重新生成委托、不对 UNKNOWN 自动重发;确认时重新发布一次 proposal.close_batch,让卡片拿到子单 id,重启回放后依然显示逐笔事实。②推送按通道判定:runtimeFeed.ts 原来只有一个 lastEventAt,行情 / 账户 / 活动 / 执行控制任一推送都刷新它,于是“行情停更 61 s、执行状态 1 s 前有推送”被判为正常、行情轮询被抑制、界面保留 dataStatus: normal 的旧行情。现在按通道记录 {receivedAt, sourceAt, status, error},各读者只看自己的通道(行情回退轮询只由行情通道决定),界面沿用既有 dataStatus / 行情陈旧提示,不加新横幅;服务端 runtime_feed.py 读取失败不再沉默保留上一次成功结果,而是在该通道推送新的 feed.status({channel, status: unavailable, reason},wiring/feed.py 带上 provider 自己的原因码),且快照版本门最多压住 5 秒,不能阻止陈旧状态的重新判定。验收:批量确认在第 2 笔发送前中断 → 父状态聚合为“1 笔已发送、3 笔未发送”、第 3 笔仍可 continue、重试不重复下单(gateway.submit_count 不变);发送前校验失败 → “未发送 + close_offset_mismatch”;4 笔全部 UNKNOWN → 重试与单笔 dispatch 都不重发;行情 61 s 未更新而执行事件 1 s 前 → 行情通道陈旧、轮询恢复;行情读取失败 → 该通道推 feed.status。(执行:Claude Code,Claude Opus 5,2026-09-19)
- 语音 V1.4:简单界面指令秒级完成,开场白按请求类型(Runtime;用户 09-19 真机反馈“我让他打开图表,还要反应好多秒”“他每次都说‘我要查一下’,这明明只是个命令”)。①开场白按类型:interim_line 由“有指标词说我看一下、其余一律我查一下”改成表驱动的纯函数——界面/导航“好,正在打开图表”(宾语取自原话,取不出说“好的,马上”)、下单/平仓/撤单“好,这就来”、查行情持仓账户“我看一下”、讲图或指标“我看一下图”、新闻/原因/影响“我查一下”、改语速音色等偏好“好,这就改”、其余“好的”,每句 ≤8 字。②固定意图表补口语:“打开图表 / 看图 / 把图表调出来 / 回到图表 / 图表页 / 看一下K线图”原来都不命中视图正则(只认 交易台/K线/图表页,且“图表页”会被设置页正则抢走),走 delegate 要 5–10 秒,现在一律是 view: trade,一秒内完成;另补“宾语在前、动词在后”的关法(把持仓收起来 / 对话关掉 / 设置关掉)与“看看沪金 / 看一下螺纹”的合约切换。③豆包直接操作界面:表未命中但明显是界面话的(界面动词 + 界面对象、无业务词,looks_like_ui)新路由 ui,该回合豆包不静音、由它调新工具 operate_ui(action: open|close|switch|set,target 限 对话/策略/阶梯/下单/持仓/设置/图表/复盘/回放/主题/字号/周期/合约/设置页,value 限枚举),Runtime 用 operate_ui_intent 映射到与固定意图表同一条 run_intent 通道(同一条 UI 命令、同一份回执),applied 后由 Runtime 念一句结果,仍是“一个声音”;豆包不调工具先开口、或 target/value 映射不到、或窗口没接受命令,就 response.cancel 回退 delegate(时间线 uiToolFallback)。④12K 预算:豆包 INSTRUCTIONS 与全部工具描述精简去重,每条 ≤60 字(instructions 577→408 字符;原六个工具的 JSON 1354→1150 字符,新增 operate_ui 后工具合计 1655 字符)。真机实测顺带修的三处:(a)“看图”“深色”这类两字界面指令原来被“≤2 字 = 寒暄”规则交给豆包(09-19 harness 实测“看图”只得到一句闲聊、没发命令),现在固定意图表命中优先于该规则;(b)一句 Runtime 已自己做完的话,豆包若仍调 operate_ui,原来要等它把话说出口才取消,现在静默答掉工具后立刻 response.cancel——固定意图表回合首音从 2.8–3.1 s 压到 1.9–2.5 s;(c)开场白把“搞一手螺纹多的”这类只有手数、没有买卖字样的话也算下单(“好,这就来”),偏好判定排在下单之前(“默认手数改成两手”仍是“好,这就改”),并按 09-19 真机实测补了 7 条 ASR 替换词(幻城→换成、视窗/池仓/实仓→持仓、交义台→交易台、自大一点→字大一点、复盘也→复盘页)。真机证据(24 句界面指令 22 句零 LLM、首音中位 2.13 s;operate_ui 层 6/6、1.46–1.91 s;fuzzy15 复跑无回归)见 ~/ai-trader-release-artifacts/voice-v14/REPORT.md。只改 Runtime,不动客户端。(执行:Claude Code,Claude Opus 5,2026-09-19)
- 修正:历史里一条未完成的旧回合把 新对话 / 历史对话 / 发送 三个按钮永久锁死(网页热修)。useWorkspaceChat 的 chatBlocked 原来对全部历史回合取 some,只要任意一条 assistant 回合的 completed 还是 false 就一直禁用;线上一个会话的第 2 条回合(09-18 的语音回合“已经切成黑色主题了,界面已生效。”,task 卡早已 completed)当年没收到 message.completed,停在 completed:false,它后面 7 条回合都完整,整个会话却再也点不动(现场用 React fiber 读到 connection: connected、chatBusy false、sendingPrompt false、chatBlocked true)。改成只看还可能在进行的回合:最后一条是未完成的 assistant 回合,或任一 task 卡仍是 running;同时对话 reducer 在追加一条新的用户回合时,把它之前所有 completed === false 的 assistant 回合置为已完成(实时与历史重放走同一条规则),旧回合不再以“进行中”的形状进快照或透传给 Runtime。只动客户端,不改 Runtime。(执行:Claude Code,Claude Opus 5,2026-09-19)
- 右侧栏重设计 v2(用户 09-19 按示意图拍板;客户端 + Runtime,网页先发、桌面随 1.6.6):右栏改成 对话 / 策略 / 阶梯 / 下单 / 持仓 / 设置 六项,前五项是互斥的侧面板(RightDock 加 positions,删除 aiPage 内页)。①对话面板 = 一条 AI 流水:标题行写“合约 · 仓位”标签并把 +新对话 / 历史 / 收起 收成图标(历史是锚定弹出的列表,仍是 disclosure: chat-history),标题行下是整宽通话栏——未通话是绿色“开始通话”点一下接通(不是按住,走同一个 voiceCallStore,与 AI 球共用一路通话和同一组 voice-call / voice-mute 开关,球保留为面板收起时的快捷入口),通话中显示音量条 + mm:ss + 静音 + 红色“结束通话”,出错显示“重试”,语音不可用时按钮禁用并写出 GET /api/voice/realtime/status 的 reason;有策略在监控时再钉一条策略运行横幅(策略名、运行时长、判断次数、今日盈亏、暂停 = 同一个 monitor/pause);新的筛选片 全部 / 对话 / 策略与交易(界面命令与快照字段 aiFilter);流水把对话回合与系统条目按时间合并成一条流——策略判断、委托与成交、平仓盈亏、保护变化、简讯,全部由客户端从已有的 /api/app/activity、/api/app/briefs、/api/trade-review 合并,不新增 Runtime 接口;底部只留输入框 + 发送,原“语音通话中 · …”状态行和“新对话 / 历史对话”按钮行删除。②策略面板独立(panel: strategy):运行中策略卡 + 策略库列表 + 研究数据卡,“配置策略”改为面板内展开态 + 返回(不再是单独 dock 值),“+设计策略”开设计窗,“流水”跳到对话面板并把筛选置 trading。③持仓面板(panel: positions,取代持仓抽屉):权益 / 今日 / 浮动盈亏 / 保证金占用四格 KPI、与底栏共用同一 positionsTab 与“历史”开关的三个页签、底部“保护”段(disclosure: protection-status 从盯盘页迁来);底栏保留现状但“查看全部”改为打开本面板,PositionsDrawer 删除,dialog: {name: "positions-drawer"} 保留为 panel: positions 的别名(Runtime 与客户端的回执判定都认,1.6.5 客户端上报的旧状态也仍匹配)。④通话按钮颜色在 theme.css 定义成对 token(--call-start-bg / --on-call-start、--call-end-bg / --on-call-end):两种主题都保留亮绿底(浅色 #07C160、深色 #2ed573)配深绿字,对比约 6.5–8.5:1(白字在 #07C160 上只有 2.4:1)。⑤Runtime:UiState / UiChanges 加 aiFilter,panel 的 positions 改判面板(旧客户端报底栏展开仍算 applied),aiPage 命令保留、快照不再上报;voice_intents 的“打开持仓 / 持仓那个页”改为 panel: positions,说“底栏 / 持仓栏”才是 positionsBar;策略监控在 latest_results 里累计 since / checks(StrategyDecision 显式字段),供横幅显示运行时长与判断次数。⑥快捷键:Alt+A 开关对话面板、Alt+P 开关持仓面板(设置里的名称同改)。内置说明(app_help 的 agent / ui-commands / voice-realtime / strategy 主题)、skills/ai-trader/SKILL.md、docs/FUTURES_AGENT_CAPABILITY_V1.md 覆盖表与 workbench.generated.ts 同 PR 更新。验证:vitest 309 项(新增 AiDock 7 项:通话栏四态、筛选、流水合并排序、横幅显隐、历史弹出、球与通话栏共用一次登记;FDW 新增持仓面板、panel: positions / positions-drawer 别名、aiFilter / aiPage 兼容、Alt+A / Alt+P)、Runtime pytest 全绿(新增 changes_match 别名与兼容、voice_intents 新面板值、监控 since/checks)、Playwright 主套 17/17 与执行套 5/5(覆盖核查 783 控件、新缺口 0)。(执行:Claude Code,Claude Opus 5,2026-09-19)
- 修正:升级上来的旧数据库里 account_trades 没有 volume_multiple 列(它只写在建表语句里、没有对应的 ALTER 迁移),GET /api/trade-review 每次都 500 no such column: volume_multiple;旧版只有底栏切到"平仓记录"才读这个接口所以少被撞到,右侧栏 v2 的流水会常读它。补上缺的迁移,并加一条回归测试(用缺列的旧表建库,打开后列必须补回、list_account_trades 能读)。(执行:Claude Code,Claude Opus 5,2026-09-19)
- 语音 V1.3(Runtime 只发;用户 09-19 拍板,Fable 审查会话派工):①豆包直查三类只读——豆包工具加 get_quote(query) / get_positions(query?) / get_account(),Runtime 实现并走与打字/CLI 相同的正式接口(合约解析复用 /api/instruments + resolve_symbol,行情/持仓/账户用现有 API),返回紧凑中文字段(≤6 项、数字已格式化),dataStatus≠normal 或 ageSeconds>15 只返回 {"error":"行情数据过时/不可用"};route_utterance 新增 quick 类(voice_intents.match_quick_query:多少钱/价格/涨跌/量/行情/怎么样+品种、手里/持仓/仓位/亏赚/盈亏、账户/资金/余额/权益/保证金/还剩多少钱,含“那沪金呢”追问;含买卖开平撤挂/下单/止损止盈/加减仓/设置/打开/关/切/画/标/新闻/为什么/原因/影响/能不能/该不该/建议/看法/分析/走势/形态/指标/K线/是不是/会不会/要不要 等一律不算),quick 回合豆包不静音、自己调工具念结果;失败关闭:豆包未发 function_call 就开口 → 立即 response.cancel 并回退 delegate(时间线 quickQueryFallback);Runtime 听出的类型与品种优先于豆包的选择(“权益多少”它调 get_quote 时按 get_account 回答,quickToolRemapped;“刚才那个多少钱”用通话里最近提到的品种);delegate/intent 回合里豆包调这三个工具一律静默应答(quickToolDropped)。quick 回合的用户原话 + 豆包念出的文本以 origin=voice 写入当前对话会话(tool_log/timeline routedBy=quick)。豆包 INSTRUCTIONS 同步:只念工具数字、不编不猜。②ASR 热词:session.create 的 extension.asr.extra.context(对象格式;火山 3.0 文档表格写 string、示例为对象,真机对象格式被接受)= 合约目录全部中文品种名(去重 ≤200)+ 交易词 + 替换词(全屏→全平、告一首→搞一手、买一首→买一手、时盘→实盘、罗文→螺纹、长了没→涨了没);enable_asr_twopass 真机实测 15 句丢 1 句定稿且判停延迟明显变长,不开(AI_TRADER_VOICE_ASR_TWOPASS=1 可试)。③上下文注入:通话建立先读客户端 hello,把当前对话最近 6 轮(每条截 200 字、跳过表格/代码块,总量 ≤2000 字)作为 extension.dialog.dialog_context 传给豆包;每个 delegate 回合结束后用 conversation.item.create 把原话 + 念出的 spoken 成对追加(不带 timestamp)。真机(本机 native Runtime + 真豆包,证据 ~/ai-trader-release-artifacts/voice-v13/):fuzzy15 复跑“全屏→全平”“告一首罗文→搞一手螺纹”“买一首→买一手”均纠正,ASR 定稿延迟均值 1.62 s → 1.70 s(+0.08 s);新增 8 句快问:直查回合首音 1.5–2.4 s(目标 ≤2.5 s),豆包不调工具时回退 delegate 4.4–5.8 s 仍正确。pytest 新增 6 项(词表命中/排除各 15 句、结果格式化与过时 fail-closed、dialog_context 构造与截断/热词表、脚本化上游:直查回合+写入会话、无 FC 开口即回退+上下文追加、工具改判)。(执行:Claude Code,Claude Opus 5,2026-09-19)
- 内置 AI 回合数削减(用户 09-19 拍板,Runtime 热修;背景:#228 后打字首 delta 中位 8.6 s、语音 6.5 s,deepseek 首 token ≈1.5 s × 回合数是主项):①开仓一轮出卡——create_trade_proposal 处理时 Runtime 自己取决策上下文(与 get_futures_decision_context 同一内部计算 _decision_context),就绪门禁结果写进卡的 readiness 与详情风控行(“就绪检查已通过:行情、K线、合约、账户、持仓与委托数据均为最新,委托价在涨跌停范围内”)和工具返回;门禁未就绪时不出卡,返回 proposal_gate_not_ready + userFacing 中文缺失项(与决策上下文 proposalReady=false 一致),行情不可用返回同名错误码、回合按“实时行情未就绪”收口;候选构造被拒(涨跌停、最小变动价、可平手数、找不到持仓等)也以中文原因返回而非泛化“数据不可用”;平仓不走 K 线门禁,沿用持仓/行情校验并写平仓就绪行。指令改为“开仓直接 create_trade_proposal,不先读上下文”(通用指令、语音指令、开发者策略、两个工具描述);原话含手数且带多/空/买/卖/挂/开仓/来(不含平/撤/止损/实盘/别)时,message_context.open_order_request 确定性识别为开仓请求,打字与语音回合都在指令前加“本轮直接出卡、不先读 K 线/行情/持仓、没说方向先问一句”(与批量平仓提示同一机制;四类评测里 deepseek 仍在半数开仓回合先读 K 线——它读 K 线是为了知道当前合约),并把本对话窗口的焦点(当前 symbol/周期,不含可见文字)附进指令,没说品种时用当前合约、不猜品种(语音转交的回合没有 workspaceContext)。②读屏按需——原话命中 这个/这里/这张/这条/这个数/屏幕上/现在显示/我看到 时,Runtime 组装回合时直接把本窗口快照摘要(焦点、弹窗、可高亮目标、可见文字,≤1.5K 字)注入指令并注明“不要再 app_call 读”;未命中不注入且指令不再要求读屏;chat.autoReadScreen=false 不注入;窗口离线/无窗口静默跳过。③pytest:一轮出卡(含门禁不通过、行情不可用、涨跌停、平仓可平手数)、注入命中/未命中/偏好关闭;四类模糊评测(order/query/chart/ui)前后表见 ~/ai-trader-release-artifacts/voice-v13/rounds/。只发 Runtime。(执行:Claude Code,Claude Fable 5.1,2026-09-19)
- 设置页重做第 1 步(用户 09-18 拍板;不加新设置项):分类重排为 账户与模型 / 语音 / 图表 / 交易 / 通知 / 界面 / 快捷键 / 数据与隐私(“运行与更新”并入账户与模型,“简讯提醒”并入通知,“执行限制/费率/交易状态”并入交易,“工作区/字体大小”并入界面与快捷键);控件只保留五种——开关(Switch)、分段选择(Segmented,≤4 项)、下拉(Select)、步进器(Stepper,带单位与范围)、按钮(状态写在旁边),裸复选框和 aria-pressed 按钮组全部替换;每行固定 左标签 + 一行灰说明 / 右控件,分区为卡片,一个滚动区;焦点态、深浅色、窄面板、大字号核过。settingsPage 枚举改为 account/voice/chart/trade/notify/ui/shortcuts/data,旧值 connection→account、appearance→ui、simulation/fees→trade 在命令与回执判定里自动映射(旧桌面客户端上报的旧值同样接受);快照 controls[] 新增 checked(开关 / 分段项状态)。所有现有设置行保留原语义与命令。
- 设置重做第 2 步 Runtime 侧(用户 09-18 拍板,Fable 规格 §5):按账号持久化的偏好文档 UserPreferences(SQLite user_preferences:JSON + 版本号;六类 voice / chart / trade / chat / notify / data,键与范围见帮助主题 preferences),GET/PUT /api/preferences(PUT 部分更新、返回全量,未知键或越界值 422 整体拒绝,query version 可选乐观锁 409)进能力目录;内置 AI 工具 get_preferences / update_preferences(走同一路由);界面命令 preference: {key, value} 与快照 preferences 字段(Runtime schema 与回执判定,客户端设置行随第 1 步合并后补)。旧表 user_voice_prefs 迁入 voice.voice,PUT /api/voice/realtime/voice 改写同一处。Runtime 消费方:语速 → 豆包 session.create speed(慢 −20 / 正常 0 / 快 30)、endpointStallSeconds → ASR 看门狗、confirmWindowSeconds → 口头确认窗口、announceFills / announceBriefs → 通话播报、autoAnnotate / defaultPriceIntent / defaultVolume / closePreference / replyStyle / autoReadScreen → 每轮“本账号设置”指令行(全默认时不加)、voiceOrderConfirm=false → 模拟盘语音方案卡由 Runtime 代为立即确认(读 liveTrading 为关才走)、sessionRetentionDays → 生命周期扫描释放超期未活动的对话(默认 365)。客户端 workbench.generated.ts 重生成(preference 命令 / preferences 快照类型)。pytest:PUT→GET→版本、422/409、音色两路一致、目录与工具、命令校验与快照匹配、指令行、通话消费方、免确认、保留天数。真机 harness:判停改 0.8 s 后通话时间线出现 asrForcedCommit stallSeconds=0.8(证据 ~/ai-trader-release-artifacts/settings-v2-runtime/)。只发 Runtime。(执行:Claude Code,Claude Opus 5,2026-09-18)
- 口语化模糊指令评测与修正(用户 09-19 要求,Runtime 热修;证据 ~/ai-trader-release-artifacts/voice-v12/fuzzy-eval/:真实 Runtime 链路 + deepseek-flash,70 句 × 打字/语音 × 2):①通用与语音指令收口——查持仓只 get_positions、查价/涨跌/量只用行情工具不联网(新鲜度提示改为“工具能答的不联网,只有新闻/原因/影响才 web_search”)、开仓方案不先读持仓/账户/活动、“哪里能进/关键位”= 分析 + annotate_chart 不用 highlight_ui、“看 X 周期/回到K线/换个颜色”= 界面命令、改偏好直接改不确认、风险规则不创建、情绪/叮嘱不调工具、实盘请求一句拒绝不出卡、回复不以“好的/好,”开头;②用户本人的下单请求一律出方案卡(打字或语音),execute_simulation_trade 仅限用户明确要 AI 自主执行——此前打字回合在有网关时会直接执行;③update_preferences 描述加口语→键映射(说话快点/回答短点/默认两手/别挂单/别念新闻/提醒成交/换男声),highlight_ui 限定界面元素;④语音意图词表补口语:太亮了/太暗了→主题,字太小/字大了→字号,换个颜色→深浅互换并提示“换涨跌色”,持仓那个页、下单的地方、把刚才画的擦了、帮我开个新的聊天、把设置打开、回到K线;“全平/清仓/撤单”二字不再当寒暄;⑤语音/快答回合可选低温度 AI_TRADER_VOICE_TEMPERATURE(评测用 0.2);⑥fake 数据源持仓补今/昨仓字段(批量平仓可在 fixture 上出卡)。(执行:Claude Code,Claude Opus 5,2026-09-19)
- 修 deepseek-flash 的工具选择(09-18 模型评测发现,Runtime 热修):“全部平仓/清仓/把持仓都平了/平掉所有空单”的原话由 message_context.close_all_request 确定性识别,语音与打字回合都在指令前加“本轮请直接用 create_close_batch_proposal(不要先读持仓、不要逐个下单工具)”;create_close_batch_proposal 工具描述补触发词与反例(“平掉沪金两手”是单个平仓)、create_trade_proposal 描述限定“平一个具体持仓”;语音指令明确讲图只用 get_market_analysis(必要时加 get_chart_bars)、查持仓只调 get_positions。裸模型回归(~/ai-trader-release-artifacts/voice-v12/model-eval/bench-after-deepseek.log):deepseek-flash 工具正确 9/15 → 15/15,首 token 中位 1.86 → 1.52 s;评测报告 model-eval/REPORT.md(结论:不切 GLM-5.3-FlashX)。只发 Runtime。(执行:Claude Code,Claude Opus 5,2026-09-18)
- 实时语音 V1.2(用户真机通话 015c71f4 三条反馈,Runtime 热修):①“细节在对话里”几乎每轮都念——只有跳过了表格(“表格我放对话里了”)或 ≥80 字正文(“后面的我放对话里了”)才补一句,空行/折叠块/短尾不算;②“简单操作说三遍”(豆包“好”→ 过渡句 → 正文)改为单一声音:Runtime 自己应答的回合(delegate / 意图 / 确认 / 放弃)指令豆包不出声,它一开口即 response.cancel(其文字与音频不进对话与播放),Runtime 提交的语音不受影响;过渡语仍只在 3 s 无首句时念一次且不重叠;③简单界面操作零 LLM 快路径 voice_intents.py:ASR 定稿先匹配固定意图表(打开/关闭设置、设置分类、主题深/浅/跟随、交易台/复盘、开关对话/阶梯/下单台/持仓/策略面板、AI 盯盘/对话页、持仓/委托/平仓记录分页、帮助、周期、返回原图、清除 AI 标注、新对话、“切到 XX 合约”经合约目录唯一解析)→ 直接发 UI 命令等回执并念一句结果(时间线 routed by=intent、intentApplied),回执非 applied 或解析不唯一才交给 AI。pytest:三种结尾形状、意图表每类一条、run_intent 回执/合约解析/回退、脚本化上游的单一声音端到端;harness 重放见 ~/ai-trader-release-artifacts/voice-v12/。只发 Runtime。(执行:Claude Code,Claude Opus 5,2026-09-18)
- 修正(P0,用户 09-18 晚网页版报“AI 打不开设置、换不了颜色,之前可以”):客户端心跳 POST /api/ui/pulse 的 state.highlights / chartAnnotations 之前复用命令输入的严格 schema(AI 标注 v2 把标签上限收到 8 字、每屏 6 条),仍拿着 v1 标注(标签 ≤40 字、≤20 条)的旧网页客户端每次心跳都 422(生产日志:该 IP 40 分钟 68 次 422、1 次 200),窗口从未登记,AI 的界面命令找不到窗口。Runtime:上报的图层状态改为宽松记录(状态是事实不是请求,只保留数量上限),命令输入保持严格;pytest 用 v1 形状与 1.6.6 网页端真实 pulse 形状(preferences、settings 上下文含 Notification 四态与空快捷键表)覆盖。客户端:心跳连续 3 次 422 时工作区显示“界面命令不可用:登记失败(原因)”并写桌面 frontend.log(logDesktop 抽成共享模块),恢复 200 后自动消失;vitest 覆盖。(执行:Claude Code,Claude Opus 5,2026-09-18)
- 桌面侧接入设置第 2 步的两项(不发版,随 1.6.6):①「导出诊断日志」在桌面版读取本机 frontend.log 尾部(≤200 KB,Tauri 命令 desktop_frontend_log)并经另存为对话框保存(desktop_save_text_file,tauri-plugin-dialog),网页版保持浏览器下载;②桌面原生通知:WebView 无 Notification API,成交/撤单/急停/简讯按 notify 偏好经 tauri-plugin-notification 投递到系统通知中心(desktop_notify),设置 → 通知的权限状态由壳回答(desktop_notification_permission,“允许桌面通知”触发系统授权),提示音仍为 WebAudio。能力表 / 内置说明 / SKILL 同步。桌面系统通知弹出未真机演示(桌面只连云端 owner Runtime,无害事件源缺失),1.6.6 上线后以首个成交/撤单事件确认。(执行:Claude Code,Claude Opus 5,2026-09-18)
- 设置重做第 2 步 客户端侧(Fable 规格 §5,Runtime 见上条):八类页里加账号偏好行,全部用第 1 步的五种控件,改一项即 PUT /api/preferences(带 ?version= 锁,409 时重读并提示再改一次,写入串行避免步进器自撞;未连接时不可改)。语音:音色(列表来自 Runtime,写 voice.voice)、语速、说完判停 0.8–3.0 s、口头确认时限 5–60 s、成交播报、简讯播报、通话中自动画图。图表:默认周期(打开软件时生效,当次已手动切过不改)、K 线样式 蜡烛/美国线、涨跌颜色 红涨绿跌/绿涨红跌(html[data-updown=intl] 同时换 K 线与面板的 --market-up/down,K 线颜色改为读语义变量而不再写死绿涨),KD/MACD 参数(kd()/macd() 参数化)、副图开关(KD/MACD 指标开关同时写 chart.subPanes)、AI 标注默认显示与自动清除分钟。交易 → 下单默认:默认手数(下单台起始手数)、默认价格方式、平今平昨、语音下单免口头确认(仅模拟盘,写 voiceOrderConfirm=false)、闪电下单(阶梯点卖档 = 买多草稿、点买档 = 卖空草稿,价格进下单台仍需确认)。账户与模型 → 对话:回复风格、自动读屏、发送键(Ctrl/Cmd+Enter 时 Enter 不发送)。通知 → 桌面通知:权限状态与“允许桌面通知”(网页版 Notification API)、成交/撤单/急停/简讯开关、提示音(WebAudio 两音,打开时试响)、休市提醒。数据与隐私:会话保留天数、清除本地缓存(保留设备 id / 上次用户名)、导出对话 JSON/Markdown、导出复盘 JSON/Markdown(/api/trade-review)、导出诊断 JSON(环境 + 最近一次语音通话事件时间线;桌面端 frontend.log 内联导出待桌面端接入)。快捷键页可录制(冲突/保留键拒绝)、恢复默认,绑定存本机,快照 settings.shortcuts 可见,删除“当前快捷键固定”描述。界面命令 preference: {key, value} 在客户端落地(异步写入,回执按回读文档判定),快照 preferences 整份上报,settings.preferencesVersion / preferencesStatus / notificationPermission 补充;覆盖核查规则、能力表(逐行)、内置说明(设置与外观 / 账号偏好设置)、SKILL 同步。vitest(偏好 hook 版本锁/409/串行、快捷键、通知、matches、各类页回执与消费方)+ e2e(每类页一条命令回执)。网页与 Runtime 先发,不发桌面。(执行:Claude Code,Claude Opus 5,2026-09-18)
- 修正:AI 对话页“新对话 / 历史对话”按钮和输入框在某个会话里永久不可用(用户 1.6.5 网页版报告;本地复现:对正在流式回答的一轮点“停止”后,占位 message.delta 已落库而没有收尾的 message.completed,该轮永远处于“回答中”,chatBlocked 一直为真,刷新也不恢复)。Runtime:取消/失败的非门控回合补发带 ended 标记的收尾消息(“已停止。/未完成。”,历史重建不把它当回答);客户端:任务结束(cancelled/failed)或错误事件到达时把该轮标为完成,旧会话的历史也随之解锁。
- 语音引导词表(Runtime):通话中引导进行时(窗口 tour.active)“下一步 / 继续 / 往下”→ tour next、“上一步”→ prev、“结束引导 / 不看了 / 结束”→ stop,Runtime 直接发界面命令并念出该步 say(走既有 speak 提交);没有引导时这些词照常路由(“下一步”仍交给 AI)。单测 + 一段“开始引导 → 下一步 → 上一步 → 结束”重放。只发 Runtime。(执行:Claude Code,Claude Opus 5,2026-09-18)
- 实时语音 V1.1 流式播报(用户 1.6.5 真机通话 dacc2997 反馈):①AI 回答边生成边逐句念出——Runtime 订阅语音回合的文本流,第一段按句号/问号/换行切句(首句过长在逗号处先开口)逐句 speech_text_buffer.commit,上一句音频送达后念下一句;表格/代码块/后续段落不念,末尾念“细节在对话里”;取消二次概括(spoken 即第一段原文),语音回合指令改为“第一段口语直答 ≤5 句,细节表格放后面”,被门控的回合在读过实时工具后也即时流式;②抢话覆盖:上一轮未完或正在播报时说下一句 → 停止播报(内容留对话,时间线 toolResultSuperseded)、新一轮带 followUp“优先答最新一句”指令;③“关闭语音/结束通话/挂断/不说了/退出语音”由 Runtime 直接挂断(一句道别后 session.close,圆圈回待机),“停/等一下/别说了”只打断播报——都在 route_utterance 判定并有单测;④语音回合一律低推理档;⑤豆包不再声明 delegate 工具(1.6.5 回放里它连调三次改写过的 delegate,把回合挂住 20 s),只保留 confirm / cancel / read_screen;⑥首句 3 s 内没到时 Runtime 念一句按原话关键词拼的过渡语(“我看一下KD和MACD”,≤12 字,只念一次,抢话追问不念,时间线 interimSpoken);⑦讲图/指标/形态类问题走 get_market_analysis + get_chart_bars(秒级),不再调决策上下文;标注只在用户要求标注/画图/讲解某段走势时调 annotate_chart,且一轮一次给全(工具描述与语音/通用指令同改)。
- AI 标注层第 ② 步 引导与教学:界面命令 tour(start 带 1–20 步 {target, label, say?, focus?},每步先执行 focus 打开表面再高亮 + 气泡;next / prev / stop;点别处只关气泡,指示器“第 n/N 步 · 上一步 / 下一步 / 结束”可点可命令,快照 tour: {active, step, total, current});入口:设置 → 连接与服务 “打开新手引导”、说明卡新主题“新手引导”内“开始引导(7 步)”,默认课程由 Runtime GET /api/app/help 的 tour 主题提供(顶栏合约 → 周期 → 主图 → AI 对话 → AI 球语音 → 下单区 → 底栏/复盘),不硬编码在组件;内置 AI 工具 start_tour(绑定对话窗口,外部 tool:start_tour),指令:“带我看看 / 教我用 / 怎么下单”生成课程,“教我看这个图”标注 + 分步讲,语音回合每步只念 say、“下一步 / 结束”发 next / stop(与流式播报的词表对接待 #216 合并后)。覆盖核查新增 tour 指示器、策略设计器内部与真实对话卡“详情”三块;vitest(tour store、matches)+ Runtime schema/工具测试 + e2e(start → next → 点别处不结束 → 指示器 → prev → stop → 坏 target 拒绝)。网页与 Runtime 先发,不发桌面。(执行:Claude Code,Claude Opus 5,2026-09-18)
- 覆盖核查首轮 4 类缺口补齐:下单区手数 −/+ 按钮加 aria-label(手数减一 / 加一);presentation: {reset: true} 恢复默认布局(等价设置→外观按钮,回执按 dockSide/dockWidth/positionsBar 判定);disclosure: activity-clear 清空 AI 动态卡显示(open: false 拒绝,回看用 activity-history);selectedPrice: 价格 | null 命令 + 快照字段(图表点选 / 阶梯点价 / 右键“仅填入草稿价 / 撤销选价”的等价物,只填草稿价不提交)。known-gap 表清空,能力表 / 内置说明 / SKILL 同步。(执行:Claude Code,Claude Opus 5,2026-09-18)
- AI 标注层第 ③ 步 覆盖自动核查:新增 e2e ui-coverage.spec.ts(execution config)遍历各表面的可交互控件,对照快照 controls 与 tests/support/uiCoverage.ts 的命令 / 能力 / 豁免 / 已知缺口四张表,无人认领或快照看不见即失败,已知缺口清单随补齐删除;首次运行 579 控件、4 类已知缺口(手数 ± 无 aria-label、恢复默认布局无命令、AI 动态卡清空显示无命令、候选价无命令),详见能力表文档“覆盖自动核查”。内置 AI 指令加“用户提到‘这个 / 屏幕上 / 现在显示的’先读本对话窗口快照再答”(打字与语音回合),内置说明与 SKILL 同步。不发版。(执行:Claude Code,Claude Opus 5,2026-09-18)
- AI 标注层 v2(用户 1.6.5 真机反馈“标注太乱、全挤到一起;多空点位应像画笔一样精准到一个点,压力位才用线或面”,以及语音“你能在 MACD 上画吗”):新增 point 标注(精确到 time+price,role: buy|sell|close|note 决定上三角/下三角/方块/圆点与颜色),多空入场/止损/止盈/平仓一律用 point,hline/zone 只表示压力/支撑;每条标注只显示编号 ①②③(按 items 顺序、跨副图连续)+ ≤8 字短标签,解释放回复正文按编号讲(agent 指令同步);标签防重叠(垂直错开、离开点位时画引线)、hline/zone 标签放线/区左端图内、vline 标签放时间轴上方、可见范围外不画、同价位 hline 只留一条;同一屏(每合约)最多 6 条,超出 rejected 并由工具回 say 让 AI 精简;chartAnnotations 加 pane: main|kd|macd,副图支持 hline/vline/point/text(price 为 K/D、DIF/DEA 数值),快照 chartAnnotations[] 含 pane;切周期标注按时间戳保留。能力表、内置说明(chart / ui-commands)、SKILL 同步;vitest + e2e。网页与 Runtime 先发,不发桌面。(执行:Claude Code,Claude Opus 5,2026-09-18)
- 发布分档改规则(不涉及用户可见行为;用户 2026-09-18 决定“改动先在网页版测,攒够再发正式桌面客户端”):release:all --scope auto 的 desktop 段只在自 desktop base 以来版本号变了(合并过版本准备 PR)时才跑;客户端改动在版本未变时只发 web(+runtime),桌面相关改动列为 deferred 并打印文件数,下次版本准备一并带上;新增 --desktop 强制桌面段,--scope full 仍为三段全发。
v1.6.52026-09-18
- AI 标注层第 ① 步(用户 09-18 拍板,Fable 规格):AI 能“指给用户看”和“在图上画给用户看”。新增界面命令 highlight(界面目标脉冲/描边高亮 + 气泡说明,最多 3 个,超时或点击消失,target 取快照 context.highlightTargets)、chartAnnotations(主图 AI 标注:水平线/区间/趋势线/竖线/圆圈/箭头/文字,每条带 label 与语义 tone,每合约 ≤20 条、按合约分开、主题变色;hline 走价格线、标签画在图内,其余为 lightweight-charts 自定义 primitive)、chartFocus(把图滚到时间段,null/“返回原图”回到最新);快照新增 highlights[]、chartAnnotations[]、chartFocus、context.highlightTargets。能力目录新增 tool:get_chart_bars(可见区间或最近 N≤300 根 OHLCV + 已开启均线逐根值 + 确定性摘要,时间为秒级时间戳)、tool:annotate_chart、tool:highlight_ui(内置 AI 同名工具,绑定本次对话窗口,同 #193 约束);内置 AI 指令改为“讲行情先画后说、每条标注带 label、讲完不自动清除”,语音回合 spoken 指着图说。图表右键新增“让 AI 讲讲这段”(可见区间作为上下文发一条对话)与“清除 AI 标注(n)”。能力表、内置说明(chart / ui-commands)、SKILL 同步;vitest + e2e 覆盖命令→标注/高亮出现→快照可见→清除。(执行:Claude Code,Claude Opus 5,2026-09-18)
v1.6.42026-09-18
- 对话流去掉两张卡(用户 1.6.3 真机反馈“没必要存在,也没啥用;想告诉客户 AI 在思考应该用流式输出”):①AiProgressCard 不再进入对话——回合进行中靠流式气泡表现,气泡下只有一行随步骤变化的状态(“正在读取行情…”,不显示工具名)和“停止”,回合结束即消失,不留“已完成 / 耗时”;步骤明细收进气泡下默认收起的“过程 · N 步”折叠(仍是 disclosure: progress-steps,按该轮 task id)。策略设计器的生成进度卡不变。②“未经实时数据核验 · 安全提示”整段卡删除:Runtime 只在回答断言了行情/新闻/账户数字且本轮没读任何实时工具时发一条 warning(“本轮未读取实时数据”),闲聊不发;客户端把 warning 事件渲染为气泡下一行灰色脚注(severity=danger 显示“已阻止 · …”),“回答被截断”同理。合成回测卡结论文案“候选参数通过合成回测门”改为“合成回测通过,可创建模拟部署候选 / 合成回测未通过,不建议部署”。
v1.6.32026-09-18
- 界面命令补全:AI 对话页的“历史对话”列表是折叠 disclosure: chat-history,打开后快照 chatHistory 列出会话,chatSession: {sessionId} 切换、chatSession: {new: true} 新建;chatSessionId 进快照。此前外部 Agent 用 chat_send 新建会话后无法让窗口显示它(1.6.1 回读时发现)。
- AI 球合并(用户 09-18 拍板):右下角“AI 动态”球与语音圆圈合成一个可拖动的 AI 球(沿用位置记忆与避让持仓栏)。单击接通/挂断语音(出错再点重试;Runtime 无语音密钥时单击开关动态卡);外观分层:待机呼吸、策略后台操作或语音请求处理中弧线慢转、听你说光环随音量、AI 在说五竖条、有未读动态右上角红点;AI 动态不再靠点球——新操作/行情提醒/资讯到达时动态卡从球上方自动弹出约 8 秒(通话中照弹,鼠标移入即钉住),长按/右键菜单:静音、挂断(通话中)、切文字、AI 动态。aiActivityCard 与 voice-call/voice-mute/voice-menu 命令落在同一表面,快照含球的状态/未读/卡开合;删除独立 VoiceOrb 与老球按钮;e2e voice-orb.spec 改为 ai-orb.spec(含 aiActivityCard 命令);能力表两行合一,内置说明与 SKILL 同步。(执行:Claude Code,Claude Opus 5,2026-09-18)
- 语音回答“只说几个字”(用户 1.6.3 通话 4655016f:“你还有什么能力”只念 3.2 s、“哪几类”1.0 s):口语版规则改为——去掉 markdown 后不超过 200 字的回答直接照念(不再二次概括);更长的才概括,上限 160 字 / 5 句并要求完整给出要点(列举类逐项说出),超出按句截断;概括请求不再带推理(deepseek-flash 在 minimal 推理下把 320–900 token 预算全花在思考上、正文为空,之前静默回退成第一句),失败或为空时改为照念回答本身(≤400 字按句截断),语音侧缺 spoken 时同样念回答而不是首句。harness 重放三句:27.3 s / 31.4 s(要点完整)/ 8.2 s。
- 通话中点“新对话”后语音仍进旧会话:delegate 每次取调用窗口当前快照里的 chatSessionId(1.6.3 起进快照)作为目标会话,没有才回退 hello/最近会话。(执行:Claude Code,Claude Opus 5,2026-09-18)
v1.6.22026-09-18
- 对话回复正文渲染修正(1.6.1 云端回读发现):普通回复此前按纯文本一整段显示——模型写的表格露出 | 合约 | 方向 | 竖线和 |---| 行,段落与换行全部塌成一段。现在按段落与换行显示,| … | 块显示为紧凑表格(数字不折行),、#、列表符号去掉,结尾的“来源”段折叠为“参考依据”(界面命令 disclosure: advice-sources)。不引入 markdown 库,只覆盖回复契约允许的写法。