feat(agent): render local interactive answers and fold completed process
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { toAgentChatMessages, toAgentUiMessages } from "./agent-session-message-state";
|
||||
import { applySessionStreamEvent, toAgentChatMessages, toAgentUiMessages } from "./agent-session-message-state";
|
||||
|
||||
describe("task context in persisted answers", () => {
|
||||
it("keeps the report reference of each answer when history is restored", () => {
|
||||
@@ -44,3 +44,42 @@ describe("task context in persisted answers", () => {
|
||||
expect(messages[0]?.content).toBe("报告引用未记录。");
|
||||
});
|
||||
});
|
||||
|
||||
describe("rich answer replay", () => {
|
||||
const block = { version: "answer-ui@1", block_id: "reading", fallback_text: "演练读数", spec: { root: "metric", elements: { metric: { type: "Metric", props: { label: "压力", value: "0.3", unit: "MPa", source: "演练数据" }, children: [] } } } };
|
||||
it("keeps text, component and summary in their original order across history restoration", () => {
|
||||
const messages = toAgentUiMessages([{ id: "answer", role: "assistant", parts: [
|
||||
{ type: "text", text: "下面是演练数据。" },
|
||||
{ type: "data-answer_ui", id: "reading", data: block },
|
||||
{ type: "text", text: "需要现场核验。" },
|
||||
{ type: "data-final_answer", data: { content: "结论仍待确认。", ui_block_ids: ["reading"] } },
|
||||
] }]);
|
||||
const restored = toAgentChatMessages(messages, {}, {})[0];
|
||||
expect(restored.answerParts?.map((part) => part.type)).toEqual(["text", "answer-ui", "text"]);
|
||||
expect(restored.content).toContain("演练读数");
|
||||
expect(restored.answerParts).toContainEqual({ type: "text", text: "需要现场核验。" });
|
||||
expect(restored.content).not.toContain("需要现场核验。");
|
||||
});
|
||||
it("updates a block once and appends later tokens after it without duplicating final text", () => {
|
||||
let messages = toAgentUiMessages([{ id: "answer", role: "assistant", parts: [{ type: "text", text: "演练:" }] }]);
|
||||
messages = applySessionStreamEvent(messages, { type: "answer_ui", data: block });
|
||||
messages = applySessionStreamEvent(messages, { type: "answer_ui", data: { ...block, fallback_text: "新读数" } });
|
||||
messages = applySessionStreamEvent(messages, { type: "token", data: { content: "仍待核验。", ui_block_ids: ["reading"] } });
|
||||
messages = applySessionStreamEvent(messages, { type: "final_answer", data: { content: "仍待核验。", ui_block_ids: ["reading"] } });
|
||||
const answer = toAgentChatMessages(messages, {}, {})[0];
|
||||
expect(answer.answerParts?.map((part) => part.type)).toEqual(["text", "answer-ui", "text"]);
|
||||
expect(answer.content.match(/新读数/g)).toHaveLength(1);
|
||||
expect(answer.content.match(/仍待核验/g)).toHaveLength(1);
|
||||
});
|
||||
it("falls back to text when an old or malformed UI block cannot be rendered", () => {
|
||||
const messages = toAgentUiMessages([{ id: "answer", role: "assistant", parts: [{ type: "data-answer_ui", data: { ...block, version: "unknown" } }] }]);
|
||||
expect(toAgentChatMessages(messages, {}, {})[0].answerParts).toEqual([{ type: "text", text: "演练读数" }]);
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps a malformed persisted data payload from crashing the conversation", () => {
|
||||
for (const data of [null, undefined, "invalid"]) {
|
||||
const messages = toAgentUiMessages([{ id: "answer", role: "assistant", parts: [{ type: "data-answer_ui", data }] }]);
|
||||
expect(toAgentChatMessages(messages, {}, {})[0].content).toBe("这段结构化内容无法显示。");
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user