fix: improve cross-device evidence and exploration lifecycle
Align Responses cache affinity across execution and summary calls, preserve required checks and evidence uncertainty, and allow safe deletion of inactive explorations while retaining independent reruns. Validation: backend suite passed except intentional prompt golden drift, then all 17 transcript tests passed after snapshot refresh; 268 frontend tests and production build passed; Ruff, quality ratchet and core type checks passed.
This commit is contained in:
1 parent
f1bb5d02aa
commit
2328a4df0c
32 files changed
+748
-79
No files matched your search
@@ -16,7 +16,7 @@
|
||||
|
||||
import { Injectable, signal, inject, computed, DestroyRef, NgZone } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
|
||||
import { Session, ModelInfo, TaskQueueItem, AgentStatusResponse, SessionUsage, CaseReviewResponse } from '../core/models/session.model';
|
||||
import { ProTuningDefaults, ProTuningOptions } from '../core/models/pro-tuning.model';
|
||||
@@ -718,45 +718,39 @@ export class AgentService {
|
||||
/**
|
||||
* Delete an individual session / task
|
||||
*/
|
||||
public canDeleteSession(session: Pick<Session, 'status'>): boolean {
|
||||
return ['completed', 'success', 'failed', 'cancelled', 'interrupted', 'skipped'].includes(session.status || '');
|
||||
}
|
||||
|
||||
public deletionPrompt(sessionId: string, explorationKind?: string): string {
|
||||
const kind = explorationKind || this.rawSessions().find(s => s.session_id === sessionId)?.exploration_kind;
|
||||
return kind === 'exploration'
|
||||
? '确定删除此探索的对话、用例版本及全部探索执行记录和文件?已生成的复跑与批次任务将保留。此操作无法撤销。'
|
||||
: '确定删除此历史任务?此操作无法撤销。';
|
||||
}
|
||||
|
||||
public deleteSession(sessionId: string): Observable<any> {
|
||||
// 1. Optimistically update local session state immediately
|
||||
this.invalidateStatusSignatures();
|
||||
this.rawSessions.update((list) => list.filter((s) => s.session_id !== sessionId));
|
||||
this.persistSessionsCache(this.rawSessions());
|
||||
this.pendingQueue.update((list) => list.filter((s) => s.session_id !== sessionId));
|
||||
|
||||
if (this.userPinnedSessionId() === sessionId) {
|
||||
this.userPinnedSessionId.set(null);
|
||||
}
|
||||
|
||||
if (this.currentSessionId() === sessionId) {
|
||||
this.selectSession('', false);
|
||||
if (this.isVideoWindowOpen()) {
|
||||
this.closeVideoPlayer();
|
||||
}
|
||||
const runningId = this.runningSessionId();
|
||||
if (runningId && this.agentStatus() === 'running') {
|
||||
this.selectSession(runningId, false);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Send API request
|
||||
return new Observable((obs) => {
|
||||
this.http.post<any>(`/api/sessions/${sessionId}/delete`, {}).subscribe({
|
||||
next: (res) => {
|
||||
this.fetchSessions();
|
||||
this.fetchStatus();
|
||||
obs.next(res);
|
||||
obs.complete();
|
||||
},
|
||||
error: (err) => {
|
||||
console.error(`删除会话失败:${sessionId}:`, err);
|
||||
this.fetchSessions();
|
||||
this.fetchStatus();
|
||||
obs.error(err);
|
||||
// Keep the task selected until the server confirms the entire deletion.
|
||||
return this.http.post<any>(`/api/sessions/${sessionId}/delete`, {}).pipe(tap(res => {
|
||||
const deleted = new Set<string>(res.deleted_session_ids || [sessionId]);
|
||||
this.invalidateStatusSignatures();
|
||||
for (const id of deleted) this.activeSessionTracking.delete(id);
|
||||
this.rawSessions.update(list => list.filter(s => !deleted.has(s.session_id)));
|
||||
this.pendingQueue.update(list => list.filter(s => !deleted.has(s.session_id)));
|
||||
this.persistSessionsCache(this.rawSessions());
|
||||
if (deleted.has(this.userPinnedSessionId() || '')) this.userPinnedSessionId.set(null);
|
||||
if (deleted.has(this.currentSessionId() || '')) {
|
||||
this.selectSession('', false);
|
||||
if (this.isVideoWindowOpen()) this.closeVideoPlayer();
|
||||
const runningId = this.runningSessionId();
|
||||
if (runningId && !deleted.has(runningId) && this.agentStatus() === 'running') {
|
||||
this.selectSession(runningId, false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
this.resultRevision.update(value => value + 1);
|
||||
this.fetchSessions();
|
||||
this.fetchStatus();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user