fix(backend): allow configured local Qwen provider
This commit is contained in:
@@ -42,7 +42,9 @@ const PROVIDER_KEY_ENV: Readonly<Record<string, string>> = {
|
||||
const COMPOUND_PROVIDERS = new Set([
|
||||
"amazon-bedrock", "azure-openai-responses", "cloudflare-ai-gateway", "cloudflare-workers-ai",
|
||||
]);
|
||||
const LOCAL_PROVIDERS = new Set(["ollama", "lmstudio", "local", "aritmolab", "faux"]);
|
||||
const LOCAL_PROVIDERS = new Set([
|
||||
"ollama", "lmstudio", "local", "aritmolab", "local-qwen", "faux",
|
||||
]);
|
||||
|
||||
export function canonicalPiProvider(provider: string | undefined): string | undefined {
|
||||
const value = provider?.trim().toLowerCase();
|
||||
|
||||
@@ -289,26 +289,29 @@ test.each([["OpenAI", "openai"], ["gemini", "google"]])(
|
||||
},
|
||||
);
|
||||
|
||||
test("local providers spawn without a model key and scrub ambient generic credentials", async () => {
|
||||
vi.stubEnv("PI_PROVIDER_API_KEY", "ambient-secret");
|
||||
vi.stubEnv("THT_MODEL_API_KEY_FILE", "/ambient/secret-path");
|
||||
vi.stubEnv("OPENAI_API_KEY", "unselected-provider-secret");
|
||||
const calls: any[][] = [];
|
||||
const child = recordingChild();
|
||||
child.stderr.resume = () => {};
|
||||
const mgr = new PiProcessManager(loadConfig({ PI_BIN: "/usr/local/bin/pi" }), {
|
||||
spawnFn: (...args: any[]) => { calls.push(args); return child as any; },
|
||||
});
|
||||
try {
|
||||
await mgr.spawnFor("local-session", { provider: "ollama" });
|
||||
expect(calls[0][2].env).not.toHaveProperty("PI_PROVIDER_API_KEY");
|
||||
expect(calls[0][2].env).not.toHaveProperty("THT_MODEL_API_KEY_FILE");
|
||||
expect(calls[0][2].env).not.toHaveProperty("OPENAI_API_KEY");
|
||||
} finally {
|
||||
mgr.teardown("local-session");
|
||||
vi.unstubAllEnvs();
|
||||
}
|
||||
});
|
||||
test.each(["ollama", "local-qwen"])(
|
||||
"local provider %s spawns without a model key and scrubs ambient credentials",
|
||||
async (provider) => {
|
||||
vi.stubEnv("PI_PROVIDER_API_KEY", "ambient-secret");
|
||||
vi.stubEnv("THT_MODEL_API_KEY_FILE", "/ambient/secret-path");
|
||||
vi.stubEnv("OPENAI_API_KEY", "unselected-provider-secret");
|
||||
const calls: any[][] = [];
|
||||
const child = recordingChild();
|
||||
child.stderr.resume = () => {};
|
||||
const mgr = new PiProcessManager(loadConfig({ PI_BIN: "/usr/local/bin/pi" }), {
|
||||
spawnFn: (...args: any[]) => { calls.push(args); return child as any; },
|
||||
});
|
||||
try {
|
||||
await mgr.spawnFor(`local-session-${provider}`, { provider });
|
||||
expect(calls[0][2].env).not.toHaveProperty("PI_PROVIDER_API_KEY");
|
||||
expect(calls[0][2].env).not.toHaveProperty("THT_MODEL_API_KEY_FILE");
|
||||
expect(calls[0][2].env).not.toHaveProperty("OPENAI_API_KEY");
|
||||
} finally {
|
||||
mgr.teardown(`local-session-${provider}`);
|
||||
vi.unstubAllEnvs();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test.each(["amazon-bedrock", "azure-openai-responses", "cloudflare-workers-ai", "cloudflare-ai-gateway"])(
|
||||
"session spawn rejects compound provider %s before spawning Pi", async (provider) => {
|
||||
|
||||
@@ -116,6 +116,20 @@ test("single-key providers scrub ambient compound companions before injecting th
|
||||
expect(env).not.toHaveProperty("CLOUDFLARE_GATEWAY_ID");
|
||||
});
|
||||
|
||||
test("local-qwen is an explicit local provider and needs no generic key", () => {
|
||||
const env = buildPiChildEnv({
|
||||
ambient: {
|
||||
PI_PROVIDER_API_KEY: "must-not-leak",
|
||||
OPENAI_API_KEY: "must-not-leak",
|
||||
THT_MODEL_API_KEY_FILE: "/must/not/leak",
|
||||
},
|
||||
provider: "local-qwen",
|
||||
});
|
||||
expect(env).not.toHaveProperty("PI_PROVIDER_API_KEY");
|
||||
expect(env).not.toHaveProperty("OPENAI_API_KEY");
|
||||
expect(env).not.toHaveProperty("THT_MODEL_API_KEY_FILE");
|
||||
});
|
||||
|
||||
test("bundle value is injected without exposing bundle metadata to Pi", () => {
|
||||
const env = buildPiChildEnv({
|
||||
ambient: {
|
||||
|
||||
Reference in New Issue
Block a user