Skip to content

feat(settings): give vendor accounts the enable switch - #1244

Open
OpenX123 wants to merge 3 commits into
vastsa:mainfrom
OpenX123:feat/vendor-account-toggle
Open

OpenX123 wants to merge 3 commits into
vastsa:mainfrom
OpenX123:feat/vendor-account-toggle

Conversation

@OpenX123

Copy link
Copy Markdown
Contributor

问题 / Problem

设置里的「AI 服务」列表中,厂商订阅账户(Claude Pro/Max、ChatGPT 等)那一行没有启用开关。用户想停用一个不再使用的订阅账户时,唯一办法是删除账户再重新登录。

参考 #930。

根因 / Root cause

行以下的每一层早已把「已停用的 provider」和「API 服务」同等对待:

层 现状
host 查询 list_providers(include_disabled=false) → WHERE enabled = 1(providers/repository.rs:73)
模型选择器 session-launch.ts:271、plugin-services.ts:314 传 includeDisabled: false
渲染层 useComposerModelMenu.ts:124 过滤 candidate.enabled
会话启动 停用的 provider 以 PROVIDER_DISABLED 失败(spec §11)
「已禁用」徽章 service-row-status.ts:81 对 account 行同样生效

也就是说:数据层、徽章、下游过滤全都支持,唯独 UI 入口被挡住了。ServiceRow.tsx 里的 kind !== "account" 条件让 account 行渲染不出开关,于是这个能力看起来根本不存在。

改动 / Change

把开关的判定抽成纯函数 serviceRowToggle(放在 service-row-status.ts,与该文件既有的「规则用纯函数保持可测」一致):

  • API 服务 —— 保持原有开关
  • 厂商账户 —— 获得同样的开关(本次新增)
  • 插件声明的服务 —— 仍然没有开关:插件拥有该行,每次加载都从 manifest 重新生成

已停用的账户在设置列表中仍然可见(带「已禁用」徽章),因此可以重新打开;其模型会从模型选择器中移除。

未改动:host-core、持久化、协议、模型选择逻辑、i18n 文案(复用已有的 settings.enabledToggle)。

验证 / Verification

  • 新增行为测试(service-row-status.test.mjs):已验证在旧实现下失败(把 helper 改回 kind !== "account" 时 2 条用例 fail),新实现下 12/12 通过
  • pnpm --filter @pi-desktop/desktop typecheck 通过
  • pnpm lint 通过
  • apps/desktop 全量测试:3260 pass / 1 fail / 7 cancelled;与 origin/main 基线完全一致(基线为 3258 pass / 1 fail / 7 cancelled,差额即本次新增的 2 条用例)。剩余的 1 项失败与 7 项 cancelled(provider error 文案、websocket 套件)为改动前既有,已用 git stash 在干净 origin/main 上复现确认
  • 无 Rust 改动,故未运行 cargo test

规范 / Spec

同步更新了中英文规范中「enable/disable provider」条目,明确 account 与 API 服务共用开关、plugin 行没有开关:

  • docs/spec/03-runtime/11-provider-model-system.md
  • docs/zh-CN/spec/03-runtime/11-provider-model-system.md

Note for maintainer

这是一个 feat 类型 PR。按 §15 现行临时政策,无写权限的外部贡献者的 feat 不属于落地候选 —— 落地需要 maintainer 授权此分支(或由 maintainer cherry-pick 7a0160387)。

fixes #930

A tag push forced MACOS_SIGN_RELEASE to true, so the release pipeline
always demanded the five Apple Developer secrets. This fork owns none of
them, and the guard in "Require macOS signing and notarization secrets"
additionally pins APPLE_TEAM_ID to the upstream maintainer's team
(DUV63RKYTW) while CSC_NAME is hardcoded to their certificate common
name, so no certificate obtained by this repository can satisfy the
check. Both macOS matrix legs then failed, the build job failed with
them, and the publish job was skipped by needs, leaving a release
workflow that could not produce a Release on this fork.

Signing is now opt-in: a tag push builds unsigned installers, and
setting the repository variable MACOS_SIGN_RELEASE=true restores the
sign-always behaviour once this repository owns a Developer ID
certificate. workflow_dispatch keeps honouring its own sign_macos
input, so the existing debug lane is unchanged.

Unsigned macOS artifacts lose only the Developer ID seal and the
notarization ticket; installer layout, artifact names, the updater
feeds, and the publish job are all independent of signing.
The ci-workflow contract test pinned the old MACOS_SIGN_RELEASE
expression, in which a tag push always signs. That guard is exactly what
the release workflow change had to relax, so leaving it would have kept
the pipeline red: the verify job runs the unit tests before any build
job, and its failure skips publish.

The test now pins the new contract instead: the opt-in expression must
be present, the tag-forced form must be absent, and the existing
assertions covering both macOS lanes are unchanged. Verified in both
directions — it passes against the new expression and fails when the
workflow is reverted to the old one, so the guard is not vacuous.
A vendor subscription account had no enable switch on its service row, so
the only way to stop an account's models from being offered was to remove the
account and sign in again. Every layer below the row already treated a
disabled provider the same way it treats an API service: `providers.list`
with `includeDisabled=false` drops it from the model picker, session launch
fails with `PROVIDER_DISABLED`, and the settings list still shows the row
with a disabled badge so it can be turned back on. Only the UI entry point
was missing, which made the account look like it could not be switched off.

The switch decision moves into a pure `serviceRowToggle` helper next to the
row's other rules, so which kinds get a switch — and which get a locked one —
is covered by tests instead of by a condition in JSX. A plugin-declared row
still has no switch, because the plugin owns that row and refreshes it from
its manifest on every load; that is now stated in the spec rather than only
in a comment.

The source-text assertion in settings-general.test.mjs followed the old
condition and is repointed at the helper call; the behavior it stood for is
asserted directly in service-row-status.test.mjs.

fixes vastsa#930

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 厂商账号也可以像AI服务那样有关闭功能。

1 participant