feat(backend): let pi self-authenticate providers from its own auth store
The backend injects a single managed model key (THT_MODEL_API_KEY[_FILE]) as the selected provider's env var, but that key belongs to one provider — so selecting a second cloud provider (e.g. DeepSeek while the managed key is zai's) forced the wrong key onto it and failed auth. This is why the model could not be switched to DeepSeek. When the selected provider is present in pi's own auth store (~/.pi/agent/auth.json), skip injection and let pi resolve that provider's key itself. Deployments without an auth store (containers) yield an empty set, so the managed-key injection stays authoritative and fail-fast there. authProviders is injectable into PiProcessManager for deterministic tests. Verified live: GLM 5.2, DeepSeek V4 Flash, and aritmolab Qwen3.6 all operate through the ThothII model selector. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import { RpcClient } from "../rpc/rpc-client.js";
|
||||
import { SessionBridge } from "../bridge/session-bridge.js";
|
||||
import type { ThtRunner } from "../tht/tht-runner.js";
|
||||
import { buildPiChildEnv, canonicalPiProvider } from "./provider-credentials.js";
|
||||
import { loadPiAuthProviders } from "./auth-providers.js";
|
||||
import { secretValue } from "../config/secret-bundle.js";
|
||||
import { clearPrincipalEnvironment, principalEnvironment, type PrincipalContext } from "../auth/principal.js";
|
||||
|
||||
@@ -35,8 +36,13 @@ export class PiProcessManager {
|
||||
private spawnFn: (
|
||||
sessionId: string, author: string, provider: string | undefined, principal?: PrincipalContext,
|
||||
) => ChildProcessWithoutNullStreams;
|
||||
private loadAuthProviders: () => ReadonlySet<string>;
|
||||
|
||||
constructor(private cfg: AppConfig, opts?: { spawnFn?: SpawnFn }) {
|
||||
constructor(
|
||||
private cfg: AppConfig,
|
||||
opts?: { spawnFn?: SpawnFn; authProviders?: () => ReadonlySet<string> },
|
||||
) {
|
||||
this.loadAuthProviders = opts?.authProviders ?? (() => loadPiAuthProviders());
|
||||
if (opts?.spawnFn) {
|
||||
this.spawnFn = (sessionId, author, provider, principal) =>
|
||||
this.spawnPi(opts.spawnFn!, sessionId, author, provider, principal);
|
||||
@@ -51,6 +57,7 @@ export class PiProcessManager {
|
||||
): ChildProcessWithoutNullStreams {
|
||||
const env = buildPiChildEnv({
|
||||
provider,
|
||||
authProviders: this.loadAuthProviders(),
|
||||
credentialValue: secretValue(this.cfg, "THT_MODEL_API_KEY"),
|
||||
credentialFile: this.cfg.modelApiKeyFile,
|
||||
additions: { THT_SESSION: sessionId, THT_AUTHOR: author },
|
||||
|
||||
Reference in New Issue
Block a user