/** * TASK-0123 — AI writing tools DTOs (zod; validated by `ZodValidate`). * * Limits (spec §Limits): ≤50 blocks (422 — also re-checked in the service, * where it is the 422-with-details path), selected text ≤100k chars (413 — * the assembler's check, since the server assembles the content), language * ≤64 chars (trim + cap; the UI constrains it too), action = the spec's * four tools. */ import { z } from "zod"; import { WRITING_ACTIONS } from "./prompts.js"; // NOTE: the >50 cap is intentionally NOT a zod refine (that would be a 400 // VALIDATION_ERROR); the service returns the spec's 422 with details. export const AiWritingDto = z.object({ /** The selected block IDs (duplicates are de-duped server-side; the >50 * cap is the service's 422 `too_many_blocks` check, per spec §Limits). */ blockIds: z.array(z.string().min(1)).min(1), /** The anchor page the selection is rendered on (UI provenance; the * blocks' own pages carry the permission checks). */ pageId: z.string().min(1), /** The writing action (the spec's four tools). */ action: z.enum(WRITING_ACTIONS), /** Target language for `translate` (trim + cap 64; ignored otherwise). */ language: z.string().trim().max(64).optional(), }); export type AiWritingInput = z.infer; export const ApplyWritingDto = z.object({ /** The assistant message id from the stream's `done.assistantMessageId`. */ suggestionId: z.string().min(1), /** Subset of the suggestion's blockIds ("accept one"); omitted = all. * Must be a subset — unknown ids are a 422 (no smuggling). */ blockIds: z.array(z.string().min(1)).min(1).optional(), }); export type ApplyWritingInput = z.infer;