"use client"; import { useState } from "react"; import { client } from "@/lib/api"; import { useBank } from "@/lib/bank-context"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Checkbox } from "@/components/ui/checkbox"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Sparkles, Info, Tag, Clock, Database, Brain, MessageSquare, Shield, X, Check, Play, } from "lucide-react"; import { Textarea } from "@/components/ui/textarea"; import JsonView from "react18-json-view"; import "react18-json-view/src/style.css"; import { MemoryDetailModal } from "./memory-detail-modal"; import { MentalModelDetailModal } from "./mental-model-detail-modal"; type TagsMatch = "any" | "all" | "any_strict" | "all_strict"; type ViewMode = "answer" | "trace" | "json"; type BasedOnTab = "directives" | "mental_models" | "observations" | "world" | "experience"; export function ThinkView() { const { currentBank } = useBank(); const [query, setQuery] = useState(""); const [budget, setBudget] = useState<"low" | "mid" | "high">("mid"); const [maxTokens, setMaxTokens] = useState(4096); const [includeFacts, setIncludeFacts] = useState(true); const [includeToolCalls, setIncludeToolCalls] = useState(true); const [viewMode, setViewMode] = useState("answer"); const [result, setResult] = useState(null); const [loading, setLoading] = useState(false); const [tags, setTags] = useState(""); const [tagsMatch, setTagsMatch] = useState("any"); const [feedback, setFeedback] = useState(""); const [feedbackSubmitting, setFeedbackSubmitting] = useState(false); const [feedbackSubmitted, setFeedbackSubmitted] = useState(false); const [selectedMemoryId, setSelectedMemoryId] = useState(null); const [selectedDirective, setSelectedDirective] = useState(null); const [fullDirective, setFullDirective] = useState(null); const [loadingDirective, setLoadingDirective] = useState(false); const [selectedObservation, setSelectedObservation] = useState(null); const [fullObservation, setFullObservation] = useState(null); const [loadingObservation, setLoadingObservation] = useState(false); const [selectedMentalModelId, setSelectedMentalModelId] = useState(null); const [activeBasedOnTab, setActiveBasedOnTab] = useState("world"); const FEEDBACK_DIRECTIVE_NAME = "General Feedback"; // Load full directive data when one is selected const handleSelectDirective = async (directive: any) => { setSelectedDirective(directive); setFullDirective(null); if (!currentBank || !directive?.id) return; setLoadingDirective(true); try { const directives = await client.listDirectives(currentBank); const fullDir = directives.items?.find((d: any) => d.id === directive.id); setFullDirective(fullDir || directive); } catch (error) { console.error("Failed to load directive:", error); setFullDirective(directive); // Fall back to partial data } finally { setLoadingDirective(false); } }; // Load full observation data when one is selected const handleSelectObservation = async (observation: any) => { setSelectedObservation(observation); setFullObservation(null); if (!currentBank || !observation?.id) return; setLoadingObservation(true); try { const observations = await client.listObservations(currentBank); const fullObs = observations.items?.find((o: any) => o.id === observation.id); setFullObservation(fullObs || observation); } catch (error) { console.error("Failed to load observation:", error); setFullObservation(observation); // Fall back to partial data } finally { setLoadingObservation(false); } }; const submitFeedback = async () => { if (!currentBank || !feedback.trim()) return; setFeedbackSubmitting(true); try { // Find existing "General Feedback" directive const directives = await client.listDirectives(currentBank); const existingDirective = directives.items?.find((d) => d.name === FEEDBACK_DIRECTIVE_NAME); if (existingDirective) { // Append to existing directive content const newContent = existingDirective.content ? `${existingDirective.content}\n${feedback.trim()}` : feedback.trim(); await client.updateDirective(currentBank, existingDirective.id, { content: newContent, }); } else { // Create new directive await client.createDirective(currentBank, { name: FEEDBACK_DIRECTIVE_NAME, content: feedback.trim(), }); } setFeedback(""); setFeedbackSubmitted(true); setTimeout(() => setFeedbackSubmitted(false), 3000); } catch (error) { console.error("Error submitting feedback:", error); alert("Error submitting feedback: " + (error as Error).message); } finally { setFeedbackSubmitting(false); } }; const runReflect = async () => { if (!currentBank || !query) return; setLoading(true); setViewMode("answer"); try { // Parse tags from comma-separated string const parsedTags = tags .split(",") .map((t) => t.trim()) .filter((t) => t.length > 0); const data: any = await client.reflect({ bank_id: currentBank, query, budget, max_tokens: maxTokens, include_facts: includeFacts, include_tool_calls: includeToolCalls, ...(parsedTags.length > 0 && { tags: parsedTags, tags_match: tagsMatch }), }); setResult(data); } catch (error) { console.error("Error running reflect:", error); alert("Error running reflect: " + (error as Error).message); } finally { setLoading(false); } }; if (!currentBank) { return (

No Bank Selected

Select a memory bank to start reflecting.

); } return (
{/* Query Input */}
setQuery(e.target.value)} placeholder="What would you like to reflect on?" className="pl-10 h-12 text-lg" onKeyDown={(e) => e.key === "Enter" && runReflect()} />
{/* Filters */}
{/* Budget */}
Budget:
{/* Max Tokens */}
Tokens: setMaxTokens(parseInt(e.target.value) || 4096)} className="w-24 h-8" />
{/* Include options */}
{/* Tags Filter */}
setTags(e.target.value)} placeholder="Filter by tags (comma-separated)" className="h-8" />
{/* Loading State */} {loading && (

Reflecting on memories...

)} {/* Results */} {!loading && result && (
{/* Summary Stats & Tabs */}
{result.usage && ( <>
Input tokens: {result.usage.input_tokens?.toLocaleString()}
Output tokens: {result.usage.output_tokens?.toLocaleString()}
)} {result.trace?.tool_calls && (
Tool calls: {result.trace.tool_calls.length} ( {result.trace.tool_calls.reduce( (sum: number, tc: any) => sum + tc.duration_ms, 0 )} ms)
)} {result.trace?.llm_calls && (
LLM calls: {result.trace.llm_calls.length} ( {result.trace.llm_calls.reduce((sum: number, lc: any) => sum + lc.duration_ms, 0)} ms)
)}
{/* View Mode Tabs */}
{(["answer", "trace", "json"] as ViewMode[]).map((mode) => ( ))}
{/* Answer View */} {viewMode === "answer" && (
{/* Main Answer */} Answer
{result.text}
{/* New Opinions Formed */} {result.new_opinions && result.new_opinions.length > 0 && ( New Opinions Formed New beliefs generated from this interaction
{result.new_opinions.map((opinion: any, i: number) => (
{opinion.text}
Confidence: {opinion.confidence?.toFixed(2)}
))}
)} {/* Directive */} Add Directive Hard rules injected into prompts that the agent must follow {feedbackSubmitted ? (
Directive saved to {FEEDBACK_DIRECTIVE_NAME}
) : (