feat(hermes): render providers: dict overlays as read-only cards

ProviderCard now detects Hermes provider entries sourced from the
v12+ `providers:` dict via the `_cc_source` marker that the backend
injects, and renders a "Hermes Managed" badge beside the title.
ProviderActions receives an `isReadOnly` prop that disables the Edit
and Delete buttons (with a tooltip pointing the user at Hermes Web
UI) while keeping Switch and Duplicate enabled — switching only
touches `model.*`, and duplicate lets users fork the overlay into
their own `custom_providers:` list.

Three-locale i18n keys `provider.managedByHermes` /
`provider.managedByHermesHint` added.
This commit is contained in:
Jason
2026-04-20 10:36:09 +08:00
parent 3f4739365e
commit abb305a82f
5 changed files with 42 additions and 5 deletions
+20
View File
@@ -180,6 +180,12 @@ export function ProviderCard({
const isCopilot =
provider.meta?.providerType === PROVIDER_TYPES.GITHUB_COPILOT ||
provider.meta?.usage_script?.templateType === "github_copilot";
// Hermes v12+ overlay entries live under the `providers:` dict and are
// read-only here — writes have to go through Hermes Web UI.
const isHermesReadOnly =
appId === "hermes" &&
(provider.settingsConfig as Record<string, unknown>)?._cc_source ===
"providers_dict";
const isCodexOauth =
provider.meta?.providerType === PROVIDER_TYPES.CODEX_OAUTH;
@@ -336,6 +342,19 @@ export function ProviderCard({
</span>
)}
{isHermesReadOnly && (
<span
className="inline-flex items-center rounded-md bg-slate-200 px-1.5 py-0.5 text-[10px] font-semibold text-slate-700 dark:bg-slate-700/60 dark:text-slate-200"
title={t("provider.managedByHermesHint", {
defaultValue: "由 Hermes 管理,请在 Hermes Web UI 中编辑",
})}
>
{t("provider.managedByHermes", {
defaultValue: "Hermes Managed",
})}
</span>
)}
</div>
{displayUrl && (
@@ -429,6 +448,7 @@ export function ProviderCard({
isTesting={isTesting}
isProxyTakeover={isProxyTakeover}
isOfficialBlockedByProxy={isOfficialBlockedByProxy}
isReadOnly={isHermesReadOnly}
isOmo={isAnyOmo}
onSwitch={() => onSwitch(provider)}
onEdit={() => onEdit(provider)}