Refactor mem-search documentation and optimize API tool definitions
- Updated SKILL.md to emphasize batch fetching for observations, clarifying usage and efficiency. - Removed deprecated tools from mcp-server.ts and streamlined tool definitions for clarity. - Enhanced formatting in FormattingService.ts for better output readability. - Adjusted SearchManager.ts to improve result headers and removed unnecessary search tips from combined text.
This commit is contained in:
+50
-243
@@ -30,18 +30,8 @@ const WORKER_BASE_URL = `http://${WORKER_HOST}:${WORKER_PORT}`;
|
||||
const TOOL_ENDPOINT_MAP: Record<string, string> = {
|
||||
'search': '/api/search',
|
||||
'timeline': '/api/timeline',
|
||||
'decisions': '/api/decisions',
|
||||
'changes': '/api/changes',
|
||||
'how_it_works': '/api/how-it-works',
|
||||
'search_observations': '/api/search/observations',
|
||||
'search_sessions': '/api/search/sessions',
|
||||
'search_user_prompts': '/api/search/prompts',
|
||||
'find_by_concept': '/api/search/by-concept',
|
||||
'find_by_file': '/api/search/by-file',
|
||||
'find_by_type': '/api/search/by-type',
|
||||
'get_recent_context': '/api/context/recent',
|
||||
'get_context_timeline': '/api/context/timeline',
|
||||
'get_timeline_by_query': '/api/timeline/by-query',
|
||||
'progressive_ix': '/api/instructions'
|
||||
};
|
||||
|
||||
@@ -192,24 +182,25 @@ async function verifyWorkerConnection(): Promise<boolean> {
|
||||
|
||||
/**
|
||||
* Tool definitions with HTTP-based handlers
|
||||
* Descriptions removed - use progressive_ix tool for parameter documentation
|
||||
*/
|
||||
const tools = [
|
||||
{
|
||||
name: 'search',
|
||||
description: 'Search observations, sessions, and prompts',
|
||||
inputSchema: z.object({
|
||||
query: z.string().optional().describe('Natural language search query for semantic ranking via ChromaDB vector search. Optional - omit for date-filtered queries only (Chroma cannot filter by date, requires direct SQLite).'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED for initial search), "full" for complete details (use only after reviewing index results)'),
|
||||
type: z.enum(['observations', 'sessions', 'prompts']).optional().describe('Filter by document type (observations, sessions, or prompts). Omit to search all types.'),
|
||||
obs_type: z.string().optional().describe('Filter observations by type (single value or comma-separated list: decision,bugfix,feature,refactor,discovery,change). Only applies when type="observations"'),
|
||||
concepts: z.string().optional().describe('Filter by concept tags (single value or comma-separated list). Only applies when type="observations"'),
|
||||
files: z.string().optional().describe('Filter by file paths (single value or comma-separated list for partial match). Only applies when type="observations"'),
|
||||
project: z.string().optional().describe('Filter by project name'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)'),
|
||||
limit: z.number().min(1).max(100).default(20).describe('Maximum number of results'),
|
||||
offset: z.number().min(0).default(0).describe('Number of results to skip'),
|
||||
orderBy: z.enum(['relevance', 'date_desc', 'date_asc']).default('date_desc').describe('Sort order')
|
||||
query: z.string().optional(),
|
||||
format: z.enum(['index', 'full']).default('index'),
|
||||
type: z.enum(['observations', 'sessions', 'prompts']).optional(),
|
||||
obs_type: z.string().optional(),
|
||||
concepts: z.string().optional(),
|
||||
files: z.string().optional(),
|
||||
project: z.string().optional(),
|
||||
dateStart: z.union([z.string(), z.number()]).optional(),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional(),
|
||||
limit: z.number().min(1).max(100).default(20),
|
||||
offset: z.number().min(0).default(0),
|
||||
orderBy: z.enum(['relevance', 'date_desc', 'date_asc']).default('date_desc')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['search'];
|
||||
@@ -220,195 +211,33 @@ const tools = [
|
||||
name: 'timeline',
|
||||
description: 'Get timeline around observation ID or query',
|
||||
inputSchema: z.object({
|
||||
query: z.string().optional().describe('Natural language query to find anchor observation (query-based mode). Mutually exclusive with anchor.'),
|
||||
anchor: z.number().optional().describe('Observation ID to use as anchor (anchor-based mode). Mutually exclusive with query.'),
|
||||
depth_before: z.number().min(0).max(100).default(10).describe('Number of observations to fetch before anchor'),
|
||||
depth_after: z.number().min(0).max(100).default(10).describe('Number of observations to fetch after anchor'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
type: z.string().optional().describe('Filter observations by type (single value or comma-separated list: decision,bugfix,feature,refactor,discovery,change)'),
|
||||
concepts: z.string().optional().describe('Filter by concept tags (single value or comma-separated list)'),
|
||||
files: z.string().optional().describe('Filter by file paths (single value or comma-separated list for partial match)'),
|
||||
project: z.string().optional().describe('Filter by project name')
|
||||
query: z.string().optional(),
|
||||
anchor: z.number().optional(),
|
||||
depth_before: z.number().min(0).max(100).default(10),
|
||||
depth_after: z.number().min(0).max(100).default(10),
|
||||
format: z.enum(['index', 'full']).default('index'),
|
||||
type: z.string().optional(),
|
||||
concepts: z.string().optional(),
|
||||
files: z.string().optional(),
|
||||
project: z.string().optional()
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['timeline'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'decisions',
|
||||
description: 'Find architectural and design decisions',
|
||||
inputSchema: z.object({
|
||||
query: z.string().describe('Natural language query for finding decisions'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
limit: z.number().min(1).max(100).default(20).describe('Maximum number of results'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['decisions'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'changes',
|
||||
description: 'Find code changes and refactorings',
|
||||
inputSchema: z.object({
|
||||
query: z.string().describe('Natural language query for finding changes'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
limit: z.number().min(1).max(100).default(20).describe('Maximum number of results'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['changes'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'how_it_works',
|
||||
description: 'Understand system architecture',
|
||||
inputSchema: z.object({
|
||||
query: z.string().describe('Natural language query for understanding how something works'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
limit: z.number().min(1).max(100).default(20).describe('Maximum number of results'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['how_it_works'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'search_observations',
|
||||
description: '[DEPRECATED] Search observations only',
|
||||
inputSchema: z.object({
|
||||
query: z.string().optional().describe('Full-text search query (FTS5)'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
type: z.string().optional().describe('Filter by observation type (single value or comma-separated list: decision,bugfix,feature,refactor,discovery,change)'),
|
||||
concepts: z.string().optional().describe('Filter by concept tags (single value or comma-separated list)'),
|
||||
files: z.string().optional().describe('Filter by file paths (single value or comma-separated list for partial match)'),
|
||||
project: z.string().optional().describe('Filter by project name'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)'),
|
||||
limit: z.number().min(1).max(100).default(20).describe('Maximum number of results'),
|
||||
offset: z.number().min(0).default(0).describe('Number of results to skip'),
|
||||
orderBy: z.enum(['relevance', 'date_desc', 'date_asc']).default('relevance').describe('Sort order (relevance only when query provided)')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['search_observations'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'search_sessions',
|
||||
description: '[DEPRECATED] Search sessions only',
|
||||
inputSchema: z.object({
|
||||
query: z.string().optional().describe('Full-text search query (FTS5)'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
project: z.string().optional().describe('Filter by project name'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)'),
|
||||
limit: z.number().min(1).max(100).default(20).describe('Maximum number of results'),
|
||||
offset: z.number().min(0).default(0).describe('Number of results to skip'),
|
||||
orderBy: z.enum(['relevance', 'date_desc', 'date_asc']).default('relevance').describe('Sort order (relevance only when query provided)')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['search_sessions'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'search_user_prompts',
|
||||
description: '[DEPRECATED] Search prompts only',
|
||||
inputSchema: z.object({
|
||||
query: z.string().optional().describe('Full-text search query (FTS5)'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
project: z.string().optional().describe('Filter by project name'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)'),
|
||||
limit: z.number().min(1).max(100).default(20).describe('Maximum number of results'),
|
||||
offset: z.number().min(0).default(0).describe('Number of results to skip'),
|
||||
orderBy: z.enum(['relevance', 'date_desc', 'date_asc']).default('relevance').describe('Sort order (relevance only when query provided)')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['search_user_prompts'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'find_by_concept',
|
||||
description: 'Find observations by concept tags',
|
||||
inputSchema: z.object({
|
||||
concepts: z.string().describe('Concept tag(s) to filter by (single value or comma-separated list)'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
type: z.string().optional().describe('Filter by observation type (single value or comma-separated list: decision,bugfix,feature,refactor,discovery,change)'),
|
||||
files: z.string().optional().describe('Filter by file paths (single value or comma-separated list for partial match)'),
|
||||
project: z.string().optional().describe('Filter by project name'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)'),
|
||||
limit: z.number().min(1).max(100).default(20).describe('Maximum number of results'),
|
||||
offset: z.number().min(0).default(0).describe('Number of results to skip'),
|
||||
orderBy: z.enum(['date_desc', 'date_asc']).default('date_desc').describe('Sort order')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['find_by_concept'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'find_by_file',
|
||||
description: 'Find observations by file paths',
|
||||
inputSchema: z.object({
|
||||
files: z.string().describe('File path(s) to filter by (single value or comma-separated list for partial match)'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
type: z.string().optional().describe('Filter by observation type (single value or comma-separated list: decision,bugfix,feature,refactor,discovery,change)'),
|
||||
concepts: z.string().optional().describe('Filter by concept tags (single value or comma-separated list)'),
|
||||
project: z.string().optional().describe('Filter by project name'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)'),
|
||||
limit: z.number().min(1).max(100).default(20).describe('Maximum number of results'),
|
||||
offset: z.number().min(0).default(0).describe('Number of results to skip'),
|
||||
orderBy: z.enum(['date_desc', 'date_asc']).default('date_desc').describe('Sort order')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['find_by_file'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'find_by_type',
|
||||
description: 'Find observations by type',
|
||||
inputSchema: z.object({
|
||||
type: z.string().describe('Observation type(s) to filter by (single value or comma-separated list: decision,bugfix,feature,refactor,discovery,change)'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
concepts: z.string().optional().describe('Filter by concept tags (single value or comma-separated list)'),
|
||||
files: z.string().optional().describe('Filter by file paths (single value or comma-separated list for partial match)'),
|
||||
project: z.string().optional().describe('Filter by project name'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)'),
|
||||
limit: z.number().min(1).max(100).default(20).describe('Maximum number of results'),
|
||||
offset: z.number().min(0).default(0).describe('Number of results to skip'),
|
||||
orderBy: z.enum(['date_desc', 'date_asc']).default('date_desc').describe('Sort order')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['find_by_type'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'get_recent_context',
|
||||
description: 'Get recent timeline items',
|
||||
inputSchema: z.object({
|
||||
limit: z.number().min(1).max(100).default(30).describe('Maximum number of timeline items to return'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
type: z.string().optional().describe('Filter by observation type (single value or comma-separated list: decision,bugfix,feature,refactor,discovery,change)'),
|
||||
concepts: z.string().optional().describe('Filter by concept tags (single value or comma-separated list)'),
|
||||
files: z.string().optional().describe('Filter by file paths (single value or comma-separated list for partial match)'),
|
||||
project: z.string().optional().describe('Filter by project name'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)')
|
||||
limit: z.number().min(1).max(100).default(30),
|
||||
format: z.enum(['index', 'full']).default('index'),
|
||||
type: z.string().optional(),
|
||||
concepts: z.string().optional(),
|
||||
files: z.string().optional(),
|
||||
project: z.string().optional(),
|
||||
dateStart: z.union([z.string(), z.number()]).optional(),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional()
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['get_recent_context'];
|
||||
@@ -419,47 +248,25 @@ const tools = [
|
||||
name: 'get_context_timeline',
|
||||
description: 'Get timeline around specific observation',
|
||||
inputSchema: z.object({
|
||||
anchor: z.number().describe('Observation ID to use as anchor point'),
|
||||
depth_before: z.number().min(0).max(100).default(10).describe('Number of observations to fetch before anchor'),
|
||||
depth_after: z.number().min(0).max(100).default(10).describe('Number of observations to fetch after anchor'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
type: z.string().optional().describe('Filter by observation type (single value or comma-separated list: decision,bugfix,feature,refactor,discovery,change)'),
|
||||
concepts: z.string().optional().describe('Filter by concept tags (single value or comma-separated list)'),
|
||||
files: z.string().optional().describe('Filter by file paths (single value or comma-separated list for partial match)'),
|
||||
project: z.string().optional().describe('Filter by project name')
|
||||
anchor: z.number(),
|
||||
depth_before: z.number().min(0).max(100).default(10),
|
||||
depth_after: z.number().min(0).max(100).default(10),
|
||||
format: z.enum(['index', 'full']).default('index'),
|
||||
type: z.string().optional(),
|
||||
concepts: z.string().optional(),
|
||||
files: z.string().optional(),
|
||||
project: z.string().optional()
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['get_context_timeline'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'get_timeline_by_query',
|
||||
description: 'Search and get timeline in one call',
|
||||
inputSchema: z.object({
|
||||
query: z.string().describe('Natural language query to find anchor observation'),
|
||||
depth_before: z.number().min(0).max(100).default(10).describe('Number of observations to fetch before anchor'),
|
||||
depth_after: z.number().min(0).max(100).default(10).describe('Number of observations to fetch after anchor'),
|
||||
format: z.enum(['index', 'full']).default('index').describe('Output format: "index" for titles/dates only (default, RECOMMENDED), "full" for complete details'),
|
||||
type: z.string().optional().describe('Filter by observation type (single value or comma-separated list: decision,bugfix,feature,refactor,discovery,change)'),
|
||||
concepts: z.string().optional().describe('Filter by concept tags (single value or comma-separated list)'),
|
||||
files: z.string().optional().describe('Filter by file paths (single value or comma-separated list for partial match)'),
|
||||
project: z.string().optional().describe('Filter by project name'),
|
||||
dateStart: z.union([z.string(), z.number()]).optional().describe('Start date for filtering (ISO string or epoch timestamp)'),
|
||||
dateEnd: z.union([z.string(), z.number()]).optional().describe('End date for filtering (ISO string or epoch timestamp)')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['get_timeline_by_query'];
|
||||
return await callWorkerAPI(endpoint, args);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'progressive_ix',
|
||||
description: 'Load detailed instructions for mem-search tools',
|
||||
description: 'Load parameter docs and usage instructions',
|
||||
inputSchema: z.object({
|
||||
topic: z.enum(['workflow', 'search_params', 'examples', 'all'])
|
||||
.default('all')
|
||||
.describe('Which instruction section to load: workflow (4-step process), search_params (parameters reference), examples (usage examples), all (complete guide)')
|
||||
topic: z.enum(['workflow', 'search_params', 'examples', 'all']).default('all')
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
const endpoint = TOOL_ENDPOINT_MAP['progressive_ix'];
|
||||
@@ -468,9 +275,9 @@ const tools = [
|
||||
},
|
||||
{
|
||||
name: 'get_observation',
|
||||
description: 'Get full details for a single observation by ID',
|
||||
description: 'Get observation by ID',
|
||||
inputSchema: z.object({
|
||||
id: z.number().describe('Observation ID from search/timeline results')
|
||||
id: z.number()
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
return await callWorkerAPIWithPath('/api/observation', args.id);
|
||||
@@ -478,12 +285,12 @@ const tools = [
|
||||
},
|
||||
{
|
||||
name: 'get_batch_observations',
|
||||
description: 'Get full details for multiple observations by IDs in one request',
|
||||
description: 'Get multiple observations by IDs',
|
||||
inputSchema: z.object({
|
||||
ids: z.array(z.number()).describe('Array of observation IDs to fetch'),
|
||||
orderBy: z.enum(['date_desc', 'date_asc']).optional().describe('Sort order for results'),
|
||||
limit: z.number().optional().describe('Maximum number of results to return'),
|
||||
project: z.string().optional().describe('Filter by project name')
|
||||
ids: z.array(z.number()),
|
||||
orderBy: z.enum(['date_desc', 'date_asc']).optional(),
|
||||
limit: z.number().optional(),
|
||||
project: z.string().optional()
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
return await callWorkerAPIPost('/api/observations/batch', args);
|
||||
@@ -491,9 +298,9 @@ const tools = [
|
||||
},
|
||||
{
|
||||
name: 'get_session',
|
||||
description: 'Get full session summary by ID',
|
||||
description: 'Get session summary by ID',
|
||||
inputSchema: z.object({
|
||||
id: z.number().describe('Session ID (just the number from S1234)')
|
||||
id: z.number()
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
return await callWorkerAPIWithPath('/api/session', args.id);
|
||||
@@ -503,7 +310,7 @@ const tools = [
|
||||
name: 'get_prompt',
|
||||
description: 'Get user prompt by ID',
|
||||
inputSchema: z.object({
|
||||
id: z.number().describe('Prompt ID from search results')
|
||||
id: z.number()
|
||||
}),
|
||||
handler: async (args: any) => {
|
||||
return await callWorkerAPIWithPath('/api/prompt', args.id);
|
||||
|
||||
@@ -38,9 +38,7 @@ Other tips:
|
||||
const date = new Date(obs.created_at_epoch).toLocaleString();
|
||||
const type = obs.type ? `[${obs.type}]` : '';
|
||||
|
||||
return `${index + 1}. ${type} ${title}
|
||||
Date: ${date}
|
||||
Source: claude-mem://observation/${obs.id}`;
|
||||
return ` ${index + 1}. ${type} ${title}\n Date: ${date}\n Source: claude-mem://observation/${obs.id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,9 +48,7 @@ Other tips:
|
||||
const title = session.request || `Session ${session.sdk_session_id?.substring(0, 8) || 'unknown'}`;
|
||||
const date = new Date(session.created_at_epoch).toLocaleString();
|
||||
|
||||
return `${index + 1}. ${title}
|
||||
Date: ${date}
|
||||
Source: claude-mem://session/${session.sdk_session_id}`;
|
||||
return ` ${index + 1}. ${title}\n Date: ${date}\n Source: claude-mem://session/${session.sdk_session_id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,9 +57,7 @@ Other tips:
|
||||
formatUserPromptIndex(prompt: UserPromptSearchResult, index: number): string {
|
||||
const date = new Date(prompt.created_at_epoch).toLocaleString();
|
||||
|
||||
return `${index + 1}. "${prompt.prompt_text}"
|
||||
Date: ${date} | Prompt #${prompt.prompt_number}
|
||||
Source: claude-mem://user-prompt/${prompt.id}`;
|
||||
return ` ${index + 1}. "${prompt.prompt_text}"\n Date: ${date} | Prompt #${prompt.prompt_number}\n Source: claude-mem://user-prompt/${prompt.id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -248,7 +248,7 @@ export class SearchManager {
|
||||
|
||||
let combinedText: string;
|
||||
if (format === 'index') {
|
||||
const header = `Found ${totalResults} result(s) matching "${query}" (${observations.length} obs, ${sessions.length} sessions, ${prompts.length} prompts):\n\n`;
|
||||
const header = ` ⎿ Found ${totalResults} result(s) matching "${query}" (${observations.length} obs, ${sessions.length} sessions, ${prompts.length} prompts):\n\n`;
|
||||
const formattedResults = limitedResults.map((item, i) => {
|
||||
if (item.type === 'observation') {
|
||||
return this.formatter.formatObservationIndex(item.data, i);
|
||||
@@ -258,7 +258,7 @@ export class SearchManager {
|
||||
return this.formatter.formatUserPromptIndex(item.data, i);
|
||||
}
|
||||
});
|
||||
combinedText = header + formattedResults.join('\n\n') + this.formatter.formatSearchTips();
|
||||
combinedText = header + formattedResults.join('\n\n');
|
||||
} else {
|
||||
const formattedResults = limitedResults.map(item => {
|
||||
if (item.type === 'observation') {
|
||||
@@ -688,7 +688,7 @@ export class SearchManager {
|
||||
|
||||
let combinedText: string;
|
||||
if (format === 'index') {
|
||||
const header = `Found ${results.length} decision(s):\n\n`;
|
||||
const header = ` ⎿ Found ${results.length} decision(s):\n\n`;
|
||||
const formattedResults = results.map((obs, i) => this.formatter.formatObservationIndex(obs, i));
|
||||
combinedText = header + formattedResults.join('\n\n');
|
||||
} else {
|
||||
@@ -786,7 +786,7 @@ export class SearchManager {
|
||||
|
||||
let combinedText: string;
|
||||
if (format === 'index') {
|
||||
const header = `Found ${results.length} change-related observation(s):\n\n`;
|
||||
const header = ` ⎿ Found ${results.length} change-related observation(s):\n\n`;
|
||||
const formattedResults = results.map((obs, i) => this.formatter.formatObservationIndex(obs, i));
|
||||
combinedText = header + formattedResults.join('\n\n');
|
||||
} else {
|
||||
@@ -862,7 +862,7 @@ export class SearchManager {
|
||||
|
||||
let combinedText: string;
|
||||
if (format === 'index') {
|
||||
const header = `Found ${results.length} "how it works" observation(s):\n\n`;
|
||||
const header = ` ⎿ Found ${results.length} "how it works" observation(s):\n\n`;
|
||||
const formattedResults = results.map((obs, i) => this.formatter.formatObservationIndex(obs, i));
|
||||
combinedText = header + formattedResults.join('\n\n');
|
||||
} else {
|
||||
@@ -939,9 +939,9 @@ export class SearchManager {
|
||||
// Format based on requested format
|
||||
let combinedText: string;
|
||||
if (format === 'index') {
|
||||
const header = `Found ${results.length} observation(s) matching "${query}":\n\n`;
|
||||
const header = ` ⎿ Found ${results.length} observation(s) matching "${query}":\n\n`;
|
||||
const formattedResults = results.map((obs, i) => this.formatter.formatObservationIndex(obs, i));
|
||||
combinedText = header + formattedResults.join('\n\n') + this.formatter.formatSearchTips();
|
||||
combinedText = header + formattedResults.join('\n\n');
|
||||
} else {
|
||||
const formattedResults = results.map((obs) => this.formatter.formatObservationResult(obs));
|
||||
combinedText = formattedResults.join('\n\n---\n\n');
|
||||
@@ -1016,9 +1016,9 @@ export class SearchManager {
|
||||
// Format based on requested format
|
||||
let combinedText: string;
|
||||
if (format === 'index') {
|
||||
const header = `Found ${results.length} session(s) matching "${query}":\n\n`;
|
||||
const header = ` ⎿ Found ${results.length} session(s) matching "${query}":\n\n`;
|
||||
const formattedResults = results.map((session, i) => this.formatter.formatSessionIndex(session, i));
|
||||
combinedText = header + formattedResults.join('\n\n') + this.formatter.formatSearchTips();
|
||||
combinedText = header + formattedResults.join('\n\n');
|
||||
} else {
|
||||
const formattedResults = results.map((session) => this.formatter.formatSessionResult(session));
|
||||
combinedText = formattedResults.join('\n\n---\n\n');
|
||||
@@ -1093,9 +1093,9 @@ export class SearchManager {
|
||||
// Format based on requested format
|
||||
let combinedText: string;
|
||||
if (format === 'index') {
|
||||
const header = `Found ${results.length} user prompt(s) matching "${query}":\n\n`;
|
||||
const header = ` ⎿ Found ${results.length} user prompt(s) matching "${query}":\n\n`;
|
||||
const formattedResults = results.map((prompt, i) => this.formatter.formatUserPromptIndex(prompt, i));
|
||||
combinedText = header + formattedResults.join('\n\n') + this.formatter.formatSearchTips();
|
||||
combinedText = header + formattedResults.join('\n\n');
|
||||
} else {
|
||||
const formattedResults = results.map((prompt) => this.formatter.formatUserPromptResult(prompt));
|
||||
combinedText = formattedResults.join('\n\n---\n\n');
|
||||
@@ -1182,9 +1182,9 @@ export class SearchManager {
|
||||
// Format based on requested format
|
||||
let combinedText: string;
|
||||
if (format === 'index') {
|
||||
const header = `Found ${results.length} observation(s) with concept "${concept}":\n\n`;
|
||||
const header = ` ⎿ Found ${results.length} observation(s) with concept "${concept}":\n\n`;
|
||||
const formattedResults = results.map((obs, i) => this.formatter.formatObservationIndex(obs, i));
|
||||
combinedText = header + formattedResults.join('\n\n') + this.formatter.formatSearchTips();
|
||||
combinedText = header + formattedResults.join('\n\n');
|
||||
} else {
|
||||
const formattedResults = results.map((obs) => this.formatter.formatObservationResult(obs));
|
||||
combinedText = formattedResults.join('\n\n---\n\n');
|
||||
@@ -1279,7 +1279,7 @@ export class SearchManager {
|
||||
|
||||
let combinedText: string;
|
||||
if (format === 'index') {
|
||||
const header = `Found ${totalResults} result(s) for file "${filePath}":\n\n`;
|
||||
const header = ` ⎿ Found ${totalResults} result(s) for file "${filePath}":\n\n`;
|
||||
const formattedResults: string[] = [];
|
||||
|
||||
// Add observations
|
||||
@@ -1292,7 +1292,7 @@ export class SearchManager {
|
||||
formattedResults.push(this.formatter.formatSessionIndex(session, i + observations.length));
|
||||
});
|
||||
|
||||
combinedText = header + formattedResults.join('\n\n') + this.formatter.formatSearchTips();
|
||||
combinedText = header + formattedResults.join('\n\n');
|
||||
} else {
|
||||
const formattedResults: string[] = [];
|
||||
|
||||
@@ -1391,9 +1391,9 @@ export class SearchManager {
|
||||
// Format based on requested format
|
||||
let combinedText: string;
|
||||
if (format === 'index') {
|
||||
const header = `Found ${results.length} observation(s) with type "${typeStr}":\n\n`;
|
||||
const header = ` ⎿ Found ${results.length} observation(s) with type "${typeStr}":\n\n`;
|
||||
const formattedResults = results.map((obs, i) => this.formatter.formatObservationIndex(obs, i));
|
||||
combinedText = header + formattedResults.join('\n\n') + this.formatter.formatSearchTips();
|
||||
combinedText = header + formattedResults.join('\n\n');
|
||||
} else {
|
||||
const formattedResults = results.map((obs) => this.formatter.formatObservationResult(obs));
|
||||
combinedText = formattedResults.join('\n\n---\n\n');
|
||||
|
||||
Reference in New Issue
Block a user