Skip to content

toolpath-desktop: memoize markdown rendering per chat turn #38

@eliothedeman

Description

@eliothedeman

Follow-up from #34 review. Perf concern, not a correctness bug.

ChatView.svelte calls renderMarkdown(t.text) inline inside the {#each turns} block on every reactive tick. In a 1700-step Claude session, that can be 500+ assistant turns × [marked.parse + DOMPurify.sanitize] per re-render. Svelte 5's $derived won't memoize across this loop; the pipeline re-runs whenever any unrelated state mutates preview (tree-query typing, selection change, view-mode toggle).

Fix

Cache the rendered HTML on the ChatTurn itself at flatten time, so subsequent renders are a trivial property read:

// in tree.ts::flattenChatHead
const textHtml = c.text ? renderMarkdown(c.text) : "";
const thinkingHtml = c.thinking ? renderMarkdown(c.thinking) : "";
// → store on ChatTurn, use in ChatView without re-calling renderMarkdown

This changes flattenChatHead from classify-only to render-too, which couples it to the markdown pipeline — acceptable given ChatTurn is a UI-model type.

Alternative: Map<stepId, string> memo external to the flatten, keyed by step.id + text hash.

Same treatment wanted

  • diff.raw.split("\n") in the tool block — cache the split on the turn.
  • viz.ts::renderCard also calls renderMarkdown(bodyText) for graph cards on every render(). Graph re-renders are less frequent but not free.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions