import type { StreamFn } from "@mariozechner/pi-agent-core"; import {
createAssistantMessageEventStream,
type AssistantMessage,
type Context,
type Model,
} from "@mariozechner/pi-ai"; import { describe, expect, it } from "vitest"; import {
applyPluginTextReplacements,
mergePluginTextTransforms,
transformStreamContextText,
wrapStreamFnTextTransforms,
} from "./plugin-text-transforms.js";
const model = {
api: "openai-responses",
provider: "test",
id: "test-model",
} as Model<"openai-responses">;
describe("plugin text transforms", () => {
it("merges registered transform groups in order", () => { const merged = mergePluginTextTransforms(
{ input: [{ from: /red basket/g, to: "blue basket" }] },
{ output: [{ from: /blue basket/g, to: "red basket" }] },
{ input: [{ from: /paper ticket/g, to: "digital ticket" }] },
);
expect(merged?.input).toHaveLength(2);
expect(merged?.output).toHaveLength(1);
expect(applyPluginTextReplacements("red basket paper ticket", merged?.input)).toBe( "blue basket digital ticket",
);
});
it("applies ordered string and regexp replacements", () => {
expect(
applyPluginTextReplacements("paper ticket on the left shelf", [
{ from: /paper ticket/g, to: "digital ticket" },
{ from: /left shelf/g, to: "right shelf" },
{ from: "digital ticket", to: "counter receipt" },
]),
).toBe("counter receipt on the right shelf");
});
it("rewrites system prompt and message text content before transport", () => { const context = transformStreamContextText(
{
systemPrompt: "Use orchid mailbox inside north tower",
messages: [
{
role: "user",
content: [
{ type: "text", text: "Please use the red basket" },
{ type: "image", url: "data:image/png;base64,abc" },
],
},
],
} as Context,
[
{
from: /orchid mailbox/g,
to: "pine mailbox",
},
{ from: /red basket/g, to: "blue basket" },
],
) as unknown as { systemPrompt: string; messages: Array<{ content: unknown[] }> };
expect(context.systemPrompt).toBe("Use pine mailbox inside north tower");
expect(context.messages[0]?.content[0]).toMatchObject({
type: "text",
text: "Please use the blue basket",
});
expect(context.messages[0]?.content[1]).toMatchObject({
type: "image",
url: "data:image/png;base64,abc",
});
});
it("wraps stream functions with inbound and outbound replacements", async () => {
let capturedContext: Context | undefined; const baseStreamFn: StreamFn = (_model, context) => {
capturedContext = context; const stream = createAssistantMessageEventStream();
queueMicrotask(() => { const partial = makeAssistantMessage("blue basket on the right shelf");
stream.push({
type: "text_delta",
contentIndex: 0,
delta: "blue basket on the right shelf",
partial,
});
stream.push({
type: "done",
reason: "stop",
message: makeAssistantMessage("final blue basket on the right shelf"),
});
stream.end();
}); return stream;
};
const wrapped = wrapStreamFnTextTransforms({
streamFn: baseStreamFn,
input: [{ from: /red basket/g, to: "blue basket" }],
output: [
{ from: /blue basket/g, to: "red basket" },
{ from: /right shelf/g, to: "left shelf" },
],
transformSystemPrompt: false,
}); const stream = await Promise.resolve(
wrapped(
model,
{
systemPrompt: "Keep red basket untouched here",
messages: [{ role: "user", content: "Use red basket" }],
} as Context,
undefined,
),
); const events = []; for await (const event of stream) {
events.push(event);
} const result = await stream.result();
expect(capturedContext?.systemPrompt).toBe("Keep red basket untouched here");
expect(capturedContext?.messages).toMatchObject([{ role: "user", content: "Use blue basket" }]);
expect(events[0]).toMatchObject({
type: "text_delta",
delta: "red basket on the left shelf",
});
expect(result.content).toMatchObject([
{ type: "text", text: "final red basket on the left shelf" },
]);
});
});
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.