Skip to content

Commit 6a1a74a

Browse files
committed
Fix GET thread goal fallback keying
1 parent 7e63893 commit 6a1a74a

2 files changed

Lines changed: 55 additions & 4 deletions

File tree

lib/runtime-rotation-proxy.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,11 @@ function readStringRecordValue(record: Record<string, unknown>, key: string): st
336336
: null;
337337
}
338338

339+
function readStringSearchParam(searchParams: URLSearchParams, key: string): string | null {
340+
const value = searchParams.get(key);
341+
return value && value.trim().length > 0 ? value.trim() : null;
342+
}
343+
339344
function resolveSessionKey(headers: Headers, parsedBody: RequestBody | null): string | null {
340345
const headerKey =
341346
headers.get(OPENAI_HEADERS.SESSION_ID) ??
@@ -404,11 +409,15 @@ function buildThreadGoalRequestContext(
404409
): RequestContext {
405410
const headers = headersFromIncoming(req);
406411
const parsedBody = parseRequestBody(body);
407-
const sessionKey = parsedBody
412+
const searchParams = new URL(req.url ?? "/", "http://127.0.0.1").searchParams;
413+
const queryThreadKey =
414+
readStringSearchParam(searchParams, "thread_id") ??
415+
readStringSearchParam(searchParams, "threadId");
416+
const bodyThreadKey = parsedBody
408417
? (readStringRecordValue(parsedBody, "thread_id") ??
409-
readStringRecordValue(parsedBody, "threadId") ??
410-
resolveSessionKey(headers, parsedBody))
411-
: resolveSessionKey(headers, null);
418+
readStringRecordValue(parsedBody, "threadId"))
419+
: null;
420+
const sessionKey = bodyThreadKey ?? queryThreadKey ?? resolveSessionKey(headers, parsedBody);
412421
return {
413422
body,
414423
headers,

test/runtime-rotation-proxy.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,21 @@ async function postThreadGoal(
167167
});
168168
}
169169

170+
async function getThreadGoal(
171+
proxy: RuntimeRotationProxyServer,
172+
path = "/thread/goal/get",
173+
headers: Record<string, string> = {},
174+
): Promise<Response> {
175+
return fetch(`${proxy.baseUrl}${path}`, {
176+
method: "GET",
177+
headers: {
178+
authorization: `Bearer ${DEFAULT_CLIENT_API_KEY}`,
179+
"x-api-key": "caller-key",
180+
...headers,
181+
},
182+
});
183+
}
184+
170185
async function postRawResponses(
171186
proxy: RuntimeRotationProxyServer,
172187
body: string,
@@ -617,6 +632,33 @@ describe("runtime rotation proxy", () => {
617632
]);
618633
});
619634

635+
it("keys blocked GET thread goal fallbacks by query thread id", async () => {
636+
const now = Date.now();
637+
const accountManager = new AccountManager(undefined, createStorage(now));
638+
const { calls, fetchImpl } = createRecordingFetch(
639+
() =>
640+
new Response("<html>blocked</html>", {
641+
status: HTTP_STATUS.FORBIDDEN,
642+
headers: { "content-type": "text/html" },
643+
}),
644+
);
645+
const proxy = await startProxy({ accountManager, fetchImpl });
646+
647+
await postThreadGoal(
648+
proxy,
649+
{ threadId: "thread-1", goal: "ship it" },
650+
"/thread/goal/set",
651+
);
652+
const response = await getThreadGoal(proxy, "/thread/goal/get?thread_id=thread-1");
653+
654+
expect(response.status).toBe(HTTP_STATUS.OK);
655+
expect(await response.json()).toEqual({ goal: "ship it" });
656+
expect(calls.map((call) => call.url)).toEqual([
657+
"https://example.test/backend-api/codex/thread/goal/set",
658+
"https://example.test/backend-api/codex/thread/goal/get?thread_id=thread-1",
659+
]);
660+
});
661+
620662
it("rejects unauthenticated model discovery requests", async () => {
621663
const now = Date.now();
622664
const accountManager = new AccountManager(undefined, createStorage(now));

0 commit comments

Comments
 (0)