diff --git a/.remember/tmp/save-session.pid b/.remember/tmp/save-session.pid index 937c971..9bc105c 100644 --- a/.remember/tmp/save-session.pid +++ b/.remember/tmp/save-session.pid @@ -1 +1 @@ -2298268 +3158517 diff --git a/fable-mcp/uv.lock b/fable-mcp/uv.lock index 3b2a4f9..046e9b5 100644 --- a/fable-mcp/uv.lock +++ b/fable-mcp/uv.lock @@ -184,7 +184,7 @@ wheels = [ [[package]] name = "fable-mcp" -version = "0.2.6" +version = "0.3.0" source = { editable = "." } dependencies = [ { name = "httpx" }, diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index f6e0819..980cc66 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -317,6 +317,7 @@ export interface JournalConfig { day_rollover_hour: number; morning_end_hour?: number; midday_end_hour?: number; + closeout_enabled?: boolean; // Ambient-context fields (carried forward from the briefing config schema) locations?: { home?: JournalLocation; work?: JournalLocation }; temp_unit?: 'C' | 'F'; @@ -696,3 +697,11 @@ export const updateProfile = (data: Partial) => export const consolidateProfile = () => apiPost<{ status: string; learned_summary: string }>('/api/profile/consolidate', {}) export const clearProfileObservations = () => apiDelete('/api/profile/observations') + +export interface ProfileObservationEntry { + date: string + bullets: string +} + +export const listProfileObservations = () => + apiGet<{ observations: ProfileObservationEntry[] }>('/api/profile/observations') diff --git a/frontend/src/views/SettingsView.vue b/frontend/src/views/SettingsView.vue index 084ee11..1fd2d78 100644 --- a/frontend/src/views/SettingsView.vue +++ b/frontend/src/views/SettingsView.vue @@ -4,7 +4,7 @@ import { ref, computed, watch, onMounted } from "vue"; import { useSettingsStore } from "@/stores/settings"; import { useAuthStore } from "@/stores/auth"; import { useToastStore } from "@/stores/toast"; -import { apiGet, apiPost, apiPut, apiDelete, listGroups, createGroup, deleteGroup, listGroupMembers, addGroupMember, removeGroupMember, searchUsers, getFableMcpInfo, listApiKeys, createApiKey as apiCreateApiKey, revokeApiKey as apiRevokeApiKey, getVoiceStatus, getVoiceList, synthesiseSpeech, getProfile, updateProfile, consolidateProfile, clearProfileObservations, getJournalConfig, saveJournalConfig, geocodeAddress, type ApiKeyEntry, type GroupEntry, type GroupMember, type UserSearchResult, type VoiceStatusResult, type VoiceEntry, type VoiceBlendEntry, type UserProfile, type JournalConfig } from "@/api/client"; +import { apiGet, apiPost, apiPut, apiDelete, listGroups, createGroup, deleteGroup, listGroupMembers, addGroupMember, removeGroupMember, searchUsers, getFableMcpInfo, listApiKeys, createApiKey as apiCreateApiKey, revokeApiKey as apiRevokeApiKey, getVoiceStatus, getVoiceList, synthesiseSpeech, getProfile, updateProfile, consolidateProfile, clearProfileObservations, listProfileObservations, getJournalConfig, saveJournalConfig, geocodeAddress, type ApiKeyEntry, type GroupEntry, type GroupMember, type UserSearchResult, type VoiceStatusResult, type VoiceEntry, type VoiceBlendEntry, type UserProfile, type JournalConfig, type ProfileObservationEntry } from "@/api/client"; import { usePushStore } from "@/stores/push"; import type { User } from "@/types/auth"; import PaginationBar from "@/components/PaginationBar.vue"; @@ -549,6 +549,26 @@ const profileSaving = ref(false) const profileSaved = ref(false) const consolidating = ref(false) const clearingObs = ref(false) +const observations = ref([]) +const observationsExpanded = ref(false) +const observationsLoading = ref(false) +const observationsLoaded = ref(false) + +async function toggleObservations() { + observationsExpanded.value = !observationsExpanded.value + if (observationsExpanded.value && !observationsLoaded.value) { + observationsLoading.value = true + try { + const res = await listProfileObservations() + observations.value = res.observations + observationsLoaded.value = true + } catch { + toastStore.show('Failed to load observations', 'error') + } finally { + observationsLoading.value = false + } + } +} async function loadProfile() { try { profile.value = await getProfile() } catch { /* non-critical */ } @@ -582,6 +602,17 @@ function toggleProfileWorkDay(day: string) { profile.value.work_schedule = { ...profile.value.work_schedule, days } } +async function onToggleCloseout(enabled: boolean) { + journalConfig.value.closeout_enabled = enabled + try { + await saveJournalConfig(journalConfig.value) + toastStore.show(enabled ? 'Nightly closeout enabled' : 'Nightly closeout disabled') + } catch { + journalConfig.value.closeout_enabled = !enabled // revert UI on failure + toastStore.show('Failed to update closeout setting', 'error') + } +} + async function runConsolidate() { consolidating.value = true try { @@ -600,6 +631,7 @@ const journalConfig = ref({ prep_hour: 5, prep_minute: 0, day_rollover_hour: 4, + closeout_enabled: true, locations: { home: { label: 'Home', address: '' }, work: { label: 'Work', address: '' } }, temp_unit: 'C', }) @@ -620,6 +652,7 @@ async function loadJournalConfig() { prep_hour: cfg.prep_hour ?? 5, prep_minute: cfg.prep_minute ?? 0, day_rollover_hour: cfg.day_rollover_hour ?? 4, + closeout_enabled: cfg.closeout_enabled ?? true, morning_end_hour: cfg.morning_end_hour, midday_end_hour: cfg.midday_end_hour, locations: { @@ -689,6 +722,8 @@ async function clearObservations() { profile.value.learned_summary = '' profile.value.observations_count = 0 profile.value.observations_updated_at = null + observations.value = [] + observationsLoaded.value = false toastStore.show('Learned data cleared') } catch { toastStore.show('Failed to clear observations', 'error') } finally { clearingObs.value = false } @@ -1901,8 +1936,38 @@ function formatUserDate(iso: string): string { The assistant observes patterns from your journal and chat conversations and builds a summary over time. The summary is included in the journal's system prompt so the daily prep can reference what it knows about you. {{ profile.observations_count }} raw observation{{ profile.observations_count !== 1 ? 's' : '' }} stored.

+ + +
{{ profile.learned_summary }}
No learned summary yet. Observations accumulate from journal and chat conversations.
+ +
+ +
+
Loading…
+
No observations yet.
+
+
+
{{ entry.date }}
+
{{ entry.bullets }}
+
+
+
+
+