Built-in plugins: what each one does
At a glance
| Plugin | In one line |
|---|---|
| Discard On Update | Test/example plugin — not for production |
| Anchor Extract | LLM proposes an extraction snippet for every field |
| Declare Items | LLM detects tables + extracts field values, verifies by rendering them |
| Iterator | Detects repeating tables, auto-inserts #iterator (100-tree classifier) |
| Sort Suggestions | Re-scores and reorders other plugins' suggestions |
| AI Selector | Finds the client/booking reference value |
| AI Checking | Finds keywords that distinguish this template from others |
| Number Handling | Normalizes numeric suggestion values and their snippets |
registry maps each Plugin enum value to the hook-producing function definePlugin built for it. availablePlugins is just getKeys(registry). None of the eight plugin implementations below are themselves exported from the package — registry is the only exported surface that touches them, so this page is where their behavior is documented. Several of them call out to an external LLM service (referred to in source comments as "Morphseek"/"MorphSeek") via the extractWithLLM/callRender functions described in Plugin framework.
Discard On Update
Plugin.DiscardOnUpdate (useDiscardOnUpdate). Its bootstrap walks every path in the tree and logs what it finds; the code that would actually add a key is commented out. Treat it as a worked example of the framework's shape, not a real feature.
Not for production
The file's own comment is the accurate description: "a plugin used for testing the plugin framework, should not be used in production." It's still registered in registry.ts — nothing prevents it from being enabled.
Anchor Extract
Plugin.AnchorExtract (anchorExtract). Given every Simple/Graph/ Cell field in the template plus each field's semantics string and (for enum-validated fields) its allowed values, it builds one prompt asking an LLM to propose an extraction snippet for each field from the document text, across the whole multi-file batch being processed. It's built for repeated use across a batch: bootstrap recognizes when it's already seen a given file's exact text (processedFileTexts) and reuses the cached structured result instead of re-querying the LLM, and resets that cache only at the start of a genuinely new session (first file, and the previously-scored file count doesn't match). fieldSuggestions then just looks up cachedStructuredResult[entry.key].options for whichever field is asking.
Declare Items
Plugin.DeclareItems (useTableLogic). The most involved of the eight. bootstrap first asks the LLM to detect table regions in the raw text (detectTablesFromFullText), then asks it again to extract field values from each detected table (extractFieldsFromTableWithLLM) — including a retry path that re-prompts with a list of specifically-failing fields (FailureReason: implausibleValue, nonReusableAnchor, renderMismatch) rather than re-running the whole extraction blind. fieldSuggestions offers two kinds of suggestion side by side: LLM-derived ones filtered to "reusable" anchors (selectReusableOptions), and, for whichever detected table has the most fields tagged as the container table (determineContainersTableIndex), plain column-reference suggestions (c<col>: value, #>$column#N for a repeating column). It also creates a Containers map path in the tree up front if one doesn't already exist (ensurePath), and checks hasContainerTableIterator from the Iterator plugin before offering column suggestions — the two plugins are meant to be used together on the same container table.
Iterator
Plugin.Iterator (useIterator). Detects repeating table-like structures in the document and, when found, calls the framework's addMapIterator (see MapApi) to insert an #iterator node for it automatically. Detection runs in two stages:
- A per-line binary classifier (
decisionTreeClassifier, a single decision tree over per-line text features) labels each lineTABLE/NOT TABLEto find candidate blocks — used as a fallback when the LLM table-detection call (shared with Declare Items,detectTablesFromFullText) doesn't apply or doesn't find anything. - Each candidate block is reduced to a 17-number feature vector and run through
predictIterator— a 100-tree decision-tree ensemble (iterator_forest.ts; the file is a direct transpile of a trained model, not hand-written logic — 100varNtrees overinput[0..16]threshold splits, whose one-hot-ish 3-class votes are summed and divided by 100) — to classify the block as one of'count occurences','get from list', or'iterate table'. A separate rule-based check (CountOccurrences) can override the model's answer and force'count occurences'when it finds a strong repeating-combination match directly.
hasContainerTableIterator() exposes whether this run found (and inserted) a container-table iterator, read by Declare Items as noted above.
Sort Suggestions
Plugin.sortSuggestions (sortSuggestions). Doesn't generate suggestions itself — it's a postFieldSuggestions pass that re-scores and reorders whatever the other active plugins proposed. For each suggestion, it renders the suggestion's snippet (via callRender) and compares the rendered result against the field's actual value (character-position similarity ratio), giving verified/cross-field suggestions a fixed high score and column-reference snippets (#>N$get pattern) a fixed medium score. Suggestions below MIN_SCORE_THRESHOLD (50) are dropped, unless the field's key is in a fixed exemption list or looks numeric (isNumericIntentField, shared with Number Handling below).
AI Selector
Plugin.AiSelector (Selector). Narrow and specific: at bootstrap, asks an LLM to find the single "client or booking reference" label/value pair in the document, caches it, and offers it as a suggestion only for a field literally keyed selector.
AI Checking
Plugin.AiChecking (Checking). Similar shape to AI Selector: at bootstrap, asks an LLM for keywords that would distinguish this document's template from others (email domain, filename keywords, body keywords, and — for the intermodal domain specifically — an import/export direction keyword), building a domain-specific prompt name via its own small resolveCheckingPrompt registry. Offers the result, compiled into a $utils.or-combined regex condition, as a suggestion only for a field keyed checking.
Number Handling
Plugin.NumberHandling (numberHandling). A postFieldSuggestions pass like Sort Suggestions, scoped to fields it considers numeric (isNumericIntentField: a Zod number validator, semantics containing "numeric", or a hardcoded key list currently just ['weight']). For each matching suggestion it strips thousands separators, converts European decimal notation (. thousands / , decimal) to a parseable number, and applies configured rounding (ceil/floor/leave) — rewriting both the suggested value and its snippet (wrapping it in $math.parseFloat and the configured rounding function) so the generated template code performs the same normalization at render time, not just in the preview value.