import { z } from "zod"; import type { AnswerViewState } from "../answer-ui/answer-view-state"; const index = z.number().int().nonnegative(); const chartTable = z.object({ query: z.string(), sort: z.object({ column: index, descending: z.boolean() }).strict().nullable(), selection: z.array(index) }).strict(); const node = z.discriminatedUnion("type", [ z.object({ type: z.literal("Chart"), view: z.enum(["line", "bar", "table"]), hidden: z.array(index), range: z.tuple([index, index]), point: index, inspecting: z.boolean(), table: chartTable.optional() }).strict(), z.object({ type: z.literal("Table"), query: z.string(), sort: z.object({ column: index, descending: z.boolean() }).strict().nullable(), selection: z.array(index) }).strict(), z.object({ type: z.literal("FollowUpForm"), values: z.record(z.string()) }).strict(), z.object({ type: z.literal("Evidence"), open: z.boolean() }).strict(), ]); const record = z.object({ version: z.literal("answer-view-state@1"), message_id: z.string(), block_id: z.string(), revision: index, schema_digest: z.string().min(1), nodes: z.record(node), block: z.object({ evidenceFilter: z.string() }).strict(), updated_at: z.string().nullable(), }).strict(); export type AnswerViewStateRecord = AnswerViewState & { version: "answer-view-state@1"; message_id: string; block_id: string; revision: number; schema_digest: string; updated_at: string | null; }; export type AnswerViewStateWrite = AnswerViewState & { message_id: string; block_id: string; schema_digest: string; expected_revision: number; request_id: string; }; export class AnswerViewStateApiError extends Error { constructor(message: string, readonly status: number, readonly code?: string, readonly current?: AnswerViewStateRecord) { super(message); this.name = "AnswerViewStateApiError"; } } export function parseAnswerViewStateRecord(value: unknown): AnswerViewStateRecord { return record.parse(value) as AnswerViewStateRecord; } export async function readAnswerViewStateResponse(response: Response): Promise { const data: unknown = await response.json(); if (!response.ok) { const error = z.object({ code: z.string().optional(), detail: z.string().optional(), current: z.unknown().optional() }).passthrough().safeParse(data); const current = error.success && error.data.current ? record.safeParse(error.data.current) : null; throw new AnswerViewStateApiError(error.success ? error.data.detail ?? "交互状态未保存,请重试" : "交互状态暂不可用,请重试", response.status, error.success ? error.data.code : undefined, current?.success ? current.data as AnswerViewStateRecord : undefined); } return parseAnswerViewStateRecord(data); }