@noelclaw/mcp 2.4.0 → 3.0.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/server.js +6 -6
- 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 +1 -1
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
|
}
|
package/dist/tools/swarm.js
CHANGED
|
@@ -38,34 +38,6 @@ exports.SWARM_TOOLS = [
|
|
|
38
38
|
description: "Get the current status of the swarm: active agents, shared memory snapshot, execution scores, and recent runs.",
|
|
39
39
|
inputSchema: { type: "object", properties: {}, required: [] },
|
|
40
40
|
},
|
|
41
|
-
{
|
|
42
|
-
name: "write_swarm_memory",
|
|
43
|
-
description: "Write a key-value pair to the swarm's shared memory.",
|
|
44
|
-
inputSchema: {
|
|
45
|
-
type: "object",
|
|
46
|
-
properties: {
|
|
47
|
-
agentId: { type: "string", description: "ID of the agent writing this memory entry" },
|
|
48
|
-
key: { type: "string", description: "Memory key" },
|
|
49
|
-
value: { type: "string", description: "Value to store" },
|
|
50
|
-
ttlSeconds: { type: "number", description: "Optional TTL in seconds" },
|
|
51
|
-
},
|
|
52
|
-
required: ["agentId", "key", "value"],
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: "get_swarm_memory",
|
|
57
|
-
description: "Read a value from the swarm's shared memory by key.",
|
|
58
|
-
inputSchema: {
|
|
59
|
-
type: "object",
|
|
60
|
-
properties: { key: { type: "string", description: "Memory key to read" } },
|
|
61
|
-
required: ["key"],
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
name: "get_execution_scores",
|
|
66
|
-
description: "Get the self-improvement scores for all skills.",
|
|
67
|
-
inputSchema: { type: "object", properties: {}, required: [] },
|
|
68
|
-
},
|
|
69
41
|
{
|
|
70
42
|
name: "swarm_research",
|
|
71
43
|
description: "Research any topic using the multi-agent swarm — automatically starts the swarm if needed, " +
|
|
@@ -117,71 +89,6 @@ exports.SWARM_TOOLS = [
|
|
|
117
89
|
required: [],
|
|
118
90
|
},
|
|
119
91
|
},
|
|
120
|
-
{
|
|
121
|
-
name: "swarm_broadcast",
|
|
122
|
-
description: "Broadcast a message or signal to all active swarm agents simultaneously. " +
|
|
123
|
-
"All agents will receive and act on the message in their next cycle. " +
|
|
124
|
-
"Use to coordinate the swarm: change focus, alert about market conditions, or inject a directive.",
|
|
125
|
-
inputSchema: {
|
|
126
|
-
type: "object",
|
|
127
|
-
properties: {
|
|
128
|
-
message: { type: "string", description: "Message to broadcast to all agents (max 500 chars)" },
|
|
129
|
-
priority: { type: "string", enum: ["low", "normal", "high", "urgent"], description: "Message priority (default: normal)" },
|
|
130
|
-
targetAgents: { type: "array", items: { type: "string" }, description: "Optional: target specific agent IDs. Omit to broadcast to all." },
|
|
131
|
-
},
|
|
132
|
-
required: ["message"],
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
name: "swarm_pulse",
|
|
137
|
-
description: "Get an instant snapshot from all swarm agents — market prices, sentiment, on-chain activity, and agent health. " +
|
|
138
|
-
"Unlike get_swarm_status, swarm_pulse triggers all agents to report their latest readings right now. " +
|
|
139
|
-
"Best for a quick market briefing or sanity check before making decisions.",
|
|
140
|
-
inputSchema: {
|
|
141
|
-
type: "object",
|
|
142
|
-
properties: {
|
|
143
|
-
token: { type: "string", description: "Optional: focus the pulse on a specific token (e.g. 'BTC', 'ETH')" },
|
|
144
|
-
},
|
|
145
|
-
required: [],
|
|
146
|
-
},
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
name: "swarm_reflect",
|
|
150
|
-
description: "Consolidate everything the swarm has learned into a single coherent intelligence summary. " +
|
|
151
|
-
"Reads all recent research vault entries from swarm agents, groups by agent, extracts key signals, " +
|
|
152
|
-
"and saves a unified reflection to vault. " +
|
|
153
|
-
"Run this after swarm_research or swarm_pulse to crystallize findings into long-term memory. " +
|
|
154
|
-
"Best used once per research session or daily for ongoing monitoring.",
|
|
155
|
-
inputSchema: {
|
|
156
|
-
type: "object",
|
|
157
|
-
properties: {
|
|
158
|
-
hoursBack: { type: "number", description: "How many hours of swarm activity to include (default: 24)" },
|
|
159
|
-
focus: { type: "string", description: "Optional: focus reflection on a specific topic or token" },
|
|
160
|
-
},
|
|
161
|
-
required: [],
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
name: "swarm_watch",
|
|
166
|
-
description: "Register a topic or token for continuous swarm monitoring. " +
|
|
167
|
-
"Swarm agents will prioritize this topic in every cycle — price changes, sentiment shifts, news, on-chain flows. " +
|
|
168
|
-
"Findings are saved to vault and semantic memory automatically. " +
|
|
169
|
-
"Use memory_insight or swarm_brief to check accumulated findings. " +
|
|
170
|
-
"Alert conditions: price_spike | sentiment_shift | news | whale_move | all.",
|
|
171
|
-
inputSchema: {
|
|
172
|
-
type: "object",
|
|
173
|
-
properties: {
|
|
174
|
-
topic: { type: "string", description: "What to watch — token symbol, protocol name, or any topic (e.g. 'ETH', 'Lido', 'Base ecosystem')" },
|
|
175
|
-
priority: { type: "string", enum: ["low", "normal", "high"], description: "Monitoring priority (default: normal)" },
|
|
176
|
-
alertOn: {
|
|
177
|
-
type: "array",
|
|
178
|
-
items: { type: "string", enum: ["price_spike", "sentiment_shift", "news", "whale_move", "all"] },
|
|
179
|
-
description: "Which signals to watch for (default: price_spike, sentiment_shift, news)",
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
required: ["topic"],
|
|
183
|
-
},
|
|
184
|
-
},
|
|
185
92
|
];
|
|
186
93
|
const StartSwarmSchema = zod_1.z.object({
|
|
187
94
|
config: zod_1.z.object({
|
|
@@ -189,26 +96,12 @@ const StartSwarmSchema = zod_1.z.object({
|
|
|
189
96
|
byok: zod_1.z.boolean().optional(),
|
|
190
97
|
}).optional(),
|
|
191
98
|
});
|
|
192
|
-
const WriteMemorySchema = zod_1.z.object({ agentId: zod_1.z.string().min(1), key: zod_1.z.string().min(1), value: zod_1.z.string(), ttlSeconds: zod_1.z.number().optional() });
|
|
193
|
-
const GetMemorySchema = zod_1.z.object({ key: zod_1.z.string().min(1) });
|
|
194
99
|
const ResearchSchema = zod_1.z.object({ topic: zod_1.z.string().min(1), depth: zod_1.z.enum(["quick", "standard", "deep"]).optional() });
|
|
195
100
|
const BriefSchema = zod_1.z.object({ limit: zod_1.z.number().optional() });
|
|
196
101
|
const TriggerAgentSchema = zod_1.z.object({
|
|
197
102
|
agentId: zod_1.z.enum(["market-monitor", "sentiment-tracker", "memory-manager", "risk-verifier", "workflow-executor", "onchain-analyst", "news-aggregator"]),
|
|
198
103
|
params: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
|
|
199
104
|
});
|
|
200
|
-
const BroadcastSchema = zod_1.z.object({
|
|
201
|
-
message: zod_1.z.string().min(1).max(500),
|
|
202
|
-
priority: zod_1.z.enum(["low", "normal", "high", "urgent"]).optional(),
|
|
203
|
-
targetAgents: zod_1.z.array(zod_1.z.string()).optional(),
|
|
204
|
-
});
|
|
205
|
-
const PulseSchema = zod_1.z.object({ token: zod_1.z.string().optional() });
|
|
206
|
-
const ReflectSchema = zod_1.z.object({ hoursBack: zod_1.z.number().positive().optional(), focus: zod_1.z.string().optional() });
|
|
207
|
-
const WatchSchema = zod_1.z.object({
|
|
208
|
-
topic: zod_1.z.string().min(1),
|
|
209
|
-
priority: zod_1.z.enum(["low", "normal", "high"]).optional(),
|
|
210
|
-
alertOn: zod_1.z.array(zod_1.z.enum(["price_spike", "sentiment_shift", "news", "whale_move", "all"])).optional(),
|
|
211
|
-
});
|
|
212
105
|
const NO_KEY_MSG = `🔑 Swarm tools require a NoelClaw API key.\n\n` +
|
|
213
106
|
`→ Get yours free at: https://noelclaw.com\n\n` +
|
|
214
107
|
`Then add it to your MCP config:\n` +
|
|
@@ -311,41 +204,6 @@ async function handleSwarmTool(name, args) {
|
|
|
311
204
|
}
|
|
312
205
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
313
206
|
}
|
|
314
|
-
case "write_swarm_memory": {
|
|
315
|
-
const parsed = WriteMemorySchema.safeParse(args);
|
|
316
|
-
if (!parsed.success)
|
|
317
|
-
return { content: [{ type: "text", text: `Invalid input: ${String(parsed.error.issues[0].path[0])} ${parsed.error.issues[0].message}` }], isError: true };
|
|
318
|
-
const { agentId, key, value, ttlSeconds } = parsed.data;
|
|
319
|
-
await (0, convex_js_1.callConvex)("/swarm/memory/write", "POST", { agentId, key, value, ttlSeconds }, "write_swarm_memory");
|
|
320
|
-
return { content: [{ type: "text", text: `✅ Memory written: [${agentId}] ${key}${ttlSeconds ? ` (expires in ${ttlSeconds}s)` : ""}` }] };
|
|
321
|
-
}
|
|
322
|
-
case "get_swarm_memory": {
|
|
323
|
-
const parsed = GetMemorySchema.safeParse(args);
|
|
324
|
-
if (!parsed.success)
|
|
325
|
-
return { content: [{ type: "text", text: `Invalid input: key ${parsed.error.issues[0].message}` }], isError: true };
|
|
326
|
-
const data = await (0, convex_js_1.callConvex)(`/swarm/memory/read?key=${encodeURIComponent(parsed.data.key)}`, "GET", undefined, "get_swarm_memory");
|
|
327
|
-
if (data.error)
|
|
328
|
-
return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
|
|
329
|
-
if (data.value === null || data.value === undefined)
|
|
330
|
-
return { content: [{ type: "text", text: `No value found for key: ${parsed.data.key}` }] };
|
|
331
|
-
return { content: [{ type: "text", text: `**${parsed.data.key}**: ${data.value}` }] };
|
|
332
|
-
}
|
|
333
|
-
case "get_execution_scores": {
|
|
334
|
-
const data = await (0, convex_js_1.callConvex)("/swarm/scores", "GET", undefined, "get_execution_scores");
|
|
335
|
-
if (data.error)
|
|
336
|
-
return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
|
|
337
|
-
const scores = data.scores ?? [];
|
|
338
|
-
if (!scores.length)
|
|
339
|
-
return { content: [{ type: "text", text: "No execution scores yet. Run some swarm agents to build a history." }] };
|
|
340
|
-
const sorted = scores.sort((a, b) => b.lastScore - a.lastScore);
|
|
341
|
-
const lines = [
|
|
342
|
-
`**Execution Scores**`, ``,
|
|
343
|
-
`| Skill | Score | W | L | Avg Duration | Last Adapted |`,
|
|
344
|
-
`|-------|-------|---|---|--------------|--------------|`,
|
|
345
|
-
...sorted.map((s) => `| ${s.skillName} | ${(s.lastScore * 100).toFixed(0)}% | ${s.successCount} | ${s.failCount} | ${Math.round(s.avgDurationMs / 1000)}s | ${new Date(s.lastAdaptedAt).toUTCString()} |`),
|
|
346
|
-
];
|
|
347
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
348
|
-
}
|
|
349
207
|
case "swarm_research": {
|
|
350
208
|
const parsed = ResearchSchema.safeParse(args);
|
|
351
209
|
if (!parsed.success)
|
|
@@ -453,219 +311,6 @@ async function handleSwarmTool(name, args) {
|
|
|
453
311
|
lines.push(`\nUse \`memory_context topic: "<topic>"\` to load full content for any research area.`);
|
|
454
312
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
455
313
|
}
|
|
456
|
-
case "swarm_broadcast": {
|
|
457
|
-
const parsed = BroadcastSchema.safeParse(args);
|
|
458
|
-
if (!parsed.success)
|
|
459
|
-
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues[0].message}` }], isError: true };
|
|
460
|
-
const { message, priority = "normal", targetAgents } = parsed.data;
|
|
461
|
-
let data;
|
|
462
|
-
try {
|
|
463
|
-
data = await (0, convex_js_1.callConvex)("/swarm/broadcast", "POST", { message, priority, targetAgents }, "swarm_broadcast");
|
|
464
|
-
}
|
|
465
|
-
catch (err) {
|
|
466
|
-
return swarmAuthError(err);
|
|
467
|
-
}
|
|
468
|
-
if (data.error)
|
|
469
|
-
return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
|
|
470
|
-
const targets = targetAgents?.join(", ") ?? "all agents";
|
|
471
|
-
return {
|
|
472
|
-
content: [{
|
|
473
|
-
type: "text",
|
|
474
|
-
text: [
|
|
475
|
-
`📡 **Broadcast sent** [${priority}]`,
|
|
476
|
-
`To: ${targets}`,
|
|
477
|
-
`Message: "${message}"`,
|
|
478
|
-
data.deliveredTo ? `Delivered to ${data.deliveredTo} agent(s)` : "",
|
|
479
|
-
].filter(Boolean).join("\n"),
|
|
480
|
-
}],
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
case "swarm_pulse": {
|
|
484
|
-
const parsed = PulseSchema.safeParse(args ?? {});
|
|
485
|
-
if (!parsed.success)
|
|
486
|
-
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues[0].message}` }], isError: true };
|
|
487
|
-
const { token } = parsed.data;
|
|
488
|
-
await (0, convex_js_1.callConvex)("/swarm/start", "POST", {}, "start_swarm").catch(() => { });
|
|
489
|
-
let data;
|
|
490
|
-
try {
|
|
491
|
-
data = await (0, convex_js_1.callConvex)("/swarm/pulse", "POST", { token }, "swarm_pulse");
|
|
492
|
-
}
|
|
493
|
-
catch (err) {
|
|
494
|
-
return swarmAuthError(err);
|
|
495
|
-
}
|
|
496
|
-
if (data.error)
|
|
497
|
-
return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
|
|
498
|
-
const readings = data.readings ?? [];
|
|
499
|
-
const lines = [
|
|
500
|
-
`💓 **Swarm Pulse**${token ? ` — ${token}` : ""}`,
|
|
501
|
-
`Agents reporting: ${readings.length}`,
|
|
502
|
-
``,
|
|
503
|
-
];
|
|
504
|
-
for (const r of readings) {
|
|
505
|
-
lines.push(`**[${r.agentId}]** ${r.summary ?? "No data"}`);
|
|
506
|
-
if (r.data) {
|
|
507
|
-
const preview = JSON.stringify(r.data).slice(0, 120);
|
|
508
|
-
lines.push(` ${preview}${preview.length === 120 ? "…" : ""}`);
|
|
509
|
-
}
|
|
510
|
-
lines.push("");
|
|
511
|
-
}
|
|
512
|
-
if (!readings.length)
|
|
513
|
-
lines.push("No agents responding. Use `start_swarm` first.");
|
|
514
|
-
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
515
|
-
}
|
|
516
|
-
case "swarm_reflect": {
|
|
517
|
-
const parsed = ReflectSchema.safeParse(args ?? {});
|
|
518
|
-
if (!parsed.success)
|
|
519
|
-
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues[0].message}` }], isError: true };
|
|
520
|
-
const { hoursBack = 24, focus } = parsed.data;
|
|
521
|
-
const params = new URLSearchParams({ type: "research", limit: "30" });
|
|
522
|
-
let data;
|
|
523
|
-
try {
|
|
524
|
-
data = await (0, convex_js_1.callConvex)(`/vault/list?${params}`, "GET", undefined, "swarm_reflect");
|
|
525
|
-
}
|
|
526
|
-
catch (err) {
|
|
527
|
-
return swarmAuthError(err);
|
|
528
|
-
}
|
|
529
|
-
if (data.error)
|
|
530
|
-
return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
|
|
531
|
-
const SWARM_AGENTS = new Set(["market-monitor", "sentiment-tracker", "onchain-analyst", "news-aggregator", "risk-verifier", "memory-manager"]);
|
|
532
|
-
const cutoff = Date.now() - hoursBack * 3600000;
|
|
533
|
-
const entries = (data.entries ?? []).filter((e) => {
|
|
534
|
-
const isSwarm = SWARM_AGENTS.has(e.agentId);
|
|
535
|
-
const isRecent = e.updatedAt >= cutoff;
|
|
536
|
-
const matchesFocus = !focus || e.title.toLowerCase().includes(focus.toLowerCase());
|
|
537
|
-
return isSwarm && isRecent && matchesFocus;
|
|
538
|
-
});
|
|
539
|
-
if (!entries.length) {
|
|
540
|
-
return {
|
|
541
|
-
content: [{
|
|
542
|
-
type: "text",
|
|
543
|
-
text: [
|
|
544
|
-
`📋 **Swarm Reflection** — Nothing to consolidate`,
|
|
545
|
-
``,
|
|
546
|
-
`No swarm research found in the last ${hoursBack}h${focus ? ` about "${focus}"` : ""}.`,
|
|
547
|
-
``,
|
|
548
|
-
`Start one: \`swarm_research topic: "${focus ?? "market overview"}"\``,
|
|
549
|
-
].join("\n"),
|
|
550
|
-
}],
|
|
551
|
-
};
|
|
552
|
-
}
|
|
553
|
-
// Group by agent
|
|
554
|
-
const byAgent = {};
|
|
555
|
-
for (const e of entries) {
|
|
556
|
-
const a = e.agentId ?? "unknown";
|
|
557
|
-
(byAgent[a] ?? (byAgent[a] = [])).push(e);
|
|
558
|
-
}
|
|
559
|
-
const agentSummaries = Object.entries(byAgent).map(([agent, es]) => {
|
|
560
|
-
const items = es.map((e) => ` • ${e.title}`).join("\n");
|
|
561
|
-
return `**[${agent}]** — ${es.length} finding(s)\n${items}`;
|
|
562
|
-
});
|
|
563
|
-
const signals = entries
|
|
564
|
-
.sort((a, b) => b.updatedAt - a.updatedAt)
|
|
565
|
-
.slice(0, 6)
|
|
566
|
-
.map((e) => `• [${e.agentId}] ${e.title}`);
|
|
567
|
-
// Write synthesis to vault for long-term memory
|
|
568
|
-
const now = new Date();
|
|
569
|
-
const reflectionKey = `swarm/reflection-${now.toISOString().slice(0, 10)}-${now.getHours()}h`;
|
|
570
|
-
const reflectionContent = [
|
|
571
|
-
`# Swarm Reflection — ${now.toUTCString()}`,
|
|
572
|
-
`Period: last ${hoursBack}h${focus ? ` · Focus: ${focus}` : ""} · ${entries.length} entries from ${Object.keys(byAgent).length} agent(s)`,
|
|
573
|
-
``,
|
|
574
|
-
`## Agent Findings`,
|
|
575
|
-
agentSummaries.join("\n\n"),
|
|
576
|
-
``,
|
|
577
|
-
`## Key Signals`,
|
|
578
|
-
signals.join("\n"),
|
|
579
|
-
].join("\n");
|
|
580
|
-
const saved = await (0, convex_js_1.callConvex)("/vault/save", "POST", {
|
|
581
|
-
type: "research",
|
|
582
|
-
title: `Swarm Reflection — ${now.toLocaleDateString("en-US")}${focus ? ` — ${focus}` : ""}`,
|
|
583
|
-
content: reflectionContent,
|
|
584
|
-
key: reflectionKey,
|
|
585
|
-
agentId: "swarm-coordinator",
|
|
586
|
-
tags: ["reflection", "swarm", ...(focus ? [focus] : [])],
|
|
587
|
-
commitMsg: "swarm_reflect auto-consolidation",
|
|
588
|
-
}, "swarm_reflect").catch(() => null);
|
|
589
|
-
// Also sync to semantic memory so it's retrievable by topic
|
|
590
|
-
if (saved) {
|
|
591
|
-
(0, memory_js_1.syncToSupermemory)(reflectionContent, {
|
|
592
|
-
vaultKey: reflectionKey, title: `Swarm Reflection ${now.toLocaleDateString("en-US")}`,
|
|
593
|
-
type: "research", tags: ["reflection"], source: "swarm_reflect",
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
return {
|
|
597
|
-
content: [{
|
|
598
|
-
type: "text",
|
|
599
|
-
text: [
|
|
600
|
-
`📋 **Swarm Reflection** — ${entries.length} findings from ${Object.keys(byAgent).length} agent(s)`,
|
|
601
|
-
`Period: last ${hoursBack}h${focus ? ` · Focus: ${focus}` : ""}`,
|
|
602
|
-
``,
|
|
603
|
-
agentSummaries.join("\n\n"),
|
|
604
|
-
``,
|
|
605
|
-
`**Key signals:**`,
|
|
606
|
-
...signals,
|
|
607
|
-
``,
|
|
608
|
-
saved ? `✅ Synthesis saved to vault: \`${reflectionKey}\`` : "⚠️ Could not save synthesis",
|
|
609
|
-
``,
|
|
610
|
-
`Use \`memory_insight topic: "${focus ?? "swarm research"}"\` for the full intelligence picture.`,
|
|
611
|
-
].filter(Boolean).join("\n"),
|
|
612
|
-
}],
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
case "swarm_watch": {
|
|
616
|
-
const parsed = WatchSchema.safeParse(args);
|
|
617
|
-
if (!parsed.success)
|
|
618
|
-
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues[0].message}` }], isError: true };
|
|
619
|
-
const { topic, priority = "normal", alertOn = ["price_spike", "sentiment_shift", "news"] } = parsed.data;
|
|
620
|
-
const watchKey = `watch:${topic.toLowerCase().replace(/\s+/g, "-")}`;
|
|
621
|
-
const watchConfig = JSON.stringify({
|
|
622
|
-
topic, priority,
|
|
623
|
-
alertOn: alertOn.includes("all") ? ["price_spike", "sentiment_shift", "news", "whale_move"] : alertOn,
|
|
624
|
-
registeredAt: Date.now(),
|
|
625
|
-
});
|
|
626
|
-
// Write to swarm shared memory (picked up by agents in next cycle)
|
|
627
|
-
await (0, convex_js_1.callConvex)("/swarm/memory/write", "POST", {
|
|
628
|
-
agentId: "swarm-coordinator",
|
|
629
|
-
key: watchKey,
|
|
630
|
-
value: watchConfig,
|
|
631
|
-
}, "swarm_watch").catch(() => { });
|
|
632
|
-
// Persist to vault so it survives swarm restarts
|
|
633
|
-
await (0, convex_js_1.callConvex)("/vault/save", "POST", {
|
|
634
|
-
type: "memory",
|
|
635
|
-
title: `Watch: ${topic}`,
|
|
636
|
-
content: watchConfig,
|
|
637
|
-
key: `watch/${topic.toLowerCase().replace(/\s+/g, "-")}`,
|
|
638
|
-
agentId: "swarm-coordinator",
|
|
639
|
-
tags: ["watch", "monitor", topic.toLowerCase()],
|
|
640
|
-
commitMsg: "swarm_watch registered",
|
|
641
|
-
}, "swarm_watch").catch(() => { });
|
|
642
|
-
const alertList = (alertOn.includes("all")
|
|
643
|
-
? ["price_spike", "sentiment_shift", "news", "whale_move"]
|
|
644
|
-
: alertOn).join(", ");
|
|
645
|
-
return {
|
|
646
|
-
content: [{
|
|
647
|
-
type: "text",
|
|
648
|
-
text: [
|
|
649
|
-
`👁️ **Watch Registered: ${topic}**`,
|
|
650
|
-
`Priority: ${priority} · Alerts: ${alertList}`,
|
|
651
|
-
``,
|
|
652
|
-
`Swarm agents will now prioritize "${topic}" in every monitoring cycle.`,
|
|
653
|
-
`Watch key: \`${watchKey}\``,
|
|
654
|
-
``,
|
|
655
|
-
`**What happens next:**`,
|
|
656
|
-
`• market-monitor will track price & volume anomalies`,
|
|
657
|
-
`• sentiment-tracker will watch social signal shifts`,
|
|
658
|
-
`• news-aggregator will flag relevant news & narratives`,
|
|
659
|
-
alertOn.includes("whale_move") || alertOn.includes("all") ? `• onchain-analyst will detect large wallet movements` : "",
|
|
660
|
-
``,
|
|
661
|
-
`**Check findings:**`,
|
|
662
|
-
`• \`swarm_brief\` — latest research entries`,
|
|
663
|
-
`• \`memory_insight topic: "${topic}"\` — full intelligence report`,
|
|
664
|
-
`• \`swarm_reflect focus: "${topic}"\` — consolidated summary`,
|
|
665
|
-
].filter(Boolean).join("\n"),
|
|
666
|
-
}],
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
314
|
default:
|
|
670
315
|
return null;
|
|
671
316
|
}
|