A display formula wider than the column scrolls in its own box, as code
and tables do, and a formula in a table header is not uppercased: n and N
are different variables.
Inline \( \) math rendered as a literal $x$ (the rewrite produced single
dollars, which remark-math is told to ignore), a one-line \[ \] shrank to
inline math, model-written $x$ never rendered, and the citation pass
linked [1] inside formulas.
- \( \) and \[ \] are micromark constructs: inline anywhere, display when
\[ starts a line and its \] ends one. A line such as "\[a\] and more"
stays inline instead of swallowing the rest of the answer, which is why
this does not alias micromark-extension-llm-math.
- $x$ follows Pandoc's rules (ported from LibreChat, MIT), so prices stay
text.
- A paragraph holding only $$ or \[ math, and anything KaTeX can only set in
display mode (\tag, align, ...), becomes display math.
- mhchem is loaded for \ce and \pu.
- Citations are linked on the syntax tree, so code, math, link text and
escaped brackets are never touched.
- While streaming, open emphasis, code and $$ / \[ math are closed (remend
plus a code-aware math pass) and a formula KaTeX cannot set yet shows in
the muted colour. Each top-level block renders on its own and is
memoised, so only the growing block is parsed and typeset again.
The remove button's label is "Remove attachment" and doesn't say which
file. Its failure description now reads "<file>: <reason>", the same text
as the tooltip.
Follow-ups to moving the failure reason into a tooltip:
- The tooltip now reads "<file>: <reason>". The name is truncated on the
chip, and two long names can look the same.
- A polite role="status" region, always mounted and screen-reader only,
lists the failed files and their reasons. The red line it replaces was
role="alert", so failures were announced; a hover tooltip is not.
- The reason now describes the remove button (aria-describedby on a
hidden span), the chip's only focusable control. Before, it was sr-only
text on a chip that can't take focus.
The composer showed each failed file's reason as a red line of text under
the chips. A failed file no longer blocks the send, since it is dropped
then, so that line was louder than it needed to be. DESIGN.md also says
status text of a sentence or more must not be a coloured paragraph.
The chip's warning icon already marks the failure. The reason is now a
Tooltip on the failed chip. It falls back to "Failed" when no reason is
known. It is also kept as sr-only text so screen readers still read it.
The native title moves from the chip to the truncating file name, where
DESIGN.md keeps title=, and is left off failed chips so the tooltip
doesn't double up.
Aborts /api/store_attachment, attaches a file, waits for the failed
chip's reason, then sends. Checks that one /stream request goes out with
no attachment ids, that the question is in the thread and the chip is
gone, and that the stored message has no attachments.
Uploads had no timeout, so a stalled XHR could leave a chip on
"uploading" forever, and a queued send waited with it. Network failures
also set no errorMessage, so the failed chip showed no reason.
guardUploadStall aborts an upload once it goes 120 s without progress.
It restarts on every upload progress event and again when the body
finishes sending. A large file on a slow link keeps going; only a silent
stall is cut off. That is why it is not xhr.timeout, which caps the whole
request against a 100 MB file limit. onerror, onabort and ontimeout now
mark the chip failed with "Upload failed. The file couldn't be read or
the connection dropped." (single and multi-file paths). A failed chip is
dropped at send, so a queued question always goes out in the end. The
5-minute processing cap is unchanged.
A queued send flushed by calling submitNow directly, which skipped the
loading check in canSubmit. submitNow clears the composer before the
consumer runs, and the consumer ignores a submit while status is
'loading'. If a retry or an edit was streaming when the attachments
settled, the question was cleared and never sent.
useArmedSend takes a canFlush flag. The composer passes whether it can
take a submit right now (not loading, not recording or transcribing).
The armed send stays queued until that holds, then goes out.
A failed attachment made getSendReadiness return 'blocked', so Send was a
no-op until the user found and removed the chip. On a phone the only hint
was a small red line after the tap, and a new user lost their question
that way. A failed file never recovers, so holding the send only costs
the question.
Readiness now ignores failed attachments: it waits only on uploading or
processing files. On submit the composer drops every failed attachment
and sends the text with the completed ones. The payloads already read
completed attachments only, so no failed id reaches the request or the
history. The hero-card path in Conversation also clears failed chips.
The failed chip still shows before Send and can be removed by hand.
Removes the send-blocked alert and its locale key.