jp_lit_list_cache
Retrieve and summarize cached search results from Japanese academic databases, with filtering by date and source.
Instructions
ローカルキャッシュの一覧・集計を返す。日付や source で絞り込み可能
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tool | No | ||
| session_id | No | ||
| saved_on | No | ||
| saved_from | No | ||
| saved_to | No | ||
| source | No | ||
| limit | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tool | Yes | ||
| session_id | Yes | ||
| saved_on | Yes | ||
| saved_on_resolved | Yes | ||
| saved_from | Yes | ||
| saved_to | Yes | ||
| source | Yes | ||
| total | Yes | ||
| limit | Yes | ||
| cache_keys | Yes | ||
| summary | Yes | ||
| items | Yes |
Implementation Reference
- src/tools/jpLitListCache.ts:30-167 (handler)The main handler function `createJpLitListCacheTool` that implements the jp_lit_list_cache tool logic. It reads cached entries from disk, filters by session, date range, tool name, and source, then returns a summary listing with aggregation by tool and source.
export function createJpLitListCacheTool( cache: FileCache, sessions: SessionStore, baseDir = process.cwd() ) { return async (input: unknown) => { const parsed = listCacheInputSchema.parse(input); const { effectiveSavedFrom, effectiveSavedTo, resolvedSavedOn } = resolveSavedDateFilter(parsed); const allSessions = parsed.session_id ? [await sessions.readById(parsed.session_id)] : await sessions.listAll(); const cacheToSessionIds = new Map<string, Set<string>>(); for (const session of allSessions) { for (const entry of session.entries) { const ids = cacheToSessionIds.get(entry.cache_key) ?? new Set<string>(); ids.add(session.session_id); cacheToSessionIds.set(entry.cache_key, ids); } } const cacheRoots = [getCacheRoot(baseDir), getLegacyCacheRoot(baseDir)]; const targetTools = parsed.tool ? [parsed.tool] : Array.from( new Set( ( await Promise.all( cacheRoots.map((root) => readdir(root).catch(() => [] as string[])) ) ).flat() ) ); const summaries: CachedSummary[] = []; for (const tool of targetTools) { const cacheKeys = Array.from( new Set( ( await Promise.all( cacheRoots.map((root) => readdir(path.join(root, tool)).catch(() => [] as string[]) ) ) ) .flat() .filter((filename) => filename.endsWith(".json")) .map((filename) => filename.replace(/\.json$/i, "")) ) ); for (const cacheKey of cacheKeys) { const cached = await cache.read<Record<string, unknown>>(tool, cacheKey); if (!cached) { continue; } if (effectiveSavedFrom && cached.saved_at < effectiveSavedFrom) { continue; } if (effectiveSavedTo && cached.saved_at > effectiveSavedTo) { continue; } const sessionIds = Array.from(cacheToSessionIds.get(cacheKey) ?? []); if (parsed.session_id && !sessionIds.includes(parsed.session_id)) { continue; } const content = cached.structured_content as Partial<SearchOutput>; const source = typeof content.source === "string" ? content.source : null; if (parsed.source && source !== parsed.source) { continue; } const query = typeof content.query === "string" ? content.query : typeof cached.input.query === "string" ? cached.input.query : null; const itemCount = Array.isArray(content.items) ? content.items.length : 0; const total = typeof content.total === "number" ? content.total : itemCount; summaries.push({ tool, cache_key: cacheKey, saved_at: cached.saved_at, source, session_ids: sessionIds, query_preview: createPreview(query), total, item_count: itemCount }); } } summaries.sort((left, right) => right.saved_at.localeCompare(left.saved_at)); const limited = summaries.slice(0, parsed.limit); const byTool: Record<string, number> = {}; const bySource: Record<string, number> = {}; for (const entry of summaries) { byTool[entry.tool] = (byTool[entry.tool] ?? 0) + 1; const sourceKey = entry.source ?? "unknown"; bySource[sourceKey] = (bySource[sourceKey] ?? 0) + 1; } const structuredContent: ListCacheOutput = listCacheOutputSchema.parse({ tool: parsed.tool ?? null, session_id: parsed.session_id ?? null, saved_on: parsed.saved_on ?? null, saved_on_resolved: resolvedSavedOn, saved_from: parsed.saved_from ?? null, saved_to: parsed.saved_to ?? null, source: parsed.source ?? null, total: summaries.length, limit: parsed.limit, cache_keys: limited.map((item) => item.cache_key), summary: { by_tool: byTool, by_source: bySource, newest_saved_at: summaries[0]?.saved_at ?? null, oldest_saved_at: summaries.at(-1)?.saved_at ?? null }, items: limited }); return { content: [ { type: "text" as const, text: JSON.stringify(structuredContent, null, 2) } ], structuredContent }; }; } - src/lib/schemas.ts:470-481 (schema)Input schema for jp_lit_list_cache: accepts optional tool, session_id, saved_on/saved_from/saved_to date filters, source, and limit (default 100, max 500).
export const listCacheInputSchema = z.object({ tool: z.string().trim().min(1).optional(), session_id: z.string().trim().regex(/^\d{4}-\d{2}-\d{2}-\d{6}$/).optional(), saved_on: z .string() .regex(/^(\d{4}-\d{2}-\d{2}|today|yesterday|last_7_days)$/) .optional(), saved_from: z.string().optional(), saved_to: z.string().optional(), source: sourceSchema.optional(), limit: z.number().int().positive().max(500).default(100) }); - src/lib/schemas.ts:483-512 (schema)Output schema for jp_lit_list_cache: returns total count, limit, cache_keys array, summary (by_tool/by_source aggregates, newest/oldest dates), and items array with tool, cache_key, saved_at, source, session_ids, query_preview, total, item_count.
export const listCacheOutputSchema = z.object({ tool: z.string().nullable(), session_id: z.string().nullable(), saved_on: z.string().nullable(), saved_on_resolved: z.string().nullable(), saved_from: z.string().nullable(), saved_to: z.string().nullable(), source: sourceSchema.nullable(), total: z.number().int().nonnegative(), limit: z.number().int().positive(), cache_keys: z.array(z.string()), summary: z.object({ by_tool: z.record(z.string(), z.number()), by_source: z.record(z.string(), z.number()), newest_saved_at: z.string().nullable(), oldest_saved_at: z.string().nullable() }), items: z.array( z.object({ tool: z.string(), cache_key: z.string(), saved_at: z.string(), source: sourceSchema.nullable(), session_ids: z.array(z.string()), query_preview: z.string().nullable(), total: z.number().int().nonnegative(), item_count: z.number().int().nonnegative() }) ) }); - src/server.ts:497-505 (registration)Tool registration: `server.registerTool("jp_lit_list_cache", ...)` with description 'ローカルキャッシュの一覧・集計を返す。日付や source で絞り込み可能'. Also at line 317 the handler is instantiated via `createJpLitListCacheTool(cache, sessions)`.
server.registerTool( "jp_lit_list_cache", { description: "ローカルキャッシュの一覧・集計を返す。日付や source で絞り込み可能", inputSchema: listCacheInputSchema, outputSchema: listCacheOutputSchema }, listCacheTool ); - src/tools/jpLitListCache.ts:22-28 (helper)Helper function `createPreview` that truncates long query strings to 120 characters for display in the cache listing.
function createPreview(value: string | null | undefined, maxLength = 120) { if (!value) { return null; } const compact = value.replace(/\s+/g, " ").trim(); return compact.length <= maxLength ? compact : `${compact.slice(0, maxLength - 1)}…`; }