🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@stll/folio-agents

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@stll/folio-agents - npm Package Compare versions

Comparing version
0.2.0
to
0.3.0
+1576
dist/operation-schema.d.ts
import { FolioDocumentOperationBatch } from "@stll/folio-core/server";
//#region src/operation-schema.d.ts
/**
* JSON Schema for the contract's `textRange` handle (a serializable range
* over the visible text of one main-story block, as returned by `find_text`
* style tools). Shared between {@link FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA}
* and the `suggest_changes` tool schema in `tools.ts` so the two cannot
* drift. `endOffset` must be greater than `startOffset`; JSON Schema cannot
* express that relation, the parser enforces it.
*/
declare const FOLIO_TEXT_RANGE_JSON_SCHEMA: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["textRange"];
};
readonly story: {
readonly type: "string";
readonly enum: readonly ["main"];
};
readonly blockId: {
readonly type: "string";
readonly minLength: 1;
};
readonly startOffset: {
readonly type: "integer";
readonly minimum: 0;
};
readonly endOffset: {
readonly type: "integer";
readonly minimum: 1;
readonly description: "Exclusive end offset; must be greater than `startOffset`.";
};
readonly selectedTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the selected text, used to detect stale ranges.";
};
};
readonly required: readonly ["type", "story", "blockId", "startOffset", "endOffset", "selectedTextHash"];
readonly additionalProperties: false;
};
/**
* JSON Schema (draft-07 compatible) for ONE document operation: the full
* ten-variant union accepted by `parseFolioDocumentOperationBatch` in
* `@stll/folio-core`, one `oneOf` variant per entry in
* `FOLIO_DOCUMENT_OPERATION_TYPES`. Intended for LLM tool definitions and
* other consumers that need the contract's wire shape without re-declaring
* it; note that the `suggest_changes` tool in `tools.ts` deliberately
* narrows this union (see the comment there).
*/
declare const FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA: {
readonly description: string;
readonly oneOf: readonly [{
readonly type: "object";
readonly description: "Replace an exact text match inside one block.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["replaceInBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly find: {
readonly type: "string";
readonly description: "The exact text to find within the block.";
};
readonly replace: {
readonly type: "string";
readonly description: "The replacement text.";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "find", "replace"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Replace the text covered by a range handle.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["replaceRange"];
};
readonly range: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["textRange"];
};
readonly story: {
readonly type: "string";
readonly enum: readonly ["main"];
};
readonly blockId: {
readonly type: "string";
readonly minLength: 1;
};
readonly startOffset: {
readonly type: "integer";
readonly minimum: 0;
};
readonly endOffset: {
readonly type: "integer";
readonly minimum: 1;
readonly description: "Exclusive end offset; must be greater than `startOffset`.";
};
readonly selectedTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the selected text, used to detect stale ranges.";
};
};
readonly required: readonly ["type", "story", "blockId", "startOffset", "endOffset", "selectedTextHash"];
readonly additionalProperties: false;
};
readonly replace: {
readonly type: "string";
readonly description: "The replacement text.";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "range", "replace"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Attach a comment to the text covered by a range handle.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["commentOnRange"];
};
readonly range: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["textRange"];
};
readonly story: {
readonly type: "string";
readonly enum: readonly ["main"];
};
readonly blockId: {
readonly type: "string";
readonly minLength: 1;
};
readonly startOffset: {
readonly type: "integer";
readonly minimum: 0;
};
readonly endOffset: {
readonly type: "integer";
readonly minimum: 1;
readonly description: "Exclusive end offset; must be greater than `startOffset`.";
};
readonly selectedTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the selected text, used to detect stale ranges.";
};
};
readonly required: readonly ["type", "story", "blockId", "startOffset", "endOffset", "selectedTextHash"];
readonly additionalProperties: false;
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "range", "comment"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["formatRange"];
};
readonly range: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["textRange"];
};
readonly story: {
readonly type: "string";
readonly enum: readonly ["main"];
};
readonly blockId: {
readonly type: "string";
readonly minLength: 1;
};
readonly startOffset: {
readonly type: "integer";
readonly minimum: 0;
};
readonly endOffset: {
readonly type: "integer";
readonly minimum: 1;
readonly description: "Exclusive end offset; must be greater than `startOffset`.";
};
readonly selectedTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the selected text, used to detect stale ranges.";
};
};
readonly required: readonly ["type", "story", "blockId", "startOffset", "endOffset", "selectedTextHash"];
readonly additionalProperties: false;
};
readonly formatting: {
readonly type: "object";
readonly description: "Inline formatting to apply; at least one property is required.";
readonly properties: {
readonly bold: {
readonly type: "boolean";
};
readonly italic: {
readonly type: "boolean";
};
readonly underline: {
readonly type: "boolean";
};
};
readonly minProperties: 1;
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "range", "formatting"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Insert a new paragraph after the anchor block.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["insertAfterBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly text: {
readonly type: "string";
readonly description: "The paragraph text to insert.";
};
readonly inheritFormatting: {
readonly type: "boolean";
readonly description: "Inherit the anchor block's formatting for the inserted paragraph.";
};
readonly pageBreakBefore: {
readonly type: "boolean";
readonly description: "Start the inserted paragraph on a new page (`pageBreakBefore`).";
};
readonly styleId: {
readonly type: "string";
readonly description: "Paragraph style id for the inserted block (e.g. \"ClauseHeading1\").";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "text"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Insert a new paragraph before the anchor block.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["insertBeforeBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly text: {
readonly type: "string";
readonly description: "The paragraph text to insert.";
};
readonly inheritFormatting: {
readonly type: "boolean";
readonly description: "Inherit the anchor block's formatting for the inserted paragraph.";
};
readonly pageBreakBefore: {
readonly type: "boolean";
readonly description: "Start the inserted paragraph on a new page (`pageBreakBefore`).";
};
readonly styleId: {
readonly type: "string";
readonly description: "Paragraph style id for the inserted block (e.g. \"ClauseHeading1\").";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "text"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Replace one block's entire text.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["replaceBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly text: {
readonly type: "string";
readonly description: "The new block text.";
};
readonly preserveFormatting: {
readonly type: "boolean";
readonly description: "Keep the block's existing formatting for the replacement text.";
};
readonly styleId: {
readonly type: "string";
readonly description: "Paragraph style id to set on the replaced block.";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "text"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Delete one block.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["deleteBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Attach a comment to one block, optionally quoting text within it.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["commentOnBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly quote: {
readonly type: "string";
readonly description: "Exact text within the block the comment is about.";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "comment"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["insertSignatureTable"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly position: {
readonly type: "string";
readonly enum: readonly ["after", "before"];
readonly description: "Insert after the anchor block (default) or before it. Defaults to \"after\".";
};
readonly parties: {
readonly type: "array";
readonly description: "The signing parties, one table cell per party.";
readonly items: {
readonly type: "object";
readonly properties: {
readonly name: {
readonly type: "string";
readonly description: "Party name (rendered bold).";
};
readonly signatory: {
readonly type: "string";
readonly description: "Name of the person signing.";
};
readonly title: {
readonly type: "string";
readonly description: "Signatory title (rendered in italics).";
};
};
readonly required: readonly ["name"];
readonly additionalProperties: false;
};
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "parties"];
readonly additionalProperties: false;
}];
};
/**
* JSON Schema (draft-07 compatible) for the versioned batch envelope accepted
* by `parseFolioDocumentOperationBatch`: `version` (always
* `FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION`), `operations`, and the
* optional `mode` / `atomic` / `dryRun` flags — the exact wire shape of
* `FolioDocumentOperationBatch`. Hand this to an LLM tool definition (or any
* JSON Schema consumer) instead of re-declaring the contract.
*/
declare const FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly version: {
readonly type: "integer";
readonly enum: readonly [1];
readonly description: "Document-operation contract version.";
};
readonly operations: {
readonly type: "array";
readonly description: "The operations to apply, in order.";
readonly items: {
readonly description: string;
readonly oneOf: readonly [{
readonly type: "object";
readonly description: "Replace an exact text match inside one block.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["replaceInBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly find: {
readonly type: "string";
readonly description: "The exact text to find within the block.";
};
readonly replace: {
readonly type: "string";
readonly description: "The replacement text.";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "find", "replace"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Replace the text covered by a range handle.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["replaceRange"];
};
readonly range: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["textRange"];
};
readonly story: {
readonly type: "string";
readonly enum: readonly ["main"];
};
readonly blockId: {
readonly type: "string";
readonly minLength: 1;
};
readonly startOffset: {
readonly type: "integer";
readonly minimum: 0;
};
readonly endOffset: {
readonly type: "integer";
readonly minimum: 1;
readonly description: "Exclusive end offset; must be greater than `startOffset`.";
};
readonly selectedTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the selected text, used to detect stale ranges.";
};
};
readonly required: readonly ["type", "story", "blockId", "startOffset", "endOffset", "selectedTextHash"];
readonly additionalProperties: false;
};
readonly replace: {
readonly type: "string";
readonly description: "The replacement text.";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "range", "replace"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Attach a comment to the text covered by a range handle.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["commentOnRange"];
};
readonly range: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["textRange"];
};
readonly story: {
readonly type: "string";
readonly enum: readonly ["main"];
};
readonly blockId: {
readonly type: "string";
readonly minLength: 1;
};
readonly startOffset: {
readonly type: "integer";
readonly minimum: 0;
};
readonly endOffset: {
readonly type: "integer";
readonly minimum: 1;
readonly description: "Exclusive end offset; must be greater than `startOffset`.";
};
readonly selectedTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the selected text, used to detect stale ranges.";
};
};
readonly required: readonly ["type", "story", "blockId", "startOffset", "endOffset", "selectedTextHash"];
readonly additionalProperties: false;
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "range", "comment"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["formatRange"];
};
readonly range: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["textRange"];
};
readonly story: {
readonly type: "string";
readonly enum: readonly ["main"];
};
readonly blockId: {
readonly type: "string";
readonly minLength: 1;
};
readonly startOffset: {
readonly type: "integer";
readonly minimum: 0;
};
readonly endOffset: {
readonly type: "integer";
readonly minimum: 1;
readonly description: "Exclusive end offset; must be greater than `startOffset`.";
};
readonly selectedTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the selected text, used to detect stale ranges.";
};
};
readonly required: readonly ["type", "story", "blockId", "startOffset", "endOffset", "selectedTextHash"];
readonly additionalProperties: false;
};
readonly formatting: {
readonly type: "object";
readonly description: "Inline formatting to apply; at least one property is required.";
readonly properties: {
readonly bold: {
readonly type: "boolean";
};
readonly italic: {
readonly type: "boolean";
};
readonly underline: {
readonly type: "boolean";
};
};
readonly minProperties: 1;
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "range", "formatting"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Insert a new paragraph after the anchor block.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["insertAfterBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly text: {
readonly type: "string";
readonly description: "The paragraph text to insert.";
};
readonly inheritFormatting: {
readonly type: "boolean";
readonly description: "Inherit the anchor block's formatting for the inserted paragraph.";
};
readonly pageBreakBefore: {
readonly type: "boolean";
readonly description: "Start the inserted paragraph on a new page (`pageBreakBefore`).";
};
readonly styleId: {
readonly type: "string";
readonly description: "Paragraph style id for the inserted block (e.g. \"ClauseHeading1\").";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "text"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Insert a new paragraph before the anchor block.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["insertBeforeBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly text: {
readonly type: "string";
readonly description: "The paragraph text to insert.";
};
readonly inheritFormatting: {
readonly type: "boolean";
readonly description: "Inherit the anchor block's formatting for the inserted paragraph.";
};
readonly pageBreakBefore: {
readonly type: "boolean";
readonly description: "Start the inserted paragraph on a new page (`pageBreakBefore`).";
};
readonly styleId: {
readonly type: "string";
readonly description: "Paragraph style id for the inserted block (e.g. \"ClauseHeading1\").";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "text"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Replace one block's entire text.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["replaceBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly text: {
readonly type: "string";
readonly description: "The new block text.";
};
readonly preserveFormatting: {
readonly type: "boolean";
readonly description: "Keep the block's existing formatting for the replacement text.";
};
readonly styleId: {
readonly type: "string";
readonly description: "Paragraph style id to set on the replaced block.";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "text"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Delete one block.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["deleteBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: "Attach a comment to one block, optionally quoting text within it.";
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["commentOnBlock"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly quote: {
readonly type: "string";
readonly description: "Exact text within the block the comment is about.";
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "comment"];
readonly additionalProperties: false;
}, {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly type: {
readonly type: "string";
readonly enum: readonly ["insertSignatureTable"];
};
readonly blockId: {
readonly type: "string";
readonly description: "Id of the target block, from a prior document read.";
};
readonly position: {
readonly type: "string";
readonly enum: readonly ["after", "before"];
readonly description: "Insert after the anchor block (default) or before it. Defaults to \"after\".";
};
readonly parties: {
readonly type: "array";
readonly description: "The signing parties, one table cell per party.";
readonly items: {
readonly type: "object";
readonly properties: {
readonly name: {
readonly type: "string";
readonly description: "Party name (rendered bold).";
};
readonly signatory: {
readonly type: "string";
readonly description: "Name of the person signing.";
};
readonly title: {
readonly type: "string";
readonly description: "Signatory title (rendered in italics).";
};
};
readonly required: readonly ["name"];
readonly additionalProperties: false;
};
};
readonly comment: {
readonly type: "object";
readonly description: "A comment attached to the text affected by this operation.";
readonly properties: {
readonly text: {
readonly type: "string";
readonly description: "The comment body.";
};
};
readonly required: readonly ["text"];
readonly additionalProperties: false;
};
readonly id: {
readonly type: "string";
readonly description: string;
};
readonly severity: {
readonly type: "string";
readonly enum: readonly ["low", "medium", "high"];
readonly description: "Optional review severity for structured-review workflows.";
};
readonly area: {
readonly type: "string";
readonly description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows.";
};
readonly precondition: {
readonly type: "object";
readonly description: string;
readonly properties: {
readonly blockTextHash: {
readonly type: "string";
readonly pattern: "^h[0-9a-z]+$";
readonly description: "Normalized hash of the target block's text.";
};
};
readonly required: readonly ["blockTextHash"];
readonly additionalProperties: false;
};
};
readonly required: readonly ["id", "type", "blockId", "parties"];
readonly additionalProperties: false;
}];
};
};
readonly mode: {
readonly type: "string";
readonly enum: readonly ["direct", "tracked-changes"];
readonly description: string;
};
readonly atomic: {
readonly type: "boolean";
readonly description: "Reject the whole batch when any operation would be skipped.";
};
readonly dryRun: {
readonly type: "boolean";
readonly description: "Preview the batch without mutating the document.";
};
};
readonly required: readonly ["version", "operations"];
readonly additionalProperties: false;
};
/**
* Minimal structural subset of the Standard Schema V1 interface
* (https://standardschema.dev). Declared locally instead of depending on
* `@standard-schema/spec` — the spec is a tiny type-only interface designed
* to be inlined, and this keeps the package dependency-free. Consumers that
* accept the spec type (TanStack AI, tRPC, etc.) match it structurally.
*/
type StandardSchemaV1Issue = {
readonly message: string;
readonly path?: readonly PropertyKey[] | undefined;
};
type StandardSchemaV1Result<Output> = {
readonly value: Output;
readonly issues?: undefined;
} | {
readonly issues: readonly StandardSchemaV1Issue[];
};
type StandardSchemaV1<Input = unknown, Output = Input> = {
readonly "~standard": {
readonly version: 1;
readonly vendor: string;
readonly validate: (value: unknown) => StandardSchemaV1Result<Output>;
readonly types?: {
readonly input: Input;
readonly output: Output;
} | undefined;
};
};
type FolioDocumentOperationBatchSchema = StandardSchemaV1<unknown, FolioDocumentOperationBatch> & {
/**
* The batch envelope's JSON Schema
* ({@link FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA}), attached so tool
* builders get the runtime validator and the LLM-facing schema from one
* import.
*/
readonly jsonSchema: typeof FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA;
};
/**
* Standard Schema V1 (https://standardschema.dev) validator for a document
* operation batch, for spec-aware consumers (TanStack AI tool `inputSchema`,
* tRPC input, etc.). Delegates to `parseFolioDocumentOperationBatch` from
* `@stll/folio-core`, so the strict parser stays the single source of truth:
* `validate` never throws, returning `{ value }` with the parser's exact
* output on success and `{ issues }` (message plus a key path when the parser
* reported one) on failure. The matching LLM-facing JSON schema is attached
* as {@link FolioDocumentOperationBatchSchema.jsonSchema}.
*/
declare const folioDocumentOperationBatchSchema: FolioDocumentOperationBatchSchema;
//#endregion
export { FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA, FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA, FOLIO_TEXT_RANGE_JSON_SCHEMA, folioDocumentOperationBatchSchema };
import { FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, parseFolioDocumentOperationBatch } from "@stll/folio-core/server";
//#region src/operation-schema.ts
/**
* Reusable projections of folio's versioned document-operation contract for
* tool builders: a JSON Schema for one operation, a JSON Schema for the
* versioned batch envelope, and a Standard Schema V1 wrapper around
* `parseFolioDocumentOperationBatch` so downstream tool definitions (e.g.
* TanStack AI tools) can consume the contract directly instead of
* hand-mirroring it in valibot/zod.
*
* The strict throwing parser in `@stll/folio-core` stays the single source of
* truth for semantics; everything here is a projection of it. Constraints
* JSON Schema cannot express (`endOffset > startOffset`, unique operation
* ids within a batch, per-type mode support) are noted in `description`s and
* enforced by the parser.
*/
/**
* Pattern for the normalized text hashes the contract uses to detect stale
* targets (`selectedTextHash`, `precondition.blockTextHash`). Mirrors the
* parser's check in `@stll/folio-core`'s `document-operations.ts`.
*/
const NORMALIZED_TEXT_HASH_PATTERN = "^h[0-9a-z]+$";
/**
* JSON Schema for the contract's `textRange` handle (a serializable range
* over the visible text of one main-story block, as returned by `find_text`
* style tools). Shared between {@link FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA}
* and the `suggest_changes` tool schema in `tools.ts` so the two cannot
* drift. `endOffset` must be greater than `startOffset`; JSON Schema cannot
* express that relation, the parser enforces it.
*/
const FOLIO_TEXT_RANGE_JSON_SCHEMA = {
type: "object",
description: "A range over the visible text of one main-story block. Offsets are zero-based UTF-16 boundaries; `endOffset` must be greater than `startOffset`. Copy range objects verbatim from the tool that produced them — `selectedTextHash` makes a shifted or edited selection fail as stale instead of hitting the wrong text.",
properties: {
type: {
type: "string",
enum: ["textRange"]
},
story: {
type: "string",
enum: ["main"]
},
blockId: {
type: "string",
minLength: 1
},
startOffset: {
type: "integer",
minimum: 0
},
endOffset: {
type: "integer",
minimum: 1,
description: "Exclusive end offset; must be greater than `startOffset`."
},
selectedTextHash: {
type: "string",
pattern: NORMALIZED_TEXT_HASH_PATTERN,
description: "Normalized hash of the selected text, used to detect stale ranges."
}
},
required: [
"type",
"story",
"blockId",
"startOffset",
"endOffset",
"selectedTextHash"
],
additionalProperties: false
};
const preconditionJsonSchema = {
type: "object",
description: "Optional guard: the operation is skipped (reason `preconditionFailed`) unless the target block's normalized text hash still matches.",
properties: { blockTextHash: {
type: "string",
pattern: NORMALIZED_TEXT_HASH_PATTERN,
description: "Normalized hash of the target block's text."
} },
required: ["blockTextHash"],
additionalProperties: false
};
const commentJsonSchema = {
type: "object",
description: "A comment attached to the text affected by this operation.",
properties: { text: {
type: "string",
description: "The comment body."
} },
required: ["text"],
additionalProperties: false
};
/**
* Properties every operation variant accepts: the required `id` plus the
* optional review metadata (`severity`, `area`) and `precondition` guard.
*/
const operationMetaProperties = {
id: {
type: "string",
description: "Caller-supplied operation id, echoed back in `applied` / `skipped` results. Must be unique within a batch (enforced by the parser)."
},
severity: {
type: "string",
enum: [
"low",
"medium",
"high"
],
description: "Optional review severity for structured-review workflows."
},
area: {
type: "string",
description: "Optional review area label (e.g. \"Penalty\") for structured-review workflows."
},
precondition: preconditionJsonSchema
};
const blockIdProperty = {
type: "string",
description: "Id of the target block, from a prior document read."
};
/**
* JSON Schema (draft-07 compatible) for ONE document operation: the full
* ten-variant union accepted by `parseFolioDocumentOperationBatch` in
* `@stll/folio-core`, one `oneOf` variant per entry in
* `FOLIO_DOCUMENT_OPERATION_TYPES`. Intended for LLM tool definitions and
* other consumers that need the contract's wire shape without re-declaring
* it; note that the `suggest_changes` tool in `tools.ts` deliberately
* narrows this union (see the comment there).
*/
const FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA = {
description: "One document operation, discriminated by `type`. Mirrors the operation union accepted by `parseFolioDocumentOperationBatch` in @stll/folio-core.",
oneOf: [
{
type: "object",
description: "Replace an exact text match inside one block.",
properties: {
...operationMetaProperties,
type: {
type: "string",
enum: ["replaceInBlock"]
},
blockId: blockIdProperty,
find: {
type: "string",
description: "The exact text to find within the block."
},
replace: {
type: "string",
description: "The replacement text."
},
comment: commentJsonSchema
},
required: [
"id",
"type",
"blockId",
"find",
"replace"
],
additionalProperties: false
},
{
type: "object",
description: "Replace the text covered by a range handle.",
properties: {
...operationMetaProperties,
type: {
type: "string",
enum: ["replaceRange"]
},
range: FOLIO_TEXT_RANGE_JSON_SCHEMA,
replace: {
type: "string",
description: "The replacement text."
},
comment: commentJsonSchema
},
required: [
"id",
"type",
"range",
"replace"
],
additionalProperties: false
},
{
type: "object",
description: "Attach a comment to the text covered by a range handle.",
properties: {
...operationMetaProperties,
type: {
type: "string",
enum: ["commentOnRange"]
},
range: FOLIO_TEXT_RANGE_JSON_SCHEMA,
comment: commentJsonSchema
},
required: [
"id",
"type",
"range",
"comment"
],
additionalProperties: false
},
{
type: "object",
description: "Apply inline formatting to the text covered by a range handle. Direct mode only (formatting is not representable as a tracked change).",
properties: {
...operationMetaProperties,
type: {
type: "string",
enum: ["formatRange"]
},
range: FOLIO_TEXT_RANGE_JSON_SCHEMA,
formatting: {
type: "object",
description: "Inline formatting to apply; at least one property is required.",
properties: {
bold: { type: "boolean" },
italic: { type: "boolean" },
underline: { type: "boolean" }
},
minProperties: 1,
additionalProperties: false
}
},
required: [
"id",
"type",
"range",
"formatting"
],
additionalProperties: false
},
{
type: "object",
description: "Insert a new paragraph after the anchor block.",
properties: {
...operationMetaProperties,
type: {
type: "string",
enum: ["insertAfterBlock"]
},
blockId: blockIdProperty,
text: {
type: "string",
description: "The paragraph text to insert."
},
inheritFormatting: {
type: "boolean",
description: "Inherit the anchor block's formatting for the inserted paragraph."
},
pageBreakBefore: {
type: "boolean",
description: "Start the inserted paragraph on a new page (`pageBreakBefore`)."
},
styleId: {
type: "string",
description: "Paragraph style id for the inserted block (e.g. \"ClauseHeading1\")."
},
comment: commentJsonSchema
},
required: [
"id",
"type",
"blockId",
"text"
],
additionalProperties: false
},
{
type: "object",
description: "Insert a new paragraph before the anchor block.",
properties: {
...operationMetaProperties,
type: {
type: "string",
enum: ["insertBeforeBlock"]
},
blockId: blockIdProperty,
text: {
type: "string",
description: "The paragraph text to insert."
},
inheritFormatting: {
type: "boolean",
description: "Inherit the anchor block's formatting for the inserted paragraph."
},
pageBreakBefore: {
type: "boolean",
description: "Start the inserted paragraph on a new page (`pageBreakBefore`)."
},
styleId: {
type: "string",
description: "Paragraph style id for the inserted block (e.g. \"ClauseHeading1\")."
},
comment: commentJsonSchema
},
required: [
"id",
"type",
"blockId",
"text"
],
additionalProperties: false
},
{
type: "object",
description: "Replace one block's entire text.",
properties: {
...operationMetaProperties,
type: {
type: "string",
enum: ["replaceBlock"]
},
blockId: blockIdProperty,
text: {
type: "string",
description: "The new block text."
},
preserveFormatting: {
type: "boolean",
description: "Keep the block's existing formatting for the replacement text."
},
styleId: {
type: "string",
description: "Paragraph style id to set on the replaced block."
},
comment: commentJsonSchema
},
required: [
"id",
"type",
"blockId",
"text"
],
additionalProperties: false
},
{
type: "object",
description: "Delete one block.",
properties: {
...operationMetaProperties,
type: {
type: "string",
enum: ["deleteBlock"]
},
blockId: blockIdProperty,
comment: commentJsonSchema
},
required: [
"id",
"type",
"blockId"
],
additionalProperties: false
},
{
type: "object",
description: "Attach a comment to one block, optionally quoting text within it.",
properties: {
...operationMetaProperties,
type: {
type: "string",
enum: ["commentOnBlock"]
},
blockId: blockIdProperty,
quote: {
type: "string",
description: "Exact text within the block the comment is about."
},
comment: commentJsonSchema
},
required: [
"id",
"type",
"blockId",
"comment"
],
additionalProperties: false
},
{
type: "object",
description: "Insert a signature table next to the anchor block. Direct mode only (table insertion is not representable as a tracked change).",
properties: {
...operationMetaProperties,
type: {
type: "string",
enum: ["insertSignatureTable"]
},
blockId: blockIdProperty,
position: {
type: "string",
enum: ["after", "before"],
description: "Insert after the anchor block (default) or before it. Defaults to \"after\"."
},
parties: {
type: "array",
description: "The signing parties, one table cell per party.",
items: {
type: "object",
properties: {
name: {
type: "string",
description: "Party name (rendered bold)."
},
signatory: {
type: "string",
description: "Name of the person signing."
},
title: {
type: "string",
description: "Signatory title (rendered in italics)."
}
},
required: ["name"],
additionalProperties: false
}
},
comment: commentJsonSchema
},
required: [
"id",
"type",
"blockId",
"parties"
],
additionalProperties: false
}
]
};
/**
* JSON Schema (draft-07 compatible) for the versioned batch envelope accepted
* by `parseFolioDocumentOperationBatch`: `version` (always
* `FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION`), `operations`, and the
* optional `mode` / `atomic` / `dryRun` flags — the exact wire shape of
* `FolioDocumentOperationBatch`. Hand this to an LLM tool definition (or any
* JSON Schema consumer) instead of re-declaring the contract.
*/
const FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA = {
type: "object",
description: "A versioned batch of document operations. Operation ids must be unique within the batch (enforced by the parser, not expressible in JSON Schema).",
properties: {
version: {
type: "integer",
enum: [FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION],
description: "Document-operation contract version."
},
operations: {
type: "array",
description: "The operations to apply, in order.",
items: FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA
},
mode: {
type: "string",
enum: FOLIO_DOCUMENT_OPERATION_MODES,
description: "How edits land: \"tracked-changes\" (default) proposes revisions for human review, \"direct\" applies immediately. `formatRange` and `insertSignatureTable` support \"direct\" only."
},
atomic: {
type: "boolean",
description: "Reject the whole batch when any operation would be skipped."
},
dryRun: {
type: "boolean",
description: "Preview the batch without mutating the document."
}
},
required: ["version", "operations"],
additionalProperties: false
};
/**
* Convert the parser's JSONPath-style location (`$.operations[0].blockId`)
* into a Standard Schema issue path (`["operations", 0, "blockId"]`).
* Returns `undefined` for the root path so root-level issues carry no path.
*/
const toStandardSchemaPath = (path) => {
const segments = [];
for (const match of path.matchAll(/\.(?<key>[^.[\]]+)|\[(?<index>\d+)\]/gu)) {
const { key, index } = match.groups ?? {};
if (key !== void 0) segments.push(key);
else if (index !== void 0) segments.push(Number(index));
}
return segments.length > 0 ? segments : void 0;
};
const toStandardSchemaIssue = (error) => {
if (error instanceof InvalidFolioDocumentOperationBatchError) {
const path = toStandardSchemaPath(error.path);
return {
message: error.message,
...path !== void 0 && { path }
};
}
if (error instanceof UnsupportedFolioDocumentOperationVersionError) return {
message: error.message,
path: ["version"]
};
return { message: error instanceof Error ? error.message : String(error) };
};
/**
* Standard Schema V1 (https://standardschema.dev) validator for a document
* operation batch, for spec-aware consumers (TanStack AI tool `inputSchema`,
* tRPC input, etc.). Delegates to `parseFolioDocumentOperationBatch` from
* `@stll/folio-core`, so the strict parser stays the single source of truth:
* `validate` never throws, returning `{ value }` with the parser's exact
* output on success and `{ issues }` (message plus a key path when the parser
* reported one) on failure. The matching LLM-facing JSON schema is attached
* as {@link FolioDocumentOperationBatchSchema.jsonSchema}.
*/
const folioDocumentOperationBatchSchema = {
"~standard": {
version: 1,
vendor: "folio",
validate: (value) => {
try {
return { value: parseFolioDocumentOperationBatch(value) };
} catch (error) {
return { issues: [toStandardSchemaIssue(error)] };
}
}
},
jsonSchema: FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA
};
//#endregion
export { FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA, FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA, FOLIO_TEXT_RANGE_JSON_SCHEMA, folioDocumentOperationBatchSchema };
+2
-1

@@ -7,5 +7,6 @@ import { FOLIO_AGENT_TOOL_NAMES, FolioAgentApplyOperationsSummary, FolioAgentBlock, FolioAgentChange, FolioAgentComment, FolioAgentCommentFilter, FolioAgentCommentReply, FolioAgentTextMatch, FolioAgentToolDefinition, FolioAgentToolName, FolioToolCallResult } from "./types.js";

import { executeFolioToolCall } from "./execute.js";
import { FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA, FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA, folioDocumentOperationBatchSchema } from "./operation-schema.js";
import { ParseAddCommentResult, ParseSuggestChangesResult, parseAddCommentInput, parseSuggestChangesInput } from "./parse.js";
import { AnthropicToolDefinition, OpenAIToolDefinition, toAnthropicTools, toOpenAITools } from "./providers.js";
import { FOLIO_AGENT_TOOLS, getFolioToolDefinitions } from "./tools.js";
export { type AnthropicToolDefinition, type CreateEditorRefBridgeOptions, type CreateReviewerBridgeOptions, FOLIO_AGENT_TOOLS, FOLIO_AGENT_TOOL_NAMES, type FolioAgentApplyOperationsSummary, type FolioAgentBlock, type FolioAgentBlockDiff, type FolioAgentBridge, type FolioAgentChange, type FolioAgentComment, type FolioAgentCommentFilter, type FolioAgentCommentReply, type FolioAgentEditorApplyDocumentOperationsOptions, type FolioAgentEditorRefLike, type FolioAgentTextMatch, type FolioAgentToolDefinition, type FolioAgentToolName, type FolioAgentVersionDiff, type FolioAgentVersionDiffSegment, type FolioToolCallResult, type OpenAIToolDefinition, type ParseAddCommentResult, type ParseSuggestChangesResult, compareDocxVersions, createEditorRefBridge, createReviewerBridge, executeFolioToolCall, formatVersionDiffForLLM, getFolioToolDefinitions, parseAddCommentInput, parseSuggestChangesInput, toAnthropicTools, toOpenAITools };
export { type AnthropicToolDefinition, type CreateEditorRefBridgeOptions, type CreateReviewerBridgeOptions, FOLIO_AGENT_TOOLS, FOLIO_AGENT_TOOL_NAMES, FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA, FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA, type FolioAgentApplyOperationsSummary, type FolioAgentBlock, type FolioAgentBlockDiff, type FolioAgentBridge, type FolioAgentChange, type FolioAgentComment, type FolioAgentCommentFilter, type FolioAgentCommentReply, type FolioAgentEditorApplyDocumentOperationsOptions, type FolioAgentEditorRefLike, type FolioAgentTextMatch, type FolioAgentToolDefinition, type FolioAgentToolName, type FolioAgentVersionDiff, type FolioAgentVersionDiffSegment, type FolioToolCallResult, type OpenAIToolDefinition, type ParseAddCommentResult, type ParseSuggestChangesResult, compareDocxVersions, createEditorRefBridge, createReviewerBridge, executeFolioToolCall, folioDocumentOperationBatchSchema, formatVersionDiffForLLM, getFolioToolDefinitions, parseAddCommentInput, parseSuggestChangesInput, toAnthropicTools, toOpenAITools };

@@ -7,4 +7,5 @@ import { compareDocxVersions, formatVersionDiffForLLM } from "./compare.js";

import { createReviewerBridge } from "./bridges/reviewer.js";
import { FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA, FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA, folioDocumentOperationBatchSchema } from "./operation-schema.js";
import { toAnthropicTools, toOpenAITools } from "./providers.js";
import { FOLIO_AGENT_TOOLS, getFolioToolDefinitions } from "./tools.js";
export { FOLIO_AGENT_TOOLS, FOLIO_AGENT_TOOL_NAMES, compareDocxVersions, createEditorRefBridge, createReviewerBridge, executeFolioToolCall, formatVersionDiffForLLM, getFolioToolDefinitions, parseAddCommentInput, parseSuggestChangesInput, toAnthropicTools, toOpenAITools };
export { FOLIO_AGENT_TOOLS, FOLIO_AGENT_TOOL_NAMES, FOLIO_DOCUMENT_OPERATION_BATCH_JSON_SCHEMA, FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA, compareDocxVersions, createEditorRefBridge, createReviewerBridge, executeFolioToolCall, folioDocumentOperationBatchSchema, formatVersionDiffForLLM, getFolioToolDefinitions, parseAddCommentInput, parseSuggestChangesInput, toAnthropicTools, toOpenAITools };
import { FolioAgentToolDefinition } from "./types.js";
import { FolioDocumentOperationType } from "@stll/folio-core/server";
//#region src/tools.d.ts
/**
* The contract operation types `suggest_changes` exposes to the model,
* derived from the shared contract constant minus the exclusions above.
* Exported (module-level only, not from the package index) so
* `parse.test.ts` can assert this enum stays in lockstep with what
* `parseSuggestChangesInput` actually accepts.
*/
declare const SUGGEST_CHANGES_OPERATION_TYPES: readonly FolioDocumentOperationType[];
/**
* The tools this package exposes, described for an LLM. Every tool that reads

@@ -16,2 +25,2 @@ * or mutates the document expects `blockId` values that came from

//#endregion
export { FOLIO_AGENT_TOOLS, getFolioToolDefinitions };
export { FOLIO_AGENT_TOOLS, SUGGEST_CHANGES_OPERATION_TYPES, getFolioToolDefinitions };
import { FOLIO_AGENT_TOOL_NAMES } from "./types.js";
import { FOLIO_TEXT_RANGE_JSON_SCHEMA } from "./operation-schema.js";
import { FOLIO_DOCUMENT_OPERATION_TYPES } from "@stll/folio-core/server";
//#region src/tools.ts
/**
* `suggest_changes` deliberately narrows the full document-operation contract
* (see `FOLIO_DOCUMENT_OPERATION_JSON_SCHEMA` in `operation-schema.ts`):
* - excluded types: `formatRange` and `insertSignatureTable` (direct-only,
* not representable as tracked changes for human review) and
* `commentOnBlock` (covered by the dedicated `add_comment` tool);
* - `id` is optional here (auto-generated `op-1`, `op-2`, … by `parse.ts`)
* where the contract requires it;
* - `comment` is a plain string here; `parse.ts` wraps it into the contract's
* `{ text }` object;
* - the review metadata (`severity`, `area`), `precondition` guard, and the
* insert/replace formatting knobs (`inheritFormatting`, `pageBreakBefore`,
* `preserveFormatting`, `styleId`, `position`, `parties`, `quote`,
* `formatting`) are not exposed to the model.
*/
const SUGGEST_CHANGES_EXCLUDED_OPERATION_TYPES = /* @__PURE__ */ new Set([
"formatRange",
"commentOnBlock",
"insertSignatureTable"
]);
/**
* The contract operation types `suggest_changes` exposes to the model,
* derived from the shared contract constant minus the exclusions above.
* Exported (module-level only, not from the package index) so
* `parse.test.ts` can assert this enum stays in lockstep with what
* `parseSuggestChangesInput` actually accepts.
*/
const SUGGEST_CHANGES_OPERATION_TYPES = FOLIO_DOCUMENT_OPERATION_TYPES.filter((type) => !SUGGEST_CHANGES_EXCLUDED_OPERATION_TYPES.has(type));
const suggestChangesOperationSchema = {
type: "object",
properties: {
id: {
type: "string",
description: "Optional caller-supplied operation id, echoed back in `applied`/`skipped`. Auto-generated (op-1, op-2, …) when omitted."
},
type: {
type: "string",
enum: SUGGEST_CHANGES_OPERATION_TYPES,
description: "The kind of edit to make."
},
blockId: {
type: "string",
description: "The block to edit, from `read_document` or `find_text`."
},
range: {
...FOLIO_TEXT_RANGE_JSON_SCHEMA,
description: "Required for `replaceRange` and `commentOnRange`: copy the range object returned by `find_text`."
},
find: {
type: "string",
description: "Required for `replaceInBlock`: the exact text to find within the block, up to 100,000 characters."
},
replace: {
type: "string",
description: "Required for `replaceInBlock` and `replaceRange`: replacement text, up to 100,000 characters."
},
text: {
type: "string",
description: "Required for `insertAfterBlock` / `insertBeforeBlock` / `replaceBlock`: the text to insert or replace the block with, up to 100,000 characters."
},
comment: {
type: "string",
description: "Optional comment explaining this edit, attached to the affected text, up to 100,000 characters."
}
},
required: ["type"],
additionalProperties: false
};
/**
* The tools this package exposes, described for an LLM. Every tool that reads

@@ -137,79 +208,3 @@ * or mutates the document expects `blockId` values that came from

description: "The edits to propose, applied in order. At most 50 per call.",
items: {
type: "object",
properties: {
id: {
type: "string",
description: "Optional caller-supplied operation id, echoed back in `applied`/`skipped`. Auto-generated (op-1, op-2, …) when omitted."
},
type: {
type: "string",
enum: [
"replaceInBlock",
"replaceRange",
"commentOnRange",
"insertAfterBlock",
"insertBeforeBlock",
"replaceBlock",
"deleteBlock"
],
description: "The kind of edit to make."
},
blockId: {
type: "string",
description: "The block to edit, from `read_document` or `find_text`."
},
range: {
type: "object",
description: "Required for `replaceRange`: copy the range object returned by `find_text`.",
properties: {
type: {
type: "string",
enum: ["textRange"]
},
story: {
type: "string",
enum: ["main"]
},
blockId: { type: "string" },
startOffset: {
type: "integer",
minimum: 0
},
endOffset: {
type: "integer",
minimum: 1
},
selectedTextHash: { type: "string" }
},
required: [
"type",
"story",
"blockId",
"startOffset",
"endOffset",
"selectedTextHash"
],
additionalProperties: false
},
find: {
type: "string",
description: "Required for `replaceInBlock`: the exact text to find within the block, up to 100,000 characters."
},
replace: {
type: "string",
description: "Required for `replaceInBlock` and `replaceRange`: replacement text, up to 100,000 characters."
},
text: {
type: "string",
description: "Required for `insertAfterBlock` / `insertBeforeBlock` / `replaceBlock`: the text to insert or replace the block with, up to 100,000 characters."
},
comment: {
type: "string",
description: "Optional comment explaining this edit, attached to the affected text, up to 100,000 characters."
}
},
required: ["type"],
additionalProperties: false
}
items: suggestChangesOperationSchema
} },

@@ -298,2 +293,2 @@ required: ["operations"],

//#endregion
export { FOLIO_AGENT_TOOLS, getFolioToolDefinitions };
export { FOLIO_AGENT_TOOLS, SUGGEST_CHANGES_OPERATION_TYPES, getFolioToolDefinitions };
{
"name": "@stll/folio-agents",
"version": "0.2.0",
"version": "0.3.0",
"description": "Framework-neutral LLM tool layer over folio's ai-edits engine: function-calling tools so an agent can read and mutate .docx documents through @stll/folio-core.",

@@ -5,0 +5,0 @@ "keywords": [