mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-07 02:51:50 +00:00
docs: clarify wrapForFrac and streaming math-fence rationale
Address two Copilot review comments on PR #17175. - `wrapForFrac` doc said "additive operators or whitespace" but the implementation also matches `*` and `/`. The wider behaviour is the one we want (nested products and fractions need parens to disambiguate inline `/`), so the doc is updated to match instead of tightening the regex. - `fenceOpenAt` was flagged as "overly conservative" vs. `markdown.tsx`, which falls back to paragraph rendering for unclosed `$$` openers. Mirroring that fallback in the streaming chunker would prematurely commit a paragraph rendering of the unclosed opener to the monotonic stable prefix, where it would be frozen and become wrong the moment the closer streams in. The asymmetry is deliberate; document why so it isn't "fixed" again later. Made-with: Cursor
This commit is contained in:
parent
cb039ac000
commit
3379f88ea4
2 changed files with 19 additions and 4 deletions
|
|
@ -42,6 +42,18 @@ import { Md } from './markdown.js'
|
||||||
// snippets like ` ```\n$$x$$\n``` ` (math example inside a code block)
|
// snippets like ` ```\n$$x$$\n``` ` (math example inside a code block)
|
||||||
// don't double-count. A `$$x$$` line that opens AND closes on its own
|
// don't double-count. A `$$x$$` line that opens AND closes on its own
|
||||||
// produces zero net toggles; that's `len >= 4` plus `endsDollar`.
|
// produces zero net toggles; that's `len >= 4` plus `endsDollar`.
|
||||||
|
//
|
||||||
|
// NB: this is INTENTIONALLY more conservative than `markdown.tsx`'s
|
||||||
|
// parser, which falls back to paragraph rendering when an `$$` opener
|
||||||
|
// has no matching closer. The renderer can do that safely because it
|
||||||
|
// always sees the full text on every call. The streaming chunker
|
||||||
|
// cannot — once a chunk is committed to the monotonic stable prefix it
|
||||||
|
// is frozen, so prematurely deciding "this `$$` is just prose" would
|
||||||
|
// permanently commit a paragraph rendering that becomes wrong the
|
||||||
|
// instant the closer streams in. Treating any unmatched `$$` opener
|
||||||
|
// as still-open keeps the boundary parked behind it until the closer
|
||||||
|
// arrives (or the stream ends and the non-streaming `<Md>` takes over,
|
||||||
|
// at which point the renderer's fallback kicks in correctly).
|
||||||
const fenceOpenAt = (s: string, end: number) => {
|
const fenceOpenAt = (s: string, end: number) => {
|
||||||
let codeOpen = false
|
let codeOpen = false
|
||||||
let mathOpen = false
|
let mathOpen = false
|
||||||
|
|
|
||||||
|
|
@ -644,10 +644,13 @@ const replaceFracs = (input: string): string => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap multi-token expressions in parens so `\frac{a+b}{c}` becomes
|
// Wrap multi-token expressions in parens so `\frac{a+b}{c}` becomes
|
||||||
// `(a+b)/c` rather than `a+b/c`. We only wrap when the expression has
|
// `(a+b)/c` rather than `a+b/c`. We wrap whenever inline `/` would
|
||||||
// loose precedence — additive operators or whitespace that would change
|
// change the meaning — that's any binary operator (`+`, `-`, `*`, `/`)
|
||||||
// meaning under inline `/`. Atomic factors like `n!`, `x^2`, `\sin x`
|
// or whitespace separating tokens. `*` and `/` matter because nested
|
||||||
// don't need parens; wrapping them just clutters the output.
|
// fractions and products like `\frac{a*b}{c}` and `\frac{1/x}{y}` would
|
||||||
|
// otherwise read as `a*b/c` (right-associative ambiguity) and `1/x/y`.
|
||||||
|
// Atomic factors like `n!`, `x^2`, `\sin x` don't trigger any of these
|
||||||
|
// and stay un-parenthesised — wrapping them just clutters the output.
|
||||||
const wrapForFrac = (expr: string) => {
|
const wrapForFrac = (expr: string) => {
|
||||||
const trimmed = expr.trim()
|
const trimmed = expr.trim()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue