fix(replay): unify step indexing, dual-index entity deduplication, and prevent step-4 start bug

- Backend: maintain _step_number_cache in DataEngine and include step_number in all step_updated SSE events (summary, thinking, execution result)
- Admin console: query unassigned trace step_ids in stepless_rows to prevent orphan traces from being lost
- Showcase UI: implement dual-indexed entity deduplication (by step_id and step_number) in extractStepReplayFrames to eliminate phantom ghost steps
- Showcase UI: filter visual screenshot steps before generating sequential 1-based frame numbers, preventing step-4 start and index shift bugs
- Showcase UI: add rawStepNumber and summary properties to StepReplayFrame
- Showcase UI: update FloatingVideoPlayerComponent session reset effect to only reset playback on sessionId change rather than on every stepFrames mutation
- Showcase UI: add stepSeekRequest signal and stepIndex parameter to AgentService.openVideoPlayer
- Unit tests: add Karma and Pytest unit tests verifying step 1 start, dual-indexing, and SSE step_number payloads
This commit is contained in:
somew1nd committed 2026-08-27 11:03:47 -07:00
1 parent 5f1ee18bc1
commit 60312abbb0
8 files changed
+384 -91

No files matched your search

+37
View File
@@ -326,3 +326,40 @@ def test_resumed_session_monotonic_step_numbering(tmp_path):
assert len(steps) == 3
assert [s.step_number for s in steps] == [1, 2, 3]
def test_update_step_summary_includes_step_number_in_sse(tmp_path):
mock_ctx = MagicMock(spec=ArtemisContext)
mock_execution_setup = MagicMock()
mock_execution_setup.traces_path = str(tmp_path)
mock_ctx.execution_setup = mock_execution_setup
mock_ctx.device = None
published_events = []
def mock_subscriber(event_type, data):
published_events.append((event_type, data))
engine = DataEngine(mock_ctx)
engine.subscribe(mock_subscriber)
sid = engine.start_session("SSE step_number verification")
step_id = engine.record_step(summary="Initial step 1")
for t in list(engine._pending_threads):
t.join()
assert engine.get_step_number(step_id) == 1
# Call update_step_summary
engine.update_step_summary(step_id, "Updated concise summary for Step 1")
for t in list(engine._pending_threads):
t.join()
# Find the published step_updated event
step_updated_events = [e for e in published_events if e[0] == "step_updated"]
assert len(step_updated_events) >= 1
last_update = step_updated_events[-1][1]
assert last_update["step_id"] == str(step_id)
assert last_update["summary"] == "Updated concise summary for Step 1"
assert last_update["step_number"] == 1