@j0hanz/memory-mcp 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/db/index.js +16 -13
  2. package/dist/lib/errors.d.ts +4 -0
  3. package/dist/lib/errors.js +11 -0
  4. package/dist/lib/graph-traversal.d.ts +12 -0
  5. package/dist/lib/graph-traversal.js +145 -0
  6. package/dist/lib/json-schema.d.ts +5 -0
  7. package/dist/lib/json-schema.js +19 -1
  8. package/dist/lib/pagination.d.ts +0 -2
  9. package/dist/lib/pagination.js +0 -43
  10. package/dist/lib/search.js +44 -23
  11. package/dist/lib/tool-contracts.js +50 -73
  12. package/dist/lib/tool-execution.d.ts +13 -0
  13. package/dist/lib/tool-execution.js +51 -0
  14. package/dist/prompts/index.js +12 -8
  15. package/dist/resources/index.js +67 -43
  16. package/dist/resources/instructions.js +44 -37
  17. package/dist/resources/server-config.js +33 -22
  18. package/dist/resources/tool-catalog.js +2 -6
  19. package/dist/resources/tool-info.js +9 -9
  20. package/dist/resources/workflows.js +69 -40
  21. package/dist/schemas/inputs.d.ts +8 -5
  22. package/dist/schemas/inputs.js +57 -40
  23. package/dist/schemas/outputs.d.ts +6 -6
  24. package/dist/schemas/outputs.js +7 -6
  25. package/dist/server.js +11 -4
  26. package/dist/tools/create-relationship.js +17 -22
  27. package/dist/tools/delete-memories.js +30 -39
  28. package/dist/tools/delete-memory.js +14 -18
  29. package/dist/tools/delete-relationship.js +9 -24
  30. package/dist/tools/get-memory.js +12 -17
  31. package/dist/tools/get-relationships.js +11 -12
  32. package/dist/tools/memory-stats.js +22 -30
  33. package/dist/tools/progress.d.ts +6 -0
  34. package/dist/tools/progress.js +68 -25
  35. package/dist/tools/recall.js +94 -203
  36. package/dist/tools/register-contract.d.ts +1 -2
  37. package/dist/tools/register-contract.js +4 -2
  38. package/dist/tools/result.d.ts +4 -0
  39. package/dist/tools/result.js +27 -0
  40. package/dist/tools/retrieve-context.js +80 -98
  41. package/dist/tools/search-memories.js +31 -34
  42. package/dist/tools/store-memories.js +33 -44
  43. package/dist/tools/store-memory.js +13 -20
  44. package/dist/tools/update-memory.js +45 -49
  45. package/package.json +1 -1
@@ -0,0 +1,51 @@
1
+ import { McpError } from '@modelcontextprotocol/sdk/types.js';
2
+ import { CancelledError, E_CANCELLED, E_UNKNOWN, getErrorMessage, rethrowMcpError, } from './errors.js';
3
+ import { createErrorResponse } from './tool-response.js';
4
+ export async function executeToolSafely(work) {
5
+ try {
6
+ return await work();
7
+ }
8
+ catch (err) {
9
+ rethrowMcpError(err);
10
+ return createErrorResponse(E_UNKNOWN, getErrorMessage(err));
11
+ }
12
+ }
13
+ export function summarizeBatch(items, isMatched) {
14
+ let succeeded = 0;
15
+ let matched = 0;
16
+ for (const item of items) {
17
+ if (item.ok) {
18
+ succeeded += 1;
19
+ }
20
+ if (isMatched(item)) {
21
+ matched += 1;
22
+ }
23
+ }
24
+ return {
25
+ succeeded,
26
+ failed: items.length - succeeded,
27
+ matched,
28
+ };
29
+ }
30
+ export async function executeLongRunningToolSafely(work, onFinally) {
31
+ let result;
32
+ let thrownError;
33
+ try {
34
+ result = await work();
35
+ }
36
+ catch (err) {
37
+ if (err instanceof CancelledError) {
38
+ result = createErrorResponse(E_CANCELLED, 'Request cancelled');
39
+ }
40
+ else if (err instanceof McpError) {
41
+ thrownError = err;
42
+ }
43
+ else {
44
+ result = createErrorResponse(E_UNKNOWN, getErrorMessage(err));
45
+ }
46
+ }
47
+ if (onFinally) {
48
+ await onFinally();
49
+ }
50
+ return result ?? createErrorResponse(E_UNKNOWN, getErrorMessage(thrownError));
51
+ }
@@ -1,5 +1,10 @@
1
1
  import { loadInstructions } from '../lib/instructions.js';
2
2
  const INSTRUCTIONS_CONTENT = loadInstructions();
3
+ const GET_HELP_PROMPT = {
4
+ name: 'get-help',
5
+ title: 'Get Help',
6
+ description: 'Return full usage instructions.',
7
+ };
3
8
  function createHelpMessages(instructions) {
4
9
  return [
5
10
  {
@@ -19,13 +24,12 @@ function createHelpMessages(instructions) {
19
24
  ];
20
25
  }
21
26
  const HELP_MESSAGES = createHelpMessages(INSTRUCTIONS_CONTENT);
22
- const GET_HELP_PROMPT_NAME = 'get-help';
23
- const GET_HELP_PROMPT_CONFIG = {
24
- title: 'Get Help',
25
- description: 'Return full usage instructions.',
26
- };
27
+ function createGetHelpPromptResult() {
28
+ return { messages: HELP_MESSAGES };
29
+ }
27
30
  export function registerAllPrompts(server) {
28
- server.registerPrompt(GET_HELP_PROMPT_NAME, GET_HELP_PROMPT_CONFIG, () => ({
29
- messages: HELP_MESSAGES,
30
- }));
31
+ server.registerPrompt(GET_HELP_PROMPT.name, {
32
+ title: GET_HELP_PROMPT.title,
33
+ description: GET_HELP_PROMPT.description,
34
+ }, createGetHelpPromptResult);
31
35
  }
@@ -44,6 +44,13 @@ function createResourceAnnotations(audience, priority) {
44
44
  function getSingleVariable(value) {
45
45
  return Array.isArray(value) ? value[0] : value;
46
46
  }
47
+ function requireValidMemoryHash(variables) {
48
+ const hash = getSingleVariable(variables['hash']);
49
+ if (!hash || !HASH_REGEX.test(hash)) {
50
+ throw new McpError(ErrorCode.InvalidParams, 'Invalid hash: must be a 64-character hex string');
51
+ }
52
+ return hash;
53
+ }
47
54
  function requireSingleVariable(variables, key, errorMessage) {
48
55
  const value = getSingleVariable(variables[key]);
49
56
  if (!value) {
@@ -51,6 +58,13 @@ function requireSingleVariable(variables, key, errorMessage) {
51
58
  }
52
59
  return value;
53
60
  }
61
+ function requireKnownToolInfo(toolName) {
62
+ const info = getToolInfo(toolName);
63
+ if (!info) {
64
+ throw new McpError(ErrorCode.InvalidParams, `Unknown tool: ${toolName}`);
65
+ }
66
+ return info;
67
+ }
54
68
  function registerStaticMarkdownResource(server, config) {
55
69
  server.registerResource(config.name, config.uri, {
56
70
  title: config.title,
@@ -90,70 +104,75 @@ const INSTRUCTIONS_CONTENT = loadInstructions();
90
104
  const TOOL_CATALOG_CONTENT = buildToolCatalog();
91
105
  const WORKFLOW_GUIDE_CONTENT = buildWorkflowGuide();
92
106
  const SERVER_CONFIG_CONTENT = buildServerConfig();
93
- // --- Registration ---
94
- export function registerAllResources(server, db) {
95
- // internal://instructions
96
- registerStaticMarkdownResource(server, {
107
+ const STATIC_CONTENT_BY_KEY = {
108
+ instructions: INSTRUCTIONS_CONTENT,
109
+ toolCatalog: TOOL_CATALOG_CONTENT,
110
+ workflows: WORKFLOW_GUIDE_CONTENT,
111
+ serverConfig: SERVER_CONFIG_CONTENT,
112
+ };
113
+ const STATIC_RESOURCE_SEEDS = [
114
+ {
97
115
  name: 'instructions',
98
116
  uri: INSTRUCTIONS_URI,
99
117
  title: 'Memory Instructions',
100
118
  description: 'Complete usage guide: tool inventory, routing decisions, error codes, data model, and workflow patterns. Read this first.',
101
119
  audience: ['assistant'],
102
120
  priority: 0.9,
103
- content: INSTRUCTIONS_CONTENT,
104
- });
105
- // internal://tool-catalog
106
- registerStaticMarkdownResource(server, {
121
+ contentKey: 'instructions',
122
+ },
123
+ {
107
124
  name: 'tool-catalog',
108
125
  uri: TOOL_CATALOG_URI,
109
126
  title: 'Tool Catalog',
110
127
  description: 'Tool reference table, optional parameter matrix, and cross-tool data flow.',
111
128
  audience: ['assistant'],
112
129
  priority: 0.7,
113
- content: TOOL_CATALOG_CONTENT,
114
- });
115
- // internal://tool-info/{toolName}
116
- server.registerResource('tool-info', new ResourceTemplate(TOOL_INFO_URI_TEMPLATE, {
117
- list: () => listToolInfoResources(),
118
- complete: {
119
- toolName: (value) => TOOL_NAMES.filter((n) => n.startsWith(value)),
120
- },
121
- }), {
122
- title: 'Tool Info',
123
- description: 'Per-tool detail: parameters, behavior, and output shape. Supports toolName auto-completion.',
124
- mimeType: 'text/markdown',
125
- annotations: createResourceAnnotations(['assistant'], 0.6),
126
- }, (uri, variables) => {
127
- const toolName = requireSingleVariable(variables, 'toolName', 'Missing toolName parameter');
128
- const info = getToolInfo(toolName);
129
- if (!info) {
130
- throw new McpError(ErrorCode.InvalidParams, `Unknown tool: ${toolName}`);
131
- }
132
- return {
133
- contents: [createMarkdownContent(uri.href, info)],
134
- };
135
- });
136
- // internal://workflows
137
- registerStaticMarkdownResource(server, {
130
+ contentKey: 'toolCatalog',
131
+ },
132
+ {
138
133
  name: 'workflows',
139
134
  uri: WORKFLOWS_URI,
140
135
  title: 'Workflow Guide',
141
136
  description: 'Recommended multi-step workflow sequences with guardrails and tool reference.',
142
137
  audience: ['assistant'],
143
138
  priority: 0.7,
144
- content: WORKFLOW_GUIDE_CONTENT,
145
- });
146
- // internal://server-config
147
- registerStaticMarkdownResource(server, {
139
+ contentKey: 'workflows',
140
+ },
141
+ {
148
142
  name: 'server-config',
149
143
  uri: SERVER_CONFIG_URI,
150
144
  title: 'Server Configuration',
151
145
  description: 'Runtime configuration, environment variables, capabilities, and data limits.',
152
146
  audience: ['user', 'assistant'],
153
147
  priority: 0.5,
154
- content: SERVER_CONFIG_CONTENT,
148
+ contentKey: 'serverConfig',
149
+ },
150
+ ];
151
+ function getStaticMarkdownResources() {
152
+ return STATIC_RESOURCE_SEEDS.map((seed) => ({
153
+ ...seed,
154
+ content: STATIC_CONTENT_BY_KEY[seed.contentKey],
155
+ }));
156
+ }
157
+ function completeToolName(value) {
158
+ return TOOL_NAMES.filter((toolName) => toolName.startsWith(value));
159
+ }
160
+ function registerToolInfoResource(server) {
161
+ server.registerResource('tool-info', new ResourceTemplate(TOOL_INFO_URI_TEMPLATE, {
162
+ list: listToolInfoResources,
163
+ complete: { toolName: completeToolName },
164
+ }), {
165
+ title: 'Tool Info',
166
+ description: 'Per-tool detail: parameters, behavior, and output shape. Supports toolName auto-completion.',
167
+ mimeType: 'text/markdown',
168
+ annotations: createResourceAnnotations(['assistant'], 0.6),
169
+ }, (uri, variables) => {
170
+ const toolName = requireSingleVariable(variables, 'toolName', 'Missing toolName parameter');
171
+ const info = requireKnownToolInfo(toolName);
172
+ return { contents: [createMarkdownContent(uri.href, info)] };
155
173
  });
156
- // memory://memories/{hash}
174
+ }
175
+ function registerMemoryResource(server, db) {
157
176
  const hashCompletion = createHashCompletionCallback(db);
158
177
  server.registerResource('memory', new ResourceTemplate(MEMORY_RESOURCE_URI_TEMPLATE, {
159
178
  list: () => listMemoryResources(db),
@@ -164,10 +183,7 @@ export function registerAllResources(server, db) {
164
183
  mimeType: 'application/json',
165
184
  annotations: createResourceAnnotations(['assistant'], 0.7),
166
185
  }, (uri, variables) => {
167
- const hash = getSingleVariable(variables['hash']);
168
- if (!hash || !HASH_REGEX.test(hash)) {
169
- throw new McpError(ErrorCode.InvalidParams, 'Invalid hash: must be a 64-character hex string');
170
- }
186
+ const hash = requireValidMemoryHash(variables);
171
187
  const row = readMemoryByHash(db, hash);
172
188
  if (!row) {
173
189
  return createErrorResourceContents(uri.href, 'Not found', hash);
@@ -177,3 +193,11 @@ export function registerAllResources(server, db) {
177
193
  };
178
194
  });
179
195
  }
196
+ // --- Registration ---
197
+ export function registerAllResources(server, db) {
198
+ for (const config of getStaticMarkdownResources()) {
199
+ registerStaticMarkdownResource(server, config);
200
+ }
201
+ registerToolInfoResource(server);
202
+ registerMemoryResource(server, db);
203
+ }
@@ -63,42 +63,49 @@ function renderSharedConstraints() {
63
63
  .map((c) => `- ${c}`)
64
64
  .join('\n');
65
65
  }
66
- export function buildServerInstructions() {
66
+ function renderTaggedSection(section) {
67
+ return [`<${section.tag}>`, section.content, `</${section.tag}>`].join('\n');
68
+ }
69
+ function buildTaggedSections() {
67
70
  return [
68
- '<role>',
69
- 'Memory MCP: Persistent memory storage, full-text retrieval, and relationship graph traversal.',
70
- '</role>',
71
- '',
72
- '<capabilities>',
73
- buildToolRouting(),
74
- '</capabilities>',
75
- '',
76
- '<constraints>',
77
- renderSharedConstraints(),
78
- '</constraints>',
79
- '',
80
- '<error_codes>',
81
- ERROR_CODES.join('\n'),
82
- '</error_codes>',
83
- '',
84
- '<error_result_conventions>',
85
- ERROR_RESULT_CONVENTIONS.join('\n'),
86
- '</error_result_conventions>',
87
- '',
88
- '<data_model>',
89
- DATA_MODEL,
90
- '</data_model>',
91
- '',
92
- '<workflows>',
93
- WORKFLOWS,
94
- '</workflows>',
95
- '',
96
- '<prompts>',
97
- PROMPTS_INVENTORY.join('\n'),
98
- '</prompts>',
99
- '',
100
- '<resources>',
101
- RESOURCES_INVENTORY.join('\n'),
102
- '</resources>',
103
- ].join('\n');
71
+ {
72
+ tag: 'role',
73
+ content: 'Memory MCP: Persistent memory storage, full-text retrieval, and relationship graph traversal.',
74
+ },
75
+ {
76
+ tag: 'capabilities',
77
+ content: buildToolRouting(),
78
+ },
79
+ {
80
+ tag: 'constraints',
81
+ content: renderSharedConstraints(),
82
+ },
83
+ {
84
+ tag: 'error_codes',
85
+ content: ERROR_CODES.join('\n'),
86
+ },
87
+ {
88
+ tag: 'error_result_conventions',
89
+ content: ERROR_RESULT_CONVENTIONS.join('\n'),
90
+ },
91
+ {
92
+ tag: 'data_model',
93
+ content: DATA_MODEL,
94
+ },
95
+ {
96
+ tag: 'workflows',
97
+ content: WORKFLOWS,
98
+ },
99
+ {
100
+ tag: 'prompts',
101
+ content: PROMPTS_INVENTORY.join('\n'),
102
+ },
103
+ {
104
+ tag: 'resources',
105
+ content: RESOURCES_INVENTORY.join('\n'),
106
+ },
107
+ ];
108
+ }
109
+ export function buildServerInstructions() {
110
+ return buildTaggedSections().map(renderTaggedSection).join('\n\n');
104
111
  }
@@ -46,32 +46,43 @@ const CAPABILITIES = [
46
46
  function toEnvVarRow(v) {
47
47
  return `| \`${v.name}\` | ${v.default} | ${v.range} | ${v.purpose} |`;
48
48
  }
49
- function toRangeRow(label, range) {
50
- return `| ${label} | ${range} |`;
49
+ function toTwoColumnRow(label, value) {
50
+ return `| ${label} | ${value} |`;
51
51
  }
52
- export function buildServerConfig() {
53
- const envRows = ENV_VARS.map(toEnvVarRow);
54
- const limitRows = DATA_LIMITS.map((l) => toRangeRow(l.dimension, l.range));
55
- const capRows = CAPABILITIES.map((c) => toRangeRow(c.capability, c.status));
52
+ function renderTableSection(section) {
56
53
  return [
57
- '# Server Configuration',
58
- '',
59
- '## Environment Variables',
60
- '',
61
- '| Variable | Default | Range | Purpose |',
62
- '|----------|---------|-------|---------|',
63
- ...envRows,
64
- '',
65
- '## Capabilities',
54
+ `## ${section.title}`,
66
55
  '',
67
- '| Capability | Status |',
68
- '|------------|--------|',
69
- ...capRows,
56
+ section.header,
57
+ section.separator,
58
+ ...section.rows,
70
59
  '',
71
- '## Data Limits',
60
+ ];
61
+ }
62
+ export function buildServerConfig() {
63
+ const sections = [
64
+ {
65
+ title: 'Environment Variables',
66
+ header: '| Variable | Default | Range | Purpose |',
67
+ separator: '|----------|---------|-------|---------|',
68
+ rows: ENV_VARS.map(toEnvVarRow),
69
+ },
70
+ {
71
+ title: 'Capabilities',
72
+ header: '| Capability | Status |',
73
+ separator: '|------------|--------|',
74
+ rows: CAPABILITIES.map((c) => toTwoColumnRow(c.capability, c.status)),
75
+ },
76
+ {
77
+ title: 'Data Limits',
78
+ header: '| Dimension | Range |',
79
+ separator: '|-----------|-------|',
80
+ rows: DATA_LIMITS.map((l) => toTwoColumnRow(l.dimension, l.range)),
81
+ },
82
+ ];
83
+ return [
84
+ '# Server Configuration',
72
85
  '',
73
- '| Dimension | Range |',
74
- '|-----------|-------|',
75
- ...limitRows,
86
+ ...sections.flatMap(renderTableSection),
76
87
  ].join('\n');
77
88
  }
@@ -1,12 +1,8 @@
1
- import { extractJsonSchema, } from '../lib/json-schema.js';
1
+ import { getSchemaMeta } from '../lib/json-schema.js';
2
2
  import { getToolContracts } from '../lib/tool-contracts.js';
3
3
  import { buildCoreContextPack } from './tool-info.js';
4
4
  function extractOptionalParams(toolName, schema) {
5
- const jsonSchema = extractJsonSchema(schema);
6
- const properties = (jsonSchema['properties'] ?? {});
7
- const requiredFields = new Set(Array.isArray(jsonSchema['required'])
8
- ? jsonSchema['required']
9
- : []);
5
+ const { properties, requiredFields } = getSchemaMeta(schema);
10
6
  const rows = [];
11
7
  for (const [name, prop] of Object.entries(properties).sort(([a], [b]) => a.localeCompare(b))) {
12
8
  if (requiredFields.has(name))
@@ -1,4 +1,4 @@
1
- import { extractJsonSchema, } from '../lib/json-schema.js';
1
+ import { extractJsonSchema, getSchemaMeta, } from '../lib/json-schema.js';
2
2
  import { getToolContracts } from '../lib/tool-contracts.js';
3
3
  // --- Shared Constraints (Single Source of Truth) ---
4
4
  const SHARED_CONSTRAINTS = [
@@ -61,6 +61,12 @@ function formatParamConstraints(prop) {
61
61
  parts.push(`enum: ${prop['enum'].join(' | ')}`);
62
62
  return parts.length > 0 ? `; ${parts.join(', ')}` : '';
63
63
  }
64
+ function getSortedSchemaProperties(properties) {
65
+ return Object.entries(properties).sort(([a], [b]) => a.localeCompare(b));
66
+ }
67
+ function formatParamLines(meta) {
68
+ return getSortedSchemaProperties(meta.properties).map(([pName, pSchema]) => formatParam(pName, pSchema, meta.requiredFields.has(pName)));
69
+ }
64
70
  function formatParam(name, prop, required) {
65
71
  const type = typeof prop['type'] === 'string' ? prop['type'] : 'unknown';
66
72
  const desc = typeof prop['description'] === 'string' ? prop['description'] : '';
@@ -87,14 +93,8 @@ export function getToolInfo(name) {
87
93
  const contract = getToolContracts().find((c) => c.name === name);
88
94
  if (!contract)
89
95
  return undefined;
90
- const inputSchema = extractJsonSchema(contract.inputSchema);
91
- const properties = (inputSchema['properties'] ?? {});
92
- const requiredFields = new Set(Array.isArray(inputSchema['required'])
93
- ? inputSchema['required']
94
- : []);
95
- const paramLines = Object.entries(properties)
96
- .sort(([a], [b]) => a.localeCompare(b))
97
- .map(([pName, pSchema]) => formatParam(pName, pSchema, requiredFields.has(pName)));
96
+ const inputMeta = getSchemaMeta(contract.inputSchema);
97
+ const paramLines = formatParamLines(inputMeta);
98
98
  const behaviorLine = formatBehavior(contract.annotations);
99
99
  const outputShape = formatOutputShape(contract.outputSchema);
100
100
  return [
@@ -1,53 +1,82 @@
1
1
  import { getSharedConstraints } from './tool-info.js';
2
- const WORKFLOW_TRACKS = `## Workflow A: Store and Link
3
-
4
- 1. \`store_memories({ items: [...] })\` → \`{ items[].hash, succeeded, failed }\`
5
- 2. \`create_relationship({ from_hash, to_hash, relation_type })\` × N
6
-
7
- > Constraint: Both endpoint memories must exist before creating a relationship.
8
-
9
- ## Workflow B: Search and Read
10
-
11
- 1. \`search_memories({ query, limit })\` → \`{ memories[], nextCursor }\`
12
- 2. \`get_memory({ hash })\` for full detail on a specific result
13
-
14
- > Or use \`recall({ query, depth: 1 })\` → \`{ memories[], graph[] }\` to follow relationships.
15
-
16
- ## Workflow C: Fill Context Window
17
-
18
- 1. \`retrieve_context({ query, token_budget: 4000, strategy: 'relevance' })\` → \`{ memories[], estimated_tokens, truncated }\`
19
-
20
- > Use \`strategy\` to control sort: \`relevance\` (FTS rank), \`importance\` (highest first), or \`recency\` (newest first).
21
-
22
- ## Workflow D: Update a Memory
23
-
24
- 1. \`update_memory({ hash, content })\` → \`{ old_hash, new_hash }\`
25
-
26
- > Existing relationships auto-update to new_hash via CASCADE.
27
- > Returns E_CONFLICT if the new content+tags already maps to an existing hash.
28
-
29
- ## Workflow E: Batch Delete
30
-
31
- 1. \`delete_memories({ hashes: [...] })\` → \`{ items[].{ hash, deleted }, succeeded, failed }\`
32
-
33
- > \`deleted: false\` means hash not found — not an error, the batch still succeeds.
34
-
35
- ## Workflow F: Explore Graph
36
-
37
- 1. \`recall({ query, depth: 2 })\` \`{ memories[], graph[], depth_reached, aborted }\`
38
- 2. \`get_relationships({ hash, direction: 'both' })\` for a specific memory's edges
39
-
40
- > BFS traversal emits progress per hop. Use \`depth: 0\` to skip traversal.`;
2
+ const WORKFLOW_TRACKS = [
3
+ {
4
+ title: 'Workflow A: Store and Link',
5
+ steps: [
6
+ '`store_memories({ items: [...] })` → `{ items[].hash, succeeded, failed }`',
7
+ '`create_relationship({ from_hash, to_hash, relation_type })` × N',
8
+ ],
9
+ notes: [
10
+ 'Constraint: Both endpoint memories must exist before creating a relationship.',
11
+ ],
12
+ },
13
+ {
14
+ title: 'Workflow B: Search and Read',
15
+ steps: [
16
+ '`search_memories({ query, limit })` `{ memories[], nextCursor }`',
17
+ '`get_memory({ hash })` for full detail on a specific result',
18
+ ],
19
+ notes: [
20
+ 'Or use `recall({ query, depth: 1 })` `{ memories[], graph[] }` to follow relationships.',
21
+ ],
22
+ },
23
+ {
24
+ title: 'Workflow C: Fill Context Window',
25
+ steps: [
26
+ "`retrieve_context({ query, token_budget: 4000, strategy: 'relevance' })` → `{ memories[], estimated_tokens, truncated }`",
27
+ ],
28
+ notes: [
29
+ 'Use `strategy` to control sort: `relevance` (FTS rank), `importance` (highest first), or `recency` (newest first).',
30
+ ],
31
+ },
32
+ {
33
+ title: 'Workflow D: Update a Memory',
34
+ steps: ['`update_memory({ hash, content })` → `{ old_hash, new_hash }`'],
35
+ notes: [
36
+ 'Existing relationships auto-update to new_hash via CASCADE.',
37
+ 'Returns E_CONFLICT if the new content+tags already maps to an existing hash.',
38
+ ],
39
+ },
40
+ {
41
+ title: 'Workflow E: Batch Delete',
42
+ steps: [
43
+ '`delete_memories({ hashes: [...] })` → `{ items[].{ hash, deleted }, succeeded, failed }`',
44
+ ],
45
+ notes: [
46
+ '`deleted: false` means hash not found - not an error, the batch still succeeds.',
47
+ ],
48
+ },
49
+ {
50
+ title: 'Workflow F: Explore Graph',
51
+ steps: [
52
+ '`recall({ query, depth: 2 })` → `{ memories[], graph[], depth_reached, aborted }`',
53
+ "`get_relationships({ hash, direction: 'both' })` for a specific memory's edges",
54
+ ],
55
+ notes: [
56
+ 'BFS traversal emits progress per hop. Use `depth: 0` to skip traversal.',
57
+ ],
58
+ },
59
+ ];
41
60
  function renderSharedConstraintsSection() {
42
61
  return getSharedConstraints()
43
62
  .map((c) => `- ${c}`)
44
63
  .join('\n');
45
64
  }
65
+ function renderWorkflowTrack(track) {
66
+ const stepLines = track.steps
67
+ .map((step, idx) => `${idx + 1}. ${step}`)
68
+ .join('\n');
69
+ const noteLines = track.notes.map((note) => `> ${note}`).join('\n');
70
+ return [`## ${track.title}`, '', stepLines, '', noteLines].join('\n');
71
+ }
72
+ function renderWorkflowTracks() {
73
+ return WORKFLOW_TRACKS.map(renderWorkflowTrack).join('\n\n');
74
+ }
46
75
  export function buildWorkflowGuide() {
47
76
  return [
48
77
  '# Workflow Reference',
49
78
  '',
50
- WORKFLOW_TRACKS,
79
+ renderWorkflowTracks(),
51
80
  '',
52
81
  '## Shared Constraints',
53
82
  renderSharedConstraintsSection(),
@@ -63,7 +63,7 @@ export declare const GetMemoryInputSchema: z.ZodObject<{
63
63
  }, z.core.$strict>;
64
64
  export declare const UpdateMemoryInputSchema: z.ZodObject<{
65
65
  hash: z.ZodString;
66
- content: z.ZodString;
66
+ content: z.ZodOptional<z.ZodString>;
67
67
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
68
68
  }, z.core.$strict>;
69
69
  export declare const DeleteMemoryInputSchema: z.ZodObject<{
@@ -77,7 +77,7 @@ export declare const SearchMemoriesInputSchema: z.ZodObject<{
77
77
  max_importance: z.ZodOptional<z.ZodNumber>;
78
78
  memory_type: z.ZodOptional<typeof MEMORY_TYPE_SCHEMA>;
79
79
  query: z.ZodString;
80
- limit: z.ZodPrefault<z.ZodOptional<z.ZodInt>>;
80
+ limit: z.ZodPrefault<z.ZodOptional<z.ZodNumber>>;
81
81
  cursor: z.ZodOptional<z.ZodString>;
82
82
  }, z.core.$strict>;
83
83
  export declare const RecallInputSchema: z.ZodObject<{
@@ -85,13 +85,16 @@ export declare const RecallInputSchema: z.ZodObject<{
85
85
  max_importance: z.ZodOptional<z.ZodNumber>;
86
86
  memory_type: z.ZodOptional<typeof MEMORY_TYPE_SCHEMA>;
87
87
  query: z.ZodString;
88
- depth: z.ZodPrefault<z.ZodOptional<z.ZodInt>>;
89
- limit: z.ZodPrefault<z.ZodOptional<z.ZodInt>>;
88
+ depth: z.ZodPrefault<z.ZodOptional<z.ZodNumber>>;
89
+ limit: z.ZodPrefault<z.ZodOptional<z.ZodNumber>>;
90
90
  cursor: z.ZodOptional<z.ZodString>;
91
91
  }, z.core.$strict>;
92
92
  export declare const RetrieveContextInputSchema: z.ZodObject<{
93
+ min_importance: z.ZodOptional<z.ZodNumber>;
94
+ max_importance: z.ZodOptional<z.ZodNumber>;
95
+ memory_type: z.ZodOptional<typeof MEMORY_TYPE_SCHEMA>;
93
96
  query: z.ZodString;
94
- token_budget: z.ZodPrefault<z.ZodOptional<z.ZodInt>>;
97
+ token_budget: z.ZodPrefault<z.ZodOptional<z.ZodNumber>>;
95
98
  strategy: z.ZodPrefault<z.ZodOptional<z.ZodEnum<{
96
99
  importance: "importance";
97
100
  recency: "recency";