fix(ai): set session id headers for all OpenAI compatible responses (#3264)
This commit is contained in:
@@ -179,7 +179,7 @@ function createClient(
|
|||||||
Object.assign(headers, copilotHeaders);
|
Object.assign(headers, copilotHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sessionId && model.provider === "openai" && model.baseUrl.includes("api.openai.com")) {
|
if (sessionId) {
|
||||||
headers.session_id = sessionId;
|
headers.session_id = sessionId;
|
||||||
headers["x-client-request-id"] = sessionId;
|
headers["x-client-request-id"] = sessionId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
import { getModel } from "../src/models.js";
|
import { getModel } from "../src/models.js";
|
||||||
import { streamOpenAIResponses } from "../src/providers/openai-responses.js";
|
import { streamOpenAIResponses } from "../src/providers/openai-responses.js";
|
||||||
|
import type { Model } from "../src/types.js";
|
||||||
|
|
||||||
type CapturedHeaders = Headers | string[][] | Record<string, string | readonly string[]> | undefined;
|
type CapturedHeaders = Headers | string[][] | Record<string, string | readonly string[]> | undefined;
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ function getHeader(headers: CapturedHeaders, name: string): string | null {
|
|||||||
|
|
||||||
async function captureOpenAIResponseHeaders(
|
async function captureOpenAIResponseHeaders(
|
||||||
options: Parameters<typeof streamOpenAIResponses>[2],
|
options: Parameters<typeof streamOpenAIResponses>[2],
|
||||||
|
model: Model<"openai-responses"> = getModel("openai", "gpt-5.4"),
|
||||||
): Promise<{ sessionId: string | null; clientRequestId: string | null }> {
|
): Promise<{ sessionId: string | null; clientRequestId: string | null }> {
|
||||||
const captured = { sessionId: null as string | null, clientRequestId: null as string | null };
|
const captured = { sessionId: null as string | null, clientRequestId: null as string | null };
|
||||||
vi.spyOn(globalThis, "fetch").mockImplementation(async (_input, init) => {
|
vi.spyOn(globalThis, "fetch").mockImplementation(async (_input, init) => {
|
||||||
@@ -34,7 +36,7 @@ async function captureOpenAIResponseHeaders(
|
|||||||
});
|
});
|
||||||
|
|
||||||
const stream = streamOpenAIResponses(
|
const stream = streamOpenAIResponses(
|
||||||
getModel("openai", "gpt-5.4"),
|
model,
|
||||||
{
|
{
|
||||||
systemPrompt: "sys",
|
systemPrompt: "sys",
|
||||||
messages: [{ role: "user", content: "hi", timestamp: Date.now() }],
|
messages: [{ role: "user", content: "hi", timestamp: Date.now() }],
|
||||||
@@ -95,6 +97,17 @@ describe("openai-responses provider defaults", () => {
|
|||||||
expect(captured).toEqual({ sessionId: "session-123", clientRequestId: "session-123" });
|
expect(captured).toEqual({ sessionId: "session-123", clientRequestId: "session-123" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("sets cache-affinity headers for proxy OpenAI Responses requests with a sessionId", async () => {
|
||||||
|
const proxyModel: Model<"openai-responses"> = {
|
||||||
|
...getModel("openai", "gpt-5.4"),
|
||||||
|
provider: "opencode",
|
||||||
|
baseUrl: "https://proxy.example.com/v1",
|
||||||
|
};
|
||||||
|
const captured = await captureOpenAIResponseHeaders({ sessionId: "session-123" }, proxyModel);
|
||||||
|
|
||||||
|
expect(captured).toEqual({ sessionId: "session-123", clientRequestId: "session-123" });
|
||||||
|
});
|
||||||
|
|
||||||
it("lets explicit headers override the default OpenAI cache-affinity headers", async () => {
|
it("lets explicit headers override the default OpenAI cache-affinity headers", async () => {
|
||||||
const captured = await captureOpenAIResponseHeaders({
|
const captured = await captureOpenAIResponseHeaders({
|
||||||
sessionId: "session-123",
|
sessionId: "session-123",
|
||||||
|
|||||||
Reference in New Issue
Block a user