@noelclaw/mcp 2.4.0 → 3.1.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 +216 -116
- package/dist/agent-loop.js +141 -0
- package/dist/cli.js +170 -0
- package/dist/server.js +10 -10
- package/dist/tools/coder.js +0 -105
- package/dist/tools/defi.js +0 -38
- package/dist/tools/framework.js +0 -108
- package/dist/tools/swarm.js +0 -355
- package/dist/tools/vault.js +0 -106
- package/package.json +3 -2
package/dist/cli.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const readline = __importStar(require("readline"));
|
|
38
|
+
const agent_loop_js_1 = require("./agent-loop.js");
|
|
39
|
+
const server_js_1 = require("./server.js");
|
|
40
|
+
// ── ANSI ─────────────────────────────────────────────────────────────────────
|
|
41
|
+
const C = {
|
|
42
|
+
reset: "\x1b[0m",
|
|
43
|
+
bold: "\x1b[1m",
|
|
44
|
+
dim: "\x1b[2m",
|
|
45
|
+
green: "\x1b[32m",
|
|
46
|
+
cyan: "\x1b[36m",
|
|
47
|
+
violet: "\x1b[35m",
|
|
48
|
+
red: "\x1b[31m",
|
|
49
|
+
yellow: "\x1b[33m",
|
|
50
|
+
};
|
|
51
|
+
const BANNER = `
|
|
52
|
+
${C.cyan}${C.bold} NOELCLAW${C.reset} ${C.dim}v3.0.0 · 74 tools · persistent AI${C.reset}
|
|
53
|
+
${C.dim}─────────────────────────────────────────${C.reset}
|
|
54
|
+
${C.dim}Type anything. /help for commands. Ctrl+C to exit.${C.reset}
|
|
55
|
+
`;
|
|
56
|
+
// ── Spinner ───────────────────────────────────────────────────────────────────
|
|
57
|
+
function spinner(label) {
|
|
58
|
+
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
59
|
+
let i = 0;
|
|
60
|
+
const iv = setInterval(() => {
|
|
61
|
+
process.stdout.write(`\r ${C.dim}${frames[i % frames.length]} ${label}${C.reset} `);
|
|
62
|
+
i++;
|
|
63
|
+
}, 80);
|
|
64
|
+
return () => {
|
|
65
|
+
clearInterval(iv);
|
|
66
|
+
process.stdout.write("\r" + " ".repeat(label.length + 12) + "\r");
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// ── Help ─────────────────────────────────────────────────────────────────────
|
|
70
|
+
function printHelp() {
|
|
71
|
+
console.log(`
|
|
72
|
+
${C.cyan}Commands:${C.reset}
|
|
73
|
+
/clear Clear conversation history
|
|
74
|
+
/tools List all 74 available tools
|
|
75
|
+
/quit Exit
|
|
76
|
+
|
|
77
|
+
${C.dim}Examples:
|
|
78
|
+
remember my coding style for next time
|
|
79
|
+
what's ETH doing right now?
|
|
80
|
+
swap 0.5 ETH to USDC on Base
|
|
81
|
+
send me a weekly digest every Monday
|
|
82
|
+
research "best DeFi yields on Base"${C.reset}
|
|
83
|
+
`);
|
|
84
|
+
}
|
|
85
|
+
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
86
|
+
async function main() {
|
|
87
|
+
process.stdout.write(BANNER);
|
|
88
|
+
// Detect active LLM
|
|
89
|
+
const mode = process.env.ANTHROPIC_API_KEY
|
|
90
|
+
? `${C.green}Anthropic${C.reset} ${C.dim}(full tool use)${C.reset}`
|
|
91
|
+
: process.env.BANKR_API_KEY
|
|
92
|
+
? `${C.green}Bankr${C.reset} ${C.dim}(full tool use)${C.reset}`
|
|
93
|
+
: `${C.yellow}Convex chat${C.reset} ${C.dim}(no tool execution — set ANTHROPIC_API_KEY for full mode)${C.reset}`;
|
|
94
|
+
console.log(` ${C.dim}Mode:${C.reset} ${mode}\n`);
|
|
95
|
+
const history = [];
|
|
96
|
+
const rl = readline.createInterface({
|
|
97
|
+
input: process.stdin,
|
|
98
|
+
output: process.stdout,
|
|
99
|
+
prompt: `${C.green}>${C.reset} `,
|
|
100
|
+
});
|
|
101
|
+
rl.prompt();
|
|
102
|
+
rl.on("line", async (raw) => {
|
|
103
|
+
const line = raw.trim();
|
|
104
|
+
if (!line) {
|
|
105
|
+
rl.prompt();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// Built-in commands
|
|
109
|
+
if (line === "/quit" || line === "/exit") {
|
|
110
|
+
console.log(`\n ${C.dim}Goodbye.${C.reset}\n`);
|
|
111
|
+
process.exit(0);
|
|
112
|
+
}
|
|
113
|
+
if (line === "/clear") {
|
|
114
|
+
history.length = 0;
|
|
115
|
+
console.log(` ${C.dim}History cleared.${C.reset}\n`);
|
|
116
|
+
rl.prompt();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (line === "/help") {
|
|
120
|
+
printHelp();
|
|
121
|
+
rl.prompt();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (line === "/tools") {
|
|
125
|
+
console.log(`\n ${C.cyan}${server_js_1.ALL_TOOLS.length} tools:${C.reset}`);
|
|
126
|
+
for (const t of server_js_1.ALL_TOOLS) {
|
|
127
|
+
console.log(` ${C.dim}·${C.reset} ${t.name} ${C.dim}${(t.description ?? "").slice(0, 60)}${C.reset}`);
|
|
128
|
+
}
|
|
129
|
+
console.log();
|
|
130
|
+
rl.prompt();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// Agent call
|
|
134
|
+
const stop = spinner("thinking");
|
|
135
|
+
let toolsUsed = 0;
|
|
136
|
+
try {
|
|
137
|
+
const result = await (0, agent_loop_js_1.runAgent)(line, history, (toolName) => {
|
|
138
|
+
stop();
|
|
139
|
+
toolsUsed++;
|
|
140
|
+
process.stdout.write(` ${C.dim}✦ ${toolName}${C.reset}\n`);
|
|
141
|
+
});
|
|
142
|
+
stop();
|
|
143
|
+
// Update conversation history (keep last 20 turns)
|
|
144
|
+
history.push({ role: "user", content: line });
|
|
145
|
+
history.push({ role: "assistant", content: result.text });
|
|
146
|
+
while (history.length > 20)
|
|
147
|
+
history.splice(0, 2);
|
|
148
|
+
// Output
|
|
149
|
+
console.log();
|
|
150
|
+
const lines = result.text.split("\n");
|
|
151
|
+
for (const l of lines) {
|
|
152
|
+
console.log(` ${l}`);
|
|
153
|
+
}
|
|
154
|
+
console.log();
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
stop();
|
|
158
|
+
console.log(`\n ${C.red}✗${C.reset} ${err.message}\n`);
|
|
159
|
+
}
|
|
160
|
+
rl.prompt();
|
|
161
|
+
});
|
|
162
|
+
rl.on("close", () => {
|
|
163
|
+
console.log(`\n ${C.dim}Goodbye.${C.reset}\n`);
|
|
164
|
+
process.exit(0);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
main().catch(err => {
|
|
168
|
+
console.error(`Fatal: ${err.message}`);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
});
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.server = exports.ALL_TOOLS = void 0;
|
|
3
|
+
exports.server = exports.HANDLER_MAP = exports.ALL_TOOLS = void 0;
|
|
4
4
|
exports.startServer = startServer;
|
|
5
5
|
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
6
6
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
@@ -38,23 +38,23 @@ function containsSensitiveRequest(args) {
|
|
|
38
38
|
exports.ALL_TOOLS = [
|
|
39
39
|
...market_js_1.MARKET_TOOLS, // 5 — get_market_data, get_token_data, compare_tokens, market_overview, token_history
|
|
40
40
|
...insight_js_1.INSIGHT_TOOLS, // 3 — ask_noel, market_thesis, trade_plan
|
|
41
|
-
...defi_js_1.DEFI_TOOLS, //
|
|
41
|
+
...defi_js_1.DEFI_TOOLS, // 6 — get_portfolio, estimate_swap, swap_tokens, send_token, analyze_wallet, get_defi_yields
|
|
42
42
|
...automation_js_1.AUTOMATION_TOOLS, // 6 — create, list, pause, delete, get_runs, run
|
|
43
|
-
...swarm_js_1.SWARM_TOOLS, //
|
|
44
|
-
...framework_js_1.FRAMEWORK_TOOLS, //
|
|
45
|
-
...vault_js_1.VAULT_TOOLS, //
|
|
43
|
+
...swarm_js_1.SWARM_TOOLS, // 6 — start, stop, status, research, trigger_agent, brief
|
|
44
|
+
...framework_js_1.FRAMEWORK_TOOLS, // 3 — list_playbooks, run_playbook, get_noel_ledger
|
|
45
|
+
...vault_js_1.VAULT_TOOLS, // 12 — save, read, list, search, history, diff, export, store_credential, get_credential, pin, delete, tag
|
|
46
46
|
...wallet_js_1.WALLET_TOOLS, // 2 — get_wallet_address, set_telegram
|
|
47
47
|
...miroshark_js_1.MIROSHARK_TOOLS, // 3 — simulate, status, stop
|
|
48
48
|
...humanizer_js_1.HUMANIZER_TOOLS, // 3 — humanize_text, write_thread, write_post
|
|
49
49
|
...agents_js_1.AGENT_TOOLS, // 2 — list_agents, hire_agent
|
|
50
50
|
...scanner_js_1.SCANNER_TOOLS, // 4 — score_token, check_token, scan_dips, scan_momentum
|
|
51
|
-
...coder_js_1.CODER_TOOLS, //
|
|
51
|
+
...coder_js_1.CODER_TOOLS, // 5 — generate_contract, audit_contract, explain_code, review_code, generate_mcp_skill
|
|
52
52
|
...base_js_1.BASE_TOOLS, // 4 — query_vaults, list_markets, prepare_deposit, chain_stats
|
|
53
53
|
...memory_js_1.MEMORY_TOOLS, // 7 — memory_add, memory_search, memory_context, memory_profile, memory_list, memory_delete, memory_insight
|
|
54
54
|
...os_js_1.OS_TOOLS, // 3 — noel_status, noel_boot, noel_shutdown
|
|
55
|
-
// total:
|
|
55
|
+
// total: 74
|
|
56
56
|
];
|
|
57
|
-
|
|
57
|
+
exports.HANDLER_MAP = new Map([
|
|
58
58
|
...market_js_1.MARKET_TOOLS.map(t => [t.name, market_js_1.handleMarketTool]),
|
|
59
59
|
...defi_js_1.DEFI_TOOLS.map(t => [t.name, defi_js_1.handleDefiTool]),
|
|
60
60
|
...automation_js_1.AUTOMATION_TOOLS.map(t => [t.name, automation_js_1.handleAutomationTool]),
|
|
@@ -72,13 +72,13 @@ const HANDLER_MAP = new Map([
|
|
|
72
72
|
...memory_js_1.MEMORY_TOOLS.map(t => [t.name, memory_js_1.handleMemoryTool]),
|
|
73
73
|
...os_js_1.OS_TOOLS.map(t => [t.name, os_js_1.handleOsTool]),
|
|
74
74
|
]);
|
|
75
|
-
exports.server = new index_js_1.Server({ name: "noelclaw", version: "
|
|
75
|
+
exports.server = new index_js_1.Server({ name: "noelclaw", version: "3.0.0" }, { capabilities: { tools: {} } });
|
|
76
76
|
exports.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({ tools: exports.ALL_TOOLS }));
|
|
77
77
|
exports.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
78
78
|
const { name, arguments: args } = request.params;
|
|
79
79
|
if (containsSensitiveRequest(args))
|
|
80
80
|
return PRIVATE_KEY_RESPONSE;
|
|
81
|
-
const handler = HANDLER_MAP.get(name);
|
|
81
|
+
const handler = exports.HANDLER_MAP.get(name);
|
|
82
82
|
if (!handler) {
|
|
83
83
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
84
84
|
}
|
package/dist/tools/coder.js
CHANGED
|
@@ -27,53 +27,6 @@ function err(text) {
|
|
|
27
27
|
}
|
|
28
28
|
// ── Tool definitions ──────────────────────────────────────────────────────────
|
|
29
29
|
exports.CODER_TOOLS = [
|
|
30
|
-
{
|
|
31
|
-
name: "scaffold_project",
|
|
32
|
-
description: "Generate a complete project scaffold for a described idea — file tree + key file contents. " +
|
|
33
|
-
"Supports: Solidity contract projects, MCP skill packages, React/Next.js dApps, Convex backends, CLI tools.",
|
|
34
|
-
inputSchema: {
|
|
35
|
-
type: "object",
|
|
36
|
-
properties: {
|
|
37
|
-
description: {
|
|
38
|
-
type: "string",
|
|
39
|
-
description: "What to build — be specific: tech stack, purpose, target chain, key features",
|
|
40
|
-
},
|
|
41
|
-
stack: {
|
|
42
|
-
type: "string",
|
|
43
|
-
enum: ["solidity", "mcp-skill", "react-dapp", "convex-backend", "node-cli", "auto"],
|
|
44
|
-
description: "Tech stack. Use 'auto' to let Noel decide based on description.",
|
|
45
|
-
},
|
|
46
|
-
extras: {
|
|
47
|
-
type: "string",
|
|
48
|
-
description: "Optional: extra requirements, constraints, or preferred libraries",
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
required: ["description"],
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
name: "generate_component",
|
|
56
|
-
description: "Generate a production-ready React/TypeScript component. Returns the full .tsx file content. " +
|
|
57
|
-
"Includes props typing, Tailwind styling, and any hooks needed.",
|
|
58
|
-
inputSchema: {
|
|
59
|
-
type: "object",
|
|
60
|
-
properties: {
|
|
61
|
-
description: {
|
|
62
|
-
type: "string",
|
|
63
|
-
description: "What the component does, what it shows, and how it should behave",
|
|
64
|
-
},
|
|
65
|
-
name: {
|
|
66
|
-
type: "string",
|
|
67
|
-
description: "Component name in PascalCase, e.g. 'TokenPriceCard'",
|
|
68
|
-
},
|
|
69
|
-
context: {
|
|
70
|
-
type: "string",
|
|
71
|
-
description: "Optional: existing imports, store usage, or API calls the component should use",
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
required: ["description", "name"],
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
30
|
{
|
|
78
31
|
name: "generate_contract",
|
|
79
32
|
description: "Generate a Solidity smart contract from a description. Returns the full .sol file. " +
|
|
@@ -190,16 +143,6 @@ exports.CODER_TOOLS = [
|
|
|
190
143
|
},
|
|
191
144
|
];
|
|
192
145
|
// ── Handlers ──────────────────────────────────────────────────────────────────
|
|
193
|
-
const ScaffoldSchema = zod_1.z.object({
|
|
194
|
-
description: zod_1.z.string().min(10),
|
|
195
|
-
stack: zod_1.z.enum(["solidity", "mcp-skill", "react-dapp", "convex-backend", "node-cli", "auto"]).optional(),
|
|
196
|
-
extras: zod_1.z.string().optional(),
|
|
197
|
-
});
|
|
198
|
-
const ComponentSchema = zod_1.z.object({
|
|
199
|
-
description: zod_1.z.string().min(5),
|
|
200
|
-
name: zod_1.z.string().min(1),
|
|
201
|
-
context: zod_1.z.string().optional(),
|
|
202
|
-
});
|
|
203
146
|
const ContractSchema = zod_1.z.object({
|
|
204
147
|
description: zod_1.z.string().min(5),
|
|
205
148
|
name: zod_1.z.string().min(1),
|
|
@@ -225,54 +168,6 @@ const McpSkillSchema = zod_1.z.object({
|
|
|
225
168
|
});
|
|
226
169
|
async function handleCoderTool(name, args) {
|
|
227
170
|
switch (name) {
|
|
228
|
-
case "scaffold_project": {
|
|
229
|
-
const p = ScaffoldSchema.safeParse(args);
|
|
230
|
-
if (!p.success)
|
|
231
|
-
return err(`Invalid input: ${p.error.message}`);
|
|
232
|
-
const { description, stack = "auto", extras } = p.data;
|
|
233
|
-
const prompt = `Generate a complete project scaffold for the following:\n\n` +
|
|
234
|
-
`Description: ${description}\n` +
|
|
235
|
-
`Stack: ${stack}\n` +
|
|
236
|
-
(extras ? `Extra requirements: ${extras}\n` : "") +
|
|
237
|
-
`\nOutput format:\n` +
|
|
238
|
-
`1. Brief overview (2-3 sentences)\n` +
|
|
239
|
-
`2. Full file tree with all files listed\n` +
|
|
240
|
-
`3. Full content of each key file (package.json, main entry, config, one core module)\n` +
|
|
241
|
-
`4. Setup instructions (3-5 steps)\n\n` +
|
|
242
|
-
`Use real, runnable code. No TODO placeholders.`;
|
|
243
|
-
try {
|
|
244
|
-
const response = await (0, llm_js_1.callLLM)(CODER_SYSTEM, prompt, 4096);
|
|
245
|
-
return ok(response);
|
|
246
|
-
}
|
|
247
|
-
catch (e) {
|
|
248
|
-
return err(`scaffold_project failed: ${e.message}`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
case "generate_component": {
|
|
252
|
-
const p = ComponentSchema.safeParse(args);
|
|
253
|
-
if (!p.success)
|
|
254
|
-
return err(`Invalid input: ${p.error.message}`);
|
|
255
|
-
const { description, name: componentName, context } = p.data;
|
|
256
|
-
const prompt = `Generate a production-ready React TypeScript component.\n\n` +
|
|
257
|
-
`Component name: ${componentName}\n` +
|
|
258
|
-
`Description: ${description}\n` +
|
|
259
|
-
(context ? `Context / existing code to integrate with:\n${context}\n` : "") +
|
|
260
|
-
`\nRequirements:\n` +
|
|
261
|
-
`- Full .tsx file, no omissions\n` +
|
|
262
|
-
`- TypeScript props interface\n` +
|
|
263
|
-
`- Tailwind CSS for styling\n` +
|
|
264
|
-
`- Use lucide-react for icons if needed\n` +
|
|
265
|
-
`- Framer Motion for animations if the component is interactive\n` +
|
|
266
|
-
`- Named export (not default)\n` +
|
|
267
|
-
`Output only the .tsx file content, no prose before or after.`;
|
|
268
|
-
try {
|
|
269
|
-
const response = await (0, llm_js_1.callLLM)(CODER_SYSTEM, prompt, 3000);
|
|
270
|
-
return ok(response);
|
|
271
|
-
}
|
|
272
|
-
catch (e) {
|
|
273
|
-
return err(`generate_component failed: ${e.message}`);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
171
|
case "generate_contract": {
|
|
277
172
|
const p = ContractSchema.safeParse(args);
|
|
278
173
|
if (!p.success)
|
package/dist/tools/defi.js
CHANGED
|
@@ -50,11 +50,6 @@ exports.DEFI_TOOLS = [
|
|
|
50
50
|
required: ["token", "toAddress", "amount"],
|
|
51
51
|
},
|
|
52
52
|
},
|
|
53
|
-
{
|
|
54
|
-
name: "scan_wallet",
|
|
55
|
-
description: "AI-powered portfolio scan — concentration risk, volatility exposure, Base ecosystem opportunities, and a concrete 3-step action plan based on your actual holdings. Requires wallet auth.",
|
|
56
|
-
inputSchema: { type: "object", properties: {}, required: [] },
|
|
57
|
-
},
|
|
58
53
|
{
|
|
59
54
|
name: "analyze_wallet",
|
|
60
55
|
description: "AI-powered analysis of any public wallet on Base — not just your own. " +
|
|
@@ -186,39 +181,6 @@ async function handleDefiTool(name, args) {
|
|
|
186
181
|
}],
|
|
187
182
|
};
|
|
188
183
|
}
|
|
189
|
-
case "scan_wallet": {
|
|
190
|
-
const data = await (0, convex_js_1.callConvex)("/wallet/scan", "GET", undefined, "scan_wallet");
|
|
191
|
-
if (data.error) {
|
|
192
|
-
return { content: [{ type: "text", text: `Scan failed: ${data.error}` }], isError: true };
|
|
193
|
-
}
|
|
194
|
-
const total = (data.totalUsd ?? 0).toFixed(2);
|
|
195
|
-
const topHoldings = (data.holdings ?? [])
|
|
196
|
-
.slice(0, 5)
|
|
197
|
-
.map((h) => `• **${h.token}**: $${(h.valueUsd ?? 0).toFixed(2)}${h.pct != null ? ` (${h.pct}%)` : ""}`)
|
|
198
|
-
.join("\n");
|
|
199
|
-
const header = [
|
|
200
|
-
`**Portfolio Scan** — Total: $${total}`,
|
|
201
|
-
`Wallet: \`${data.address ?? "unknown"}\``,
|
|
202
|
-
``,
|
|
203
|
-
`**Holdings:**`,
|
|
204
|
-
topHoldings,
|
|
205
|
-
``,
|
|
206
|
-
].join("\n");
|
|
207
|
-
let body;
|
|
208
|
-
if (data.analysis) {
|
|
209
|
-
body = data.analysis;
|
|
210
|
-
}
|
|
211
|
-
else if (data.analysisError) {
|
|
212
|
-
body = `*AI analysis unavailable: ${data.analysisError}*`;
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
body = "*AI analysis not available*";
|
|
216
|
-
}
|
|
217
|
-
const footer = data.tokensUsed
|
|
218
|
-
? `\n\n*Tokens used: ${data.tokensUsed} · Scanned: ${data.scannedAt ?? ""}*`
|
|
219
|
-
: "";
|
|
220
|
-
return { content: [{ type: "text", text: header + body + footer }] };
|
|
221
|
-
}
|
|
222
184
|
case "analyze_wallet": {
|
|
223
185
|
const parsed = AnalyzeWalletSchema.safeParse(args);
|
|
224
186
|
if (!parsed.success)
|
package/dist/tools/framework.js
CHANGED
|
@@ -4,32 +4,6 @@ exports.FRAMEWORK_TOOLS = void 0;
|
|
|
4
4
|
exports.handleFrameworkTool = handleFrameworkTool;
|
|
5
5
|
const convex_js_1 = require("../convex.js");
|
|
6
6
|
exports.FRAMEWORK_TOOLS = [
|
|
7
|
-
{
|
|
8
|
-
name: "create_task_packet",
|
|
9
|
-
description: "Define a scoped task for Noel Framework. Converts plain-English intent into a " +
|
|
10
|
-
"structured Task Packet (territory, permissions, doNotDo constraints). " +
|
|
11
|
-
"Sentinel validates before any agent action. " +
|
|
12
|
-
"Example: 'buy ETH when it drops 5%, max $20, don't touch my USDC'.",
|
|
13
|
-
inputSchema: {
|
|
14
|
-
type: "object",
|
|
15
|
-
properties: {
|
|
16
|
-
task: {
|
|
17
|
-
type: "string",
|
|
18
|
-
description: "What you want the agents to do, in plain English.",
|
|
19
|
-
},
|
|
20
|
-
name: {
|
|
21
|
-
type: "string",
|
|
22
|
-
description: "Optional short name for this task (max 5 words).",
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
required: ["task"],
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
name: "list_task_packets",
|
|
30
|
-
description: "List all your Task Packets — draft, active, completed, and blocked.",
|
|
31
|
-
inputSchema: { type: "object", properties: {}, required: [] },
|
|
32
|
-
},
|
|
33
7
|
{
|
|
34
8
|
name: "list_playbooks",
|
|
35
9
|
description: "List available Noel Framework playbooks — predefined multi-step agent workflows. " +
|
|
@@ -65,62 +39,10 @@ exports.FRAMEWORK_TOOLS = [
|
|
|
65
39
|
"Full transparency on what agents are and aren't allowed to do.",
|
|
66
40
|
inputSchema: { type: "object", properties: {}, required: [] },
|
|
67
41
|
},
|
|
68
|
-
{
|
|
69
|
-
name: "get_sentinel_rules",
|
|
70
|
-
description: "Get Sentinel rules for each swarm agent and each playbook role — " +
|
|
71
|
-
"territory, permissions, blocked actions, and value caps. " +
|
|
72
|
-
"Shows exactly what each agent is and isn't allowed to do.",
|
|
73
|
-
inputSchema: { type: "object", properties: {}, required: [] },
|
|
74
|
-
},
|
|
75
42
|
];
|
|
76
43
|
async function handleFrameworkTool(name, args) {
|
|
77
44
|
const a = (args ?? {});
|
|
78
45
|
switch (name) {
|
|
79
|
-
// ── create_task_packet ──────────────────────────────────────────────────
|
|
80
|
-
case "create_task_packet": {
|
|
81
|
-
if (!a.task) {
|
|
82
|
-
return { content: [{ type: "text", text: "task is required" }], isError: true };
|
|
83
|
-
}
|
|
84
|
-
const result = await (0, convex_js_1.callConvex)("/framework/task", "POST", {
|
|
85
|
-
naturalLanguage: a.task,
|
|
86
|
-
name: a.name,
|
|
87
|
-
}, "create_task_packet");
|
|
88
|
-
if (result.error) {
|
|
89
|
-
return { content: [{ type: "text", text: `Failed: ${result.error}` }], isError: true };
|
|
90
|
-
}
|
|
91
|
-
const p = result.packet ?? {};
|
|
92
|
-
const lines = [
|
|
93
|
-
`✅ **Task Packet created**`,
|
|
94
|
-
``,
|
|
95
|
-
`**Name:** ${p.name ?? "—"}`,
|
|
96
|
-
`**Task:** ${p.task ?? a.task}`,
|
|
97
|
-
`**Territory:** ${(p.territory ?? []).join(", ") || "—"}`,
|
|
98
|
-
`**Permissions:** ${(p.permissions ?? []).join(", ") || "—"}`,
|
|
99
|
-
`**Blocked:** ${(p.doNotDo ?? []).join(", ") || "none"}`,
|
|
100
|
-
`**Max value:** ${p.maxValueUsd != null ? `$${p.maxValueUsd}` : "no limit"}`,
|
|
101
|
-
``,
|
|
102
|
-
`ID: \`${result.id}\``,
|
|
103
|
-
`Ready to run a playbook with this task scope.`,
|
|
104
|
-
];
|
|
105
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
106
|
-
}
|
|
107
|
-
// ── list_task_packets ───────────────────────────────────────────────────
|
|
108
|
-
case "list_task_packets": {
|
|
109
|
-
const result = await (0, convex_js_1.callConvex)("/framework/tasks", "GET", undefined, "list_task_packets");
|
|
110
|
-
const tasks = result.tasks ?? [];
|
|
111
|
-
if (tasks.length === 0) {
|
|
112
|
-
return {
|
|
113
|
-
content: [{
|
|
114
|
-
type: "text",
|
|
115
|
-
text: "No task packets yet. Use create_task_packet to define your first task.",
|
|
116
|
-
}],
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
const list = tasks
|
|
120
|
-
.map((t) => `• **${t.name}** [${t.status}]\n ${t.task}`)
|
|
121
|
-
.join("\n\n");
|
|
122
|
-
return { content: [{ type: "text", text: `**Your Task Packets**\n\n${list}` }] };
|
|
123
|
-
}
|
|
124
46
|
// ── list_playbooks ──────────────────────────────────────────────────────
|
|
125
47
|
case "list_playbooks": {
|
|
126
48
|
const result = await (0, convex_js_1.callConvex)("/framework/playbooks", "GET", undefined, "list_playbooks");
|
|
@@ -223,36 +145,6 @@ async function handleFrameworkTool(name, args) {
|
|
|
223
145
|
}],
|
|
224
146
|
};
|
|
225
147
|
}
|
|
226
|
-
// ── get_sentinel_rules ──────────────────────────────────────────────────
|
|
227
|
-
case "get_sentinel_rules": {
|
|
228
|
-
const rules = {
|
|
229
|
-
"market-monitor": { territory: ["market_data", "price_check", "market"], permissions: ["read:market", "write:memory"], doNotDo: ["swap", "send", "transfer", "buy", "sell", "drain"], maxValueUsd: 0 },
|
|
230
|
-
"sentiment-tracker": { territory: ["sentiment", "news_analysis", "news"], permissions: ["read:market", "read:social", "write:memory"], doNotDo: ["swap", "send", "transfer", "buy", "sell"], maxValueUsd: 0 },
|
|
231
|
-
"workflow-executor": { territory: ["swap", "send", "automation"], permissions: ["read:market", "write:tx", "write:memory"], doNotDo: ["delete_wallet", "change_keys", "drain_wallet"], maxValueUsd: 500 },
|
|
232
|
-
"memory-manager": { territory: ["memory_compress", "memory_prune", "memory"], permissions: ["read:memory", "write:memory", "delete:memory"], doNotDo: ["swap", "send", "transfer"], maxValueUsd: 0 },
|
|
233
|
-
"risk-verifier": { territory: ["risk_check", "verify", "risk"], permissions: ["read:market", "read:memory"], doNotDo: ["swap", "send", "transfer", "modify_rules"], maxValueUsd: 0 },
|
|
234
|
-
"playbook:scout": { territory: ["get", "read", "list", "market", "signal", "portfolio", "insight", "research", "data", "recap", "whale", "score", "execution", "memory", "noel", "swarm", "smart"], permissions: ["read:market", "read:signals", "read:portfolio", "read:memory", "write:memory"], doNotDo: ["send_token", "deploy_token", "mint_nft", "claim_fees", "swap_tokens", "delete_automation", "stop_swarm"], maxValueUsd: 0, note: "Playbook read-only scout role" },
|
|
235
|
-
"playbook:tinker": { territory: ["create", "write", "start", "run", "swap", "send", "deploy", "mint", "claim", "automation", "memory", "swarm"], permissions: ["write:tx", "write:memory", "execute:automation", "swap:token", "deploy:token"], doNotDo: ["delete_wallet", "drain_wallet"], maxValueUsd: 100, note: "Playbook execution role" },
|
|
236
|
-
"playbook:skeptic": { territory: ["get", "read", "ask", "analyze", "verify", "research", "check", "market", "signal", "execution", "score", "portfolio", "memory", "noel", "insight"], permissions: ["read:market", "read:signals", "read:portfolio", "read:memory"], doNotDo: ["send_token", "deploy_token", "mint_nft", "claim_fees", "swap_tokens", "delete"], maxValueUsd: 0, note: "Playbook analysis/verification role" },
|
|
237
|
-
"playbook:memory": { territory: ["memory", "write", "read", "compress", "prune", "summarize"], permissions: ["read:memory", "write:memory", "delete:memory"], doNotDo: ["send_token", "swap_tokens", "deploy_token", "mint_nft", "claim_fees"], maxValueUsd: 0, note: "Playbook memory management role" },
|
|
238
|
-
};
|
|
239
|
-
const sections = [
|
|
240
|
-
"**Sentinel Rules**",
|
|
241
|
-
"",
|
|
242
|
-
"**Swarm Agents (DEFAULT_RULES)**",
|
|
243
|
-
...["market-monitor", "sentiment-tracker", "workflow-executor", "memory-manager", "risk-verifier"].map(agent => {
|
|
244
|
-
const r = rules[agent];
|
|
245
|
-
return `\n**${agent}**\n Territory: ${r.territory.join(", ")}\n Permissions: ${r.permissions.join(", ")}\n Blocked: ${r.doNotDo.join(", ")}\n Max value: $${r.maxValueUsd}`;
|
|
246
|
-
}),
|
|
247
|
-
"",
|
|
248
|
-
"**Playbook Roles (DB rules — seeded at deploy)**",
|
|
249
|
-
...["playbook:scout", "playbook:tinker", "playbook:skeptic", "playbook:memory"].map(agent => {
|
|
250
|
-
const r = rules[agent];
|
|
251
|
-
return `\n**${agent}** _(${r.note})_\n Territory: ${r.territory.slice(0, 6).join(", ")}…\n Blocked: ${r.doNotDo.join(", ")}\n Max value: $${r.maxValueUsd}`;
|
|
252
|
-
}),
|
|
253
|
-
];
|
|
254
|
-
return { content: [{ type: "text", text: sections.join("\n") }] };
|
|
255
|
-
}
|
|
256
148
|
default:
|
|
257
149
|
return null;
|
|
258
150
|
}
|