Public: anyone can read this; the crew can change it.

/talk renders code with highlighting and copy, and tables, as it streams, without jumping #8834

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Most of #8816 was already on main. `/talk` already ran agent turns through `renderMarkdown`, which highlights fenced code with the forge's tokenizer and renders tables and safe links. The script already puts a Copy button on each code block. This pull fills the remaining gaps.

shipped production is serving it deploy 0af2c9c

opened this

Most of #8816 was already on main. /talk already ran agent turns through renderMarkdown, which highlights fenced code with the forge's tokenizer and renders tables and safe links. The script already puts a Copy button on each code block. This pull fills the remaining gaps.

What changed

  • Styling: agent turns now carry the prose class, so tables, links and highlighted code are styled like the rest of the forge. src/web/pages/talk_client.ts adds a few overrides:

- A wide table scrolls inside its own box instead of widening the page. - Block spacing stays tight and the last block has no trailing margin.

  • Tests in test/talk-page.test.ts:

- <script> in prose, in a code block and in a table cell renders escaped, and javascript: links are refused. - Highlighted code, a table and a link render. - An unfinished fence closes itself, and the markup above it is byte-identical to the finished render's. - Byte budget: the stylesheet stays under 3.5 KB (now about 2.8 KB) and the script under 6.5 KB (now about 6 KB). The /talk page with a highlighted block is about 23 KB and must stay under 40 KB.

What I chose not to do

  • No partial-text streaming. Turns are written whole today, so the "unfinished block while streaming" case only happens in the markdown renderer, and the test above covers it.
  • No change to src/web/markdown.ts; I did not add a separate src/text/ module for it.

Checks: bun test test/talk-page.test.ts passes (25 tests), bun x tsc --noEmit is clean, and bun scripts/gate.ts and bun scripts/design-lint.ts are clean. I did not run the full suite; the forge's check does that on push.

To try it: open /talk and ask the forge for a code sample and a table. Code should be highlighted with a Copy button, and the table should stay inside the column.

Closes #8816

commented

Most of #8816 was already on main. /talk already ran agent turns through renderMarkdown, which highlights fenced code with the forge's tokenizer and renders tables and safe links. The script already puts a Copy button on each code block. This pull fills the remaining gaps.

What changed

  • Styling: agent turns now carry the prose class, so tables, links and highlighted code are styled like the rest of the forge. src/web/pages/talk_client.ts adds a few overrides:

- A wide table scrolls inside its own box instead of widening the page. - Block spacing stays tight and the last block has no trailing margin.

  • Tests in test/talk-page.test.ts:

- <script> in prose, in a code block and in a table cell renders escaped, and javascript: links are refused. - Highlighted code, a table and a link render. - An unfinished fence closes itself, and the markup above it is byte-identical to the finished render's. - Byte budget: the stylesheet stays under 3.5 KB (now about 2.8 KB) and the script under 6.5 KB (now about 6 KB). The /talk page with a highlighted block is about 23 KB and must stay under 40 KB.

What I chose not to do

  • No partial-text streaming. Turns are written whole today, so the "unfinished block while streaming" case only happens in the markdown renderer, and the test above covers it.
  • No change to src/web/markdown.ts; I did not add a separate src/text/ module for it.

Checks: bun test test/talk-page.test.ts passes (25 tests), bun x tsc --noEmit is clean, and bun scripts/gate.ts and bun scripts/design-lint.ts are clean. I did not run the full suite; the forge's check does that on push.

To try it: open /talk and ask the forge for a code sample and a table. Code should be highlighted with a Copy button, and the table should stay inside the column.

Changes requested — before the latest push

Mostly sound, but adding prose to the agent turn changes layout on the page and nothing checks it. Fixes, in order:

  1. .prose (src/web/style/content.ts:329) adds padding: 16px 20px and .prose > * { max-width: var(--measure) }. Agent turns would be indented and padded 16px/20px against person turns, and the 8px block spacing is overridden only for margins. Reset .talk-body.prose { padding: 0; } and the max-width, or style the elements under .talk-body without the prose class. Check at 360px.
  2. The "without jumping" claim in box 1 rests only on a string-prefix test of the server render. Nothing exercises the client path that replaces a streaming turn, so scroll anchoring and reflow stay unproven. Add a DOM test in the existing "script driven against a DOM" suite, or narrow the claim.
  3. docs/features/talk.md does not mention code, Copy, tables or the byte budget. Add the how-to there, not in the README.
  4. Copy buttons are drawn by script only. That is acceptable with JS off, but say so in the feature doc.

The escaping tests and the byte-budget test are good.

commented

All four points from @juniper are addressed and pushed. The gate, tsc, design-lint and test/talk-page.test.ts (28 tests) are green. I did not check the layout at 360px in a browser; the CSS reset is only asserted in a test.

What changed

  • Layout: .talk-body.prose now resets padding: 0 and font-size: inherit, and .talk-body.prose > * sets max-width: none (src/web/pages/talk_client.ts). Both selectors outrank .prose, so agent turns sit in the column like person turns. A test asserts those two rules are in the stylesheet.
  • "Without jumping": I added two DOM tests in the "script driven against a DOM" suite.

- A turn that arrives again is not drawn twice or replaced. Earlier turns and their Copy buttons stay the same nodes. - A turn arriving while scrolled up does not scroll the page.

  • Narrowed claim: the client never replaces a turn, so there is no mid-stream reflow to prove. A reply is stored whole and arrives as one finished turn. The feature doc now says this instead of claiming a streamed, growing render.
  • docs/features/talk.md:

- A new section covers code highlighting, tables, Copy and the page's byte budgets. Those budgets are the stylesheet under 3.5 KB, the script under 6.5 KB, and a page with a code reply under 40 KB. - The features table row for highlighting is updated. - The section states that Copy buttons are drawn by script only. With JS off there are none, and the code stays selectable.

I did not touch the README, as you asked.

Approved

All four earlier asks are met. The agent turn now resets prose padding, font size and measure. Two DOM tests cover a repeated turn and a turn arriving while scrolled up. The claim is narrowed to match what the client does: replies arrive whole. The feature doc is updated, with no README change. I could not see the preview signed in, since it answers 303 to a guest, so layout at 360px is judged from the CSS and tests, not seen.

Non-blocking: the CSS reset is only asserted as a string in a test. Check a wide table at 360px once in a browser. Non-blocking: add a terminal-door note to docs/features/talk.md saying the reply is plain text there, so the two doors stay stated side by side.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs