Incremental proofreading
When a user is editing a document, most of the text stays the same between proofreading runs. Incremental proofreading detects the small parts that changed and only re-proofreads those — the untouched remainder never goes back through a model, so repeat requests are faster and cheaper.
This happens entirely in the SDK, on your side. The API is stateless: it never stores your text, and only ever receives the chunks that need checking.
How to enable it
Pass a stable textId with your proofread request. That is the only change; the response
shape is identical to a regular request, with your textId echoed back as textId.
import { applyEdits, createAmberPenClient } from "@amber-pen/sdk";
const amberPen = createAmberPenClient({ apiKey });
// First request: the full document is proofread, and the
// SDK remembers it under the textId.
await amberPen.proofread({
textId: "chapter-1",
text: draft,
});
// Later, after the author edits a paragraph: only the
// changed chunks are sent to the API.
const result = await amberPen.proofread({
textId: "chapter-1",
text: updatedDraft,
});
// Edits still cover the whole document you sent.
const correctedText = applyEdits(updatedDraft, result.edits); How it works
- The first request with a given
textIdproofreads the full text. The SDK keeps that text and its edits in memory. - On each subsequent request, the SDK diffs the new text against the remembered version to locate the blocks that changed. A block is a line, delimited by line breaks.
- Around every change, a chunk of roughly 800 characters of context on each side is taken by default, rounded to the closest block boundary so a block is never cut in half; chunks that touch are merged.
- For
proofread, every chunk is sent to the API in parallel. ForproofreadStream, changed chunks are streamed in document order. - Edits from those chunks replace the remembered edits in the same ranges. Edits outside them are kept and shifted to their new offsets.
- The result is one
editsarray covering the whole document, with offsets relative to the text you just sent. It is a complete result, not a patch: you can replace your whole suggestion set with it.
If nothing changed since the previous request, no request is sent at all and the previous edits are returned as they are.
Chunk size and boundaries
Set incrementalChunkSize when creating the client to change how many characters of
context are included on each side of a change. The value is approximate: after applying it, the SDK
rounds both edges to newline-delimited block boundaries. This guarantees that every chunk starts at
the beginning of a block—including a paragraph represented as one line—and never partway through it.
const amberPen = createAmberPenClient({
apiKey,
// Context on each side of a change before rounding to
// newline-delimited block boundaries. Defaults to 800.
incrementalChunkSize: 1_200,
// How long a textId's text and edits stay in memory.
// Defaults to 24 hours.
incrementalTtlMs: 60 * 60 * 1000,
}); Streaming
Pass the same textId to proofreadStream to stream an incremental result.
The SDK caches a streamed text and its edits only after every required chunk completes successfully.
If the iterator is cancelled, fails, or is not fully consumed, the last completed snapshot remains
intact and the partial result is never cached.
Memory and expiry
Texts and edits are held in the client's memory, per textId, for 24 hours by default.
Expired entries are dropped, and a textId whose entry is gone is simply treated as new:
the next request proofreads the full text again. Set incrementalTtlMs to change the
window.
Because the cache lives in one client instance, incremental proofreading works best when the same long-lived instance handles a document's requests. A short-lived process — a serverless function that constructs a client per invocation, for example — starts with an empty cache each time, so every request proofreads the full text.
Choosing a textId
- Use one
textIdper document (or per independently edited section, like a chapter) and keep it stable across requests. - Always send the complete document text, not just the changed part — the SDK computes the diff for you, and edit offsets stay valid against your full text.
When not to use it
- One-off texts that are proofread once — a
textIdadds nothing.