UNPKG

@stll/folio-agents

Version:

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.

209 lines 8.32 kB
import { FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FolioAITextRangeHandle, FolioDocumentOperationIssue, FolioDocumentOperationReceipt, FolioDocumentOutlineEntry, FolioDocumentSectionHandle, FolioDocumentStoryHandle, FolioReviewChange } from "@stll/folio-core/server"; //#region src/types.d.ts /** * Provider-neutral tool-layer types. `FolioAgentToolDefinition` describes a * tool the same way every model provider ends up wanting it described (name + * prose description + a JSON-Schema-shaped input schema); `providers.ts` maps * that single shape onto each SDK's own tool-definition envelope. */ declare const folioAgentToolDefinitionBrand: unique symbol; type FolioAgentJsonObjectSchema = { readonly type: "object"; readonly properties: Record<string, unknown>; readonly required: readonly string[]; readonly additionalProperties: false; } & Record<string, unknown>; /** Every tool name this package exposes, as a stable string union (no enums). */ declare const FOLIO_AGENT_TOOL_NAMES: { readonly readDocument: "read_document"; readonly getDocumentOutline: "get_document_outline"; readonly readSection: "read_section"; readonly listStories: "list_stories"; readonly readStory: "read_story"; readonly findText: "find_text"; readonly readComments: "read_comments"; readonly readChanges: "read_changes"; readonly addComment: "add_comment"; readonly suggestChanges: "suggest_changes"; readonly replyComment: "reply_comment"; readonly resolveComment: "resolve_comment"; readonly readPage: "read_page"; readonly readSelection: "read_selection"; readonly scrollToBlock: "scroll_to_block"; readonly showInDocument: "show_in_document"; }; type FolioAgentToolName = (typeof FOLIO_AGENT_TOOL_NAMES)[keyof typeof FOLIO_AGENT_TOOL_NAMES]; /** * A provider-neutral tool definition: name, an LLM-facing description (when to * call it, what it returns), and a JSON-Schema (draft-07-ish) object schema for * its arguments. `providers.ts` maps a list of these onto Anthropic's or * OpenAI's tool-definition shape. */ type FolioAgentToolDefinition = { name: FolioAgentToolName; description: string; inputSchema: Record<string, unknown>; }; type FolioAgentTypedToolDefinition<TName extends FolioAgentToolName = FolioAgentToolName, TInput = unknown, TOutput = unknown, TSchema extends FolioAgentJsonObjectSchema = FolioAgentJsonObjectSchema> = FolioAgentToolDefinition & { readonly name: TName; readonly inputSchema: TSchema; readonly [folioAgentToolDefinitionBrand]?: { readonly input: TInput; readonly output: TOutput; }; }; /** * Result of executing one tool call. `ok: false` covers every EXPECTED failure * (bad arguments, an unknown tool, a capability the bridge does not support, a * domain-level skip) — never throw for these, since the whole point is to feed * the reason back to the model so it can retry or adjust. `executeFolioToolCall` * is the only boundary layer allowed to catch an unexpected throw and fold it * into this shape too. */ type FolioToolCallResult<TResult = unknown> = { ok: true; result: TResult; } | { ok: false; error: string; }; /** One document block as exposed to a model: id, kind, and its plain text. */ type FolioAgentBlock = { blockId: string; kind: string; text: string; /** * Normalized-text hash of this block at read time. Echo it back as * `precondition.blockTextHash` on a `suggest_changes` / `add_comment` * operation targeting this block so the apply call is guarded against * edits made to the document between this read and that apply — without * it, only same-call staleness within one `suggest_changes` batch is * caught. */ blockTextHash: string; }; /** One main-story `find_text` match. Existing consumers can keep using its block and range directly. */ type FolioAgentTextMatch = { /** Present on results from the current executor; optional for source compatibility with older hosts. */ type?: "main"; story?: { type: "main"; }; blockId: string; /** Normalized-text hash of the whole containing block; see {@link FolioAgentBlock.blockTextHash}. */ blockTextHash: string; /** Stable handle that can be passed directly to `show_in_document` or a range operation. */ range: FolioAITextRangeHandle; /** 0-based index of this occurrence within its block. */ occurrenceInBlock: number; /** Real rendered page when a live paginated surface supplies it. */ page?: number; context: string; }; type FolioAgentStoryTextMatch = { type: "story"; story: Exclude<FolioDocumentStoryHandle, { type: "main"; }>; startOffset: number; endOffset: number; /** 0-based index of this occurrence within the story. */ occurrenceInStory: number; context: string; }; type FolioAgentOutlineEntry = FolioDocumentOutlineEntry & { page?: number; }; type FolioAgentDocumentOutline = { sections: FolioAgentOutlineEntry[]; totalSections: number; truncated: boolean; }; type FolioAgentSectionRead = { handle: FolioDocumentSectionHandle; heading: FolioDocumentOutlineEntry; blocks: FolioAgentBlock[]; totalBlocks: number; truncated: boolean; nextAfterBlockId?: string; }; /** * Result of {@link FOLIO_AGENT_TOOL_NAMES.findText}. `matches` is capped at a * fixed limit; when the query has more hits than that, `truncated` is `true` * and `totalMatches` reports the real count so the model knows to narrow the * query instead of assuming it saw everything. */ type FolioAgentFindTextResult = { matches: FolioAgentTextMatch[]; truncated: boolean; totalMatches: number; }; type FolioAgentStoryFindTextResult = { matches: FolioAgentStoryTextMatch[]; truncated: boolean; totalMatches: number; }; type FolioAgentScopedFindTextResult = FolioAgentFindTextResult | FolioAgentStoryFindTextResult; /** One reply within a comment thread. */ type FolioAgentCommentReply = { id: string; author: string; text: string; }; /** * A comment thread, shaped to match what {@link FolioDocxReviewer.getComments} * (from `@stll/folio-core/server`) returns, minus fields a tool-calling model * has no use for (raw dates). `resolved` mirrors the underlying model's * `done` flag; `quote` mirrors `anchoredText` (the text the comment is * attached to, empty when unavailable). */ type FolioAgentComment = { id: string; author: string; text: string; resolved: boolean; blockId: string | null; quote: string; replies: FolioAgentCommentReply[]; }; /** A pending tracked change, shaped to match {@link FolioDocxReviewer.getChanges}. */ type FolioAgentChange = { id: string; type: FolioReviewChange["type"]; author: string; text: string; blockId: string | null; }; /** Filter for {@link FOLIO_AGENT_TOOL_NAMES.readComments}. */ type FolioAgentCommentFilter = "all" | "open" | "resolved"; /** * One lenient-decoding step the parser took on a tool call's arguments * (a `kind` key read as `type`, an operation supplied as a JSON string, a * stray property dropped). Reported back to the model so sloppy calls * still succeed without the normalisation going unnoticed. */ type FolioAgentInputNormalization = { /** Where in the arguments, e.g. `operations[2].kind`. */ path: string; message: string; }; /** Result of {@link FOLIO_AGENT_TOOL_NAMES.addComment} / `suggest_changes`. */ type FolioAgentApplyOperationsSummary = { version: typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION; applied: { id: string; }[]; /** Operations a host review-queue bridge accepted for later human review instead of applying. */ queued: { id: string; }[]; skipped: { id: string; reason: string; }[]; issues: FolioDocumentOperationIssue[]; receipts: FolioDocumentOperationReceipt[]; normalizations: FolioAgentInputNormalization[]; }; //#endregion export { FOLIO_AGENT_TOOL_NAMES, FolioAgentApplyOperationsSummary, FolioAgentBlock, FolioAgentChange, FolioAgentComment, FolioAgentCommentFilter, FolioAgentCommentReply, FolioAgentDocumentOutline, FolioAgentFindTextResult, FolioAgentInputNormalization, FolioAgentJsonObjectSchema, FolioAgentOutlineEntry, FolioAgentScopedFindTextResult, FolioAgentSectionRead, FolioAgentStoryFindTextResult, FolioAgentStoryTextMatch, FolioAgentTextMatch, FolioAgentToolDefinition, FolioAgentToolName, FolioAgentTypedToolDefinition, FolioToolCallResult };