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:
1 parent
5f1ee18bc1
commit
60312abbb0
8 files changed
+384
-91
No files matched your search
@@ -232,9 +232,11 @@ export class AgentService {
|
||||
public recordingPlaybackMessage = signal<string>('');
|
||||
public shouldAutoplayVideo = signal<boolean>(false);
|
||||
public videoSeekRequest = signal<{ seconds: number; requestId: number } | null>(null);
|
||||
public stepSeekRequest = signal<{ index: number; requestId: number } | null>(null);
|
||||
public playerMode = signal<'video' | 'steps'>('video');
|
||||
private activeVideoSessionId: string | null = null;
|
||||
private videoSeekRequestId = 0;
|
||||
private stepSeekRequestId = 0;
|
||||
private videoRequestGeneration = 0;
|
||||
private videoRetryTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
private videoWaitStartedAt = 0;
|
||||
@@ -258,6 +260,11 @@ export class AgentService {
|
||||
this.playerMode.update((mode) => (mode === 'video' ? 'steps' : 'video'));
|
||||
}
|
||||
|
||||
public requestStepSeek(index: number): void {
|
||||
this.stepSeekRequestId++;
|
||||
this.stepSeekRequest.set({ index, requestId: this.stepSeekRequestId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear user-pinned selection so subsequent runs automatically follow active runner
|
||||
*/
|
||||
@@ -1407,7 +1414,8 @@ export class AgentService {
|
||||
sessionId?: string,
|
||||
videoUrl?: string,
|
||||
title?: string,
|
||||
seekSeconds?: number
|
||||
seekSeconds?: number,
|
||||
stepIndex?: number
|
||||
): void {
|
||||
const targetSessionId = sessionId || this.currentSessionId();
|
||||
const session = this.sessions().find(s => s.session_id === targetSessionId);
|
||||
@@ -1424,6 +1432,10 @@ export class AgentService {
|
||||
this.recordingPlaybackMessage.set('');
|
||||
this.activeVideoSegments.set([]);
|
||||
if (Number.isFinite(seekSeconds)) this.requestVideoSeek(Number(seekSeconds));
|
||||
if (Number.isFinite(stepIndex)) {
|
||||
this.playerMode?.set('steps');
|
||||
this.requestStepSeek(Number(stepIndex));
|
||||
}
|
||||
if (!targetSessionId) {
|
||||
this.activeVideoUrl.set(null);
|
||||
this.isVideoLoading.set(false);
|
||||
|
||||
Reference in new issue
Block a user