@memoryblock/plugin-agents 0.1.0-beta

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 memoryblock
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ import type { Tool } from '@memoryblock/tools';
2
+ export declare const tools: Tool[];
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAK/C,eAAO,MAAM,KAAK,EAAE,IAAI,EAIvB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import { createAgentTool } from './tools/create-agent.js';
2
+ import { listAgentsTool } from './tools/list-agents.js';
3
+ import { queryAgentTool } from './tools/query-agent.js';
4
+ export const tools = [
5
+ createAgentTool,
6
+ listAgentsTool,
7
+ queryAgentTool
8
+ ];
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,CAAC,MAAM,KAAK,GAAW;IACzB,eAAe;IACf,cAAc;IACd,cAAc;CACjB,CAAC"}
@@ -0,0 +1,13 @@
1
+ export declare const createAgentTool: {
2
+ definition: {
3
+ name: string;
4
+ description: string;
5
+ parameters: Record<string, unknown>;
6
+ requiresApproval: boolean;
7
+ };
8
+ execute(params: Record<string, unknown>): Promise<{
9
+ content: string;
10
+ isError: boolean;
11
+ }>;
12
+ };
13
+ //# sourceMappingURL=create-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-agent.d.ts","sourceRoot":"","sources":["../../src/tools/create-agent.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,eAAe;;;;;;;oBAWF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;CAgEhD,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { createSchema } from '@memoryblock/tools';
2
+ import { join } from 'node:path';
3
+ import { promises as fsp } from 'node:fs';
4
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
5
+ // @ts-ignore - workspace resolution cache issue
6
+ import { loadGlobalConfig, resolveBlocksDir, saveBlockConfig, BlockConfigSchema } from 'memoryblock';
7
+ export const createAgentTool = {
8
+ definition: {
9
+ name: 'create_agent',
10
+ description: 'Creates a new memoryblock sub-agent with a specific name, description, and model.',
11
+ parameters: createSchema({
12
+ name: { type: 'string', description: 'Agent identifier, lowercase alphanumeric and hyphens (e.g. "code-reviewer")' },
13
+ description: { type: 'string', description: 'What this agent is designed to do' },
14
+ model: { type: 'string', description: 'The LLM model to use. Defaults to bedrock but can be openai, gemini, or anthropic if api keys configured (e.g. "gpt-4o", "gemini-2.5-pro", "claude-3-5-sonnet-20241022").' }
15
+ }, ['name', 'description']),
16
+ requiresApproval: true
17
+ },
18
+ async execute(params) {
19
+ const { name, description, model = 'anthropic.claude-3-haiku-20240307-v1:0' } = params;
20
+ if (!/^[a-z0-9][a-z0-9-]{0,31}$/.test(name)) {
21
+ return { content: 'Invalid name format. Use lowercase letters, numbers, and hyphens (max 32 chars).', isError: true };
22
+ }
23
+ try {
24
+ const globalConfig = await loadGlobalConfig();
25
+ const blocksDir = resolveBlocksDir(globalConfig);
26
+ const blockPath = join(blocksDir, name);
27
+ const exists = await fsp.stat(blockPath).then(() => true).catch(() => false);
28
+ if (exists) {
29
+ return { content: `Agent "${name}" already exists.`, isError: true };
30
+ }
31
+ await fsp.mkdir(blockPath, { recursive: true });
32
+ // Determine provider natively based on common prefixes
33
+ let provider = 'bedrock';
34
+ if (model.includes('gpt-') || model.includes('o1-'))
35
+ provider = 'openai';
36
+ if (model.includes('gemini-'))
37
+ provider = 'gemini';
38
+ if (model.includes('claude-') && !model.includes('anthropic.'))
39
+ provider = 'anthropic';
40
+ // Adopt default config with sandbox enabled
41
+ const config = BlockConfigSchema.parse({
42
+ name,
43
+ description,
44
+ adapter: {
45
+ ...globalConfig.defaults.adapter,
46
+ provider,
47
+ model
48
+ },
49
+ goals: [description],
50
+ tools: {
51
+ enabled: ['*'],
52
+ searchProvider: 'brave',
53
+ sandbox: true // Sub-agents must be sandboxed natively
54
+ },
55
+ channel: { type: 'cli' },
56
+ permissions: {
57
+ scope: 'block',
58
+ allowShell: false,
59
+ allowNetwork: true,
60
+ maxTimeout: 120_000
61
+ },
62
+ memory: globalConfig.defaults.memory,
63
+ pulse: globalConfig.defaults.pulse
64
+ });
65
+ await saveBlockConfig(blockPath, config);
66
+ // Initial memory empty
67
+ await fsp.writeFile(join(blockPath, 'memory.md'), '# Memory\n\n(no memory yet)', 'utf8');
68
+ return {
69
+ content: `Created sub-agent "${name}" successfully in sandboxed mode using ${provider}/${model}. You can now use query_agent to assign it tasks.`,
70
+ isError: false
71
+ };
72
+ }
73
+ catch (err) {
74
+ return { content: `Failed to create agent: ${err.message}`, isError: true };
75
+ }
76
+ }
77
+ };
78
+ //# sourceMappingURL=create-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-agent.js","sourceRoot":"","sources":["../../src/tools/create-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export declare const listAgentsTool: {
2
+ definition: {
3
+ name: string;
4
+ description: string;
5
+ parameters: Record<string, unknown>;
6
+ requiresApproval: boolean;
7
+ };
8
+ execute(): Promise<{
9
+ content: string;
10
+ isError: boolean;
11
+ }>;
12
+ };
13
+ //# sourceMappingURL=list-agents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-agents.d.ts","sourceRoot":"","sources":["../../src/tools/list-agents.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,cAAc;;;;;;;;;;;CAyC1B,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { createSchema } from '@memoryblock/tools';
2
+ import { join } from 'node:path';
3
+ import { promises as fsp } from 'node:fs';
4
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
5
+ // @ts-ignore - workspace resolution cache issue
6
+ import { loadGlobalConfig, resolveBlocksDir, loadBlockConfig } from 'memoryblock';
7
+ export const listAgentsTool = {
8
+ definition: {
9
+ name: 'list_agents',
10
+ description: 'Discovers available memoryblock sub-agents that can be queried or delegated tasks to.',
11
+ parameters: createSchema({}),
12
+ requiresApproval: false
13
+ },
14
+ async execute() {
15
+ try {
16
+ const globalConfig = await loadGlobalConfig();
17
+ const blocksDir = resolveBlocksDir(globalConfig);
18
+ const entries = await fsp.readdir(blocksDir, { withFileTypes: true });
19
+ const agents = [];
20
+ for (const entry of entries) {
21
+ if (entry.isDirectory()) {
22
+ try {
23
+ const blockPath = join(blocksDir, entry.name);
24
+ const config = await loadBlockConfig(blockPath);
25
+ let status = 'UNKNOWN';
26
+ try {
27
+ const pulseRaw = await fsp.readFile(join(blockPath, 'pulse.json'), 'utf-8');
28
+ status = JSON.parse(pulseRaw).status;
29
+ }
30
+ catch { /* ignore */ }
31
+ agents.push(`- **${config.name}**: ${config.description} (Status: ${status})`);
32
+ }
33
+ catch {
34
+ // skip invalid blocks
35
+ }
36
+ }
37
+ }
38
+ if (agents.length === 0)
39
+ return { content: 'No other agents found.', isError: false };
40
+ return {
41
+ content: `Available Agents:\n\n${agents.join('\n')}`,
42
+ isError: false
43
+ };
44
+ }
45
+ catch (err) {
46
+ return { content: `Failed to list agents: ${err.message}`, isError: true };
47
+ }
48
+ }
49
+ };
50
+ //# sourceMappingURL=list-agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-agents.js","sourceRoot":"","sources":["../../src/tools/list-agents.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,IAAI,GAAG,EAAE,MAAM,SAAS,CAAC;AAC1C,6DAA6D;AAC7D,gDAAgD;AAChD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAElF,MAAM,CAAC,MAAM,cAAc,GAAG;IAC1B,UAAU,EAAE;QACR,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,uFAAuF;QACpG,UAAU,EAAE,YAAY,CAAC,EAAE,CAAC;QAC5B,gBAAgB,EAAE,KAAK;KAC1B;IACD,KAAK,CAAC,OAAO;QACT,IAAI,CAAC;YACD,MAAM,YAAY,GAAG,MAAM,gBAAgB,EAAE,CAAC;YAC9C,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAEtE,MAAM,MAAM,GAAG,EAAE,CAAC;YAClB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC1B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACtB,IAAI,CAAC;wBACD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;wBAC9C,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC;wBAChD,IAAI,MAAM,GAAG,SAAS,CAAC;wBACvB,IAAI,CAAC;4BACD,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;4BAC5E,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;wBACzC,CAAC;wBAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;wBAExB,MAAM,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,WAAW,aAAa,MAAM,GAAG,CAAC,CAAC;oBACnF,CAAC;oBAAC,MAAM,CAAC;wBACL,sBAAsB;oBAC1B,CAAC;gBACL,CAAC;YACL,CAAC;YAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,OAAO,EAAE,wBAAwB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACtF,OAAO;gBACH,OAAO,EAAE,wBAAwB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACpD,OAAO,EAAE,KAAK;aACjB,CAAC;QACN,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,OAAO,EAAE,OAAO,EAAE,0BAA2B,GAAa,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC1F,CAAC;IACL,CAAC;CACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ export declare const queryAgentTool: {
2
+ definition: {
3
+ name: string;
4
+ description: string;
5
+ parameters: Record<string, unknown>;
6
+ requiresApproval: boolean;
7
+ };
8
+ execute(params: Record<string, unknown>): Promise<{
9
+ content: string;
10
+ isError: boolean;
11
+ }>;
12
+ };
13
+ //# sourceMappingURL=query-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-agent.d.ts","sourceRoot":"","sources":["../../src/tools/query-agent.ts"],"names":[],"mappings":"AA0DA,eAAO,MAAM,cAAc;;;;;;;oBAUD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;CAqEhD,CAAC"}
@@ -0,0 +1,119 @@
1
+ import { createSchema, createDefaultRegistry } from '@memoryblock/tools';
2
+ import { join } from 'node:path';
3
+ import { promises as fsp } from 'node:fs';
4
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
5
+ // @ts-ignore - workspace resolution cache issue
6
+ import { loadGlobalConfig, resolveBlocksDir, loadBlockConfig, loadAuth, Monitor } from 'memoryblock';
7
+ // Quick inline OrchestratorChannel for interception
8
+ class OrchestratorChannel {
9
+ name = 'orchestrator';
10
+ messageHandler = null;
11
+ resolveResponse = null;
12
+ finalResponse = '';
13
+ onMessage(handler) {
14
+ this.messageHandler = handler;
15
+ }
16
+ async send(msg) {
17
+ if (!msg.isSystem && msg.content) {
18
+ this.finalResponse = msg.content;
19
+ if (this.resolveResponse) {
20
+ this.resolveResponse(this.finalResponse);
21
+ }
22
+ }
23
+ }
24
+ async requestApproval() {
25
+ // Sub-agents auto-deny unapproved actions in orchestration
26
+ return false;
27
+ }
28
+ async start() { }
29
+ async stop() { }
30
+ simulateUser(content) {
31
+ if (this.messageHandler) {
32
+ this.messageHandler({
33
+ blockName: 'orchestrator',
34
+ monitorName: 'orchestrator',
35
+ content,
36
+ isSystem: false,
37
+ timestamp: new Date().toISOString()
38
+ });
39
+ }
40
+ }
41
+ waitForResponse() {
42
+ return new Promise(resolve => {
43
+ this.resolveResponse = resolve;
44
+ });
45
+ }
46
+ }
47
+ export const queryAgentTool = {
48
+ definition: {
49
+ name: 'query_agent',
50
+ description: 'Delegates a task to a sub-agent. The orchestrator will pause until the sub-agent completes the request and returns its response.',
51
+ parameters: createSchema({
52
+ agent_name: { type: 'string', description: 'Name of the sub-agent to query.' },
53
+ prompt: { type: 'string', description: 'The objective, task, or question to delegate to the sub-agent.' }
54
+ }, ['agent_name', 'prompt']),
55
+ requiresApproval: true // Delegating tasks is a major action
56
+ },
57
+ async execute(params) {
58
+ const { agent_name, prompt } = params;
59
+ try {
60
+ const globalConfig = await loadGlobalConfig();
61
+ const blockPath = join(resolveBlocksDir(globalConfig), agent_name);
62
+ const exists = await fsp.stat(blockPath).then(() => true).catch(() => false);
63
+ if (!exists) {
64
+ return { content: `Agent "${agent_name}" does not exist. Use create_agent first.`, isError: true };
65
+ }
66
+ const blockConfig = await loadBlockConfig(blockPath);
67
+ // Load adapter natively
68
+ const adapters = await import('@memoryblock/adapters');
69
+ let adapter;
70
+ const provider = blockConfig.adapter.provider || 'bedrock';
71
+ if (provider === 'openai') {
72
+ const auth = await loadAuth();
73
+ adapter = new adapters.OpenAIAdapter({
74
+ model: blockConfig.adapter.model,
75
+ apiKey: auth?.openai?.apiKey || process.env.OPENAI_API_KEY || '',
76
+ });
77
+ }
78
+ else if (provider === 'gemini') {
79
+ const auth = await loadAuth();
80
+ adapter = new adapters.GeminiAdapter({
81
+ model: blockConfig.adapter.model,
82
+ apiKey: auth?.gemini?.apiKey || process.env.GEMINI_API_KEY || '',
83
+ });
84
+ }
85
+ else {
86
+ adapter = new adapters.BedrockAdapter({
87
+ model: blockConfig.adapter.model,
88
+ region: blockConfig.adapter.region,
89
+ maxTokens: blockConfig.adapter.maxTokens,
90
+ });
91
+ }
92
+ const registry = createDefaultRegistry();
93
+ const channel = new OrchestratorChannel();
94
+ const monitor = new Monitor({
95
+ blockPath,
96
+ blockConfig,
97
+ adapter,
98
+ registry,
99
+ channel: channel
100
+ });
101
+ // Start monitor
102
+ await monitor.start();
103
+ // Push prompt
104
+ channel.simulateUser(prompt);
105
+ // Wait until the monitor emits a non-system message
106
+ const finalResponse = await channel.waitForResponse();
107
+ // Stop monitor cleanup
108
+ await monitor.stop();
109
+ return {
110
+ content: `Response from ${agent_name}:\n\n${finalResponse}`,
111
+ isError: false
112
+ };
113
+ }
114
+ catch (err) {
115
+ return { content: `Agent query failed: ${err.message}`, isError: true };
116
+ }
117
+ }
118
+ };
119
+ //# sourceMappingURL=query-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-agent.js","sourceRoot":"","sources":["../../src/tools/query-agent.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@memoryblock/plugin-agents",
3
+ "version": "0.1.0-beta",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "dependencies": {
14
+ "@memoryblock/tools": "0.1.0-beta",
15
+ "@memoryblock/adapters": "0.1.0-beta",
16
+ "memoryblock": "0.1.0-beta"
17
+ },
18
+ "scripts": {
19
+ "build": "tsc -p tsconfig.json"
20
+ }
21
+ }
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ import type { Tool } from '@memoryblock/tools';
2
+ import { createAgentTool } from './tools/create-agent.js';
3
+ import { listAgentsTool } from './tools/list-agents.js';
4
+ import { queryAgentTool } from './tools/query-agent.js';
5
+
6
+ export const tools: Tool[] = [
7
+ createAgentTool,
8
+ listAgentsTool,
9
+ queryAgentTool
10
+ ];
@@ -0,0 +1,84 @@
1
+
2
+ import { createSchema } from '@memoryblock/tools';
3
+ import { join } from 'node:path';
4
+ import { promises as fsp } from 'node:fs';
5
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
+ // @ts-ignore - workspace resolution cache issue
7
+ import { loadGlobalConfig, resolveBlocksDir, saveBlockConfig, BlockConfigSchema } from 'memoryblock';
8
+
9
+ export const createAgentTool = {
10
+ definition: {
11
+ name: 'create_agent',
12
+ description: 'Creates a new memoryblock sub-agent with a specific name, description, and model.',
13
+ parameters: createSchema({
14
+ name: { type: 'string', description: 'Agent identifier, lowercase alphanumeric and hyphens (e.g. "code-reviewer")' },
15
+ description: { type: 'string', description: 'What this agent is designed to do' },
16
+ model: { type: 'string', description: 'The LLM model to use. Defaults to bedrock but can be openai, gemini, or anthropic if api keys configured (e.g. "gpt-4o", "gemini-2.5-pro", "claude-3-5-sonnet-20241022").' }
17
+ }, ['name', 'description']),
18
+ requiresApproval: true
19
+ },
20
+ async execute(params: Record<string, unknown>) {
21
+ const { name, description, model = 'anthropic.claude-3-haiku-20240307-v1:0' } = params as { name: string, description: string, model?: string };
22
+
23
+ if (!/^[a-z0-9][a-z0-9-]{0,31}$/.test(name)) {
24
+ return { content: 'Invalid name format. Use lowercase letters, numbers, and hyphens (max 32 chars).', isError: true };
25
+ }
26
+
27
+ try {
28
+ const globalConfig = await loadGlobalConfig();
29
+ const blocksDir = resolveBlocksDir(globalConfig);
30
+ const blockPath = join(blocksDir, name);
31
+
32
+ const exists = await fsp.stat(blockPath).then(() => true).catch(() => false);
33
+ if (exists) {
34
+ return { content: `Agent "${name}" already exists.`, isError: true };
35
+ }
36
+
37
+ await fsp.mkdir(blockPath, { recursive: true });
38
+
39
+ // Determine provider natively based on common prefixes
40
+ let provider = 'bedrock';
41
+ if (model.includes('gpt-') || model.includes('o1-')) provider = 'openai';
42
+ if (model.includes('gemini-')) provider = 'gemini';
43
+ if (model.includes('claude-') && !model.includes('anthropic.')) provider = 'anthropic';
44
+
45
+ // Adopt default config with sandbox enabled
46
+ const config = BlockConfigSchema.parse({
47
+ name,
48
+ description,
49
+ adapter: {
50
+ ...globalConfig.defaults.adapter,
51
+ provider,
52
+ model
53
+ },
54
+ goals: [description],
55
+ tools: {
56
+ enabled: ['*'],
57
+ searchProvider: 'brave',
58
+ sandbox: true // Sub-agents must be sandboxed natively
59
+ },
60
+ channel: { type: 'cli' },
61
+ permissions: {
62
+ scope: 'block',
63
+ allowShell: false,
64
+ allowNetwork: true,
65
+ maxTimeout: 120_000
66
+ },
67
+ memory: globalConfig.defaults.memory,
68
+ pulse: globalConfig.defaults.pulse
69
+ });
70
+
71
+ await saveBlockConfig(blockPath, config);
72
+
73
+ // Initial memory empty
74
+ await fsp.writeFile(join(blockPath, 'memory.md'), '# Memory\n\n(no memory yet)', 'utf8');
75
+
76
+ return {
77
+ content: `Created sub-agent "${name}" successfully in sandboxed mode using ${provider}/${model}. You can now use query_agent to assign it tasks.`,
78
+ isError: false
79
+ };
80
+ } catch (err) {
81
+ return { content: `Failed to create agent: ${(err as Error).message}`, isError: true };
82
+ }
83
+ }
84
+ };
@@ -0,0 +1,50 @@
1
+
2
+ import { createSchema } from '@memoryblock/tools';
3
+ import { join } from 'node:path';
4
+ import { promises as fsp } from 'node:fs';
5
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
+ // @ts-ignore - workspace resolution cache issue
7
+ import { loadGlobalConfig, resolveBlocksDir, loadBlockConfig } from 'memoryblock';
8
+
9
+ export const listAgentsTool = {
10
+ definition: {
11
+ name: 'list_agents',
12
+ description: 'Discovers available memoryblock sub-agents that can be queried or delegated tasks to.',
13
+ parameters: createSchema({}),
14
+ requiresApproval: false
15
+ },
16
+ async execute() {
17
+ try {
18
+ const globalConfig = await loadGlobalConfig();
19
+ const blocksDir = resolveBlocksDir(globalConfig);
20
+ const entries = await fsp.readdir(blocksDir, { withFileTypes: true });
21
+
22
+ const agents = [];
23
+ for (const entry of entries) {
24
+ if (entry.isDirectory()) {
25
+ try {
26
+ const blockPath = join(blocksDir, entry.name);
27
+ const config = await loadBlockConfig(blockPath);
28
+ let status = 'UNKNOWN';
29
+ try {
30
+ const pulseRaw = await fsp.readFile(join(blockPath, 'pulse.json'), 'utf-8');
31
+ status = JSON.parse(pulseRaw).status;
32
+ } catch { /* ignore */ }
33
+
34
+ agents.push(`- **${config.name}**: ${config.description} (Status: ${status})`);
35
+ } catch {
36
+ // skip invalid blocks
37
+ }
38
+ }
39
+ }
40
+
41
+ if (agents.length === 0) return { content: 'No other agents found.', isError: false };
42
+ return {
43
+ content: `Available Agents:\n\n${agents.join('\n')}`,
44
+ isError: false
45
+ };
46
+ } catch (err) {
47
+ return { content: `Failed to list agents: ${(err as Error).message}`, isError: true };
48
+ }
49
+ }
50
+ };
@@ -0,0 +1,138 @@
1
+
2
+ import { createSchema, createDefaultRegistry } from '@memoryblock/tools';
3
+ import { join } from 'node:path';
4
+ import { promises as fsp } from 'node:fs';
5
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
+ // @ts-ignore - workspace resolution cache issue
7
+ import {
8
+ loadGlobalConfig, resolveBlocksDir, loadBlockConfig, loadAuth,
9
+ Monitor
10
+ } from 'memoryblock';
11
+
12
+ // Quick inline OrchestratorChannel for interception
13
+ class OrchestratorChannel {
14
+ public readonly name = 'orchestrator';
15
+ private messageHandler: ((msg: any) => void) | null = null;
16
+ private resolveResponse: ((res: string) => void) | null = null;
17
+ private finalResponse = '';
18
+
19
+ onMessage(handler: (msg: any) => void) {
20
+ this.messageHandler = handler;
21
+ }
22
+
23
+ async send(msg: any) {
24
+ if (!msg.isSystem && msg.content) {
25
+ this.finalResponse = msg.content;
26
+ if (this.resolveResponse) {
27
+ this.resolveResponse(this.finalResponse);
28
+ }
29
+ }
30
+ }
31
+
32
+ async requestApproval() {
33
+ // Sub-agents auto-deny unapproved actions in orchestration
34
+ return false;
35
+ }
36
+
37
+ async start() {}
38
+ async stop() {}
39
+
40
+ simulateUser(content: string) {
41
+ if (this.messageHandler) {
42
+ this.messageHandler({
43
+ blockName: 'orchestrator',
44
+ monitorName: 'orchestrator',
45
+ content,
46
+ isSystem: false,
47
+ timestamp: new Date().toISOString()
48
+ });
49
+ }
50
+ }
51
+
52
+ waitForResponse(): Promise<string> {
53
+ return new Promise(resolve => {
54
+ this.resolveResponse = resolve;
55
+ });
56
+ }
57
+ }
58
+
59
+ export const queryAgentTool = {
60
+ definition: {
61
+ name: 'query_agent',
62
+ description: 'Delegates a task to a sub-agent. The orchestrator will pause until the sub-agent completes the request and returns its response.',
63
+ parameters: createSchema({
64
+ agent_name: { type: 'string', description: 'Name of the sub-agent to query.' },
65
+ prompt: { type: 'string', description: 'The objective, task, or question to delegate to the sub-agent.' }
66
+ }, ['agent_name', 'prompt']),
67
+ requiresApproval: true // Delegating tasks is a major action
68
+ },
69
+ async execute(params: Record<string, unknown>) {
70
+ const { agent_name, prompt } = params as { agent_name: string, prompt: string };
71
+
72
+ try {
73
+ const globalConfig = await loadGlobalConfig();
74
+ const blockPath = join(resolveBlocksDir(globalConfig), agent_name);
75
+
76
+ const exists = await fsp.stat(blockPath).then(() => true).catch(() => false);
77
+ if (!exists) {
78
+ return { content: `Agent "${agent_name}" does not exist. Use create_agent first.`, isError: true };
79
+ }
80
+
81
+ const blockConfig = await loadBlockConfig(blockPath);
82
+
83
+ // Load adapter natively
84
+ const adapters = await import('@memoryblock/adapters');
85
+ let adapter: any;
86
+ const provider = blockConfig.adapter.provider || 'bedrock';
87
+ if (provider === 'openai') {
88
+ const auth = await loadAuth();
89
+ adapter = new adapters.OpenAIAdapter({
90
+ model: blockConfig.adapter.model,
91
+ apiKey: auth?.openai?.apiKey || process.env.OPENAI_API_KEY || '',
92
+ });
93
+ } else if (provider === 'gemini') {
94
+ const auth = await loadAuth();
95
+ adapter = new adapters.GeminiAdapter({
96
+ model: blockConfig.adapter.model,
97
+ apiKey: auth?.gemini?.apiKey || process.env.GEMINI_API_KEY || '',
98
+ });
99
+ } else {
100
+ adapter = new adapters.BedrockAdapter({
101
+ model: blockConfig.adapter.model,
102
+ region: blockConfig.adapter.region,
103
+ maxTokens: blockConfig.adapter.maxTokens,
104
+ });
105
+ }
106
+
107
+ const registry = createDefaultRegistry();
108
+ const channel = new OrchestratorChannel();
109
+
110
+ const monitor = new Monitor({
111
+ blockPath,
112
+ blockConfig,
113
+ adapter,
114
+ registry,
115
+ channel: channel as any
116
+ });
117
+
118
+ // Start monitor
119
+ await monitor.start();
120
+
121
+ // Push prompt
122
+ channel.simulateUser(prompt);
123
+
124
+ // Wait until the monitor emits a non-system message
125
+ const finalResponse = await channel.waitForResponse();
126
+
127
+ // Stop monitor cleanup
128
+ await monitor.stop();
129
+
130
+ return {
131
+ content: `Response from ${agent_name}:\n\n${finalResponse}`,
132
+ isError: false
133
+ };
134
+ } catch (err) {
135
+ return { content: `Agent query failed: ${(err as Error).message}`, isError: true };
136
+ }
137
+ }
138
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": [
8
+ "src"
9
+ ]
10
+ }