Repository navigation
Conversation
目录未声明 supportsImageInput 的自定义模型会在客户端被 Pi 拒收图片,且报错指引的开关并不存在:\n- 设置 → 模型 → 高级设置新增「图片输入能力」三态声明(跟随供应商/支持/不支持),\n 写本机目录 override(preset 连接仍跟随官方目录),新开专用 IPC(不进 device-link allowlist);\n- Pi 运行期能力对账:会话启动后目录才声明能力时,切模与发送带图消息两处都会\n 就地刷新会话快照(热写 models.json + switch_session 重载),补上即放行,补不上仍\n fail-closed;全分支 debug 日志可定位。\n- 顺带修正高级抽屉「上游最大上下文」的展示来源(未验证的 200K 展示兜底不再冒充\n 上游窗口)与上下文上限提交在途时闪回旧值的问题。 Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
[Medium impact] 本轮未发现新增的合并阻塞问题。
|
对抗审核与 PR review 的合并修复:\n- 对账里的 switch_session 必须重放当前路由 + get_state 读回(否则会话内切过模的会话会被\n 静默拽回启动路由:同路由 no-op / 发图 / steer 都不再打 set_model);整段对账进会话串行链,\n 避免与心跳 setModel、compact 交错。\n- 对账改为双向(先对账再信任快照):声明从「支持」改成「不支持」时旧快照不再放行图片。\n- 回合运行中不重建子会话(会打断在跑的回合),只对齐宿主快照并置 pending,空闲时补重载。\n- 声明覆盖该行全部引擎 id(桥接两端 id 不同:openai 行 codex=gpt-5.6-sol、pi=chatgpt/gpt-5.6-sol),\n 此前只写主展示引擎的 id,运行期读不到、UI 却显示已声明。\n- SET 拒绝网关(xd)目标;目录成员校验移入写队列(与价格/上下文上限同一顺序);\n value=null 清陈旧 override 不再要求成员校验。\n- store:按 agent 算有效声明、清掉遮蔽 base 的 perAgent 残留;手改文件里会被 sanitize\n 丢弃的 patches 条目改为显式拒绝写入(不静默删除)。\n- hook:写在途时忽略广播触发的回读(旧值会顶掉写入回声)、加 owner 代次守卫;\n 抽屉:超限告警按 max→已验证窗口同一来源、提交代次化(旧提交不再清新状态)。\n- 对账失败文案本地化(新增 PI_IMAGE_CAPABILITY_REFRESH_FAILED)并补 5 语;\n PI_CATALOG_RELOAD_UNCONFIRMED 文案不再假定「切换模型」场景。\n- 新增测试:路由重放、反向对账、多引擎 id 写入、perAgent 残留、sanitize 丢条目拒绝、\n 写在途广播、owner 守卫、抽屉目标覆盖 pi 侧 id、已验证窗口超限告警。 Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
|
@greptileai review |
第二轮对抗审核的修复:\n- 路由重放改为「先 get_state 读回、读回已等于当前路由就不发 set_model」:spawn 能靠 custom\n model id 跑在 Pi 自带目录没有的路由上,对这种路由重发 set_model 会被 Pi 拒,而重放失败\n 会 terminate 整个任务 —— 只改一个能力声明就杀掉正在跑的任务。读回确实不同才重放,且\n 重放被拒/读回不匹配都是 fail-closed 终止(子进程确实跑在错路由上,静默发错模型更糟)。\n- 宿主快照已改、子进程还没加载(回合在跑,重载被延后)时不再放行图片:此前会放行给一个\n 仍按旧清单判定的子进程,用户看到的是子进程的报错/无图回答。改为抛可重试的\n PI_IMAGE_CAPABILITY_REFRESH_FAILED。\n- 会话快照里没有该模型行(启动后才新增的 BYOM/目录行)时显式跳过:写盘是空操作却会置\n pending、触发有终止风险的重载,而准入门读的快照始终没变(声明永远不生效)。\n- 新增的 PI_IMAGE_CAPABILITY_REFRESH_FAILED 接进 ErrorBanner(此前只在模型切换 toast 路径\n 本地化,对话里显示的是中文原文),两种码不再互相误判。\n- store 的「拒绝丢掉手改条目」改用独立错误类型,IPC 映射成 PRECONDITION_FAILED 并把指引\n 带给用户(不再退化成笼统的保存失败)。\n- hook 写在途时跳过回读只对同一 target 生效:否则写 A 行后立刻打开 B 行,B 的回读被跳过、\n 界面永远停在 loading(显示成「跟随供应商」且点击无效)。\n- 新增测试:spawn-only 路由不重放/不终止、重放被拒终止、非 no-op 切模落在目标模型、\n 新增行的跳过、两码互不误判、跨 target 回读不被吞、loss guard 的错误类型与 IPC 码。 Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
Greptile 第三批意见的处置:\n- 同一行各引擎的声明可能不一致(手工改文件、或旧版只写主展示引擎键的存量数据):读回\n 此前取「第一个非空」,于是 UI 显示主展示引擎的值、运行期 Pi 读另一键 —— 显示“支持”\n 而 Pi 仍拒收图片。现在展示值优先取运行期真正消费该能力的引擎(Pi)那一侧,并在不一致\n 时回 diverged。\n- 抽屉的同值 no-op 会在分叉时把「重选当前项」挡掉,用户无法从 UI 修复分叉。diverged 时\n 放行写入,把各引擎键写回一致;未分叉时仍然跳过空写入(不引入多余的全量目录刷新)。\n- 新增测试:分叉时展示 Pi 侧值 + diverged、各键一致时不标分叉、diverged 时同值可写入\n 修复、未分叉时同值仍为 no-op。 Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
zyjisdog
left a comment
There was a problem hiding this comment.
第二轮独立对抗审核(对上一批修复本身)
审核对象:44c6a3fbe(第一轮 review 的修复批次)。结论:修完 P0 再合,已全部处理并推送 c98098750。
P0(已修)
路由重放会对 spawn-only 路由发 set_model,失败即终止整个任务。 本文件自己写明「spawn 能靠 custom model id 跑在 Pi 自带目录没有的路由上,重复 set_model 反而 fail-closed」(switchModel 开头同路由 no-op 不变量),而上一批的路由重放是无条件 set_model + 失败 terminate —— 用户在 SuperGrok 这类路由上改一次「图片输入能力」,下一次同步点就会把正在跑的任务杀掉。修法:switch_session 后先 get_state 读回,读回已等于当前路由就不发 set_model(这正是 spawn 路由这一类);读回确实不同才重放。重放被拒/读回不匹配仍 fail-closed 终止(子进程确实跑在错路由上,静默发错模型比终止更糟)。
P1(已修)
- 回合延后期间把图片放行给旧清单的子进程:延后只对齐宿主快照,而准入门读的就是这份快照 → 立即放行;子进程 models.json 还是旧值。改为 pending 且本次需要该能力时抛可重试的
PI_IMAGE_CAPABILITY_REFRESH_FAILED(不再假装已生效)。 currentSpec === undefined(启动后才新增的模型行)假装对账成功:写盘是空操作,却照样置 pending + 触发重载,而快照始终没变。改为显式跳过 + warn。- 新错误码不会在对话里本地化:
ErrorBanner只特判了PI_IMAGE_INPUT_UNSUPPORTED,新码走兜底显示中文原文。已补同型分支(isPiImageCapabilityRefreshFailedError)并加「两码互不误判」测试。
P2(已修 / 已知)
- 已修:hook 写在途跳过回读改为只对同一 target 生效(否则写 A 行后立刻打开 B 行,B 卡在 loading 且点击无效);store 的 loss guard 改用独立错误类型 → IPC 映射
PRECONDITION_FAILED并把「先修正该文件」的指引带给用户。 - 已知并接受:读路径「取第一个非空」对存量单键条目(只写了一个引擎 id)仍可能 UI 显示已声明而运行期拒收。该状态只可能由本未合分支的旧写法产生,外发数据不存在;多引擎写入已保证新写入不再产生该状态。
- 测试缺口:回合运行中的延后分支缺少自动化用例 —— 该测试文件的 harness 没有事件注入通道(
ctx.isStreaming由 translator 事件驱动,rpc-client 被整体 mock),补测需要扩 harness。已用 P1-1 的分支守卫(pending + supportsNow → 抛错)覆盖逻辑,但未做端到端断言。
验证
pnpm test:unit:related EXIT=0(desktop/maker-core 全 PASS);maker-core 与 desktop typecheck 0 错;check:i18n-glossary ✅;check:design-inventory ✅。新增测试 7 条:spawn-only 路由不重放/不终止、重放被拒终止、非 no-op 切模落在目标模型、两码互不误判、跨 target 回读不被吞、loss guard 错误类型与 IPC 码。
…undeclared Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
|
已并入 upstream/main(45 commits,含 #4854「未知图片能力默认按支持处理」), 冲突点的处置(
验证: |
|
@greptileai review |
Greptile 第四批(两条 P2)的处置:\n- 写 A 未完成 → 切 B → 切回 A:A 的首次读取当时被跳过,旧写入回声又被 generation 守卫\n 丢弃,界面会永远停在 loading 占位(显示成「跟随供应商」且点击无效)。现在写入落定时若\n 回声丢失、且用户又回到同一行,补一次读取(用户停在其他行时不补 —— 那一行 key 不同,\n 本就没被跳过)。\n- store 拒绝写入时给出「先修正 model-catalog-overrides.json」的指引,但 hook 只回 false,\n 抽屉只显示通用「保存失败」——用户反复失败却看不到唯一的修复方式。现在 hook 暴露\n errorReason(去掉 [CODE] 机器码前缀),抽屉用带 {{message}} 的文案提示;无原因时仍是\n 原通用文案。5 语同步新增 saveFailedWithReason。\n- 新增测试:切走再切回补读(不补读则停在 loading)、errorReason 去前缀、抽屉带原因提示。
Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
|
@greptileai review |
upstream 新增的设置面板文件(makecindy#4813 Cindy Make 等)让 desktop.settings 的裸圆角计数 717 → 718;\n合并后 GENERATED 区块与源码不同步会让 scripts/__tests__/design-inventory.test.mjs 的\n「CLI --check 在当前台账上通过」失败(Windows/Linux 两个分片都红)。按设计门禁要求\n重算台账(只改这一个统计单元格,人工区保留)。 Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
CI 红的两条根因(已定位,一条已修,一条在 upstream/main 上)① 已修:
|
|
这条 PR 需要维护者确认后才能继续自动审查和合并。 当前拦截是产品 / UI:设置高级抽屉新增「图片输入」三态声明(跟随供应商 / 支持 / 不支持),图片失败文案也变了。架构面上新增两条本机 IPC,并在切模、发图时按目录声明热重载 Pi 会话。 请维护者在 PR 上 Approve;需要作者修改时请 Request Changes。讨论:#4889 |
Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
# Conflicts: # docs/design-rules/design-inventory.md
…lt timing) Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn> makecindy#4856 的代码块本轮自动合并成功(上次合入的 restoredConfirmed 并集已在基线里),只剩 design-inventory.md 的 surface 计数冲突,按固定口径 checkout --theirs + node scripts/design-inventory.mjs 重算。
|
@greptileai review |
Skipping the duplicate set_thinking_level also skipped the post-success state updates: an explicit thinkingEnabled carrier must clear thinkingExplicitlyOff, or the next carrier-less switch still treats the user as having explicitly disabled thinking and skips tier restore, silently re-closing what the carrier just re-opened. Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
# Conflicts: # docs/design-rules/design-inventory.md
|
@greptileai review |
Two engine keys declaring the same tier set with different default tiers (a hand-edited file leftover) were not reported as diverged, so the drawer treated re-selecting the current value as a no-op and the default-tier split could never be reconciled. Both the IPC read-back and the store divergence check now compare the default tier (undefined and null both mean unset). Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
|
@greptileai review |
上游这 206 个提交把 makecindy#6990(文件树显示被忽略目录)合了,workdir-browse / file-browser / file-browser-core / remote-file-service 全部取上游 d795c6d(此前的 hardDisabled 撤回不再需要)。<br>另修 6 处非冲突自动合并缺口(git 不报冲突、只有 tsc 能抓):makerChatStore 的 captureRunningClaudeTaskIds 被本地 makecindy#4700 重构改名为 captureReconcilableRunningTaskIds → 上游 useBackgroundBashTasks 跟着改名;gitReviewWire 补回 makecindy#4793 的 beforeContent / branchMergeBaseOid / GIT_REVIEW_MAX_JSON_BYTES;sessionContextWindow 补回 makecindy#4598 的 resolveRouteContextWindowBounds;inputError 补回 makecindy#4856 的 isPiImageCapabilityRefreshFailedError;preload 与 vite-env 补回 showIgnoredDirs(listDir + startWatch);pi/index.ts 去掉解冲突并集产生的重复 hasPendingHostOperation。<br>验证:desktop + maker-core + maker-shared + file-browser-core + remote-file-service + lizi-mcps typecheck 全过。 Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
本轮代码侧无冲突(前几轮已把 restoredConfirmed 并集与图片能力对账落到基线),只剩 design-inventory.md 的 surface 行重复。 Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn> makecindy#7011 是 makecindy#4598 的后续版本,把预算对账重构为 sessionContextWindowBudgetApplier(变更即应用、锁内重读会话行、按 live 收敛),废弃 pendingSessionContextWindowBudgetReconciles + replayPendingSessionContextWindowBudgetUnderLock。10 个冲突文件里 9 个取 PR 侧,pi/index.ts 取本地(保留 makecindy#4856/makecindy#5044 的思考档位与图片能力对账符号,PR 侧不含)。补两处 makecindy#7011 未覆盖的落地:删掉调用已删除函数的两处重放;fork.test 的 beforeEach mkdtemp 改成 await(原 fire-and-forget 让用例体里 userDataDirRef 仍为空串,预算写入点与读取点不一致,2 条 fork 预算用例随机读回 null)。验证:desktop typecheck、sessionsUpdate 110 + fork 89 + ordering/chip/budget 208 + pi-native-auto-compact 54 全过。
# Conflicts: # docs/design-rules/design-inventory.md # packages/maker-core/src/agents/pi/index.ts
|
@greptileai review |
The image capability reload and the native catalog rollback rewrote settings.json without sessionContextWindowBudget, so per-model compaction.modelOverrides got recomputed from each model's own window (falling back to 16_384) and the task-level budget silently stopped applying after a reload. Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
|
@greptileai review |
…nvalidation timing) Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
|
@greptileai review |
PR 侧那行注释少 6 个空格(它没跟上上游这轮格式化),语义与 HEAD 完全相同;msg 内容一致只留 HEAD 版。maker-core typecheck 通过。 Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
|
@greptileai review |
干净线首次重建:上游 c01d749 + 仅 OPEN PR。本 PR 自动合并无冲突。 Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
冲突仅设计台账 surface 行,按固定口径取 theirs 后重算(54 surfaces)。4 个 OPEN PR(makecindy#7328 安卓输入法发送、makecindy#7317 Orca lead 派发纪律、makecindy#7299 会话引用去重、makecindy#4856 图片能力)全部自动合并无代码冲突。 Signed-off-by: Zhang Yunjin <zhangyunjin@zju.edu.cn>
这次改了什么
摘要
让用户能在设置 → 模型 → 高级设置里,为任意一个模型声明上游目录没说清、但实际成立的模型能力,声明只落在本机
model-catalog-overrides.json,不写回 Server、不改连接配置。背景是一条真实的用户困境:目录(Server 正本 → 客户端目录)里某些模型的能力位是错的或缺失的。典型实报——
space-bunny-free被声明为「不支持思考」且六档思考档全为null,而厂商模型卡明确它是强制推理模型(reasoning_effort: none无效,档位max/xhigh/high/medium/low)。目录这么写,Pi 客户端就没有任何 thinking 通道可用,模型的推理文本只能随content通道返回、被 Cindy 当作普通 assistant 正文渲染,用户看到的是「思考被写进正文」,而不是可折叠的思考块。这个 PR 把 override 写入面从「只有读」补成「可声明」,并在两条能力上真正落地:图片输入能力(多模态)与思考档位。
变更类型
feat新功能fix缺陷修复refactor/perf重构或性能优化docs/test/chore文档、测试或工程维护范围
readModelCatalogOverrides):新增 store 写入函数、IPC handler、preload 桥、抽屉 UI 控件区;非法组合在 IPC 边界就拒,不让 sanitize 事后把整条判无效、用户看着「保存了但没生效」supportsImageInput三态(跟随 / 显式支持 / 显式不支持);运行期对账按声明决定是否拒收图片efforts+defaultEffort,三态 + 逐档勾选;Pi 侧无档位时记 warn 而非静默照发「上游最大上下文」不再拿 200K 展示兜底冒充上游窗口(按
contextWindowMax→ 已验证contextWindow→ 未声明 三级来源,第 3 条必须排除「自定义模型缺元数据时的 200K 兜底」——那个常量会让用户以为容量只有 200K,而运行期窗口其实取模型级上下文上限);上下文上限提交在途时不再闪回旧值(ctxCommitting收口)UI 变化
docs/design-rules/DESIGN.md§4 Component Stylings(Buttons):声明控件沿用同抽屉既有 dropdown 触发按钮的形态——同一控件内「状态图标 + 文案 + Chevron」的组合、rounded-full胶囊外形、hover 走--surface-hover,颜色全部走语义 token,Light/Dark 两套都不写死;disabled状态沿用同抽屉协议控件既有约定(禁用但不改 opacity),未新增视觉语言。docs/design-rules/DESIGN.md§11 Voice & Content:文案沿用既有 override 控件的「跟随供应商 / 已声明」措辞与 §11.1「动宾结构、结果点名对象」的要求,失败提示按 §11.1「错误 = 发生了什么 + 下一步」给出可执行原因(errorReason透出),五语言经 i18n key 落地。docs/design-rules/DESIGN.md§14.2 Focus Management:多选下拉勾选时preventDefault阻止 Radix 自动关闭,便于连续勾多档,键盘路径沿用 Radix 既有行为,未改 Tab 遍历。怎么验证的
自动验证
手工验证
space-bunny-free这类目录声明「零档位」但实际会推理的模型,声明其真实档位(max/xhigh/high/medium/low)→ 该模型在 Pi 侧能开真正的 thinking 通道,推理回到可折叠思考块,不再混进正文。未执行的验证
models.json的实测(reasoning: false+ 六档全null)。风险
风险分类
影响与回滚
权限 / 安全(本 PR 的关键门):override 是本机最高优先级,不加这道门就能让运行期能力偏离管理员下发的企业配置。因此写入面对两类来源拒写:
xd(Cindy AI Gateway,能力由服务端目录控制)→INVALID_PARAMSPERMISSION_DENIED,与价格 override 同一位置、同一错误码抽屉控件也一并
disabled(按钮禁用挡不住受信 renderer 直调,IPC 侧拒写是真正的那道门)。多引擎 id 双写:桥接投影两端 id 不同(如 openai 行 codex 用
gpt-5.6-sol、pi 用chatgpt/gpt-5.6-sol),override 按provider:model精确匹配。只写主展示引擎的 id,运行期真正消费该能力的 Pi 读不到、UI 却显示「已声明」。因此写入面一次写该行全部引擎 id;各引擎键分叉时读回报diverged,UI 允许「重选当前项」写回一致。恢复继承:用户把「显式不支持」改回「跟随供应商」后 override 被删、声明读回
undefined,与「目录自己标了 text-only」在读回看来相同。为此运行期新增「活动目录最终结论」钩子(readModelCatalogImageCapability),以最终 input 判定「该恢复支持」;拿不到结论则保持现状不翻转(不猜)。影响范围:仅模型能力元数据(图片输入 / 思考档位)的本机声明;不改会话数据、不改凭证、不改连接配置。
回滚 / 降级方式:删除
model-catalog-overrides.json中对应条目即回到「跟随目录」;整文件删除回到「无覆盖」。本 PR 全部逻辑在客户端,回滚无服务端残留。提交前检查
git commit -s,见 DCO)design-inventory已重跑生成器并保持最新)