Z ZPI 文档 v0.3.8
介绍页

源码

packages/ui/test/user-question-presentation.test.ts

typescript58 行查看原文
import { expect, test } from "vitest";
import type { ToolView } from "../src/components/tool-presentation.ts";
import { questionPresentation } from "../src/components/user-question-presentation.ts";

const block: ToolView = {
  id: "m:0",
  messageId: "m",
  type: "tool",
  toolCallId: "q",
  name: "AskUserQuestion",
  argsText: JSON.stringify({ questions: [{ question: "去哪?" }, { question: "几天?" }] }),
  status: "completed",
  output: "",
};

test("uses structured answers independently of the tool's display text", () => {
  const presentation = questionPresentation({
    ...block,
    output: '回答:{"answers":{"去哪?":"上海"}}',
    questionAnswers: { answers: { "去哪?": "北京", "几天?": "2天, 3天" } },
  });
  expect(presentation.summary).toBe("2 个问题");
  expect(presentation.questions.map((question) => question.answer)).toEqual(["北京", "2天, 3天"]);
});

test("unanswered and interrupted questions keep the ZCode question record instead of raw tool data", () => {
  expect(questionPresentation({ ...block, questionAnswers: { answers: {} } }).summary).toBe(
    "未回答,已自动继续",
  );
  const failed = questionPresentation({
    ...block,
    status: "error",
    output: "Interrupted: side effects unknown; tool was not replayed.",
  });
  expect(failed.summary).toBe("2 个问题");
  expect(failed.questions.map((question) => question.answer)).toEqual(["未提供回答", "未提供回答"]);
  expect(questionPresentation({ ...block, status: "running" }).running).toBe(true);
});

test("tolerates incomplete streamed parameters and leaves skipped answers explicit", () => {
  expect(questionPresentation({ ...block, argsText: '{"questions":[' }).questions).toEqual([]);
  const presentation = questionPresentation({ ...block, questionAnswers: { answers: { "去哪?": "北京" } } });
  expect(presentation.questions[1].answer).toBe("未提供回答");
});

test("question text cannot pick up inherited object properties as an answer", () => {
  const argsText = JSON.stringify({ questions: [{ question: "__proto__" }, { question: "toString" }] });
  expect(questionPresentation({ ...block, argsText }).questions.map((question) => question.answer)).toEqual([
    "未提供回答",
    "未提供回答",
  ]);
  const questionAnswers = { answers: Object.fromEntries([["__proto__", "A"]]) };
  expect(questionPresentation({ ...block, argsText, questionAnswers }).questions[0].answer).toBe("A");
  expect(questionPresentation({ ...block, argsText, questionAnswers }).questions[1].answer).toBe(
    "未提供回答",
  );
});