Repository navigation
Conversation
…s page The delegation catalog the parent agent may pick from was only editable one service at a time, inside that service's own model dialog, so there was no way to review it. The Models page now states which configured models carry the `availableForSubagents` opt-in and edits that same flag across every service in one list, next to the image-model row. The list reuses the per-binding flag the runtime already reads instead of adding a second stored selection, so the page and the delegation catalog cannot disagree. A save re-reads the service and rewrites only the touched binding, which keeps a concurrent model edit intact, and a plugin-owned row stays read-only because `providers.update` refuses it. Specs, their zh-CN mirrors and E2E-267 describe the new surface. Refs vastsa#1736
…-row # Conflicts: # docs/spec/06-delivery/04-e2e-test-plan.md # docs/zh-CN/spec/06-delivery/04-e2e-test-plan.md
|
Reviewed in an isolated worktree: The single-source-of-truth claim holds.
So editing the flags themselves — rather than storing a second selection the runtime would have to merge — is the right call, and it avoids the classic drift where the page shows one set and the runtime authorizes another. That is the part I would have pushed back on if it had gone the other way. Edge handling matches what the runtime does. Two non-blocking notes:
Nothing blocking from my side. |
|
Heads-up: this PR is No code conflict. Both sides append to the same anchors:
Resolution that keeps both, and is what I verified locally:
After that the branch merges cleanly: I ran the merge locally and the only conflicts were those two files. Your code and tests are untouched by the conflict. One suggestion while you are in there: the E2E table is now long enough that adjacent-row insertions will keep colliding. Appending new rows at the end of the table (rather than next to a related entry) would avoid this class of conflict for future PRs. |
…-row # Conflicts: # docs/spec/06-delivery/04-e2e-test-plan.md # docs/zh-CN/spec/06-delivery/04-e2e-test-plan.md
… auth kind Review note on vastsa#1758: the eligibility check reads credential presence, not the auth-kind name, so a flow added later must not be labelled "no credential" just because this page has never heard of it. The comment states the rule and the test proves both ends of it: a stored grant counts, and a row with nothing stored really is unusable, because the runtime cannot obtain a key for it either.
|
Thanks — both notes are addressed, and the branch merges cleanly now. Conflicts (docs only). Auth kind. You were right that asserting a cause is riskier than describing the state, so I checked which of the two the code actually does. It reads credential presence, not the auth-kind name: Disabled services. Spelled out in the PR body now: the opt-in is a durable choice, so the flag has to stay reachable — otherwise disabling a service would strand a selection the user can no longer withdraw. One measurement note for transparency: |
The first cut expanded every configured model into a checkbox list and gave the row its own add menu. That buried the answer: a service can publish dozens of models, while the set worth reviewing is only the opted-in one. The row now reuses the service model list's own parts — the search field, the row with its limits, Advanced, and the remove control — and shows only the models that carry the opt-in. Advanced opens that service's model editor, where "Available for AI delegation" is ticked, so adding stays a model-editor job and both surfaces read and write the same `availableForSubagents` binding field.
…-row # Conflicts: # docs/spec/06-delivery/04-e2e-test-plan.md # docs/zh-CN/spec/06-delivery/04-e2e-test-plan.md
…or into a dialog The Models page should not grow a second model list. The row now shows the delegated models as chips, capped at 60% of the row; whatever does not fit collapses into +N. The full list — search, limits, Advanced, remove — moved into a dialog that Edit opens, so the page keeps one compact line and the editor keeps every action. Chip widths come from an off-screen twin of the same chips, because only the browser knows how wide a model id is at the current font and zoom; the pure fitSubagentChips() then decides how many fit and reserves room for +N. The editor still reads and writes ModelBinding.availableForSubagents, and Advanced still opens the service model editor where that opt-in is ticked, so the summary, the dialog and the service dialog can never disagree.
|
@vastsa 您好,按您的意见重新设计了,麻烦再看一下。 之前的问题:这一行把「完整模型列表(搜索框 + 上下文/输出 + 高级 + ×)」直接铺在设置页里,等于在设置页又开了一份模型管理面板,确实太重。 现在的做法
一致性:摘要、弹窗、模型编辑器读写的是同一个 实测:1440 宽时,行宽 1061px、标签区 547px(约 52%,没有超过 60%),显示 6 个 + 截图(真实渲染产物 + fixture 数据,非手绘稿):
点「编辑」后的弹窗: 如果这个轻重还是不对(比如希望连标签都不要、只留一行「6 个模型」,或者 60% 这个比例要调),您说一声我再改。 |










What this changes
The Models page already states the current image-generation model at the bottom, but the delegation catalog — the models the parent agent may pick when it delegates a task with
model— could only be reviewed one service at a time, inside that service's model dialog.This adds a Subagent models summary row under the image-model row:
+N;context · max outputlimits, Advanced and × a service's own model list uses;Total surface added to the page: one line. Everything else lives one click away.
Chip widths are measured from an off-screen twin of the same chips, because only the browser knows how wide a model id is at the current font and zoom;
fitSubagentChips()then decides how many fit and reserves room for+N.Nothing here adds a second stored selection: the summary, the dialog and the service model editor all read and write
ModelBinding.availableForSubagents, the exact field the runtime reads. Ticking the box in a model's editor makes the chip appear; removing it here makes the tick disappear there. The three surfaces cannot drift.Refs #1736.
Screenshots
Taken from the real renderer bundle (
apps/desktop/out/renderer) with fixture services; images live on thepr-1758-screenshotsbranch so this diff stays code-only.+N+NDesign note: reuse the existing opt-in instead of adding a second list
The issue thread suggested a
subagentModelBindingslist inpackages/shared. This implementation deliberately does not add one, because the runtime already owns that decision on each model binding:packages/host-runtime/src/launch-resolver.tsbuilds the delegation catalog fromModelBinding.availableForSubagentsonly;apps/desktop/electron/main/runtime/sidecar.tsandservices/session-collaboration.tsauthorize everyTask.model/spawn modelKeyagainst that same flag (D278, ADRsubagent-model-opt-in).A second stored list would be a second gate that can disagree with the first. Reading and writing the binding field also answers the obvious follow-up — "I changed it here, did the model editor change too?" — with one shared state instead of a sync problem.
Write path: the save re-reads the service with
providers.list, refuses when the row is plugin-owned or the model is gone, and rewrites only the touched binding withavailableForSubagentsset (or dropped, so nofalseaccumulates on records that never wanted delegation). It never posts this page's snapshot back, so a concurrent model edit from another window is preserved. No Host RPC, database schema, migration, or Plugin SDK change.Files
New:
apps/desktop/src/components/settings/subagent-delegation.ts— candidate construction, the opt-in write draft, andfitSubagentChips()(pure; no runtime imports so it is testable on its own)apps/desktop/src/components/settings/SubagentModelRow.tsx— the chip summary lineapps/desktop/src/components/settings/SubagentModelsDialog.tsx— the editor dialogapps/desktop/test/subagent-delegation.test.mjs— 12 unit testsChanged:
apps/desktop/src/components/settings/ModelConfigPage.tsx— candidate memo, save handler, mount point; Advanced reuses the page's existing provider dialogapps/desktop/src/components/settings/subagent-models.ts— the subagent editor's "is this service runnable" rule now delegates to the shared predicate instead of duplicating itapps/desktop/src/styles/model-config.css— the chip line and dialog furniture; the dialog's rows are the service list's ownprovider-chosen-*partspackages/i18n/src/locales/*— 12 newsettings.subagent*keys in all 9 shipped locales03-runtime/02-agent-runtime.md§5f,03-runtime/11-provider-model-system.md§7,04-ux/06-settings-ia.md,06-delivery/04-e2e-test-plan.md(new E2E-268)Review follow-up
CONFLICTINGstate (docs only). Merged currentupstream/maininto the branch; the E2E files conflicted only where both sides append a coverage-table row. Both rows are kept, mirrored inzh-CNso the pair stays shape-compatible.pnpm docs:check: 86 locale pairs, 585 pages.Auth-kind note. The "why is this row idle" label reads credential presence, not an auth-kind name:
hasSecretis the host's own "this row holds a usable credential" flag, so a flow added later still counts. OnlyauthKind === "none"(keyless local endpoint) is named explicitly, because that is the one case where no credential is expected. A test pins both ends.Disabled-service editing. The opt-in is durable, so a row stays listed and removable even while its service is off.
Validation
Run on the head that carries this design:
pnpm build:jspnpm --filter @pi-desktop/desktop typecheckpnpm lint(biome + style-token guard)pnpm --filter @pi-desktop/i18n testapps/desktop/test/subagent-delegation.test.mjspnpm docs:checkpnpm check:pr-baseMeasured in the rendered page: at 1440 wide the row is 1061px and the chip line 547px (≈52%, inside the 60% cap), showing six chips plus
+2.The full
apps/desktopsuite was last run before this redesign (4144 tests / 103–106 failures vs 4133 / 105 onupstream/main, identical failing sets, all environment-only on this Windows host); it was not re-run afterwards. Interactive E2E-268 remains documented but not driven in a real desktop session.Policy note (please read)
AGENTS.mdR6.1 (the temporary PR type scope effective 2026-09-26, still present onmain) says outside contributions are limited toperfandfix, and that afeatPR from a contributor without write access is not a landing candidate. This is afeat, and I am the author of the linked issue.I asked in the issue first and did not get an answer, so I opened this with the note visible rather than after the fact. If the restriction stays strict, closing this is a completely reasonable outcome. If it is useful, I am glad to reshape it however you prefer. The work is complete and reproducible either way.
中文摘要
模型页底部在生图模型行下方新增一行 子代理模型:
+N;ModelBinding.availableForSubagents,三处永远一致,没有第二份状态。无 RPC / schema / 迁移 / Plugin SDK 改动。实测:1440 宽时行宽 1061px、标签区 547px(≈52%),显示 6 个 +
+2;1100 宽时自动少显示。校验:构建、typecheck、lint(含 style-token)、docs(86 组中英配对 / 585 页)、i18n 31 项、新增 12 项单测通过。