maquina_remend
Repairs the tail of a markdown buffer that is still being streamed.
A model emits markdown a token at a time. Rendered naively, the tail of the
buffer is broken for most of the message's life. The model has typed **bol
and the reader sees two asterisks; it has typed [the guide](https://exa and
the reader sees a link to the wrong host. maquina_remend completes that tail,
so the renderer always receives a well-formed document.
MaquinaRemend.call("**unclosed bold") # => "**unclosed bold**"
MaquinaRemend.call("`code") # => "`code`"
MaquinaRemend.call("[label](https://exa") # => "[label](#)"
MaquinaRemend.call("<thinking>\nstill reasoning")
# => "<thinking>\nstill reasoning</thinking>"
It is a pure function. It is idempotent. A document that is already well formed comes back byte for byte. Zero runtime dependencies, and no Rails — it runs in a plain Ruby process with nothing else loaded.
Install
bundle add maquina_remend
or, in a Gemfile:
gem "maquina_remend"
Ruby >= 3.1.
Usage
require "maquina_remend"
MaquinaRemend.call(markdown, **) # => String
Call it on every frame of the stream, on the whole buffer so far, and render the result. Nothing is remembered between calls.
buffer = +""
stream.each do |chunk|
buffer << chunk
render MaquinaRemend.call(buffer)
end
nil and "" come back exactly as they went in. An unrecognised option raises
MaquinaRemend::UnknownOption rather than being ignored, so a typo in a host's
configuration surfaces at once.
Options
Every repair is individually disableable, and one is off by default.
| Option | Default | Broken input | Repaired to |
|---|---|---|---|
bold: |
true |
**unclosed bold |
**unclosed bold** |
italic: |
true |
*unclosed / _unclosed |
*unclosed* / _unclosed_ |
bold_italic: |
true |
***both |
***both*** |
inline_code: |
true |
`code |
`code` |
strikethrough: |
true |
~~struck |
~~struck~~ |
links: |
true |
[label |
[label]() |
images: |
true |
![alt |
![alt]() |
block_math: |
true |
$$x = 1 |
$$x = 1$$ |
inline_math: |
false |
$x = 1 |
$x = 1$ |
setext_headings: |
true |
Title\n= |
Title\n===== |
comparison_operators: |
true |
- a > b |
- a \> b |
html_tags: |
true |
text <div cla |
text |
single_tilde: |
true |
20~25°C |
20\~25°C |
dangling_escape: |
true |
media ecuación \ |
media ecuación and a space |
app_tags: |
five names | <thinking>\nstill reasoning |
<thinking>\nstill reasoning</thinking> |
link_mode: |
:protocol |
[label](http |
[label](#) |
handlers: |
[] |
— | your own handlers, run last |
Pass false to switch a repair off:
MaquinaRemend.call("**unclosed bold", bold: false) # => "**unclosed bold"
MaquinaRemend.call("![alt", images: false) # => "![alt"
inline_math: is off because a bare dollar sign is currency far more often
than it is mathematics. Turn it on only if you know your corpus.
app_tags: is a list, not a boolean. It names the tags a model emits to
carry application meaning — thinking, answer, tool_call, citation,
scratchpad by default — and closes the ones the model has left open. Pass
your own names to match the host's tag registry, or false to switch it off:
MaquinaRemend.call("<plan>\nstep one", app_tags: %w[plan])
# => "<plan>\nstep one</plan>"
Every repair, with the input it fires on and the input it refuses to touch, is
in docs/repairs.md. The reasoning behind the app_tags:
list is under Application tags.
What it will not do
Guards matter more than completions. A false repair corrupts a message that was never broken, and there is no frame later in the stream that undoes it.
MaquinaRemend.call("```\n**not bold") # => "```\n**not bold"
MaquinaRemend.call("`a * b`") # => "`a * b`"
MaquinaRemend.call("$$a_1 + b_2$$") # => "$$a_1 + b_2$$"
MaquinaRemend.call("some_var_name") # => "some_var_name"
MaquinaRemend.call("costs $5 and $10") # => "costs $5 and $10"
Nothing is completed inside a fenced code block, inside an inline code span, or inside math, because in those places broken-looking markup is the content. The full list is in docs/repairs.md.
Documentation
- docs/repairs.md — every repair, one section each, with the input it fires on and the guards that hold it back.
- docs/handlers.md — writing a handler of your own: the
contract, the
Contextobject, ordering, and a worked example. - docs/streaming.md — using it in a stream, what idempotence and prefix safety buy a caller, and what the gem deliberately does not do.
API documentation for every class is on rubydoc.info.
Guarantees
Three properties, asserted over a corpus of whole documents at every truncation point rather than over hand-picked inputs:
- Idempotence —
call(call(x)) == call(x). - No-op on well-formed input — a complete document comes back byte-identical.
- Prefix safety — every truncation point of a document is repairable without raising.
A fourth is measured rather than proved: an 8KB buffer is repaired in under a millisecond.
Run them with bundle exec rake test. The prefix-safety property also accepts a
local corpus of real transcripts:
MAQUINA_REMEND_CORPUS=~/some/transcripts bundle exec rake test
That corpus is deliberately not committed: a transcript contains whatever the session contained.
maquina
Part of maquina — open source for Ruby and Ruby AI.
License
MIT, © Mario Alberto Chávez. See LICENSE.txt.