feat(session-manager): implement session management tools

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-04-10 15:53:08 +09:00
parent 1a090af2eb
commit 7244d048fb
+54 -15
View File
@@ -27,9 +27,48 @@ function withTimeout<T>(promise: Promise<T>, ms: number, operation: string): Pro
]) ])
} }
export function createSessionManagerTools(ctx: PluginInput): Record<string, ToolDefinition> { type SessionManagerToolDeps = {
getAllSessions: typeof getAllSessions
getMainSessions: typeof getMainSessions
getSessionInfo: typeof getSessionInfo
readSessionMessages: typeof readSessionMessages
readSessionTodos: typeof readSessionTodos
sessionExists: typeof sessionExists
setStorageClient: typeof setStorageClient
filterSessionsByDate: typeof filterSessionsByDate
formatSessionInfo: typeof formatSessionInfo
formatSessionList: typeof formatSessionList
formatSessionMessages: typeof formatSessionMessages
formatSearchResults: typeof formatSearchResults
searchInSession: typeof searchInSession
}
const defaultSessionManagerToolDeps: SessionManagerToolDeps = {
getAllSessions,
getMainSessions,
getSessionInfo,
readSessionMessages,
readSessionTodos,
sessionExists,
setStorageClient,
filterSessionsByDate,
formatSessionInfo,
formatSessionList,
formatSessionMessages,
formatSearchResults,
searchInSession,
}
export function createSessionManagerTools(
ctx: PluginInput,
deps: Partial<SessionManagerToolDeps> = {},
): Record<string, ToolDefinition> {
const resolvedDeps: SessionManagerToolDeps = {
...defaultSessionManagerToolDeps,
...deps,
}
// Initialize storage client for SDK-based operations (beta mode) // Initialize storage client for SDK-based operations (beta mode)
setStorageClient(ctx.client) resolvedDeps.setStorageClient(ctx.client)
const session_list: ToolDefinition = tool({ const session_list: ToolDefinition = tool({
description: SESSION_LIST_DESCRIPTION, description: SESSION_LIST_DESCRIPTION,
@@ -42,18 +81,18 @@ export function createSessionManagerTools(ctx: PluginInput): Record<string, Tool
execute: async (args: SessionListArgs, _context) => { execute: async (args: SessionListArgs, _context) => {
try { try {
const directory = args.project_path ?? ctx.directory const directory = args.project_path ?? ctx.directory
let sessions = await getMainSessions({ directory }) let sessions = await resolvedDeps.getMainSessions({ directory })
let sessionIDs = sessions.map((s) => s.id) let sessionIDs = sessions.map((s) => s.id)
if (args.from_date || args.to_date) { if (args.from_date || args.to_date) {
sessionIDs = await filterSessionsByDate(sessionIDs, args.from_date, args.to_date) sessionIDs = await resolvedDeps.filterSessionsByDate(sessionIDs, args.from_date, args.to_date)
} }
if (args.limit && args.limit > 0) { if (args.limit && args.limit > 0) {
sessionIDs = sessionIDs.slice(0, args.limit) sessionIDs = sessionIDs.slice(0, args.limit)
} }
return await formatSessionList(sessionIDs) return await resolvedDeps.formatSessionList(sessionIDs)
} catch (e) { } catch (e) {
return `Error: ${e instanceof Error ? e.message : String(e)}` return `Error: ${e instanceof Error ? e.message : String(e)}`
} }
@@ -70,11 +109,11 @@ export function createSessionManagerTools(ctx: PluginInput): Record<string, Tool
}, },
execute: async (args: SessionReadArgs, _context) => { execute: async (args: SessionReadArgs, _context) => {
try { try {
if (!(await sessionExists(args.session_id))) { if (!(await resolvedDeps.sessionExists(args.session_id))) {
return `Session not found: ${args.session_id}` return `Session not found: ${args.session_id}`
} }
let messages = await readSessionMessages(args.session_id) let messages = await resolvedDeps.readSessionMessages(args.session_id)
if (messages.length === 0) { if (messages.length === 0) {
return `Session not found: ${args.session_id}` return `Session not found: ${args.session_id}`
@@ -84,9 +123,9 @@ export function createSessionManagerTools(ctx: PluginInput): Record<string, Tool
messages = messages.slice(0, args.limit) messages = messages.slice(0, args.limit)
} }
const todos = args.include_todos ? await readSessionTodos(args.session_id) : undefined const todos = args.include_todos ? await resolvedDeps.readSessionTodos(args.session_id) : undefined
return formatSessionMessages(messages, args.include_todos, todos) return resolvedDeps.formatSessionMessages(messages, args.include_todos, todos)
} catch (e) { } catch (e) {
return `Error: ${e instanceof Error ? e.message : String(e)}` return `Error: ${e instanceof Error ? e.message : String(e)}`
} }
@@ -107,10 +146,10 @@ export function createSessionManagerTools(ctx: PluginInput): Record<string, Tool
const searchOperation = async (): Promise<SearchResult[]> => { const searchOperation = async (): Promise<SearchResult[]> => {
if (args.session_id) { if (args.session_id) {
return searchInSession(args.session_id, args.query, args.case_sensitive, resultLimit) return resolvedDeps.searchInSession(args.session_id, args.query, args.case_sensitive, resultLimit)
} }
const allSessions = await getAllSessions() const allSessions = await resolvedDeps.getAllSessions()
const sessionsToScan = allSessions.slice(0, MAX_SESSIONS_TO_SCAN) const sessionsToScan = allSessions.slice(0, MAX_SESSIONS_TO_SCAN)
const allResults: SearchResult[] = [] const allResults: SearchResult[] = []
@@ -118,7 +157,7 @@ export function createSessionManagerTools(ctx: PluginInput): Record<string, Tool
if (allResults.length >= resultLimit) break if (allResults.length >= resultLimit) break
const remaining = resultLimit - allResults.length const remaining = resultLimit - allResults.length
const sessionResults = await searchInSession(sid, args.query, args.case_sensitive, remaining) const sessionResults = await resolvedDeps.searchInSession(sid, args.query, args.case_sensitive, remaining)
allResults.push(...sessionResults) allResults.push(...sessionResults)
} }
@@ -127,7 +166,7 @@ export function createSessionManagerTools(ctx: PluginInput): Record<string, Tool
const results = await withTimeout(searchOperation(), SEARCH_TIMEOUT_MS, "Search") const results = await withTimeout(searchOperation(), SEARCH_TIMEOUT_MS, "Search")
return formatSearchResults(results) return resolvedDeps.formatSearchResults(results)
} catch (e) { } catch (e) {
return `Error: ${e instanceof Error ? e.message : String(e)}` return `Error: ${e instanceof Error ? e.message : String(e)}`
} }
@@ -141,13 +180,13 @@ export function createSessionManagerTools(ctx: PluginInput): Record<string, Tool
}, },
execute: async (args: SessionInfoArgs, _context) => { execute: async (args: SessionInfoArgs, _context) => {
try { try {
const info = await getSessionInfo(args.session_id) const info = await resolvedDeps.getSessionInfo(args.session_id)
if (!info) { if (!info) {
return `Session not found: ${args.session_id}` return `Session not found: ${args.session_id}`
} }
return formatSessionInfo(info) return resolvedDeps.formatSessionInfo(info)
} catch (e) { } catch (e) {
return `Error: ${e instanceof Error ? e.message : String(e)}` return `Error: ${e instanceof Error ? e.message : String(e)}`
} }