nesquena/hermes-webui

Workspace Artifacts keeps stale, dead-link entries after files are moved or deleted

开放

#6,867 创建于 2026年8月9日

 (1 条评论) (0 个反应) (0 位负责人)Python (2,386 个派生)github user discovery
bughelp wantedworkspace

仓库指标

星标
 (17,368 个星标)
PR 合并指标
 (平均合并 14小时 31分钟) (30 天内合并 314 个 PR)

描述

Report

The Workspace Artifacts tab can retain an obsolete path after files are updated or moved. The stale row remains clickable and ends in the generic “file not found” / file_open_failed state even though the file exists at its current location. Switching to another session and back rebuilds the list correctly.

Reported from exp-v0.52.158-dirty-a9b7cc19; the lifecycle gap is still present on master at 614b5c9f485d33de0f35f0c2b5b95e4090ef3af3 (exp-v0.52.186).

Investigation

The canonical artifact data updates, but one settled-session recovery path does not project that new data into the already-rendered Artifacts DOM:

  1. collectSessionArtifacts() derives the current rows from S.toolCalls and structured message metadata. renderSessionArtifacts() is what materializes that state into the panel; the DOM is not otherwise reactive.
  2. Normal live paths do refresh the panel: tool / tool_complete schedule an artifact render, and the normal done path renders after applying the settled session.
  3. _restoreSettledSession() replaces S.session, S.messages, and S.toolCalls from the canonical persisted session after stream-end/SSE recovery, then calls only syncTopbar() and renderMessages(). It never calls renderSessionArtifacts() or scheduleRenderSessionArtifacts().
  4. The reported self-heal matches the other lifecycle exactly: loadSession() explicitly calls renderSessionArtifacts() after loading the session. Switching away and back therefore projects the already-correct canonical artifact state and removes the stale row.
  5. openArtifactPath() then explains the visible failure: clicking the retained old DOM row performs an existence check and emits file_open_failed.

I executed the real current-head collector and renderer against the relevant state transition:

{
  "initialDom": ["old/path.md"],
  "canonicalAfterRestore": ["new/path.md"],
  "domAfterRestoreWithoutProjection": ["old/path.md"],
  "domAfterSessionLoadProjection": ["new/path.md"]
}

This isolates the bug: canonical state is already correct after recovery; only the Artifacts DOM remains stale until the session-load render runs.

Reproduction shape

  1. Keep the Artifacts tab/panel mounted while a live turn changes the session artifact set.
  2. Let the turn settle through the stream_end / settled-session recovery path rather than the ordinary done projection.
  3. Observe that the transcript and canonical S.toolCalls settle, but the Artifacts DOM retains its previous row.
  4. Click that obsolete row and observe file_open_failed.
  5. Switch to another session and back; the Artifacts list now reflects the canonical path.

Expected behavior

Every path that installs canonical session messages/tool metadata for the actively viewed session should refresh all dependent projections, including Workspace Artifacts. Users should not need to switch sessions to reconcile the panel.

Fix shape and acceptance criteria

  • After _restoreSettledSession() installs canonical S.messages / S.toolCalls, refresh Workspace Artifacts for the active viewed session.
  • Prefer a shared post-session-state projection helper used by normal done, settled-session recovery, and loadSession() so these dependent views cannot drift again.
  • Preserve openArtifactPath()'s existence check as a safety boundary; prevent the obsolete row rather than weakening file-not-found handling.
  • Add a deterministic regression test using the real collector and renderer: render an old path, apply a settled snapshot containing a replacement path, run the recovery projection, and assert that the new path is visible without a session switch and the old row is absent.
  • Ensure recovery for a non-viewed/foreign session cannot repaint the currently viewed panel.

Distinct from existing issues

  • #5747 and PRs #5752/#6691 cover stale content in an already-open file preview, not stale rows in the Artifacts list.
  • #6205 / #6207 / #6469 concern durable turn-owned artifact references and explicitly leave the existing Artifacts-tab reconstruction unchanged.
  • #6593 / #6694 add artifact categories; they do not cover settled-session DOM invalidation.
  • #3329 fixed structured tool metadata and absolute-path opening. The current bug has correct canonical metadata but a stale rendered row.
  • #3885 is related lifecycle history: it added settled-session recovery for a missing transcript after stream_end, but did not refresh Workspace Artifacts.

贡献者指南