Merge remote-tracking branch 'origin/master' into worktree/pi-ai-per-model-reasoning

# Conflicts:
#	docs/config-catalog.md
#	docs/user/guide/providers.i18n.yaml
#	packages/llm/llm-pi-ai/README.i18n.yaml
#	packages/llm/llm-pi-ai/README.md
#	packages/llm/llm-pi-ai/README.zh.md
#	packages/llm/llm-pi-ai/tests/config.spec.ts
This commit is contained in:
Yichen Jiang
2026-08-08 10:32:22 +08:00
172 changed files with 2499 additions and 986 deletions
+3 -4
View File
@@ -56,6 +56,7 @@
*/
import type { Context } from 'cordis'
import { environmentOf } from '@deepseek-ai/dsh-environment'
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'
@@ -162,7 +163,6 @@ export function apply(ctx: Context, config: Config): void {
provider: string,
profile: ResolvedPiAiProviderProfile,
): Promise<string | undefined> => {
if (profile.apiKey !== undefined) return profile.apiKey
const ref = profile.apiKeyEnv
// Only a profile that names no credential at all defers to pi-ai's
// provider-native discovery. Once one is named, a miss must fail loud:
@@ -173,9 +173,8 @@ export function apply(ctx: Context, config: Config): void {
const credentials = ctx.get('credentials')
const hit = credentials !== undefined
? (await credentials.resolve(ref))?.value
// Without the seam, read exactly the named variable so a plain
// cordis.yml composition works from the environment alone.
: process.env[ref]
// Without the seam the environment is the whole credential plane.
: environmentOf(ctx).get(ref)?.value
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`