feat(providers): LLM seam 改造 Stack 合并版——统一流式入口/重试策略/拦截器注册化/轨迹账本 + 生产构建修复 - #605
Open
AlphaCatMeow wants to merge 8 commits into
Open
feat(providers): LLM seam 改造 Stack 合并版——统一流式入口/重试策略/拦截器注册化/轨迹账本 + 生产构建修复#605AlphaCatMeow wants to merge 8 commits into
AlphaCatMeow wants to merge 8 commits into
Conversation
为 LLM seam 改造提供行为等价判定基准: - wire-payload-golden:anthropic-messages / openai-completions / openai-responses / google-generative-ai / deepseek-responses 五协议 固定输入下的完整请求体逐字段锁定(thinking 档位、工具、缓存断点、 text-only 双形态),走真实 pi-ai stream() 与全部 payload 中间件, onPayload 链尾截获后中断,零网络。 - transport-golden:prepareProviderRequest 完整输出快照(反代 URL、 全量头集、base64 覆盖包解码断言、鉴权头排除、full URL 模式、 useSystemProxy 开关),并锁定 failover 逐候选传输配置独立性 (主选走代理+备选直连互不泄漏,双向拓扑)。 零生产代码改动。
将 streamByApi.ts 的五协议 switch 原样搬移为 service/ 下的双适配器 (piAiAdapter 承接 4 条 pi-ai 协议,deepSeekAdapter 承接 deepseek 原生), 经 api→adapter 注册表分发;新增统一流式入口 llm.stream(),携带仅 dev 构建生效的请求信封冻结与一次性分发不变量。streamByApi.ts 收缩为保留 原签名的兼容壳(分发针孔),agentRunner 与 textOnlyRuntime 共 5 处调用 换用统一入口。行为严格等价:PR-0 两个 golden 套件(13 用例)零修改 通过;新增 seam 单测 8 用例覆盖注册表分发、错误文案逐字等价、dev 冻结开关与双入口 wire payload 等价。零 Rust 改动、零镜像文件改动。
将流内重试策略的归属权从全局常量反转到供应商配置(PR-2,stack 第 3 层): - 共享真源 agent-ui settings 新增 CustomProvider.retryPolicy?(off | custom+maxRetries),maxRetries 为首次失败后的重试次数(不含首次请求, 钳位 1..10)。normalizeProviderRetryPolicy 保证非法/缺省一律落 default 且不落字段,旧配置零迁移;default 态在持久层不存在。 - agent-gui 运行时经 ProviderRuntimeConfig 唯一构造点透传策略,新增 resolveStreamRetryConfig 把策略解析为 withStreamRetry 选项(off → disabled,custom → maxAttempts=maxRetries+1,缺省 → 空对象落全局默认)。 agentRunner 与 textOnlyRuntime 两个 streamRetry 注入点展开合并,回调 语义与 buffer-until-commit 不变;failover 逐候选使用各自 runtime 的 策略。streamRetry.ts 与协议适配器零改动, DEFAULT_STREAM_RETRY_MAX_ATTEMPTS 降级为未配置时的默认值。 - 共享 settings UI(ProviderModal/ProviderModalView)请求面板新增 流式重试三态控件(默认/关闭/自定义次数),GUI 与 WebUI 镜像同源; UI 展示镜像常量 PROVIDER_RETRY_DEFAULT_MAX_RETRIES 与运行时真源的 一致性由单测锁定。 - 新增 provider-retry-policy.test.mjs(13 用例):归一化矩阵、构造点 透传、消费方合并语义三种 mode、failover 候选策略独立、口径换算。 PR-0 golden 两套件与既有 stream-retry 套件零修改通过。
把 payload 中间件的组织权反转到 LlmService seam(PR-3,stack 第 4 层)。 未注册任何自定义拦截器时行为与 PR-2 严格等价: - 新增 service/interceptors.ts 注册表:具名 PayloadInterceptor (name + intercept),usePayloadInterceptor / llm.use() 返回幂等 dispose,同名重复注册抛错;组合链带失效缓存,注册/移除时重建, finalize 热路径(agentRunner 每轮、textOnly 每次调用)零重组开销。 - payloadPipeline.ts 的 10 个中间件原样包装为具名默认拦截器,模块 初始化时一次性安装,顺序与注册化前数组逐项一致(顺序即协议正确性 的一部分,由顺序快照测试锁定)。payload-debug-logging 钉住链尾: 自定义拦截器插入默认之后、链尾之前,自定义改动仍被调试日志观测。 - finalizeProviderStreamOptions 改为从注册表组合执行;agentRunner 与 textOnlyRuntime 两处调用零改动,composePayloadMiddlewares 等 既有导出保留,10 个中间件实现文件零改动。 - 新增 llm-interceptors.test.mjs(8 用例):默认顺序快照(10 个 名字)、llm.use 同源、params 可见与 options 变换、插入位置、链尾 观测不变量、dispose 幂等、同名抛错、与旧数组组合逐字段等价(多 形态参数矩阵)。golden 两套件、seam、retry-policy、stream-retry 及中间件相关回归零修改通过。
seam 改造第五层(PR-4):流内重试与跨供应商 failover 此前只喂 UI 临时状态, 审计线索随进程消失。本层把三类事实落入轨迹账本,重启后仍可回放: - 线格式新增 failover(from/to/ti/err)与 transport(p/o/sp/fu/hn)事件; retry 增补 p(候选标签)与真实退避时长——failover 下各候选的重试可区分 - transport 快照只采头名与路由标记,逐候选独立记录,审计"主选带 use-system-proxy、备选不带"的传输装配独立性;头值一律不采集 - recorder 全部 err 出口接入密钥洗涤(URL query key/Bearer/已知 key 形状), 供应商报错回显的凭据不落盘;测试含反向断言 - withStreamRetry 退避提前计算并经 onRetry 上报整毫秒值——上报的就是实际 要睡的值;取整同时关闭浮点往返身份漂移(serde_json ULP 误差会让同一条 重试在收敛账本里出现两份) - agent 模式 failover 首次落账(此前仅 onToolStatus);text 模式 failover 从误记 noteRetry 改为独立 failover 事件,fromLabel/toLabel/targetIndex 不再丢失 - OptionsTab/OverviewTab 渲染三类新行,中英文案;旧读端对未知事件种类 按既有收敛路径静默忽略,线格式只增不改
…tors, trajectory-events)
1. style-to-js 是纯 CJS 包(无 exports 字段),与 rolldown 生产构建的 interop 判断不兼容,通过 pnpm.overrides 固定到 2.0.2 规避。 2. SkillCategoryControls.tsx 中 STORE_CATEGORY_OPTIONS 在模块顶层对 跨 chunk 导入的 CLAWHUB_CATEGORY_SLUGS 做 spread 展开,在激进代码 分割(vite.config.ts maxSize: 450_000)下偶发早于目标 chunk 初始化 完成执行,读到 undefined 抛出 TypeError。改为惰性求值+memoization 规避。 两处均只在生产打包后复现,dev 模式因不做代码分割而无法触发,通过 WebView2 CDP 远程调试(--remote-debugging-port)连接安装后的实例, 逐步定位 console 异常与 DOM 渲染状态确认根因。修复后重新构建安装包, CDP 诊断 EXCEPTIONS_COUNT: 0,截图确认界面完整渲染。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #591, Closes #593, Closes #596, Closes #598, Closes #600
概述
本 PR 是 LLM seam 改造 Stack 的合并版本,把原本 5 层 stacked PR(#590 → #594 → #597 → #599 → #601)整合为一个 PR 提交,额外包含一处生产构建下发现的界面渲染 bugfix。原 5 层 PR 保持 Open 状态作为改动记录,本 PR 合并后会一并关闭。
Stack 各层职责(自底向上,每层在上一层的行为等价基线上推进):
llm.stream()与协议适配器注册表,streamByApi.ts收缩为兼容壳每层改动前均以上一层 golden 快照为基线验证行为严格等价,改动仅发生在各自声明的范围内。
追加修复:生产构建安装包界面空白
Stack 完成后,本地重新走生产构建(
tauri build)+ NSIS 打包 + 安装验证时发现:dev 模式运行正常,但打包安装后界面完全空白(AppErrorBoundary捕获渲染错误)。通过 WebView2 原生 CDP 远程调试连接安装后的实例,定位到两处独立问题,均已修复:style-to-jsCJS/ESM interop 不兼容:该依赖是纯 CJS 包(无exports字段),与 rolldown 生产构建的 interop 判断存在冲突,通过pnpm.overrides固定到2.0.2规避SkillCategoryControls.tsx中STORE_CATEGORY_OPTIONS在模块顶层对跨 rolldown chunk 导入的CLAWHUB_CATEGORY_SLUGS做 spread 展开,在项目的激进代码分割配置(vite.config.tsmaxSize: 450_000)下,读取时机偶发早于目标 chunk 完成初始化,触发TypeError: xt is not iterable。改为惰性求值 + memoization 规避两处问题都只在生产打包后复现,dev server 不做同等代码分割因而无法触发;本仓库 CI/既有测试套件也未覆盖"安装后启动"这一路径,因而 5 层 PR 各自的验证均未发现。
验证结果
继承自各层 PR 的自动化验证(详见各原 PR 描述,此处不重复罗列用例明细):
pnpm --dir crates/agent-gui build✅ /test:frontend✅pnpm --dir crates/agent-gateway/web build✅ /test631/631 ✅cargo check --tests✅;全 diff 不含非预期的src-tauri/**改动;git diff --check✅本次追加验证(生产构建 bugfix):
tauri build(release profile)+ NSIS 打包 + 静默安装TypeError两枚(style-to-js interop 报错 → 修复后消失;xt is not iterable→ 定位并修复后消失)EXCEPTIONS_COUNT: 0,console 日志干净(仅 4 条正常 MCP bridge 初始化日志)Page.captureScreenshot截图确认界面完整渲染(侧边栏、工作空间列表、欢迎语、快捷操作卡片、消息输入框),与 dev 模式视觉一致(见下方截图)人工验收结果
继承自各层 PR 在 Windows Tauri 调试客户端的人工验收(详见各原 PR):
补充:本次生产安装包验收,确认修复后界面正常渲染,无 JS 异常。
Screenshots / preview
生产安装包修复后界面(WebView2 CDP
Page.captureScreenshot截图,修复前此处为空白):LLM seam 骨架(原 PR-1,#594):
Golden 基线(原 PR-0,#590):
流式重试三态控件(原 PR-2,#597):
拦截器注册化(原 PR-3,#599):
轨迹账本(原 PR-4,#601):
关联 PR
原 stacked PR:#590、#594、#597、#599、#601(本 PR 合入后关闭,改动历史保留在各自分支)