Assistant: gestione cancel, status e refactor chiamate (AssistantService, AssistantCall)
This commit is contained in:
parent
73312f82c0
commit
df26fdc666
|
|
@ -46,7 +46,7 @@ export type AssistantConfig = {
|
|||
availableModelsRetrieverUrl: string;
|
||||
};
|
||||
|
||||
export type AssistantCallStatus = 'QUEUED' | 'RUNNING' | 'COMPLETED' | 'FAILED';
|
||||
export type AssistantCallStatus = 'QUEUED' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELLED';
|
||||
|
||||
export type AssistantCallPhase =
|
||||
| 'queued'
|
||||
|
|
@ -58,7 +58,8 @@ export type AssistantCallPhase =
|
|||
| 'fixing'
|
||||
| 'explaining'
|
||||
| 'completed'
|
||||
| 'failed';
|
||||
| 'failed'
|
||||
| 'cancelled';
|
||||
|
||||
export type AssistantCallState = {
|
||||
id: string;
|
||||
|
|
|
|||
|
|
@ -19,5 +19,7 @@ export abstract class AssistantCallServiceBase {
|
|||
|
||||
abstract getCall(callId: string): Observable<AssistantCallState>;
|
||||
|
||||
abstract cancelCall(callId: string): Observable<AssistantCallState>;
|
||||
|
||||
abstract getSession(sessionId: string): Observable<AssistantSessionState>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ type FakeCallRecord = {
|
|||
phases: AssistantCallPhase[];
|
||||
completed: boolean;
|
||||
failed: boolean;
|
||||
cancelled: boolean;
|
||||
};
|
||||
|
||||
export class AssistantCallServiceFake extends AssistantCallServiceBase {
|
||||
|
|
@ -83,7 +84,8 @@ export class AssistantCallServiceFake extends AssistantCallServiceBase {
|
|||
phaseIndex: 0,
|
||||
phases,
|
||||
completed: false,
|
||||
failed: false
|
||||
failed: false,
|
||||
cancelled: false
|
||||
});
|
||||
session.lastCallId = callId;
|
||||
|
||||
|
|
@ -96,7 +98,7 @@ export class AssistantCallServiceFake extends AssistantCallServiceBase {
|
|||
throw new Error(`Assistant call ${callId} not found`);
|
||||
}
|
||||
|
||||
if (!call.completed && !call.failed) {
|
||||
if (!call.completed && !call.failed && !call.cancelled) {
|
||||
if (call.phaseIndex < call.phases.length - 1) {
|
||||
call.phaseIndex += 1;
|
||||
} else {
|
||||
|
|
@ -109,23 +111,44 @@ export class AssistantCallServiceFake extends AssistantCallServiceBase {
|
|||
? 'completed'
|
||||
: call.failed
|
||||
? 'failed'
|
||||
: call.phases[call.phaseIndex];
|
||||
: call.cancelled
|
||||
? 'cancelled'
|
||||
: call.phases[call.phaseIndex];
|
||||
|
||||
return of({
|
||||
id: call.id,
|
||||
sessionId: call.sessionId,
|
||||
status: call.failed
|
||||
? 'FAILED'
|
||||
: call.cancelled
|
||||
? 'CANCELLED'
|
||||
: call.completed
|
||||
? 'COMPLETED'
|
||||
: call.phaseIndex === 0
|
||||
? 'QUEUED'
|
||||
: 'RUNNING',
|
||||
phase,
|
||||
progressMessage: call.cancelled ? 'Assistant request cancelled' : undefined,
|
||||
errorMessage: call.failed ? 'Fake assistant call failed.' : undefined
|
||||
});
|
||||
}
|
||||
|
||||
override cancelCall(callId: string): Observable<AssistantCallState> {
|
||||
const call = this.calls.get(callId);
|
||||
if (!call) {
|
||||
throw new Error(`Assistant call ${callId} not found`);
|
||||
}
|
||||
|
||||
call.cancelled = true;
|
||||
return of({
|
||||
id: call.id,
|
||||
sessionId: call.sessionId,
|
||||
status: 'CANCELLED',
|
||||
phase: 'cancelled',
|
||||
progressMessage: 'Assistant request cancelled'
|
||||
});
|
||||
}
|
||||
|
||||
override getSession(sessionId: string): Observable<AssistantSessionState> {
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (!session) {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,13 @@ export class AssistantCallService extends AssistantCallServiceBase {
|
|||
.pipe(map((raw) => mapAssistantCallState(raw)));
|
||||
}
|
||||
|
||||
override cancelCall(callId: string): Observable<AssistantCallState> {
|
||||
const encodedId = encodeURIComponent(callId);
|
||||
return this.http
|
||||
.put<unknown>(`${environment.apiUrl}/assistant/calls/${encodedId}/cancel`, {})
|
||||
.pipe(map((raw) => mapAssistantCallState(raw)));
|
||||
}
|
||||
|
||||
override getSession(sessionId: string): Observable<AssistantSessionState> {
|
||||
const encodedId = encodeURIComponent(sessionId);
|
||||
return this.http
|
||||
|
|
@ -222,7 +229,7 @@ function mapValidationIssues(raw: unknown): AssistantValidationIssue[] {
|
|||
|
||||
function mapCallStatus(raw: unknown): AssistantCallStatus {
|
||||
const normalized = typeof raw === 'string' ? raw.toUpperCase() : '';
|
||||
if (normalized === 'QUEUED' || normalized === 'RUNNING' || normalized === 'FAILED') return normalized;
|
||||
if (normalized === 'QUEUED' || normalized === 'RUNNING' || normalized === 'FAILED' || normalized === 'CANCELLED') return normalized;
|
||||
return 'COMPLETED';
|
||||
}
|
||||
|
||||
|
|
@ -239,6 +246,7 @@ function mapCallPhase(raw: unknown): AssistantCallPhase {
|
|||
case 'explaining':
|
||||
case 'completed':
|
||||
case 'failed':
|
||||
case 'cancelled':
|
||||
return normalized;
|
||||
default:
|
||||
return 'queued';
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@ export class AssistantService {
|
|||
return this.assistantCall.getCall(callId);
|
||||
}
|
||||
|
||||
cancelCall(callId: string) {
|
||||
return this.assistantCall.cancelCall(callId);
|
||||
}
|
||||
|
||||
getSession(sessionId: string) {
|
||||
return this.assistantCall.getSession(sessionId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,10 +10,14 @@ export type AssistantSessionSnapshot = {
|
|||
localMessages: AssistantChatMessage[];
|
||||
currentCall: AssistantCallState | null;
|
||||
sessionState: AssistantSessionState | null;
|
||||
assistantErrorMessage: string | null;
|
||||
lastFailedPrompt: string | null;
|
||||
lastSubmittedPrompt: string;
|
||||
};
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AssistantSessionStore {
|
||||
static readonly CREATE_MODAL_FLOW_KEY = '__assistant:create-modal';
|
||||
private static readonly NO_FLOW_KEY = '__assistant:no-flow__';
|
||||
private static readonly STORAGE_KEY = 'assistant-session-store:v1';
|
||||
private static readonly STORAGE_TARGETS: Array<'localStorage' | 'sessionStorage'> = ['localStorage', 'sessionStorage'];
|
||||
|
|
@ -32,6 +36,10 @@ export class AssistantSessionStore {
|
|||
return snapshot ? structuredClone(snapshot) : null;
|
||||
}
|
||||
|
||||
hasSnapshot(flowKey: string): boolean {
|
||||
return this.snapshots.has(flowKey);
|
||||
}
|
||||
|
||||
setSnapshot(flowKey: string, snapshot: AssistantSessionSnapshot) {
|
||||
this.snapshots.set(flowKey, structuredClone(snapshot));
|
||||
this.persistToStorage();
|
||||
|
|
@ -44,6 +52,11 @@ export class AssistantSessionStore {
|
|||
this.persistToStorage();
|
||||
}
|
||||
|
||||
clearSnapshot(flowKey: string) {
|
||||
if (!this.snapshots.delete(flowKey)) return;
|
||||
this.persistToStorage();
|
||||
}
|
||||
|
||||
private hydrateFromStorage() {
|
||||
const raw = this.readStoredPayload();
|
||||
if (!raw) return;
|
||||
|
|
@ -83,7 +96,16 @@ export class AssistantSessionStore {
|
|||
: null,
|
||||
sessionState: snapshot['sessionState'] && typeof snapshot['sessionState'] === 'object'
|
||||
? this.normalizeSessionState(snapshot['sessionState'])
|
||||
: null
|
||||
: null,
|
||||
assistantErrorMessage: typeof snapshot['assistantErrorMessage'] === 'string'
|
||||
? snapshot['assistantErrorMessage']
|
||||
: null,
|
||||
lastFailedPrompt: typeof snapshot['lastFailedPrompt'] === 'string'
|
||||
? snapshot['lastFailedPrompt']
|
||||
: null,
|
||||
lastSubmittedPrompt: typeof snapshot['lastSubmittedPrompt'] === 'string'
|
||||
? snapshot['lastSubmittedPrompt']
|
||||
: ''
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue