mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-13 10:11:20 +00:00
141 lines
4.2 KiB
TypeScript
141 lines
4.2 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import type { CodexAppServerClient } from "./client.js";
|
|
import { maybeCompactCodexAppServerSession, __testing } from "./compact.js";
|
|
import type { CodexServerNotification } from "./protocol.js";
|
|
import { writeCodexAppServerBinding } from "./session-binding.js";
|
|
|
|
const OLD_RUNTIME = process.env.OPENCLAW_AGENT_RUNTIME;
|
|
|
|
let tempDir: string;
|
|
|
|
describe("maybeCompactCodexAppServerSession", () => {
|
|
beforeEach(async () => {
|
|
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-compact-"));
|
|
process.env.OPENCLAW_AGENT_RUNTIME = "codex-app-server";
|
|
});
|
|
|
|
afterEach(async () => {
|
|
__testing.resetCodexAppServerClientFactoryForTests();
|
|
if (OLD_RUNTIME === undefined) {
|
|
delete process.env.OPENCLAW_AGENT_RUNTIME;
|
|
} else {
|
|
process.env.OPENCLAW_AGENT_RUNTIME = OLD_RUNTIME;
|
|
}
|
|
await fs.rm(tempDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it("waits for native app-server compaction before reporting success", async () => {
|
|
const fake = createFakeCodexClient();
|
|
__testing.setCodexAppServerClientFactoryForTests(async () => fake.client);
|
|
const sessionFile = path.join(tempDir, "session.jsonl");
|
|
await writeCodexAppServerBinding(sessionFile, {
|
|
threadId: "thread-1",
|
|
cwd: tempDir,
|
|
});
|
|
|
|
const pendingResult = maybeCompactCodexAppServerSession({
|
|
sessionId: "session-1",
|
|
sessionKey: "agent:main:session-1",
|
|
sessionFile,
|
|
workspaceDir: tempDir,
|
|
currentTokenCount: 123,
|
|
});
|
|
await vi.waitFor(() => {
|
|
expect(fake.request).toHaveBeenCalledWith("thread/compact/start", { threadId: "thread-1" });
|
|
});
|
|
|
|
let settled = false;
|
|
void pendingResult.then(() => {
|
|
settled = true;
|
|
});
|
|
await Promise.resolve();
|
|
expect(settled).toBe(false);
|
|
|
|
fake.emit({
|
|
method: "thread/compacted",
|
|
params: { threadId: "thread-1", turnId: "turn-1" },
|
|
});
|
|
const result = await pendingResult;
|
|
|
|
expect(result).toMatchObject({
|
|
ok: true,
|
|
compacted: true,
|
|
result: {
|
|
tokensBefore: 123,
|
|
details: {
|
|
backend: "codex-app-server",
|
|
threadId: "thread-1",
|
|
signal: "thread/compacted",
|
|
turnId: "turn-1",
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
it("accepts native context-compaction item completion as success", async () => {
|
|
const fake = createFakeCodexClient();
|
|
__testing.setCodexAppServerClientFactoryForTests(async () => fake.client);
|
|
const sessionFile = path.join(tempDir, "session.jsonl");
|
|
await writeCodexAppServerBinding(sessionFile, {
|
|
threadId: "thread-1",
|
|
cwd: tempDir,
|
|
});
|
|
|
|
const pendingResult = maybeCompactCodexAppServerSession({
|
|
sessionId: "session-1",
|
|
sessionKey: "agent:main:session-1",
|
|
sessionFile,
|
|
workspaceDir: tempDir,
|
|
});
|
|
await vi.waitFor(() => {
|
|
expect(fake.request).toHaveBeenCalledWith("thread/compact/start", { threadId: "thread-1" });
|
|
});
|
|
fake.emit({
|
|
method: "item/completed",
|
|
params: {
|
|
threadId: "thread-1",
|
|
turnId: "turn-1",
|
|
item: { type: "contextCompaction", id: "compact-1" },
|
|
},
|
|
});
|
|
|
|
await expect(pendingResult).resolves.toMatchObject({
|
|
ok: true,
|
|
compacted: true,
|
|
result: {
|
|
details: {
|
|
signal: "item/completed",
|
|
itemId: "compact-1",
|
|
},
|
|
},
|
|
});
|
|
});
|
|
});
|
|
|
|
function createFakeCodexClient(): {
|
|
client: CodexAppServerClient;
|
|
request: ReturnType<typeof vi.fn>;
|
|
emit: (notification: CodexServerNotification) => void;
|
|
} {
|
|
const handlers = new Set<(notification: CodexServerNotification) => void>();
|
|
const request = vi.fn(async () => ({}));
|
|
return {
|
|
client: {
|
|
request,
|
|
addNotificationHandler(handler: (notification: CodexServerNotification) => void) {
|
|
handlers.add(handler);
|
|
return () => handlers.delete(handler);
|
|
},
|
|
} as unknown as CodexAppServerClient,
|
|
request,
|
|
emit(notification: CodexServerNotification): void {
|
|
for (const handler of handlers) {
|
|
handler(notification);
|
|
}
|
|
},
|
|
};
|
|
}
|