Files
moltbot/extensions/codex/src/app-server/protocol-validators.test.ts
Kagura 8a1a86279a fix(codex): normalize thread id/sessionId cross-fill before schema validation (#80137)
Merged via squash.

Prepared head SHA: b2c20dd5d6
Co-authored-by: kagura-agent <268167063+kagura-agent@users.noreply.github.com>
Co-authored-by: omarshahine <10343873+omarshahine@users.noreply.github.com>
Reviewed-by: @omarshahine
2026-05-10 12:07:42 -04:00

72 lines
2.4 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
assertCodexThreadStartResponse,
assertCodexThreadResumeResponse,
} from "./protocol-validators.js";
function makeMinimalThread(overrides: Record<string, unknown> = {}) {
return {
id: "thread-1",
sessionId: "session-1",
cliVersion: "0.129.0",
createdAt: 1715299200,
updatedAt: 1715299200,
cwd: "/tmp",
ephemeral: false,
modelProvider: "openai",
preview: "test thread",
source: "appServer",
status: { type: "notLoaded" },
turns: [],
...overrides,
};
}
function makeMinimalResponse(threadOverrides: Record<string, unknown> = {}) {
return {
approvalPolicy: "never",
approvalsReviewer: "user",
cwd: "/tmp",
model: "gpt-5.4",
modelProvider: "openai",
sandbox: { type: "dangerFullAccess" },
thread: makeMinimalThread(threadOverrides),
};
}
describe("assertCodexThreadStartResponse", () => {
it("accepts response with both id and sessionId", () => {
const response = makeMinimalResponse();
const result = assertCodexThreadStartResponse(response);
expect(result.thread).toMatchObject({ id: "thread-1", sessionId: "session-1" });
});
it("normalizes missing sessionId from id", () => {
const response = makeMinimalResponse({ sessionId: undefined });
// Remove the sessionId key entirely
delete (response.thread as Record<string, unknown>).sessionId;
const result = assertCodexThreadStartResponse(response);
expect(result.thread).toMatchObject({ id: "thread-1", sessionId: "thread-1" });
});
it("normalizes missing id from sessionId", () => {
const response = makeMinimalResponse({ id: undefined, sessionId: "session-1" });
delete (response.thread as Record<string, unknown>).id;
const result = assertCodexThreadStartResponse(response);
expect(result.thread).toMatchObject({ id: "session-1", sessionId: "session-1" });
});
it("throws on invalid response", () => {
expect(() => assertCodexThreadStartResponse({})).toThrow("Invalid Codex app-server");
});
});
describe("assertCodexThreadResumeResponse", () => {
it("normalizes missing sessionId from id", () => {
const response = makeMinimalResponse({ sessionId: undefined });
delete (response.thread as Record<string, unknown>).sessionId;
const result = assertCodexThreadResumeResponse(response);
expect(result.thread).toMatchObject({ id: "thread-1", sessionId: "thread-1" });
});
});