import React, { useState, useCallback } from 'react'; import { recall, type RecallResultItem } from '../api/client'; const SCOPE_OPTIONS = [ { value: '', label: 'All' }, { value: 'event', label: 'Events' }, { value: 'session', label: 'Sessions' }, { value: 'memory', label: 'Memories' }, ]; function formatTimestamp(ts?: string): string { if (!ts) return ''; try { return new Date(ts).toLocaleString(); } catch { return ts; } } function sourceTypeBadge(type: string): string { switch (type) { case 'event': return 'bg-blue-100 text-blue-700'; case 'session': return 'bg-green-100 text-green-700'; case 'memory': return 'bg-purple-100 text-purple-700'; default: return 'bg-gray-100 text-gray-700'; } } export function Search(): React.ReactElement { const [query, setQuery] = useState(''); const [scope, setScope] = useState(''); const [from, setFrom] = useState(''); const [to, setTo] = useState(''); const [results, setResults] = useState([]); const [totalResults, setTotalResults] = useState(0); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [searched, setSearched] = useState(false); const handleSearch = useCallback( async (e?: React.FormEvent) => { e?.preventDefault(); if (!query.trim()) return; setLoading(true); setError(null); setSearched(true); try { const result = await recall({ query: query.trim(), scope: scope || undefined, from: from || undefined, to: to || undefined, limit: 20, }); setResults(result.results); setTotalResults(result.totalResults); } catch (err) { setError(err instanceof Error ? err.message : 'Search failed'); setResults([]); setTotalResults(0); } finally { setLoading(false); } }, [query, scope, from, to], ); return (

Semantic Search

setQuery(e.target.value)} />
setFrom(e.target.value)} placeholder="From" /> setTo(e.target.value)} placeholder="To" />
{error && (
{error}
)} {searched && !loading && (
{totalResults} result{totalResults !== 1 ? 's' : ''} found
)}
{results.map((item, idx) => (
{item.sourceType} {item.sourceId}
{typeof item.metadata?.timestamp === 'string' && ( {formatTimestamp(item.metadata.timestamp)} )}

{item.text}

Score:
{(item.score * 100).toFixed(1)}%
))}
{searched && !loading && results.length === 0 && !error && (
🔍

No results found. Try a different query.

)}
); }