Add session_type ('guided'|'chat') and title columns to ai_sessions,
enabling both FlowPilot guided sessions and assistant chat sessions to
live in a single table. This is the foundation for a unified session
history and consistent UX across both interaction modes.
Backend:
- Migration 066: session_type + title columns
- unified_chat_service: chat sessions on ai_sessions with same AI/RAG
- POST /ai-sessions supports session_type='chat' creation
- POST /ai-sessions/{id}/chat for chat messages
- DELETE /ai-sessions/{id} for session deletion
- session_type filter on GET /ai-sessions
Frontend:
- AssistantChatPage rewired to aiSessionsApi (no more assistantChatApi)
- /assistant/:sessionId route for deep-linking
- Session history: type filter pills (All/Guided/Chat), type icons
- Dashboard: both types shown with correct routing and icons
- Fixed glass-border → border-default in dashboard components
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
176 lines
5.5 KiB
TypeScript
176 lines
5.5 KiB
TypeScript
import apiClient from './client'
|
|
import type {
|
|
AISessionCreateRequest,
|
|
AISessionCreateResponse,
|
|
StepResponseRequest,
|
|
StepResponseResponse,
|
|
ResolveSessionRequest,
|
|
EscalateSessionRequest,
|
|
SessionCloseResponse,
|
|
SessionDocumentation,
|
|
AISessionSummary,
|
|
AISessionDetail,
|
|
AISessionSearchResult,
|
|
SimilarSession,
|
|
PickupSessionRequest,
|
|
StatusUpdateRequest,
|
|
StatusUpdateResponse,
|
|
ChatSessionCreateResponse,
|
|
ChatMessageRequest,
|
|
ChatMessageResponse,
|
|
} from '@/types/ai-session'
|
|
|
|
export const aiSessionsApi = {
|
|
async createSession(data: AISessionCreateRequest): Promise<AISessionCreateResponse> {
|
|
const response = await apiClient.post<AISessionCreateResponse>('/ai-sessions', data)
|
|
return response.data
|
|
},
|
|
|
|
async createChatSession(data: AISessionCreateRequest): Promise<ChatSessionCreateResponse> {
|
|
const response = await apiClient.post<ChatSessionCreateResponse>('/ai-sessions', {
|
|
...data,
|
|
session_type: 'chat',
|
|
})
|
|
return response.data
|
|
},
|
|
|
|
async sendChatMessage(sessionId: string, data: ChatMessageRequest): Promise<ChatMessageResponse> {
|
|
const response = await apiClient.post<ChatMessageResponse>(
|
|
`/ai-sessions/${sessionId}/chat`,
|
|
data
|
|
)
|
|
return response.data
|
|
},
|
|
|
|
async respondToStep(sessionId: string, data: StepResponseRequest): Promise<StepResponseResponse> {
|
|
const response = await apiClient.post<StepResponseResponse>(
|
|
`/ai-sessions/${sessionId}/respond`,
|
|
data
|
|
)
|
|
return response.data
|
|
},
|
|
|
|
async resolveSession(sessionId: string, data: ResolveSessionRequest): Promise<SessionCloseResponse> {
|
|
const response = await apiClient.post<SessionCloseResponse>(
|
|
`/ai-sessions/${sessionId}/resolve`,
|
|
data
|
|
)
|
|
return response.data
|
|
},
|
|
|
|
async escalateSession(sessionId: string, data: EscalateSessionRequest): Promise<SessionCloseResponse> {
|
|
const response = await apiClient.post<SessionCloseResponse>(
|
|
`/ai-sessions/${sessionId}/escalate`,
|
|
data
|
|
)
|
|
return response.data
|
|
},
|
|
|
|
async listSessions(params?: {
|
|
status?: string
|
|
session_type?: string
|
|
skip?: number
|
|
limit?: number
|
|
problem_domain?: string
|
|
matched_flow_id?: string
|
|
confidence_tier?: string
|
|
ticket_id?: string
|
|
date_from?: string
|
|
date_to?: string
|
|
q?: string
|
|
}): Promise<AISessionSummary[]> {
|
|
// Strip empty string values so they aren't sent as empty query params
|
|
const cleanParams = params
|
|
? Object.fromEntries(Object.entries(params).filter(([, v]) => v !== '' && v !== undefined))
|
|
: undefined
|
|
const response = await apiClient.get<AISessionSummary[]>('/ai-sessions', { params: cleanParams })
|
|
return response.data
|
|
},
|
|
|
|
async getSession(sessionId: string): Promise<AISessionDetail> {
|
|
const response = await apiClient.get<AISessionDetail>(`/ai-sessions/${sessionId}`)
|
|
return response.data
|
|
},
|
|
|
|
async getDocumentation(sessionId: string): Promise<SessionDocumentation> {
|
|
const response = await apiClient.get<SessionDocumentation>(
|
|
`/ai-sessions/${sessionId}/documentation`
|
|
)
|
|
return response.data
|
|
},
|
|
|
|
async rateSession(sessionId: string, data: { rating: number; feedback?: string }): Promise<void> {
|
|
await apiClient.post(`/ai-sessions/${sessionId}/rate`, data)
|
|
},
|
|
|
|
async retryPsaPush(sessionId: string): Promise<{ psa_push_status: string; psa_push_error: string | null }> {
|
|
const response = await apiClient.post<{ psa_push_status: string; psa_push_error: string | null }>(
|
|
`/ai-sessions/${sessionId}/retry-psa-push`
|
|
)
|
|
return response.data
|
|
},
|
|
|
|
async pauseSession(sessionId: string): Promise<void> {
|
|
await apiClient.post(`/ai-sessions/${sessionId}/pause`)
|
|
},
|
|
|
|
async resumeSession(sessionId: string): Promise<void> {
|
|
await apiClient.post(`/ai-sessions/${sessionId}/resume`)
|
|
},
|
|
|
|
async abandonSession(sessionId: string, reason?: string): Promise<void> {
|
|
await apiClient.post(`/ai-sessions/${sessionId}/abandon`, null, {
|
|
params: reason ? { reason } : undefined,
|
|
})
|
|
},
|
|
|
|
async deleteSession(sessionId: string): Promise<void> {
|
|
await apiClient.delete(`/ai-sessions/${sessionId}`)
|
|
},
|
|
|
|
async pickupSession(sessionId: string, data: PickupSessionRequest): Promise<StepResponseResponse> {
|
|
const response = await apiClient.post<StepResponseResponse>(
|
|
`/ai-sessions/${sessionId}/pickup`,
|
|
data
|
|
)
|
|
return response.data
|
|
},
|
|
|
|
async linkTicket(sessionId: string, data: { psa_ticket_id: string; psa_connection_id: string }): Promise<AISessionDetail> {
|
|
const response = await apiClient.post<AISessionDetail>(
|
|
`/ai-sessions/${sessionId}/link-ticket`,
|
|
data
|
|
)
|
|
return response.data
|
|
},
|
|
|
|
async getEscalationQueue(): Promise<AISessionSummary[]> {
|
|
const response = await apiClient.get<AISessionSummary[]>('/ai-sessions/escalation-queue')
|
|
return response.data
|
|
},
|
|
|
|
async search(q: string, limit: number = 5): Promise<AISessionSearchResult[]> {
|
|
const response = await apiClient.get<AISessionSearchResult[]>('/ai-sessions/search', {
|
|
params: { q, limit },
|
|
})
|
|
return response.data
|
|
},
|
|
|
|
async getSimilar(sessionId: string, limit: number = 5): Promise<SimilarSession[]> {
|
|
const response = await apiClient.get<SimilarSession[]>(`/ai-sessions/${sessionId}/similar`, {
|
|
params: { limit },
|
|
})
|
|
return response.data
|
|
},
|
|
|
|
async generateStatusUpdate(sessionId: string, data: StatusUpdateRequest): Promise<StatusUpdateResponse> {
|
|
const response = await apiClient.post<StatusUpdateResponse>(
|
|
`/ai-sessions/${sessionId}/status-update`,
|
|
data
|
|
)
|
|
return response.data
|
|
},
|
|
}
|
|
|
|
export default aiSessionsApi
|