Files
next-tjwater-frontend/src/features/agent/api/answer-view-state.ts
T
jiang c0e4231b83
Generic Container CI/CD / test-build-publish (push) Successful in 1m52s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 1m52s
feat: expand intelligent investigation workspace
2026-10-30 17:30:19 +08:00

45 lines
2.7 KiB
TypeScript

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<AnswerViewStateRecord> {
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);
}