Files
paseo/packages/app/e2e/support/fixtures/acp-chunks-plugin/index.server.ts
Lukas BuckandMohamed Boudra 4be34f05ef fix(plugin): continue one timeline item across ACP chunks without messageId (#4701)
* fix(plugin): continue one timeline item across ACP chunks without messageId

The plugin ACP reducer minted a new fallback id for every
agent_message_chunk / agent_thought_chunk that carried no messageId, so
a streamed reply rendered as one block per chunk, splitting words and
Markdown delimiters (#4699). Keep one fallback id per chunk kind and end
it on a chunk of the other kind, a tool call, a plan, a user message, or
a turn boundary, matching the server-side ACP provider.

* fix(plugin): end the other chunk kind's item on any chunk

A chunk of one kind now ends the other kind's fallback item before the
content or id is looked at, so an explicit-id text chunk between two
id-less thoughts yields three items instead of merging the thoughts.
The test declares the streamed updates through the connector harness
instead of handling protocol frames itself.

* test(plugin): verify ACP message boundaries and rendered Markdown

* test(app): synchronize rewind setup and menu selection

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-09-15 21:25:27 +02:00

47 lines
1.6 KiB
TypeScript

import type { PluginServerContext } from "@getpaseo/plugin/server";
import { runAcpProvider, type AcpStreamMessage } from "@getpaseo/plugin/server/acp";
function connect() {
let controller: ReadableStreamDefaultController<AcpStreamMessage>;
return {
readable: new ReadableStream<AcpStreamMessage>({
start(value) {
controller = value;
},
}),
writable: new WritableStream<AcpStreamMessage>({
write(message) {
if (!("method" in message) || !("id" in message)) return;
let result: unknown = {};
if (message.method === "initialize") result = { protocolVersion: 1, agentCapabilities: {} };
if (message.method === "session/new") result = { sessionId: "chunks" };
if (message.method === "session/prompt") {
for (const text of [
"- **Current tem",
"perature**: 25°C. Read [Paseo ",
"docs](https://example.com/docs).",
]) {
controller.enqueue({
jsonrpc: "2.0",
method: "session/update",
params: {
sessionId: "chunks",
update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text } },
},
});
}
result = { stopReason: "end_turn" };
}
controller.enqueue({ jsonrpc: "2.0", id: message.id, result });
},
}),
};
}
export default function contribute(server: PluginServerContext) {
server.registerProvider(
runAcpProvider({ id: "acp-chunks", label: "ACP chunks", connector: connect }),
);
return () => {};
}