|
2 | 2 | import { personaStore } from '../stores/persona.svelte'; |
3 | 3 | import { sceneStore } from '../stores/scene.svelte'; |
4 | 4 | import { chatStore } from '../stores/chat.svelte'; |
5 | | - import { getLatestConversationForPersona } from '../lib/conversation/store'; |
6 | | - import { getMemoriesForPersona } from '../lib/memory/store'; |
| 5 | + import { getLatestConversationForPersona, deleteConversationsForPersona } from '../lib/conversation/store'; |
| 6 | + import { getMemoriesForPersona, deleteMemoriesForPersona } from '../lib/memory/store'; |
7 | 7 | import { llmEngine } from '../lib/llm/engine.svelte'; |
8 | 8 | import { buildSystemPrompt } from '../lib/llm/prompts'; |
9 | 9 | import { summarizeAndStoreConversation } from '../lib/memory/episodic'; |
10 | 10 | import { saveConversation } from '../lib/conversation/store'; |
| 11 | + import { deletePersona } from '../lib/persona/store'; |
11 | 12 | import type { Persona } from '../lib/persona/schema'; |
12 | 13 |
|
13 | 14 | let isResuming = $state(false); |
14 | 15 |
|
| 16 | + async function removePersona(e: Event, persona: Persona) { |
| 17 | + e.stopPropagation(); |
| 18 | + if (!confirm(`Forget ${persona.identity.name}? This removes all conversations and memories.`)) return; |
| 19 | +
|
| 20 | + try { |
| 21 | + await deletePersona(persona.id); |
| 22 | + await deleteConversationsForPersona(persona.id); |
| 23 | + await deleteMemoriesForPersona(persona.id); |
| 24 | + personaStore.all = personaStore.all.filter(p => p.id !== persona.id); |
| 25 | + } catch { /* silent */ } |
| 26 | + } |
| 27 | +
|
15 | 28 | async function resumePersona(persona: Persona) { |
16 | 29 | if (isResuming) return; |
17 | 30 | isResuming = true; |
|
112 | 125 |
|
113 | 126 | <div class="flex-1 overflow-y-auto"> |
114 | 127 | {#each inactivePersonas as persona} |
115 | | - <button |
116 | | - onclick={() => resumePersona(persona)} |
117 | | - disabled={isResuming || chatStore.isGenerating} |
118 | | - class="w-full text-left px-3 py-3 hover:bg-gray-700/50 transition-colors border-b border-gray-800 disabled:opacity-50 cursor-pointer" |
119 | | - > |
120 | | - <p class="text-sm font-medium text-gray-200 truncate">{persona.identity.name}</p> |
121 | | - <p class="text-xs text-gray-500 truncate">{persona.background.profession}</p> |
122 | | - <p class="text-xs text-gray-600 truncate">📍 {persona.background.currentLocation}</p> |
123 | | - </button> |
| 128 | + <div class="flex items-center border-b border-gray-800 hover:bg-gray-700/50 transition-colors group"> |
| 129 | + <button |
| 130 | + onclick={() => resumePersona(persona)} |
| 131 | + disabled={isResuming || chatStore.isGenerating} |
| 132 | + class="flex-1 text-left px-3 py-3 disabled:opacity-50 cursor-pointer" |
| 133 | + > |
| 134 | + <p class="text-sm font-medium text-gray-200 truncate">{persona.identity.name}</p> |
| 135 | + <p class="text-xs text-gray-500 truncate">{persona.background.profession}</p> |
| 136 | + <p class="text-xs text-gray-600 truncate">📍 {persona.background.currentLocation}</p> |
| 137 | + </button> |
| 138 | + <button |
| 139 | + onclick={(e) => removePersona(e, persona)} |
| 140 | + class="px-2 py-1 text-gray-600 hover:text-red-400 opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer" |
| 141 | + title="Forget {persona.identity.name}" |
| 142 | + > |
| 143 | + ✕ |
| 144 | + </button> |
| 145 | + </div> |
124 | 146 | {/each} |
125 | 147 | </div> |
126 | 148 | </div> |
|
0 commit comments