@learningnodes/elen-mcp 0.1.2
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/index.d.ts +7 -0
- package/dist/index.js +92 -0
- package/dist/server.d.ts +14 -0
- package/dist/server.js +88 -0
- package/dist/tools/commit.d.ts +46 -0
- package/dist/tools/commit.js +40 -0
- package/dist/tools/competency.d.ts +18 -0
- package/dist/tools/competency.js +35 -0
- package/dist/tools/expand.d.ts +20 -0
- package/dist/tools/expand.js +24 -0
- package/dist/tools/get-context.d.ts +34 -0
- package/dist/tools/get-context.js +84 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.js +39 -0
- package/dist/tools/legacy.d.ts +72 -0
- package/dist/tools/legacy.js +80 -0
- package/dist/tools/log-decision.d.ts +81 -0
- package/dist/tools/log-decision.js +121 -0
- package/dist/tools/search.d.ts +28 -0
- package/dist/tools/search.js +49 -0
- package/dist/tools/suggest.d.ts +30 -0
- package/dist/tools/suggest.js +32 -0
- package/dist/tools/supersede.d.ts +50 -0
- package/dist/tools/supersede.js +43 -0
- package/final_test.txt +68 -0
- package/mcp_test2.txt +60 -0
- package/mcp_test_output.txt +107 -0
- package/package.json +24 -0
- package/src/index.ts +107 -0
- package/src/server.ts +116 -0
- package/src/shims.d.ts +41 -0
- package/src/tools/commit.ts +40 -0
- package/src/tools/competency.ts +40 -0
- package/src/tools/expand.ts +24 -0
- package/src/tools/index.ts +23 -0
- package/src/tools/legacy.ts +88 -0
- package/src/tools/suggest.ts +32 -0
- package/src/tools/supersede.ts +43 -0
- package/tests/server.test.ts +43 -0
- package/tests/tools.test.ts +82 -0
- package/tsconfig.json +17 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.parseCliArgs = parseCliArgs;
|
|
5
|
+
const node_child_process_1 = require("node:child_process");
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const server_1 = require("./server");
|
|
9
|
+
// MCP SDK overrides the ambient `process` type, stripping cwd().
|
|
10
|
+
// We use execSync as a workaround.
|
|
11
|
+
const currentDir = () => (0, node_child_process_1.execSync)('cd', { encoding: 'utf-8' }).trim();
|
|
12
|
+
/**
|
|
13
|
+
* Auto-detect project identity from the environment.
|
|
14
|
+
* Priority: git remote name > package.json name > cwd basename > 'default'
|
|
15
|
+
*/
|
|
16
|
+
function detectProject() {
|
|
17
|
+
// 1. Try git remote URL → extract repo name
|
|
18
|
+
try {
|
|
19
|
+
const remote = (0, node_child_process_1.execSync)('git remote get-url origin', {
|
|
20
|
+
encoding: 'utf-8',
|
|
21
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
22
|
+
}).trim();
|
|
23
|
+
// https://github.com/org/repo-name.git → repo-name
|
|
24
|
+
// git@github.com:org/repo-name.git → repo-name
|
|
25
|
+
const match = remote.match(/[/:]([^/]+?)(?:\.git)?$/);
|
|
26
|
+
if (match?.[1])
|
|
27
|
+
return match[1];
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Not a git repo or git not available
|
|
31
|
+
}
|
|
32
|
+
// 2. Try package.json name
|
|
33
|
+
const pkgPath = (0, node_path_1.resolve)(currentDir(), 'package.json');
|
|
34
|
+
if ((0, node_fs_1.existsSync)(pkgPath)) {
|
|
35
|
+
try {
|
|
36
|
+
const pkg = JSON.parse((0, node_fs_1.readFileSync)(pkgPath, 'utf-8'));
|
|
37
|
+
if (pkg.name) {
|
|
38
|
+
// Strip scope: @org/name → name
|
|
39
|
+
return pkg.name.replace(/^@[^/]+\//, '');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Malformed package.json
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// 3. Working directory basename
|
|
47
|
+
return (0, node_path_1.basename)(currentDir()) || 'default';
|
|
48
|
+
}
|
|
49
|
+
function parseCliArgs(argv) {
|
|
50
|
+
let agentId = 'default-agent';
|
|
51
|
+
let projectId;
|
|
52
|
+
let storagePath;
|
|
53
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
54
|
+
const arg = argv[i];
|
|
55
|
+
if (arg === '--agent-id') {
|
|
56
|
+
agentId = argv[i + 1] ?? agentId;
|
|
57
|
+
i += 1;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (arg === '--project') {
|
|
61
|
+
projectId = argv[i + 1] ?? projectId;
|
|
62
|
+
i += 1;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (arg === '--storage') {
|
|
66
|
+
storagePath = argv[i + 1] ?? storagePath;
|
|
67
|
+
i += 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
agentId,
|
|
72
|
+
projectId: projectId ?? detectProject(),
|
|
73
|
+
storagePath
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function main() {
|
|
77
|
+
const options = parseCliArgs(process.argv.slice(2));
|
|
78
|
+
process.stderr.write(`✦ Elen MCP starting — agent: ${options.agentId}, project: ${options.projectId}\n`);
|
|
79
|
+
const server = (0, server_1.createMcpServer)({
|
|
80
|
+
agentId: options.agentId,
|
|
81
|
+
projectId: options.projectId,
|
|
82
|
+
storagePath: options.storagePath ?? (0, server_1.defaultStoragePath)()
|
|
83
|
+
});
|
|
84
|
+
await server.start();
|
|
85
|
+
}
|
|
86
|
+
if (require.main === module) {
|
|
87
|
+
main().catch((error) => {
|
|
88
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
89
|
+
process.stderr.write(`Failed to start @learningnodes/elen-mcp: ${message}\n`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
});
|
|
92
|
+
}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Elen } from '@learningnodes/elen';
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
export interface McpServerOptions {
|
|
4
|
+
agentId: string;
|
|
5
|
+
projectId?: string;
|
|
6
|
+
storagePath?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function defaultStoragePath(): string;
|
|
9
|
+
export declare function createElenClient(options: McpServerOptions): Elen;
|
|
10
|
+
export declare function routeToolCall(elen: Elen, agentId: string, name: string, args: unknown): Promise<unknown>;
|
|
11
|
+
export declare function createMcpServer(options: McpServerOptions): {
|
|
12
|
+
server: Server;
|
|
13
|
+
start(): Promise<void>;
|
|
14
|
+
};
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultStoragePath = defaultStoragePath;
|
|
4
|
+
exports.createElenClient = createElenClient;
|
|
5
|
+
exports.routeToolCall = routeToolCall;
|
|
6
|
+
exports.createMcpServer = createMcpServer;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_os_1 = require("node:os");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const elen_1 = require("@learningnodes/elen");
|
|
11
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
12
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
13
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
14
|
+
const tools_1 = require("./tools");
|
|
15
|
+
function defaultStoragePath() {
|
|
16
|
+
return (0, node_path_1.join)((0, node_os_1.homedir)(), '.elen', 'decisions.db');
|
|
17
|
+
}
|
|
18
|
+
function createElenClient(options) {
|
|
19
|
+
const sqlitePath = options.storagePath ?? defaultStoragePath();
|
|
20
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(sqlitePath), { recursive: true });
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
return new elen_1.Elen({
|
|
23
|
+
agentId: options.agentId,
|
|
24
|
+
projectId: options.projectId,
|
|
25
|
+
storage: 'sqlite',
|
|
26
|
+
sqlitePath
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async function routeToolCall(elen, agentId, name, args) {
|
|
30
|
+
switch (name) {
|
|
31
|
+
case tools_1.elenCommitTool.name:
|
|
32
|
+
return (0, tools_1.handleCommit)(elen, args);
|
|
33
|
+
case tools_1.elenSuggestTool.name:
|
|
34
|
+
return (0, tools_1.handleSuggest)(elen, args);
|
|
35
|
+
case tools_1.elenExpandTool.name:
|
|
36
|
+
return (0, tools_1.handleExpand)(elen, args);
|
|
37
|
+
case tools_1.elenSupersedeTool.name:
|
|
38
|
+
return (0, tools_1.handleSupersede)(elen, args);
|
|
39
|
+
case tools_1.elenGetCompetencyTool.name:
|
|
40
|
+
return (0, tools_1.handleGetCompetency)(elen, args, agentId);
|
|
41
|
+
case tools_1.elenLogDecisionTool.name:
|
|
42
|
+
return (0, tools_1.handleLogDecision)(elen, args);
|
|
43
|
+
case tools_1.elenSearchPrecedentsTool.name:
|
|
44
|
+
return (0, tools_1.handleSearchPrecedents)(elen, args);
|
|
45
|
+
default:
|
|
46
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function createMcpServer(options) {
|
|
50
|
+
const elen = createElenClient(options);
|
|
51
|
+
const server = new index_js_1.Server({
|
|
52
|
+
name: '@learningnodes/elen-mcp',
|
|
53
|
+
version: '0.1.0'
|
|
54
|
+
}, {
|
|
55
|
+
capabilities: {
|
|
56
|
+
tools: {}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
60
|
+
tools: [
|
|
61
|
+
tools_1.elenCommitTool,
|
|
62
|
+
tools_1.elenSuggestTool,
|
|
63
|
+
tools_1.elenExpandTool,
|
|
64
|
+
tools_1.elenSupersedeTool,
|
|
65
|
+
tools_1.elenGetCompetencyTool,
|
|
66
|
+
tools_1.elenLogDecisionTool,
|
|
67
|
+
tools_1.elenSearchPrecedentsTool
|
|
68
|
+
]
|
|
69
|
+
}));
|
|
70
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
71
|
+
const result = await routeToolCall(elen, options.agentId, request.params.name, request.params.arguments);
|
|
72
|
+
return {
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: 'text',
|
|
76
|
+
text: JSON.stringify(result, null, 2)
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
server,
|
|
83
|
+
async start() {
|
|
84
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
85
|
+
await server.connect(transport);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Elen } from '@learningnodes/elen';
|
|
3
|
+
export declare const elenCommitTool: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: string;
|
|
8
|
+
properties: {
|
|
9
|
+
question: {
|
|
10
|
+
type: string;
|
|
11
|
+
description: string;
|
|
12
|
+
};
|
|
13
|
+
domain: {
|
|
14
|
+
type: string;
|
|
15
|
+
description: string;
|
|
16
|
+
};
|
|
17
|
+
decisionText: {
|
|
18
|
+
type: string;
|
|
19
|
+
description: string;
|
|
20
|
+
};
|
|
21
|
+
constraints: {
|
|
22
|
+
type: string;
|
|
23
|
+
items: {
|
|
24
|
+
type: string;
|
|
25
|
+
};
|
|
26
|
+
description: string;
|
|
27
|
+
};
|
|
28
|
+
refs: {
|
|
29
|
+
type: string;
|
|
30
|
+
items: {
|
|
31
|
+
type: string;
|
|
32
|
+
};
|
|
33
|
+
description: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
required: string[];
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export declare const commitInputSchema: z.ZodObject<{
|
|
40
|
+
question: z.ZodString;
|
|
41
|
+
domain: z.ZodString;
|
|
42
|
+
decisionText: z.ZodString;
|
|
43
|
+
constraints: z.ZodArray<z.ZodString>;
|
|
44
|
+
refs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
45
|
+
}, z.core.$strip>;
|
|
46
|
+
export declare function handleCommit(elen: Elen, args: unknown): Promise<unknown>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.commitInputSchema = exports.elenCommitTool = void 0;
|
|
4
|
+
exports.handleCommit = handleCommit;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
exports.elenCommitTool = {
|
|
7
|
+
name: 'elen_commit',
|
|
8
|
+
description: 'Commit a new minimal epistemic decision to the graph. Pass constraints as plain text array.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
question: { type: 'string', description: 'The question or problem statement' },
|
|
13
|
+
domain: { type: 'string', description: 'Domain of decision (e.g. infrastructure, product)' },
|
|
14
|
+
decisionText: { type: 'string', description: 'The proposed answer/decision made' },
|
|
15
|
+
constraints: {
|
|
16
|
+
type: 'array',
|
|
17
|
+
items: { type: 'string' },
|
|
18
|
+
description: 'Plain-text constraint rules (e.g. "budget < 500 tokens")'
|
|
19
|
+
},
|
|
20
|
+
refs: {
|
|
21
|
+
type: 'array',
|
|
22
|
+
items: { type: 'string' },
|
|
23
|
+
description: 'Explicit pointers to other decision IDs or artifacts'
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
required: ['question', 'domain', 'decisionText', 'constraints']
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
exports.commitInputSchema = zod_1.z.object({
|
|
30
|
+
question: zod_1.z.string().min(1),
|
|
31
|
+
domain: zod_1.z.string().min(1),
|
|
32
|
+
decisionText: zod_1.z.string().min(1),
|
|
33
|
+
constraints: zod_1.z.array(zod_1.z.string().min(1)),
|
|
34
|
+
refs: zod_1.z.array(zod_1.z.string()).optional()
|
|
35
|
+
});
|
|
36
|
+
async function handleCommit(elen, args) {
|
|
37
|
+
const parsed = exports.commitInputSchema.parse(args);
|
|
38
|
+
const result = await elen.commitDecision(parsed);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Elen } from '@learningnodes/elen';
|
|
2
|
+
export declare const elenGetCompetencyTool: {
|
|
3
|
+
readonly name: "elen_get_competency";
|
|
4
|
+
readonly description: "View the competency profile for this agent — domain expertise based on validated decision history.";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly agentId: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly description: "Agent ID (defaults to current agent)";
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export declare function validateCompetencyInput(input: unknown): {
|
|
16
|
+
agentId?: string;
|
|
17
|
+
};
|
|
18
|
+
export declare function handleGetCompetency(elen: Elen, args: unknown, defaultAgentId: string): Promise<unknown>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.elenGetCompetencyTool = void 0;
|
|
4
|
+
exports.validateCompetencyInput = validateCompetencyInput;
|
|
5
|
+
exports.handleGetCompetency = handleGetCompetency;
|
|
6
|
+
exports.elenGetCompetencyTool = {
|
|
7
|
+
name: 'elen_get_competency',
|
|
8
|
+
description: 'View the competency profile for this agent — domain expertise based on validated decision history.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
agentId: { type: 'string', description: 'Agent ID (defaults to current agent)' }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function validateCompetencyInput(input) {
|
|
17
|
+
if (input === undefined) {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
if (!input || typeof input !== 'object') {
|
|
21
|
+
throw new Error('Invalid input: expected object');
|
|
22
|
+
}
|
|
23
|
+
const candidate = input;
|
|
24
|
+
if (candidate.agentId !== undefined && typeof candidate.agentId !== 'string') {
|
|
25
|
+
throw new Error('Invalid input: agentId must be a string');
|
|
26
|
+
}
|
|
27
|
+
return { agentId: candidate.agentId };
|
|
28
|
+
}
|
|
29
|
+
async function handleGetCompetency(elen, args, defaultAgentId) {
|
|
30
|
+
const parsed = validateCompetencyInput(args);
|
|
31
|
+
if (parsed.agentId && parsed.agentId !== defaultAgentId) {
|
|
32
|
+
throw new Error('Cross-agent profile lookup is not supported by this MCP server');
|
|
33
|
+
}
|
|
34
|
+
return elen.getCompetencyProfile();
|
|
35
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Elen } from '@learningnodes/elen';
|
|
3
|
+
export declare const elenExpandTool: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: string;
|
|
8
|
+
properties: {
|
|
9
|
+
decisionId: {
|
|
10
|
+
type: string;
|
|
11
|
+
description: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
required: string[];
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export declare const expandInputSchema: z.ZodObject<{
|
|
18
|
+
decisionId: z.ZodString;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
export declare function handleExpand(elen: Elen, args: unknown): Promise<unknown>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.expandInputSchema = exports.elenExpandTool = void 0;
|
|
4
|
+
exports.handleExpand = handleExpand;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
exports.elenExpandTool = {
|
|
7
|
+
name: 'elen_expand',
|
|
8
|
+
description: 'Expand a minimal pointer decision ID into its full constraints and text when ambiguity requires it.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
decisionId: { type: 'string', description: 'The decision_id (e.g. dec:INFA-aBcDeF) to expand' }
|
|
13
|
+
},
|
|
14
|
+
required: ['decisionId']
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
exports.expandInputSchema = zod_1.z.object({
|
|
18
|
+
decisionId: zod_1.z.string().min(1)
|
|
19
|
+
});
|
|
20
|
+
async function handleExpand(elen, args) {
|
|
21
|
+
const parsed = exports.expandInputSchema.parse(args);
|
|
22
|
+
const result = await elen.expand(parsed.decisionId);
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Elen } from '@learningnodes/elen';
|
|
2
|
+
export declare const elenGetContextTool: {
|
|
3
|
+
readonly name: "elen_get_context";
|
|
4
|
+
readonly description: "Call this at the start of every deliberation to load your current decision context. Returns active threads and recent decisions.";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly domain: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly description: "Optional domain filter to narrow context";
|
|
11
|
+
};
|
|
12
|
+
readonly limit: {
|
|
13
|
+
readonly type: "number";
|
|
14
|
+
readonly description: "Max recent decisions to return (default: 5)";
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export declare function validateGetContextInput(input: unknown): {
|
|
20
|
+
domain?: string;
|
|
21
|
+
limit?: number;
|
|
22
|
+
};
|
|
23
|
+
export declare function handleGetContext(elen: Elen, input: unknown): Promise<{
|
|
24
|
+
total_decisions: number;
|
|
25
|
+
active_threads: {
|
|
26
|
+
thread_id: string;
|
|
27
|
+
thread_name: string;
|
|
28
|
+
decision_count: number;
|
|
29
|
+
latest_decision: string;
|
|
30
|
+
domains: string[];
|
|
31
|
+
turn_breakdown: Record<string, number>;
|
|
32
|
+
}[];
|
|
33
|
+
summary: string;
|
|
34
|
+
}>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.elenGetContextTool = void 0;
|
|
4
|
+
exports.validateGetContextInput = validateGetContextInput;
|
|
5
|
+
exports.handleGetContext = handleGetContext;
|
|
6
|
+
exports.elenGetContextTool = {
|
|
7
|
+
name: 'elen_get_context',
|
|
8
|
+
description: 'Call this at the start of every deliberation to load your current decision context. Returns active threads and recent decisions.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
domain: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
description: 'Optional domain filter to narrow context'
|
|
15
|
+
},
|
|
16
|
+
limit: {
|
|
17
|
+
type: 'number',
|
|
18
|
+
description: 'Max recent decisions to return (default: 5)'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function validateGetContextInput(input) {
|
|
24
|
+
if (!input || typeof input !== 'object') {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
const candidate = input;
|
|
28
|
+
if (candidate.domain !== undefined && typeof candidate.domain !== 'string') {
|
|
29
|
+
throw new Error('Invalid input: domain must be a string');
|
|
30
|
+
}
|
|
31
|
+
if (candidate.limit !== undefined && typeof candidate.limit !== 'number') {
|
|
32
|
+
throw new Error('Invalid input: limit must be a number');
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
domain: candidate.domain,
|
|
36
|
+
limit: candidate.limit
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async function handleGetContext(elen, input) {
|
|
40
|
+
const opts = validateGetContextInput(input);
|
|
41
|
+
const limit = opts.limit ?? 5;
|
|
42
|
+
const records = await elen.searchRecords({
|
|
43
|
+
domain: opts.domain,
|
|
44
|
+
limit
|
|
45
|
+
});
|
|
46
|
+
// Group by thread
|
|
47
|
+
const threads = {};
|
|
48
|
+
for (const record of records) {
|
|
49
|
+
const threadId = record.thread_id || `auto-${record.domain || 'general'}`;
|
|
50
|
+
const threadName = record.thread_name || `${record.domain || 'General'} Decisions`;
|
|
51
|
+
if (!threads[threadId]) {
|
|
52
|
+
threads[threadId] = {
|
|
53
|
+
thread_name: threadName,
|
|
54
|
+
count: 0,
|
|
55
|
+
latest: '',
|
|
56
|
+
domains: new Set(),
|
|
57
|
+
turn_types: {}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const thread = threads[threadId];
|
|
61
|
+
thread.count++;
|
|
62
|
+
thread.domains.add(record.domain || 'general');
|
|
63
|
+
const turnType = record.turn_type || 'ASK';
|
|
64
|
+
thread.turn_types[turnType] = (thread.turn_types[turnType] || 0) + 1;
|
|
65
|
+
if (!thread.latest || record.published_at > thread.latest) {
|
|
66
|
+
thread.latest = record.published_at;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const activeThreads = Object.entries(threads).map(([id, t]) => ({
|
|
70
|
+
thread_id: id,
|
|
71
|
+
thread_name: t.thread_name,
|
|
72
|
+
decision_count: t.count,
|
|
73
|
+
latest_decision: t.latest,
|
|
74
|
+
domains: [...t.domains],
|
|
75
|
+
turn_breakdown: t.turn_types
|
|
76
|
+
}));
|
|
77
|
+
return {
|
|
78
|
+
total_decisions: records.length,
|
|
79
|
+
active_threads: activeThreads,
|
|
80
|
+
summary: activeThreads.length === 0
|
|
81
|
+
? 'No decisions recorded yet. Start by logging your first decision with elen_log_decision.'
|
|
82
|
+
: `${records.length} decisions across ${activeThreads.length} thread(s). Use elen_search_precedents to find related prior decisions.`
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { elenCommitTool, handleCommit, commitInputSchema } from './commit';
|
|
2
|
+
export { elenSuggestTool, handleSuggest, suggestInputSchema } from './suggest';
|
|
3
|
+
export { elenExpandTool, handleExpand, expandInputSchema } from './expand';
|
|
4
|
+
export { elenSupersedeTool, handleSupersede, supersedeInputSchema } from './supersede';
|
|
5
|
+
export { elenGetCompetencyTool, handleGetCompetency, validateCompetencyInput } from './competency';
|
|
6
|
+
export { elenLogDecisionTool, elenSearchPrecedentsTool, handleLogDecision, handleSearchPrecedents, validateLogDecisionInput, validateSearchInput } from './legacy';
|
|
7
|
+
export declare const ELEN_TOOLS: readonly ["elen_commit", "elen_suggest", "elen_expand", "elen_supersede", "elen_get_competency", "elen_log_decision", "elen_search_precedents"];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ELEN_TOOLS = exports.validateSearchInput = exports.validateLogDecisionInput = exports.handleSearchPrecedents = exports.handleLogDecision = exports.elenSearchPrecedentsTool = exports.elenLogDecisionTool = exports.validateCompetencyInput = exports.handleGetCompetency = exports.elenGetCompetencyTool = exports.supersedeInputSchema = exports.handleSupersede = exports.elenSupersedeTool = exports.expandInputSchema = exports.handleExpand = exports.elenExpandTool = exports.suggestInputSchema = exports.handleSuggest = exports.elenSuggestTool = exports.commitInputSchema = exports.handleCommit = exports.elenCommitTool = void 0;
|
|
4
|
+
var commit_1 = require("./commit");
|
|
5
|
+
Object.defineProperty(exports, "elenCommitTool", { enumerable: true, get: function () { return commit_1.elenCommitTool; } });
|
|
6
|
+
Object.defineProperty(exports, "handleCommit", { enumerable: true, get: function () { return commit_1.handleCommit; } });
|
|
7
|
+
Object.defineProperty(exports, "commitInputSchema", { enumerable: true, get: function () { return commit_1.commitInputSchema; } });
|
|
8
|
+
var suggest_1 = require("./suggest");
|
|
9
|
+
Object.defineProperty(exports, "elenSuggestTool", { enumerable: true, get: function () { return suggest_1.elenSuggestTool; } });
|
|
10
|
+
Object.defineProperty(exports, "handleSuggest", { enumerable: true, get: function () { return suggest_1.handleSuggest; } });
|
|
11
|
+
Object.defineProperty(exports, "suggestInputSchema", { enumerable: true, get: function () { return suggest_1.suggestInputSchema; } });
|
|
12
|
+
var expand_1 = require("./expand");
|
|
13
|
+
Object.defineProperty(exports, "elenExpandTool", { enumerable: true, get: function () { return expand_1.elenExpandTool; } });
|
|
14
|
+
Object.defineProperty(exports, "handleExpand", { enumerable: true, get: function () { return expand_1.handleExpand; } });
|
|
15
|
+
Object.defineProperty(exports, "expandInputSchema", { enumerable: true, get: function () { return expand_1.expandInputSchema; } });
|
|
16
|
+
var supersede_1 = require("./supersede");
|
|
17
|
+
Object.defineProperty(exports, "elenSupersedeTool", { enumerable: true, get: function () { return supersede_1.elenSupersedeTool; } });
|
|
18
|
+
Object.defineProperty(exports, "handleSupersede", { enumerable: true, get: function () { return supersede_1.handleSupersede; } });
|
|
19
|
+
Object.defineProperty(exports, "supersedeInputSchema", { enumerable: true, get: function () { return supersede_1.supersedeInputSchema; } });
|
|
20
|
+
var competency_1 = require("./competency");
|
|
21
|
+
Object.defineProperty(exports, "elenGetCompetencyTool", { enumerable: true, get: function () { return competency_1.elenGetCompetencyTool; } });
|
|
22
|
+
Object.defineProperty(exports, "handleGetCompetency", { enumerable: true, get: function () { return competency_1.handleGetCompetency; } });
|
|
23
|
+
Object.defineProperty(exports, "validateCompetencyInput", { enumerable: true, get: function () { return competency_1.validateCompetencyInput; } });
|
|
24
|
+
var legacy_1 = require("./legacy");
|
|
25
|
+
Object.defineProperty(exports, "elenLogDecisionTool", { enumerable: true, get: function () { return legacy_1.elenLogDecisionTool; } });
|
|
26
|
+
Object.defineProperty(exports, "elenSearchPrecedentsTool", { enumerable: true, get: function () { return legacy_1.elenSearchPrecedentsTool; } });
|
|
27
|
+
Object.defineProperty(exports, "handleLogDecision", { enumerable: true, get: function () { return legacy_1.handleLogDecision; } });
|
|
28
|
+
Object.defineProperty(exports, "handleSearchPrecedents", { enumerable: true, get: function () { return legacy_1.handleSearchPrecedents; } });
|
|
29
|
+
Object.defineProperty(exports, "validateLogDecisionInput", { enumerable: true, get: function () { return legacy_1.validateLogDecisionInput; } });
|
|
30
|
+
Object.defineProperty(exports, "validateSearchInput", { enumerable: true, get: function () { return legacy_1.validateSearchInput; } });
|
|
31
|
+
exports.ELEN_TOOLS = [
|
|
32
|
+
'elen_commit',
|
|
33
|
+
'elen_suggest',
|
|
34
|
+
'elen_expand',
|
|
35
|
+
'elen_supersede',
|
|
36
|
+
'elen_get_competency',
|
|
37
|
+
'elen_log_decision',
|
|
38
|
+
'elen_search_precedents'
|
|
39
|
+
];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Elen } from '@learningnodes/elen';
|
|
2
|
+
export declare const elenLogDecisionTool: {
|
|
3
|
+
readonly name: "elen_log_decision";
|
|
4
|
+
readonly description: "Create a validated Decision Record from constraints/evidence/answer.";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly question: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
};
|
|
11
|
+
readonly domain: {
|
|
12
|
+
readonly type: "string";
|
|
13
|
+
};
|
|
14
|
+
readonly constraints: {
|
|
15
|
+
readonly type: "array";
|
|
16
|
+
readonly items: {
|
|
17
|
+
readonly type: "string";
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
readonly evidence: {
|
|
21
|
+
readonly type: "array";
|
|
22
|
+
readonly items: {
|
|
23
|
+
readonly type: "string";
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
readonly answer: {
|
|
27
|
+
readonly type: "string";
|
|
28
|
+
};
|
|
29
|
+
readonly parentPrompt: {
|
|
30
|
+
readonly type: "string";
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
readonly required: readonly ["question", "constraints", "evidence", "answer"];
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export declare const elenSearchPrecedentsTool: {
|
|
37
|
+
readonly name: "elen_search_precedents";
|
|
38
|
+
readonly description: "Search validated decisions for precedents.";
|
|
39
|
+
readonly inputSchema: {
|
|
40
|
+
readonly type: "object";
|
|
41
|
+
readonly properties: {
|
|
42
|
+
readonly query: {
|
|
43
|
+
readonly type: "string";
|
|
44
|
+
};
|
|
45
|
+
readonly domain: {
|
|
46
|
+
readonly type: "string";
|
|
47
|
+
};
|
|
48
|
+
readonly minConfidence: {
|
|
49
|
+
readonly type: "number";
|
|
50
|
+
};
|
|
51
|
+
readonly limit: {
|
|
52
|
+
readonly type: "number";
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
export declare function validateLogDecisionInput(input: unknown): {
|
|
58
|
+
question: string;
|
|
59
|
+
domain?: string;
|
|
60
|
+
constraints: string[];
|
|
61
|
+
evidence: string[];
|
|
62
|
+
answer: string;
|
|
63
|
+
parentPrompt?: string;
|
|
64
|
+
};
|
|
65
|
+
export declare function validateSearchInput(input: unknown): {
|
|
66
|
+
query?: string;
|
|
67
|
+
domain?: string;
|
|
68
|
+
minConfidence?: number;
|
|
69
|
+
limit?: number;
|
|
70
|
+
};
|
|
71
|
+
export declare function handleLogDecision(elen: Elen, args: unknown): Promise<unknown>;
|
|
72
|
+
export declare function handleSearchPrecedents(elen: Elen, args: unknown): Promise<unknown>;
|