Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ui/web/src/api/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export const Methods = {
SESSIONS_PATCH: "sessions.patch",
SESSIONS_DELETE: "sessions.delete",
SESSIONS_RESET: "sessions.reset",
SESSIONS_COMPACT: "sessions.compact",

// Phase 2 - NEEDED
SKILLS_LIST: "skills.list",
Expand Down
6 changes: 6 additions & 0 deletions ui/web/src/i18n/locales/en/sessions.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@
},
"detail": {
"reset": "Reset",
"compact": "Compact",
"delete": "Delete",
"deleteTitle": "Delete Session",
"deleteDescription": "This will permanently delete all messages in this session.",
"resetTitle": "Reset Session",
"resetDescription": "This will clear all messages but keep the session.",
"compactTitle": "Compact Session",
"compactDescription": "Truncate message history to the last 4 messages while keeping the summary. Unlike Reset, the summary is preserved so the agent retains context.",
"confirmDelete": "Delete",
"confirmReset": "Reset",
"confirmCompact": "Compact",
"noMessages": "No messages in this session",
"summary": "Summary",
"showMore": "Show more",
Expand All @@ -39,6 +43,8 @@
"deleteFailed": "Failed to delete session",
"reset": "Session reset",
"resetFailed": "Failed to reset session",
"compacted": "Session compacted",
"compactFailed": "Failed to compact session",
"updated": "Session updated",
"updateFailed": "Failed to update session"
}
Expand Down
6 changes: 6 additions & 0 deletions ui/web/src/i18n/locales/vi/sessions.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@
},
"detail": {
"reset": "Đặt lại",
"compact": "Nén",
"delete": "Xóa",
"deleteTitle": "Xóa session",
"deleteDescription": "Thao tác này sẽ xóa vĩnh viễn tất cả tin nhắn trong session này.",
"resetTitle": "Đặt lại phiên",
"resetDescription": "Thao tác này sẽ xóa tất cả tin nhắn nhưng giữ lại phiên.",
"compactTitle": "Nén phiên",
"compactDescription": "Cắt ngắn lịch sử tin nhắn xuống 4 tin gần nhất, giữ lại tóm tắt. Khác với Đặt lại - không xóa tóm tắt, agent vẫn nhớ ngữ cảnh.",
"confirmDelete": "Xóa",
"confirmReset": "Đặt lại",
"confirmCompact": "Nén",
"noMessages": "Không có tin nhắn trong session này",
"summary": "Tóm tắt",
"showMore": "Xem thêm",
Expand All @@ -39,6 +43,8 @@
"deleteFailed": "Không thể xóa session",
"reset": "Đã đặt lại session",
"resetFailed": "Không thể đặt lại session",
"compacted": "Đã nén session",
"compactFailed": "Không thể nén session",
"updated": "Đã cập nhật session",
"updateFailed": "Không thể cập nhật session"
}
Expand Down
6 changes: 6 additions & 0 deletions ui/web/src/i18n/locales/zh/sessions.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@
},
"detail": {
"reset": "重置",
"compact": "压缩",
"delete": "删除",
"deleteTitle": "删除Session",
"deleteDescription": "这将永久删除此Session中的所有消息。",
"resetTitle": "重置Session",
"resetDescription": "这将清除所有消息但保留Session。",
"compactTitle": "压缩Session",
"compactDescription": "将消息历史截断为最近 4 条消息,但保留摘要。与重置不同,摘要会保留,以便Agent保留上下文。",
"confirmDelete": "删除",
"confirmReset": "重置",
"confirmCompact": "压缩",
"noMessages": "此Session中没有消息",
"summary": "摘要",
"showMore": "显示更多",
Expand All @@ -39,6 +43,8 @@
"deleteFailed": "删除Session失败",
"reset": "Session已重置",
"resetFailed": "重置Session失败",
"compacted": "Session已压缩",
"compactFailed": "压缩Session失败",
"updated": "Session已更新",
"updateFailed": "更新Session失败"
}
Expand Down
17 changes: 16 additions & 1 deletion ui/web/src/pages/sessions/hooks/use-sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,21 @@ export function useSessions(opts: UseSessionsOptions = {}) {
[ws, invalidate],
);

const compactSession = useCallback(
async (key: string, keepLast?: number) => {
if (!ws.isConnected) return;
try {
await ws.call(Methods.SESSIONS_COMPACT, { key, keepLast });
await invalidate();
toast.success(i18next.t("sessions:toast.compacted"));
} catch (err) {
toast.error(i18next.t("sessions:toast.compactFailed"), userFriendlyError(err));
throw err;
}
},
[ws, invalidate],
);

const patchSession = useCallback(
async (key: string, updates: { label?: string; model?: string; metadata?: Record<string, string> }) => {
if (!ws.isConnected) return;
Expand All @@ -104,5 +119,5 @@ export function useSessions(opts: UseSessionsOptions = {}) {
[ws, invalidate],
);

return { sessions, total, loading, refresh: invalidate, preview, deleteSession, resetSession, patchSession };
return { sessions, total, loading, refresh: invalidate, preview, deleteSession, resetSession, compactSession, patchSession };
}
27 changes: 26 additions & 1 deletion ui/web/src/pages/sessions/session-detail-page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useEffect, useCallback } from "react";
import { useTranslation } from "react-i18next";
import { ArrowLeft, Trash2, RotateCcw, Eye, Pencil, Check, X } from "lucide-react";
import { ArrowLeft, Trash2, RotateCcw, Shrink, Eye, Pencil, Check, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { MessageBubble } from "@/components/chat/message-bubble";
Expand Down Expand Up @@ -40,6 +40,7 @@ interface SessionDetailPageProps {
onPreview: (key: string) => Promise<SessionPreview | null>;
onDelete: (key: string) => Promise<void>;
onReset: (key: string) => Promise<void>;
onCompact?: (key: string, keepLast?: number) => Promise<void>;
onPatch?: (key: string, updates: { label?: string }) => Promise<void>;
}

Expand All @@ -49,6 +50,7 @@ export function SessionDetailPage({
onPreview,
onDelete,
onReset,
onCompact,
onPatch,
}: SessionDetailPageProps) {
const { t } = useTranslation("sessions");
Expand All @@ -57,6 +59,7 @@ export function SessionDetailPage({
const [loading, setLoading] = useState(true);
const [confirmDelete, setConfirmDelete] = useState(false);
const [confirmReset, setConfirmReset] = useState(false);
const [confirmCompact, setConfirmCompact] = useState(false);
const [editingTitle, setEditingTitle] = useState(false);
const [titleDraft, setTitleDraft] = useState("");

Expand Down Expand Up @@ -206,6 +209,11 @@ export function SessionDetailPage({
</div>
</div>
<div className="flex gap-2">
{onCompact && (
<Button variant="outline" size="sm" onClick={() => setConfirmCompact(true)} className="gap-1">
<Shrink className="h-3.5 w-3.5" /> {t("detail.compact")}
</Button>
)}
<Button variant="outline" size="sm" onClick={() => setConfirmReset(true)} className="gap-1">
<RotateCcw className="h-3.5 w-3.5" /> {t("detail.reset")}
</Button>
Expand Down Expand Up @@ -268,6 +276,23 @@ export function SessionDetailPage({
setMessages([]);
}}
/>

{onCompact && (
<ConfirmDialog
open={confirmCompact}
onOpenChange={setConfirmCompact}
title={t("detail.compactTitle")}
description={t("detail.compactDescription")}
confirmLabel={t("detail.confirmCompact")}
onConfirm={async () => {
await onCompact(session.key);
setConfirmCompact(false);
// Reload preview to reflect truncated history.
const p = await onPreview(session.key);
if (p) setMessages(p.messages);
}}
/>
)}
</div>
);
}
Expand Down
3 changes: 2 additions & 1 deletion ui/web/src/pages/sessions/sessions-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function SessionsPage() {
const [pageSize, setPageSizeRaw] = useState(globalPageSize);
const setPageSize = (size: number) => { setPageSizeRaw(size); setPage(1); setGlobalPageSize(size); };

const { sessions, total, loading, preview, deleteSession, resetSession, patchSession } = useSessions({
const { sessions, total, loading, preview, deleteSession, resetSession, compactSession, patchSession } = useSessions({
limit: pageSize,
offset: (page - 1) * pageSize,
});
Expand All @@ -50,6 +50,7 @@ export function SessionsPage() {
navigate("/sessions");
}}
onReset={resetSession}
onCompact={compactSession}
onPatch={patchSession}
/>
);
Expand Down
Loading