
























@@ -30,6 +30,19 @@ function startCompaction(sessionFile: string, options: { currentTokenCount?: num
3030});
3131}
323233+type CompactResult = NonNullable<Awaited<ReturnType<typeof maybeCompactCodexAppServerSession>>>;
34+35+function requireCompactResult(result: CompactResult | undefined): CompactResult {
36+if (!result) {
37+throw new Error("expected compaction result");
38+}
39+return result;
40+}
41+42+function compactDetails(result: CompactResult): Record<string, unknown> {
43+return (result.result?.details ?? {}) as Record<string, unknown>;
44+}
45+3346describe("maybeCompactCodexAppServerSession", () => {
3447beforeEach(async () => {
3548tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-compact-"));
@@ -61,21 +74,16 @@ describe("maybeCompactCodexAppServerSession", () => {
6174method: "thread/compacted",
6275params: { threadId: "thread-1", turnId: "turn-1" },
6376});
64-const result = await pendingResult;
77+const result = requireCompactResult(await pendingResult);
657866-expect(result).toMatchObject({
67-ok: true,
68-compacted: true,
69-result: {
70-tokensBefore: 123,
71-details: {
72-backend: "codex-app-server",
73-threadId: "thread-1",
74-signal: "thread/compacted",
75-turnId: "turn-1",
76-},
77-},
78-});
79+expect(result.ok).toBe(true);
80+expect(result.compacted).toBe(true);
81+expect(result.result?.tokensBefore).toBe(123);
82+const details = compactDetails(result);
83+expect(details.backend).toBe("codex-app-server");
84+expect(details.threadId).toBe("thread-1");
85+expect(details.signal).toBe("thread/compacted");
86+expect(details.turnId).toBe("turn-1");
7987});
80888189it("accepts native context-compaction item completion as success", async () => {
@@ -96,16 +104,12 @@ describe("maybeCompactCodexAppServerSession", () => {
96104},
97105});
9810699-await expect(pendingResult).resolves.toMatchObject({
100-ok: true,
101-compacted: true,
102-result: {
103-details: {
104-signal: "item/completed",
105-itemId: "compact-1",
106-},
107-},
108-});
107+const result = requireCompactResult(await pendingResult);
108+expect(result.ok).toBe(true);
109+expect(result.compacted).toBe(true);
110+const details = compactDetails(result);
111+expect(details.signal).toBe("item/completed");
112+expect(details.itemId).toBe("compact-1");
109113});
110114111115it("reuses the bound auth profile for native compaction", async () => {
@@ -205,26 +209,25 @@ describe("maybeCompactCodexAppServerSession", () => {
205209params: { threadId: "thread-1", turnId: "turn-1" },
206210});
207211208-await expect(pendingResult).resolves.toMatchObject({
209-ok: true,
210-compacted: true,
211-result: {
212-summary: "engine summary",
213-firstKeptEntryId: "entry-1",
214-tokensBefore: 55,
215-details: {
216-engine: "lossless-claw",
217-codexNativeCompaction: {
218-ok: true,
219-compacted: true,
220-details: {
221-backend: "codex-app-server",
222-threadId: "thread-1",
223-},
224-},
225-},
226-},
227-});
212+const result = requireCompactResult(await pendingResult);
213+expect(result.ok).toBe(true);
214+expect(result.compacted).toBe(true);
215+expect(result.result?.summary).toBe("engine summary");
216+expect(result.result?.firstKeptEntryId).toBe("entry-1");
217+expect(result.result?.tokensBefore).toBe(55);
218+const details = compactDetails(result);
219+expect(details.engine).toBe("lossless-claw");
220+const nativeDetails = details.codexNativeCompaction as
221+| {
222+ok?: boolean;
223+compacted?: boolean;
224+details?: { backend?: string; threadId?: string };
225+}
226+| undefined;
227+expect(nativeDetails?.ok).toBe(true);
228+expect(nativeDetails?.compacted).toBe(true);
229+expect(nativeDetails?.details?.backend).toBe("codex-app-server");
230+expect(nativeDetails?.details?.threadId).toBe("thread-1");
228231expect(compact).toHaveBeenCalledTimes(1);
229232const [compactCall] = compact.mock.calls[0] ?? [];
230233expect(compactCall).toStrictEqual({
@@ -292,18 +295,14 @@ describe("maybeCompactCodexAppServerSession", () => {
292295params: { threadId: "thread-1", turnId: "turn-1" },
293296});
294297295-await expect(pendingResult).resolves.toMatchObject({
296-ok: true,
297-compacted: true,
298-result: {
299-details: {
300-codexNativeCompaction: {
301-ok: true,
302-compacted: true,
303-},
304-},
305-},
306-});
298+const result = requireCompactResult(await pendingResult);
299+expect(result.ok).toBe(true);
300+expect(result.compacted).toBe(true);
301+const nativeDetails = compactDetails(result).codexNativeCompaction as
302+| { ok?: boolean; compacted?: boolean }
303+| undefined;
304+expect(nativeDetails?.ok).toBe(true);
305+expect(nativeDetails?.compacted).toBe(true);
307306});
308307309308it("records native compaction status when primary compaction has no result payload", async () => {
@@ -337,20 +336,16 @@ describe("maybeCompactCodexAppServerSession", () => {
337336params: { threadId: "thread-1", turnId: "turn-1" },
338337});
339338340-await expect(pendingResult).resolves.toMatchObject({
341-ok: true,
342-compacted: false,
343-reason: "below threshold",
344-result: {
345-tokensBefore: 222,
346-details: {
347-codexNativeCompaction: {
348-ok: true,
349-compacted: true,
350-},
351-},
352-},
353-});
339+const result = requireCompactResult(await pendingResult);
340+expect(result.ok).toBe(true);
341+expect(result.compacted).toBe(false);
342+expect(result.reason).toBe("below threshold");
343+expect(result.result?.tokensBefore).toBe(222);
344+const nativeDetails = compactDetails(result).codexNativeCompaction as
345+| { ok?: boolean; compacted?: boolean }
346+| undefined;
347+expect(nativeDetails?.ok).toBe(true);
348+expect(nativeDetails?.compacted).toBe(true);
354349});
355350356351it("reports context-engine compaction errors without skipping native compaction", async () => {
@@ -382,23 +377,21 @@ describe("maybeCompactCodexAppServerSession", () => {
382377params: { threadId: "thread-1", turnId: "turn-1" },
383378});
384379385-await expect(pendingResult).resolves.toMatchObject({
386-ok: false,
387-compacted: true,
388-reason: "context engine compaction failed: engine boom",
389-result: {
390-details: {
391-contextEngineCompaction: {
392-ok: false,
393-reason: "context engine compaction failed: engine boom",
394-},
395-codexNativeCompaction: {
396-ok: true,
397-compacted: true,
398-},
399-},
400-},
401-});
380+const result = requireCompactResult(await pendingResult);
381+expect(result.ok).toBe(false);
382+expect(result.compacted).toBe(true);
383+expect(result.reason).toBe("context engine compaction failed: engine boom");
384+const details = compactDetails(result);
385+const engineDetails = details.contextEngineCompaction as
386+| { ok?: boolean; reason?: string }
387+| undefined;
388+const nativeDetails = details.codexNativeCompaction as
389+| { ok?: boolean; compacted?: boolean }
390+| undefined;
391+expect(engineDetails?.ok).toBe(false);
392+expect(engineDetails?.reason).toBe("context engine compaction failed: engine boom");
393+expect(nativeDetails?.ok).toBe(true);
394+expect(nativeDetails?.compacted).toBe(true);
402395});
403396404397it("does not fail owning context-engine compaction when Codex native compaction cannot run", async () => {
@@ -425,20 +418,16 @@ describe("maybeCompactCodexAppServerSession", () => {
425418 contextEngine,
426419});
427420428-expect(result).toMatchObject({
429-ok: true,
430-compacted: true,
431-result: {
432-summary: "engine summary",
433-details: {
434-codexNativeCompaction: {
435-ok: false,
436-compacted: false,
437-reason: "no codex app-server thread binding",
438-},
439-},
440-},
441-});
421+const compactResult = requireCompactResult(result);
422+expect(compactResult.ok).toBe(true);
423+expect(compactResult.compacted).toBe(true);
424+expect(compactResult.result?.summary).toBe("engine summary");
425+const nativeDetails = compactDetails(compactResult).codexNativeCompaction as
426+| { ok?: boolean; compacted?: boolean; reason?: string }
427+| undefined;
428+expect(nativeDetails?.ok).toBe(false);
429+expect(nativeDetails?.compacted).toBe(false);
430+expect(nativeDetails?.reason).toBe("no codex app-server thread binding");
442431});
443432});
444433此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。