The SDK exposes Revise’s canonical document-local tool subset. The tools are
JSON-schema described, safe to call without React state or browser focus, and
operate on semantic document structure rather than UI geometry.
The loop
That is the whole integration: schemas out, results back in. The definitions
are generated from the same source as Revise’s production agent, so they carry
the descriptions and constraints the tools were designed with.
Results
Both surfaces — this one and @reviseio/sdk/backend — return the same
discriminated envelope, so result handling is shared verbatim between web
and Node:
A rejected edit resolves — it does not throw. Always check ok, and feed
error.message back to the model: it explains why a call failed in
terms the model can act on, which is usually the difference between a retry
that works and one that repeats the mistake. (tools.call() is the
throwing variant for application code, raising a typed ReviseToolError.)
Read and search tools return context.html: HTML that preserves block IDs,
inline formatting, tables, and notes rather than flattening the document to
plain text. Those IDs are what mutation tools target, so the read/act cycle
composes. Suggesting-posture mutations report the tracked records they
created in suggestionIds — feed them straight to
review.acceptSuggestions().
Working with blocks
The model reads a window of the document, then edits by block ID:
replace operates inside one block. Two edits in different blocks are
two calls — a single call with finds spanning blocks fails rather than
partially applying.
Editing every match at once
A search of the active document returns a search_result_id standing for the
whole unpaginated match set. Pass it to replace, replace_block,
style_blocks, or remove_blocks instead of an id, and the edit applies
independently to every matched block — no paging through IDs, no call per
occurrence:
The reference is scoped to the editor session that produced it, and is
rejected once the matched blocks have changed underneath it — nothing is
partially applied. Re-run search_document and use the new ID.
Routing to a document
Every tool schema carries an optional document_id. Omit it for the active
document, or target any ready document in the same editor:
Suggestions or direct edits
Mutations land as tracked changes by default, whatever mode the editor’s own
typing surface is in. Pass directMode to apply them outright:
See tracked changes for when that is appropriate.
Review navigation, comment-panel state, focus, viewport, zoom, and direct
canvas rendering are host concerns, not tools in this external catalogue. An
agent should not be clicking “next suggestion” — it should be making semantic
edits and letting your UI present them. A delegated Revise agent can inspect
the mounted canvas with its internal render_document_pages tool. See
architecture and delegation.
The full catalogue is in the tool reference.
Node: semantic editing without an editor
@reviseio/sdk/backend binds the same deterministic definitions and executor
to a host-owned Y.Doc; no model or React mount is involved. (Full surface —
conversion, room lifecycle, and the session API — in the
backend reference.) A session is
document-scoped, retains search references across calls, and must be disposed.
Disposal releases Revise observers but deliberately leaves your Y.Doc alive.
Because the session is bound to one document, its schemas and descriptions
carry no document_id. Literal tool names infer their exact schema input and
structured output. Use call() in ordinary application code; it returns the
successful response directly and throws ReviseToolError for an expected tool
rejection. Use execute() when you want a discriminated result, or
executeDynamic() for untrusted model-provided names and JSON. Every path is
serialized in arrival order on one session. Switch with
document.setSuggestingMode() and document.setEditingMode(); each call
captures the mode when submitted, so toggling is deterministic even with queued
work.
For a model-driven loop, keep expected failures as data:
Read/search response.context.html is constrained Revise semantic HTML:
semantic document markup with stable block IDs for paragraphs, formatted runs,
tables, comments, and notes where supported. Structured tool metadata is in
the inferred response.data; the concise model-oriented summary is
response.message. Structural insertion and whole-block replacement accept
this dialect because it is safer than constructing DocRoot or OOXML. It is
not arbitrary browser HTML/CSS and is not a lossless web representation of
unsupported Word geometry. The Yjs-backed Revise model remains authoritative,
DOCX remains the import/export format, and executing a tool does not reparse
untouched content through HTML.
Do not mutate DocRoot directly. Existing conversion calls may still return
that type for compatibility, but the supported server mutation contract is
(await createServerDocumentSession(ydoc, ...)).tools.