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, **options) # => 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 Context object, 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:

  1. Idempotence — call(call(x)) == call(x).
  2. No-op on well-formed input — a complete document comes back byte-identical.
  3. 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.