@grec0/memory-bank-mcp 0.2.6 → 0.2.8
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.
- package/dist/common/agentBoardSqlite.js +25 -4
- package/dist/common/database.js +23 -1
- package/dist/common/version.js +1 -1
- package/dist/tools/routeTask.js +70 -50
- package/package.json +1 -1
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { databaseManager } from './database.js';
|
|
7
7
|
import * as crypto from 'crypto';
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import * as os from 'os';
|
|
8
11
|
// ============================================================================
|
|
9
12
|
// Agent Board SQLite Implementation
|
|
10
13
|
// ============================================================================
|
|
@@ -20,6 +23,7 @@ export class AgentBoardSqlite {
|
|
|
20
23
|
* Register a new agent for this project.
|
|
21
24
|
* Automatically deactivates any previous active agent.
|
|
22
25
|
* The MCP generates the hash suffix - client only provides base ID.
|
|
26
|
+
* Also syncs project keywords/responsibilities from registry to SQLite.
|
|
23
27
|
*/
|
|
24
28
|
registerAgent(baseAgentId, sessionId) {
|
|
25
29
|
const db = databaseManager.getConnection();
|
|
@@ -29,6 +33,23 @@ export class AgentBoardSqlite {
|
|
|
29
33
|
// Generate session ID if not provided
|
|
30
34
|
const effectiveSessionId = sessionId || crypto.randomUUID();
|
|
31
35
|
const now = new Date().toISOString();
|
|
36
|
+
// Get project metadata from registry (keywords, responsibilities) - sync read
|
|
37
|
+
let keywords = [];
|
|
38
|
+
let responsibilities = [];
|
|
39
|
+
try {
|
|
40
|
+
const registryPath = path.join(os.homedir(), '.memorybank', 'global_registry.json');
|
|
41
|
+
if (fs.existsSync(registryPath)) {
|
|
42
|
+
const registryData = JSON.parse(fs.readFileSync(registryPath, 'utf-8'));
|
|
43
|
+
const project = registryData.projects?.find((p) => p.projectId === this.projectId);
|
|
44
|
+
if (project) {
|
|
45
|
+
keywords = project.keywords || [];
|
|
46
|
+
responsibilities = project.responsibilities || [];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
// Registry not available, continue without metadata
|
|
52
|
+
}
|
|
32
53
|
return databaseManager.transaction(() => {
|
|
33
54
|
// Deactivate any currently active agents for this project
|
|
34
55
|
db.prepare(`
|
|
@@ -36,11 +57,11 @@ export class AgentBoardSqlite {
|
|
|
36
57
|
SET status = 'INACTIVE', last_heartbeat = ?
|
|
37
58
|
WHERE project_id = ? AND status = 'ACTIVE'
|
|
38
59
|
`).run(now, this.projectId);
|
|
39
|
-
// Insert new agent as ACTIVE
|
|
60
|
+
// Insert new agent as ACTIVE with project metadata
|
|
40
61
|
db.prepare(`
|
|
41
|
-
INSERT INTO agents (id, project_id, session_id, status, focus, last_heartbeat)
|
|
42
|
-
VALUES (?, ?, ?, 'ACTIVE', '-', ?)
|
|
43
|
-
`).run(fullAgentId, this.projectId, effectiveSessionId, now);
|
|
62
|
+
INSERT INTO agents (id, project_id, session_id, status, focus, last_heartbeat, keywords, responsibilities)
|
|
63
|
+
VALUES (?, ?, ?, 'ACTIVE', '-', ?, ?, ?)
|
|
64
|
+
`).run(fullAgentId, this.projectId, effectiveSessionId, now, JSON.stringify(keywords), JSON.stringify(responsibilities));
|
|
44
65
|
// Log the registration
|
|
45
66
|
this.logMessage(fullAgentId, `Agent registered and activated`);
|
|
46
67
|
return { agentId: fullAgentId, sessionId: effectiveSessionId };
|
package/dist/common/database.js
CHANGED
|
@@ -7,7 +7,7 @@ import Database from 'better-sqlite3';
|
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import * as os from 'os';
|
|
9
9
|
import * as fs from 'fs';
|
|
10
|
-
const SCHEMA_VERSION =
|
|
10
|
+
const SCHEMA_VERSION = 3; // v2: Added orchestrator_logs table, v3: Added keywords/responsibilities to agents
|
|
11
11
|
/**
|
|
12
12
|
* SQL Schema for Agent Board
|
|
13
13
|
*/
|
|
@@ -21,6 +21,8 @@ CREATE TABLE IF NOT EXISTS agents (
|
|
|
21
21
|
status TEXT NOT NULL DEFAULT 'ACTIVE', -- ACTIVE, INACTIVE
|
|
22
22
|
focus TEXT DEFAULT '-', -- Current task/file being worked on
|
|
23
23
|
last_heartbeat TEXT NOT NULL, -- ISO timestamp of last activity
|
|
24
|
+
keywords TEXT, -- JSON array of project keywords (synced from registry)
|
|
25
|
+
responsibilities TEXT, -- JSON array of project responsibilities (synced from registry)
|
|
24
26
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
25
27
|
PRIMARY KEY (id, project_id)
|
|
26
28
|
);
|
|
@@ -180,6 +182,26 @@ class DatabaseManager {
|
|
|
180
182
|
console.error(`[Database] Migrating schema from v${currentVersion} to v${SCHEMA_VERSION}`);
|
|
181
183
|
// Run schema creation (IF NOT EXISTS makes it safe)
|
|
182
184
|
this.db.exec(SCHEMA_SQL);
|
|
185
|
+
// v3 migration: Add keywords and responsibilities columns to agents table
|
|
186
|
+
if (currentVersion < 3) {
|
|
187
|
+
try {
|
|
188
|
+
// Check if columns already exist
|
|
189
|
+
const tableInfo = this.db.prepare("PRAGMA table_info(agents)").all();
|
|
190
|
+
const hasKeywords = tableInfo.some(col => col.name === 'keywords');
|
|
191
|
+
const hasResponsibilities = tableInfo.some(col => col.name === 'responsibilities');
|
|
192
|
+
if (!hasKeywords) {
|
|
193
|
+
this.db.exec('ALTER TABLE agents ADD COLUMN keywords TEXT');
|
|
194
|
+
console.error('[Database] Added keywords column to agents table');
|
|
195
|
+
}
|
|
196
|
+
if (!hasResponsibilities) {
|
|
197
|
+
this.db.exec('ALTER TABLE agents ADD COLUMN responsibilities TEXT');
|
|
198
|
+
console.error('[Database] Added responsibilities column to agents table');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch (alterError) {
|
|
202
|
+
console.error(`[Database] Warning during v3 migration: ${alterError.message}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
183
205
|
// Record/update schema version
|
|
184
206
|
this.db.prepare('INSERT OR REPLACE INTO schema_version (version) VALUES (?)').run(SCHEMA_VERSION);
|
|
185
207
|
console.error(`[Database] Schema initialized at v${SCHEMA_VERSION}`);
|
package/dist/common/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Version of the MCP Kanban server
|
|
2
|
-
export const VERSION = "0.2.
|
|
2
|
+
export const VERSION = "0.2.8";
|
package/dist/tools/routeTask.js
CHANGED
|
@@ -41,28 +41,26 @@ function buildProjectsContext(projects, currentProjectId) {
|
|
|
41
41
|
return context;
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
|
-
* Tools available to the orchestrator for verification
|
|
44
|
+
* Tools available to the orchestrator for verification (Responses API format)
|
|
45
45
|
*/
|
|
46
46
|
const ORCHESTRATOR_TOOLS = [
|
|
47
47
|
{
|
|
48
48
|
type: "function",
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
description: "Natural language query describing what you're looking for (e.g., 'UserDTO class', 'authentication service', 'database connection')",
|
|
62
|
-
},
|
|
49
|
+
name: "semantic_search",
|
|
50
|
+
description: "Search for code semantically in a specific project. Use this to verify if code already exists, where implementations are located, or to understand project structure before routing decisions.",
|
|
51
|
+
parameters: {
|
|
52
|
+
type: "object",
|
|
53
|
+
properties: {
|
|
54
|
+
projectId: {
|
|
55
|
+
type: "string",
|
|
56
|
+
description: "The project ID to search in",
|
|
57
|
+
},
|
|
58
|
+
query: {
|
|
59
|
+
type: "string",
|
|
60
|
+
description: "Natural language query describing what you're looking for (e.g., 'UserDTO class', 'authentication service', 'database connection')",
|
|
63
61
|
},
|
|
64
|
-
required: ["projectId", "query"],
|
|
65
62
|
},
|
|
63
|
+
required: ["projectId", "query"],
|
|
66
64
|
},
|
|
67
65
|
},
|
|
68
66
|
];
|
|
@@ -227,21 +225,18 @@ export async function routeTaskTool(params, indexManager) {
|
|
|
227
225
|
warning: 'AI routing unavailable. Proceeding without validation.',
|
|
228
226
|
};
|
|
229
227
|
}
|
|
230
|
-
// Model
|
|
231
|
-
const model = process.env.
|
|
228
|
+
// Model and reasoning config (use same as project knowledge service)
|
|
229
|
+
const model = process.env.MEMORYBANK_REASONING_MODEL || "gpt-5-mini";
|
|
230
|
+
const reasoningEffort = process.env.MEMORYBANK_REASONING_EFFORT || "medium";
|
|
232
231
|
try {
|
|
233
232
|
const client = new OpenAI({ apiKey });
|
|
234
233
|
const prompt = ROUTING_PROMPT
|
|
235
234
|
.replace('{projectsContext}', projectsContext)
|
|
236
235
|
.replace('{currentProject}', projectId)
|
|
237
236
|
.replace('{taskDescription}', taskDescription);
|
|
238
|
-
console.error(`Calling AI orchestrator with
|
|
239
|
-
//
|
|
240
|
-
const
|
|
241
|
-
{
|
|
242
|
-
role: "system",
|
|
243
|
-
content: "You are a Task Routing Orchestrator. Analyze tasks and route them to appropriate projects. You can use semantic_search to verify where code exists before making decisions. Always respond with JSON after your analysis.",
|
|
244
|
-
},
|
|
237
|
+
console.error(`Calling AI orchestrator with Responses API (${model}, effort: ${reasoningEffort})...`);
|
|
238
|
+
// Build initial input for Responses API
|
|
239
|
+
const input = [
|
|
245
240
|
{
|
|
246
241
|
role: "user",
|
|
247
242
|
content: prompt,
|
|
@@ -254,42 +249,67 @@ export async function routeTaskTool(params, indexManager) {
|
|
|
254
249
|
while (iterations < maxIterations) {
|
|
255
250
|
iterations++;
|
|
256
251
|
console.error(` Iteration ${iterations}/${maxIterations}`);
|
|
257
|
-
|
|
252
|
+
// Call Responses API with reasoning
|
|
253
|
+
const response = await client.responses.create({
|
|
258
254
|
model,
|
|
259
|
-
|
|
255
|
+
reasoning: {
|
|
256
|
+
effort: reasoningEffort,
|
|
257
|
+
},
|
|
258
|
+
instructions: "You are a Task Routing Orchestrator. Analyze tasks and route them to appropriate projects. You can use semantic_search to verify where code exists before making decisions. Always respond with JSON after your analysis.",
|
|
259
|
+
input,
|
|
260
260
|
tools: ORCHESTRATOR_TOOLS,
|
|
261
261
|
tool_choice: "auto",
|
|
262
|
-
|
|
262
|
+
max_output_tokens: 8000,
|
|
263
263
|
});
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
264
|
+
// Process output items from Responses API
|
|
265
|
+
let hasToolCalls = false;
|
|
266
|
+
const toolCalls = [];
|
|
267
|
+
for (const item of response.output || []) {
|
|
268
|
+
if (item.type === "function_call") {
|
|
269
|
+
hasToolCalls = true;
|
|
270
|
+
toolCalls.push({
|
|
271
|
+
id: item.call_id,
|
|
272
|
+
name: item.name,
|
|
273
|
+
arguments: item.arguments,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
else if (item.type === "message" && item.content) {
|
|
277
|
+
// Extract text content from message
|
|
278
|
+
for (const contentItem of item.content) {
|
|
279
|
+
if (contentItem.type === "output_text") {
|
|
280
|
+
finalResponse = contentItem.text;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
268
284
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
285
|
+
if (hasToolCalls) {
|
|
286
|
+
console.error(` Model requested ${toolCalls.length} tool call(s)`);
|
|
287
|
+
// Execute each tool call and add results to input
|
|
288
|
+
for (const toolCall of toolCalls) {
|
|
289
|
+
const toolArgs = JSON.parse(toolCall.arguments);
|
|
290
|
+
const toolResult = await executeToolCall(toolCall.name, toolArgs, allProjects, indexManager);
|
|
291
|
+
// Add function call and result to input for next iteration
|
|
292
|
+
input.push({
|
|
293
|
+
type: "function_call",
|
|
294
|
+
call_id: toolCall.id,
|
|
295
|
+
name: toolCall.name,
|
|
296
|
+
arguments: toolCall.arguments,
|
|
297
|
+
});
|
|
298
|
+
input.push({
|
|
299
|
+
type: "function_call_output",
|
|
300
|
+
call_id: toolCall.id,
|
|
301
|
+
output: toolResult,
|
|
284
302
|
});
|
|
285
303
|
}
|
|
286
304
|
}
|
|
287
|
-
else {
|
|
288
|
-
// No tool calls, this is the final response
|
|
289
|
-
finalResponse = message.content;
|
|
305
|
+
else if (finalResponse) {
|
|
290
306
|
console.error(` Final response received`);
|
|
291
307
|
break;
|
|
292
308
|
}
|
|
309
|
+
else {
|
|
310
|
+
console.error(` No response or tool calls`);
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
293
313
|
}
|
|
294
314
|
if (!finalResponse) {
|
|
295
315
|
console.error(` No final response after ${iterations} iterations`);
|