Skip to content

fix(tui): "extracting graph..." spinner never cleared after spawn_graph_extraction #1924

@bug-ops

Description

@bug-ops

Problem

The TUI status bar shows extracting graph... spinner indefinitely after each turn where graph extraction is triggered.

Root cause

In crates/zeph-core/src/agent/persistence.rs:

// line 473
let _ = self.channel.send_status("extracting graph...").await;  // spinner ON

// line 489
memory.spawn_graph_extraction(...);  // fire-and-forget tokio::spawn — returns immediately
// ← no send_status("") here — spinner is NEVER cleared

spawn_graph_extraction() spawns a background task and returns immediately. The status "" is only reset inside check_summarization() (line 527), which is a separate code path. After graph extraction is spawned, the status bar is never cleared.

Additionally, if the extraction LLM times out (extraction_timeout_secs = 15 default), the timeout is silently swallowed with only a tracing::warn — the spinner still stays visible.

Fix options

Option A (simplest): Clear status immediately after spawn_graph_extraction():

memory.spawn_graph_extraction(...);
let _ = self.channel.send_status("").await;  // clear right away

This is honest — the task is background, the UI shouldn't pretend to be waiting for it.

Option B (accurate): Pass a oneshot::Sender into the background task and clear the status when the task completes or times out:

let (done_tx, done_rx) = tokio::sync::oneshot::channel();
memory.spawn_graph_extraction(..., Some(done_tx));
// inside spawn: done_tx.send(()) on completion/error/timeout
// in agent: await done_rx then send_status("")

This would require making the agent block on extraction, defeating the fire-and-forget design.

Recommended: Option A. Since extraction is intentionally async and non-blocking, the status message should reflect that — e.g. change the label to "saving to graph..." and clear it immediately after spawn, or simply remove the send_status call entirely for this path.

Affected code

  • crates/zeph-core/src/agent/persistence.rs lines 473–489

Steps to reproduce

  1. Enable graph memory in config ([memory.graph] enabled = true)
  2. Start a conversation — after each turn the TUI shows extracting graph...
  3. The spinner never goes away until the next status event overwrites it

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions