feat: unified sessions — merge assistant chat into ai_sessions table
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>
This commit is contained in:
@@ -27,6 +27,7 @@ export function SessionHistoryPage() {
|
||||
const aiSearchTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)
|
||||
const [aiFilters, setAiFilters] = useState({
|
||||
q: '',
|
||||
session_type: '',
|
||||
problem_domain: '',
|
||||
confidence_tier: '',
|
||||
date_from: '',
|
||||
@@ -176,6 +177,7 @@ export function SessionHistoryPage() {
|
||||
const data = await aiSessionsApi.listSessions({
|
||||
limit: 50,
|
||||
q: aiFilters.q || undefined,
|
||||
session_type: aiFilters.session_type || undefined,
|
||||
problem_domain: aiFilters.problem_domain || undefined,
|
||||
confidence_tier: aiFilters.confidence_tier || undefined,
|
||||
date_from: aiFilters.date_from || undefined,
|
||||
@@ -267,7 +269,7 @@ export function SessionHistoryPage() {
|
||||
return labels[outcome] ?? outcome
|
||||
}
|
||||
|
||||
const hasAiFiltersActive = !!(aiSearchInput || aiFilters.q || aiFilters.problem_domain || aiFilters.confidence_tier || aiFilters.date_from || aiFilters.date_to)
|
||||
const hasAiFiltersActive = !!(aiSearchInput || aiFilters.q || aiFilters.session_type || aiFilters.problem_domain || aiFilters.confidence_tier || aiFilters.date_from || aiFilters.date_to)
|
||||
const hasFlowFiltersActive = !!(filters.ticketNumber || filters.clientName || filters.treeName || filters.dateRange?.from)
|
||||
|
||||
// Determine section visibility
|
||||
@@ -314,7 +316,7 @@ export function SessionHistoryPage() {
|
||||
{/* FlowPilot Sessions Section */}
|
||||
{showAiSection && (
|
||||
<>
|
||||
<h2 className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground mb-3">FlowPilot Sessions</h2>
|
||||
<h2 className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground mb-3">AI Sessions</h2>
|
||||
|
||||
{/* AI Session Filter Bar */}
|
||||
<div className="card-flat p-3 mb-4">
|
||||
@@ -331,6 +333,24 @@ export function SessionHistoryPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Session type pills */}
|
||||
<div className="flex gap-1">
|
||||
{(['', 'guided', 'chat'] as const).map((t) => (
|
||||
<button
|
||||
key={t}
|
||||
onClick={() => setAiFilters((f) => ({ ...f, session_type: t }))}
|
||||
className={cn(
|
||||
'rounded-full border px-3 py-1 text-xs font-sans transition-colors',
|
||||
aiFilters.session_type === t
|
||||
? 'bg-accent-dim text-foreground border-primary/30'
|
||||
: 'bg-card text-muted-foreground border-border hover:text-foreground hover:border-[rgba(255,255,255,0.12)]'
|
||||
)}
|
||||
>
|
||||
{t === '' ? 'All' : t === 'guided' ? 'Guided' : 'Chat'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Problem domain dropdown */}
|
||||
<select
|
||||
value={aiFilters.problem_domain}
|
||||
@@ -393,7 +413,7 @@ export function SessionHistoryPage() {
|
||||
<button
|
||||
onClick={() => {
|
||||
setAiSearchInput('')
|
||||
setAiFilters({ q: '', problem_domain: '', confidence_tier: '', date_from: '', date_to: '' })
|
||||
setAiFilters({ q: '', session_type: '', problem_domain: '', confidence_tier: '', date_from: '', date_to: '' })
|
||||
}}
|
||||
className="text-xs text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
@@ -415,7 +435,7 @@ export function SessionHistoryPage() {
|
||||
<button
|
||||
onClick={() => {
|
||||
setAiSearchInput('')
|
||||
setAiFilters({ q: '', problem_domain: '', confidence_tier: '', date_from: '', date_to: '' })
|
||||
setAiFilters({ q: '', session_type: '', problem_domain: '', confidence_tier: '', date_from: '', date_to: '' })
|
||||
}}
|
||||
className="text-foreground hover:underline text-sm"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user