assist: The Assist Seam (opt-in, degrade-only LM suggestions)#
The deterministic degradation path always runs and always produces a result; an Assist can only
improve a lowering the rules flagged as a judgment call. NullAssist is the default and the only
path when assists are disabled – that mode makes zero network attempts. The gateway-backed assist
posts tiny schema-constrained prompts to the local OpenAI-compatible gateway and memoizes results
on disk by node content hash.
get_assist is the one seam callers need: it resolves enabled/config precedence and returns
either NullAssist (disabled), GatewayAssist (enabled without caching), or CachedAssist
wrapping a gateway (enabled with caching), importing network-facing modules only when enabled.
The Assist Seam (opt-in, degrade-only LM suggestions).
The deterministic degradation path always runs and always produces a result; an Assist can only
improve a lowering the rules flagged as a judgment call. NullAssist is the default and the only
path when assists are disabled – that mode makes zero network attempts. The gateway-backed assist
posts tiny schema-constrained prompts to the local OpenAI-compatible gateway and memoizes results
on disk by node content hash.
get_assist is the one seam callers need: it resolves enabled/config precedence and returns
either NullAssist (disabled), GatewayAssist (enabled without caching), or CachedAssist
wrapping a gateway (enabled with caching), importing network-facing modules only when enabled.
- class myform.assist.Assist#
The assist seam: improve a deterministic lowering, or defer to it.
- suggest(request: AssistRequest) AssistResult | None#
Return an improved suggestion for request, or
Noneto use the fallback.
- class myform.assist.AssistRequest(**data: Any)#
One improve-this-lowering ask, built by the degradation engine from a flagged node.
nodeis the flagged node’smodel_dump(mode='json')payload rather than the live pydantic object – anAssistnever needs to reconstruct a typed node, only read it, and the payload is directly usable as LM prompt content.content_hashis that same node’s~myform.model.Node.content_hash(the cache key ingredient); carrying it here rather than recomputing it fromnodekeepsAssistimplementations from needing the node model at all.- node: dict[str, Any]#
The flagged node, dumped (
model_dump(mode='json')); never the live pydantic object.
- content_hash: str#
~myform.model.Node.content_hashofnode– the assist-cache key ingredient.
- source_format: str#
The document’s source format name (e.g.
'myst').
- target_format: str#
The writer’s target format name (e.g.
'typst').
- fallback: str#
A human-readable description of what the deterministic engine would do without an assist.
- purpose: PurposeTag#
Which kind of judgment call this is; see
PurposeTag.
- class myform.assist.AssistResult(**data: Any)#
One assist answer: a replacement/suggestion plus how much to trust it.
Exactly one of
replacement(ready-to-use text) orsuggestion(a structured lowering hint the degradation engine interprets, e.g. a placement/ordering choice) must be set – a result that supplies neither is a decline in disguise and should be a bareNonefromAssist.suggestinstead.- replacement: str | None#
Ready-to-use replacement text, when the judgment call is textual (e.g. a caption summary).
- suggestion: dict[str, Any] | None#
A structured lowering hint (e.g. a placement choice) for the degradation engine to apply.
- confidence: float#
How much to trust this answer, in
[0, 1].
- note: str#
A short human-readable note (surfaced in the
ConversionReport).
- class myform.assist.CachedAssist(inner: Assist, cache_dir: Path | None = None)#
Wraps another
Assist, memoizingsuggeston disk by(node hash, target, model).- suggest(request: AssistRequest) AssistResult | None#
Return the cached answer for request, asking
innerand caching it on a miss.
- class myform.assist.GatewayAssist(base_url: str | None = None, model: str = 'bulletin', api_key_env: str = 'LITELLM_TOKEN', timeout: float = 5.0)#
Posts tiny JSON-schema-constrained prompts to an OpenAI-compatible chat-completions API.
- disabled#
Set on the first failure; short-circuits every later
suggestcall on this instance.
- suggest(request: AssistRequest) AssistResult | None#
Ask the gateway to improve request, or
Noneon decline/failure/disabled.
- class myform.assist.NullAssist#
The default, network-free assist – always defers to the deterministic fallback.
- suggest(request: AssistRequest) AssistResult | None#
Always decline; the only path when assists are disabled (AC5: zero network calls).
- myform.assist.default_cache_dir() Path#
$XDG_CACHE_HOME/myform/assist/, defaulting to~/.cache/myform/assist/.
- myform.assist.get_assist(config: Mapping[str, Any] | BaseModel | None = None, *, enabled: bool | None = None) Assist#
Build the
Assistconfigured by config, defaulting to disabled (NullAssist).Precedence for whether assists are enabled: an explicit enabled keyword beats
config['enabled'], which beats the default (off). When disabled, this returnsNullAssistwithout importing.gateway/.cachefrom this function – a disabled seam makes zero network attempts (AC5), which holds regardless of import path, since neither submodule touches the network at import time either.Call this once per conversion run and hold the result for every node it processes:
GatewayAssist’s “disable after one failure, never retry” guarantee is scoped to that instance (self.disabled). Callingget_assistfresh per node would build a new, not-yet-disabledGatewayAssisteach time and reproduce the retry storm the contract forbids – the process-wide warning would still log only once, but the network attempts would not be suppressed.- Parameters:
config – The typed config-layer
AssistConfig(or its raw mapping equivalent). Unknown mapping keys are ignored, mirroringmyform.options.MystOptions.from_options. Recognized keys:cache, andcache_dir.enabled – Explicit override, taking precedence over
config['enabled'].
- Returns:
NullAssistwhen disabled; a~myform.assist.gateway.GatewayAssistwhen enabled with caching off; otherwise a~myform.assist.cache.CachedAssistwrapping the gateway.