mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-14 13:22:37 +00:00
test(timeline): preserve oversized history reproductions
Diagnostic tests for #2220. These intentionally fail on main; no production behavior is changed.
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import { expect, test } from "vitest";
|
||||
import {
|
||||
mapCodexToolCallFromThreadItem,
|
||||
splitCodexMcpToolResultImages,
|
||||
} from "./tool-call-mapper.js";
|
||||
|
||||
test("Codex screenshot metadata takes the existing image extraction path", () => {
|
||||
const result = {
|
||||
content: [{ type: "text", text: "Captured screenshot" }],
|
||||
_meta: {
|
||||
"codex/toolSurface": {
|
||||
screenshot: { url: "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ==", width: 1280 },
|
||||
},
|
||||
},
|
||||
};
|
||||
const mapped = mapCodexToolCallFromThreadItem({
|
||||
type: "mcpToolCall",
|
||||
id: "screenshot",
|
||||
server: "node_repl",
|
||||
tool: "js",
|
||||
status: "completed",
|
||||
result,
|
||||
});
|
||||
expect(JSON.stringify(mapped)).not.toContain("data:image");
|
||||
expect(splitCodexMcpToolResultImages(result).images).toEqual([
|
||||
{ data: "/9j/4AAQSkZJRgABAQ==", mimeType: "image/jpeg" },
|
||||
]);
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
import { mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { Writable } from "node:stream";
|
||||
import pino from "pino";
|
||||
import { expect, test } from "vitest";
|
||||
import { createDaemonTestContext } from "../test-utils/index.js";
|
||||
|
||||
// Diagnostic regression for #2220. The provider is faked; committed image-heavy
|
||||
// tool outputs and the daemon/client WebSocket exchange use production code.
|
||||
test.each([40, 0])(
|
||||
"fetching image-heavy history with limit %i keeps the direct connection usable",
|
||||
async (limit) => {
|
||||
const highWater: Array<{ bufferedAmount: number; maxBufferedBytes: number }> = [];
|
||||
const logger = pino(
|
||||
{ level: "warn" },
|
||||
new Writable({
|
||||
write(chunk, _encoding, callback) {
|
||||
const record = JSON.parse(chunk.toString());
|
||||
if (record.msg === "Closing physical WebSocket at outbound high-water mark")
|
||||
highWater.push(record);
|
||||
callback();
|
||||
},
|
||||
}),
|
||||
);
|
||||
const ctx = await createDaemonTestContext({ logger });
|
||||
const cwd = mkdtempSync(path.join(tmpdir(), "timeline-repro-"));
|
||||
try {
|
||||
const agent = await ctx.client.createAgent({ provider: "codex", cwd });
|
||||
const imageUrl = `data:image/jpeg;base64,${"A".repeat(14 * 1024 * 1024)}`;
|
||||
for (let index = 0; index < 5; index += 1) {
|
||||
await ctx.daemon.daemon.agentManager.appendTimelineItem(agent.id, {
|
||||
type: "tool_call",
|
||||
callId: `screenshot-${index}`,
|
||||
name: "node_repl.js",
|
||||
status: "completed",
|
||||
error: null,
|
||||
detail: {
|
||||
type: "unknown",
|
||||
input: { index },
|
||||
output: { _meta: { "codex/toolSurface": { screenshot: { url: imageUrl } } } },
|
||||
},
|
||||
});
|
||||
}
|
||||
// Control: the same connection and data work when the selected page is small.
|
||||
const one = await ctx.client.fetchAgentTimeline(agent.id, { direction: "tail", limit: 1 });
|
||||
expect(one.entries).toHaveLength(1);
|
||||
expect(one.hasOlder).toBe(true);
|
||||
|
||||
// A 40-item fetch (the app size) or limit 0 (the CLI logs request) should return a usable page,
|
||||
// with remaining history reachable by its cursors, rather than kill the socket.
|
||||
const fetch = ctx.client.fetchAgentTimeline(agent.id, { direction: "tail", limit });
|
||||
const outcome = await fetch.then(
|
||||
(page) => ({ page }),
|
||||
(error: Error) => ({ error }),
|
||||
);
|
||||
if ("error" in outcome) {
|
||||
expect(highWater).toMatchObject([
|
||||
{ bufferedAmount: 0, maxBufferedBytes: 64 * 1024 * 1024 },
|
||||
]);
|
||||
console.log({
|
||||
limit,
|
||||
selectedImageBytes: 5 * 14 * 1024 * 1024,
|
||||
close: outcome.error.message,
|
||||
bufferedAmount: highWater[0].bufferedAmount,
|
||||
});
|
||||
throw outcome.error;
|
||||
}
|
||||
expect(outcome.page.agentId).toBe(agent.id);
|
||||
} finally {
|
||||
await ctx.cleanup();
|
||||
rmSync(cwd, { recursive: true, force: true });
|
||||
}
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
Reference in New Issue
Block a user