@mindot/will 0.1.0 → 0.2.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.
- package/README.md +38 -3
- package/dist/index.d.ts +52 -7760
- package/dist/index.js +374 -86
- package/dist/index.js.map +1 -1
- package/dist/mcp/cli.d.ts +1 -0
- package/dist/mcp/cli.js +26048 -0
- package/dist/mcp/cli.js.map +1 -0
- package/dist/mcp/effectors.d.ts +55 -0
- package/dist/mcp/effectors.js +76 -0
- package/dist/mcp/effectors.js.map +1 -0
- package/dist/will-B5eKs3Wv.d.ts +7903 -0
- package/package.json +38 -30
- package/src/cognition/agency/engines/action.selector.ts +3 -0
- package/src/cognition/agency/engines/affordance.synthesizer.ts +26 -12
- package/src/cognition/agency/engines/deliberation.engine.ts +7 -2
- package/src/cognition/agency/engines/motor.schema.executor.ts +2 -0
- package/src/cognition/agency/schemas/external.ts +27 -10
- package/src/cognition/agency/schemas/repertoire.ts +12 -0
- package/src/cognition/agency/types.ts +51 -2
- package/src/cognition/faculties/executive.engine/commands.ts +47 -11
- package/src/cognition/faculties/executive.engine/context.ts +28 -0
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +15 -1
- package/src/cognition/faculties/executive.engine/facet.ts +32 -6
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +11 -1
- package/src/cognition/faculties/executive.engine/types.ts +24 -2
- package/src/cognition/index.ts +1 -1
- package/src/core/abstracts.ts +39 -12
- package/src/index.ts +6 -0
- package/src/mcp/cli.ts +129 -0
- package/src/mcp/effectors.ts +159 -0
- package/src/mcp/server.ts +167 -0
- package/src/sdk/will.ts +269 -44
- package/src/stem/index.ts +16 -0
- package/src/stem/mind.ts +11 -4
- package/src/stem/tracts/effector.controller.ts +1 -0
- package/src/types.ts +2 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { E as EffectorHandler, W as Will } from '../will-B5eKs3Wv.js';
|
|
3
|
+
|
|
4
|
+
/** Where the tools live: spawn a local server, reach a remote one, or bring a connected client. */
|
|
5
|
+
type McpToolsSource = {
|
|
6
|
+
command: string;
|
|
7
|
+
args?: string[];
|
|
8
|
+
env?: Record<string, string>;
|
|
9
|
+
} | {
|
|
10
|
+
url: string;
|
|
11
|
+
} | {
|
|
12
|
+
client: Client;
|
|
13
|
+
};
|
|
14
|
+
interface McpEffectorsOptions {
|
|
15
|
+
/** Intrinsic effort prior 0..1 seeded on every bridged ability (default 0.2). */
|
|
16
|
+
cost?: number;
|
|
17
|
+
/** Prefix for the ability names (e.g. 'fs_') — avoids collisions across servers. */
|
|
18
|
+
prefix?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Minimal structural view of an MCP tool (the SDK's zod-inferred type, loosened). */
|
|
21
|
+
interface McpToolInfo {
|
|
22
|
+
name: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
inputSchema?: {
|
|
25
|
+
type?: string;
|
|
26
|
+
properties?: Record<string, {
|
|
27
|
+
type?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
}>;
|
|
30
|
+
required?: string[];
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The ability's *meaning*: the tool's description plus a compact hint of the
|
|
35
|
+
* arguments it takes — so the executive knows what to supply in an action's
|
|
36
|
+
* `args` when it enacts this ability.
|
|
37
|
+
*/
|
|
38
|
+
declare function describeMcpTool(tool: McpToolInfo): string;
|
|
39
|
+
/**
|
|
40
|
+
* The effector handler for one bridged tool: checks required args (an ability
|
|
41
|
+
* enacted without its needed articulation fails informatively — reafference
|
|
42
|
+
* learns from it), calls the tool, and maps the result onto EffectorResult.
|
|
43
|
+
*/
|
|
44
|
+
declare function buildMcpHandler(client: Client, tool: McpToolInfo): EffectorHandler;
|
|
45
|
+
/**
|
|
46
|
+
* Register an MCP server's tools as the Will's abilities. Returns the ability
|
|
47
|
+
* names registered and a `close()` for the connection (call it when the Will
|
|
48
|
+
* stops; a client passed in via `source.client` is left open).
|
|
49
|
+
*/
|
|
50
|
+
declare function connectMcpEffectors(will: Will, source: McpToolsSource, opts?: McpEffectorsOptions): Promise<{
|
|
51
|
+
names: string[];
|
|
52
|
+
close: () => Promise<void>;
|
|
53
|
+
}>;
|
|
54
|
+
|
|
55
|
+
export { type McpEffectorsOptions, type McpToolInfo, type McpToolsSource, buildMcpHandler, connectMcpEffectors, describeMcpTool };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
4
|
+
|
|
5
|
+
// src/mcp/effectors.ts
|
|
6
|
+
var RESULT_DESCRIPTION_CAP = 700;
|
|
7
|
+
var MEANING_CAP = 300;
|
|
8
|
+
function describeMcpTool(tool) {
|
|
9
|
+
const props = tool.inputSchema?.properties ?? {};
|
|
10
|
+
const required = new Set(tool.inputSchema?.required ?? []);
|
|
11
|
+
const argHints = Object.entries(props).map(([key, p]) => `${key}${required.has(key) ? "" : "?"}${p.description ? `: ${p.description}` : ""}`);
|
|
12
|
+
const base = (tool.description ?? `The ${tool.name} tool.`).trim().replace(/\s+/g, " ");
|
|
13
|
+
const hint = argHints.length > 0 ? ` (args \u2014 ${argHints.join("; ")})` : "";
|
|
14
|
+
const full = `${base}${hint}`;
|
|
15
|
+
return full.length > MEANING_CAP ? `${full.slice(0, MEANING_CAP - 1)}\u2026` : full;
|
|
16
|
+
}
|
|
17
|
+
function buildMcpHandler(client, tool) {
|
|
18
|
+
return async (args) => {
|
|
19
|
+
const props = tool.inputSchema?.properties;
|
|
20
|
+
const filtered = {};
|
|
21
|
+
for (const [k, v] of Object.entries(args ?? {}))
|
|
22
|
+
if (!props || k in props) filtered[k] = v;
|
|
23
|
+
const missing = (tool.inputSchema?.required ?? []).filter(
|
|
24
|
+
(k) => filtered[k] === void 0 || filtered[k] === ""
|
|
25
|
+
);
|
|
26
|
+
if (missing.length > 0)
|
|
27
|
+
return {
|
|
28
|
+
success: false,
|
|
29
|
+
description: `${tool.name} needs ${missing.join(", ")} \u2014 enact it deliberately, supplying them in the action's args.`
|
|
30
|
+
};
|
|
31
|
+
try {
|
|
32
|
+
const res = await client.callTool({ name: tool.name, arguments: filtered });
|
|
33
|
+
const text = (res.content ?? []).filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("\n").trim() || (res.isError ? "The tool reported an error." : "Done (no output).");
|
|
34
|
+
const bounded = text.length > RESULT_DESCRIPTION_CAP ? `${text.slice(0, RESULT_DESCRIPTION_CAP - 1)}\u2026` : text;
|
|
35
|
+
return { success: !res.isError, description: bounded };
|
|
36
|
+
} catch (err) {
|
|
37
|
+
return { success: false, description: `${tool.name} failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function connect(source) {
|
|
42
|
+
if ("client" in source) return { client: source.client, owned: false };
|
|
43
|
+
const client = new Client({ name: "mindot-will", version: "0" });
|
|
44
|
+
if ("url" in source)
|
|
45
|
+
await client.connect(new StreamableHTTPClientTransport(new URL(source.url)));
|
|
46
|
+
else
|
|
47
|
+
await client.connect(new StdioClientTransport({
|
|
48
|
+
command: source.command,
|
|
49
|
+
...source.args ? { args: source.args } : {},
|
|
50
|
+
// Merge over the SDK's safe default env so PATH etc. survive a custom env.
|
|
51
|
+
env: { ...getDefaultEnvironment(), ...source.env ?? {} }
|
|
52
|
+
}));
|
|
53
|
+
return { client, owned: true };
|
|
54
|
+
}
|
|
55
|
+
async function connectMcpEffectors(will, source, opts = {}) {
|
|
56
|
+
const { client, owned } = await connect(source);
|
|
57
|
+
const { tools } = await client.listTools();
|
|
58
|
+
const names = [];
|
|
59
|
+
for (const tool of tools) {
|
|
60
|
+
const name = `${opts.prefix ?? ""}${tool.name}`;
|
|
61
|
+
will.effector(name, {
|
|
62
|
+
description: describeMcpTool(tool),
|
|
63
|
+
cost: opts.cost ?? 0.2,
|
|
64
|
+
tags: ["mcp"],
|
|
65
|
+
handler: buildMcpHandler(client, tool)
|
|
66
|
+
});
|
|
67
|
+
names.push(name);
|
|
68
|
+
}
|
|
69
|
+
return { names, close: async () => {
|
|
70
|
+
if (owned) await client.close();
|
|
71
|
+
} };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export { buildMcpHandler, connectMcpEffectors, describeMcpTool };
|
|
75
|
+
//# sourceMappingURL=effectors.js.map
|
|
76
|
+
//# sourceMappingURL=effectors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/effectors.ts"],"names":[],"mappings":"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","file":"effectors.js","sourcesContent":["// ─────────────────────────────────────────────────────────────\n// src/mcp/effectors.ts — a Will EMPLOYING MCP tools (Seam 1)\n// ─────────────────────────────────────────────────────────────\n//\n// The other direction from server.ts: connect a Will to an external MCP server\n// and register that server's tools as the Will's own ABILITIES. Each tool\n// becomes a learnable affordance — its description (plus a compact hint of the\n// arguments it takes) is the ability's meaning, surfaced to the executive and\n// the deliberator; the WILL decides when to enact one (nothing here dispatches);\n// the tool's result feeds back through reafference, so the Will gets *skilled*\n// at the tools it uses.\n//\n// Arguments come from conscious intent: the executive supplies them via an\n// action's `args`, which ride the ideomotor leg into the invocation (see\n// executive commands.ts). A tool with required arguments enacted habitually\n// (without args) fails informatively — reafference then teaches the Will that\n// this ability wants deliberate articulation.\n//\n// const { names, close } = await connectMcpEffectors( will, {\n// command: 'npx', args: [ '-y', '@modelcontextprotocol/server-filesystem', '/tmp' ],\n// } )\n//\n// Import from '@mindot/will/mcp' — kept off the main entry so non-MCP\n// consumers never load the MCP SDK.\n// ─────────────────────────────────────────────────────────────\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport type { Will, EffectorHandler, EffectorResult } from '#sdk/will'\n\n/** Where the tools live: spawn a local server, reach a remote one, or bring a connected client. */\nexport type McpToolsSource =\n | { command: string; args?: string[]; env?: Record<string, string> }\n | { url: string }\n | { client: Client }\n\nexport interface McpEffectorsOptions {\n /** Intrinsic effort prior 0..1 seeded on every bridged ability (default 0.2). */\n cost?: number\n /** Prefix for the ability names (e.g. 'fs_') — avoids collisions across servers. */\n prefix?: string\n}\n\n/** Minimal structural view of an MCP tool (the SDK's zod-inferred type, loosened). */\nexport interface McpToolInfo {\n name: string\n description?: string\n inputSchema?: {\n type?: string\n properties?: Record<string, { type?: string; description?: string }>\n required?: string[]\n }\n}\n\n/** Keep tool outcomes bounded — the description feeds reafference + episodic memory. */\nconst RESULT_DESCRIPTION_CAP = 700\n/** Keep ability meanings bounded — they render into the executive prompt. */\nconst MEANING_CAP = 300\n\n/**\n * The ability's *meaning*: the tool's description plus a compact hint of the\n * arguments it takes — so the executive knows what to supply in an action's\n * `args` when it enacts this ability.\n */\nexport function describeMcpTool( tool: McpToolInfo ): string {\n const props = tool.inputSchema?.properties ?? {}\n const required = new Set( tool.inputSchema?.required ?? [] )\n const argHints = Object.entries( props ).map( ( [ key, p ] ) =>\n `${ key }${ required.has( key ) ? '' : '?' }${ p.description ? `: ${ p.description }` : '' }` )\n\n const base = ( tool.description ?? `The ${ tool.name } tool.` ).trim().replace( /\\s+/g, ' ' )\n const hint = argHints.length > 0 ? ` (args — ${ argHints.join( '; ' ) })` : ''\n const full = `${ base }${ hint }`\n return full.length > MEANING_CAP ? `${ full.slice( 0, MEANING_CAP - 1 ) }…` : full\n}\n\n/**\n * The effector handler for one bridged tool: checks required args (an ability\n * enacted without its needed articulation fails informatively — reafference\n * learns from it), calls the tool, and maps the result onto EffectorResult.\n */\nexport function buildMcpHandler( client: Client, tool: McpToolInfo ): EffectorHandler {\n return async ( args ): Promise<EffectorResult> => {\n const props = tool.inputSchema?.properties\n // Only pass keys the tool declares — invocation params can carry situation\n // extras (targetEntityName, learned priors) the tool never asked for.\n const filtered: Record<string, unknown> = {}\n for( const [ k, v ] of Object.entries( args ?? {} ) )\n if( !props || k in props ) filtered[ k ] = v\n\n const missing = ( tool.inputSchema?.required ?? [] ).filter(\n k => filtered[ k ] === undefined || filtered[ k ] === '' )\n if( missing.length > 0 )\n return {\n success: false,\n description: `${ tool.name } needs ${ missing.join( ', ' ) } — enact it deliberately, supplying them in the action's args.`,\n }\n\n try {\n const res = await client.callTool( { name: tool.name, arguments: filtered } ) as\n { content?: Array<{ type: string; text?: string }>; isError?: boolean }\n const text = ( res.content ?? [] )\n .filter( c => c.type === 'text' && typeof c.text === 'string' )\n .map( c => c.text as string )\n .join( '\\n' )\n .trim() || ( res.isError ? 'The tool reported an error.' : 'Done (no output).' )\n const bounded = text.length > RESULT_DESCRIPTION_CAP ? `${ text.slice( 0, RESULT_DESCRIPTION_CAP - 1 ) }…` : text\n return { success: !res.isError, description: bounded }\n }\n catch( err ){\n return { success: false, description: `${ tool.name } failed: ${ err instanceof Error ? err.message : String( err ) }` }\n }\n }\n}\n\nasync function connect( source: McpToolsSource ): Promise<{ client: Client; owned: boolean }> {\n if( 'client' in source ) return { client: source.client, owned: false }\n\n const client = new Client( { name: 'mindot-will', version: '0' } )\n if( 'url' in source )\n await client.connect( new StreamableHTTPClientTransport( new URL( source.url ) ) )\n else\n await client.connect( new StdioClientTransport( {\n command: source.command,\n ...( source.args ? { args: source.args } : {} ),\n // Merge over the SDK's safe default env so PATH etc. survive a custom env.\n env: { ...getDefaultEnvironment(), ...( source.env ?? {} ) },\n } ) )\n return { client, owned: true }\n}\n\n/**\n * Register an MCP server's tools as the Will's abilities. Returns the ability\n * names registered and a `close()` for the connection (call it when the Will\n * stops; a client passed in via `source.client` is left open).\n */\nexport async function connectMcpEffectors(\n will: Will,\n source: McpToolsSource,\n opts: McpEffectorsOptions = {},\n): Promise<{ names: string[]; close: () => Promise<void> }> {\n const { client, owned } = await connect( source )\n const { tools } = await client.listTools() as unknown as { tools: McpToolInfo[] }\n\n const names: string[] = []\n for( const tool of tools ){\n const name = `${ opts.prefix ?? '' }${ tool.name }`\n will.effector( name, {\n description: describeMcpTool( tool ),\n cost: opts.cost ?? 0.2,\n tags: [ 'mcp' ],\n handler: buildMcpHandler( client, tool ),\n } )\n names.push( name )\n }\n\n return { names, close: async () => { if( owned ) await client.close() } }\n}\n"]}
|