mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-07 17:04:42 +00:00
test(acp): preserve post-response history replay diagnosis
Keep a passing protocol-order control and two failing post-response replay cases for #4108. The controlled peer uses the public provider interface over real stdio. Co-authored-by: xingzhi <chuzihao.czh@alibaba-inc.com>
This commit is contained in:
co-authored by
xingzhi
parent
a449271d57
commit
a72721b387
@@ -0,0 +1,66 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { ACPAgentClient } from "./acp-agent.js";
|
||||
import { createTestLogger } from "../../../test-utils/test-logger.js";
|
||||
import type { AgentStreamEvent } from "../agent-sdk-types.js";
|
||||
|
||||
// A mode request deterministically releases replay through a controlled stdio peer.
|
||||
// Post-result cases deliberately violate the protocol completion boundary.
|
||||
const peer = String.raw`
|
||||
import { createInterface } from 'node:readline';
|
||||
const beforeResult = process.argv[1] === 'before';
|
||||
const send = (value) => process.stdout.write(JSON.stringify({jsonrpc:'2.0', ...value})+'\n');
|
||||
const update = (kind, id, text) => send({method:'session/update', params:{sessionId:'saved',update:{sessionUpdate:kind,messageId:id,content:{type:'text',text}}}});
|
||||
const tail = () => {
|
||||
update('agent_message_chunk','reply-1','first reply');
|
||||
update('user_message_chunk','user-2','follow up');
|
||||
update('agent_message_chunk','reply-2','second reply');
|
||||
};
|
||||
for await (const line of createInterface({input:process.stdin})) {
|
||||
const request = JSON.parse(line);
|
||||
if (request.method === 'initialize') {
|
||||
send({id:request.id,result:{protocolVersion:1,agentCapabilities:{loadSession:true},authMethods:[]}});
|
||||
} else if (request.method === 'session/load') {
|
||||
update('user_message_chunk','user-1','first prompt');
|
||||
if (beforeResult) tail();
|
||||
send({id:request.id,result:{modes:{currentModeId:'default',availableModes:[{id:'default',name:'Default'}]}}});
|
||||
} else if (request.method === 'session/set_mode') {
|
||||
if (!beforeResult) tail();
|
||||
send({id:request.id,result:{}});
|
||||
} else if (request.id !== undefined) {
|
||||
send({id:request.id,result:{}});
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
describe("ACP persisted history through a real stdio peer", () => {
|
||||
for (const order of ["before", "after", "during-drain"] as const) {
|
||||
test(`retains all turns with ${order} replay`, async () => {
|
||||
const client = new ACPAgentClient({
|
||||
provider: "acp",
|
||||
logger: createTestLogger(),
|
||||
defaultCommand: [process.execPath, "--input-type=module", "-e", peer, order],
|
||||
});
|
||||
const session = await client.resumeSession(
|
||||
{ provider: "acp", sessionId: "saved" },
|
||||
{ cwd: process.cwd() },
|
||||
);
|
||||
try {
|
||||
const collect = async () => {
|
||||
const events: AgentStreamEvent[] = [];
|
||||
for await (const event of session.streamHistory()) events.push(event);
|
||||
return events;
|
||||
};
|
||||
const pendingHistory = order === "during-drain" ? collect() : undefined;
|
||||
await session.setMode("default");
|
||||
const history = await (pendingHistory ?? collect());
|
||||
expect(
|
||||
history.flatMap((event) =>
|
||||
event.type === "timeline" && "text" in event.item ? [event.item.text] : [],
|
||||
),
|
||||
).toEqual(["first prompt", "first reply", "follow up", "second reply"]);
|
||||
} finally {
|
||||
await session.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user