Skip to content

fix(ui): restore status indicator during tool calls after text has streamed#89

Merged
ScottKirvan merged 1 commit intoScottKirvan:mainfrom
SKVFX-DevBot:fix/thinking-status-indicator
Mar 31, 2026
Merged

fix(ui): restore status indicator during tool calls after text has streamed#89
ScottKirvan merged 1 commit intoScottKirvan:mainfrom
SKVFX-DevBot:fix/thinking-status-indicator

Conversation

@SKVFX-DevBot
Copy link
Copy Markdown
Collaborator

Summary

The "Thinking…" / tool-status indicator was silently dropped during multi-step responses where Claude emitted text before calling tools. assistantEl.setText(accumulated) in the onText callback replaces the element's entire child list, detaching statusEl. Subsequent onToolCall handlers called statusEl.setText() on the detached element, so the update was invisible. The indicator only worked reliably when tool calls preceded all text.

Issue

Closes #67

Root Cause

statusEl is a child <span> of assistantEl. assistantEl.setText(accumulated) sets textContent on the parent, which is equivalent to removing all child nodes first. After the first text token, statusEl is gone from the DOM. The owner's comment ("seems to work sometimes") is explained by the sequence: tool-calls-first responses show the status correctly; text-first responses lose it.

Fix

  • Introduced a dedicated streamingTextEl span inside assistantEl for streaming text, so statusEl remains a sibling rather than being clobbered by textContent replacement.
  • onText now writes to streamingTextEl.textContent instead of assistantEl.setText().
  • onToolCall re-appends statusEl via assistantEl.appendChild(statusEl) if !statusEl.isConnected — handles the case where prior text already removed it.
  • Applied identically to both handleSend and handleVaultInject response groups.
  • The assistantEl.empty() + MarkdownRenderer.render() path in onDone is unchanged; it clears everything and renders final markdown as before.

Testing

  1. Open Obsidian with a test vault that has Cortex enabled.
  2. Ask a question that causes Claude to narrate before acting — e.g. "Read my daily note and summarise it." Claude will typically respond with a sentence like "I'll read your daily note." before calling the Read tool.
  3. Expected (after fix): "Thinking…" appears immediately on send. After the first text token it disappears. When the Read tool fires, the status reappears as "Reading…" or similar. When the final response streams in, the status disappears.
  4. Previous behaviour (regression): After the first text token, no status appeared for any subsequent tool calls — the panel looked idle while Claude was still working.
  5. Also test a tool-calls-only response (no leading text) to confirm the existing behaviour is unchanged.
  6. Also test a plain text response (no tools) to confirm "Thinking…" → text streaming → no status works as before.

Regression Risk

  • Session persistence: not affected — no changes to session save/load logic.
  • Vault file operations: not affected — tool dispatch logic unchanged.
  • Claude Code subprocess lifecycle: not affected — parseStreamOutput is unchanged.
  • Markdown rendering: not affected — onDone calls assistantEl.empty() then MarkdownRenderer.render() as before; the new streamingTextEl is cleared along with everything else.
  • Export-to-vault / copy: assistantEl.dataset.markdown is still set from accumulated in onDone — no change.
  • UIBridge actions: action extraction still runs against accumulated in onText; the change is only to which element receives the display update.

Notes

isConnected is a standard Node property (MDN); it is available on all Obsidian-extended HTMLElement instances. No new dependencies introduced.

…reamed

When an assistant response begins with text before calling tools (e.g.
"I'm going to read these files."), assistantEl.setText() was replacing
all child nodes including statusEl, leaving it detached. Subsequent
onToolCall handlers updated the detached element's text with no visible
effect.

Fix: introduce a dedicated streamingTextEl span for in-progress text so
statusEl remains a sibling. Re-append statusEl in onToolCall if it has
been removed. Apply to both handleSend and handleVaultInject response
groups. Adds a parseStreamOutput test covering the text→tool→text
callback sequence that the DOM fix depends on.

Closes ScottKirvan#67

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ScottKirvan ScottKirvan merged commit abe07f6 into ScottKirvan:main Mar 31, 2026
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.

"Thinking..." status indicator no longer appears while Claude is working

2 participants