@hanhnd/agent-kit 1.0.38 → 1.0.40

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.
@@ -1,29 +1,33 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { z } from 'zod';
4
- import { Embedder } from '../services/memory/embedder.js';
5
- import { MemoryIndexer } from '../services/memory/indexer.js';
6
- import { MemoryStore } from '../services/memory/store.js';
4
+ import { createMemorySubsystem, } from '../services/memory/subsystem.js';
7
5
  import { SOURCE_TYPES } from '../services/memory/types.js';
8
6
  import { initializeConversationDigestModel } from '../services/digest/processor.js';
9
7
  import { DEFAULT_DIGEST_MODEL_ID } from '../services/digest/constants.js';
10
8
  import { formatError, mcpJson, mcpText } from '../utils/utils.js';
11
- import { loadGlobalSettings, resolveConversationDigestConfig, resolveMemoryConfig, } from '../core/config/index.js';
9
+ import { loadGlobalSettings, resolveConversationDigestConfig } from '../core/config/index.js';
12
10
  /**
13
- * Registers tool handlers onto an already-constructed indexer/store pair.
11
+ * Registers tool handlers against the current memory subsystem state.
14
12
  */
15
- function registerMemoryToolHandlers(server, indexer, store, config, workspaceRoot = process.cwd()) {
13
+ function registerMemoryToolHandlers(server, subsystem, workspaceRoot = process.cwd()) {
14
+ const { config } = subsystem;
16
15
  server.tool('kit_memory_search', 'Search persistent memory for factual or semantic matches (decisions, concepts, entities). Extract concise keywords only, removing stopwords and filler words from the user request before querying. Use kit_memory_recent for temporal or recency questions.', {
17
16
  query: z.string().min(1).describe('Keyword-only search query with stopwords removed'),
18
17
  top_k: z.number().int().positive().optional().describe('Number of results to return'),
19
18
  }, async ({ query, top_k }) => {
20
19
  try {
20
+ if (!subsystem.indexer || !subsystem.store) {
21
+ return mcpText(formatInitializationFailure(subsystem));
22
+ }
23
+ const { indexer, store } = subsystem;
21
24
  const results = await indexer.search(query, top_k ?? config.topK);
25
+ const lifecycleNote = formatLifecycleNote(subsystem);
22
26
  const degradedNote = !store.vecAvailable
23
27
  ? '⚠️ Vector search unavailable — showing keyword-only results.\n\n'
24
28
  : '';
25
29
  if (results.length === 0) {
26
- return mcpText(`${degradedNote}No memories found for query: "${query}"`);
30
+ return mcpText(`${lifecycleNote}${degradedNote}No memories found for query: "${query}"`);
27
31
  }
28
32
  const formatted = results
29
33
  .map((r) => {
@@ -34,7 +38,7 @@ function registerMemoryToolHandlers(server, indexer, store, config, workspaceRoo
34
38
  return `### ${displaySource} (score: ${r.score.toFixed(3)})\n${content}`;
35
39
  })
36
40
  .join('\n\n---\n\n');
37
- return mcpText(`${degradedNote}${formatted}`);
41
+ return mcpText(`${lifecycleNote}${degradedNote}${formatted}`);
38
42
  }
39
43
  catch (err) {
40
44
  return mcpText(`kit_memory_search failed: ${formatError(err)}`);
@@ -45,13 +49,17 @@ function registerMemoryToolHandlers(server, indexer, store, config, workspaceRoo
45
49
  source_type: z.enum(SOURCE_TYPES).optional().describe('Optional source type filter'),
46
50
  }, async ({ n, source_type }) => {
47
51
  try {
52
+ if (!subsystem.store) {
53
+ return mcpText(formatInitializationFailure(subsystem));
54
+ }
55
+ const store = subsystem.store;
48
56
  const rows = store.getRecentSources({ limit: n ?? 5, sourceType: source_type });
49
57
  if (rows.length === 0)
50
58
  return mcpText('No recent sources found.');
51
59
  const blocks = [];
52
60
  for (const row of rows) {
53
61
  try {
54
- const content = fs.readFileSync(path.join(config.wikiDir, row.source), 'utf8');
62
+ const content = await fs.promises.readFile(path.join(config.wikiDir, row.source), 'utf8');
55
63
  const displaySource = row.source.replace(/^compiled\//, '');
56
64
  blocks.push(`### ${displaySource}\n${content}`);
57
65
  }
@@ -71,6 +79,13 @@ function registerMemoryToolHandlers(server, indexer, store, config, workspaceRoo
71
79
  content: z.string().min(1).describe('Content to save to memory'),
72
80
  }, async ({ content }) => {
73
81
  try {
82
+ if (!subsystem.indexer) {
83
+ return mcpJson({
84
+ saved: false,
85
+ error: formatInitializationFailure(subsystem),
86
+ });
87
+ }
88
+ const indexer = subsystem.indexer;
74
89
  await indexer.save(content);
75
90
  return mcpJson({
76
91
  saved: true,
@@ -109,22 +124,31 @@ function registerMemoryToolHandlers(server, indexer, store, config, workspaceRoo
109
124
  }
110
125
  });
111
126
  }
127
+ function formatLifecycleNote(subsystem) {
128
+ if (subsystem.status.state === 'warming' || subsystem.status.state === 'initializing') {
129
+ return '⚠️ Memory index is warming — results may be stale until startup indexing completes.\n\n';
130
+ }
131
+ if (subsystem.status.state === 'degraded') {
132
+ return `⚠️ Memory index is degraded${subsystem.status.error ? `: ${subsystem.status.error}` : ''}.\n\n`;
133
+ }
134
+ return '';
135
+ }
136
+ function formatInitializationFailure(subsystem) {
137
+ const detail = subsystem.status.error ? `: ${subsystem.status.error}` : '';
138
+ return `Memory initialization failed${detail}`;
139
+ }
112
140
  /**
113
141
  * Initializes the memory subsystem and registers all memory tools.
114
- * Returns the MemoryIndexer so the caller can fire startupIndex() after server.connect().
142
+ * Returns the MemorySubsystem so the caller can fire startWarmup() after server.connect().
115
143
  * Returns null when memory is disabled (settings.memory.enabled !== true).
116
144
  */
117
145
  export function registerMemoryTools(server, workspaceRoot, overrides) {
118
146
  const settings = overrides?.settings ?? loadGlobalSettings();
119
147
  if (settings.memory?.enabled !== true)
120
148
  return null;
121
- const config = overrides?.config ?? resolveMemoryConfig(settings, workspaceRoot);
122
- const store = overrides?.store ?? new MemoryStore(path.join(config.wikiDir, 'index.db'), config);
123
- const indexer = overrides?.indexer ??
124
- (() => {
125
- const embedder = new Embedder(config.embeddingModel);
126
- return new MemoryIndexer(store, embedder, config);
127
- })();
128
- registerMemoryToolHandlers(server, indexer, store, config, workspaceRoot);
129
- return indexer;
149
+ const subsystem = createMemorySubsystem(workspaceRoot, { ...overrides, settings });
150
+ if (!subsystem)
151
+ return null;
152
+ registerMemoryToolHandlers(server, subsystem, workspaceRoot);
153
+ return subsystem;
130
154
  }