summaryrefslogtreecommitdiffhomepage
path: root/src/features/chat/ui/CompactionView.svelte
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/chat/ui/CompactionView.svelte')
-rw-r--r--src/features/chat/ui/CompactionView.svelte278
1 files changed, 139 insertions, 139 deletions
diff --git a/src/features/chat/ui/CompactionView.svelte b/src/features/chat/ui/CompactionView.svelte
index 7bec984..5014e5c 100644
--- a/src/features/chat/ui/CompactionView.svelte
+++ b/src/features/chat/ui/CompactionView.svelte
@@ -1,154 +1,154 @@
<script lang="ts">
- export type CompactNowResult =
- | { readonly ok: true; readonly messagesSummarized: number; readonly messagesKept: number }
- | { readonly ok: false; readonly error: string };
+ export type CompactNowResult =
+ | { readonly ok: true; readonly messagesSummarized: number; readonly messagesKept: number }
+ | { readonly ok: false; readonly error: string };
- export type SaveCompactPercentResult =
- | { readonly ok: true; readonly percent: number }
- | { readonly ok: false; readonly error: string };
+ export type SaveCompactPercentResult =
+ | { readonly ok: true; readonly percent: number }
+ | { readonly ok: false; readonly error: string };
- let {
- percent,
- canCompact,
- compactNow,
- savePercent,
- }: {
- /** The conversation's auto-compact percent (0-100), or null when not yet fetched. 0 = disabled. */
- percent: number | null;
- /** Whether a real conversation is focused (a draft has nothing to compact). */
- canCompact: boolean;
- compactNow: () => Promise<CompactNowResult | null>;
- savePercent: (percent: number) => Promise<SaveCompactPercentResult | null>;
- } = $props();
+ let {
+ percent,
+ canCompact,
+ compactNow,
+ savePercent,
+ }: {
+ /** The conversation's auto-compact percent (0-100), or null when not yet fetched. 0 = disabled. */
+ percent: number | null;
+ /** Whether a real conversation is focused (a draft has nothing to compact). */
+ canCompact: boolean;
+ compactNow: () => Promise<CompactNowResult | null>;
+ savePercent: (percent: number) => Promise<SaveCompactPercentResult | null>;
+ } = $props();
- const DEFAULT_PERCENT = 85;
+ const DEFAULT_PERCENT = 85;
- let compacting = $state(false);
- let compactError = $state<string | null>(null);
- let compactResult = $state<{ summarized: number; kept: number } | null>(null);
+ let compacting = $state(false);
+ let compactError = $state<string | null>(null);
+ let compactResult = $state<{ summarized: number; kept: number } | null>(null);
- let percentInput = $state("");
- let savingPercent = $state(false);
- let percentError = $state<string | null>(null);
- let percentSaved = $state(false);
+ let percentInput = $state("");
+ let savingPercent = $state(false);
+ let percentError = $state<string | null>(null);
+ let percentSaved = $state(false);
- // Sync the input from the prop when it changes (focus switch / initial load).
- let lastPercent = $state<number | null>(null);
- $effect(() => {
- if (percent !== lastPercent) {
- lastPercent = percent;
- percentInput = percent !== null ? String(percent) : "";
- percentError = null;
- percentSaved = false;
- }
- });
+ // Sync the input from the prop when it changes (focus switch / initial load).
+ let lastPercent = $state<number | null>(null);
+ $effect(() => {
+ if (percent !== lastPercent) {
+ lastPercent = percent;
+ percentInput = percent !== null ? String(percent) : "";
+ percentError = null;
+ percentSaved = false;
+ }
+ });
- const percentLabel = $derived(
- percent == null
- ? "Loading…"
- : percent === 0
- ? "Disabled (manual only)"
- : percent === DEFAULT_PERCENT
- ? `${percent}% (default)`
- : `${percent}%`,
- );
+ const percentLabel = $derived(
+ percent == null
+ ? "Loading…"
+ : percent === 0
+ ? "Disabled (manual only)"
+ : percent === DEFAULT_PERCENT
+ ? `${percent}% (default)`
+ : `${percent}%`,
+ );
- async function handleCompact() {
- if (compacting || !canCompact) return;
- compacting = true;
- compactError = null;
- compactResult = null;
- const result = await compactNow();
- compacting = false;
- if (result === null) return;
- if (result.ok) {
- compactResult = { summarized: result.messagesSummarized, kept: result.messagesKept };
- } else {
- compactError = result.error;
- }
- }
+ async function handleCompact() {
+ if (compacting || !canCompact) return;
+ compacting = true;
+ compactError = null;
+ compactResult = null;
+ const result = await compactNow();
+ compacting = false;
+ if (result === null) return;
+ if (result.ok) {
+ compactResult = { summarized: result.messagesSummarized, kept: result.messagesKept };
+ } else {
+ compactError = result.error;
+ }
+ }
- async function handleSavePercent() {
- const value = Number.parseInt(percentInput, 10);
- if (Number.isNaN(value) || value < 0 || value > 100) {
- percentError = "Must be 0-100";
- return;
- }
- savingPercent = true;
- percentError = null;
- percentSaved = false;
- const result = await savePercent(value);
- savingPercent = false;
- if (result === null) return;
- if (result.ok) {
- percentSaved = true;
- } else {
- percentError = result.error;
- }
- }
+ async function handleSavePercent() {
+ const value = Number.parseInt(percentInput, 10);
+ if (Number.isNaN(value) || value < 0 || value > 100) {
+ percentError = "Must be 0-100";
+ return;
+ }
+ savingPercent = true;
+ percentError = null;
+ percentSaved = false;
+ const result = await savePercent(value);
+ savingPercent = false;
+ if (result === null) return;
+ if (result.ok) {
+ percentSaved = true;
+ } else {
+ percentError = result.error;
+ }
+ }
</script>
<div class="flex flex-col gap-3">
- <!-- Manual compaction -->
- <section class="flex flex-col gap-1">
- <span class="text-xs font-semibold uppercase opacity-60">Manual compaction</span>
- <button
- type="button"
- class="btn btn-sm btn-outline"
- disabled={!canCompact || compacting}
- onclick={handleCompact}
- >
- {#if compacting}
- <span class="loading loading-spinner loading-xs"></span>
- Compacting…
- {:else}
- Compact now
- {/if}
- </button>
- {#if !canCompact}
- <p class="text-xs opacity-60">Open or start a conversation to compact its history.</p>
- {:else if compactError}
- <p class="text-xs text-error">{compactError}</p>
- {:else if compactResult}
- <p class="text-xs text-success">
- Compacted — {compactResult.summarized} messages summarized, {compactResult.kept} kept.
- </p>
- {:else}
- <p class="text-xs opacity-50">
- Summarizes old messages into a system summary + retains the most recent messages.
- </p>
- {/if}
- </section>
+ <!-- Manual compaction -->
+ <section class="flex flex-col gap-1">
+ <span class="text-xs font-semibold uppercase opacity-60">Manual compaction</span>
+ <button
+ type="button"
+ class="btn btn-sm btn-outline"
+ disabled={!canCompact || compacting}
+ onclick={handleCompact}
+ >
+ {#if compacting}
+ <span class="loading loading-spinner loading-xs"></span>
+ Compacting…
+ {:else}
+ Compact now
+ {/if}
+ </button>
+ {#if !canCompact}
+ <p class="text-xs opacity-60">Open or start a conversation to compact its history.</p>
+ {:else if compactError}
+ <p class="text-xs text-error">{compactError}</p>
+ {:else if compactResult}
+ <p class="text-xs text-success">
+ Compacted — {compactResult.summarized} messages summarized, {compactResult.kept} kept.
+ </p>
+ {:else}
+ <p class="text-xs opacity-50">
+ Summarizes old messages into a system summary + retains the most recent messages.
+ </p>
+ {/if}
+ </section>
- <!-- Auto-compact percent -->
- <section class="flex flex-col gap-1">
- <span class="text-xs font-semibold uppercase opacity-60">Auto-compact percent</span>
- <div class="flex items-center gap-2">
- <input
- type="number"
- class="input input-bordered input-sm w-24"
- min="0"
- max="100"
- placeholder={String(DEFAULT_PERCENT)}
- value={percentInput}
- disabled={savingPercent}
- onchange={handleSavePercent}
- aria-label="Compact percent (0-100)"
- />
- <span class="text-xs opacity-60">%</span>
- {#if savingPercent}
- <span class="loading loading-spinner loading-xs"></span>
- {/if}
- </div>
- <p class="text-xs opacity-50">
- Current: {percentLabel}
- <br />
- 0 disables auto-compact. Default is {DEFAULT_PERCENT}%.
- </p>
- {#if percentError}
- <p class="text-xs text-error">{percentError}</p>
- {:else if percentSaved}
- <p class="text-xs text-success">Saved.</p>
- {/if}
- </section>
+ <!-- Auto-compact percent -->
+ <section class="flex flex-col gap-1">
+ <span class="text-xs font-semibold uppercase opacity-60">Auto-compact percent</span>
+ <div class="flex items-center gap-2">
+ <input
+ type="number"
+ class="input input-bordered input-sm w-24"
+ min="0"
+ max="100"
+ placeholder={String(DEFAULT_PERCENT)}
+ value={percentInput}
+ disabled={savingPercent}
+ onchange={handleSavePercent}
+ aria-label="Compact percent (0-100)"
+ />
+ <span class="text-xs opacity-60">%</span>
+ {#if savingPercent}
+ <span class="loading loading-spinner loading-xs"></span>
+ {/if}
+ </div>
+ <p class="text-xs opacity-50">
+ Current: {percentLabel}
+ <br />
+ 0 disables auto-compact. Default is {DEFAULT_PERCENT}%.
+ </p>
+ {#if percentError}
+ <p class="text-xs text-error">{percentError}</p>
+ {:else if percentSaved}
+ <p class="text-xs text-success">Saved.</p>
+ {/if}
+ </section>
</div>