Skip to content

fix: keep chat output in the originating note when switching notes mid-stream - #206

Open
Vokinloksar wants to merge 1 commit into
bramses:masterfrom
Vokinloksar:fix/streaming-output-to-originating-note
Open

fix: keep chat output in the originating note when switching notes mid-stream#206
Vokinloksar wants to merge 1 commit into
bramses:masterfrom
Vokinloksar:fix/streaming-output-to-originating-note

Conversation

@Vokinloksar

Copy link
Copy Markdown
Contributor

Summary

Fixes a bug where streaming a chat response in note A and then switching the
tab to note B caused the response to be written into note B instead of note A.
Root cause: Obsidian reuses a single editor instance per tab and swaps its
document when you navigate to another note in the same tab. The chat command
captured that live editor at invocation but wrote to it asynchronously during
streaming, so once the tab switched notes, all subsequent output (and the
trailing user delimiter / inferred title) landed in the wrong note.

Changes

  • Add getFileForEditor() to detect which file an editor currently displays.
  • StreamingHandler verifies the editor still shows the original note before
    each write. Once the user navigates away, it sticky-redirects remaining
    output to the original file via app.vault.process() (ordered append queue).
    Live streaming is unchanged while the note stays active.
  • AiProviderService threads the originating app/file through the streaming
    path and only touches the editor (cursor, error text, tool notices) when it
    still shows the target note.
  • MessageService appends the trailing role::user delimiter to the original
    file when the editor has navigated away.
  • Title inference now renames the captured file instead of whatever note is
    currently active (same bug class).
  • Import jest in the obsidian test mock (the new runtime obsidian import
    surfaced an ESM module-scope reference).

Note

The one edge case: if you switch notes mid-stream while in at-cursor mode, the redirected text is appended to the end of the original file rather than at the old cursor position. That's intentional —
once the note isn't in the visible editor, the cursor/selection no longer exists, so end-of-file append is the only safe option. The alternative (writing at a stale cursor in a hidden document) is
exactly the corruption we're fixing.

Test plan

  • yarn test — 120 passing (added StreamingHandler tests covering
    on-target writes, redirect-on-switch, and sticky redirect)
  • yarn build — type-check + production bundle succeed
  • yarn lint — no new errors
  • Manual: prompt in note A, switch tab to note B mid-stream → response
    stays in note A; note B untouched; reopening A shows the full response.

…d-stream

Obsidian reuses a single editor instance per tab and swaps its document when
the user navigates to a different note in the same tab. The chat command
captured that live editor at invocation but wrote to it asynchronously while
streaming, so prompting in note A and then switching the tab to note B caused
the response (and the trailing user delimiter / inferred title) to land in
note B.

Pin all output to the file captured when the command was invoked:

- Add getFileForEditor() to detect which file an editor currently displays.
- StreamingHandler verifies the editor still shows the original note before
  each write; once the user navigates away it sticky-redirects remaining
  output to the original file via app.vault.process() (ordered append queue),
  while live streaming is unchanged when the note stays active.
- AiProviderService threads the originating app/file through the streaming
  path and only touches the editor (cursor, error text, tool notices) when it
  still shows the target note.
- MessageService appends the trailing user delimiter to the original file when
  the editor has navigated away.
- Title inference renames the captured file instead of whatever note is
  currently active.

Add StreamingHandler tests covering on-target writes, redirect-on-switch, and
sticky redirect. Import jest in the obsidian test mock (the new runtime
obsidian import surfaced an ESM module-scope reference).

Co-authored-by: Cursor <cursoragent@cursor.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.

1 participant