supplier+deploy/mainnet: optional OPENAI_API_KEY for DeepSeek (and other hosted OpenAI-compatible APIs)

Adds an optional OPENAI_API_KEY env var that supplier/src/openai.ts forwards as
`Authorization: Bearer <key>`. Empty/unset preserves the ChatMock behaviour
(no auth header). Unlocks pointing the openai backend at DeepSeek directly
(https://api.deepseek.com) — no local proxy needed.

New compose: deploy/mainnet/docker-compose.supplier-deepseek.yml (third mainnet
supplier, model deepseek-v4-pro, mp-suppliers-deepseek.vector.apexfusion.org).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
david
2026-05-27 11:23:57 +02:00
parent d59d3f56b8
commit 1466442870
6 changed files with 151 additions and 2 deletions

View File

@@ -102,6 +102,39 @@ describe("callOpenAi() — request shape", () => {
const body = JSON.parse(init.body as string);
expect(body.stream).toBe(false);
});
it("omits authorization header when apiKey is not provided (ChatMock path)", async () => {
await callOpenAi({ baseUrl: BASE_URL, model: MODEL, messages: MESSAGES, timeoutMs: TIMEOUT_MS });
const [, init] = (global.fetch as ReturnType<typeof vi.fn>).mock.calls[0] as [string, RequestInit];
const headers = init.headers as Record<string, string>;
expect(headers.authorization).toBeUndefined();
});
it("sends authorization: Bearer <apiKey> when apiKey is provided (DeepSeek/OpenAI path)", async () => {
await callOpenAi({
baseUrl: BASE_URL,
model: MODEL,
messages: MESSAGES,
timeoutMs: TIMEOUT_MS,
apiKey: "sk-test-deepseek-key",
});
const [, init] = (global.fetch as ReturnType<typeof vi.fn>).mock.calls[0] as [string, RequestInit];
const headers = init.headers as Record<string, string>;
expect(headers.authorization).toBe("Bearer sk-test-deepseek-key");
});
it("omits authorization header when apiKey is empty string", async () => {
await callOpenAi({
baseUrl: BASE_URL,
model: MODEL,
messages: MESSAGES,
timeoutMs: TIMEOUT_MS,
apiKey: "",
});
const [, init] = (global.fetch as ReturnType<typeof vi.fn>).mock.calls[0] as [string, RequestInit];
const headers = init.headers as Record<string, string>;
expect(headers.authorization).toBeUndefined();
});
});
// ─── Happy path ─────────────────────────────────────────────────────────────