🩹 Numbered paragraphs keep counting across the text between them
A filing whose numbered paragraphs are separated by section titles, evidence notes and
lists of exhibits came out half-formatted: the first couple of paragraphs were a real
Word numbered list, and every one after that was an ordinary paragraph with the number
typed into the text. Editing such a document in Word meant renumbering by hand.
The running count that lets a list resume after an interruption only survived a fixed
set of blocks — a markdown # heading, a block quote, a <!-- style: … --> directive.
Anything else cleared it. A filing interposes exactly what was not on that list:
- a centred section title,
<center>**II.**</center>, which is an aligned paragraph
rather than a#heading; - an italic evidence note,
*__Důkaz__:*; - the bullet list of exhibits under it.
Once the count was gone, a lone 3. followed by a blank line could not be told from a
date, so it stayed prose — and so did 4., 5. and the rest of the document.
The count now survives anything written between the items — section titles, notes,
bullet lists, tables, quotes — and ends only where a new list begins again at 1..
Write 1., 2., 3. … straight through a document and it renders as one numbered
list, whatever sits between the items.
What this means for your markdown
- Keep numbering consecutively. Don't restart at
1.under each section heading
unless you really want the numbering to restart there. - The numbers must run consecutively to be recognised. A number that skips (…
3.,
then5.) does not continue the count, and neither does anything after it. - A date at the start of a line may need escaping. A line beginning with a number
and a dot is read as a list item, so escape the dot in a date that would land on a
list number: a day-1 date (1\. ledna 2026) or one whose day is the next number in
the count (3\. září 2026written right after item 2). Dates that don't collide —
23. června 2026after item 2 — are left as prose automatically.
The create_word_document tool description and the Readme both carry these rules, so a
model generating markdown is told about them up front.
🔒 Security: image URLs can no longer probe your internal network
Image URLs reached the downloader straight from caller-supplied tool arguments, so a URL
could be used to probe loopback and private-network services or cloud-metadata endpoints,
and redirects were followed without any check — a public URL could bounce onto an
internal one.
Every host is now resolved and required to be publicly routable. Resolution goes through
getaddrinfo for all hosts, bare IP literals included, so alternative encodings
(2130706433, 0177.0.0.1) are normalised the same way the HTTP client normalises them,
and IPv4-mapped IPv6 (::ffff:127.0.0.1) is collapsed before the check. Loopback,
RFC 1918, link-local — 169.254.169.254 included — CGNAT, documentation and reserved
ranges are all rejected, in both address families. Redirects are followed manually so
every hop is re-validated.
SSRF_ALLOW_PRIVATE_ADDRESSES=true opts out, for deployments that legitimately serve
images from inside their own network (a sibling service, an internal MinIO endpoint).
Leave it unset anywhere untrusted callers can reach.
Known limitation, documented rather than papered over: the host is resolved again at
connect time, so this does not close DNS rebinding. Pinning the validated address into
the connection would, and was deliberately left out of scope.
Redirect chains can no longer hold a worker thread
Each redirect hop used to get its own REQUEST_TIMEOUT, so a server chaining slow
redirects could hold a request for up to 30s × (MAX_REDIRECTS + 1) — about three minutes.
Tool handlers run on a small bounded thread pool (RUN_BLOCKING_MAX_WORKERS, default 4),
so a handful of such calls could starve it and put liveness probes at risk. The whole
chain now runs against a single deadline computed up front.
Note the bound is on the redirect chain, not on wall-clock: requests applies a timeout
per socket operation, so a server dribbling bytes fast enough to keep resetting the read
timeout still holds a hop past the budget — measured 11s against a nominal 2s. That is
pre-existing behaviour, now stated accurately in the docstring.