88 lines
2.2 KiB
TypeScript
88 lines
2.2 KiB
TypeScript
const A2UI_ACTION_KEYS = [
|
|
"beginRendering",
|
|
"surfaceUpdate",
|
|
"dataModelUpdate",
|
|
"deleteSurface",
|
|
"createSurface",
|
|
] as const;
|
|
|
|
export type A2UIVersion = "v0.8" | "v0.9";
|
|
|
|
export function buildA2UITextJsonl(text: string) {
|
|
const surfaceId = "main";
|
|
const rootId = "root";
|
|
const textId = "text";
|
|
const payloads = [
|
|
{
|
|
surfaceUpdate: {
|
|
surfaceId,
|
|
components: [
|
|
{
|
|
id: rootId,
|
|
component: { Column: { children: { explicitList: [textId] } } },
|
|
},
|
|
{
|
|
id: textId,
|
|
component: {
|
|
Text: { text: { literalString: text }, usageHint: "body" },
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{ beginRendering: { surfaceId, root: rootId } },
|
|
];
|
|
return payloads.map((payload) => JSON.stringify(payload)).join("\n");
|
|
}
|
|
|
|
export function validateA2UIJsonl(jsonl: string) {
|
|
const lines = jsonl.split(/\r?\n/);
|
|
const errors: string[] = [];
|
|
let sawV08 = false;
|
|
let sawV09 = false;
|
|
let messageCount = 0;
|
|
|
|
lines.forEach((line, idx) => {
|
|
const trimmed = line.trim();
|
|
if (!trimmed) return;
|
|
messageCount += 1;
|
|
let obj: unknown;
|
|
try {
|
|
obj = JSON.parse(trimmed) as unknown;
|
|
} catch (err) {
|
|
errors.push(`line ${idx + 1}: ${String(err)}`);
|
|
return;
|
|
}
|
|
if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
|
|
errors.push(`line ${idx + 1}: expected JSON object`);
|
|
return;
|
|
}
|
|
const record = obj as Record<string, unknown>;
|
|
const actionKeys = A2UI_ACTION_KEYS.filter((key) => key in record);
|
|
if (actionKeys.length !== 1) {
|
|
errors.push(
|
|
`line ${idx + 1}: expected exactly one action key (${A2UI_ACTION_KEYS.join(", ")})`,
|
|
);
|
|
return;
|
|
}
|
|
if (actionKeys[0] === "createSurface") {
|
|
sawV09 = true;
|
|
} else {
|
|
sawV08 = true;
|
|
}
|
|
});
|
|
|
|
if (messageCount === 0) {
|
|
errors.push("no JSONL messages found");
|
|
}
|
|
if (sawV08 && sawV09) {
|
|
errors.push("mixed A2UI v0.8 and v0.9 messages in one file");
|
|
}
|
|
if (errors.length > 0) {
|
|
throw new Error(`Invalid A2UI JSONL:\n- ${errors.join("\n- ")}`);
|
|
}
|
|
|
|
const version: A2UIVersion = sawV09 ? "v0.9" : "v0.8";
|
|
return { version, messageCount };
|
|
}
|