mirror of
https://github.com/luckyyzh/pi-agent-integrated.git
synced 2026-10-03 02:59:35 +00:00
131 lines
4.5 KiB
JavaScript
131 lines
4.5 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
async function loadSubject() {
|
|
return import("./message-display.ts");
|
|
}
|
|
|
|
function assistant(content) {
|
|
return {
|
|
role: "assistant",
|
|
provider: "test",
|
|
model: "test-model",
|
|
content,
|
|
};
|
|
}
|
|
|
|
test("splits trailing final answer blocks from process blocks", async () => {
|
|
const { splitFinalAssistantBlocks } = await loadSubject();
|
|
const message = assistant([
|
|
{ type: "thinking", thinking: "work through it" },
|
|
{ type: "toolCall", toolCallId: "call-1", toolName: "bash", input: {} },
|
|
{ type: "text", text: "Final answer" },
|
|
{ type: "image", source: { type: "url", url: "https://example.com/final.png" } },
|
|
]);
|
|
|
|
const result = splitFinalAssistantBlocks(message, { isStreaming: false });
|
|
|
|
assert.deepEqual(result.answerBlocks.map((block) => block.type), ["text", "image"]);
|
|
assert.deepEqual(result.processBlocks.map((block) => block.type), ["thinking", "toolCall"]);
|
|
});
|
|
|
|
test("keeps pre-tool text in process blocks", async () => {
|
|
const { splitFinalAssistantBlocks } = await loadSubject();
|
|
const message = assistant([
|
|
{ type: "text", text: "I will inspect the repo first." },
|
|
{ type: "toolCall", toolCallId: "call-1", toolName: "bash", input: {} },
|
|
{ type: "text", text: "Final answer" },
|
|
]);
|
|
|
|
const result = splitFinalAssistantBlocks(message, { isStreaming: false });
|
|
|
|
assert.deepEqual(result.answerBlocks.map((block) => block.type), ["text"]);
|
|
assert.equal(result.answerBlocks[0].text, "Final answer");
|
|
assert.deepEqual(result.processBlocks.map((block) => block.type), ["text", "toolCall"]);
|
|
});
|
|
|
|
test("does not expose text before a trailing tool call as final answer", async () => {
|
|
const { splitFinalAssistantBlocks } = await loadSubject();
|
|
const message = assistant([
|
|
{ type: "thinking", thinking: "work through it" },
|
|
{ type: "text", text: "I need to call a tool." },
|
|
{ type: "toolCall", toolCallId: "call-1", toolName: "bash", input: {} },
|
|
]);
|
|
|
|
const result = splitFinalAssistantBlocks(message, { isStreaming: false });
|
|
|
|
assert.deepEqual(result.answerBlocks, []);
|
|
assert.deepEqual(result.processBlocks.map((block) => block.type), ["thinking", "text", "toolCall"]);
|
|
});
|
|
|
|
test("drops empty thinking blocks after completion", async () => {
|
|
const { getDisplayableAssistantBlocks, splitFinalAssistantBlocks } = await loadSubject();
|
|
const message = assistant([
|
|
{ type: "thinking", thinking: "" },
|
|
{ type: "text", text: "Final answer" },
|
|
]);
|
|
|
|
assert.deepEqual(
|
|
getDisplayableAssistantBlocks(message, { isStreaming: false }).map((block) => block.type),
|
|
["text"],
|
|
);
|
|
|
|
const result = splitFinalAssistantBlocks(message, { isStreaming: false });
|
|
assert.deepEqual(result.answerBlocks.map((block) => block.type), ["text"]);
|
|
assert.deepEqual(result.processBlocks, []);
|
|
});
|
|
|
|
test("keeps empty thinking while streaming", async () => {
|
|
const { splitFinalAssistantBlocks } = await loadSubject();
|
|
const message = assistant([
|
|
{ type: "thinking", thinking: "" },
|
|
{ type: "text", text: "Partial answer" },
|
|
]);
|
|
|
|
const result = splitFinalAssistantBlocks(message, { isStreaming: true });
|
|
|
|
assert.deepEqual(result.answerBlocks.map((block) => block.type), ["text"]);
|
|
assert.deepEqual(result.processBlocks.map((block) => block.type), ["thinking"]);
|
|
});
|
|
|
|
test("keeps deferred historical thinking placeholders", async () => {
|
|
const { getDisplayableAssistantBlocks } = await loadSubject();
|
|
const message = assistant([
|
|
{ type: "thinking", thinking: "", deferred: true },
|
|
{ type: "text", text: "Final answer" },
|
|
]);
|
|
|
|
assert.deepEqual(
|
|
getDisplayableAssistantBlocks(message, { isStreaming: false }).map((block) => block.type),
|
|
["thinking", "text"],
|
|
);
|
|
});
|
|
|
|
test("returns completed provider errors even when the message has no content", async () => {
|
|
const { getAssistantErrorMessage } = await loadSubject();
|
|
const message = {
|
|
...assistant([]),
|
|
stopReason: "error",
|
|
errorMessage: "OpenAI API error (403): request forbidden",
|
|
};
|
|
|
|
assert.equal(
|
|
getAssistantErrorMessage(message),
|
|
"OpenAI API error (403): request forbidden",
|
|
);
|
|
assert.equal(getAssistantErrorMessage(message, { isStreaming: true }), null);
|
|
});
|
|
|
|
test("falls back when a provider error has no message", async () => {
|
|
const { getAssistantErrorMessage } = await loadSubject();
|
|
|
|
assert.equal(
|
|
getAssistantErrorMessage({ ...assistant([]), stopReason: "error" }),
|
|
"Unknown provider error",
|
|
);
|
|
assert.equal(
|
|
getAssistantErrorMessage({ ...assistant([]), stopReason: "stop" }),
|
|
null,
|
|
);
|
|
});
|