Skip to content

fix(asv3): render finalised messages on mount in MarkdownBlock#409

Open
Luis85 wants to merge 1 commit into
developfrom
fix/asv3-markdownblock-render-on-mount
Open

fix(asv3): render finalised messages on mount in MarkdownBlock#409
Luis85 wants to merge 1 commit into
developfrom
fix/asv3-markdownblock-render-on-mount

Conversation

@Luis85
Copy link
Copy Markdown
Owner

@Luis85 Luis85 commented May 17, 2026

Summary

  • The native-renderer branch added by PR feat(agent): MarkdownRenderPort backed by Obsidian native renderer (PR-ASV-7-obsidian) #377 used a single watch(() => props.text, ..., { immediate: true, flush: 'post' }) to drive every render.
  • Inside Obsidian's view lifecycle with Vue 3.5, the immediate run fires before the template ref is bound — nativeContainer.value is still null, so rerenderNative() returns early.
  • For completed message bubbles whose text never changes again after mount, that early-return is terminal: the body stays empty even though the rendered scratch div is fully populated for streaming bubbles.
  • Streaming bubbles hid this because their text keeps growing post-mount, so subsequent watcher firings end up rendering after the container has bound.
  • Fix: add an explicit onMounted(() => void rerenderNative()) so finalised messages get one post-mount render even when their text never changes.

How it was caught

  • User reported empty user and assistant message bodies in the Obsidian Agent sidepanel; streaming bubble showed text but final bubbles were empty.
  • Instrumentation in MarkdownBlock.vue confirmed: the watch's immediate run reported "no el" before mount; the final-message instances mounted (onMounted fired, container bound) but no second watcher firing followed, since text is immutable post-finalisation.
  • Streaming bubble (whose text grows) re-fired the watcher and rendered correctly — masking the bug.

Test plan

  • npm run typecheck — clean (0 errors)
  • npm run lint — 0 errors
  • npm run test — 1863 / 1863 passing
  • npm run build — clean bundle
  • Manual: deploy to test vault, reload plugin in Obsidian, send a fresh prompt — user message body and assistant response body now render their markdown content as expected.

🤖 Generated with Claude Code

The native-renderer branch installed by PR #377 used a single
`watch(() => props.text, ..., { immediate: true, flush: 'post' })` to
drive every render. Inside Obsidian's view lifecycle with Vue 3.5, the
immediate run consistently fires before the template ref is bound:
`nativeContainer.value` is still `null` and `rerenderNative()` returns
early. For completed message bubbles whose `text` never changes again
after mount, that early-return is terminal — the body stays empty.

Streaming bubbles previously hid this because their `text` keeps growing
post-mount, so subsequent watcher firings render the text after the
container has bound.

Add an explicit `onMounted` trigger so finalised messages get one
post-mount render even when their text never changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants