fix(ai): honor scoped env in compat API key injection

This commit is contained in:
Mario Zechner
2026-06-23 13:45:26 +02:00
parent 2cbce395fb
commit 8eeaa2bcba
2 changed files with 75 additions and 1 deletions
+1 -1
View File
@@ -100,7 +100,7 @@ function withEnvApiKey<TOptions extends StreamOptions>(
options: TOptions | undefined,
): TOptions | undefined {
if (hasExplicitApiKey(options?.apiKey)) return options;
const apiKey = getEnvApiKey(model.provider);
const apiKey = getEnvApiKey(model.provider, options?.env);
if (!apiKey) return options;
return { ...options, apiKey } as TOptions;
}
+74
View File
@@ -0,0 +1,74 @@
import { afterEach, describe, expect, it } from "vitest";
import { complete, registerApiProvider, resetApiProviders } from "../src/compat.ts";
import type { AssistantMessage, Context, Model } from "../src/types.ts";
import { AssistantMessageEventStream } from "../src/utils/event-stream.ts";
const context: Context = { messages: [{ role: "user", content: "hi", timestamp: Date.now() }] };
const model: Model<"openai-responses"> = {
id: "test-model",
name: "Test Model",
api: "openai-responses",
provider: "openai",
baseUrl: "https://example.test/v1",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128000,
maxTokens: 4096,
};
function message(): AssistantMessage {
return {
role: "assistant",
content: [{ type: "text", text: "ok" }],
api: model.api,
provider: model.provider,
model: model.id,
usage: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
totalTokens: 0,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
},
stopReason: "stop",
timestamp: Date.now(),
};
}
describe("compat env API key injection", () => {
afterEach(() => {
resetApiProviders();
});
it("uses request-scoped env when injecting provider API keys", async () => {
let capturedApiKey: string | undefined;
registerApiProvider({
api: "openai-responses",
stream: (_model, _context, options) => {
capturedApiKey = options?.apiKey;
const stream = new AssistantMessageEventStream();
const output = message();
stream.push({ type: "start", partial: output });
stream.push({ type: "done", reason: "stop", message: output });
stream.end(output);
return stream;
},
streamSimple: (_model, _context, options) => {
capturedApiKey = options?.apiKey;
const stream = new AssistantMessageEventStream();
const output = message();
stream.push({ type: "start", partial: output });
stream.push({ type: "done", reason: "stop", message: output });
stream.end(output);
return stream;
},
});
await complete(model, context, { env: { OPENAI_API_KEY: "scoped-key" } });
expect(capturedApiKey).toBe("scoped-key");
});
});