Merge remote-tracking branch 'origin/master' into worktree/default-model-persistence

Carries two edits beyond conflict resolution, both forced by what master
brought in:

- `CustomProviderCard`: master added front-end key validation and a
  component-level `keyValue` (already trimmed) while still writing
  `apiKeyEnv` unconditionally. Kept this branch's blank-key rule and its
  committed-profile retry gate, and adopted master's single `keyValue` so
  the component has one spelling of the key rather than two.
- `docs/user/guide/providers`: master merged #1810, whose default-model
  section still taught overriding the `api-gateway` row in
  `$DSH_HOME/config.yaml` — the behavior this branch replaced. Rewritten
  for the settings section the picker now writes, plus the review fix from
  #1810 replacing the colloquial 挂着 in the opener.
This commit is contained in:
Yichen Jiang
2026-08-07 15:44:17 +08:00
91 changed files with 1940 additions and 117 deletions
+2 -2
View File
@@ -43,7 +43,7 @@
*/
import type { Context } from 'cordis'
import { LlmError } from '@deepseek-ai/dsh-llm'
import { assertUsableApiKey, LlmError } from '@deepseek-ai/dsh-llm'
import type { AdapterRegistrationHandle, DirectoryRegistrationHandle, LlmConfigurableProvider } from '@deepseek-ai/dsh-llm'
import { deepEqualJson, installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings'
import { PiAiAdapter } from './adapter.ts'
@@ -155,7 +155,7 @@ export function apply(ctx: Context, config: Config): void {
// Without the seam, read exactly the named variable so a plain
// cordis.yml composition works from the environment alone.
: process.env[ref]
if (hit !== undefined && hit.length > 0) return hit
if (hit !== undefined && hit.length > 0) return assertUsableApiKey(hit, 'llm-pi-ai', ref)
throw new LlmError(
`llm-pi-ai: no credential for provider route "${provider}"; its profile resolves ${ref}, which is not`
+ ` set — store ${ref} through the credentials service (the web Models page writes it) or export it,`