feat(session-history): Add delete button and show sessions for all agents

- Add deleteSession method to useSessionHistory hook
- Add Delete button to all session items (always visible)
- Change early return for restoration non-supporting agents to warning banner
- Show locally saved sessions for all agents (for deletion)
- Add warning banner and delete button styles
This commit is contained in:
RAIT-09 2026-01-09 00:19:41 +09:00
parent a9f412113a
commit 89aef910c7
4 changed files with 125 additions and 19 deletions

View file

@ -381,6 +381,16 @@ function ChatComponent({
logger.error("Session fork error:", error);
}
},
onDeleteSession: async (sessionId: string) => {
try {
logger.log(`[ChatView] Deleting session: ${sessionId}`);
await sessionHistory.deleteSession(sessionId);
new Notice("[Agent Client] Session deleted");
} catch (error) {
new Notice("[Agent Client] Failed to delete session");
logger.error("Session delete error:", error);
}
},
onLoadMore: () => {
void sessionHistory.loadMoreSessions();
},
@ -452,6 +462,16 @@ function ChatComponent({
logger.error("Session fork error:", error);
}
},
onDeleteSession: async (sessionId: string) => {
try {
logger.log(`[ChatView] Deleting session: ${sessionId}`);
await sessionHistory.deleteSession(sessionId);
new Notice("[Agent Client] Session deleted");
} catch (error) {
new Notice("[Agent Client] Failed to delete session");
logger.error("Session delete error:", error);
}
},
onLoadMore: () => {
void sessionHistory.loadMoreSessions();
},

View file

@ -43,6 +43,8 @@ export interface SessionHistoryContentProps {
onResumeSession: (sessionId: string, cwd: string) => Promise<void>;
/** Callback when a session is forked (create new branch) */
onForkSession: (sessionId: string, cwd: string) => Promise<void>;
/** Callback when a session is deleted */
onDeleteSession: (sessionId: string) => Promise<void>;
/** Callback to load more sessions (pagination) */
onLoadMore: () => void;
/** Callback to fetch sessions with filter */
@ -229,6 +231,7 @@ function SessionItem({
onLoadSession,
onResumeSession,
onForkSession,
onDeleteSession,
onClose,
}: {
session: SessionInfo;
@ -238,6 +241,7 @@ function SessionItem({
onLoadSession: (sessionId: string, cwd: string) => Promise<void>;
onResumeSession: (sessionId: string, cwd: string) => Promise<void>;
onForkSession: (sessionId: string, cwd: string) => Promise<void>;
onDeleteSession: (sessionId: string) => Promise<void>;
onClose: () => void;
}) {
const handleLoad = useCallback(() => {
@ -255,6 +259,10 @@ function SessionItem({
void onForkSession(session.sessionId, session.cwd);
}, [session, onForkSession, onClose]);
const handleDelete = useCallback(() => {
void onDeleteSession(session.sessionId);
}, [session.sessionId, onDeleteSession]);
return (
<div className="agent-client-session-history-item">
<div className="agent-client-session-history-item-content">
@ -297,6 +305,12 @@ function SessionItem({
onClick={handleFork}
/>
)}
<IconButton
iconName="trash-2"
label="Delete session"
className="agent-client-session-history-action-icon agent-client-session-history-delete-icon"
onClick={handleDelete}
/>
</div>
</div>
);
@ -328,6 +342,7 @@ export function SessionHistoryContent({
onLoadSession,
onResumeSession,
onForkSession,
onDeleteSession,
onLoadMore,
onFetchSessions,
onClose,
@ -361,18 +376,11 @@ export function SessionHistoryContent({
// Check if any session operation is available
const canPerformAnyOperation = canLoad || canResume || canFork;
// Show message if no session operations are supported
if (!canPerformAnyOperation && !debugMode) {
return (
<div className="agent-client-session-history-empty">
<p className="agent-client-session-history-empty-text">
This agent does not support session restoration.
</p>
</div>
);
}
const canShowList = canList || isUsingLocalSessions;
// Show local sessions list (always show for delete functionality)
// - If agent supports list: use agent's session/list
// - If agent doesn't support list OR doesn't support restoration: use locally saved sessions
const canShowList =
canList || isUsingLocalSessions || !canPerformAnyOperation;
return (
<>
@ -387,13 +395,21 @@ export function SessionHistoryContent({
/>
)}
{/* Warning banner for agents that don't support restoration */}
{!canPerformAnyOperation && (
<div className="agent-client-session-history-warning-banner">
<p>
This agent does not support session restoration.
Messages are saved locally but cannot be restored to the
agent.
</p>
</div>
)}
{/* Local sessions banner */}
{isUsingLocalSessions && (
{(isUsingLocalSessions || !canPerformAnyOperation) && (
<div className="agent-client-session-history-local-banner">
<span>
Locally saved sessions (agent doesn't support
session/list)
</span>
<span>Locally saved sessions</span>
</div>
)}
@ -470,6 +486,7 @@ export function SessionHistoryContent({
onLoadSession={onLoadSession}
onResumeSession={onResumeSession}
onForkSession={onForkSession}
onDeleteSession={onDeleteSession}
onClose={onClose}
/>
))}

View file

@ -132,6 +132,12 @@ export interface UseSessionHistoryReturn {
*/
forkSession: (sessionId: string, cwd: string) => Promise<void>;
/**
* Delete a session (local metadata + message file).
* @param sessionId - Session to delete
*/
deleteSession: (sessionId: string) => Promise<void>;
/**
* Invalidate the session cache.
* Call this when creating a new session to refresh the list.
@ -220,15 +226,25 @@ export function useSessionHistory(
cacheRef.current = null;
}, []);
// Check if any restoration operation is available
const canPerformAnyOperation =
capabilities.canLoad || capabilities.canResume || capabilities.canFork;
/**
* Fetch sessions list from agent or local storage.
* Uses agent's session/list if supported, otherwise falls back to local storage.
* For agents that don't support restoration, local sessions are used for deletion.
* Replaces existing sessions in state.
*/
const fetchSessions = useCallback(
async (cwd?: string) => {
// If agent doesn't support list, use local sessions
if (!capabilities.canList) {
// Use local sessions if:
// - Agent doesn't support session/list, OR
// - Agent doesn't support any restoration operation (for delete only)
const shouldUseLocalSessions =
!capabilities.canList || !canPerformAnyOperation;
if (shouldUseLocalSessions) {
// Get locally saved sessions for this agent
const localSessions = settingsAccess.getSavedSessions(
session.agentId,
@ -289,6 +305,7 @@ export function useSessionHistory(
[
agentClient,
capabilities.canList,
canPerformAnyOperation,
isCacheValid,
settingsAccess,
session.agentId,
@ -450,6 +467,33 @@ export function useSessionHistory(
],
);
/**
* Delete a session (local metadata + message file).
* Removes from both local state and persistent storage.
*/
const deleteSession = useCallback(
async (sessionId: string) => {
try {
// Delete from persistent storage (metadata + message file)
await settingsAccess.deleteSession(sessionId);
// Remove from local state
setSessions((prev) =>
prev.filter((s) => s.sessionId !== sessionId),
);
// Invalidate cache to ensure consistency
invalidateCache();
} catch (err) {
const errorMessage =
err instanceof Error ? err.message : String(err);
setError(`Failed to delete session: ${errorMessage}`);
throw err; // Re-throw to allow caller to handle
}
},
[settingsAccess, invalidateCache],
);
return {
sessions,
loading,
@ -475,6 +519,7 @@ export function useSessionHistory(
loadSession,
resumeSession,
forkSession,
deleteSession,
invalidateCache,
};
}

View file

@ -1519,3 +1519,27 @@ If your plugin does not need CSS, delete this file.
color: var(--text-muted);
border-left: 3px solid var(--interactive-accent);
}
/* Warning banner for agents that don't support restoration */
.agent-client-session-history-warning-banner {
padding: 8px 12px;
margin-bottom: 12px;
background: var(--background-secondary);
border-radius: 4px;
border-left: 3px solid var(--text-warning);
}
.agent-client-session-history-warning-banner p {
margin: 0;
color: var(--text-muted);
font-size: 12px;
}
/* Delete button */
.agent-client-session-history-delete-icon {
color: var(--text-muted);
}
.agent-client-session-history-delete-icon:hover {
color: var(--text-error);
}